3 * Main SQL module file. Most ICRADIUS code is located in sql.c
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * Copyright 2000 The FreeRADIUS server project
22 * Copyright 2000 Mike Machado <mike@innercite.com>
23 * Copyright 2000 Alan DeKok <aland@ox.org>
26 static const char rcsid[] =
29 #include <freeradius-devel/autoconf.h>
37 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
45 #include <freeradius-devel/radiusd.h>
46 #include <freeradius-devel/modules.h>
48 #include <freeradius-devel/rad_assert.h>
50 static char *allowed_chars = NULL;
52 static const CONF_PARSER module_config[] = {
53 {"driver",PW_TYPE_STRING_PTR,
54 offsetof(SQL_CONFIG,sql_driver), NULL, "mysql"},
55 {"server",PW_TYPE_STRING_PTR,
56 offsetof(SQL_CONFIG,sql_server), NULL, "localhost"},
57 {"port",PW_TYPE_STRING_PTR,
58 offsetof(SQL_CONFIG,sql_port), NULL, ""},
59 {"login", PW_TYPE_STRING_PTR,
60 offsetof(SQL_CONFIG,sql_login), NULL, ""},
61 {"password", PW_TYPE_STRING_PTR,
62 offsetof(SQL_CONFIG,sql_password), NULL, ""},
63 {"radius_db", PW_TYPE_STRING_PTR,
64 offsetof(SQL_CONFIG,sql_db), NULL, "radius"},
65 {"sqltrace", PW_TYPE_BOOLEAN,
66 offsetof(SQL_CONFIG,sqltrace), NULL, "no"},
67 {"sqltracefile", PW_TYPE_STRING_PTR,
68 offsetof(SQL_CONFIG,tracefile), NULL, SQLTRACEFILE},
69 {"readclients", PW_TYPE_BOOLEAN,
70 offsetof(SQL_CONFIG,do_clients), NULL, "no"},
71 {"deletestalesessions", PW_TYPE_BOOLEAN,
72 offsetof(SQL_CONFIG,deletestalesessions), NULL, "yes"},
73 {"num_sql_socks", PW_TYPE_INTEGER,
74 offsetof(SQL_CONFIG,num_sql_socks), NULL, "5"},
75 {"sql_user_name", PW_TYPE_STRING_PTR,
76 offsetof(SQL_CONFIG,query_user), NULL, ""},
77 {"default_user_profile", PW_TYPE_STRING_PTR,
78 offsetof(SQL_CONFIG,default_profile), NULL, ""},
79 {"nas_query", PW_TYPE_STRING_PTR,
80 offsetof(SQL_CONFIG,nas_query), NULL, "SELECT id,nasname,shortname,type,secret FROM nas"},
81 {"authorize_check_query", PW_TYPE_STRING_PTR,
82 offsetof(SQL_CONFIG,authorize_check_query), NULL, ""},
83 {"authorize_reply_query", PW_TYPE_STRING_PTR,
84 offsetof(SQL_CONFIG,authorize_reply_query), NULL, ""},
85 {"authorize_group_check_query", PW_TYPE_STRING_PTR,
86 offsetof(SQL_CONFIG,authorize_group_check_query), NULL, ""},
87 {"authorize_group_reply_query", PW_TYPE_STRING_PTR,
88 offsetof(SQL_CONFIG,authorize_group_reply_query), NULL, ""},
89 {"accounting_onoff_query", PW_TYPE_STRING_PTR,
90 offsetof(SQL_CONFIG,accounting_onoff_query), NULL, ""},
91 {"accounting_update_query", PW_TYPE_STRING_PTR,
92 offsetof(SQL_CONFIG,accounting_update_query), NULL, ""},
93 {"accounting_update_query_alt", PW_TYPE_STRING_PTR,
94 offsetof(SQL_CONFIG,accounting_update_query_alt), NULL, ""},
95 {"accounting_start_query", PW_TYPE_STRING_PTR,
96 offsetof(SQL_CONFIG,accounting_start_query), NULL, ""},
97 {"accounting_start_query_alt", PW_TYPE_STRING_PTR,
98 offsetof(SQL_CONFIG,accounting_start_query_alt), NULL, ""},
99 {"accounting_stop_query", PW_TYPE_STRING_PTR,
100 offsetof(SQL_CONFIG,accounting_stop_query), NULL, ""},
101 {"accounting_stop_query_alt", PW_TYPE_STRING_PTR,
102 offsetof(SQL_CONFIG,accounting_stop_query_alt), NULL, ""},
103 {"group_membership_query", PW_TYPE_STRING_PTR,
104 offsetof(SQL_CONFIG,groupmemb_query), NULL, ""},
105 {"connect_failure_retry_delay", PW_TYPE_INTEGER,
106 offsetof(SQL_CONFIG,connect_failure_retry_delay), NULL, "60"},
107 {"simul_count_query", PW_TYPE_STRING_PTR,
108 offsetof(SQL_CONFIG,simul_count_query), NULL, ""},
109 {"simul_verify_query", PW_TYPE_STRING_PTR,
110 offsetof(SQL_CONFIG,simul_verify_query), NULL, ""},
111 {"postauth_query", PW_TYPE_STRING_PTR,
112 offsetof(SQL_CONFIG,postauth_query), NULL, ""},
113 {"safe-characters", PW_TYPE_STRING_PTR,
114 offsetof(SQL_CONFIG,allowed_chars), NULL,
115 "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},
117 {NULL, -1, 0, NULL, NULL}
121 * Fall-Through checking function from rlm_files.c
123 static int fallthrough(VALUE_PAIR *vp)
126 tmp = pairfind(vp, PW_FALL_THROUGH);
128 return tmp ? tmp->lvalue : 0;
136 static int sql_set_user(SQL_INST *inst, REQUEST *request, char *sqlusername, const char *username);
137 static int generate_sql_clients(SQL_INST *inst);
138 static int sql_escape_func(char *out, int outlen, const char *in);
141 * sql xlat function. Right now only SELECTs are supported. Only
142 * the first element of the SELECT result will be used.
144 static int sql_xlat(void *instance, REQUEST *request,
145 char *fmt, char *out, size_t freespace,
146 UNUSED RADIUS_ESCAPE_STRING func)
150 SQL_INST *inst = instance;
151 char querystr[MAX_QUERY_LEN];
152 char sqlusername[MAX_STRING_LEN];
155 DEBUG("rlm_sql (%s): - sql_xlat", inst->config->xlat_name);
157 * Add SQL-User-Name attribute just in case it is needed
158 * We could search the string fmt for SQL-User-Name to see if this is
161 sql_set_user(inst, request, sqlusername, NULL);
163 * Do an xlat on the provided string (nice recursive operation).
165 if (!radius_xlat(querystr, sizeof(querystr), fmt, request, sql_escape_func)) {
166 radlog(L_ERR, "rlm_sql (%s): xlat failed.",
167 inst->config->xlat_name);
171 query_log(request, inst,querystr);
172 sqlsocket = sql_get_socket(inst);
173 if (sqlsocket == NULL)
175 if (rlm_sql_select_query(sqlsocket,inst,querystr)){
176 radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
177 inst->config->xlat_name,querystr,
178 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
179 sql_release_socket(inst,sqlsocket);
183 ret = rlm_sql_fetch_row(sqlsocket, inst);
186 DEBUG("rlm_sql (%s): SQL query did not succeed",
187 inst->config->xlat_name);
188 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
189 sql_release_socket(inst,sqlsocket);
193 row = sqlsocket->row;
195 DEBUG("rlm_sql (%s): SQL query did not return any results",
196 inst->config->xlat_name);
197 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
198 sql_release_socket(inst,sqlsocket);
203 DEBUG("rlm_sql (%s): row[0] returned NULL",
204 inst->config->xlat_name);
205 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
206 sql_release_socket(inst,sqlsocket);
209 ret = strlen(row[0]);
210 if (ret > freespace){
211 DEBUG("rlm_sql (%s): sql_xlat:: Insufficient string space",
212 inst->config->xlat_name);
213 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
214 sql_release_socket(inst,sqlsocket);
218 strncpy(out,row[0],ret);
220 DEBUG("rlm_sql (%s): - sql_xlat finished",
221 inst->config->xlat_name);
223 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
224 sql_release_socket(inst,sqlsocket);
228 static int generate_sql_clients(SQL_INST *inst)
232 char querystr[MAX_QUERY_LEN];
234 char *prefix_ptr = NULL;
237 DEBUG("rlm_sql (%s): Processing generate_sql_clients",
238 inst->config->xlat_name);
240 /* NAS query isn't xlat'ed */
241 strNcpy(querystr, inst->config->nas_query, sizeof(querystr));
242 DEBUG("rlm_sql (%s) in generate_sql_clients: query is %s",
243 inst->config->xlat_name, querystr);
245 sqlsocket = sql_get_socket(inst);
246 if (sqlsocket == NULL)
248 if (rlm_sql_select_query(sqlsocket,inst,querystr)){
249 radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
250 inst->config->xlat_name,querystr,
251 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
252 sql_release_socket(inst,sqlsocket);
256 while(rlm_sql_fetch_row(sqlsocket, inst) == 0) {
258 row = sqlsocket->row;
262 * The return data for each row MUST be in the following order:
264 * 0. Row ID (currently unused)
265 * 1. Name (or IP address)
271 radlog(L_ERR, "rlm_sql (%s): No row id found on pass %d",inst->config->xlat_name,i);
275 radlog(L_ERR, "rlm_sql (%s): No nasname found for row %s",inst->config->xlat_name,row[0]);
279 radlog(L_ERR, "rlm_sql (%s): No short name found for row %s",inst->config->xlat_name,row[0]);
283 radlog(L_ERR, "rlm_sql (%s): No secret found for row %s",inst->config->xlat_name,row[0]);
287 DEBUG("rlm_sql (%s): Read entry nasname=%s,shortname=%s,secret=%s",inst->config->xlat_name,
288 row[1],row[2],row[4]);
290 c = rad_malloc(sizeof(RADCLIENT));
291 memset(c, 0, sizeof(RADCLIENT));
297 prefix_ptr = strchr(row[1], '/');
299 c->prefix = atoi(prefix_ptr + 1);
300 if ((c->prefix < 0) || (c->prefix > 128)) {
301 radlog(L_ERR, "rlm_sql (%s): Invalid Prefix value '%s' for IP.",
302 inst->config->xlat_name, prefix_ptr + 1);
306 /* Replace '/' with '\0' */
311 * Always get the numeric representation of IP
313 if (ip_hton(row[1], AF_UNSPEC, &c->ipaddr) < 0) {
314 radlog(L_CONS|L_ERR, "rlm_sql (%s): Failed to look up hostname %s: %s",
315 inst->config->xlat_name,
316 row[1], librad_errstr);
321 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
322 c->longname = strdup(buffer);
325 if (c->prefix < 0) switch (c->ipaddr.af) {
337 * Other values (secret, shortname, nastype)
339 c->secret = (u_char *)strdup(row[4]);
340 c->shortname = strdup(row[2]);
342 c->nastype = strdup(row[3]);
344 DEBUG("rlm_sql (%s): Adding client %s (%s) to clients list",
345 inst->config->xlat_name,
346 c->longname,c->shortname);
347 if (!client_add(mainconfig.clients, c)) {
352 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
353 sql_release_socket(inst, sqlsocket);
360 * Translate the SQL queries.
362 static int sql_escape_func(char *out, int outlen, const char *in)
368 * Non-printable characters get replaced with their
369 * mime-encoded equivalents.
372 strchr(allowed_chars, *in) == NULL) {
374 * Only 3 or less bytes available.
380 snprintf(out, outlen, "=%02X", (unsigned char) in[0]);
389 * Only one byte left.
409 * Set the SQL user name.
411 * We don't call the escape function here. The resulting string
412 * will be escaped later in the queries xlat so we don't need to
413 * escape it twice. (it will make things wrong if we have an
414 * escape candidate character in the username)
416 static int sql_set_user(SQL_INST *inst, REQUEST *request, char *sqlusername, const char *username)
419 char tmpuser[MAX_STRING_LEN];
422 sqlusername[0]= '\0';
424 /* Remove any user attr we added previously */
425 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
427 if (username != NULL) {
428 strNcpy(tmpuser, username, MAX_STRING_LEN);
429 } else if (strlen(inst->config->query_user)) {
430 radius_xlat(tmpuser, sizeof(tmpuser), inst->config->query_user, request, NULL);
436 strNcpy(sqlusername, tmpuser, MAX_STRING_LEN);
437 DEBUG2("rlm_sql (%s): sql_set_user escaped user --> '%s'",
438 inst->config->xlat_name, sqlusername);
439 vp = pairmake("SQL-User-Name", sqlusername, 0);
441 radlog(L_ERR, "%s", librad_errstr);
445 pairadd(&request->packet->vps, vp);
452 static void sql_grouplist_free (SQL_GROUPLIST **group_list)
458 *group_list = (*group_list)->next;
464 static int sql_get_grouplist (SQL_INST *inst, SQLSOCK *sqlsocket, REQUEST *request, SQL_GROUPLIST **group_list)
466 char querystr[MAX_QUERY_LEN];
469 SQL_GROUPLIST *group_list_tmp;
471 /* NOTE: sql_set_user should have been run before calling this function */
473 group_list_tmp = *group_list = NULL;
475 if (inst->config->groupmemb_query[0] == 0)
478 if (!radius_xlat(querystr, sizeof(querystr), inst->config->groupmemb_query, request, sql_escape_func)) {
479 radlog(L_ERR, "rlm_sql (%s): xlat failed.",
480 inst->config->xlat_name);
484 if (rlm_sql_select_query(sqlsocket, inst, querystr) < 0) {
485 radlog(L_ERR, "rlm_sql (%s): database query error, %s: %s",
486 inst->config->xlat_name,querystr,
487 (char *)(inst->module->sql_error)(sqlsocket,inst->config));
490 while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {
491 row = sqlsocket->row;
495 DEBUG("rlm_sql (%s): row[0] returned NULL",
496 inst->config->xlat_name);
497 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
498 sql_grouplist_free(group_list);
501 if (*group_list == NULL) {
502 *group_list = rad_malloc(sizeof(SQL_GROUPLIST));
503 group_list_tmp = *group_list;
505 group_list_tmp->next = rad_malloc(sizeof(SQL_GROUPLIST));
506 group_list_tmp = group_list_tmp->next;
508 group_list_tmp->next = NULL;
509 strNcpy(group_list_tmp->groupname, row[0], MAX_STRING_LEN);
512 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
519 * sql groupcmp function. That way we can do group comparisons (in the users file for example)
520 * with the group memberships reciding in sql
521 * The group membership query should only return one element which is the username. The returned
522 * username will then be checked with the passed check string.
525 static int sql_groupcmp(void *instance, REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check,
526 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
529 SQL_INST *inst = instance;
530 char sqlusername[MAX_STRING_LEN];
531 SQL_GROUPLIST *group_list, *group_list_tmp;
533 check_pairs = check_pairs;
534 reply_pairs = reply_pairs;
537 DEBUG("rlm_sql (%s): - sql_groupcmp", inst->config->xlat_name);
538 if (!check || !check->vp_strvalue || !check->length){
539 DEBUG("rlm_sql (%s): sql_groupcmp: Illegal group name",
540 inst->config->xlat_name);
544 DEBUG("rlm_sql (%s): sql_groupcmp: NULL request",
545 inst->config->xlat_name);
549 * Set, escape, and check the user attr here
551 if (sql_set_user(inst, req, sqlusername, NULL) < 0)
555 * Get a socket for this lookup
557 sqlsocket = sql_get_socket(inst);
558 if (sqlsocket == NULL) {
559 /* Remove the username we (maybe) added above */
560 pairdelete(&req->packet->vps, PW_SQL_USER_NAME);
565 * Get the list of groups this user is a member of
567 if (sql_get_grouplist(inst, sqlsocket, req, &group_list)) {
568 radlog(L_ERR, "rlm_sql (%s): Error getting group membership",
569 inst->config->xlat_name);
570 /* Remove the username we (maybe) added above */
571 pairdelete(&req->packet->vps, PW_SQL_USER_NAME);
572 sql_release_socket(inst, sqlsocket);
576 for (group_list_tmp = group_list; group_list_tmp != NULL; group_list_tmp = group_list_tmp->next) {
577 if (strcmp(group_list_tmp->groupname, check->vp_strvalue) == 0){
578 DEBUG("rlm_sql (%s): - sql_groupcmp finished: User is a member of group %s",
579 inst->config->xlat_name,
580 (char *)check->vp_strvalue);
581 /* Free the grouplist */
582 sql_grouplist_free(&group_list);
583 /* Remove the username we (maybe) added above */
584 pairdelete(&req->packet->vps, PW_SQL_USER_NAME);
585 sql_release_socket(inst, sqlsocket);
590 /* Free the grouplist */
591 sql_grouplist_free(&group_list);
592 /* Remove the username we (maybe) added above */
593 pairdelete(&req->packet->vps, PW_SQL_USER_NAME);
594 sql_release_socket(inst,sqlsocket);
596 DEBUG("rlm_sql (%s): - sql_groupcmp finished: User is NOT a member of group %s",
597 inst->config->xlat_name, (char *)check->vp_strvalue);
604 static int rlm_sql_process_groups(SQL_INST *inst, REQUEST *request, SQLSOCK *sqlsocket, int *dofallthrough)
606 VALUE_PAIR *check_tmp = NULL;
607 VALUE_PAIR *reply_tmp = NULL;
608 SQL_GROUPLIST *group_list, *group_list_tmp;
609 VALUE_PAIR *sql_group = NULL;
610 char querystr[MAX_QUERY_LEN];
615 * Get the list of groups this user is a member of
617 if (sql_get_grouplist(inst, sqlsocket, request, &group_list)) {
618 radlog(L_ERR, "rlm_sql (%s): Error retrieving group list",
619 inst->config->xlat_name);
623 for (group_list_tmp = group_list; group_list_tmp != NULL && *dofallthrough != 0; group_list_tmp = group_list_tmp->next) {
625 * Add the Sql-Group attribute to the request list so we know
626 * which group we're retrieving attributes for
628 sql_group = pairmake("Sql-Group", group_list_tmp->groupname, T_OP_EQ);
630 radlog(L_ERR, "rlm_sql (%s): Error creating Sql-Group attribute",
631 inst->config->xlat_name);
634 pairadd(&request->packet->vps, sql_group);
635 if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func)) {
636 radlog(L_ERR, "rlm_sql (%s): Error generating query; rejecting user",
637 inst->config->xlat_name);
638 /* Remove the grouup we added above */
639 pairdelete(&request->packet->vps, PW_SQL_GROUP);
642 rows = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr);
644 radlog(L_ERR, "rlm_sql (%s): Error retrieving check pairs for group %s",
645 inst->config->xlat_name, group_list_tmp->groupname);
646 /* Remove the grouup we added above */
647 pairdelete(&request->packet->vps, PW_SQL_GROUP);
648 pairfree(&check_tmp);
650 } else if (rows > 0) {
652 * Only do this if *some* check pairs were returned
654 if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) {
656 DEBUG2("rlm_sql (%s): User found in group %s",
657 inst->config->xlat_name, group_list_tmp->groupname);
659 * Now get the reply pairs since the paircompare matched
661 if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func)) {
662 radlog(L_ERR, "rlm_sql (%s): Error generating query; rejecting user",
663 inst->config->xlat_name);
664 /* Remove the grouup we added above */
665 pairdelete(&request->packet->vps, PW_SQL_GROUP);
666 pairfree(&check_tmp);
669 if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
670 radlog(L_ERR, "rlm_sql (%s): Error retrieving reply pairs for group %s",
671 inst->config->xlat_name, group_list_tmp->groupname);
672 /* Remove the grouup we added above */
673 pairdelete(&request->packet->vps, PW_SQL_GROUP);
674 pairfree(&check_tmp);
675 pairfree(&reply_tmp);
678 *dofallthrough = fallthrough(reply_tmp);
679 pairxlatmove(request, &request->reply->vps, &reply_tmp);
680 pairxlatmove(request, &request->config_items, &check_tmp);
684 * rows == 0. This is like having the username on a line
685 * in the user's file with no check vp's. As such, we treat
686 * it as found and add the reply attributes, so that we
687 * match expected behavior
690 DEBUG2("rlm_sql (%s): User found in group %s",
691 inst->config->xlat_name, group_list_tmp->groupname);
693 * Now get the reply pairs since the paircompare matched
695 if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func)) {
696 radlog(L_ERR, "rlm_sql (%s): Error generating query; rejecting user",
697 inst->config->xlat_name);
698 /* Remove the grouup we added above */
699 pairdelete(&request->packet->vps, PW_SQL_GROUP);
700 pairfree(&check_tmp);
703 if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
704 radlog(L_ERR, "rlm_sql (%s): Error retrieving reply pairs for group %s",
705 inst->config->xlat_name, group_list_tmp->groupname);
706 /* Remove the grouup we added above */
707 pairdelete(&request->packet->vps, PW_SQL_GROUP);
708 pairfree(&check_tmp);
709 pairfree(&reply_tmp);
712 *dofallthrough = fallthrough(reply_tmp);
713 pairxlatmove(request, &request->reply->vps, &reply_tmp);
714 pairxlatmove(request, &request->config_items, &check_tmp);
718 * Delete the Sql-Group we added above
719 * And clear out the pairlists
721 pairdelete(&request->packet->vps, PW_SQL_GROUP);
722 pairfree(&check_tmp);
723 pairfree(&reply_tmp);
726 sql_grouplist_free(&group_list);
731 static int rlm_sql_detach(void *instance)
733 SQL_INST *inst = instance;
739 if (inst->config->xlat_name) {
740 xlat_unregister(inst->config->xlat_name,(RAD_XLAT_FUNC)sql_xlat);
741 free(inst->config->xlat_name);
744 paircompare_unregister(PW_SQL_GROUP, sql_groupcmp);
750 * Free up dynamically allocated string pointers.
752 for (i = 0; module_config[i].name != NULL; i++) {
754 if (module_config[i].type != PW_TYPE_STRING_PTR) {
759 * Treat 'config' as an opaque array of bytes,
760 * and take the offset into it. There's a
761 * (char*) pointer at that offset, and we want
764 p = (char **) (((char *)inst->config) + module_config[i].offset);
765 if (!*p) { /* nothing allocated */
771 allowed_chars = NULL;
779 * FIXME: Call the modules 'destroy' function?
781 lt_dlclose(inst->handle); /* ignore any errors */
788 static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
791 const char *xlat_name;
793 inst = rad_malloc(sizeof(SQL_INST));
794 memset(inst, 0, sizeof(SQL_INST));
796 inst->config = rad_malloc(sizeof(SQL_CONFIG));
797 memset(inst->config, 0, sizeof(SQL_CONFIG));
800 * If the configuration parameters can't be parsed, then
803 if (cf_section_parse(conf, inst->config, module_config) < 0) {
804 rlm_sql_detach(inst);
808 xlat_name = cf_section_name2(conf);
809 if (xlat_name == NULL)
810 xlat_name = cf_section_name1(conf);
812 inst->config->xlat_name = strdup(xlat_name);
813 xlat_register(xlat_name, (RAD_XLAT_FUNC)sql_xlat, inst);
816 if (inst->config->num_sql_socks > MAX_SQL_SOCKS) {
817 radlog(L_ERR | L_CONS, "rlm_sql (%s): sql_instantiate: number of sqlsockets cannot exceed MAX_SQL_SOCKS, %d",
818 inst->config->xlat_name, MAX_SQL_SOCKS);
819 rlm_sql_detach(inst);
824 * Sanity check for crazy people.
826 if (strncmp(inst->config->sql_driver, "rlm_sql_", 8) != 0) {
827 radlog(L_ERR, "rlm_sql (%s): \"%s\" is NOT an SQL driver!",
828 inst->config->xlat_name, inst->config->sql_driver);
829 rlm_sql_detach(inst);
833 inst->handle = lt_dlopenext(inst->config->sql_driver);
834 if (inst->handle == NULL) {
835 radlog(L_ERR, "rlm_sql (%s): Could not link driver %s: %s",
836 inst->config->xlat_name, inst->config->sql_driver,
838 radlog(L_ERR, "rlm_sql (%s): Make sure it (and all its dependent libraries!) are in the search path of your system's ld.",
839 inst->config->xlat_name);
840 rlm_sql_detach(inst);
844 inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle, inst->config->sql_driver);
846 radlog(L_ERR, "rlm_sql (%s): Could not link symbol %s: %s",
847 inst->config->xlat_name, inst->config->sql_driver,
849 rlm_sql_detach(inst);
853 radlog(L_INFO, "rlm_sql (%s): Driver %s (module %s) loaded and linked",
854 inst->config->xlat_name, inst->config->sql_driver,
856 radlog(L_INFO, "rlm_sql (%s): Attempting to connect to %s@%s:%s/%s",
857 inst->config->xlat_name, inst->config->sql_login,
858 inst->config->sql_server, inst->config->sql_port,
859 inst->config->sql_db);
861 if (sql_init_socketpool(inst) < 0) {
862 rlm_sql_detach(inst);
865 paircompare_register(PW_SQL_GROUP, PW_USER_NAME, sql_groupcmp, inst);
867 if (inst->config->do_clients){
868 if (generate_sql_clients(inst) == -1){
869 radlog(L_ERR, "rlm_sql (%s): generate_sql_clients() returned error",inst->config->xlat_name);
870 rlm_sql_detach(inst);
874 allowed_chars = inst->config->allowed_chars;
878 return RLM_MODULE_OK;
882 static int rlm_sql_authorize(void *instance, REQUEST * request)
884 VALUE_PAIR *check_tmp = NULL;
885 VALUE_PAIR *reply_tmp = NULL;
886 VALUE_PAIR *user_profile = NULL;
888 int dofallthrough = 1;
891 SQL_INST *inst = instance;
892 char querystr[MAX_QUERY_LEN];
893 char sqlusername[MAX_STRING_LEN];
895 * the profile username is used as the sqlusername during
896 * profile checking so that we don't overwrite the orignal
899 char profileusername[MAX_STRING_LEN];
902 * They MUST have a user name to do SQL authorization.
904 if ((request->username == NULL) ||
905 (request->username->length == 0)) {
906 radlog(L_ERR, "rlm_sql (%s): zero length username not permitted\n", inst->config->xlat_name);
907 return RLM_MODULE_INVALID;
912 * Set, escape, and check the user attr here
914 if (sql_set_user(inst, request, sqlusername, NULL) < 0)
915 return RLM_MODULE_FAIL;
921 sqlsocket = sql_get_socket(inst);
922 if (sqlsocket == NULL) {
923 /* Remove the username we (maybe) added above */
924 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
925 return RLM_MODULE_FAIL;
930 * After this point, ALL 'return's MUST release the SQL socket!
934 * Alright, start by getting the specific entry for the user
936 if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_check_query, request, sql_escape_func)) {
937 radlog(L_ERR, "rlm_sql (%s): Error generating query; rejecting user",
938 inst->config->xlat_name);
939 sql_release_socket(inst, sqlsocket);
940 /* Remove the username we (maybe) added above */
941 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
942 return RLM_MODULE_FAIL;
944 rows = sql_getvpdata(inst, sqlsocket, &check_tmp, querystr);
946 radlog(L_ERR, "rlm_sql (%s): SQL query error; rejecting user",
947 inst->config->xlat_name);
948 sql_release_socket(inst, sqlsocket);
949 /* Remove the username we (maybe) added above */
950 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
951 pairfree(&check_tmp);
952 return RLM_MODULE_FAIL;
953 } else if (rows > 0) {
955 * Only do this if *some* check pairs were returned
957 if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) {
959 DEBUG2("rlm_sql (%s): User found in radcheck table", inst->config->xlat_name);
961 * Now get the reply pairs since the paircompare matched
963 if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_reply_query, request, sql_escape_func)) {
964 radlog(L_ERR, "rlm_sql (%s): Error generating query; rejecting user",
965 inst->config->xlat_name);
966 sql_release_socket(inst, sqlsocket);
967 /* Remove the username we (maybe) added above */
968 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
969 pairfree(&check_tmp);
970 return RLM_MODULE_FAIL;
972 if (sql_getvpdata(inst, sqlsocket, &reply_tmp, querystr) < 0) {
973 radlog(L_ERR, "rlm_sql (%s): SQL query error; rejecting user",
974 inst->config->xlat_name);
975 sql_release_socket(inst, sqlsocket);
976 /* Remove the username we (maybe) added above */
977 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
978 pairfree(&check_tmp);
979 pairfree(&reply_tmp);
980 return RLM_MODULE_FAIL;
982 if (!inst->config->read_groups)
983 dofallthrough = fallthrough(reply_tmp);
984 pairxlatmove(request, &request->reply->vps, &reply_tmp);
985 pairxlatmove(request, &request->config_items, &check_tmp);
990 * Clear out the pairlists
992 pairfree(&check_tmp);
993 pairfree(&reply_tmp);
996 * dofallthrough is set to 1 by default so that if the user information
997 * is not found, we will still process groups. If the user information,
998 * however, *is* found, Fall-Through must be set in order to process
1001 if (dofallthrough) {
1002 rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough);
1004 radlog(L_ERR, "rlm_sql (%s): Error processing groups; rejecting user",
1005 inst->config->xlat_name);
1006 sql_release_socket(inst, sqlsocket);
1007 /* Remove the username we (maybe) added above */
1008 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
1009 return RLM_MODULE_FAIL;
1010 } else if (rows > 0) {
1016 * repeat the above process with the default profile or User-Profile
1018 if (dofallthrough) {
1019 int profile_found = 0;
1021 * Check for a default_profile or for a User-Profile.
1023 user_profile = pairfind(request->config_items, PW_USER_PROFILE);
1024 if (inst->config->default_profile[0] != 0 || user_profile != NULL){
1025 char *profile = inst->config->default_profile;
1027 if (user_profile != NULL)
1028 profile = user_profile->vp_strvalue;
1029 if (profile && strlen(profile)){
1030 radlog(L_DBG, "rlm_sql (%s): Checking profile %s",
1031 inst->config->xlat_name, profile);
1032 if (sql_set_user(inst, request, profileusername, profile) < 0) {
1033 radlog(L_ERR, "rlm_sql (%s): Error setting profile; rejecting user",
1034 inst->config->xlat_name);
1035 sql_release_socket(inst, sqlsocket);
1036 /* Remove the username we (maybe) added above */
1037 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
1038 return RLM_MODULE_FAIL;
1045 if (profile_found) {
1046 rows = rlm_sql_process_groups(inst, request, sqlsocket, &dofallthrough);
1048 radlog(L_ERR, "rlm_sql (%s): Error processing profile groups; rejecting user",
1049 inst->config->xlat_name);
1050 sql_release_socket(inst, sqlsocket);
1051 /* Remove the username we (maybe) added above */
1052 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
1053 return RLM_MODULE_FAIL;
1054 } else if (rows > 0) {
1060 /* Remove the username we (maybe) added above */
1061 pairdelete(&request->packet->vps, PW_SQL_USER_NAME);
1062 sql_release_socket(inst, sqlsocket);
1065 radlog(L_DBG, "rlm_sql (%s): User %s not found",
1066 inst->config->xlat_name, sqlusername);
1067 return RLM_MODULE_NOTFOUND;
1069 return RLM_MODULE_OK;
1074 * Accounting: save the account data to our sql table
1076 static int rlm_sql_accounting(void *instance, REQUEST * request) {
1078 SQLSOCK *sqlsocket = NULL;
1080 SQL_INST *inst = instance;
1081 int ret = RLM_MODULE_OK;
1082 int numaffected = 0;
1083 int acctstatustype = 0;
1084 char querystr[MAX_QUERY_LEN];
1085 char logstr[MAX_QUERY_LEN];
1086 char sqlusername[MAX_STRING_LEN];
1088 #ifdef CISCO_ACCOUNTING_HACK
1089 int acctsessiontime = 0;
1092 memset(querystr, 0, MAX_QUERY_LEN);
1095 * Find the Acct Status Type
1097 if ((pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL) {
1098 acctstatustype = pair->lvalue;
1100 radius_xlat(logstr, sizeof(logstr), "packet has no accounting status type. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
1101 radlog(L_ERR, "rlm_sql (%s) in sql_accounting: %s",
1102 inst->config->xlat_name, logstr);
1103 return RLM_MODULE_INVALID;
1106 switch (acctstatustype) {
1108 * The Terminal server informed us that it was rebooted
1109 * STOP all records from this NAS
1111 case PW_STATUS_ACCOUNTING_ON:
1112 case PW_STATUS_ACCOUNTING_OFF:
1113 radlog(L_INFO, "rlm_sql (%s): received Acct On/Off packet", inst->config->xlat_name);
1114 radius_xlat(querystr, sizeof(querystr), inst->config->accounting_onoff_query, request, sql_escape_func);
1115 query_log(request, inst, querystr);
1117 sqlsocket = sql_get_socket(inst);
1118 if (sqlsocket == NULL)
1119 return(RLM_MODULE_FAIL);
1120 if (*querystr) { /* non-empty query */
1121 if (rlm_sql_query(sqlsocket, inst, querystr)) {
1122 radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting for Acct On/Off packet - %s",
1123 inst->config->xlat_name,
1124 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
1125 ret = RLM_MODULE_FAIL;
1127 (inst->module->sql_finish_query)(sqlsocket, inst->config);
1133 * Got an update accounting packet
1135 case PW_STATUS_ALIVE:
1138 * Set, escape, and check the user attr here
1140 sql_set_user(inst, request, sqlusername, NULL);
1142 radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query, request, sql_escape_func);
1143 query_log(request, inst, querystr);
1145 sqlsocket = sql_get_socket(inst);
1146 if (sqlsocket == NULL)
1147 return(RLM_MODULE_FAIL);
1148 if (*querystr) { /* non-empty query */
1149 if (rlm_sql_query(sqlsocket, inst, querystr)) {
1150 radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting ALIVE record - %s",
1151 inst->config->xlat_name,
1152 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
1153 ret = RLM_MODULE_FAIL;
1156 numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
1157 if (numaffected < 1) {
1160 * If our update above didn't match anything
1161 * we assume it's because we haven't seen a
1162 * matching Start record. So we have to
1163 * insert this update rather than do an update
1165 radius_xlat(querystr, sizeof(querystr), inst->config->accounting_update_query_alt, request, sql_escape_func);
1166 query_log(request, inst, querystr);
1167 if (*querystr) { /* non-empty query */
1168 if (rlm_sql_query(sqlsocket, inst, querystr)) {
1169 radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting ALIVE record - %s",
1170 inst->config->xlat_name,
1171 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
1172 ret = RLM_MODULE_FAIL;
1174 (inst->module->sql_finish_query)(sqlsocket, inst->config);
1178 (inst->module->sql_finish_query)(sqlsocket, inst->config);
1183 * Got accounting start packet
1185 case PW_STATUS_START:
1188 * Set, escape, and check the user attr here
1190 sql_set_user(inst, request, sqlusername, NULL);
1192 radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query, request, sql_escape_func);
1193 query_log(request, inst, querystr);
1195 sqlsocket = sql_get_socket(inst);
1196 if (sqlsocket == NULL)
1197 return(RLM_MODULE_FAIL);
1198 if (*querystr) { /* non-empty query */
1199 if (rlm_sql_query(sqlsocket, inst, querystr)) {
1200 radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting START record - %s",
1201 inst->config->xlat_name,
1202 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
1205 * We failed the insert above. It's probably because
1206 * the stop record came before the start. We try
1207 * our alternate query now (typically an UPDATE)
1209 radius_xlat(querystr, sizeof(querystr), inst->config->accounting_start_query_alt, request, sql_escape_func);
1210 query_log(request, inst, querystr);
1212 if (*querystr) { /* non-empty query */
1213 if (rlm_sql_query(sqlsocket, inst, querystr)) {
1214 radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting START record - %s",
1215 inst->config->xlat_name,
1216 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
1217 ret = RLM_MODULE_FAIL;
1219 (inst->module->sql_finish_query)(sqlsocket, inst->config);
1222 (inst->module->sql_finish_query)(sqlsocket, inst->config);
1227 * Got accounting stop packet
1229 case PW_STATUS_STOP:
1232 * Set, escape, and check the user attr here
1234 sql_set_user(inst, request, sqlusername, NULL);
1236 radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query, request, sql_escape_func);
1237 query_log(request, inst, querystr);
1239 sqlsocket = sql_get_socket(inst);
1240 if (sqlsocket == NULL)
1241 return(RLM_MODULE_FAIL);
1242 if (*querystr) { /* non-empty query */
1243 if (rlm_sql_query(sqlsocket, inst, querystr)) {
1244 radlog(L_ERR, "rlm_sql (%s): Couldn't update SQL accounting STOP record - %s",
1245 inst->config->xlat_name,
1246 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
1247 ret = RLM_MODULE_FAIL;
1250 numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
1251 if (numaffected < 1) {
1253 * If our update above didn't match anything
1254 * we assume it's because we haven't seen a
1255 * matching Start record. So we have to
1256 * insert this stop rather than do an update
1258 #ifdef CISCO_ACCOUNTING_HACK
1260 * If stop but zero session length AND no previous
1261 * session found, drop it as in invalid packet
1262 * This is to fix CISCO's aaa from filling our
1263 * table with bogus crap
1265 if ((pair = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME)) != NULL)
1266 acctsessiontime = pair->lvalue;
1268 if (acctsessiontime <= 0) {
1269 radius_xlat(logstr, sizeof(logstr), "stop packet with zero session length. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
1270 radlog(L_ERR, "rlm_sql (%s) in sql_accounting: %s", inst->config->xlat_name, logstr);
1271 sql_release_socket(inst, sqlsocket);
1272 ret = RLM_MODULE_NOOP;
1276 radius_xlat(querystr, sizeof(querystr), inst->config->accounting_stop_query_alt, request, sql_escape_func);
1277 query_log(request, inst, querystr);
1279 if (*querystr) { /* non-empty query */
1280 if (rlm_sql_query(sqlsocket, inst, querystr)) {
1281 radlog(L_ERR, "rlm_sql (%s): Couldn't insert SQL accounting STOP record - %s",
1282 inst->config->xlat_name,
1283 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
1284 ret = RLM_MODULE_FAIL;
1286 (inst->module->sql_finish_query)(sqlsocket, inst->config);
1290 (inst->module->sql_finish_query)(sqlsocket, inst->config);
1295 * Anything else is ignored.
1298 radlog(L_INFO, "rlm_sql (%s): Unsupported Acct-Status-Type = %d", inst->config->xlat_name, acctstatustype);
1299 return RLM_MODULE_NOOP;
1304 sql_release_socket(inst, sqlsocket);
1311 * See if a user is already logged in. Sets request->simul_count to the
1312 * current session count for this user.
1314 * Check twice. If on the first pass the user exceeds his
1315 * max. number of logins, do a second pass and validate all
1316 * logins by querying the terminal server (using eg. SNMP).
1319 static int rlm_sql_checksimul(void *instance, REQUEST * request) {
1321 SQL_INST *inst = instance;
1323 char querystr[MAX_QUERY_LEN];
1324 char sqlusername[MAX_STRING_LEN];
1327 char *call_num = NULL;
1330 uint32_t nas_addr = 0;
1333 /* If simul_count_query is not defined, we don't do any checking */
1334 if (inst->config->simul_count_query[0] == 0) {
1335 return RLM_MODULE_NOOP;
1338 if((request->username == NULL) || (request->username->length == 0)) {
1339 radlog(L_ERR, "rlm_sql (%s): Zero Length username not permitted\n", inst->config->xlat_name);
1340 return RLM_MODULE_INVALID;
1344 if(sql_set_user(inst, request, sqlusername, NULL) < 0)
1345 return RLM_MODULE_FAIL;
1347 radius_xlat(querystr, sizeof(querystr), inst->config->simul_count_query, request, sql_escape_func);
1349 /* initialize the sql socket */
1350 sqlsocket = sql_get_socket(inst);
1351 if(sqlsocket == NULL)
1352 return RLM_MODULE_FAIL;
1354 if(rlm_sql_select_query(sqlsocket, inst, querystr)) {
1355 radlog(L_ERR, "rlm_sql (%s) sql_checksimul: Database query failed", inst->config->xlat_name);
1356 sql_release_socket(inst, sqlsocket);
1357 return RLM_MODULE_FAIL;
1360 ret = rlm_sql_fetch_row(sqlsocket, inst);
1363 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
1364 sql_release_socket(inst, sqlsocket);
1365 return RLM_MODULE_FAIL;
1368 row = sqlsocket->row;
1370 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
1371 sql_release_socket(inst, sqlsocket);
1372 return RLM_MODULE_FAIL;
1375 request->simul_count = atoi(row[0]);
1376 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
1378 if(request->simul_count < request->simul_max) {
1379 sql_release_socket(inst, sqlsocket);
1380 return RLM_MODULE_OK;
1384 * Looks like too many sessions, so let's start verifying
1385 * them, unless told to rely on count query only.
1387 if (inst->config->simul_verify_query[0] == '\0') {
1388 sql_release_socket(inst, sqlsocket);
1389 return RLM_MODULE_OK;
1392 radius_xlat(querystr, sizeof(querystr), inst->config->simul_verify_query, request, sql_escape_func);
1393 if(rlm_sql_select_query(sqlsocket, inst, querystr)) {
1394 radlog(L_ERR, "rlm_sql (%s): sql_checksimul: Database query error", inst->config->xlat_name);
1395 sql_release_socket(inst, sqlsocket);
1396 return RLM_MODULE_FAIL;
1400 * Setup some stuff, like for MPP detection.
1402 request->simul_count = 0;
1404 if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL)
1406 if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)
1407 call_num = vp->vp_strvalue;
1410 while (rlm_sql_fetch_row(sqlsocket, inst) == 0) {
1411 row = sqlsocket->row;
1415 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
1416 sql_release_socket(inst, sqlsocket);
1417 DEBUG("rlm_sql (%s): Cannot zap stale entry. No username present in entry.", inst->config->xlat_name);
1418 return RLM_MODULE_FAIL;
1421 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
1422 sql_release_socket(inst, sqlsocket);
1423 DEBUG("rlm_sql (%s): Cannot zap stale entry. No session id in entry.", inst->config->xlat_name);
1424 return RLM_MODULE_FAIL;
1427 nas_addr = inet_addr(row[3]);
1429 nas_port = atoi(row[4]);
1431 check = rad_check_ts(nas_addr, nas_port, row[2], row[1]);
1435 * Stale record - zap it.
1437 if (inst->config->deletestalesessions == TRUE) {
1438 uint32_t framed_addr = 0;
1443 framed_addr = inet_addr(row[5]);
1445 if (strcmp(row[7], "PPP") == 0)
1447 else if (strcmp(row[7], "SLIP") == 0)
1451 sess_time = atoi(row[8]);
1452 session_zap(request, nas_addr, nas_port,
1453 row[2], row[1], framed_addr,
1457 else if (check == 1) {
1459 * User is still logged in.
1461 ++request->simul_count;
1464 * Does it look like a MPP attempt?
1466 if (row[5] && ipno && inet_addr(row[5]) == ipno)
1467 request->simul_mpp = 2;
1468 else if (row[6] && call_num &&
1469 !strncmp(row[6],call_num,16))
1470 request->simul_mpp = 2;
1474 * Failed to check the terminal server for
1475 * duplicate logins: return an error.
1477 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
1478 sql_release_socket(inst, sqlsocket);
1479 radlog(L_ERR, "rlm_sql (%s): sql_checksimul: Failed to check the terminal server for user '%s'.", inst->config->xlat_name, row[2]);
1480 return RLM_MODULE_FAIL;
1484 (inst->module->sql_finish_select_query)(sqlsocket, inst->config);
1485 sql_release_socket(inst, sqlsocket);
1488 * The Auth module apparently looks at request->simul_count,
1489 * not the return value of this module when deciding to deny
1490 * a call for too many sessions.
1492 return RLM_MODULE_OK;
1496 * Execute postauth_query after authentication
1498 static int rlm_sql_postauth(void *instance, REQUEST *request) {
1499 SQLSOCK *sqlsocket = NULL;
1500 SQL_INST *inst = instance;
1501 char querystr[MAX_QUERY_LEN];
1502 char sqlusername[MAX_STRING_LEN];
1504 DEBUG("rlm_sql (%s): Processing sql_postauth", inst->config->xlat_name);
1506 if(sql_set_user(inst, request, sqlusername, NULL) < 0)
1507 return RLM_MODULE_FAIL;
1509 /* If postauth_query is not defined, we stop here */
1510 if (inst->config->postauth_query[0] == '\0')
1511 return RLM_MODULE_NOOP;
1513 /* Expand variables in the query */
1514 memset(querystr, 0, MAX_QUERY_LEN);
1515 radius_xlat(querystr, sizeof(querystr), inst->config->postauth_query,
1516 request, sql_escape_func);
1517 query_log(request, inst, querystr);
1518 DEBUG2("rlm_sql (%s) in sql_postauth: query is %s",
1519 inst->config->xlat_name, querystr);
1521 /* Initialize the sql socket */
1522 sqlsocket = sql_get_socket(inst);
1523 if (sqlsocket == NULL)
1524 return RLM_MODULE_FAIL;
1526 /* Process the query */
1527 if (rlm_sql_query(sqlsocket, inst, querystr)) {
1528 radlog(L_ERR, "rlm_sql (%s) in sql_postauth: Database query error - %s",
1529 inst->config->xlat_name,
1530 (char *)(inst->module->sql_error)(sqlsocket, inst->config));
1531 sql_release_socket(inst, sqlsocket);
1532 return RLM_MODULE_FAIL;
1534 (inst->module->sql_finish_query)(sqlsocket, inst->config);
1536 sql_release_socket(inst, sqlsocket);
1537 return RLM_MODULE_OK;
1540 /* globally exported name */
1541 module_t rlm_sql = {
1544 RLM_TYPE_THREAD_SAFE, /* type: reserved */
1545 rlm_sql_instantiate, /* instantiation */
1546 rlm_sql_detach, /* detach */
1548 NULL, /* authentication */
1549 rlm_sql_authorize, /* authorization */
1550 NULL, /* preaccounting */
1551 rlm_sql_accounting, /* accounting */
1552 rlm_sql_checksimul, /* checksimul */
1553 NULL, /* pre-proxy */
1554 NULL, /* post-proxy */
1555 rlm_sql_postauth /* post-auth */