Rename SQL data types so they don't conflict with drivers
[freeradius.git] / src / modules / rlm_sql / rlm_sql.c
index 2cc898d..6dd6c19 100644 (file)
@@ -1,14 +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 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>
+ * @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$")
 
@@ -39,69 +37,70 @@ RCSID("$Id$")
 
 #include "rlm_sql.h"
 
-static char *allowed_chars = NULL;
-
-static const CONF_PARSER section_config[] = {
-       { "reference",  PW_TYPE_STRING_PTR,
-         offsetof(rlm_sql_config_section_t, reference), NULL, ".query"},
+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(rlm_sql_config_section_t, logfile), NULL, NULL},
+        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(SQL_CONFIG,sql_file), NULL, NULL},
+        offsetof(rlm_sql_config_t,sql_file), NULL, NULL},
        {"read_groups", PW_TYPE_BOOLEAN,
-        offsetof(SQL_CONFIG,read_groups), NULL, "yes"},
+        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"},
+        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, ""},
+        offsetof(rlm_sql_config_t,authorize_group_reply_query), NULL, ""},
        {"group_membership_query", PW_TYPE_STRING_PTR,
-        offsetof(SQL_CONFIG,groupmemb_query), NULL, NULL},
+        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, ""},
+        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(SQL_CONFIG,query_timeout), NULL, NULL},
+        offsetof(rlm_sql_config_t,query_timeout), NULL, NULL},
         
        {NULL, -1, 0, NULL, NULL}
 };
@@ -112,18 +111,16 @@ static const CONF_PARSER module_config[] = {
 static int fallthrough(VALUE_PAIR *vp)
 {
        VALUE_PAIR *tmp;
-       tmp = pairfind(vp, PW_FALL_THROUGH, 0);
+       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
@@ -132,15 +129,13 @@ static size_t sql_escape_func(char *out, size_t outlen, const char *in);
  *  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");
@@ -150,21 +145,21 @@ 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;
        }
 
-       sqlsocket = sql_get_socket(inst);
-       if (sqlsocket == NULL)
+       handle = sql_get_socket(inst);
+       if (handle == NULL)
                return 0;
 
-       query_log(inst, request, NULL, querystr);
+       rlm_sql_query_log(inst, request, NULL, querystr);
 
        /*
         *      If the query starts with any of the following prefixes,
@@ -176,13 +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)) {
-                       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",
@@ -202,51 +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)){
-               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("Null value in first column");
-               (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;
        }
        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;
        }
 
@@ -254,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;
@@ -277,16 +272,16 @@ 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)){
+       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;
                /*
@@ -319,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;
@@ -336,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' */
@@ -347,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) {
@@ -372,19 +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);
+               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, sqlsocket);
+                       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);
@@ -392,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;
 }
@@ -402,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]) {
@@ -412,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.
                         */
@@ -456,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, 0);
+       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;
@@ -504,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 */
 
@@ -519,38 +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) {
+       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;
 }
@@ -566,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;
        }
@@ -585,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, 0);
+       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, 0);
-               sql_release_socket(inst, sqlsocket);
+               sql_release_socket(inst, handle);
                return 1;
        }
 
@@ -618,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, 0);
-                       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, 0);
-       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);
@@ -639,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;
@@ -652,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;
        }
@@ -670,20 +654,20 @@ static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sql
                        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, 0);
+                       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, 0);
+                       pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
                        pairfree(&check_tmp);
                        sql_grouplist_free(&group_list);
                        return -1;
@@ -698,27 +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, 0);
+                                       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, 0);
+                                       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 {
                        /*
@@ -733,34 +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, 0);
+                               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, 0);
+                               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, 0);
+               pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
                pairfree(&check_tmp);
                pairfree(&reply_tmp);
        }
@@ -772,50 +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->pool) sql_poolfree(inst);
 
                if (inst->config->xlat_name) {
-                       xlat_unregister(inst->config->xlat_name,(RAD_XLAT_FUNC)sql_xlat, instance);
-                       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) {
@@ -826,14 +776,13 @@ static int rlm_sql_detach(void *instance)
                lt_dlclose(inst->handle);       /* ignore any errors */
 #endif
        }
