key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port-Id"
}
-
- #
- # Configuration for the SQL module.
- #
- sql {
-
- # Connect info
- server = "localhost"
- login = "root"
- password = "rootpass"
-
- # Database table configuration
- radius_db = "radius"
- acct_table = "radacct"
-
- authcheck_table = "radcheck"
- authreply_table = "radreply"
-
- groupcheck_table = "radgroupcheck"
- groupreply_table = "radgroupreply"
-
- usergroup_table = "usergroup"
-
- realms_table = "realms"
- realmgroup_table = "realmgroup"
-
- # Check case on usernames
- sensitiveusername = no
-
- # Remove stale session if checkrad does not see a double login
- deletestalesessions = yes
-
- # Print all SQL statements when in debug mode (-x)
- sqltrace = no
- sqltracefile = ${logdir}/sqltrace.sql
-
- # number of sql connections to make to server
- num_sql_socks = 5
- }
-
- #
- # A second instance of the same module, with the name "sql2" to identify it
- #
- sql sql2 {
-
- # Connect info
- server = "myothersever"
- login = "root"
- password = "rootpass"
-
- # Database table configuration
- radius_db = "radius"
- acct_table = "radacct"
-
- authcheck_table = "radcheck"
- authreply_table = "radreply"
-
- groupcheck_table = "radgroupcheck"
- groupreply_table = "radgroupreply"
-
- usergroup_table = "usergroup"
-
- realms_table = "realms"
- realmgroup_table = "realmgroup"
-
- # Check case on usernames
- sensitiveusername = no
-
- # Remove stale session if checkrad does not see a double login
- deletestalesessions = yes
-
- # Print all SQL statements when in debug mode (-x)
- sqltrace = no
- }
+ $INCLUDE ${confdir}/sql.conf
radutmp {
filename = ${logdir}/radutmp
--- /dev/null
+#
+# Configuration for the SQL module.
+#
+sql {
+
+ # Connect info
+ server = "localhost"
+ login = "root"
+ password = "rootpass"
+
+ # Database table configuration
+ radius_db = "radius"
+
+ # If you want both stop and start records logged to the
+ # same SQL table, leave this as is. If you want them in
+ # different tables, put the start table in acct_table1
+ # and stop table in acct_table2
+ acct_table1 = "radacct"
+ acct_table2 = "radacct"
+
+ authcheck_table = "radcheck"
+ authreply_table = "radreply"
+
+ groupcheck_table = "radgroupcheck"
+ groupreply_table = "radgroupreply"
+
+ usergroup_table = "usergroup"
+
+ # Remove stale session if checkrad does not see a double login
+ deletestalesessions = yes
+
+ # Print all SQL statements when in debug mode (-x)
+ sqltrace = no
+ sqltracefile = ${logdir}/sqltrace.sql
+
+ # number of sql connections to make to server
+ num_sql_socks = 5
+
+ ########################################################################
+ # Authorization Queries
+ ########################################################################
+ # These queries compare the check items for the user
+ # in ${authcheck_table} and setup the reply items in
+ # ${authreply_table}. You can use any query/tables
+ # you want, but the return data for each row MUST
+ # be in the following order:
+ #
+ # 0. Check Item Attr Name
+ # 1. Check Item Attr Value
+ # 2. Reply Item Attr Name
+ # 3. Reply Item Attr Value
+ ########################################################################
+
+ authorize_query = "SELECT ${authcheck_table}.Attribute,${authcheck_table}.Value,${authreply_table}.Attribute,${authreply_table}.Value FROM ${authcheck_table},${authreply_table} WHERE STRCMP(${authcheck_table}.Username, '%{User-Name}') = 0 ORDER BY ${authcheck_table}.id"
+
+ authorize_group_query = "SELECT ${groupcheck_table}.Attribute,${groupcheck_table}.Value,${groupreply_table}.Attribute,${groupreply_table}.Value FROM ${groupcheck_table},${groupreply_table},${usergroup_table} WHERE STRCMP(${usergroup_table}.Username, '%{User-Name}') = 0 AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName ORDER BY ${groupcheck_table}.id"
+
+ ########################################################################
+ # Authentication Query
+ ########################################################################
+ # This query is used only to get the Password for the
+ # user we want to authenticate. The password MUST
+ # be the first field in the return row data.
+ ########################################################################
+
+ authenticate_query = "SELECT Value FROM ${authcheck_table} WHERE UserName = '%{User-Name}' AND Attribute = 'Password'"
+
+ ########################################################################
+ # Accounting Queries
+ ########################################################################
+ # accounting_onoff_query - query for Accounting On/Off packets
+ # accounting_update_query - query for Accounting update packets
+ # accounting_start_query - query for Accounting start packets
+ # accounting_start_query_alt - query for Accounting start packets
+ # (alternate in case first query fails)
+ # accounting_stop_query - query for Accounting stop packets
+ # accounting_stop_query_alt - query for Accounting start packets
+ # (alternate in case first query doesn't
+ # affect any existing rows in the table)
+ ########################################################################
+ accounting_onoff_query = "UPDATE ${acct_table1} SET AcctStopTime='%S', AcctSessionTime=unix_timestamp('%S') - unix_timestamp(AcctStartTime), AcctTerminateCause='%{Acct-Terminate-Cause}', AcctStopDelay = %{Acct-Delay-Time} WHERE AcctSessionTime=0 AND AcctStopTime=0 AND NASIPAddress= '%{NAS-IP-Address}' AND AcctStartTime <= '%S'"
+
+ accounting_update_query = "UPDATE ${acct_table1} SET FramedIPAddress = '%{Framed-IP-Address}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{User-Name}' AND NASIPAddress= '%{NAS-IP-Address}'"
+
+ accounting_start_query = "INSERT into radacct (RadAcctId, AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPortId, NASPortType, AcctStartTime, AcctStopTime, AcctSessionTime, AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, AcctOutputOctets, CalledStationId, CallingStationId, AcctTerminateCause, ServiceType, FramedProtocol, FramedIPAddress, AcctStartDelay, AcctStopDelay) values('', '%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', '%S', '0', '0', '%{Acct-Authentic}', '%{Connect-Info}', '', '0', '0', '%{Called-Station-Id}', '%{Calling-Station-Id}', '', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', '%{Acct-Delay-Time}', '0')"
+
+ accounting_start_query_alt = "UPDATE ${acct_table1} SET AcctStartTime = '%S', AcctStartDelay = '%{Acct-Delay-Time}', ConnectInfo_start = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{User-Name}' AND NASIPAddress = '%{NAS-IP-Address}'"
+
+ accounting_stop_query = "UPDATE ${acct_table1} SET AcctStopTime = '%S', AcctSessionTime = '%{Acct-Session-Time}', AcctInputOctets = '%{Acct-Input-Octets}', AcctOutputOctets = '%{Acct-Output-Octets}', AcctTerminateCause = '%{Acct-Terminate-Cause}', AcctStopDelay = %{Acct-Delay-Time}, ConnectInfo_stop = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{User-Name}' AND NASIPAddress = '%{NAS-IP-Address}'"
+
+ accounting_stop_query_alt = "INSERT into radacct (RadAcctId, AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPortId, NASPortType, AcctStartTime, AcctStopTime, AcctSessionTime, AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, AcctOutputOctets, CalledStationId, CallingStationId, AcctTerminateCause, ServiceType, FramedProtocol, FramedIPAddress, AcctStartDelay, AcctStopDelay) values('', '%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', '0', '%S', '%{Acct-Session-Time}', '%{Acct-Authentic}', '', '%{Connect-Info}', '%{Acct-Input-Octets}', '%{Acct-Output-Octets}', '%{Called-Station-Id}', '%{Calling-Station-Id}', '%{Acct-Terminate-Cause}', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', '0', '%{Acct-Delay-Time}')"
+
+}
}
}
+static void decode_attribute(char **from, char **to, int freespace, int *open, REQUEST *request) {
+
+ DICT_ATTR *tmpda;
+ VALUE_PAIR *tmppair;
+ char attrname[256];
+ char *p, *q, *pa;
+ int stop=0, found=0;
+ int openbraces = *open;
+
+ p = *from;
+ q = *to;
+ pa = &attrname[0];
+
+ /*
+ * Skip the '}' at the front of 'p'
+ * Increment open braces
+ */
+ p++;
+ openbraces++;
+
+ while ((*p) && (!stop)) {
+ switch(*p) {
+ case '}':
+ openbraces--;
+ stop=1;
+ break;
+
+ case ':':
+ if(*(p+1) && (*(p+1) == '-')) {
+ p+=2;
+ stop=1;
+ }
+ break;
+
+ default:
+ *pa++ = *p++;
+ }
+ }
+ *pa = '\0';
+
+ if (strncasecmp(attrname,"reply:",6) == 0) {
+ if((tmpda = dict_attrbyname(&attrname[6])) &&
+ (tmppair = pairfind(request->reply->vps, tmpda->attr))) {
+ q += valuepair2str(q,freespace,tmppair,tmpda->type);
+ found = 1;
+ }
+ } else if (strncasecmp(attrname,"request:",8) == 0) {
+ if((tmpda = dict_attrbyname(&attrname[8])) &&
+ (tmppair = pairfind(request->packet->vps, tmpda->attr))) {
+ q += valuepair2str(q,freespace,tmppair,tmpda->type);
+ found = 1;
+ }
+ } else {
+ if((tmpda = dict_attrbyname(attrname)) &&
+ (tmppair = pairfind(request->packet->vps,tmpda->attr))) {
+ q += valuepair2str(q,freespace,tmppair,tmpda->type);
+ found = 1;
+ }
+ }
+
+ /*
+ * Skip to last '}' if attr is found
+ * The rest of the stuff within the braces is
+ * useless if we found we we need
+ */
+ if(found) {
+ while((*p) && (openbraces)) {
+ if(*p == '}')
+ openbraces--;
+ if(openbraces)
+ p++;
+ }
+ } else {
+ p--;
+ }
+
+ *open = openbraces;
+ *from = p;
+ *to = q;
+
+}
+
/*
* Based on radius_xlat from exec.c
* %n NAS IP address
* %p Port number
* %s Speed (PW_CONNECT_INFO)
- * %t MTU
+ * %t request in ctime format
* %u User name
* %A radacct_dir
* %C clientname
* %D request date (YYYYMMDD)
- * %I request in ctime format
* %L radlog_dir
+ * %M MTU
* %R radius_dir
+ * %S request timestamp in database format (w/ spaces)
* %T request timestamp in database format
* %U Stripped User name
* %V Request-Authenticator (Verified/None)
int radius_xlat2(char * out,int outlen, const char *fmt, REQUEST * request)
{
- char attrname[128];
- char *pa;
int i, c,freespace;
const char *p;
char *q;
VALUE_PAIR *tmp;
struct tm * TM;
char tmpdt[40]; /* For temporary storing of dates */
+ int openbraces=0;
q = out;
for (p = fmt; *p ; p++) {
break;
c = *p;
if ((c != '%') && (c != '$') && (c != '\\')) {
+ /*
+ * We check if we're inside an open brace. If we are
+ * then we assume this brace is NOT literal, but is
+ * a closing brace and apply it
+ */
+ if((c == '}') && openbraces) {
+ openbraces--;
+ continue;
+ }
*q++ = *p;
continue;
}
break;
} else if (c == '$') switch(*p) {
case '{': /* Attribute by Name */
- decode_attribute:
- pa = &attrname[0];
- p++;
- while (*p && (*p != '}')) {
- *pa++ = *p++;
- }
- *pa = '\0';
- if (strncasecmp(attrname,"reply:",6) == 0) {
- q += valuebyname(q,freespace,request->reply->vps,&attrname[6]);
- } else if (strncasecmp(attrname,"request:",8) == 0) {
- q += valuebyname(q,freespace,request->packet->vps,&attrname[8]);
- } else {
- q += valuebyname(q,freespace,request->packet->vps,attrname);
- }
- break;
+ decode_attribute((char **)&p, &q, freespace, &openbraces, request);
default:
*q++ = c;
*q++ = *p;
break;
+
} else if (c == '%') switch(*p) {
case '{':
- goto decode_attribute;
+ decode_attribute((char **)&p, &q, freespace, &openbraces, request);
break;
case '%':
case 's': /* Speed */
q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CONNECT_INFO),PW_TYPE_STRING);
break;
- case 't': /* MTU */
- q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_MTU),PW_TYPE_INTEGER);
+ case 't': /* request timestamp */
+ strNcpy(q,ctime(&request->timestamp),freespace);
+ q += strlen(q);
break;
case 'u': /* User name */
q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_USER_NAME),PW_TYPE_STRING);
strNcpy(q,tmpdt,freespace);
q += strlen(q);
break;
- case 'I': /* request timestamp */
- strNcpy(q,ctime(&request->timestamp),freespace);
- q += strlen(q);
- break;
case 'L': /* radlog_dir */
strNcpy(q,radlog_dir,freespace-1);
q += strlen(q);
break;
+ case 'M': /* MTU */
+ q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_MTU),PW_TYPE_INTEGER);
+ break;
case 'R': /* radius_dir */
strNcpy(q,radius_dir,freespace-1);
q += strlen(q);
break;
+ case 'S': /* request timestamp in SQL format*/
+ TM = localtime(&request->timestamp);
+ strftime(tmpdt,sizeof(tmpdt),"%Y%m%d%H%M%S",TM);
+ strNcpy(q,tmpdt,freespace);
+ q += strlen(q);
+ break;
case 'T': /* request timestamp */
TM = localtime(&request->timestamp);
strftime(tmpdt,sizeof(tmpdt),"%Y-%m-%d-%H.%M.%S.000000",TM);