Rename SQL data types so they don't conflict with drivers
[freeradius.git] / src / modules / rlm_sql / rlm_sql.c
index abcea04..6dd6c19 100644 (file)
@@ -1,13 +1,7 @@
 /*
- * rlm_sql.c           SQL Module
- *             Main SQL module file. Most ICRADIUS code is located in sql.c
- *
- * 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 is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License, version 2 if the
+ *   License as published by the Free Software Foundation.
  *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  *   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+/**
+ * $Id$
+ * @file rlm_sql.c
+ * @brief Implements SQL 'users' file, and SQL accounting.
  *
- * Copyright 2000,2006  The FreeRADIUS server project
- * Copyright 2000  Mike Machado <mike@innercite.com>
- * Copyright 2000  Alan DeKok <aland@ox.org>
+ * @copyright 2012  Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2000,2006  The FreeRADIUS server project
+ * @copyright 2000  Mike Machado <mike@innercite.com>
+ * @copyright 2000  Alan DeKok <aland@ox.org>
  */
-
 #include <freeradius-devel/ident.h>
 RCSID("$Id$")
 
+#include <ctype.h>
+
 #include <freeradius-devel/radiusd.h>
 #include <freeradius-devel/modules.h>
+#include <freeradius-devel/token.h>
 #include <freeradius-devel/rad_assert.h>
-#include <ltdl.h>
 
 #include <sys/stat.h>
 
 #include "rlm_sql.h"
 
-static char *allowed_chars = NULL;
+static const CONF_PARSER acct_section_config[] = {
+       {"reference", PW_TYPE_STRING_PTR,
+         offsetof(sql_acct_section_t, reference), NULL, ".query"},
+         
+       {"logfile", PW_TYPE_STRING_PTR,
+        offsetof(sql_acct_section_t, logfile), NULL, NULL},
+       {NULL, -1, 0, NULL, NULL}
+};
 
 static const CONF_PARSER module_config[] = {
-       {"driver",PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,sql_driver), NULL, "mysql"},
-       {"server",PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,sql_server), NULL, "localhost"},
-       {"port",PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,sql_port), NULL, ""},
+       {"driver", PW_TYPE_STRING_PTR,
+        offsetof(rlm_sql_config_t,sql_driver), NULL, "mysql"},
+       {"server", PW_TYPE_STRING_PTR,
+        offsetof(rlm_sql_config_t,sql_server), NULL, "localhost"},
+       {"port", PW_TYPE_STRING_PTR,
+        offsetof(rlm_sql_config_t,sql_port), NULL, ""},
        {"login", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,sql_login), NULL, ""},
+        offsetof(rlm_sql_config_t,sql_login), NULL, ""},
        {"password", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,sql_password), NULL, ""},
+        offsetof(rlm_sql_config_t,sql_password), NULL, ""},
        {"radius_db", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,sql_db), NULL, "radius"},
+        offsetof(rlm_sql_config_t,sql_db), NULL, "radius"},
+       {"filename", PW_TYPE_FILENAME, /* for sqlite */
+        offsetof(rlm_sql_config_t,sql_file), NULL, NULL},
        {"read_groups", PW_TYPE_BOOLEAN,
-        offsetof(SQL_CONFIG,read_groups), NULL, "yes"},
-       {"sqltrace", PW_TYPE_BOOLEAN,
-        offsetof(SQL_CONFIG,sqltrace), NULL, "no"},
-       {"sqltracefile", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,tracefile), NULL, SQLTRACEFILE},
+        offsetof(rlm_sql_config_t,read_groups), NULL, "yes"},
        {"readclients", PW_TYPE_BOOLEAN,
-        offsetof(SQL_CONFIG,do_clients), NULL, "no"},
+        offsetof(rlm_sql_config_t,do_clients), NULL, "no"},
        {"deletestalesessions", PW_TYPE_BOOLEAN,
-        offsetof(SQL_CONFIG,deletestalesessions), NULL, "yes"},
-       {"num_sql_socks", PW_TYPE_INTEGER,
-        offsetof(SQL_CONFIG,num_sql_socks), NULL, "5"},
-       {"lifetime", PW_TYPE_INTEGER,
-        offsetof(SQL_CONFIG,lifetime), NULL, "0"},
-       {"max_queries", PW_TYPE_INTEGER,
-        offsetof(SQL_CONFIG,max_queries), NULL, "0"},
+        offsetof(rlm_sql_config_t,deletestalesessions), NULL, "yes"},
        {"sql_user_name", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,query_user), NULL, ""},
+        offsetof(rlm_sql_config_t,query_user), NULL, ""},
+       {"logfile", PW_TYPE_STRING_PTR,
+        offsetof(rlm_sql_config_t,logfile), NULL, NULL},
        {"default_user_profile", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,default_profile), NULL, ""},