-       free(inst);
 
        return 0;
 }
 
 static int parse_sub_section(CONF_SECTION *parent, 
-                            UNUSED SQL_INST *instance,
-                            rlm_sql_config_section_t *config,
+                            rlm_sql_t *inst,
+                            sql_acct_section_t **config,
                             rlm_components_t comp)
 {
        CONF_SECTION *cs;
@@ -842,32 +791,40 @@ static int parse_sub_section(CONF_SECTION *parent,
        
        cs = cf_section_sub_find(parent, name);
        if (!cs) {
-               /* TODO: Should really setup section with default values */
-               goto error;
+               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;
        }
        
-       if (cf_section_parse(cs, config, section_config) < 0)
-               goto error;
+       *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;
+       (*config)->cs = cs;
 
-       return 1;
-       
-       error:
-       radlog(L_ERR, "Failed parsing configuration for section %s",
-              name);
-       
-       return -1;
-               
+       return 0;
 }
 
-static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
+static int rlm_sql_instantiate(CONF_SECTION *conf, void **instance)
 {
-       SQL_INST *inst;
+       rlm_sql_t *inst;
        const char *xlat_name;
 
-       inst = rad_malloc(sizeof(SQL_INST));
-       memset(inst, 0, sizeof(SQL_INST));
+       *instance = inst = talloc_zero(conf, rlm_sql_t);
+       if (!inst) return -1;
+       
+       /*
+        *      Cache the SQL-User-Name DICT_ATTR, so we can be slightly
+        *      more efficient about creating SQL-User-Name attributes.
+        */
+       inst->sql_user = dict_attrbyname("SQL-User-Name");
+       if (!inst->sql_user) return -1;
 
        /*
         *      Export these methods, too.  This avoids RTDL_GLOBAL.
@@ -880,71 +837,46 @@ static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
        inst->sql_select_query          = rlm_sql_select_query;
        inst->sql_fetch_row             = rlm_sql_fetch_row;
        
-       inst->config = rad_malloc(sizeof(SQL_CONFIG));
-       memset(inst->config, 0, sizeof(SQL_CONFIG));
+       inst->config = talloc_zero(inst, rlm_sql_config_t);
        inst->cs = conf;
-               
-       /*
-        *      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, "Failed parsing configuration");
-                       
-               goto error;
-       }
-       /*
-        *      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);       
-               goto error;
-       }
 
        xlat_name = cf_section_name2(conf);
        if (xlat_name == NULL) {
                xlat_name = cf_section_name1(conf);
        } else {
                char *group_name;
-               DICT_ATTR *dattr;
+               const DICT_ATTR *dattr;
                ATTR_FLAGS flags;
 
                /*
                 *      Allocate room for <instance>-SQL-Group
                 */
-               group_name = rad_malloc((strlen(xlat_name) + 1 + 11) * sizeof(char));
-               sprintf(group_name,"%s-SQL-Group", xlat_name);
-               DEBUG("rlm_sql Creating new attribute %s",group_name);
+               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));
-               dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags);
-               dattr = dict_attrbyname(group_name);
-               if (dattr == NULL){
-                       radlog(L_ERR, "rlm_sql: Failed to create attribute %s",
-                              group_name);
-                              
-                       free(group_name);
+               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;
+               }
 
-                       goto error;
+               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: Registering sql_groupcmp for %s",
-                             group_name);
+                       DEBUG("rlm_sql (%s): Registering sql_groupcmp for %s",
+                             xlat_name, group_name);
                        paircompare_register(dattr->attr, PW_USER_NAME,
                                             sql_groupcmp, inst);
                }
