39 |
static void sql_check_config(SQL_cfg *); |
static void sql_check_config(SQL_cfg *); |
40 |
static struct sql_connection *attach_sql_connection(int type); |
static struct sql_connection *attach_sql_connection(int type); |
41 |
static void detach_sql_connection(int type); |
static void detach_sql_connection(int type); |
42 |
|
static void sql_conn_destroy(struct sql_connection **conn); |
43 |
|
|
44 |
static char *getline(); |
static char *getline(); |
45 |
static int get_boolean(char *str, int *retval); |
static int get_boolean(char *str, int *retval); |
76 |
#define STMT_INTERFACE 22 |
#define STMT_INTERFACE 22 |
77 |
#define STMT_CHECK_ATTR_QUERY 23 |
#define STMT_CHECK_ATTR_QUERY 23 |
78 |
|
|
79 |
|
|
80 |
|
/* *********************** Configuration File Parser *********************** */ |
81 |
|
|
82 |
static FILE *sqlfd; |
static FILE *sqlfd; |
83 |
static int line_no; |
static int line_no; |
84 |
static char *cur_line, *cur_ptr; |
static char *cur_line, *cur_ptr; |
486 |
return 0; |
return 0; |
487 |
} |
} |
488 |
|
|
|
static void |
|
|
sql_conn_destroy(struct sql_connection **conn) |
|
|
{ |
|
|
if (*conn) { |
|
|
disp_sql_disconnect(*conn); |
|
|
efree(*conn); |
|
|
*conn = NULL; |
|
|
} |
|
|
} |
|
|
|
|
489 |
void |
void |
490 |
radiusd_sql_shutdown() |
radiusd_sql_shutdown() |
491 |
{ |
{ |
558 |
cfg->doauth)); |
cfg->doauth)); |
559 |
} |
} |
560 |
|
|
|
|
|
561 |
void |
void |
562 |
sql_flush() |
sql_flush() |
563 |
{ |
{ |
567 |
radiusd_sql_shutdown(); |
radiusd_sql_shutdown(); |
568 |
} |
} |
569 |
|
|
570 |
|
|
571 |
|
/* ********************************* SQL Cache ***************************** */ |
572 |
|
static void |
573 |
|
sql_result_destroy(SQL_RESULT *res) |
574 |
|
{ |
575 |
|
size_t i; |
576 |
|
|
577 |
|
if (!res) |
578 |
|
return; |
579 |
|
efree(res->query); |
580 |
|
for (i = 0; i < res->ntuples; i++) { |
581 |
|
size_t j; |
582 |
|
for (j = 0; j < res->nfields; j++) |
583 |
|
efree(res->tuple[i][j]); |
584 |
|
efree(res->tuple[i]); |
585 |
|
} |
586 |
|
efree(res->tuple); |
587 |
|
efree(res); |
588 |
|
} |
589 |
|
|
590 |
|
static size_t |
591 |
|
sql_cache_level(struct sql_connection *conn) |
592 |
|
{ |
593 |
|
if (conn->tail < conn->head) |
594 |
|
return conn->tail + SQL_CACHE_SIZE - conn->head; |
595 |
|
else |
596 |
|
return conn->tail - conn->head; |
597 |
|
} |
598 |
|
|
599 |
|
static void |
600 |
|
sql_cache_destroy(struct sql_connection *conn) |
601 |
|
{ |
602 |
|
size_t i; |
603 |
|
|
604 |
|
for (; sql_cache_level(conn) > 0; |
605 |
|
conn->head = (conn->head + 1) % SQL_CACHE_SIZE) |
606 |
|
sql_result_destroy(conn->cache[conn->head]); |
607 |
|
} |
608 |
|
|
609 |
|
static void |
610 |
|
sql_cache_insert(struct sql_connection *conn, SQL_RESULT *res) |
611 |
|
{ |
612 |
|
debug(1,("cache: %d,(%d,%d)",sql_cache_level(conn),conn->head,conn->tail)); |
613 |
|
if (sql_cache_level(conn) >= SQL_CACHE_SIZE-1) { |
614 |
|
sql_result_destroy(conn->cache[conn->head]); |
615 |
|
conn->head = (conn->head + 1) % SQL_CACHE_SIZE; |
616 |
|
debug(1,("head: %d,%d", conn->head,conn->tail)); |
617 |
|
} |
618 |
|
debug(1,("inserting at pos %d", conn->tail)); |
619 |
|
conn->cache[conn->tail] = res; |
620 |
|
conn->tail = (conn->tail + 1) % SQL_CACHE_SIZE; |
621 |
|
debug(1,("tail: %d,%d", conn->head,conn->tail)); |
622 |
|
} |
623 |
|
|
624 |
|
static SQL_RESULT * |
625 |
|
sql_cache_retrieve(struct sql_connection *conn, char *query) |
626 |
|
{ |
627 |
|
void *data; |
628 |
|
SQL_RESULT *res; |
629 |
|
size_t i; |
630 |
|
|
631 |
|
debug(1,("query: %s",query)); |
632 |
|
res = emalloc(sizeof(*res)); |
633 |
|
res->query = estrdup(query); |
634 |
|
res->nfields = res->ntuples = 0; |
635 |
|
res->tuple = NULL; |
636 |
|
data = disp_sql_exec(conn, query); |
637 |
|
if (!data) { |
638 |
|
sql_cache_insert(conn, res); |
639 |
|
return res; |
640 |
|
} |
641 |
|
|
642 |
|
if (disp_sql_num_tuples(conn, data, &res->ntuples) |
643 |
|
|| disp_sql_num_columns(conn, data, &res->nfields)) { |
644 |
|
disp_sql_free(conn, data); |
645 |
|
res->nfields = res->ntuples = 0; |
646 |
|
sql_cache_insert(conn, res); |
647 |
|
return res; |
648 |
|
} |
649 |
|
|
650 |
|
res->tuple = emalloc(sizeof(res->tuple[0]) * res->ntuples); |
651 |
|
for (i = 0; i < res->ntuples |
652 |
|
&& disp_sql_next_tuple(conn, data) == 0; i++) { |
653 |
|
int j; |
654 |
|
|
655 |
|
res->tuple[i] = emalloc(sizeof(res->tuple[0][0]) * res->nfields); |
656 |
|
|
657 |
|
for (j = 0; j < res->nfields; j++) { |
658 |
|
char *p = disp_sql_column(conn, data, j); |
659 |
|
chop(p); |
660 |
|
res->tuple[i][j] = estrdup(p); |
661 |
|
} |
662 |
|
} |
663 |
|
|
664 |
|
disp_sql_free(conn, data); |
665 |
|
|
666 |
|
sql_cache_insert(conn, res); |
667 |
|
|
668 |
|
return res; |
669 |
|
} |
670 |
|
|
671 |
|
static SQL_RESULT * |
672 |
|
sql_cache_lookup(struct sql_connection *conn, char *query) |
673 |
|
{ |
674 |
|
size_t i; |
675 |
|
|
676 |
|
debug(1,("looking up %s", query)); |
677 |
|
for (i = conn->head; i != conn->tail; |
678 |
|
i = (i + 1) % SQL_CACHE_SIZE) { |
679 |
|
if (strcmp(conn->cache[i]->query, query) == 0) { |
680 |
|
debug(1,("found at %d", i)); |
681 |
|
return conn->cache[i]; |
682 |
|
} |
683 |
|
} |
684 |
|
debug(1,("NOT FOUND")); |
685 |
|
return NULL; |
686 |
|
} |
687 |
|
|
688 |
|
|
689 |
|
/* *********************** SQL Connection Handling ************************* */ |
690 |
|
|
691 |
struct sql_connection * |
struct sql_connection * |
692 |
attach_sql_connection(int type) |
attach_sql_connection(int type) |
693 |
{ |
{ |
704 |
conn->last_used = now; |
conn->last_used = now; |
705 |
conn->type = type; |
conn->type = type; |
706 |
|
|
707 |
|
conn->head = 0; |
708 |
|
conn->tail = 0; |
709 |
sql_conn[type] = conn; |
sql_conn[type] = conn; |
710 |
} |
} |
711 |
|
|
738 |
} |
} |
739 |
} |
} |
740 |
|
|
741 |
|
static void |
742 |
|
sql_conn_destroy(struct sql_connection **conn) |
743 |
|
{ |
744 |
|
if (*conn) { |
745 |
|
disp_sql_disconnect(*conn); |
746 |
|
sql_cache_destroy(*conn); |
747 |
|
efree(*conn); |
748 |
|
*conn = NULL; |
749 |
|
} |
750 |
|
} |
751 |
|
|
752 |
|
|
753 |
|
/* ************************* Interface Functions *************************** */ |
754 |
|
|
755 |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
756 |
void |
void |
757 |
rad_sql_cleanup(int type, void *req ARG_UNUSED) |
rad_sql_cleanup(int type, void *req ARG_UNUSED) |
910 |
{ |
{ |
911 |
int rc = -1; |
int rc = -1; |
912 |
struct sql_connection *conn; |
struct sql_connection *conn; |
|
void *data; |
|
|
char *p; |
|
913 |
char *query; |
char *query; |
914 |
struct obstack stack; |
struct obstack stack; |
915 |
|
SQL_RESULT *res; |
916 |
|
size_t i; |
917 |
|
|
918 |
if (sql_cfg.doauth == 0 || sql_cfg.group_query == NULL) |
if (sql_cfg.doauth == 0 || sql_cfg.group_query == NULL) |
919 |
return -1; |
return -1; |
925 |
obstack_init(&stack); |
obstack_init(&stack); |
926 |
|
|
927 |
query = radius_xlate(&stack, sql_cfg.group_query, req, NULL); |
query = radius_xlate(&stack, sql_cfg.group_query, req, NULL); |
928 |
|
res = sql_cache_lookup(conn, query); |
929 |
|
if (!res) { |
930 |
|
res = sql_cache_retrieve(conn, query); |
931 |
|
if (!res) |
932 |
|
return rc; |
933 |
|
} |
934 |
|
obstack_free(&stack, NULL); |
935 |
|
|
936 |
data = disp_sql_exec(conn, query); |
if (res->ntuples == 0 || res->nfields == 0) |
937 |
if (data) { |
return rc; |
938 |
while (rc != 0 |
|
939 |
&& disp_sql_next_tuple(conn, data) == 0) { |
for (i = 0; rc != 0 && i < res->ntuples; i++) { |
940 |
if ((p = disp_sql_column(conn, data, 0)) == NULL) |
if (strcmp(res->tuple[i][0], groupname) == 0) |
941 |
break; |
rc = 0; |
|
chop(p); |
|
|
if (strcmp(p, groupname) == 0) |
|
|
rc = 0; |
|
|
} |
|
|
disp_sql_free(conn, data); |
|
942 |
} |
} |
943 |
|
|
|
obstack_free(&stack, NULL); |
|
944 |
return rc; |
return rc; |
945 |
} |
} |
946 |
|
|
950 |
VALUE_PAIR **return_pairs, |
VALUE_PAIR **return_pairs, |
951 |
int op_too) |
int op_too) |
952 |
{ |
{ |
953 |
void *data; |
SQL_RESULT *res; |
954 |
int i; |
size_t i; |
955 |
|
|
956 |
data = disp_sql_exec(conn, query); |
res = sql_cache_lookup(conn, query); |
957 |
if (!data) |
if (!res) { |
958 |
return 0; |
res = sql_cache_retrieve(conn, query); |
959 |
|
if (!res) |
960 |
for (i = 0; disp_sql_next_tuple(conn, data) == 0; i++) { |
return 0; |
961 |
VALUE_PAIR *pair; |
} |
962 |
char *attribute; |
|
963 |
char *value; |
if (res->ntuples == 0 |
964 |
int op; |
|| res->nfields < 2 |
965 |
|
|| (op_too && res->nfields < 3)) |
966 |
if (!(attribute = disp_sql_column(conn, data, 0)) |
return 0; |
967 |
|| !(value = disp_sql_column(conn, data, 1))) |
|
968 |
break; |
for (i = 0; i < res->ntuples; i++) { |
969 |
if (op_too) { |
int op; |
970 |
char *opstr; |
VALUE_PAIR *pair; |
971 |
opstr = disp_sql_column(conn, data, 2); |
|
972 |
if (!opstr) |
if (op_too) { |
973 |
break; |
char *opstr = res->tuple[i][2]; |
|
chop(opstr); |
|
974 |
op = str_to_op(opstr); |
op = str_to_op(opstr); |
975 |
if (op == NUM_OPERATORS) { |
if (op == NUM_OPERATORS) { |
976 |
radlog(L_NOTICE, |
radlog(L_NOTICE, |
977 |
_("SQL: invalid operator: %s"), opstr); |
_("SQL: invalid operator: %s"), opstr); |
978 |
continue; |
continue; |
979 |
} |
} |
980 |
} else |
} else |
981 |
op = OPERATOR_EQUAL; |
op = OPERATOR_EQUAL; |
982 |
|
|
983 |
chop(attribute); |
pair = install_pair(__FILE__, __LINE__, |
984 |
chop(value); |
res->tuple[i][0], |
985 |
|
op, |
986 |
pair = install_pair(__FILE__, __LINE__, attribute, op, value); |
res->tuple[i][1]); |
987 |
|
|
988 |
if (pair) { |
if (pair) { |
989 |
avl_merge(return_pairs, &pair); |
avl_merge(return_pairs, &pair); |
990 |
avl_free(pair); |
avl_free(pair); |
991 |
} |
} |
992 |
} |
} |
993 |
|
|
994 |
disp_sql_free(conn, data); |
return i; |
|
return i; |
|
995 |
} |
} |
996 |
|
|
997 |
int |
int |
998 |
rad_sql_reply_attr_query(RADIUS_REQ *req, VALUE_PAIR **reply_pairs) |
rad_sql_reply_attr_query(RADIUS_REQ *req, VALUE_PAIR **reply_pairs) |
999 |
{ |
{ |