# Database table configuration for everything except Oracle
radius_db = "radius"
# If you are using Oracle then use this instead
- # radius_db = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SID=your_sid)))"
+ # radius_db = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SID=your_sid)))"
# If you want both stop and start records logged to the
# same SQL table, leave this as is. If you want them in
ORDER BY priority"
#######################################################################
- # Accounting Queries
+ # Accounting and Post-Auth Queries
#######################################################################
- # accounting_onoff_query - query for Accounting On/Off packets
- # accounting_update_query - query for Accounting update packets
- # accounting_update_query_alt - query for Accounting update packets
- # (alternate in case first query fails)
- # 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)
+ # These queries insert/update accounting and authentication records.
+ # The query to use is determined by the value of 'reference'.
+ # This value is used as a configuration path and should resolve to one
+ # or more 'query's. If reference points to multiple queries, and a query
+ # fails, the next query is executed.
+ #
+ # Behaviour is identical to the old 1.x/2.x module, except we can now
+ # fail between N queries, and query selection can be based on any
+ # combination of attributes, or custom 'Acct-Status-Type' values.
#######################################################################
- accounting_onoff_query = "UPDATE ${acct_table1} SET AcctStopTime='%S', AcctSessionTime=unix_timestamp('%S') - unix_timestamp(AcctStartTime), AcctTerminateCause='%{Acct-Terminate-Cause}', AcctStopDelay = %{Acct-Delay-Time:-0} WHERE 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 = '%{SQL-User-Name}' AND NASIPAddress= '%{NAS-IP-Address}' AND AcctStopTime = 0"
-
- accounting_update_query_alt = "INSERT into ${acct_table1} (AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPort, NASPortType, AcctSessionTime, AcctAuthentic, ConnectInfo_start, AcctInputOctets, AcctOutputOctets, CalledStationId, CallingStationId, ServiceType, FramedProtocol, FramedIPAddress, AcctStartDelay, XAscendSessionSvrKey) \
- VALUES('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', '%{Acct-Session-Time}', '%{Acct-Authentic}', '', '%{Acct-Input-Octets}', '%{Acct-Output-Octets}', '%{Called-Station-Id}', '%{Calling-Station-Id}', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', '0', '%{X-Ascend-Session-Svr-Key}')"
-
- # accounting_start_query: Inserting of RadAcctId and AcctStopTime was
- # removed. These fields are processing by a database
- accounting_start_query = "INSERT into ${acct_table1} (AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPort, NASPortType, AcctStartTime, AcctSessionTime, AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, AcctInputOctets, AcctOutputOctets, CalledStationId, CallingStationId, AcctTerminateCause, ServiceType, FramedProtocol, FramedIPAddress, AcctStartDelay, AcctStopDelay, XAscendSessionSvrKey) \
- VALUES('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', '%S', '0', '%{Acct-Authentic}', '%{Connect-Info}', '', '0', '0', '%{Called-Station-Id}', '%{Calling-Station-Id}', '', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', '%{Acct-Delay-Time}', '0', '%{X-Ascend-Session-Svr-Key}')"
-
- accounting_start_query_alt = "UPDATE ${acct_table1} SET AcctStartTime = '%S', AcctStartDelay = '%{Acct-Delay-Time:-0}', ConnectInfo_start = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' AND NASIPAddress = '%{NAS-IP-Address}' AND AcctStopTime = 0"
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
- accounting_stop_query = "UPDATE ${acct_table2} SET AcctStopTime = '%S', AcctSessionTime = '%{Acct-Session-Time}', AcctInputOctets = '%{Acct-Input-Octets}', AcctOutputOctets = '%{Acct-Output-Octets}', AcctTerminateCause = '%{Acct-Terminate-Cause}', AcctStopDelay = '%{Acct-Delay-Time:-0}', ConnectInfo_stop = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' AND NASIPAddress = '%{NAS-IP-Address}' AND AcctStopTime = 0"
+ type {
+ accounting-on {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime='%S', \
+ AcctSessionTime=unix_timestamp('%S') - \
+ unix_timestamp(AcctStartTime), \
+ AcctTerminateCause='%{Acct-Terminate-Cause}', \
+ AcctStopDelay = %{Acct-Delay-Time:-0} \
+ WHERE AcctStopTime = 0 \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStartTime <= '%S'"
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
- # accounting_stop_query_alt: Inserting of RadAcctId and AcctStartTime was
- # removed. These fields are processing by a database
- accounting_stop_query_alt = "INSERT into ${acct_table2} (AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPort, NASPortType, 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}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', '%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:-0}')"
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPort, \
+ NASPortType, AcctStartTime, AcctSessionTime, \
+ AcctAuthentic, ConnectInfo_start, ConnectInfo_stop, \
+ AcctInputOctets, AcctOutputOctets, CalledStationId, \
+ CallingStationId, AcctTerminateCause, ServiceType, \
+ FramedProtocol, FramedIPAddress, AcctStartDelay, \
+ AcctStopDelay, XAscendSessionSvrKey) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ '%S', \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Acct-Delay-Time}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}')"
+
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = '%S', \
+ AcctStartDelay = '%{Acct-Delay-Time:-0}', \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime = 0"
+ }
+ interim-update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ FramedIPAddress = '%{Framed-IP-Address}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress= '%{NAS-IP-Address}' \
+ AND AcctStopTime = 0"
+
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPort, \
+ NASPortType, AcctSessionTime, AcctAuthentic, \
+ ConnectInfo_start, AcctInputOctets, AcctOutputOctets, \
+ CalledStationId, CallingStationId, ServiceType, \
+ FramedProtocol, FramedIPAddress, AcctStartDelay, \
+ XAscendSessionSvrKey) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Acct-Input-Octets}', \
+ '%{Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}')"
+ }
+
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = '%S', \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}', \
+ AcctOutputOctets = '%{Acct-Output-Octets}', \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = '%{Acct-Delay-Time:-0}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime = 0"
+
+ query = "\
+ INSERT into ${....acct_table2} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPort, \
+ NASPortType, 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}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ '%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:-0}')"
+ }
+ }
+ }
+
+ post-auth {
+
+ }
WHERE groupname = '%{Sql-Group}' \
ORDER BY id"
- #######################################################################
- # Accounting Queries
- #######################################################################
- # accounting_onoff_query - query for Accounting On/Off packets
- # accounting_update_query - query for Accounting update packets
- # accounting_update_query_alt - query for Accounting update packets
- # (alternate in case first query fails)
- # 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 = FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- acctsessiontime = '%{integer:Event-Timestamp}' \
- - UNIX_TIMESTAMP(acctstarttime), \
- acctterminatecause = '%{Acct-Terminate-Cause}', \
- WHERE acctstoptime IS NULL \
- AND nasipaddress = '%{NAS-IP-Address}' \
- AND acctstarttime <= '%S'"
-
- accounting_update_query = "\
- UPDATE ${acct_table1} \
- SET \
- acctupdatetime = (@acctupdatetime_old:=acctupdatetime), \
- acctupdatetime = FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- acctinterval = \
- %{integer:Event-Timestamp} - UNIX_TIMESTAMP(@acctupdatetime_old), \
- framedipaddress = '%{Framed-IP-Address}', \
- acctsessiontime = '%{Acct-Session-Time}', \
- acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Input-Octets}:-0}', \
- acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Output-Octets}:-0}' \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
-
- accounting_update_query_alt = "\
- INSERT INTO ${acct_table1} \
- (acctsessionid, acctuniqueid, username, \
- realm, nasipaddress, nasportid, \
- nasporttype, acctstarttime, acctupdatetime, \
- acctsessiontime, acctauthentic, connectinfo_start, \
- acctinputoctets, acctoutputoctets, calledstationid, \
- callingstationid, servicetype, framedprotocol, \
- framedipaddress) \
- VALUES \
- ('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- FROM_UNIXTIME(%{integer:Event-Timestamp} - \
- %{%{Acct-Session-Time}:-0}), \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', '', \
- '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Input-Octets}:-0}', \
- '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Output-Octets}:-0}', \
- '%{Called-Station-Id}', '%{Calling-Station-Id}', \
- '%{Service-Type}', '%{Framed-Protocol}', \
- '%{Framed-IP-Address}')"
-
- accounting_start_query = "\
- INSERT INTO ${acct_table1} \
- (acctsessionid, acctuniqueid, username, \
- realm, nasipaddress, nasportid, \
- nasporttype, acctstarttime, acctupdatetime, \
- acctstoptime, acctsessiontime, acctauthentic, \
- connectinfo_start, connectinfo_stop, acctinputoctets, \
- acctoutputoctets, calledstationid, callingstationid, \
- acctterminatecause, servicetype, framedprotocol, \
- framedipaddress) \
- VALUES \
- ('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- NULL, '0', '%{Acct-Authentic}', \
- '%{Connect-Info}', '', '0', \
- '0', '%{Called-Station-Id}', '%{Calling-Station-Id}', \
- '', '%{Service-Type}', '%{Framed-Protocol}', \
- '%{Framed-IP-Address}')"
-
- accounting_start_query_alt = "\
- UPDATE ${acct_table1} SET \
- acctstarttime = FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- acctupdatetime = FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- connectinfo_start = '%{Connect-Info}' \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
-
- accounting_stop_query = "\
- UPDATE ${acct_table2} SET \
- acctstoptime = FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- acctsessiontime = '%{Acct-Session-Time}', \
- acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Input-Octets}:-0}', \
- acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Output-Octets}:-0}', \
- acctterminatecause = '%{Acct-Terminate-Cause}', \
- connectinfo_stop = '%{Connect-Info}' \
- WHERE acctsessionid = '%{Acct-Session-Id}' \
- AND username = '%{SQL-User-Name}' \
- AND nasipaddress = '%{NAS-IP-Address}'"
-
- accounting_stop_query_alt = "\
- INSERT INTO ${acct_table2} \
- (acctsessionid, acctuniqueid, username, \
- realm, nasipaddress, nasportid, \
- nasporttype, acctstarttime, acctupdatetime, \
- acctstoptime, acctsessiontime, acctauthentic, \
- connectinfo_start, connectinfo_stop, acctinputoctets, \
- acctoutputoctets, calledstationid, callingstationid, \
- acctterminatecause, servicetype, framedprotocol, \
- framedipaddress) \
- VALUES \
- ('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', \
- '%{NAS-Port-Type}', \
- FROM_UNIXTIME(%{integer:Event-Timestamp} - \
- %{%{Acct-Session-Time}:-0}), \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- FROM_UNIXTIME(%{integer:Event-Timestamp}), \
- '%{Acct-Session-Time}', '%{Acct-Authentic}', '', \
- '%{Connect-Info}', \
- '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Input-Octets}:-0}', \
- '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
- '%{%{Acct-Output-Octets}:-0}', \
- '%{Called-Station-Id}', '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}')"
-
#######################################################################
# Simultaneous Use Checking Queries
#######################################################################
# simul_count_query - query for the number of current connections
# - If this is not defined, no simultaneouls use checking
# - will be performed by this module instance
- # simul_verify_query - query to return details of current connections for verification
+ # simul_verify_query - query to return details of current connections
+ # for verification
# - Leave blank or commented out to disable verification step
# - Note that the returned field order should not be changed.
#######################################################################
WHERE username = '%{SQL-User-Name}' \
AND acctstoptime IS NULL"
+ #######################################################################
+ # Accounting and Post-Auth Queries
+ #######################################################################
+ # These queries insert/update accounting and authentication records.
+ # The query to use is determined by the value of 'reference'.
+ # This value is used as a configuration path and should resolve to one
+ # or more 'query's. If reference points to multiple queries, and a query
+ # fails, the next query is executed.
+ #
+ # Behaviour is identical to the old 1.x/2.x module, except we can now
+ # fail between N queries, and query selection can be based on any
+ # combination of attributes, or custom 'Acct-Status-Type' values.
+ #######################################################################
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+
+ column_list = "\
+ acctsessionid, acctuniqueid, username, \
+ realm, nasipaddress, nasportid, \
+ nasporttype, acctstarttime, acctupdatetime, \
+ acctstoptime, acctsessiontime, acctauthentic, \
+ connectinfo_start, connectinfo_stop, acctinputoctets, \
+ acctoutputoctets, calledstationid, callingstationid, \
+ acctterminatecause, servicetype, framedprotocol, \
+ framedipaddress"
+
+ type {
+ accounting-on {
+ #
+ # Bulk terminate all sessions associated with a given NAS
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctstoptime = FROM_UNIXTIME(\
+ %{integer:Event-Timestamp}), \
+ acctsessiontime = '%{integer:Event-Timestamp}' \
+ - UNIX_TIMESTAMP(acctstarttime), \
+ acctterminatecause = '%{Acct-Terminate-Cause}' \
+ WHERE acctstoptime IS NULL \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND acctstarttime <= FROM_UNIXTIME(\
+ %{integer:Event-Timestamp})"
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ start {
+ #
+ # Insert a new record into the sessions table
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
+
+ #
+ # Key constraints prevented us from inserting a new session,
+ # use the alternate query to update an existing session.
+ #
+ query = "\
+ UPDATE ${....acct_table1} SET \
+ acctstarttime = FROM_UNIXTIME(\
+ %{integer:Event-Timestamp}), \
+ acctupdatetime = FROM_UNIXTIME(\
+ %{integer:Event-Timestamp}), \
+ connectinfo_start = '%{Connect-Info}' \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
+ }
+
+ interim-update {
+ #
+ # Update an existing session and calculate the interval
+ # between the last data we received for the session and this
+ # update. This can be used to find stale sessions.
+ #
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ acctupdatetime = (\
+ @acctupdatetime_old:=acctupdatetime), \
+ acctupdatetime = FROM_UNIXTIME(\
+ %{integer:Event-Timestamp}), \
+ acctinterval = %{integer:Event-Timestamp} - \
+ UNIX_TIMESTAMP(@acctupdatetime_old), \
+ framedipaddress = '%{Framed-IP-Address}', \
+ acctsessiontime = '%{Acct-Session-Time}', \
+ acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}' \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(%{integer:Event-Timestamp} - \
+ %{%{Acct-Session-Time}:-0}), \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', '', \
+ '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
+ '%{%{Acct-Input-Octets}:-0}', \
+ '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
+ '%{%{Acct-Output-Octets}:-0}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
+ }
+
+ stop {
+ #
+ # Session has terminated, update the stop time and statistics.
+ #
+ query = "\
+ UPDATE ${....acct_table2} SET \
+ acctstoptime = FROM_UNIXTIME(\
+ %{integer:Event-Timestamp}), \
+ acctsessiontime = '%{Acct-Session-Time}', \
+ acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Input-Octets}:-0}', \
+ acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' \
+ << 32 | '%{%{Acct-Output-Octets}:-0}', \
+ acctterminatecause = '%{Acct-Terminate-Cause}', \
+ connectinfo_stop = '%{Connect-Info}' \
+ WHERE acctsessionid = '%{Acct-Session-Id}' \
+ AND username = '%{SQL-User-Name}' \
+ AND nasipaddress = '%{NAS-IP-Address}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${....acct_table2} \
+ (${...column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(%{integer:Event-Timestamp} - \
+ %{%{Acct-Session-Time}:-0}), \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ FROM_UNIXTIME(%{integer:Event-Timestamp}), \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', '', \
+ '%{Connect-Info}', \
+ '%{%{Acct-Input-Gigawords}:-0}' << 32 | \
+ '%{%{Acct-Input-Octets}:-0}', \
+ '%{%{Acct-Output-Gigawords}:-0}' << 32 | \
+ '%{%{Acct-Output-Octets}:-0}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}')"
+ }
+ }
+ }
+
#######################################################################
# Authentication Logging Queries
#######################################################################
# postauth_query - Insert some info after authentication
#######################################################################
- postauth_query = "\
- INSERT INTO ${postauth_table} \
- (username, pass, reply, authdate) \
- VALUES ( \
- '%{SQL-User-Name}', \
- '%{%{User-Password}:-%{Chap-Password}}', \
- '%{reply:Packet-Type}', '%S')"
-
+ post-auth {
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate) \
+ VALUES ( \
+ '%{SQL-User-Name}', \
+ '%{%{User-Password}:-%{Chap-Password}}', \
+ '%{reply:Packet-Type}', \
+ '%S')"
+ }
authorize_group_check_query = "SELECT ${groupcheck_table}.id,${groupcheck_table}.GroupName,${groupcheck_table}.Attribute,${groupcheck_table}.Value,${groupcheck_table}.op FROM ${groupcheck_table},${usergroup_table} WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName ORDER BY ${groupcheck_table}.id"
authorize_group_reply_query = "SELECT ${groupreply_table}.id,${groupreply_table}.GroupName,${groupreply_table}.Attribute,${groupreply_table}.Value,${groupreply_table}.op FROM ${groupreply_table},${usergroup_table} WHERE ${usergroup_table}.Username = '%{SQL-User-Name}' AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName ORDER BY ${groupreply_table}.id"
- #######################################################################
- # Accounting Queries
- #######################################################################
- # accounting_onoff_query - query for Accounting On/Off packets
- # accounting_update_query - query for Accounting update packets
- # accounting_update_query_alt - query for Accounting update packets
- # (alternate in case first query fails)
- # 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=TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), AcctSessionTime=round((TO_DATE('%S','yyyy-mm-dd hh24:mi:ss')-TO_DATE(TO_CHAR(acctstarttime, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss'))*86400), AcctTerminateCause='%{Acct-Terminate-Cause}', AcctStopDelay = %{Acct-Delay-Time:-0} WHERE AcctStopTime IS NULL AND NASIPAddress = '%{NAS-IP-Address}' AND AcctStartTime <= TO_DATE('%S','yyyy-mm-dd hh24:mi:ss')"
-
-accounting_update_query = "UPDATE ${acct_table1} \
- SET FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = '%{Acct-Input-Octets}' + ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
- AcctOutputOctets = '%{Acct-Output-Octets}' + ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296) \
- WHERE \
- AcctSessionId = '%{Acct-Session-Id}' AND \
- UserName = '%{SQL-User-Name}' AND \
- NASIPAddress= '%{NAS-IP-Address}' AND \
- AcctStopTime IS NULL"
-
-accounting_update_query_alt = "INSERT into ${acct_table1} (RadAcctId, AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPortId, NASPortType, AcctStartTime, AcctSessionTime, AcctAuthentic, ConnectInfo_start, AcctInputOctets, AcctOutputOctets, CalledStationId, CallingStationId, ServiceType, FramedProtocol, FramedIPAddress, AcctStartDelay, XAscendSessionSvrKey) \
- VALUES('', '%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', \
- '%{NAS-Port-Type}', NULL, '%{Acct-Session-Time}', '%{Acct-Authentic}', '', \
- '%{Acct-Input-Octets}' + ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
- '%{Acct-Output-Octets}' + ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
- '%{Called-Station-Id}', '%{Calling-Station-Id}', '%{Service-Type}', \
- '%{Framed-Protocol}', '%{Framed-IP-Address}', '0', '%{X-Ascend-Session-Svr-Key}')"
-
- accounting_start_query = "INSERT into ${acct_table1} (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, XAscendSessionSvrKey) \
- VALUES('', '%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), NULL, '0', '%{Acct-Authentic}', '%{Connect-Info}', '', '0', '0', '%{Called-Station-Id}', '%{Calling-Station-Id}', '', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', '%{Acct-Delay-Time}', '0', '%{X-Ascend-Session-Svr-Key}')"
-
- accounting_start_query_alt = "UPDATE ${acct_table1} SET AcctStartTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), AcctStartDelay = '%{Acct-Delay-Time:-0}', ConnectInfo_start = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' AND NASIPAddress = '%{NAS-IP-Address}' AND AcctStopTime IS NULL"
-
- accounting_stop_query = "UPDATE ${acct_table2} \
- SET AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = '%{Acct-Input-Octets}' + ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
- AcctOutputOctets = '%{Acct-Output-Octets}' + ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', AcctStopDelay = '%{Acct-Delay-Time:-0}', ConnectInfo_stop = '%{Connect-Info}' WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' AND NASIPAddress = '%{NAS-IP-Address}' AND AcctStopTime IS NULL"
-
- # Optional Query - pnixon
- #accounting_stop_query =3D "UPDATE ${acct_table2} SET AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), AcctSessionTime = (substr((sysdate-acctstarttime),instr((sysdate-acctstarttime),' ')+7,2) + substr((sysdate-acctstarttime),instr((sysdate-acctstarttime),' ')+4,2)*60 + substr((sysdate-acctstarttime),instr((sysdate-acctstarttime),' ')+1,2)*3600 + trunc(to_number(substr((sysdate-acctstarttime),1,instr(sysdate-acctstarttime,' '))))*86400), AcctInputOctets = '%{Acct-Input-Octets}', AcctOutputOctets = '%{Acct-Output-Octets}', AcctTerminateCause = '%{Acct-Terminate-Cause}', AcctStopDelay = '%{Acct-Delay-Time}', ConnectInfo_stop = '%{Connect-Info}' WHERE AcctSessionId =3D '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' AND NASIPAddress = '%{NAS-IP-Address}' AND AcctStopTime IS NULL"
-
-accounting_stop_query_alt = "INSERT into ${acct_table2} (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}', '%{SQL-User-Name}', '%{Realm}', \
- '%{NAS-IP-Address}', '%{NAS-Port-Id}', '%{NAS-Port-Type}', NULL, TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
- '%{Acct-Session-Time}', '%{Acct-Authentic}', '', '%{Connect-Info}', \
- '%{Acct-Input-Octets}' + ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
- '%{Acct-Output-Octets}' + ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
- '%{Called-Station-Id}', '%{Calling-Station-Id}', '%{Acct-Terminate-Cause}', '%{Service-Type}', \
- '%{Framed-Protocol}', '%{Framed-IP-Address}', '0', '%{Acct-Delay-Time:-0}')"
-
#######################################################################
# Simultaneous Use Checking Queries
#######################################################################
group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE UserName='%{SQL-User-Name}'"
- # Authentication Logging Queries
- #######################################################################
- # postauth_query - Insert some info after authentication
- #######################################################################
+ #######################################################################
+ # Accounting and Post-Auth Queries
+ #######################################################################
+ # These queries insert/update accounting and authentication records.
+ # The query to use is determined by the value of 'reference'.
+ # This value is used as a configuration path and should resolve to one
+ # or more 'query's. If reference points to multiple queries, and a query
+ # fails, the next query is executed.
+ #
+ # Behaviour is identical to the old 1.x/2.x module, except we can now
+ # fail between N queries, and query selection can be based on any
+ # combination of attributes, or custom 'Acct-Status-Type' values.
+ #######################################################################
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+
+ type {
+ accounting-on {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctSessionTime = round((TO_DATE('%S','yyyy-mm-dd hh24:mi:ss') - \
+ TO_DATE(TO_CHAR(acctstarttime, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss'))*86400), \
+ AcctTerminateCause='%{Acct-Terminate-Cause}', \
+ AcctStopDelay = %{Acct-Delay-Time:-0} \
+ WHERE AcctStopTime IS NULL \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStartTime <= TO_DATE('%S','yyyy-mm-dd hh24:mi:ss')"
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (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, \
+ XAscendSessionSvrKey) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Acct-Delay-Time}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}')"
+
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctStartDelay = '%{Acct-Delay-Time:-0}', \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
+ }
+
+ interim-update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ AcctOutputOctets = '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296) \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress= '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT into ${....acct_table1} \
+ (RadAcctId, AcctSessionId, AcctUniqueId, \
+ UserName, Realm, NASIPAddress, \
+ NASPortId, NASPortType, AcctStartTime, \
+ AcctSessionTime, AcctAuthentic, ConnectInfo_start, \
+ AcctInputOctets, AcctOutputOctets, CalledStationId, \
+ CallingStationId, ServiceType, FramedProtocol, \
+ FramedIPAddress, AcctStartDelay, XAscendSessionSvrKey) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ NULL, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{X-Ascend-Session-Svr-Key}')"
+ }
+
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ AcctOutputOctets = '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = '%{Acct-Delay-Time:-0}', \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ "INSERT into ${....acct_table2} \
+ (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}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{NAS-Port-Id}', \
+ '%{NAS-Port-Type}', \
+ NULL, \
+ TO_DATE('%S','yyyy-mm-dd hh24:mi:ss'), \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ '%{Acct-Input-Octets}' + \
+ ('%{%{Acct-Input-Gigawords}:-0}' * 4294967296), \
+ '%{Acct-Output-Octets}' + \
+ ('%{%{Acct-Output-Gigawords}:-0}' * 4294967296), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{Acct-Delay-Time:-0}')"
+
+ }
+ }
+ }
+
+ #######################################################################
+ # Authentication Logging Queries
+ #######################################################################
+ # postauth_query - Insert some info after authentication
+ #######################################################################
- postauth_query = "INSERT INTO ${postauth_table} \
- (username, pass, reply, authdate) \
- VALUES ( \
- '%{User-Name}', \
- '%{%{User-Password}:-%{Chap-Password}}', \
- '%{reply:Packet-Type}', TO_TIMESTAMP('%S','YYYY-MM-DDHH24:MI:SS'))"
+ post-auth {
+ query = "\
+ INSERT INTO ${..postauth_table} \
+ (username, pass, reply, authdate) \
+ VALUES (\
+ '%{User-Name}', \
+ '%{%{User-Password}:-%{Chap-Password}}', \
+ '%{reply:Packet-Type}', \
+ TO_TIMESTAMP('%S','YYYY-MM-DDHH24:MI:SS'))"
+ }
\ No newline at end of file
-# -*- text -*-
-##
-## dialup.conf -- PostgreSQL configuration for default schema (schema.sql)
-##
-## $Id$
-
-# Safe characters list for sql queries. Everything else is replaced
-# with their mime-encoded equivalents.
-# The default list should be ok
-# safe-characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
-
-#######################################################################
-# Query config: Username
-#######################################################################
-# This is the username that will get substituted, escaped, and added
-# as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
-# below everywhere a username substitution is needed so you you can
-# be sure the username passed from the client is escaped properly.
-#
-# Uncomment the next line, if you want the sql_user_name to mean:
-#
-# Use Stripped-User-Name, if it's there.
-# Else use User-Name, if it's there,
-# Else use hard-coded string "none" as the user name.
-#
-#sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
-
-sql_user_name = "%{User-Name}"
-
-#######################################################################
-# Default profile
-#######################################################################
-# This is the default profile. It is found in SQL by group membership.
-# That means that this profile must be a member of at least one group
-# which will contain the corresponding check and reply items.
-# This profile will be queried in the authorize section for every user.
-# The point is to assign all users a default profile without having to
-# manually add each one to a group that will contain the profile.
-# The SQL module will also honor the User-Profile attribute. This
-# attribute can be set anywhere in the authorize section (ie the users
-# file). It is found exactly as the default profile is found.
-# If it is set then it will *overwrite* the default profile setting.
-# The idea is to select profiles based on checks on the incoming
-# packets, not on user group membership. For example:
-# -- users file --
-# DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
-# DEFAULT Service-Type == Framed-User, User-Profile := "framed"
-#
-# By default the default_user_profile is not set
-#
-# default_user_profile = "DEFAULT"
-
-#######################################################################
-# NAS Query
-#######################################################################
-# This query retrieves the radius clients
-#
-# 0. Row ID (currently unused)
-# 1. Name (or IP address)
-# 2. Shortname
-# 3. Type
-# 4. Secret
-# 5. Server
-#######################################################################
-
-nas_query = "SELECT id, nasname, shortname, type, secret, server FROM ${nas_table}"
-
-#######################################################################
-# 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. Row ID (currently unused)
-# 1. UserName/GroupName
-# 2. Item Attr Name
-# 3. Item Attr Value
-# 4. Item Attr Operation
-#######################################################################
-
-# Use these for case insensitive usernames. WARNING: Slower queries!
-# authorize_check_query = "SELECT id, UserName, Attribute, Value, Op \
-# FROM ${authcheck_table} \
-# WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
-# ORDER BY id"
-# authorize_reply_query = "SELECT id, UserName, Attribute, Value, Op \
-# FROM ${authreply_table} \
-# WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
-# ORDER BY id"
-
-authorize_check_query = "SELECT id, UserName, Attribute, Value, Op \
- FROM ${authcheck_table} \
- WHERE Username = '%{SQL-User-Name}' \
- ORDER BY id"
-
-authorize_reply_query = "SELECT id, UserName, Attribute, Value, Op \
- FROM ${authreply_table} \
- WHERE Username = '%{SQL-User-Name}' \
- ORDER BY id"
-
-# Use these for case insensitive usernames. WARNING: Slower queries!
-# authorize_group_check_query = "SELECT ${groupcheck_table}.id, ${groupcheck_table}.GroupName, \
-# ${groupcheck_table}.Attribute, ${groupcheck_table}.Value, ${groupcheck_table}.Op \
-# FROM ${groupcheck_table}, ${usergroup_table} \
-# WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
-# ORDER BY ${groupcheck_table}.id"
-# authorize_group_reply_query = "SELECT ${groupreply_table}.id, ${groupreply_table}.GroupName, \
-# ${groupreply_table}.Attribute, ${groupreply_table}.Value, ${groupreply_table}.Op \
-# FROM ${groupreply_table}, ${usergroup_table} \
-# WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
-# ORDER BY ${groupreply_table}.id"
-
-authorize_group_check_query = "SELECT id, GroupName, Attribute, Value, op \
- FROM ${groupcheck_table} \
- WHERE GroupName = '%{Sql-Group}' \
- ORDER BY id"
-
-authorize_group_reply_query = "SELECT id, GroupName, Attribute, Value, op \
- FROM ${groupreply_table} \
- WHERE GroupName = '%{Sql-Group}' \
- ORDER BY id"
-
-#######################################################################
-# Simultaneous Use Checking Queries
-#######################################################################
-# simul_count_query - query for the number of current connections
-# - If this is not defined, no simultaneous use checking
-# - will be performed by this module instance
-# simul_verify_query - query to return details of current connections for verification
-# - Leave blank or commented out to disable verification step
-# - Note that the returned field order should not be changed.
-#######################################################################
-
-# Uncomment simul_count_query to enable simultaneous use checking
-# simul_count_query = "SELECT COUNT(*) FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
-# simul_verify_query = "SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, FramedProtocol FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
-
-
-
-#######################################################################
-# Accounting Queries
-#######################################################################
-# accounting_onoff_query - query for Accounting On/Off packets
-# accounting_update_query - query for Accounting update packets
-# accounting_update_query_alt - query for Accounting update packets
-# (alternate in case first query fails)
-# 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'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- AcctSessionTime = (EXTRACT(EPOCH FROM ('%S'::timestamp with time zone - AcctStartTime::timestamp with time zone \
- - '%{%{Acct-Delay-Time}:-0}'::interval)))::BIGINT, \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- AcctStopDelay = 0 \
- WHERE AcctStopTime IS NULL \
- AND NASIPAddress= '%{NAS-IP-Address}' \
- AND AcctStartTime <= '%S'::timestamp"
-
-accounting_update_query = "UPDATE ${acct_table1} \
- SET FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + '%{%{Acct-Input-Octets}:-0}'::bigint), \
- AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + '%{%{Acct-Output-Octets}:-0}'::bigint) \
- WHERE AcctSessionId = '%{Acct-Session-Id}' AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress= '%{NAS-IP-Address}' AND AcctStopTime IS NULL"
-
-accounting_update_query_alt = "INSERT INTO ${acct_table1} \
- (AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, \
- NASPortId, NASPortType, AcctStartTime, \
- AcctSessionTime, AcctAuthentic, AcctInputOctets, \
- AcctOutputOctets, CalledStationId, CallingStationId, \
- ServiceType, FramedProtocol, FramedIPAddress, XAscendSessionSvrKey) \
- VALUES('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', NULLIF('%{Realm}', ''), '%{NAS-IP-Address}', \
- %{%{NAS-Port}:-NULL}, '%{NAS-Port-Type}', \
- ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval - '%{%{Acct-Session-Time}:-0}'::interval), \
- '%{Acct-Session-Time}', '%{Acct-Authentic}', \
- (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + '%{%{Acct-Input-Octets}:-0}'::bigint), \
- (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + '%{%{Acct-Output-Octets}:-0}'::bigint), \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', '%{Service-Type}', '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, '%{X-Ascend-Session-Svr-Key}')"
-
-accounting_start_query = "INSERT INTO ${acct_table1} \
- (AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, \
- NASPortId, NASPortType, AcctStartTime, AcctAuthentic, \
- ConnectInfo_start, CalledStationId, CallingStationId, ServiceType, \
- FramedProtocol, FramedIPAddress, AcctStartDelay, XAscendSessionSvrKey) \
- VALUES('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- NULLIF('%{Realm}', ''), \
- '%{NAS-IP-Address}', \
- %{%{NAS-Port}:-NULL}, \
- '%{NAS-Port-Type}', \
- ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, \
- 0, \
- '%{X-Ascend-Session-Svr-Key}')"
-
-accounting_start_query_alt = "UPDATE ${acct_table1} \
- SET AcctStartTime = ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- AcctStartDelay = 0, \
- ConnectInfo_start = '%{Connect-Info}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStopTime IS NULL"
-
-accounting_stop_query = "UPDATE ${acct_table2} \
- SET AcctStopTime = ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- AcctSessionTime = CASE WHEN '%{Acct-Session-Time}' = '' THEN \
- (EXTRACT(EPOCH FROM ('%S'::TIMESTAMP WITH TIME ZONE - AcctStartTime::TIMESTAMP WITH TIME ZONE \
- - '%{%{Acct-Delay-Time}:-0}'::INTERVAL)))::BIGINT \
- ELSE NULLIF('%{Acct-Session-Time}','')::BIGINT END, \
- AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + '%{%{Acct-Input-Octets}:-0}'::bigint), \
- AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + '%{%{Acct-Output-Octets}:-0}'::bigint), \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- AcctStopDelay = 0, \
- FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
- ConnectInfo_stop = '%{Connect-Info}' \
- WHERE AcctSessionId = '%{Acct-Session-Id}' \
- AND UserName = '%{SQL-User-Name}' \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStopTime IS NULL"
-
-accounting_stop_query_alt = "INSERT INTO ${acct_table2} \
- (AcctSessionId, AcctUniqueId, UserName, Realm, NASIPAddress, NASPortId, NASPortType, AcctStartTime, AcctStopTime, \
- AcctSessionTime, AcctAuthentic, ConnectInfo_stop, AcctInputOctets, AcctOutputOctets, CalledStationId, \
- CallingStationId, AcctTerminateCause, ServiceType, FramedProtocol, FramedIPAddress, AcctStopDelay) \
- values('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- NULLIF('%{Realm}', ''), \
- '%{NAS-IP-Address}', \
- %{%{NAS-Port}:-NULL}, \
- '%{NAS-Port-Type}', \
- ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval - '%{%{Acct-Session-Time}:-0}'::interval), \
- ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
- NULLIF('%{Acct-Session-Time}', '')::bigint, '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + '%{%{Acct-Input-Octets}:-0}'::bigint), \
- (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + '%{%{Acct-Output-Octets}:-0}'::bigint), \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, 0)"
-
-#######################################################################
-# Group Membership Queries
-#######################################################################
-# group_membership_query - Check user group membership
-#######################################################################
-
-# Use these for case insensitive usernames. WARNING: Slower queries!
-# group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') ORDER BY priority"
-
-group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE UserName='%{SQL-User-Name}' ORDER BY priority"
-
-#######################################################################
-# Authentication Logging Queries
-#######################################################################
-# postauth_query - Insert some info after authentication
-#######################################################################
-postauth_query = "INSERT INTO ${postauth_table} (username, pass, reply, authdate) \
- VALUES ('%{User-Name}', '%{%{User-Password}:-Chap-Password}', '%{reply:Packet-Type}', NOW())"
-
+ # -*- text -*-
+ ##
+ ## dialup.conf -- PostgreSQL configuration for default schema (schema.sql)
+ ##
+ ## $Id$
+
+ # Safe characters list for sql queries. Everything else is replaced
+ # with their mime-encoded equivalents.
+ # The default list should be ok
+ # safe-characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"
+
+ #######################################################################
+ # Query config: Username
+ #######################################################################
+ # This is the username that will get substituted, escaped, and added
+ # as attribute 'SQL-User-Name'. '%{SQL-User-Name}' should be used
+ # below everywhere a username substitution is needed so you you can
+ # be sure the username passed from the client is escaped properly.
+ #
+ # Uncomment the next line, if you want the sql_user_name to mean:
+ #
+ # Use Stripped-User-Name, if it's there.
+ # Else use User-Name, if it's there,
+ # Else use hard-coded string "none" as the user name.
+ #
+ #sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-none}}"
+
+ sql_user_name = "%{User-Name}"
+
+ #######################################################################
+ # Default profile
+ #######################################################################
+ # This is the default profile. It is found in SQL by group membership.
+ # That means that this profile must be a member of at least one group
+ # which will contain the corresponding check and reply items.
+ # This profile will be queried in the authorize section for every user.
+ # The point is to assign all users a default profile without having to
+ # manually add each one to a group that will contain the profile.
+ # The SQL module will also honor the User-Profile attribute. This
+ # attribute can be set anywhere in the authorize section (ie the users
+ # file). It is found exactly as the default profile is found.
+ # If it is set then it will *overwrite* the default profile setting.
+ # The idea is to select profiles based on checks on the incoming
+ # packets, not on user group membership. For example:
+ # -- users file --
+ # DEFAULT Service-Type == Outbound-User, User-Profile := "outbound"
+ # DEFAULT Service-Type == Framed-User, User-Profile := "framed"
+ #
+ # By default the default_user_profile is not set
+ #
+ # default_user_profile = "DEFAULT"
+
+ #######################################################################
+ # NAS Query
+ #######################################################################
+ # This query retrieves the radius clients
+ #
+ # 0. Row ID (currently unused)
+ # 1. Name (or IP address)
+ # 2. Shortname
+ # 3. Type
+ # 4. Secret
+ # 5. Server
+ #######################################################################
+
+ nas_query = "SELECT id, nasname, shortname, type, secret, server FROM ${nas_table}"
+
+ #######################################################################
+ # 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. Row ID (currently unused)
+ # 1. UserName/GroupName
+ # 2. Item Attr Name
+ # 3. Item Attr Value
+ # 4. Item Attr Operation
+ #######################################################################
+
+ # Use these for case insensitive usernames. WARNING: Slower queries!
+ # authorize_check_query = "SELECT id, UserName, Attribute, Value, Op \
+ # FROM ${authcheck_table} \
+ # WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
+ # ORDER BY id"
+ # authorize_reply_query = "SELECT id, UserName, Attribute, Value, Op \
+ # FROM ${authreply_table} \
+ # WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') \
+ # ORDER BY id"
+
+ authorize_check_query = "SELECT id, UserName, Attribute, Value, Op \
+ FROM ${authcheck_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+ authorize_reply_query = "SELECT id, UserName, Attribute, Value, Op \
+ FROM ${authreply_table} \
+ WHERE Username = '%{SQL-User-Name}' \
+ ORDER BY id"
+
+ # Use these for case insensitive usernames. WARNING: Slower queries!
+ # authorize_group_check_query = "SELECT ${groupcheck_table}.id, ${groupcheck_table}.GroupName, \
+ # ${groupcheck_table}.Attribute, ${groupcheck_table}.Value, ${groupcheck_table}.Op \
+ # FROM ${groupcheck_table}, ${usergroup_table} \
+ # WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') AND ${usergroup_table}.GroupName = ${groupcheck_table}.GroupName \
+ # ORDER BY ${groupcheck_table}.id"
+ # authorize_group_reply_query = "SELECT ${groupreply_table}.id, ${groupreply_table}.GroupName, \
+ # ${groupreply_table}.Attribute, ${groupreply_table}.Value, ${groupreply_table}.Op \
+ # FROM ${groupreply_table}, ${usergroup_table} \
+ # WHERE LOWER(${usergroup_table}.UserName) = LOWER('%{SQL-User-Name}') AND ${usergroup_table}.GroupName = ${groupreply_table}.GroupName \
+ # ORDER BY ${groupreply_table}.id"
+
+ authorize_group_check_query = "SELECT id, GroupName, Attribute, Value, op \
+ FROM ${groupcheck_table} \
+ WHERE GroupName = '%{Sql-Group}' \
+ ORDER BY id"
+
+ authorize_group_reply_query = "SELECT id, GroupName, Attribute, Value, op \
+ FROM ${groupreply_table} \
+ WHERE GroupName = '%{Sql-Group}' \
+ ORDER BY id"
+
+ #######################################################################
+ # Simultaneous Use Checking Queries
+ #######################################################################
+ # simul_count_query - query for the number of current connections
+ # - If this is not defined, no simultaneous use checking
+ # - will be performed by this module instance
+ # simul_verify_query - query to return details of current connections for verification
+ # - Leave blank or commented out to disable verification step
+ # - Note that the returned field order should not be changed.
+ #######################################################################
+
+ # Uncomment simul_count_query to enable simultaneous use checking
+ # simul_count_query = "SELECT COUNT(*) FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
+ # simul_verify_query = "SELECT RadAcctId, AcctSessionId, UserName, NASIPAddress, NASPortId, FramedIPAddress, CallingStationId, FramedProtocol FROM ${acct_table1} WHERE UserName='%{SQL-User-Name}' AND AcctStopTime IS NULL"
+
+ #######################################################################
+ # Group Membership Queries
+ #######################################################################
+ # group_membership_query - Check user group membership
+ #######################################################################
+
+ # Use these for case insensitive usernames. WARNING: Slower queries!
+ # group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE LOWER(UserName) = LOWER('%{SQL-User-Name}') ORDER BY priority"
+
+ group_membership_query = "SELECT GroupName FROM ${usergroup_table} WHERE UserName='%{SQL-User-Name}' ORDER BY priority"
+
+ #######################################################################
+ # Accounting and Post-Auth Queries
+ #######################################################################
+ # These queries insert/update accounting and authentication records.
+ # The query to use is determined by the value of 'reference'.
+ # This value is used as a configuration path and should resolve to one
+ # or more 'query's. If reference points to multiple queries, and a query
+ # fails, the next query is executed.
+ #
+ # Behaviour is identical to the old 1.x/2.x module, except we can now
+ # fail between N queries, and query selection can be based on any
+ # combination of attributes, or custom 'Acct-Status-Type' values.
+ #######################################################################
+ accounting {
+ reference = "%{tolower:type.%{Acct-Status-Type}.query}"
+
+ type {
+ accounting-on {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStopTime = ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
+ AcctSessionTime = (EXTRACT(EPOCH FROM ('%S'::timestamp with time zone - AcctStartTime::timestamp with time zone \
+ - '%{%{Acct-Delay-Time}:-0}'::interval)))::BIGINT, \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = 0 \
+ WHERE AcctStopTime IS NULL \
+ AND NASIPAddress= '%{NAS-IP-Address}' \
+ AND AcctStartTime <= '%S'::timestamp"
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
+
+ start {
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPortId, \
+ NASPortType, AcctStartTime, AcctAuthentic, \
+ ConnectInfo_start, CalledStationId, CallingStationId, \
+ ServiceType, FramedProtocol, FramedIPAddress, \
+ AcctStartDelay, XAscendSessionSvrKey) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{NAS-IP-Address}', \
+ %{%{NAS-Port}:-NULL}, \
+ '%{NAS-Port-Type}', \
+ ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, \
+ 0, \
+ '%{X-Ascend-Session-Svr-Key}')"
+
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ AcctStartTime = ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
+ AcctStartDelay = 0, \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
+ }
+
+ update {
+ query = "\
+ UPDATE ${....acct_table1} \
+ SET \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint) \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress= '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT INTO ${....acct_table1} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPortId, \
+ NASPortType, AcctStartTime, AcctSessionTime, \
+ AcctAuthentic, AcctInputOctets, AcctOutputOctets, \
+ CalledStationId, CallingStationId, ServiceType, \
+ FramedProtocol, FramedIPAddress, XAscendSessionSvrKey) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{NAS-IP-Address}', \
+ %{%{NAS-Port}:-NULL}, \
+ '%{NAS-Port-Type}', \
+ ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval - \
+ '%{%{Acct-Session-Time}:-0}'::interval), \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, \
+ '%{X-Ascend-Session-Svr-Key}')"
+ }
+
+ stop {
+ query = "\
+ UPDATE ${....acct_table2} \
+ SET \
+ AcctStopTime = ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
+ AcctSessionTime = CASE WHEN '%{Acct-Session-Time}' = ''\
+ THEN \
+ (EXTRACT(EPOCH FROM ('%S'::TIMESTAMP WITH TIME ZONE - \
+ AcctStartTime::TIMESTAMP WITH TIME ZONE - \
+ '%{%{Acct-Delay-Time}:-0}'::INTERVAL)))::BIGINT \
+ ELSE \
+ NULLIF('%{Acct-Session-Time}','')::BIGINT END, \
+ AcctInputOctets = (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ AcctOutputOctets = (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = 0, \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ ConnectInfo_stop = '%{Connect-Info}' \
+ WHERE AcctSessionId = '%{Acct-Session-Id}' \
+ AND UserName = '%{SQL-User-Name}' \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT INTO ${....acct_table2} \
+ (AcctSessionId, AcctUniqueId, UserName, \
+ Realm, NASIPAddress, NASPortId, \
+ NASPortType, AcctStartTime, AcctStopTime, \
+ AcctSessionTime, AcctAuthentic, ConnectInfo_stop, \
+ AcctInputOctets, AcctOutputOctets, CalledStationId, \
+ CallingStationId, AcctTerminateCause, ServiceType, \
+ FramedProtocol, FramedIPAddress, AcctStopDelay) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{NAS-IP-Address}', \
+ %{%{NAS-Port}:-NULL}, \
+ '%{NAS-Port-Type}', \
+ ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval - \
+ '%{%{Acct-Session-Time}:-0}'::interval), \
+ ('%S'::timestamp - '%{%{Acct-Delay-Time}:-0}'::interval), \
+ NULLIF('%{Acct-Session-Time}', '')::bigint, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ (('%{%{Acct-Input-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Input-Octets}:-0}'::bigint), \
+ (('%{%{Acct-Output-Gigawords}:-0}'::bigint << 32) + \
+ '%{%{Acct-Output-Octets}:-0}'::bigint), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, 0)"
+ }
+ }
+ }
+
+
+ #######################################################################
+ # Authentication Logging Queries
+ #######################################################################
+ # postauth_query - Insert some info after authentication
+ #######################################################################
+
+ post-auth {
+ query = "\
+ INSERT INTO ${postauth_table} \
+ (username, pass, reply, authdate) \
+ VALUES(\
+ '%{User-Name}', \
+ '%{%{User-Password}:-Chap-Password}', \
+ '%{reply:Packet-Type}', \
+ NOW())"
+ }
#include <freeradius-devel/ident.h>
RCSIDH(conf_h, "$Id$")
-typedef struct sql_config {
- char *sql_driver;
- char *sql_server;
- char *sql_port;
- char *sql_login;
- char *sql_password;
- char *sql_db;
- char *sql_file; /* for sqlite */
- char *query_user;
- char *default_profile;
- char *nas_query;
- char *authorize_check_query;
- char *authorize_reply_query;
- char *authorize_group_check_query;
- char *authorize_group_reply_query;
- char *accounting_onoff_query;
- char *accounting_update_query;
- char *accounting_update_query_alt;
- char *accounting_start_query;
- char *accounting_start_query_alt;
- char *accounting_stop_query;
- char *accounting_stop_query_alt;
- char *simul_count_query;
- char *simul_verify_query;
- char *groupmemb_query;
- int sqltrace;
- int do_clients;
- int read_groups;
- char *tracefile;
- char *xlat_name;
- int deletestalesessions;
- char *postauth_query;
- char *allowed_chars;
- int query_timeout;
-
- /* individual driver config */
- void *localcfg;
-
-} SQL_CONFIG;
-
-
#define CHECKRAD1 "/usr/sbin/checkrad"
#define CHECKRAD2 "/usr/local/sbin/checkrad"
#define ASCEND_PORT_HACK
#define ASCEND_CHANNELS_PER_LINE 23
-#define CISCO_ACCOUNTING_HACK
/* SQL defines */
#define MAX_QUERY_LEN 4096
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
+ * Copyright 2012 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
* Copyright 2000,2006 The FreeRADIUS server project
* Copyright 2000 Mike Machado <mike@innercite.com>
* Copyright 2000 Alan DeKok <aland@ox.org>
#include <freeradius-devel/ident.h>
RCSID("$Id$")
+#include <ctype.h>
+
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
+#include <freeradius-devel/token.h>
#include <freeradius-devel/rad_assert.h>
#include <sys/stat.h>
static char *allowed_chars = NULL;
+static const CONF_PARSER section_config[] = {
+ { "reference", PW_TYPE_STRING_PTR,
+ offsetof(rlm_sql_config_section_t, reference), NULL, ".query"},
+
+ {"sqltrace", PW_TYPE_BOOLEAN,
+ offsetof(rlm_sql_config_section_t, sqltrace), NULL, "no"},
+ {"sqltracefile", PW_TYPE_STRING_PTR,
+ offsetof(rlm_sql_config_section_t, tracefile), NULL, NULL},
+ {NULL, -1, 0, NULL, NULL}
+};
+
static const CONF_PARSER module_config[] = {
{"driver",PW_TYPE_STRING_PTR,
offsetof(SQL_CONFIG,sql_driver), NULL, "mysql"},
offsetof(SQL_CONFIG,sql_file), NULL, NULL},
{"read_groups", PW_TYPE_BOOLEAN,
offsetof(SQL_CONFIG,read_groups), NULL, "yes"},
- {"sqltrace", PW_TYPE_BOOLEAN,
- offsetof(SQL_CONFIG,sqltrace), NULL, "no"},
- {"sqltracefile", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,tracefile), NULL, SQLTRACEFILE},
{"readclients", PW_TYPE_BOOLEAN,
offsetof(SQL_CONFIG,do_clients), NULL, "no"},
{"deletestalesessions", PW_TYPE_BOOLEAN,
offsetof(SQL_CONFIG,authorize_group_check_query), NULL, ""},
{"authorize_group_reply_query", PW_TYPE_STRING_PTR,
offsetof(SQL_CONFIG,authorize_group_reply_query), NULL, ""},
-#ifdef WITH_ACCOUNTING
- {"accounting_onoff_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_onoff_query), NULL, ""},
- {"accounting_update_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_update_query), NULL, ""},
- {"accounting_update_query_alt", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_update_query_alt), NULL, ""},
- {"accounting_start_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_start_query), NULL, ""},
- {"accounting_start_query_alt", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_start_query_alt), NULL, ""},
- {"accounting_stop_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_stop_query), NULL, ""},
- {"accounting_stop_query_alt", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,accounting_stop_query_alt), NULL, ""},
-#endif
{"group_membership_query", PW_TYPE_STRING_PTR,
offsetof(SQL_CONFIG,groupmemb_query), NULL, NULL},
#ifdef WITH_SESSION_MGMT
{"simul_verify_query", PW_TYPE_STRING_PTR,
offsetof(SQL_CONFIG,simul_verify_query), NULL, ""},
#endif
- {"postauth_query", PW_TYPE_STRING_PTR,
- offsetof(SQL_CONFIG,postauth_query), NULL, ""},
{"safe-characters", PW_TYPE_STRING_PTR,
offsetof(SQL_CONFIG,allowed_chars), NULL,
"@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},
static size_t sql_escape_func(char *out, size_t outlen, const char *in);
/*
- * sql xlat function. Right now only SELECTs are supported. Only
- * the first element of the SELECT result will be used.
+ * SQL xlat function
*
- * For other statements (insert, update, delete, etc.), the
- * number of affected rows will be returned.
+ * For selects the first value of the first column will be returned,
+ * for inserts, updates and deletes the number of rows afftected will be
+ * returned instead.
*/
static int sql_xlat(void *instance, REQUEST *request,
char *fmt, char *out, size_t freespace,
return 0;
}
- query_log(request, inst,querystr);
+ query_log(inst, request, NULL, querystr);
sqlsocket = sql_get_socket(inst);
if (sqlsocket == NULL)
return 0;
}
if (row[0] == NULL){
- RDEBUG("row[0] returned NULL");
+ RDEBUG("Null value in first column");
(inst->module->sql_finish_select_query)(sqlsocket, inst->config);
sql_release_socket(inst,sqlsocket);
return 0;
return 0;
}
+
+static int parse_sub_section(CONF_SECTION *parent,
+ UNUSED SQL_INST *instance,
+ rlm_sql_config_section_t *config,
+ rlm_components_t comp)
+{
+ CONF_SECTION *cs;
+
+ const char *name = section_type_value[comp].section;
+
+ cs = cf_section_sub_find(parent, name);
+ if (!cs) {
+ /* TODO: Should really setup section with default values */
+ goto error;
+ }
+
+ if (cf_section_parse(cs, config, section_config) < 0)
+ goto error;
+
+ config->cs = cs;
+
+ return 1;
+
+ error:
+ radlog(L_ERR, "Failed parsing configuration for section %s",
+ name);
+
+ return -1;
+
+}
+
static int rlm_sql_instantiate(CONF_SECTION * conf, void **instance)
{
SQL_INST *inst;
inst = rad_malloc(sizeof(SQL_INST));
memset(inst, 0, sizeof(SQL_INST));
+ /*
+ * Export these methods, too. This avoids RTDL_GLOBAL.
+ */
+ inst->sql_set_user = sql_set_user;
+ inst->sql_get_socket = sql_get_socket;
+ inst->sql_release_socket = sql_release_socket;
+ inst->sql_escape_func = sql_escape_func;
+ inst->sql_query = rlm_sql_query;
+ inst->sql_select_query = rlm_sql_select_query;
+ inst->sql_fetch_row = rlm_sql_fetch_row;
+
inst->config = rad_malloc(sizeof(SQL_CONFIG));
memset(inst->config, 0, sizeof(SQL_CONFIG));
inst->cs = conf;
-
+
/*
- * Export these methods, too. This avoids RTDL_GLOBAL.
+ * If the configuration parameters can't be parsed, then fail.
*/
- inst->sql_set_user = sql_set_user;
- inst->sql_get_socket = sql_get_socket;
- inst->sql_release_socket = sql_release_socket;
- inst->sql_escape_func = sql_escape_func;
- inst->sql_query = rlm_sql_query;
- inst->sql_select_query = rlm_sql_select_query;
- inst->sql_fetch_row = rlm_sql_fetch_row;
-
+ if (
+ (cf_section_parse(conf, inst->config, module_config) < 0) ||
+ (parse_sub_section(conf, inst,
+ &inst->config->accounting,
+ RLM_COMPONENT_ACCT) < 0) ||
+ (parse_sub_section(conf, inst,
+ &inst->config->postauth,
+ RLM_COMPONENT_POST_AUTH) < 0)
+ ) {
+ radlog(L_ERR, "Failed parsing configuration");
+
+ goto error;
+ }
/*
- * If the configuration parameters can't be parsed, then
- * fail.
+ * Sanity check for crazy people.
*/
- if (cf_section_parse(conf, inst->config, module_config) < 0) {
- rlm_sql_detach(inst);
- return -1;
+ if (strncmp(inst->config->sql_driver, "rlm_sql_", 8) != 0) {
+ radlog(L_ERR, "\"%s\" is NOT an SQL driver!",
+ inst->config->sql_driver);
+ goto error;
}
xlat_name = cf_section_name2(conf);
ATTR_FLAGS flags;
/*
- * Allocate room for <instance>-SQL-Group
+ * Allocate room for <instance>-SQL-Group
*/
group_name = rad_malloc((strlen(xlat_name) + 1 + 11) * sizeof(char));
- sprintf(group_name,"%s-SQL-Group",xlat_name);
+ sprintf(group_name,"%s-SQL-Group", xlat_name);
DEBUG("rlm_sql Creating new attribute %s",group_name);
memset(&flags, 0, sizeof(flags));
dict_addattr(group_name, 0, PW_TYPE_STRING, -1, flags);
dattr = dict_attrbyname(group_name);
if (dattr == NULL){
- radlog(L_ERR, "rlm_sql: Failed to create attribute %s",group_name);
+ radlog(L_ERR, "rlm_sql: Failed to create attribute %s",
+ group_name);
+
free(group_name);
- free(inst); /* FIXME: detach */
- return -1;
+
+ goto error;
}
if (inst->config->groupmemb_query &&
inst->config->groupmemb_query[0]) {
- DEBUG("rlm_sql: Registering sql_groupcmp for %s",group_name);
- paircompare_register(dattr->attr, PW_USER_NAME, sql_groupcmp, inst);
+ DEBUG("rlm_sql: Registering sql_groupcmp for %s",
+ group_name);
+ paircompare_register(dattr->attr, PW_USER_NAME,
+ sql_groupcmp, inst);
}
free(group_name);
}
- if (xlat_name){
- inst->config->xlat_name = strdup(xlat_name);
- xlat_register(xlat_name, (RAD_XLAT_FUNC)sql_xlat, inst);
- }
+
+ rad_assert(xlat_name);
/*
- * Sanity check for crazy people.
+ * Register the SQL xlat function
+ */
+ inst->config->xlat_name = strdup(xlat_name);
+ xlat_register(xlat_name, (RAD_XLAT_FUNC)sql_xlat, inst);
+
+ /*
+ * Load the appropriate driver for our database
*/
- if (strncmp(inst->config->sql_driver, "rlm_sql_", 8) != 0) {
- radlog(L_ERR, "\"%s\" is NOT an SQL driver!",
- inst->config->sql_driver);
- rlm_sql_detach(inst);
- return -1;
- }
-
inst->handle = lt_dlopenext(inst->config->sql_driver);
if (inst->handle == NULL) {
radlog(L_ERR, "Could not link driver %s: %s",
inst->config->sql_driver,
lt_dlerror());
- radlog(L_ERR, "Make sure it (and all its dependent libraries!) are in the search path of your system's ld.");
- rlm_sql_detach(inst);
- return -1;
+ radlog(L_ERR, "Make sure it (and all its dependent libraries!)"
+ "are in the search path of your system's ld.");
+
+ goto error;
}
- inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle, inst->config->sql_driver);
+ inst->module = (rlm_sql_module_t *) lt_dlsym(inst->handle,
+ inst->config->sql_driver);
if (!inst->module) {
radlog(L_ERR, "Could not link symbol %s: %s",
inst->config->sql_driver,
lt_dlerror());
- rlm_sql_detach(inst);
- return -1;
+
+ goto error;
}
radlog(L_INFO, "rlm_sql (%s): Driver %s (module %s) loaded and linked",
inst->config->xlat_name, inst->config->sql_driver,
inst->module->name);
+
+ /*
+ * Initialise the connection pool for this instance
+ */
radlog(L_INFO, "rlm_sql (%s): Attempting to connect to %s@%s:%s/%s",
inst->config->xlat_name, inst->config->sql_login,
inst->config->sql_server, inst->config->sql_port,
inst->config->sql_db);
-
- if (sql_init_socketpool(inst) < 0) {
- rlm_sql_detach(inst);
- return -1;
- }
+
+ if (sql_init_socketpool(inst) < 0)
+ goto error;
if (inst->config->groupmemb_query &&
inst->config->groupmemb_query[0]) {
paircompare_register(PW_SQL_GROUP, PW_USER_NAME, sql_groupcmp, inst);
}
- if (inst->config->do_clients){
+ if (inst->config->do_clients) {
if (generate_sql_clients(inst) == -1){
radlog(L_ERR, "Failed to load clients from SQL.");
- rlm_sql_detach(inst);
- return -1;
+
+ goto error;
}
}
allowed_chars = inst->config->allowed_chars;
*instance = inst;
return RLM_MODULE_OK;
+
+ error:
+ rlm_sql_detach(inst);
+
+ return -1;
}
/*
- * reserve a socket
+ * Reserve a socket
*/
sqlsocket = sql_get_socket(inst);
if (sqlsocket == NULL) {
pairdelete(&request->packet->vps, PW_SQL_USER_NAME, 0);
pairfree(&check_tmp);
pairfree(&reply_tmp);
+
return RLM_MODULE_FAIL;
}
}
}
-#ifdef WITH_ACCOUNTING
/*
- * Accounting: save the account data to our sql table
+ * Generic function for failing between a bunch of queries.
+ *
+ * Uses the same principle as rlm_linelog, expanding the 'reference' config
+ * item using xlat to figure out what query it should execute.
+ *
+ * If the reference matches multiple config items, and a query fails or
+ * doesn't update any rows, the next matching config item is used.
+ *
*/
-static int rlm_sql_accounting(void *instance, REQUEST * request) {
-
- SQLSOCK *sqlsocket = NULL;
- VALUE_PAIR *pair;
- SQL_INST *inst = instance;
- int sql_ret;
+static int rlm_sql_redundant(SQL_INST *inst, REQUEST *request,
+ rlm_sql_config_section_t *section)
+{
int ret = RLM_MODULE_OK;
- int numaffected = 0;
- int acctstatustype = 0;
- char querystr[MAX_QUERY_LEN];
- char logstr[MAX_QUERY_LEN];
- char sqlusername[MAX_STRING_LEN];
-#ifdef CISCO_ACCOUNTING_HACK
- int acctsessiontime = 0;
-#endif
+ SQLSOCK *sqlsocket = NULL;
+ int sql_ret;
+ int numaffected = 0;
- memset(querystr, 0, MAX_QUERY_LEN);
+ CONF_ITEM *item;
+ CONF_PAIR *pair;
+ CONF_SECTION *base;
+ const char *attr = NULL;
+ const char *value;
- /*
- * Find the Acct Status Type
- */
- pair = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0);
- if (pair == NULL) {
- radius_xlat(logstr, sizeof(logstr), "Packet has no accounting status type. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
- radlog_request(L_ERR, 0, request, "%s", logstr);
-
- return RLM_MODULE_INVALID;
- }
+ char path[MAX_STRING_LEN];
+ char querystr[MAX_QUERY_LEN];
+ char sqlusername[MAX_STRING_LEN];
- acctstatustype = pair->vp_integer;
-
- /*
- * Bulk update queries
- */
- if (acctstatustype == PW_STATUS_ACCOUNTING_ON ||
- acctstatustype == PW_STATUS_ACCOUNTING_OFF) {
- /*
- * The NAS informed us that it was rebooted, close all sessions
- * associated with it.
- */
- radius_xlat(logstr, sizeof(logstr), "Bulk closing sessions using 'accounting_onoff_query' - [nas '%{NAS-IP-Address}']", request, NULL);
- radlog_request(L_DBG, 0, request, "%s", logstr);
-
- radius_xlat(querystr, sizeof(querystr),
- inst->config->accounting_onoff_query, request,
- sql_escape_func);
- if (!*querystr)
- goto null_query;
+ char *p = path;
- query_log(request, inst, querystr);
+ memset(querystr, 0, sizeof(querystr));
+
+ sql_set_user(inst, request, sqlusername, NULL);
+
+ if (section->reference[0] != '.')
+ *p++ = '.';
+
+ if (radius_xlat(p, (sizeof(path) - (p - path)) - 1,
+ section->reference, request, NULL) < 0)
+ return RLM_MODULE_FAIL;
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
- return RLM_MODULE_FAIL;
+ item = cf_reference_item(NULL, section->cs, path);
+ if (!item)
+ return RLM_MODULE_FAIL;
- sql_ret = rlm_sql_query(&sqlsocket, inst, querystr);
- if (sql_ret)
- return RLM_MODULE_FAIL;
-
- numaffected = (inst->module->sql_affected_rows)(sqlsocket,
- inst->config);
- radlog_request(L_DBG, 0, request, "Closed %i sessions", numaffected);
- if (numaffected < 1)
- ret = RLM_MODULE_NOOP;
+ if (cf_item_is_section(item)){
+ radlog(L_ERR, "Sections are not supported as references");
- goto cleanup;
+ return RLM_MODULE_FAIL;
}
- /*
- * Session specific queries
- */
- sql_set_user(inst, request, sqlusername, NULL);
+ pair = cf_itemtopair(item);
+ attr = cf_pair_attr(pair);
+
+ RDEBUG2("Failing between pairs with name '%s'", attr);
- /*
- * Setup the primary query for a given packet type
- */
- switch (acctstatustype) {
- case PW_STATUS_ALIVE:
- radlog_request(L_DBG, 0, request, "Updating session using 'accounting_update_query'");
-
- radius_xlat(querystr, sizeof(querystr),
- inst->config->accounting_update_query, request,
- sql_escape_func);
- if (!*querystr)
- goto null_query;
-
- break;
-
- case PW_STATUS_START:
- radlog_request(L_DBG, 0, request, "Creating session using 'accounting_start_query'");
-
- radius_xlat(querystr, sizeof(querystr),
- inst->config->accounting_start_query, request,
- sql_escape_func);
- if (!*querystr)
- goto null_query;
-
- break;
-
- case PW_STATUS_STOP:
- radlog_request(L_DBG, 0, request, "Closing session using 'accounting_stop_query'");
-
- radius_xlat(querystr, sizeof(querystr),
- inst->config->accounting_stop_query, request,
- sql_escape_func);
- if (!*querystr)
- goto null_query;
-
- break;
-
- default:
- RDEBUG("Unsupported Acct-Status-Type value (%d)", acctstatustype);
-
- return RLM_MODULE_NOOP;
- }
-
- /*
- * Log the query. Maybe we should do this only if were not using the
- * alternate?
- */
- query_log(request, inst, querystr);
-
sqlsocket = sql_get_socket(inst);
if (sqlsocket == NULL)
return RLM_MODULE_FAIL;
- sql_ret = rlm_sql_query(&sqlsocket, inst, querystr);
- if (sql_ret == SQL_DOWN)
- return RLM_MODULE_FAIL;
-
- rad_assert(sqlsocket);
-
- /*
- * Assume all other errors are incidental, and just meant our operation
- * failed and its not a client or SQL syntax error.
- */
- if (sql_ret == 0) {
- numaffected = (inst->module->sql_affected_rows)(sqlsocket,
- inst->config);
- if (numaffected > 0)
- goto cleanup;
- }
-
- /*
- * The primary query failed this may be because:
- * update - The session hasn't be created with a start record -
- * so create the session.
- * start - The session was created from a stop or interim update
- * packet so the insert failed (presumably on unique index
- * constraint) - so update the session.
- * stop - The session does not already exist. We never received
- * a Start or Interim-Update packet for this session -
- * so create the session.
- */
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
-
- /*
- * Setup the alternate query for a given packet type
- */
- switch (acctstatustype) {
- case PW_STATUS_ALIVE:
- radlog_request(L_DBG, 0, request, "Failed updating session, creating session using 'accounting_update_query_alt'");
-
- radius_xlat(querystr, sizeof(querystr),
- inst->config->accounting_update_query_alt,
- request, sql_escape_func);
- if (!*querystr)
- goto null_query;
-
- break;
+ while (TRUE) {
+ value = cf_pair_value(pair);
+ if (!value)
+ goto null_query;
- case PW_STATUS_START:
- radlog_request(L_DBG, 0, request, "Failed creating session, updating session using 'accounting_start_query_alt'");
+ radius_xlat(querystr, sizeof(querystr), value, request,
+ sql_escape_func);
+ if (!*querystr)
+ goto null_query;
- radius_xlat(querystr, sizeof(querystr),
- inst->config->accounting_start_query_alt,
- request, sql_escape_func);
- if (!*querystr)
- goto null_query;
-
- break;
+ query_log(inst, request, section, querystr);
- case PW_STATUS_STOP:
-#ifdef CISCO_ACCOUNTING_HACK
- /*
- * If stop but zero session length AND no previous session found,
- * drop it as in invalid packet This is to fix CISCO's aaa from
- * filling our table with bogus crap
- */
- pair = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME, 0);
- if (pair != NULL)
- acctsessiontime = pair->vp_integer;
-
- if (acctsessiontime <= 0) {
- radius_xlat(logstr, sizeof(logstr), "Stop packet with zero session length. [user '%{User-Name}', nas '%{NAS-IP-Address}']", request, NULL);
- radlog_request(L_DBG, 0, request, "%s", logstr);
-
- goto release;
- }
-#endif
-
- radlog_request(L_DBG, 0, request, "Failed closing session, creating closed session using 'accounting_stop_query_alt'");
+ sql_ret = rlm_sql_query(&sqlsocket, inst, querystr);
+ if (sql_ret == SQL_DOWN)
+ return RLM_MODULE_FAIL;
- radius_xlat(querystr, sizeof(querystr),
- inst->config->accounting_stop_query_alt,
- request, sql_escape_func);
- if (!*querystr)
- goto null_query;
+ rad_assert(sqlsocket);
+
+ /*
+ * Assume all other errors are incidental, and just meant our
+ * operation failed and its not a client or SQL syntax error.
+ */
+ if (sql_ret == 0) {
+ numaffected = (inst->module->sql_affected_rows)
+ (sqlsocket, inst->config);
+ if (numaffected > 0)
+ break;
+
+ RDEBUG("No records updated");
+ }
- break;
- default:
- rad_assert(0);
- }
+ (inst->module->sql_finish_query)(sqlsocket, inst->config);
- query_log(request, inst, querystr);
-
- if (rlm_sql_query(&sqlsocket, inst, querystr) == SQL_DOWN)
- return RLM_MODULE_FAIL;
+ /*
+ * We assume all entries with the same name form a redundant
+ * set of queries.
+ */
+ pair = cf_pair_find_next(base, pair, attr);
- rad_assert(sqlsocket);
+ if (!pair) {
+ RDEBUG("No additional queries configured");
+
+ ret = RLM_MODULE_NOOP;
+
+ goto release;
+ }
- /*
- * This time we *know* this was some sort of error...
- */
- if (sql_ret) {
- ret = RLM_MODULE_FAIL;
- goto cleanup;
+ RDEBUG("Trying next query...");
}
- numaffected = (inst->module->sql_affected_rows)(sqlsocket, inst->config);
- if (numaffected < 1)
- ret = RLM_MODULE_NOOP;
-
- cleanup:
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
+ (inst->module->sql_finish_query)(sqlsocket, inst->config);
release:
- sql_release_socket(inst, sqlsocket);
+
+ sql_release_socket(inst, sqlsocket);
return ret;
null_query:
+
radlog_request(L_DBG, 0, request, "Ignoring null query");
+
+ sql_release_socket(inst, sqlsocket);
+
return RLM_MODULE_NOOP;
}
-#endif
+#ifdef WITH_ACCOUNTING
+
+/*
+ * Accounting: Insert or update session data in our sql table
+ */
+static int rlm_sql_accounting(void *instance, REQUEST * request) {
+ SQL_INST *inst = instance;
+
+ return rlm_sql_redundant(inst, request, &inst->config->accounting);
+}
+
+#endif
#ifdef WITH_SESSION_MGMT
/*
#endif
/*
- * Execute postauth_query after authentication
+ * Postauth: Write a record of the authentication attempt
*/
-static int rlm_sql_postauth(void *instance, REQUEST *request) {
- SQLSOCK *sqlsocket = NULL;
- SQL_INST *inst = instance;
- char querystr[MAX_QUERY_LEN];
- char sqlusername[MAX_STRING_LEN];
-
- if(sql_set_user(inst, request, sqlusername, NULL) < 0)
- return RLM_MODULE_FAIL;
-
- /* If postauth_query is not defined, we stop here */
- if (!inst->config->postauth_query ||
- (inst->config->postauth_query[0] == '\0'))
- return RLM_MODULE_NOOP;
-
- /* Expand variables in the query */
- memset(querystr, 0, MAX_QUERY_LEN);
- radius_xlat(querystr, sizeof(querystr), inst->config->postauth_query,
- request, sql_escape_func);
- query_log(request, inst, querystr);
- DEBUG2("rlm_sql (%s) in sql_postauth: query is %s",
- inst->config->xlat_name, querystr);
-
- /* Initialize the sql socket */
- sqlsocket = sql_get_socket(inst);
- if (sqlsocket == NULL)
- return RLM_MODULE_FAIL;
+static int rlm_sql_postauth(void *instance, REQUEST * request) {
+ SQL_INST *inst = instance;
+
+ return rlm_sql_redundant(inst, request, &inst->config->postauth);
+}
- /* Process the query */
- if (rlm_sql_query(&sqlsocket, inst, querystr)) {
- sql_release_socket(inst, sqlsocket);
-
- return RLM_MODULE_FAIL;
- }
- (inst->module->sql_finish_query)(sqlsocket, inst->config);
+/*
+ * Execute postauth_query after authentication
+ */
- sql_release_socket(inst, sqlsocket);
- return RLM_MODULE_OK;
-}
/* globally exported name */
module_t rlm_sql = {
#include "conf.h"
-#define SQLSOCK_LOCKED 0
-#define SQLSOCK_UNLOCKED 1
-
-#define PW_ITEM_CHECK 0
-#define PW_ITEM_REPLY 1
+#define PW_ITEM_CHECK 0
+#define PW_ITEM_REPLY 1
typedef char** SQL_ROW;
+/*
+ * Sections where we dynamically resolve the config entry to use,
+ * by xlating reference.
+ */
+typedef struct rlm_sql_config_section {
+ CONF_SECTION *cs;
+
+ char *reference;
+
+ int sqltrace;
+ char *tracefile;
+} rlm_sql_config_section_t;
+
+typedef struct sql_config {
+ char *sql_driver;
+ char *sql_server;
+ char *sql_port;
+ char *sql_login;
+ char *sql_password;
+ char *sql_db;
+ char *sql_file; /* for sqlite */
+ char *query_user;
+ char *default_profile;
+ char *nas_query;
+ char *authorize_check_query;
+ char *authorize_reply_query;
+ char *authorize_group_check_query;
+ char *authorize_group_reply_query;
+ char *simul_count_query;
+ char *simul_verify_query;
+ char *groupmemb_query;
+ int sqltrace;
+ int do_clients;
+ int read_groups;
+ char *tracefile;
+ char *xlat_name;
+ int deletestalesessions;
+ char *allowed_chars;
+ int query_timeout;
+ void *localcfg; /* individual driver config */
+
+ /*
+ * TODO: The rest of the queries should also be moved into their own
+ * sections.
+ */
+
+ /* Section configurations */
+ rlm_sql_config_section_t postauth;
+ rlm_sql_config_section_t accounting;
+} SQL_CONFIG;
+
typedef struct sql_socket {
void *conn;
SQL_ROW row;
int sql_read_naslist(SQLSOCK * sqlsocket);
int sql_read_clients(SQLSOCK * sqlsocket);
int sql_dict_init(SQLSOCK * sqlsocket);
-void query_log(REQUEST *request, SQL_INST * inst, char *querystr);
+void query_log(SQL_INST *inst, REQUEST *request,
+ rlm_sql_config_section_t *section, char *querystr);
int rlm_sql_select_query(SQLSOCK **sqlsocket, SQL_INST *inst, char *query);
int rlm_sql_query(SQLSOCK **sqlsocket, SQL_INST *inst, char *query);
int rlm_sql_fetch_row(SQLSOCK **sqlsocket, SQL_INST *inst);
if (ret < 0) {
radlog(L_ERR,
- "rlm_sql (%s): Database query error '%s' in query '%s'",
+ "rlm_sql (%s): Database query error '%s'",
inst->config->xlat_name,
- (inst->module->sql_error)(*sqlsocket, inst->config),
- query);
+ (inst->module->sql_error)(*sqlsocket, inst->config));
}
return ret;
if (ret < 0) {
radlog(L_ERR,
- "rlm_sql (%s): Database query error '%s' in query '%s'",
+ "rlm_sql (%s): Database query error '%s'",
inst->config->xlat_name,
- (inst->module->sql_error)(*sqlsocket, inst->config),
- query);
+ (inst->module->sql_error)(*sqlsocket, inst->config));
}
return ret;
return rows;
}
-void query_log(REQUEST *request, SQL_INST *inst, char *querystr)
+void query_log(SQL_INST *inst, REQUEST *request,
+ rlm_sql_config_section_t *section, char *querystr)
{
- FILE *sqlfile = NULL;
-
- if (inst->config->sqltrace) {
- char buffer[8192];
+ FILE *sqlfile = NULL;
+
+ if (!inst->config->sqltrace && (!section || !section->sqltrace))
+ return;
+
+ char buffer[8192];
+
+ if (!radius_xlat(buffer, sizeof(buffer),
+ section && section->tracefile ? section->tracefile :
+ inst->config->tracefile,
+ request, NULL)) {
+ radlog(L_ERR, "rlm_sql (%s): xlat failed.",
+ inst->config->xlat_name);
+ return;
+ }
- if (!radius_xlat(buffer, sizeof(buffer),
- inst->config->tracefile, request, NULL)) {
- radlog(L_ERR, "rlm_sql (%s): xlat failed.",
- inst->config->xlat_name);
- return;
- }
+ if ((sqlfile = fopen(buffer, "a")) == (FILE *) NULL) {
+ radlog(L_ERR, "rlm_sql (%s): Couldn't open file %s",
+ inst->config->xlat_name,
+ buffer);
+ } else {
+ int fd = fileno(sqlfile);
- if ((sqlfile = fopen(buffer, "a")) == (FILE *) NULL) {
- radlog(L_ERR, "rlm_sql (%s): Couldn't open file %s",
- inst->config->xlat_name,
- buffer);
- } else {
- int fd = fileno(sqlfile);
-
- rad_lockfd(fd, MAX_QUERY_LEN);
- fputs(querystr, sqlfile);
- fputs(";\n", sqlfile);
- fclose(sqlfile); /* and release the lock */
- }
+ rad_lockfd(fd, MAX_QUERY_LEN);
+ fputs(querystr, sqlfile);
+ fputs(";\n", sqlfile);
+ fclose(sqlfile); /* and release the lock */
}
}