-
-               free(group_name);
        }
        
        rad_assert(xlat_name);
@@ -952,10 +884,34 @@ static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
        /*
         *      Register the SQL xlat function
         */
-       inst->config->xlat_name = strdup(xlat_name);
-       xlat_register(xlat_name, (RAD_XLAT_FUNC)sql_xlat, inst);
+       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, "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);
@@ -965,8 +921,7 @@ static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
                       lt_dlerror());
                radlog(L_ERR, "Make sure it (and all its dependent libraries!)"
                       "are in the search path of your system's ld.");
-
-               goto error;
+               return -1;
        }
 
        inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle,
@@ -975,8 +930,7 @@ static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
                radlog(L_ERR, "Could not link symbol %s: %s",
                       inst->config->sql_driver,
                       lt_dlerror());
-
-               goto error;
+               return -1;
        }
 
        radlog(L_INFO, "rlm_sql (%s): Driver %s (module %s) loaded and linked",
@@ -991,8 +945,7 @@ static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
               inst->config->sql_server, inst->config->sql_port,
               inst->config->sql_db);
               
-       if (sql_init_socketpool(inst) < 0)
-               goto error;
+       if (sql_init_socketpool(inst) < 0) return -1;
 
        if (inst->config->groupmemb_query && 
            inst->config->groupmemb_query[0]) {
@@ -1002,200 +955,186 @@ static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
        if (inst->config->do_clients) {
                if (generate_sql_clients(inst) == -1){
                        radlog(L_ERR, "Failed to load clients from SQL.");
-                       
-                       goto error;
+                       return -1;
                }
        }
-       allowed_chars = inst->config->allowed_chars;
-
-       *instance = inst;
 
        return RLM_MODULE_OK;
-       
-       error:
-       rlm_sql_detach(inst);
-       
-       return -1;
 }
 
 
-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, 0);
+       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, 0);
-               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, 0);
-               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, 0);
-                               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, 0);
-                               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, 0);
-                       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, 0);
-               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, 0);
-                                       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, 0);
-                               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, 0);
-       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;
 }
 
 /*
@@ -1208,33 +1147,32 @@ static int rlm_sql_authorize(void *instance, REQUEST * request)
  *     doesn't update any rows, the next matching config item is used.
  *  
  */
-static int rlm_sql_redundant(SQL_INST *inst, REQUEST *request, 
-                            rlm_sql_config_section_t *section)
+static int acct_redundant(rlm_sql_t *inst, REQUEST *request, 
+                         sql_acct_section_t *section)
 {
-       int             ret = RLM_MODULE_OK;
+       int     ret = RLM_MODULE_OK;
 
-       SQLSOCK         *sqlsocket = NULL;
-       int             sql_ret;
-       int             numaffected = 0;
+       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;
+       CONF_ITEM  *item;
+       CONF_PAIR  *pair;
+       const char *attr = NULL;
+       const char *value;
 
        char    path[MAX_STRING_LEN];
        char    querystr[MAX_QUERY_LEN];
-       char    sqlusername[MAX_STRING_LEN];
        
        char    *p = path;
 
-       sql_set_user(inst, request, sqlusername, NULL);
+       rad_assert(section);
        
        if (section->reference[0] != '.')
                *p++ = '.';
        
-       if (radius_xlat(p, (sizeof(path) - (p - path)) - 1,
-                       section->reference, request, NULL) < 0)
+       if (!radius_xlat(p, (sizeof(path) - (p - path)) - 1,
+                       section->reference, request, NULL, NULL))
                return RLM_MODULE_FAIL;
 
        item = cf_reference_item(NULL, section->cs, path);
@@ -1250,29 +1188,48 @@ static int rlm_sql_redundant(SQL_INST *inst, REQUEST *request,
        pair = cf_itemtopair(item);
        attr = cf_pair_attr(pair);
        
-       RDEBUG2("Failing between pairs with name '%s'", attr);
+       RDEBUG2("Using query template '%s'", attr);
        
-       sqlsocket = sql_get_socket(inst);
-       if (sqlsocket == NULL)
+       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)
-                       goto null_query;
+               if (!value) {
+                       RDEBUG("Ignoring null query");
+                       ret = RLM_MODULE_NOOP;
+                       
+                       goto release;
+               }
                
                radius_xlat(querystr, sizeof(querystr), value, request,
-                           sql_escape_func);
-               if (!*querystr)
-                       goto null_query;
+                           sql_escape_func, inst);
+               if (!*querystr) {
+                       RDEBUG("Ignoring null query");
+                       ret = RLM_MODULE_NOOP;
+                       
+                       goto release;
+               }
                