+        offsetof(rlm_sql_config_t,default_profile), NULL, ""},
        {"nas_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,nas_query), NULL, "SELECT id,nasname,shortname,type,secret FROM nas"},
+        offsetof(rlm_sql_config_t,nas_query), NULL,
+        "SELECT id,nasname,shortname,type,secret FROM nas"},
        {"authorize_check_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,authorize_check_query), NULL, ""},
+        offsetof(rlm_sql_config_t,authorize_check_query), NULL, ""},
        {"authorize_reply_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,authorize_reply_query), NULL, NULL},
+        offsetof(rlm_sql_config_t,authorize_reply_query), NULL, NULL},
        {"authorize_group_check_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,authorize_group_check_query), NULL, ""},
+        offsetof(rlm_sql_config_t,authorize_group_check_query), NULL, ""},
        {"authorize_group_reply_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,authorize_group_reply_query), NULL, ""},
-       {"accounting_onoff_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,accounting_onoff_query), NULL, ""},
-       {"accounting_update_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,accounting_update_query), NULL, ""},
-       {"accounting_update_query_alt", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,accounting_update_query_alt), NULL, ""},
-       {"accounting_start_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,accounting_start_query), NULL, ""},
-       {"accounting_start_query_alt", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,accounting_start_query_alt), NULL, ""},
-       {"accounting_stop_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,accounting_stop_query), NULL, ""},
-       {"accounting_stop_query_alt", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,accounting_stop_query_alt), NULL, ""},
+        offsetof(rlm_sql_config_t,authorize_group_reply_query), NULL, ""},
        {"group_membership_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,groupmemb_query), NULL, NULL},
-       {"connect_failure_retry_delay", PW_TYPE_INTEGER,
-        offsetof(SQL_CONFIG,connect_failure_retry_delay), NULL, "60"},
+        offsetof(rlm_sql_config_t,groupmemb_query), NULL, NULL},
+#ifdef WITH_SESSION_MGMT
        {"simul_count_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,simul_count_query), NULL, ""},
+        offsetof(rlm_sql_config_t,simul_count_query), NULL, ""},
        {"simul_verify_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,simul_verify_query), NULL, ""},
-       {"postauth_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,postauth_query), NULL, ""},
+        offsetof(rlm_sql_config_t,simul_verify_query), NULL, ""},
+#endif
        {"safe-characters", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,allowed_chars), NULL,
+        offsetof(rlm_sql_config_t,allowed_chars), NULL,
        "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},
 
+       /*
+        *      This only works for a few drivers.
+        */
+       {"query_timeout", PW_TYPE_INTEGER,
+        offsetof(rlm_sql_config_t,query_timeout), NULL, NULL},
+        
        {NULL, -1, 0, NULL, NULL}
 };
 
@@ -117,35 +111,31 @@ static const CONF_PARSER module_config[] = {
 static int fallthrough(VALUE_PAIR *vp)
 {
        VALUE_PAIR *tmp;
-       tmp = pairfind(vp, PW_FALL_THROUGH);
+       tmp = pairfind(vp, PW_FALL_THROUGH, 0, TAG_ANY);
 
        return tmp ? tmp->vp_integer : 0;
 }
 
-
-
 /*
  *     Yucky prototype.
  */
-static int generate_sql_clients(SQL_INST *inst);
-static size_t sql_escape_func(char *out, size_t outlen, const char *in);
+static int generate_sql_clients(rlm_sql_t *inst);
+static size_t sql_escape_func(REQUEST *, char *out, size_t outlen, const char *in, void *arg);
 
 /*
- *     sql xlat function. Right now only SELECTs are supported. Only
- *     the first element of the SELECT result will be used.
+ *                     SQL xlat function
  *
- *     For other statements (insert, update, delete, etc.), the
- *     number of affected rows will be returned.
+ *  For selects the first value of the first column will be returned,
+ *  for inserts, updates and deletes the number of rows afftected will be
+ *  returned instead.
  */
-static int sql_xlat(void *instance, REQUEST *request,
-                   char *fmt, char *out, size_t freespace,
-                   UNUSED RADIUS_ESCAPE_STRING func)
+static size_t sql_xlat(void *instance, REQUEST *request,
+                   const char *fmt, char *out, size_t freespace)
 {
-       SQLSOCK *sqlsocket;
-       SQL_ROW row;
-       SQL_INST *inst = instance;
+       rlm_sql_handle_t *handle;
+       rlm_sql_row_t row;
+       rlm_sql_t *inst = instance;
        char querystr[MAX_QUERY_LEN];
-       char sqlusername[MAX_STRING_LEN];
        size_t ret = 0;
 
        RDEBUG("sql_xlat");
@@ -155,21 +145,22 @@ static int sql_xlat(void *instance, REQUEST *request,
          *  We could search the string fmt for SQL-User-Name to see if this is
          *  needed or not
          */
-       sql_set_user(inst, request, sqlusername, NULL);
+       sql_set_user(inst, request, NULL);
        /*
         * Do an xlat on the provided string (nice recursive operation).
         */
-       if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func)) {
+       if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func, inst)) {
                radlog(L_ERR, "rlm_sql (%s): xlat failed.",
                       inst->config->xlat_name);
                return 0;
        }
 
-       query_log(request, inst,querystr);
-       sqlsocket = sql_get_socket(inst);
-       if (sqlsocket == NULL)
+       handle = sql_get_socket(inst);
+       if (handle == NULL)
                return 0;
 
+       rlm_sql_query_log(inst, request, NULL, querystr);
+
        /*
         *      If the query starts with any of the following prefixes,
         *      then return the number of rows affected
@@ -180,16 +171,13 @@ static int sql_xlat(void *instance, REQUEST *request,
                int numaffected;
                char buffer[21]; /* 64bit max is 20 decimal chars + null byte */
 
-               if (rlm_sql_query(sqlsocket,inst,querystr)) {
-                       radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
-                               inst->config->xlat_name, querystr,
-                               (inst->module->sql_error)(sqlsocket,
-                                                         inst->config));
-                       sql_release_socket(inst,sqlsocket);
+               if (rlm_sql_query(&handle,inst,querystr)) {
+                       sql_release_socket(inst,handle);
+                       
                        return 0;
                }
               
-               numaffected = (inst->module->sql_affected_rows)(sqlsocket,
+               numaffected = (inst->module->sql_affected_rows)(handle,
                                                                inst->config);
                if (numaffected < 1) {
                        RDEBUG("rlm_sql (%s): SQL query affected no rows",
@@ -209,55 +197,51 @@ static int sql_xlat(void *instance, REQUEST *request,
                if (ret >= freespace){
                        RDEBUG("rlm_sql (%s): Can't write result, insufficient string space",
                               inst->config->xlat_name);
-                       (inst->module->sql_finish_query)(sqlsocket,
+                       (inst->module->sql_finish_query)(handle,
                                                         inst->config);
-                       sql_release_socket(inst,sqlsocket);
+                       sql_release_socket(inst,handle);
                        return 0;
                }
                
                memcpy(out, buffer, ret + 1); /* we did bounds checking above */
 
-               (inst->module->sql_finish_query)(sqlsocket, inst->config);
-               sql_release_socket(inst,sqlsocket);
+               (inst->module->sql_finish_query)(handle, inst->config);
+               sql_release_socket(inst,handle);
                return ret;
        } /* else it's a SELECT statement */
 
-       if (rlm_sql_select_query(sqlsocket,inst,querystr)){
-               radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
-                      inst->config->xlat_name,querystr,
-                      (inst->module->sql_error)(sqlsocket, inst->config));
-               sql_release_socket(inst,sqlsocket);
+       if (rlm_sql_select_query(&handle,inst,querystr)){
+               sql_release_socket(inst,handle);
                return 0;
        }
 
-       ret = rlm_sql_fetch_row(sqlsocket, inst);
-
+       ret = rlm_sql_fetch_row(&handle, inst);
        if (ret) {
                RDEBUG("SQL query did not succeed");
-               (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-               sql_release_socket(inst,sqlsocket);
+               (inst->module->sql_finish_select_query)(handle, inst->config);
+               sql_release_socket(inst,handle);
                return 0;
        }
 
-       row = sqlsocket->row;
+       row = handle->row;
        if (row == NULL) {
                RDEBUG("SQL query did not return any results");
-               (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-               sql_release_socket(inst,sqlsocket);
+               (inst->module->sql_finish_select_query)(handle, inst->config);
+               sql_release_socket(inst,handle);
                return 0;
        }
 
        if (row[0] == NULL){
-               RDEBUG("row[0] returned NULL");
-               (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-               sql_release_socket(inst,sqlsocket);
+               RDEBUG("Null value in first column");
+               (inst->module->sql_finish_select_query)(handle, inst->config);
+               sql_release_socket(inst,handle);
                return 0;
        }
        ret = strlen(row[0]);
        if (ret >= freespace){
                RDEBUG("Insufficient string space");
-               (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-               sql_release_socket(inst,sqlsocket);
+               (inst->module->sql_finish_select_query)(handle, inst->config);
+               sql_release_socket(inst,handle);
                return 0;
        }
 
@@ -265,15 +249,15 @@ static int sql_xlat(void *instance, REQUEST *request,
 
        RDEBUG("sql_xlat finished");
 
-       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-       sql_release_socket(inst,sqlsocket);
+       (inst->module->sql_finish_select_query)(handle, inst->config);
+       sql_release_socket(inst,handle);
        return ret;
 }
 
-static int generate_sql_clients(SQL_INST *inst)
+static int generate_sql_clients(rlm_sql_t *inst)
 {
-       SQLSOCK *sqlsocket;
-       SQL_ROW row;
+       rlm_sql_handle_t *handle;
+       rlm_sql_row_t row;
        char querystr[MAX_QUERY_LEN];
        RADCLIENT *c;
        char *prefix_ptr = NULL;
@@ -288,32 +272,28 @@ static int generate_sql_clients(SQL_INST *inst)
        DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s",
              inst->config->xlat_name, querystr);
 
-       sqlsocket = sql_get_socket(inst);
-       if (sqlsocket == NULL)
+       handle = sql_get_socket(inst);
+       if (handle == NULL)
                return -1;
-       if (rlm_sql_select_query(sqlsocket,inst,querystr)){
-               radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
-                      inst->config->xlat_name,querystr,
-                      (inst->module->sql_error)(sqlsocket, inst->config));
-               sql_release_socket(inst,sqlsocket);
+       if (rlm_sql_select_query(&handle,inst,querystr)){
                return -1;
        }
 
-       while(rlm_sql_fetch_row(sqlsocket, inst) == 0) {
+       while(rlm_sql_fetch_row(&handle, inst) == 0) {
                i++;
-               row = sqlsocket->row;
+               row = handle->row;
                if (row == NULL)
                        break;
-       /*
-        *  The return data for each row MUST be in the following order:
-        *
-        *  0. Row ID (currently unused)
-        *  1. Name (or IP address)
-        *  2. Shortname
-        *  3. Type
-        *  4. Secret
-        *  5. Virtual Server (optional)
-        */
+               /*
+                *  The return data for each row MUST be in the following order:
+                *
+                *  0. Row ID (currently unused)
+                *  1. Name (or IP address)
+                *  2. Shortname
+                *  3. Type
+                *  4. Secret
+                *  5. Virtual Server (optional)
+                */
                if (!row[0]){
                        radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i);
                        continue;
@@ -334,8 +314,7 @@ static int generate_sql_clients(SQL_INST *inst)
                DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name,
                        row[1],row[2],row[4]);
 
-               c = rad_malloc(sizeof(*c));
-               memset(c, 0, sizeof(*c));
+               c = talloc_zero(inst, RADCLIENT);
 
 #ifdef WITH_DYNAMIC_CLIENTS
                c->dynamic = 1;
@@ -351,7 +330,7 @@ static int generate_sql_clients(SQL_INST *inst)
                        if ((c->prefix < 0) || (c->prefix > 128)) {
                                radlog(L_ERR, "rlm_sql (%s): Invalid Prefix value '%s' for IP.",
                                       inst->config->xlat_name, prefix_ptr + 1);
-                               free(c);
+                               talloc_free(c);
                                continue;
                        }
                        /* Replace '/' with '\0' */
@@ -362,15 +341,15 @@ static int generate_sql_clients(SQL_INST *inst)
                 *      Always get the numeric representation of IP
                 */
                if (ip_hton(row[1], AF_UNSPEC, &c->ipaddr) < 0) {
-                       radlog(L_CONS|L_ERR, "rlm_sql (%s): Failed to look up hostname %s: %s",
+                       radlog(L_ERR, "rlm_sql (%s): Failed to look up hostname %s: %s",
                               inst->config->xlat_name,
                               row[1], fr_strerror());
-                       free(c);
+                       talloc_free(c);
                        continue;
                } else {
                        char buffer[256];
                        ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
-                       c->longname = strdup(buffer);
+                       c->longname = talloc_strdup(c, buffer);
                }
 
                if (c->prefix < 0) switch (c->ipaddr.af) {
@@ -387,18 +366,19 @@ static int generate_sql_clients(SQL_INST *inst)
                /*
                 *      Other values (secret, shortname, nastype, virtual_server)
                 */
-               c->secret = strdup(row[4]);
-               c->shortname = strdup(row[2]);
+               c->secret = talloc_strdup(c, row[4]);
+               c->shortname = talloc_strdup(c, row[2]);
                if(row[3] != NULL)
                        c->nastype = strdup(row[3]);
 
-               numf = (inst->module->sql_num_fields)(sqlsocket, inst->config);
-               if ((numf > 5) && (row[5] != NULL)) c->server = strdup(row[5]);
+               numf = (inst->module->sql_num_fields)(handle, inst->config);
+               if ((numf > 5) && (row[5] != NULL) && *row[5]) c->server = strdup(row[5]);
 
                DEBUG("rlm_sql (%s): Adding client %s (%s, server=%s) to clients list",
                      inst->config->xlat_name,
                      c->longname,c->shortname, c->server ? c->server : "<none>");
                if (!client_add(NULL, c)) {
+                       sql_release_socket(inst, handle);
                        DEBUG("rlm_sql (%s): Failed to add client %s (%s) to clients list.  Maybe there's a duplicate?",
                              inst->config->xlat_name,
                              c->longname,c->shortname);
@@ -406,8 +386,8 @@ static int generate_sql_clients(SQL_INST *inst)
                        return -1;
                }
        }
-       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-       sql_release_socket(inst, sqlsocket);
+       (inst->module->sql_finish_select_query)(handle, inst->config);
+       sql_release_socket(inst, handle);
 
        return 0;
 }
@@ -416,8 +396,10 @@ static int generate_sql_clients(SQL_INST *inst)
 /*
  *     Translate the SQL queries.
  */
-static size_t sql_escape_func(char *out, size_t outlen, const char *in)
+static size_t sql_escape_func(UNUSED REQUEST *request, char *out, size_t outlen,
+                             const char *in, void *arg)
 {
+       rlm_sql_t *inst = arg;
        size_t len = 0;
 
        while (in[0]) {
@@ -426,7 +408,7 @@ static size_t sql_escape_func(char *out, size_t outlen, const char *in)
                 *      mime-encoded equivalents.
                 */
                if ((in[0] < 32) ||
-                   strchr(allowed_chars, *in) == NULL) {
+                   strchr(inst->config->allowed_chars, *in) == NULL) {
                        /*
                         *      Only 3 or less bytes available.
                         */
@@ -470,45 +452,42 @@ static size_t sql_escape_func(char *out, size_t outlen, const char *in)
  *     escape it twice. (it will make things wrong if we have an
  *     escape candidate character in the username)
  */
-int sql_set_user(SQL_INST *inst, REQUEST *request, char *sqlusername, const char *username)
+int sql_set_user(rlm_sql_t *inst, REQUEST *request, const char *username)
 {
-       VALUE_PAIR *vp=NULL;
-       char tmpuser[MAX_STRING_LEN];
-
-       tmpuser[0] = '\0';
-       sqlusername[0]= '\0';
-
-       /* Remove any user attr we added previously */
-       pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
+       char buffer[254];
+       VALUE_PAIR *vp = NULL;
+       const char *sqluser;
+       size_t len;
 
        if (username != NULL) {
-               strlcpy(tmpuser, username, sizeof(tmpuser));
-       } else if (strlen(inst->config->query_user)) {
-               radius_xlat(tmpuser, sizeof(tmpuser), inst->config->query_user, request, NULL);
+               sqluser = username;
+       } else if (*inst->config->query_user) {
+               sqluser = inst->config->query_user;
        } else {
                return 0;
        }
-
-       strlcpy(sqlusername, tmpuser, MAX_STRING_LEN);
-       RDEBUG2("sql_set_user escaped user --> '%s'", sqlusername);
-       vp = radius_pairmake(request, &request->packet->vps,
-                            "SQL-User-Name", NULL, 0);
-       if (!vp) {
-               radlog(L_ERR, "%s", fr_strerror());
+       
+       len = radius_xlat(buffer, sizeof(buffer), sqluser, request, NULL, NULL);
+       if (!len) {
                return -1;
        }
-
-       strlcpy(vp->vp_strvalue, tmpuser, sizeof(vp->vp_strvalue));
+       
+       vp = pairalloc(NULL, inst->sql_user);
+       vp->op = T_OP_SET;
+       
+       strlcpy(vp->vp_strvalue, buffer, sizeof(vp->vp_strvalue));
        vp->length = strlen(vp->vp_strvalue);
+       pairadd(&request->packet->vps, vp);
 
-       return 0;
+       RDEBUG2("SQL-User-Name updated");
 
+       return 0;
 }
 
 
-static void sql_grouplist_free (SQL_GROUPLIST **group_list)
+static void sql_grouplist_free (rlm_sql_grouplist_t **group_list)
 {
-       SQL_GROUPLIST *last;
+       rlm_sql_grouplist_t *last;
 
        while(*group_list) {
                last = *group_list;
@@ -518,12 +497,12 @@ static void sql_grouplist_free (SQL_GROUPLIST **group_list)
 }
 
 
-static int sql_get_grouplist (SQL_INST *inst, SQLSOCK *sqlsocket, REQUEST *request, SQL_GROUPLIST **group_list)
+static int sql_get_grouplist (rlm_sql_t *inst, rlm_sql_handle_t *handle, REQUEST *request, rlm_sql_grouplist_t **group_list)
 {
        char    querystr[MAX_QUERY_LEN];
        int     num_groups = 0;
-       SQL_ROW row;
-       SQL_GROUPLIST   *group_list_tmp;
+       rlm_sql_row_t row;
+       rlm_sql_grouplist_t   *group_list_tmp;
 
        /* NOTE: sql_set_user should have been run before calling this function */
 
@@ -533,42 +512,38 @@ static int sql_get_grouplist (SQL_INST *inst, SQLSOCK *sqlsocket, REQUEST *reque
            (inst->config->groupmemb_query[0] == 0))
                return 0;
 
-       if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, request, sql_escape_func)) {
+       if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, request, sql_escape_func, inst)) {
                radlog_request(L_ERR, 0, request, "xlat \"%s\" failed.",
                               inst->config->groupmemb_query);
                return -1;
        }
 
-       if (rlm_sql_select_query(sqlsocket, inst, querystr) < 0) {
-               radlog_request(L_ERR, 0, request,
-                              "database query error, %s: %s",
-                              querystr,
-                      (inst->module->sql_error)(sqlsocket,inst->config));
+       if (rlm_sql_select_query(&handle, inst, querystr) < 0) {
                return -1;
        }
-       while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {
-               row = sqlsocket->row;
+       while (rlm_sql_fetch_row(&handle, inst) == 0) {
+               row = handle->row;
                if (row == NULL)
                        break;
                if (row[0] == NULL){
                        RDEBUG("row[0] returned NULL");
-                       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
+                       (inst->module->sql_finish_select_query)(handle, inst->config);
                        sql_grouplist_free(group_list);
                        return -1;
                }
                if (*group_list == NULL) {
-                       *group_list = rad_malloc(sizeof(SQL_GROUPLIST));
+                       *group_list = rad_malloc(sizeof(rlm_sql_grouplist_t));
                        group_list_tmp = *group_list;
                } else {
                        rad_assert(group_list_tmp != NULL);
-                       group_list_tmp->next = rad_malloc(sizeof(SQL_GROUPLIST));
+                       group_list_tmp->next = rad_malloc(sizeof(rlm_sql_grouplist_t));
                        group_list_tmp = group_list_tmp->next;
                }
                group_list_tmp->next = NULL;
                strlcpy(group_list_tmp->groupname, row[0], MAX_STRING_LEN);
        }
 
-       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
+       (inst->module->sql_finish_select_query)(handle, inst->config);
 
        return num_groups;
 }
@@ -584,17 +559,16 @@ static int sql_get_grouplist (SQL_INST *inst, SQLSOCK *sqlsocket, REQUEST *reque
 static int sql_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp, VALUE_PAIR *check,
                        VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
 {
-       SQLSOCK *sqlsocket;
-       SQL_INST *inst = instance;
-       char sqlusername[MAX_STRING_LEN];
-       SQL_GROUPLIST *group_list, *group_list_tmp;
+       rlm_sql_handle_t *handle;
+       rlm_sql_t *inst = instance;
+       rlm_sql_grouplist_t *group_list, *group_list_tmp;
 
        check_pairs = check_pairs;
        reply_pairs = reply_pairs;
        request_vp = request_vp;
 
        RDEBUG("sql_groupcmp");
-       if (!check || !check->vp_strvalue || !check->length){
+       if (!check || !check->length){
                RDEBUG("sql_groupcmp: Illegal group name");
                return 1;
        }
@@ -603,30 +577,26 @@ static int sql_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp
                return 1;
        }
        /*
-        * Set, escape, and check the user attr here
+        *      Set, escape, and check the user attr here
         */
-       if (sql_set_user(inst, request, sqlusername, NULL) < 0)
+       if (sql_set_user(inst, request, NULL) < 0)
                return 1;
 
        /*
         *      Get a socket for this lookup
         */
-       sqlsocket = sql_get_socket(inst);
-       if (sqlsocket == NULL) {
-               /* Remove the username we (maybe) added above */
-               pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
+       handle = sql_get_socket(inst);
+       if (handle == NULL) {
                return 1;
        }
 
        /*
         *      Get the list of groups this user is a member of
         */
-       if (sql_get_grouplist(inst, sqlsocket, request, &group_list) < 0) {
+       if (sql_get_grouplist(inst, handle, request, &group_list) < 0) {
                radlog_request(L_ERR, 0, request,
                               "Error getting group membership");
-               /* Remove the username we (maybe) added above */
-               pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-               sql_release_socket(inst, sqlsocket);
+               sql_release_socket(inst, handle);
                return 1;
        }
 
@@ -636,18 +606,14 @@ static int sql_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp
                               check->vp_strvalue);
                        /* Free the grouplist */
                        sql_grouplist_free(&group_list);
-                       /* Remove the username we (maybe) added above */
-                       pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-                       sql_release_socket(inst, sqlsocket);
+                       sql_release_socket(inst, handle);
                        return 0;
                }
        }
 
        /* Free the grouplist */
        sql_grouplist_free(&group_list);
-       /* Remove the username we (maybe) added above */
-       pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-       sql_release_socket(inst,sqlsocket);
+       sql_release_socket(inst,handle);
 
        RDEBUG("sql_groupcmp finished: User is NOT a member of group %s",
               check->vp_strvalue);
@@ -657,11 +623,11 @@ static int sql_groupcmp(void *instance, REQUEST *request, VALUE_PAIR *request_vp
 
 
 
-static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sqlsocket, int *dofallthrough)
+static int rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle, int *dofallthrough)
 {
        VALUE_PAIR *check_tmp = NULL;
        VALUE_PAIR *reply_tmp = NULL;
-       SQL_GROUPLIST *group_list, *group_list_tmp;
+       rlm_sql_grouplist_t *group_list, *group_list_tmp;
        VALUE_PAIR *sql_group = NULL;
        char    querystr[MAX_QUERY_LEN];
        int found = 0;
@@ -670,7 +636,7 @@ static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sql
        /*
         *      Get the list of groups this user is a member of
         */
-       if (sql_get_grouplist(inst, sqlsocket, request, &group_list) < 0) {
+       if (sql_get_grouplist(inst, handle, request, &group_list) < 0) {
                radlog_request(L_ERR, 0, request, "Error retrieving group list");
                return -1;
        }
@@ -684,23 +650,26 @@ static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sql
                if (!sql_group) {
                        radlog_request(L_ERR, 0, request,
                                       "Error creating Sql-Group attribute");
+                       sql_grouplist_free(&group_list);
                        return -1;
                }
                pairadd(&request->packet->vps, sql_group);
-               if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func)) {
+               if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func, inst)) {
                        radlog_request(L_ERR, 0, request,
                                       "Error generating query; rejecting user");
                        /* Remove the grouup we added above */
-                       pairdelete(&request->packet->vps, PW_SQL_GROUP);
+                       pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
+                       sql_grouplist_free(&group_list);
                        return -1;
                }
-               rows = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr);
+               rows = sql_getvpdata(inst, &handle, &check_tmp, querystr);
                if (rows < 0) {
                        radlog_request(L_ERR, 0, request, "Error retrieving check pairs for group %s",
                               group_list_tmp->groupname);
                        /* Remove the grouup we added above */
-                       pairdelete(&request->packet->vps, PW_SQL_GROUP);
+                       pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
                        pairfree(&check_tmp);
+                       sql_grouplist_free(&group_list);
                        return -1;
                } else if (rows > 0) {
                        /*
@@ -713,25 +682,27 @@ static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sql
                                /*
                                 *      Now get the reply pairs since the paircompare matched
                                 */
-                               if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func)) {
+                               if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func, inst)) {
                                        radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
                                        /* Remove the grouup we added above */
-                                       pairdelete(&request->packet->vps, PW_SQL_GROUP);
+                                       pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
                                        pairfree(&check_tmp);
+                                       sql_grouplist_free(&group_list);
                                        return -1;
                                }
-                               if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
+                               if (sql_getvpdata(inst, &handle, &reply_tmp, querystr) < 0) {
                                        radlog_request(L_ERR, 0, request, "Error retrieving reply pairs for group %s",
                                               group_list_tmp->groupname);
                                        /* Remove the grouup we added above */
-                                       pairdelete(&request->packet->vps, PW_SQL_GROUP);
+                                       pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
                                        pairfree(&check_tmp);
                                        pairfree(&reply_tmp);
+                                       sql_grouplist_free(&group_list);
                                        return -1;
                                }
                                *dofallthrough = fallthrough(reply_tmp);
-                               pairxlatmove(request, &request->reply->vps, &reply_tmp);
-                               pairxlatmove(request, &request->config_items, &check_tmp);
+                               radius_xlat_move(request, &request->reply->vps, &reply_tmp);
+                               radius_xlat_move(request, &request->config_items, &check_tmp);
                        }
                } else {
                        /*
@@ -746,32 +717,34 @@ static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sql
                        /*
                         *      Now get the reply pairs since the paircompare matched
                         */
-                       if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func)) {
+                       if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func, inst)) {
                                radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
                                /* Remove the grouup we added above */
-                               pairdelete(&request->packet->vps, PW_SQL_GROUP);
+                               pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
                                pairfree(&check_tmp);
+                               sql_grouplist_free(&group_list);
                                return -1;
                        }
-                       if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
+                       if (sql_getvpdata(inst, &handle, &reply_tmp, querystr) < 0) {
                                radlog_request(L_ERR, 0, request, "Error retrieving reply pairs for group %s",
                                       group_list_tmp->groupname);
                                /* Remove the grouup we added above */
-                               pairdelete(&request->packet->vps, PW_SQL_GROUP);
+                               pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
                                pairfree(&check_tmp);
                                pairfree(&reply_tmp);
+                               sql_grouplist_free(&group_list);
                                return -1;
                        }
                        *dofallthrough = fallthrough(reply_tmp);
-                       pairxlatmove(request, &request->reply->vps, &reply_tmp);
-                       pairxlatmove(request, &request->config_items, &check_tmp);
+                       radius_xlat_move(request, &request->reply->vps, &reply_tmp);
+                       radius_xlat_move(request, &request->config_items, &check_tmp);
                }
 
                /*
                 * Delete the Sql-Group we added above
                 * And clear out the pairlists
                 */
-               pairdelete(&request->packet->vps, PW_SQL_GROUP);
+               pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
                pairfree(&check_tmp);
                pairfree(&reply_tmp);
        }
@@ -783,52 +756,16 @@ static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sql
 
 static int rlm_sql_detach(void *instance)
 {
-       SQL_INST *inst = instance;
+       rlm_sql_t *inst = instance;
 
        paircompare_unregister(PW_SQL_GROUP, sql_groupcmp);
-
+       
        if (inst->config) {
-               int i;
-
-               if (inst->sqlpool) {
-                       sql_poolfree(inst);
-               }
+               if (inst->pool) sql_poolfree(inst);
 
                if (inst->config->xlat_name) {
-                       xlat_unregister(inst->config->xlat_name,(RAD_XLAT_FUNC)sql_xlat);
-                       free(inst->config->xlat_name);
-               }
-
-               /*
-                *      Free up dynamically allocated string pointers.
-                */
-               for (i = 0; module_config[i].name != NULL; i++) {
-                       char **p;
-                       if (module_config[i].type != PW_TYPE_STRING_PTR) {
-                               continue;
-                       }
-
-                       /*
-                        *      Treat 'config' as an opaque array of bytes,
-                        *      and take the offset into it.  There's a
-                        *      (char*) pointer at that offset, and we want
-                        *      to point to it.
-                        */
-                       p = (char **) (((char *)inst->config) + module_config[i].offset);
-                       if (!*p) { /* nothing allocated */
-                               continue;
-                       }
-                       free(*p);
-                       *p = NULL;
-               }
-               /*
-                *      Catch multiple instances of the module.
-                */
-               if (allowed_chars == inst->config->allowed_chars) {
-                       allowed_chars = NULL;
+                       xlat_unregister(inst->config->xlat_name, sql_xlat, instance);
                }
-               free(inst->config);
-               inst->config = NULL;
        }
 
        if (inst->handle) {
@@ -839,524 +776,519 @@ static int rlm_sql_detach(void *instance)
                lt_dlclose(inst->handle);       /* ignore any errors */
 #endif
        }
-       free(inst);
 
        return 0;
 }
-static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
+
+static int parse_sub_section(CONF_SECTION *parent, 
+                            rlm_sql_t *inst,
+                            sql_acct_section_t **config,
+                            rlm_components_t comp)
 {
-       SQL_INST *inst;
-       const char *xlat_name;
+       CONF_SECTION *cs;
+
+       const char *name = section_type_value[comp].section;
+       
+       cs = cf_section_sub_find(parent, name);
+       if (!cs) {
+               radlog(L_INFO, "rlm_sql (%s): Couldn't find configuration for "
+                      "%s, will return NOOP for calls from this section",
+                      inst->config->xlat_name, name);
+               
+               return 0;
+       }
+       
+       *config = talloc_zero(parent, sql_acct_section_t);
+       if (cf_section_parse(cs, *config, acct_section_config) < 0) {
+               radlog(L_ERR, "rlm_sql (%s): Couldn't find configuration for "
+                      "%s, will return NOOP for calls from this section",
+                      inst->config->xlat_name, name);
+               return -1;
+       }
+               
+       (*config)->cs = cs;
 
-       inst = rad_malloc(sizeof(SQL_INST));
-       memset(inst, 0, sizeof(SQL_INST));
+       return 0;
+}
 
-       inst->config = rad_malloc(sizeof(SQL_CONFIG));
-       memset(inst->config, 0, sizeof(SQL_CONFIG));
+static int rlm_sql_instantiate(CONF_SECTION *conf, void **instance)
+{
+       rlm_sql_t *inst;
+       const char *xlat_name;
 
+       *instance = inst = talloc_zero(conf, rlm_sql_t);
+       if (!inst) return -1;
+       
        /*
-        *      Export these methods, too.  This avoids RTDL_GLOBAL.
+        *      Cache the SQL-User-Name DICT_ATTR, so we can be slightly
+        *      more efficient about creating SQL-User-Name attributes.
         */
-       inst->sql_set_user = sql_set_user;
-       inst->sql_get_socket = sql_get_socket;
-       inst->sql_release_socket = sql_release_socket;
-       inst->sql_escape_func = sql_escape_func;
-       inst->sql_query = rlm_sql_query;
-       inst->sql_select_query = rlm_sql_select_query;
-       inst->sql_fetch_row = rlm_sql_fetch_row;
+       inst->sql_user = dict_attrbyname("SQL-User-Name");
+       if (!inst->sql_user) return -1;
 
        /*
-        * If the configuration parameters can't be parsed, then
-        * fail.
+        *      Export these methods, too.  This avoids RTDL_GLOBAL.
         */
-       if (cf_section_parse(conf, inst->config, module_config) < 0) {
-               rlm_sql_detach(inst);
-               return -1;
-       }
+       inst->sql_set_user              = sql_set_user;
+       inst->sql_get_socket            = sql_get_socket;
+       inst->sql_release_socket        = sql_release_socket;
+       inst->sql_escape_func           = sql_escape_func;
+       inst->sql_query                 = rlm_sql_query;
+       inst->sql_select_query          = rlm_sql_select_query;
+       inst->sql_fetch_row             = rlm_sql_fetch_row;
+       
+       inst->config = talloc_zero(inst, rlm_sql_config_t);
+       inst->cs = conf;
 
        xlat_name = cf_section_name2(conf);
-       if (xlat_name == NULL)
+       if (xlat_name == NULL) {
                xlat_name = cf_section_name1(conf);
-       if (xlat_name){
-               inst->config->xlat_name = strdup(xlat_name);
-               xlat_register(xlat_name, (RAD_XLAT_FUNC)sql_xlat, inst);
+       } else {
+               char *group_name;
+               const DICT_ATTR *dattr;
+               ATTR_FLAGS flags;
+
+               /*
+                *      Allocate room for <instance>-SQL-Group
+                */
+               group_name = talloc_asprintf(inst, "%s-SQL-Group", xlat_name);
+               DEBUG("rlm_sql (%s): Creating new attribute %s",
+                     xlat_name, group_name);
+
+               memset(&flags, 0, sizeof(flags));
+               if (dict_addattr(group_name, -1, 0, PW_TYPE_STRING, flags) < 0) {
+                       radlog(L_ERR, "rlm_sql (%s): Failed to create "
+                              "attribute %s: %s", xlat_name, group_name,
+                              fr_strerror());
+                       return -1;
+               }
+
+               dattr = dict_attrbyname(group_name);
+               if (!dattr) {
+                       radlog(L_ERR, "rlm_sql (%s): Failed to create "
+                              "attribute %s", xlat_name, group_name);
+                       return -1;
+               }
+
+               if (inst->config->groupmemb_query && 
+                   inst->config->groupmemb_query[0]) {
+                       DEBUG("rlm_sql (%s): Registering sql_groupcmp for %s",
+                             xlat_name, group_name);
+                       paircompare_register(dattr->attr, PW_USER_NAME,
+                                            sql_groupcmp, inst);
+               }
        }
+       
+       rad_assert(xlat_name);
 
-       if (inst->config->num_sql_socks > MAX_SQL_SOCKS) {
-               radlog(L_ERR, "rlm_sql (%s): sql_instantiate: number of sqlsockets cannot exceed MAX_SQL_SOCKS, %d",
-                      inst->config->xlat_name, MAX_SQL_SOCKS);
-               rlm_sql_detach(inst);
+       /*
+        *      Register the SQL xlat function
+        */
+       inst->config->xlat_name = talloc_strdup(inst->config, xlat_name);
+       xlat_register(xlat_name, sql_xlat, inst);
+
+       /*
+        *      If the configuration parameters can't be parsed, then fail.
+        */
+       if ((cf_section_parse(conf, inst->config, module_config) < 0) ||
+           (parse_sub_section(conf, inst,
+                              &inst->config->accounting,
+                              RLM_COMPONENT_ACCT) < 0) ||
+           (parse_sub_section(conf, inst,
+                              &inst->config->postauth,
+                              RLM_COMPONENT_POST_AUTH) < 0)) {
+               radlog(L_ERR, "rlm_sql (%s): Failed parsing configuration",
+                      inst->config->xlat_name);
                return -1;
        }
-
+               
        /*
         *      Sanity check for crazy people.
         */
        if (strncmp(inst->config->sql_driver, "rlm_sql_", 8) != 0) {
-               radlog(L_ERR, "\"%s\" is NOT an SQL driver!",
-                      inst->config->sql_driver);
-               rlm_sql_detach(inst);
+               radlog(L_ERR, "rlm_sql (%s): \"%s\" is NOT an SQL driver!",
+                      inst->config->xlat_name, inst->config->sql_driver);
                return -1;
        }
 
+       /*
+        *      Load the appropriate driver for our database
+        */
        inst->handle = lt_dlopenext(inst->config->sql_driver);
        if (inst->handle == NULL) {
                radlog(L_ERR, "Could not link driver %s: %s",
                       inst->config->sql_driver,
                       lt_dlerror());
-               radlog(L_ERR, "Make sure it (and all its dependent libraries!) are in the search path of your system's ld.");
-               rlm_sql_detach(inst);
+               radlog(L_ERR, "Make sure it (and all its dependent libraries!)"
+                      "are in the search path of your system's ld.");
                return -1;
        }
 
-       inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle, inst->config->sql_driver);
+       inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle,
+                                                    inst->config->sql_driver);
        if (!inst->module) {
                radlog(L_ERR, "Could not link symbol %s: %s",
                       inst->config->sql_driver,
                       lt_dlerror());
-               rlm_sql_detach(inst);
                return -1;
        }
 
        radlog(L_INFO, "rlm_sql (%s): Driver %s (module %s) loaded and linked",
               inst->config->xlat_name, inst->config->sql_driver,
               inst->module->name);
+
+       /*
+        *      Initialise the connection pool for this instance
+        */
        radlog(L_INFO, "rlm_sql (%s): Attempting to connect to %s@%s:%s/%s",
               inst->config->xlat_name, inst->config->sql_login,
               inst->config->sql_server, inst->config->sql_port,
               inst->config->sql_db);
+              
+       if (sql_init_socketpool(inst) < 0) return -1;
 
-       if (sql_init_socketpool(inst) < 0) {
-               rlm_sql_detach(inst);
-               return -1;
+       if (inst->config->groupmemb_query && 
+           inst->config->groupmemb_query[0]) {
+               paircompare_register(PW_SQL_GROUP, PW_USER_NAME, sql_groupcmp, inst);
        }
 
-       paircompare_register(PW_SQL_GROUP, PW_USER_NAME, sql_groupcmp, inst);
-
-       if (inst->config->do_clients){
+       if (inst->config->do_clients) {
                if (generate_sql_clients(inst) == -1){
                        radlog(L_ERR, "Failed to load clients from SQL.");
-                       rlm_sql_detach(inst);
                        return -1;
                }
        }
-       allowed_chars = inst->config->allowed_chars;
-
-       *instance = inst;
 
        return RLM_MODULE_OK;
 }
 
 
-static int rlm_sql_authorize(void *instance, REQUEST * request)
+static rlm_rcode_t rlm_sql_authorize(void *instance, REQUEST * request)
 {
+       int ret = RLM_MODULE_NOTFOUND;
+       
+       rlm_sql_t *inst = instance;
+       rlm_sql_handle_t  *handle;
+       
        VALUE_PAIR *check_tmp = NULL;
        VALUE_PAIR *reply_tmp = NULL;
        VALUE_PAIR *user_profile = NULL;
-       int     found = 0;
+
        int     dofallthrough = 1;
        int     rows;
-       SQLSOCK *sqlsocket;
-       SQL_INST *inst = instance;
-       char    querystr[MAX_QUERY_LEN];
-       char    sqlusername[MAX_STRING_LEN];
-       /*
-        * the profile username is used as the sqlusername during
-        * profile checking so that we don't overwrite the orignal
-        * sqlusername string
-        */
-       char   profileusername[MAX_STRING_LEN];
-
-       /*
-        * Set, escape, and check the user attr here
-        */
-       if (sql_set_user(inst, request, sqlusername, NULL) < 0)
-               return RLM_MODULE_FAIL;
 
+       char    querystr[MAX_QUERY_LEN];
 
        /*
-        * reserve a socket
+        *  Set, escape, and check the user attr here
         */
-       sqlsocket = sql_get_socket(inst);
-       if (sqlsocket == NULL) {
-               /* Remove the username we (maybe) added above */
-               pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
+       if (sql_set_user(inst, request, NULL) < 0)
                return RLM_MODULE_FAIL;
-       }
-
 
        /*
-        *  After this point, ALL 'return's MUST release the SQL socket!
+        *  Reserve a socket 
+        *
+        *  After this point use goto error or goto release to cleanup sockets
+        *  temporary pairlists and temporary attributes.
         */
+       handle = sql_get_socket(inst);
+       if (handle == NULL)
+               goto error;
 
        /*
-        * Alright, start by getting the specific entry for the user
+        *  Query the check table to find any conditions associated with 
+        *  this user/realm/whatever...
         */
-       if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func)) {
-               radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
-               sql_release_socket(inst, sqlsocket);
-               /* Remove the username we (maybe) added above */
-               pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-               return RLM_MODULE_FAIL;
-       }
-       rows = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr);
-       if (rows < 0) {
-               radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
-               sql_release_socket(inst, sqlsocket);
-               /* Remove the username we (maybe) added above */
-               pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-               pairfree(&check_tmp);
-               return RLM_MODULE_FAIL;
-       } else if (rows > 0) {
+       if (inst->config->authorize_check_query &&
+           *inst->config->authorize_check_query) {
+               if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func, inst)) {
+                       radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
+       
+                       goto error;
+               }
+               
+               rows = sql_getvpdata(inst, &handle, &check_tmp, querystr);
+               if (rows < 0) {
+                       radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
+       
+                       goto error;
+               }
+               
                /*
-                *      Only do this if *some* check pairs were returned
+                *  Only do this if *some* check pairs were returned
                 */
-               if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) {
-                       found = 1;
+               if ((rows > 0) && 
+                   (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0)) {       
                        RDEBUG2("User found in radcheck table");
+                       
+                       radius_xlat_move(request, &request->config_items, &check_tmp);
+                       
+                       ret = RLM_MODULE_OK;
+               }
+               
+               /*
+                *  We only process reply table items if check conditions
+                *  were verified
+                */
+               else
+                       goto skipreply;
+       }
+       
+       if (inst->config->authorize_reply_query &&
+           *inst->config->authorize_reply_query) {
+               /*
+                *  Now get the reply pairs since the paircompare matched
+                */
+               if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func, inst)) {
+                       radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
+                       
+                       goto error;
+               }
+               
+               rows = sql_getvpdata(inst, &handle, &reply_tmp, querystr);
+               if (rows < 0) {
+                       radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
 
-                       if (inst->config->authorize_reply_query &&
-                           *inst->config->authorize_reply_query) {
-
-                       /*
-                        *      Now get the reply pairs since the paircompare matched
-                        */
-                       if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func)) {
-                               radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
-                               sql_release_socket(inst, sqlsocket);
-                               /* Remove the username we (maybe) added above */
-                               pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-                               pairfree(&check_tmp);
-                               return RLM_MODULE_FAIL;
-                       }
-                       if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
-                               radlog_request(L_ERR, 0, request, "SQL query error; rejecting user");
-                               sql_release_socket(inst, sqlsocket);
-                               /* Remove the username we (maybe) added above */
-                               pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-                               pairfree(&check_tmp);
-                               pairfree(&reply_tmp);
-                               return RLM_MODULE_FAIL;
-                       }
-
+                       goto error;
+               }
+               
+               if (rows > 0) {
                        if (!inst->config->read_groups)
                                dofallthrough = fallthrough(reply_tmp);
-                       pairxlatmove(request, &request->reply->vps, &reply_tmp);
-                       }
-                       pairxlatmove(request, &request->config_items, &check_tmp);
+                               
+                       radius_xlat_move(request, &request->reply->vps, &reply_tmp);
+                       
+                       ret = RLM_MODULE_OK;
                }
        }
