1 |
/* This file is part of GNU RADIUS. |
/* This file is part of GNU Radius. |
2 |
Copyright (C) 2000,2001, Sergey Poznyakoff |
Copyright (C) 2000,2001,2002,2003 Sergey Poznyakoff |
3 |
|
|
4 |
This program is free software; you can redistribute it and/or modify |
GNU Radius is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
6 |
the Free Software Foundation; either version 2 of the License, or |
the Free Software Foundation; either version 2 of the License, or |
7 |
(at your option) any later version. |
(at your option) any later version. |
8 |
|
|
9 |
This program is distributed in the hope that it will be useful, |
GNU Radius is distributed in the hope that it will be useful, |
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
GNU General Public License for more details. |
GNU General Public License for more details. |
13 |
|
|
14 |
You should have received a copy of the GNU General Public License |
You should have received a copy of the GNU General Public License |
15 |
along with this program; if not, write to the Free Software Foundation, |
along with GNU Radius; if not, write to the Free Software Foundation, |
16 |
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
17 |
|
|
18 |
#define RADIUS_MODULE_SQL_C |
#define RADIUS_MODULE_SQL_C |
|
#ifndef lint |
|
|
static char rcsid[] = |
|
|
"@(#) $Id$"; |
|
|
#endif |
|
19 |
|
|
20 |
#if defined(HAVE_CONFIG_H) |
#if defined(HAVE_CONFIG_H) |
21 |
# include <config.h> |
# include <config.h> |
39 |
|
|
40 |
static char *getline(); |
static char *getline(); |
41 |
static int get_boolean(char *str, int *retval); |
static int get_boolean(char *str, int *retval); |
|
static int get_unsigned(char *str, unsigned *retval); |
|
42 |
static char * sql_digest(SQL_cfg *cfg); |
static char * sql_digest(SQL_cfg *cfg); |
43 |
static int sql_digest_comp(char *d1, char *d2); |
static int sql_digest_comp(char *d1, char *d2); |
44 |
static int sql_cfg_comp(SQL_cfg *a, SQL_cfg *b); |
static int sql_cfg_comp(SQL_cfg *a, SQL_cfg *b); |
46 |
static void sql_flush(); |
static void sql_flush(); |
47 |
|
|
48 |
SQL_cfg sql_cfg; |
SQL_cfg sql_cfg; |
49 |
|
static struct sql_connection *sql_conn[SQL_NSERVICE]; |
50 |
|
|
51 |
#define STMT_SERVER 1 |
#define STMT_SERVER 1 |
52 |
#define STMT_PORT 2 |
#define STMT_PORT 2 |
78 |
static struct obstack parse_stack; |
static struct obstack parse_stack; |
79 |
static int stmt_type; |
static int stmt_type; |
80 |
|
|
|
static pthread_key_t sql_conn_key[SQL_NSERVICE]; |
|
|
static pthread_once_t sql_conn_key_once = PTHREAD_ONCE_INIT; |
|
|
|
|
81 |
struct keyword sql_keyword[] = { |
struct keyword sql_keyword[] = { |
82 |
"server", STMT_SERVER, |
"server", STMT_SERVER, |
83 |
"port", STMT_PORT, |
"port", STMT_PORT, |
110 |
* Chop off trailing whitespace. Return length of the resulting string |
* Chop off trailing whitespace. Return length of the resulting string |
111 |
*/ |
*/ |
112 |
int |
int |
113 |
chop(str) |
chop(char *str) |
|
char *str; |
|
114 |
{ |
{ |
115 |
int len; |
int len; |
116 |
|
|
175 |
} |
} |
176 |
|
|
177 |
int |
int |
178 |
get_boolean(str, retval) |
get_boolean(char *str, int *retval) |
|
char *str; |
|
|
int *retval; |
|
179 |
{ |
{ |
180 |
if (strcmp(str, "yes") == 0) |
if (strcmp(str, "yes") == 0) |
181 |
*retval = 1; |
*retval = 1; |
187 |
} |
} |
188 |
|
|
189 |
char * |
char * |
190 |
sql_digest(cfg) |
sql_digest(SQL_cfg *cfg) |
|
SQL_cfg *cfg; |
|
191 |
{ |
{ |
192 |
int length; |
int length; |
193 |
char *digest, *p; |
char *digest, *p; |
235 |
} |
} |
236 |
|
|
237 |
int |
int |
238 |
sql_digest_comp(d1, d2) |
sql_digest_comp(char *d1, char *d2) |
|
char *d1, *d2; |
|
239 |
{ |
{ |
240 |
int len; |
int len; |
241 |
|
|
246 |
} |
} |
247 |
|
|
248 |
int |
int |
249 |
sql_cfg_comp(a, b) |
sql_cfg_comp(SQL_cfg *a, SQL_cfg *b) |
|
SQL_cfg *a, *b; |
|
250 |
{ |
{ |
251 |
char *dig1, *dig2; |
char *dig1, *dig2; |
252 |
int rc; |
int rc; |
259 |
return rc; |
return rc; |
260 |
} |
} |
261 |
|
|
|
static void |
|
|
sql_conn_destroy(void *data) |
|
|
{ |
|
|
struct sql_connection *conn = data; |
|
|
disp_sql_disconnect(sql_cfg.interface, conn); |
|
|
mem_free(conn); |
|
|
} |
|
|
|
|
|
static void |
|
|
sql_conn_key_alloc() |
|
|
{ |
|
|
pthread_key_create(&sql_conn_key[SQL_AUTH], sql_conn_destroy); |
|
|
pthread_key_create(&sql_conn_key[SQL_ACCT], sql_conn_destroy); |
|
|
} |
|
|
|
|
|
void |
|
|
rad_sql_thread_cleanup(arg) |
|
|
void *arg; |
|
|
{ |
|
|
struct obstack *stk = arg; |
|
|
|
|
|
obstack_free(stk, NULL); |
|
|
|
|
|
disp_sql_drop(sql_cfg.interface, |
|
|
pthread_getspecific(sql_conn_key[SQL_AUTH])); |
|
|
disp_sql_drop(sql_cfg.interface, |
|
|
pthread_getspecific(sql_conn_key[SQL_ACCT])); |
|
|
} |
|
|
|
|
262 |
int |
int |
263 |
rad_sql_init() |
rad_sql_init() |
264 |
{ |
{ |
268 |
time_t timeout; |
time_t timeout; |
269 |
SQL_cfg new_cfg; |
SQL_cfg new_cfg; |
270 |
|
|
|
pthread_once(&sql_conn_key_once, sql_conn_key_alloc); |
|
|
|
|
271 |
#define FREE(a) if (a) efree(a); a = NULL |
#define FREE(a) if (a) efree(a); a = NULL |
272 |
|
|
273 |
bzero(&new_cfg, sizeof(new_cfg)); |
bzero(&new_cfg, sizeof(new_cfg)); |
482 |
} |
} |
483 |
|
|
484 |
static void |
static void |
485 |
radiusd_sql_shutdown_thread(unused) |
sql_conn_destroy(struct sql_connection **conn) |
|
void *unused; |
|
486 |
{ |
{ |
487 |
struct sql_connection *conn; |
if (*conn) { |
488 |
|
disp_sql_disconnect(sql_cfg.interface, *conn); |
489 |
debug(10, ("shutting down sql connections")); |
mem_free(*conn); |
490 |
conn = pthread_getspecific(sql_conn_key[SQL_AUTH]); |
*conn = NULL; |
491 |
if (conn) |
} |
|
disp_sql_disconnect(SQL_AUTH, conn); |
|
|
conn = pthread_getspecific(sql_conn_key[SQL_ACCT]); |
|
|
if (conn) |
|
|
disp_sql_disconnect(SQL_ACCT, conn); |
|
492 |
} |
} |
493 |
|
|
494 |
void |
void |
495 |
radiusd_sql_shutdown() |
radiusd_sql_shutdown() |
496 |
{ |
{ |
497 |
request_thread_command(radiusd_sql_shutdown_thread, NULL); |
sql_conn_destroy(&sql_conn[SQL_AUTH]); |
498 |
|
sql_conn_destroy(&sql_conn[SQL_ACCT]); |
499 |
} |
} |
500 |
|
|
501 |
void |
void |
502 |
sql_check_config(cfg) |
sql_check_config(SQL_cfg *cfg) |
|
SQL_cfg *cfg; |
|
503 |
{ |
{ |
504 |
#define FREE_IF_EMPTY(s) if (s && strcmp(s, "none") == 0) {\ |
#define FREE_IF_EMPTY(s) if (s && strcmp(s, "none") == 0) {\ |
505 |
efree(s);\ |
efree(s);\ |
569 |
{ |
{ |
570 |
radlog(L_NOTICE, |
radlog(L_NOTICE, |
571 |
_("SQL configuration changed: closing existing connections")); |
_("SQL configuration changed: closing existing connections")); |
572 |
radiusd_flush_queues(); |
radiusd_flush_queue(); |
573 |
radiusd_sql_shutdown(); |
radiusd_sql_shutdown(); |
574 |
} |
} |
575 |
|
|
576 |
struct sql_connection * |
struct sql_connection * |
577 |
attach_sql_connection(type) |
attach_sql_connection(int type) |
|
int type; |
|
578 |
{ |
{ |
579 |
struct sql_connection *conn; |
struct sql_connection *conn; |
580 |
time_t now; |
time_t now; |
581 |
|
|
582 |
time(&now); |
time(&now); |
583 |
conn = pthread_getspecific(sql_conn_key[type]); |
conn = sql_conn[type]; |
584 |
if (!conn) { |
if (!conn) { |
585 |
debug(1, ("allocating new %d sql connection", type)); |
debug(1, ("allocating new %d sql connection", type)); |
586 |
|
|
590 |
conn->last_used = now; |
conn->last_used = now; |
591 |
conn->type = type; |
conn->type = type; |
592 |
|
|
593 |
pthread_setspecific(sql_conn_key[type], conn); |
sql_conn[type] = conn; |
594 |
} |
} |
595 |
|
|
596 |
if (!conn->connected || now - conn->last_used > sql_cfg.idle_timeout) { |
if (!conn->connected || now - conn->last_used > sql_cfg.idle_timeout) { |
604 |
} |
} |
605 |
|
|
606 |
void |
void |
607 |
detach_sql_connection(type) |
detach_sql_connection(int type) |
|
int type; |
|
608 |
{ |
{ |
609 |
struct sql_connection *conn; |
struct sql_connection *conn; |
610 |
|
|
611 |
conn = pthread_getspecific(sql_conn_key[type]); |
conn = sql_conn[type]; |
612 |
if (!conn) |
if (!conn) |
613 |
return; |
return; |
614 |
debug(1, ("detaching %p [%d]", conn, type)); |
debug(1, ("detaching %p [%d]", conn, type)); |
618 |
if (conn->connected) |
if (conn->connected) |
619 |
disp_sql_disconnect(sql_cfg.interface, conn); |
disp_sql_disconnect(sql_cfg.interface, conn); |
620 |
mem_free(conn); |
mem_free(conn); |
621 |
pthread_setspecific(sql_conn_key[type], NULL); |
sql_conn[type] = NULL; |
622 |
} |
} |
623 |
} |
} |
624 |
|
|
625 |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
626 |
void |
void |
627 |
rad_sql_cleanup(type, req) |
rad_sql_cleanup(int type, void *req ARG_UNUSED) |
|
int type; |
|
|
RADIUS_REQ *req; /* Unused */ |
|
628 |
{ |
{ |
629 |
if (sql_cfg.active[type]) |
if (sql_cfg.active[type]) |
630 |
detach_sql_connection(type); |
detach_sql_connection(type); |
634 |
* Perform normal accounting |
* Perform normal accounting |
635 |
*/ |
*/ |
636 |
void |
void |
637 |
rad_sql_acct(radreq) |
rad_sql_acct(RADIUS_REQ *radreq) |
|
RADIUS_REQ *radreq; |
|
638 |
{ |
{ |
639 |
int rc, count; |
int rc, count; |
640 |
int status; |
int status; |
658 |
|
|
659 |
conn = attach_sql_connection(SQL_ACCT); |
conn = attach_sql_connection(SQL_ACCT); |
660 |
obstack_init(&stack); |
obstack_init(&stack); |
|
pthread_cleanup_push(rad_sql_thread_cleanup, &stack); |
|
661 |
|
|
662 |
switch (status) { |
switch (status) { |
663 |
case DV_ACCT_STATUS_TYPE_START: |
case DV_ACCT_STATUS_TYPE_START: |
743 |
count); |
count); |
744 |
} |
} |
745 |
|
|
|
pthread_cleanup_pop(0); |
|
746 |
obstack_free(&stack, NULL); |
obstack_free(&stack, NULL); |
747 |
} |
} |
748 |
|
|
749 |
|
|
750 |
char * |
char * |
751 |
rad_sql_pass(req, authdata) |
rad_sql_pass(RADIUS_REQ *req, char *authdata) |
|
RADIUS_REQ *req; |
|
|
char *authdata; |
|
752 |
{ |
{ |
753 |
char *mysql_passwd; |
char *mysql_passwd; |
754 |
struct sql_connection *conn; |
struct sql_connection *conn; |
773 |
avl_delete(&req->request, DA_AUTH_DATA); |
avl_delete(&req->request, DA_AUTH_DATA); |
774 |
|
|
775 |
conn = attach_sql_connection(SQL_AUTH); |
conn = attach_sql_connection(SQL_AUTH); |
|
pthread_cleanup_push(rad_sql_thread_cleanup, &stack); |
|
776 |
mysql_passwd = disp_sql_getpwd(sql_cfg.interface, conn, query); |
mysql_passwd = disp_sql_getpwd(sql_cfg.interface, conn, query); |
|
pthread_cleanup_pop(0); |
|
777 |
|
|
778 |
if (mysql_passwd) |
if (mysql_passwd) |
779 |
chop(mysql_passwd); |
chop(mysql_passwd); |
783 |
return mysql_passwd; |
return mysql_passwd; |
784 |
} |
} |
785 |
|
|
|
struct cleanup_data { |
|
|
struct sql_connection *conn; |
|
|
void *data; |
|
|
}; |
|
|
|
|
|
void |
|
|
rad_sql_data_cleanup(arg) |
|
|
void *arg; |
|
|
{ |
|
|
struct cleanup_data *p = arg; |
|
|
disp_sql_free(sql_cfg.interface, p->conn, p->data); |
|
|
} |
|
|
|
|
786 |
int |
int |
787 |
rad_sql_checkgroup(req, groupname) |
rad_sql_checkgroup(req, groupname) |
788 |
RADIUS_REQ *req; |
RADIUS_REQ *req; |
794 |
char *p; |
char *p; |
795 |
char *query; |
char *query; |
796 |
struct obstack stack; |
struct obstack stack; |
|
struct cleanup_data cleanup_data; |
|
797 |
|
|
798 |
if (sql_cfg.doauth == 0 || sql_cfg.group_query == NULL) |
if (sql_cfg.doauth == 0 || sql_cfg.group_query == NULL) |
799 |
return -1; |
return -1; |
803 |
return -1; |
return -1; |
804 |
|
|
805 |
obstack_init(&stack); |
obstack_init(&stack); |
|
pthread_cleanup_push(rad_sql_thread_cleanup, &stack); |
|
806 |
|
|
807 |
query = radius_xlate(&stack, sql_cfg.group_query, req, NULL); |
query = radius_xlate(&stack, sql_cfg.group_query, req, NULL); |
808 |
|
|
809 |
data = disp_sql_exec(sql_cfg.interface, conn, query); |
data = disp_sql_exec(sql_cfg.interface, conn, query); |
810 |
|
|
|
cleanup_data.conn = conn; |
|
|
cleanup_data.data = data; |
|
|
pthread_cleanup_push(rad_sql_data_cleanup, &cleanup_data); |
|
|
|
|
811 |
while (rc != 0 |
while (rc != 0 |
812 |
&& disp_sql_next_tuple(sql_cfg.interface, conn, data) == 0) { |
&& disp_sql_next_tuple(sql_cfg.interface, conn, data) == 0) { |
813 |
if ((p = disp_sql_column(sql_cfg.interface, data, 0)) == NULL) |
if ((p = disp_sql_column(sql_cfg.interface, data, 0)) == NULL) |
818 |
} |
} |
819 |
disp_sql_free(sql_cfg.interface, conn, data); |
disp_sql_free(sql_cfg.interface, conn, data); |
820 |
|
|
|
pthread_cleanup_pop(0); |
|
|
pthread_cleanup_pop(0); |
|
|
|
|
821 |
obstack_free(&stack, NULL); |
obstack_free(&stack, NULL); |
822 |
return rc; |
return rc; |
823 |
} |
} |
824 |
|
|
825 |
static int rad_sql_retrieve_pairs(struct sql_connection *conn, |
static int |
826 |
char *query, |
rad_sql_retrieve_pairs(struct sql_connection *conn, |
827 |
VALUE_PAIR **return_pairs, |
char *query, |
828 |
int op_too); |
VALUE_PAIR **return_pairs, |
829 |
|
int op_too) |
|
int |
|
|
rad_sql_retrieve_pairs(conn, query, return_pairs, op_too) |
|
|
struct sql_connection *conn; |
|
|
char *query; |
|
|
VALUE_PAIR **return_pairs; |
|
|
int op_too; |
|
830 |
{ |
{ |
831 |
void *data; |
void *data; |
832 |
int i; |
int i; |
876 |
} |
} |
877 |
|
|
878 |
int |
int |
879 |
rad_sql_reply_attr_query(req, reply_pairs) |
rad_sql_reply_attr_query(RADIUS_REQ *req, VALUE_PAIR **reply_pairs) |
|
RADIUS_REQ *req; |
|
|
VALUE_PAIR **reply_pairs; |
|
880 |
{ |
{ |
881 |
struct sql_connection *conn; |
struct sql_connection *conn; |
882 |
char *query; |
char *query; |
888 |
|
|
889 |
conn = attach_sql_connection(SQL_AUTH); |
conn = attach_sql_connection(SQL_AUTH); |
890 |
obstack_init(&stack); |
obstack_init(&stack); |
|
pthread_cleanup_push(rad_sql_thread_cleanup, &stack); |
|
891 |
|
|
892 |
query = radius_xlate(&stack, sql_cfg.reply_attr_query, req, NULL); |
query = radius_xlate(&stack, sql_cfg.reply_attr_query, req, NULL); |
893 |
rc = rad_sql_retrieve_pairs(conn, query, reply_pairs, 0); |
rc = rad_sql_retrieve_pairs(conn, query, reply_pairs, 0); |
894 |
|
|
|
pthread_cleanup_pop(0); |
|
895 |
obstack_free(&stack, NULL); |
obstack_free(&stack, NULL); |
896 |
return rc == 0; |
return rc == 0; |
897 |
} |
} |
898 |
|
|
899 |
int |
int |
900 |
rad_sql_check_attr_query(req, return_pairs) |
rad_sql_check_attr_query(RADIUS_REQ *req, VALUE_PAIR **return_pairs) |
|
RADIUS_REQ *req; |
|
|
VALUE_PAIR **return_pairs; |
|
901 |
{ |
{ |
902 |
struct sql_connection *conn; |
struct sql_connection *conn; |
903 |
char *query; |
char *query; |
909 |
|
|
910 |
conn = attach_sql_connection(SQL_AUTH); |
conn = attach_sql_connection(SQL_AUTH); |
911 |
obstack_init(&stack); |
obstack_init(&stack); |
|
pthread_cleanup_push(rad_sql_thread_cleanup, &stack); |
|
912 |
|
|
913 |
query = radius_xlate(&stack, sql_cfg.check_attr_query, req, NULL); |
query = radius_xlate(&stack, sql_cfg.check_attr_query, req, NULL); |
914 |
rc = rad_sql_retrieve_pairs(conn, query, return_pairs, 1); |
rc = rad_sql_retrieve_pairs(conn, query, return_pairs, 1); |
915 |
|
|
|
pthread_cleanup_pop(0); |
|
916 |
obstack_free(&stack, NULL); |
obstack_free(&stack, NULL); |
917 |
return rc == 0; |
return rc == 0; |
918 |
} |
} |