Jeff Carneal <jeff@apex.net>
authorjcarneal <jcarneal>
Fri, 2 Feb 2001 21:22:56 +0000 (21:22 +0000)
committerjcarneal <jcarneal>
Fri, 2 Feb 2001 21:22:56 +0000 (21:22 +0000)
Finally.  The SQL config-based queries patch.  It's really alpha, and there
are probably bugs.  However, whatever bugs exist should be simple, as the
logic behind the patch is straight-forward.

raddb/radiusd.conf.in
raddb/sql.conf [new file with mode: 0644]
src/main/xlat.c

index 607e5e7..67c6ddb 100644 (file)
@@ -492,80 +492,7 @@ modules {
                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
diff --git a/raddb/sql.conf b/raddb/sql.conf
new file mode 100644 (file)
index 0000000..784fb1e
--- /dev/null
@@ -0,0 +1,93 @@
+#
+#  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}')"
+
+}
index 6cc42e2..8ed49de 100644 (file)
@@ -79,6 +79,88 @@ static int valuebyname(char * out,int outlen,VALUE_PAIR * request, char * attrna
        }
 }
 
+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
@@ -96,14 +178,15 @@ static int valuebyname(char * out,int outlen,VALUE_PAIR * request, char * attrna
  *     %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)
@@ -116,14 +199,13 @@ static int valuebyname(char * out,int outlen,VALUE_PAIR * request, char * attrna
 
 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++) {
@@ -133,6 +215,15 @@ int radius_xlat2(char * out,int outlen, const char *fmt, REQUEST * request)
                  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;
                }
@@ -153,28 +244,15 @@ int radius_xlat2(char * out,int outlen, const char *fmt, REQUEST * request)
                                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 '%':
@@ -218,8 +296,9 @@ int radius_xlat2(char * out,int outlen, const char *fmt, REQUEST * request)
                        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);
@@ -238,18 +317,23 @@ int radius_xlat2(char * out,int outlen, const char *fmt, REQUEST * request)
                                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);