+       
+       skipreply:
 
        /*
-        *      Clear out the pairlists
+        *  Clear out the pairlists
         */
        pairfree(&check_tmp);
        pairfree(&reply_tmp);
 
        /*
-        *      dofallthrough is set to 1 by default so that if the user information
-        *      is not found, we will still process groups.  If the user information,
-        *      however, *is* found, Fall-Through must be set in order to process
-        *      the groups as well
+        *  dofallthrough is set to 1 by default so that if the user information
+        *  is not found, we will still process groups.  If the user information,
+        *  however, *is* found, Fall-Through must be set in order to process
+        *  the groups as well.
         */
        if (dofallthrough) {
-               rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough);
+               rows = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
                if (rows < 0) {
                        radlog_request(L_ERR, 0, request, "Error processing groups; rejecting user");
-                       sql_release_socket(inst, sqlsocket);
-                       /* Remove the username we (maybe) added above */
-                       pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-                       return RLM_MODULE_FAIL;
-               } else if (rows > 0) {
-                       found = 1;
+
+                       goto error;
                }
+               
+               if (rows > 0)
+                       ret = RLM_MODULE_OK;
        }
 
        /*
-        *      repeat the above process with the default profile or User-Profile
+        *  Repeat the above process with the default profile or User-Profile
         */
        if (dofallthrough) {
-               int profile_found = 0;
                /*
-               * Check for a default_profile or for a User-Profile.
-               */
-               user_profile = pairfind(request->config_items, PW_USER_PROFILE);
-               if (inst->config->default_profile[0] != 0 || user_profile != NULL){
-                       char *profile = inst->config->default_profile;
-
-                       if (user_profile != NULL)
-                               profile = user_profile->vp_strvalue;
-                       if (profile && strlen(profile)){
-                               RDEBUG("Checking profile %s", profile);
-                               if (sql_set_user(inst, request, profileusername, profile) < 0) {
-                                       radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user");
-                                       sql_release_socket(inst, sqlsocket);
-                                       /* Remove the username we (maybe) added above */
-                                       pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-                                       return RLM_MODULE_FAIL;
-                               } else {
-                                       profile_found = 1;
-                               }
-                       }
-               }
+                *  Check for a default_profile or for a User-Profile.
+                */
+               user_profile = pairfind(request->config_items, PW_USER_PROFILE, 0, TAG_ANY);
+               
+               const char *profile = user_profile ?
+                                     user_profile->vp_strvalue :
+                                     inst->config->default_profile;
+                       
+               if (!profile || !*profile)
+                       goto release;
+                       
+               RDEBUG("Checking profile %s", profile);
+               
+               if (sql_set_user(inst, request, profile) < 0) {
+                       radlog_request(L_ERR, 0, request, "Error setting profile; rejecting user");
 
-               if (profile_found) {
-                       rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough);
-                       if (rows < 0) {
-                               radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user");
-                               sql_release_socket(inst, sqlsocket);
-                               /* Remove the username we (maybe) added above */
-                               pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-                               return RLM_MODULE_FAIL;
-                       } else if (rows > 0) {
-                               found = 1;
-                       }
+                       goto error;
                }
-       }
-
-       /* Remove the username we (maybe) added above */
-       pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
-       sql_release_socket(inst, sqlsocket);
+               
+               rows = rlm_sql_process_groups(inst, request, handle, &dofallthrough);
+               if (rows < 0) {
+                       radlog_request(L_ERR, 0, request, "Error processing profile groups; rejecting user");
 
-       if (!found) {
-               RDEBUG("User %s not found", sqlusername);
-               return RLM_MODULE_NOTFOUND;
-       } else {
-               return RLM_MODULE_OK;
+                       goto error;
+               }
+               
+               if (rows > 0)
+                       ret = RLM_MODULE_OK;
        }