-               query_log(inst, request, section, querystr);
+               rlm_sql_query_log(inst, request, section, querystr);
                
-               sql_ret = rlm_sql_query(&sqlsocket, inst, 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(sqlsocket);
+               
+               rad_assert(handle);
        
                /* 
                 *  Assume all other errors are incidental, and just meant our
@@ -1280,14 +1237,14 @@ static int rlm_sql_redundant(SQL_INST *inst, REQUEST *request,
                 */
                if (sql_ret == 0) {
                        numaffected = (inst->module->sql_affected_rows)
-                                       (sqlsocket, inst->config);
+                                       (handle, inst->config);
                        if (numaffected > 0)
                                break;
                                
                        RDEBUG("No records updated");
                }
 
-               (inst->module->sql_finish_query)(sqlsocket, inst->config);
+               (inst->module->sql_finish_query)(handle, inst->config);
                
                /*
                 *  We assume all entries with the same name form a redundant
@@ -1306,21 +1263,12 @@ static int rlm_sql_redundant(SQL_INST *inst, REQUEST *request,
                RDEBUG("Trying next query...");
        }
        
-       (inst->module->sql_finish_query)(sqlsocket, inst->config);
+       (inst->module->sql_finish_query)(handle, inst->config);
 
        release:
-       
-       sql_release_socket(inst, sqlsocket);
+       sql_release_socket(inst, handle);
 
        return ret;
-       
-       null_query:
-       
-       radlog_request(L_DBG, 0, request, "Ignoring null query");
-       
-       sql_release_socket(inst, sqlsocket);
-
-       return RLM_MODULE_NOOP;
 }
 
 #ifdef WITH_ACCOUNTING
@@ -1328,10 +1276,14 @@ static int rlm_sql_redundant(SQL_INST *inst, REQUEST *request,
 /*
  *     Accounting: Insert or update session data in our sql table
  */
-static int rlm_sql_accounting(void *instance, REQUEST * request) {
-       SQL_INST *inst = instance;              
+static rlm_rcode_t rlm_sql_accounting(void *instance, REQUEST * request) {
+       rlm_sql_t *inst = instance;             
 
-       return rlm_sql_redundant(inst, request, &inst->config->accounting); 
+       if (inst->config->accounting) {
+               return acct_redundant(inst, request, inst->config->accounting); 
+       }
+       
+       return RLM_MODULE_NOOP;
 }
 
 #endif
@@ -1346,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;
@@ -1373,40 +1324,40 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
        }
 
 
-       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)) {
-               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;
        }
 
@@ -1416,13 +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)) {
-               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;
        }
 
@@ -1431,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, 0)) != 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, 0)) != 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;
                }
@@ -1504,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,
@@ -1526,10 +1477,14 @@ static int rlm_sql_checksimul(void *instance, REQUEST * request) {
 /*
  *     Postauth: Write a record of the authentication attempt
  */
-static int rlm_sql_postauth(void *instance, REQUEST * request) {
-       SQL_INST *inst = instance;
+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);
+       }
        
-       return rlm_sql_redundant(inst, request, &inst->config->postauth)
+       return RLM_MODULE_NOOP
 }
 
 /*