+       
+       goto release;
+       
+       error:
+       ret = RLM_MODULE_FAIL;
+       
+       release:
+       sql_release_socket(inst, handle);
+               
+       pairfree(&check_tmp);
+       pairfree(&reply_tmp);
+       
+       return ret;
 }
 
 /*
- *     Accounting: save the account data to our sql table
+ *     Generic function for failing between a bunch of queries.
+ *
+ *     Uses the same principle as rlm_linelog, expanding the 'reference' config
+ *     item using xlat to figure out what query it should execute.
+ *
+ *     If the reference matches multiple config items, and a query fails or
+ *     doesn't update any rows, the next matching config item is used.
+ *  
  */
-static int rlm_sql_accounting(void *instance, REQUEST * request) {
-
-       SQLSOCK *sqlsocket = NULL;
-       VALUE_PAIR *pair;
-       SQL_INST *inst = instance;
+static int acct_redundant(rlm_sql_t *inst, REQUEST *request, 
+                         sql_acct_section_t *section)
+{
        int     ret = RLM_MODULE_OK;
-       int     numaffected = 0;
-       int     acctstatustype = 0;
-       char    querystr[MAX_QUERY_LEN];
-       char    logstr[MAX_QUERY_LEN];
-       char    sqlusername[MAX_STRING_LEN];
 
-#ifdef CISCO_ACCOUNTING_HACK
-       int     acctsessiontime = 0;
-#endif
+       rlm_sql_handle_t        *handle = NULL;
+       int     sql_ret;
+       int     numaffected = 0;
+
+       CONF_ITEM  *item;
+       CONF_PAIR  *pair;
+       const char *attr = NULL;
+       const char *value;
+
+       char    path[MAX_STRING_LEN];
+       char    querystr[MAX_QUERY_LEN];
+       
+       char    *p = path;
+
+       rad_assert(section);
+       
+       if (section->reference[0] != '.')
+               *p++ = '.';
+       
+       if (!radius_xlat(p, (sizeof(path) - (p - path)) - 1,
+                       section->reference, request, NULL, NULL))
+               return RLM_MODULE_FAIL;
 
-       memset(querystr, 0, MAX_QUERY_LEN);
+       item = cf_reference_item(NULL, section->cs, path);
+       if (!item)
+               return RLM_MODULE_FAIL;
 
-       /*
-        * Find the Acct Status Type
-        */
-       if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL) {
-               acctstatustype = pair->vp_integer;
-       } else {
-               radius_xlat(logstr, sizeof(logstr), "packet has no accounting status type. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
-               radlog_request(L_ERR, 0, request, "%s", logstr);
-               return RLM_MODULE_INVALID;
+       if (cf_item_is_section(item)){
+               radlog(L_ERR, "Sections are not supported as references");
+               
+               return RLM_MODULE_FAIL;
        }
+       
+       pair = cf_itemtopair(item);
+       attr = cf_pair_attr(pair);
+       
+       RDEBUG2("Using query template '%s'", attr);
+       
+       handle = sql_get_socket(inst);
+       if (handle == NULL)
+               return RLM_MODULE_FAIL;
+               
+       sql_set_user(inst, request, NULL);
+
+       while (TRUE) {
+               value = cf_pair_value(pair);
+               if (!value) {
+                       RDEBUG("Ignoring null query");
+                       ret = RLM_MODULE_NOOP;
+                       
+                       goto release;
+               }
+               
+               radius_xlat(querystr, sizeof(querystr), value, request,
+                           sql_escape_func, inst);
+               if (!*querystr) {
+                       RDEBUG("Ignoring null query");
+                       ret = RLM_MODULE_NOOP;
+                       
+                       goto release;
+               }
+               
+               rlm_sql_query_log(inst, request, section, querystr);
+               
+               /*
+                *  If rlm_sql_query cannot use the socket it'll try and
+                *  reconnect. Reconnecting will automatically release 
+                *  the current socket, and try to select a new one.
+                *
+                *  If we get SQL_DOWN it means all connections in the pool
+                *  were exhausted, and we couldn't create a new connection,
+                *  so we do not need to call sql_release_socket.
+                */
+               sql_ret = rlm_sql_query(&handle, inst, querystr);       
+               if (sql_ret == SQL_DOWN)
+                       return RLM_MODULE_FAIL;
+               
+               rad_assert(handle);
+       
+               /* 
+                *  Assume all other errors are incidental, and just meant our
+                *  operation failed and its not a client or SQL syntax error.
+                */
+               if (sql_ret == 0) {
+                       numaffected = (inst->module->sql_affected_rows)
+                                       (handle, inst->config);
+                       if (numaffected > 0)
+                               break;
+                               
+                       RDEBUG("No records updated");
+               }
 
-       switch (acctstatustype) {
-                       /*
-                        * The Terminal server informed us that it was rebooted
-                        * STOP all records from this NAS
-                        */
-               case PW_STATUS_ACCOUNTING_ON:
-               case PW_STATUS_ACCOUNTING_OFF:
-                       RDEBUG("Received Acct On/Off packet");
-                       radius_xlat(querystr, sizeof(querystr), inst->config->accounting_onoff_query, request, sql_escape_func);
-                       query_log(request, inst, querystr);
-
-                       sqlsocket = sql_get_socket(inst);
-                       if (sqlsocket == NULL)
-                               return(RLM_MODULE_FAIL);
-                       if (*querystr) { /* non-empty query */
-                               if (rlm_sql_query(sqlsocket, inst, querystr)) {
-                                       radlog_request(L_ERR, 0, request, "Couldn't update SQL accounting for Acct On/Off packet - %s",
-                                              (inst->module->sql_error)(sqlsocket, inst->config));
-                                       ret = RLM_MODULE_FAIL;
-                               }
-                               (inst->module->sql_finish_query)(sqlsocket, inst->config);
-                       }
-
-                       break;
-
-                       /*
-                        * Got an update accounting packet
-                        */
-               case PW_STATUS_ALIVE:
-
-                       /*
-                        * Set, escape, and check the user attr here
-                        */
-                       sql_set_user(inst, request, sqlusername, NULL);
-
-                       radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query, request, sql_escape_func);
-                       query_log(request, inst, querystr);
-
-                       sqlsocket = sql_get_socket(inst);
-                       if (sqlsocket == NULL)
-                               return(RLM_MODULE_FAIL);
-                       if (*querystr) { /* non-empty query */
-                               if (rlm_sql_query(sqlsocket, inst, querystr)) {
-                                       radlog_request(L_ERR, 0, request, "Couldn't update SQL accounting ALIVE record - %s",
-                                              (inst->module->sql_error)(sqlsocket, inst->config));
-                                       ret = RLM_MODULE_FAIL;
-                               }
-                               else {
-                                       numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
-                                       if (numaffected < 1) {
-
-                                               /*
-                                                * If our update above didn't match anything
-                                                * we assume it's because we haven't seen a
-                                                * matching Start record.  So we have to
-                                                * insert this update rather than do an update
-                                                */
-                                               radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query_alt, request, sql_escape_func);
-                                               query_log(request, inst, querystr);
-                                               if (*querystr) { /* non-empty query */
-                                                       if (rlm_sql_query(sqlsocket, inst, querystr)) {
-                                                               radlog_request(L_ERR, 0, request, "Couldn't insert SQL accounting ALIVE record - %s",
-                                                                      (inst->module->sql_error)(sqlsocket, inst->config));
-                                                               ret = RLM_MODULE_FAIL;
-                                                       }
-                                                       (inst->module->sql_finish_query)(sqlsocket, inst->config);
-                                               }
-                                       }
-                               }
-                               (inst->module->sql_finish_query)(sqlsocket, inst->config);
-                       }
-                       break;
-
-                       /*
-                        * Got accounting start packet
-                        */
-               case PW_STATUS_START:
-
-                       /*
-                        * Set, escape, and check the user attr here
-                        */
-                       sql_set_user(inst, request, sqlusername, NULL);
-
-                       radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query, request, sql_escape_func);
-                       query_log(request, inst, querystr);
-
-                       sqlsocket = sql_get_socket(inst);
-                       if (sqlsocket == NULL)
-                               return(RLM_MODULE_FAIL);
-                       if (*querystr) { /* non-empty query */
-                               if (rlm_sql_query(sqlsocket, inst, querystr)) {
-                                       radlog_request(L_ERR, 0, request, "Couldn't insert SQL accounting START record - %s",
-                                              (inst->module->sql_error)(sqlsocket, inst->config));
-
-                                       /*
-                                        * We failed the insert above.  It's probably because
-                                        * the stop record came before the start.  We try
-                                        * our alternate query now (typically an UPDATE)
-                                        */
-                                       radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query_alt, request, sql_escape_func);
-                                       query_log(request, inst, querystr);
-
-                                       if (*querystr) { /* non-empty query */
-                                               if (rlm_sql_query(sqlsocket, inst, querystr)) {
-                                                       radlog_request(L_ERR, 0, request, "Couldn't update SQL accounting START record - %s",
-                                                              (inst->module->sql_error)(sqlsocket, inst->config));
-                                                       ret = RLM_MODULE_FAIL;
-                                               }
-                                               (inst->module->sql_finish_query)(sqlsocket, inst->config);
-                                       }
-                               }
-                               (inst->module->sql_finish_query)(sqlsocket, inst->config);
-                       }
-                       break;
-
-                       /*
-                        * Got accounting stop packet
-                        */
-               case PW_STATUS_STOP:
+               (inst->module->sql_finish_query)(handle, inst->config);
+               
+               /*
+                *  We assume all entries with the same name form a redundant
+                *  set of queries.
+                */
+               pair = cf_pair_find_next(section->cs, pair, attr);
+               
+               if (!pair) {
+                       RDEBUG("No additional queries configured");
+                       
+                       ret = RLM_MODULE_NOOP;
+                       
+                       goto release;
+               }
 
-                       /*
-                        * Set, escape, and check the user attr here
-                        */
-                       sql_set_user(inst, request, sqlusername, NULL);
-
-                       radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query, request, sql_escape_func);
-                       query_log(request, inst, querystr);
-
-                       sqlsocket = sql_get_socket(inst);
-                       if (sqlsocket == NULL)
-                               return(RLM_MODULE_FAIL);
-                       if (*querystr) { /* non-empty query */
-                               if (rlm_sql_query(sqlsocket, inst, querystr)) {
-                                       radlog_request(L_ERR, 0, request, "Couldn't update SQL accounting STOP record - %s",
-                                              (inst->module->sql_error)(sqlsocket, inst->config));
-                                       ret = RLM_MODULE_FAIL;
-                               }
-                               else {
-                                       numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
-                                       if (numaffected < 1) {
-                                               /*
-                                                * If our update above didn't match anything
-                                                * we assume it's because we haven't seen a
-                                                * matching Start record.  So we have to
-                                                * insert this stop rather than do an update
-                                                */
-#ifdef CISCO_ACCOUNTING_HACK
-                                               /*
-                                                * If stop but zero session length AND no previous
-                                                * session found, drop it as in invalid packet
-                                                * This is to fix CISCO's aaa from filling our
-                                                * table with bogus crap
-                                                */
-                                               if ((pair = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME)) != NULL)
-                                                       acctsessiontime = pair->vp_integer;
-
-                                               if (acctsessiontime <= 0) {
-                                                       radius_xlat(logstr, sizeof(logstr), "stop packet with zero session length. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
-                                                       radlog_request(L_ERR, 0, request, "%s", logstr);
-                                                       sql_release_socket(inst, sqlsocket);
-                                                       ret = RLM_MODULE_NOOP;
-                                               }
-#endif
+               RDEBUG("Trying next query...");
+       }
+       
+       (inst->module->sql_finish_query)(handle, inst->config);
 
-                                               radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query_alt, request, sql_escape_func);
-                                               query_log(request, inst, querystr);
+       release:
+       sql_release_socket(inst, handle);
 
-                                               if (*querystr) { /* non-empty query */
-                                                       if (rlm_sql_query(sqlsocket, inst, querystr)) {
-                                                               radlog_request(L_ERR, 0, request, "Couldn't insert SQL accounting STOP record - %s",
+       return ret;
+}
 
-                                                                      (inst->module->sql_error)(sqlsocket, inst->config));
-                                                               ret = RLM_MODULE_FAIL;
-                                                       }
-                                                       (inst->module->sql_finish_query)(sqlsocket, inst->config);
-                                               }
-                                       }
-                               }
-                               (inst->module->sql_finish_query)(sqlsocket, inst->config);
-                       }
-                       break;
+#ifdef WITH_ACCOUNTING
 
-                       /*
-                        *      Anything else is ignored.
-                        */
-               default:
-                       RDEBUG("Unsupported Acct-Status-Type = %d",
-                      acctstatustype);
-                       return RLM_MODULE_NOOP;
-                       break;
+/*
+ *     Accounting: Insert or update session data in our sql table
+ */
+static rlm_rcode_t rlm_sql_accounting(void *instance, REQUEST * request) {
+       rlm_sql_t *inst = instance;             
 
+       if (inst->config->accounting) {
+               return acct_redundant(inst, request, inst->config->accounting); 
        }
-
-       sql_release_socket(inst, sqlsocket);
-
-       return ret;
+       
+       return RLM_MODULE_NOOP;
 }
 
+#endif
 
+#ifdef WITH_SESSION_MGMT
 /*
  *        See if a user is already logged in. Sets request->simul_count to the
  *        current session count for this user.
@@ -1366,12 +1298,11 @@ static int rlm_sql_accounting(void *instance, REQUEST * request) {
  *        logins by querying the terminal server (using eg. SNMP).
  */
 
-static int rlm_sql_checksimul(void *instance, REQUEST * request) {
-       SQLSOCK         *sqlsocket;
-       SQL_INST        *inst = instance;
-       SQL_ROW         row;
+static rlm_rcode_t rlm_sql_checksimul(void *instance, REQUEST * request) {
+       rlm_sql_handle_t        *handle;
+       rlm_sql_t       *inst = instance;
+       rlm_sql_row_t           row;
        char            querystr[MAX_QUERY_LEN];
-       char            sqlusername[MAX_STRING_LEN];
        int             check = 0;
         uint32_t        ipno = 0;
         char            *call_num = NULL;
@@ -1387,47 +1318,46 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
        }
 
        if((request->username == NULL) || (request->username->length == 0)) {
-               radlog_request(L_ERR, 0, request, "Zero Length username not permitted\n");
+               radlog_request(L_ERR, 0, request,
+                                          "Zero Length username not permitted\n");
                return RLM_MODULE_INVALID;
        }
 
 
-       if(sql_set_user(inst, request, sqlusername, NULL) < 0)
+       if(sql_set_user(inst, request, NULL) < 0)
                return RLM_MODULE_FAIL;
 
-       radius_xlat(querystr, sizeof(querystr), inst->config->simul_count_query, request, sql_escape_func);
+       radius_xlat(querystr, sizeof(querystr), inst->config->simul_count_query, request, sql_escape_func, inst);
 
        /* initialize the sql socket */
-       sqlsocket = sql_get_socket(inst);
-       if(sqlsocket == NULL)
+       handle = sql_get_socket(inst);
+       if(handle == NULL)
                return RLM_MODULE_FAIL;
 
-       if(rlm_sql_select_query(sqlsocket, inst, querystr)) {
-               radlog(L_ERR, "rlm_sql (%s) sql_checksimul: Database query failed", inst->config->xlat_name);
-               sql_release_socket(inst, sqlsocket);
+       if(rlm_sql_select_query(&handle, inst, querystr)) {
+               sql_release_socket(inst, handle);
                return RLM_MODULE_FAIL;
        }
 
-       ret = rlm_sql_fetch_row(sqlsocket, inst);
-
+       ret = rlm_sql_fetch_row(&handle, inst);
        if (ret != 0) {
-               (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-               sql_release_socket(inst, sqlsocket);
+               (inst->module->sql_finish_select_query)(handle, inst->config);
+               sql_release_socket(inst, handle);
                return RLM_MODULE_FAIL;
        }
 
-       row = sqlsocket->row;
+       row = handle->row;
        if (row == NULL) {
-               (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-               sql_release_socket(inst, sqlsocket);
+               (inst->module->sql_finish_select_query)(handle, inst->config);
+               sql_release_socket(inst, handle);
                return RLM_MODULE_FAIL;
        }
 
        request->simul_count = atoi(row[0]);
-       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
+       (inst->module->sql_finish_select_query)(handle, inst->config);
 
        if(request->simul_count < request->simul_max) {
-               sql_release_socket(inst, sqlsocket);
+               sql_release_socket(inst, handle);
                return RLM_MODULE_OK;
        }
 
@@ -1437,14 +1367,13 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
         */
        if (!inst->config->simul_verify_query ||
            (inst->config->simul_verify_query[0] == '\0')) {
-               sql_release_socket(inst, sqlsocket);
+               sql_release_socket(inst, handle);
                return RLM_MODULE_OK;
        }
 
-       radius_xlat(querystr, sizeof(querystr), inst->config->simul_verify_query, request, sql_escape_func);
-       if(rlm_sql_select_query(sqlsocket, inst, querystr)) {
-               radlog_request(L_ERR, 0, request, "Database query error");
-               sql_release_socket(inst, sqlsocket);
+       radius_xlat(querystr, sizeof(querystr), inst->config->simul_verify_query, request, sql_escape_func, inst);
+       if(rlm_sql_select_query(&handle, inst, querystr)) {
+               sql_release_socket(inst, handle);
                return RLM_MODULE_FAIL;
        }
 
@@ -1453,25 +1382,25 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
          */
        request->simul_count = 0;
 
-        if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL)
+        if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY)) != NULL)
                 ipno = vp->vp_ipaddr;
-        if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)
+        if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) != NULL)
                 call_num = vp->vp_strvalue;
 
 
-       while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {
-               row = sqlsocket->row;
+       while (rlm_sql_fetch_row(&handle, inst) == 0) {
+               row = handle->row;
                if (row == NULL)
                        break;
                if (!row[2]){
-                       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-                       sql_release_socket(inst, sqlsocket);
+                       (inst->module->sql_finish_select_query)(handle, inst->config);
+                       sql_release_socket(inst, handle);
                        RDEBUG("Cannot zap stale entry. No username present in entry.", inst->config->xlat_name);
                        return RLM_MODULE_FAIL;
                }
                if (!row[1]){
-                       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-                       sql_release_socket(inst, sqlsocket);
+                       (inst->module->sql_finish_select_query)(handle, inst->config);
+                       sql_release_socket(inst, handle);
                        RDEBUG("Cannot zap stale entry. No session id in entry.", inst->config->xlat_name);
                        return RLM_MODULE_FAIL;
                }
@@ -1526,15 +1455,15 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
                         *      Failed to check the terminal server for
                         *      duplicate logins: return an error.
                         */
-                       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-                       sql_release_socket(inst, sqlsocket);
+                       (inst->module->sql_finish_select_query)(handle, inst->config);
+                       sql_release_socket(inst, handle);
                        radlog_request(L_ERR, 0, request, "Failed to check the terminal server for user '%s'.", row[2]);
                        return RLM_MODULE_FAIL;
                }
        }
 
-       (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
-       sql_release_socket(inst, sqlsocket);
+       (inst->module->sql_finish_select_query)(handle, inst->config);
+       sql_release_socket(inst, handle);
 
        /*
         *      The Auth module apparently looks at request->simul_count,
@@ -1543,51 +1472,26 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
         */
        return RLM_MODULE_OK;
 }
+#endif
 
 /*
- *     Execute postauth_query after authentication
+ *     Postauth: Write a record of the authentication attempt
  */
-static int rlm_sql_postauth(void *instance, REQUEST *request) {
-       SQLSOCK         *sqlsocket = NULL;
-       SQL_INST        *inst = instance;
-       char            querystr[MAX_QUERY_LEN];
-       char            sqlusername[MAX_STRING_LEN];
-
-       if(sql_set_user(inst, request, sqlusername, NULL) < 0)
-               return RLM_MODULE_FAIL;
-
-       /* If postauth_query is not defined, we stop here */
-       if (!inst->config->postauth_query ||
-           (inst->config->postauth_query[0] == '\0'))
-               return RLM_MODULE_NOOP;
-
-       /* Expand variables in the query */
-       memset(querystr, 0, MAX_QUERY_LEN);
-       radius_xlat(querystr, sizeof(querystr), inst->config->postauth_query,
-                   request, sql_escape_func);
-       query_log(request, inst, querystr);
-       DEBUG2("rlm_sql (%s) in sql_postauth: query is %s",
-              inst->config->xlat_name, querystr);
-
-       /* Initialize the sql socket */
-       sqlsocket = sql_get_socket(inst);
-       if (sqlsocket == NULL)
-               return RLM_MODULE_FAIL;
-
-       /* Process the query */
-       if (rlm_sql_query(sqlsocket, inst, querystr)) {
-               radlog(L_ERR, "rlm_sql (%s) in sql_postauth: Database query error - %s",
-                      inst->config->xlat_name,
-                      (inst->module->sql_error)(sqlsocket, inst->config));
-               sql_release_socket(inst, sqlsocket);
-               return RLM_MODULE_FAIL;
+static rlm_rcode_t rlm_sql_postauth(void *instance, REQUEST * request) {
+       rlm_sql_t *inst = instance;
+       
+       if (inst->config->postauth) {
+               return acct_redundant(inst, request, inst->config->postauth);
        }
-       (inst->module->sql_finish_query)(sqlsocket, inst->config);
-
-       sql_release_socket(inst, sqlsocket);
-       return RLM_MODULE_OK;
+       
+       return RLM_MODULE_NOOP; 
 }
 
+/*
+ *     Execute postauth_query after authentication
+ */
+
+
 /* globally exported name */
 module_t rlm_sql = {
        RLM_MODULE_INIT,
@@ -1599,8 +1503,16 @@ module_t rlm_sql = {
                NULL,                   /* authentication */
                rlm_sql_authorize,      /* authorization */
                NULL,                   /* preaccounting */
+#ifdef WITH_ACCOUNTING
                rlm_sql_accounting,     /* accounting */
+#else
+               NULL,
+#endif
+#ifdef WITH_SESSION_MGMT
                rlm_sql_checksimul,     /* checksimul */
+#else
+               NULL,
+#endif
                NULL,                   /* pre-proxy */
                NULL,                   /* post-proxy */
                rlm_sql_postauth        /* post-auth */