Added support for customizable called-station-id, nas-identifier. Added session-timeout support. RADIUS plugin returns the error message reported by the server to pGina.

This commit is contained in:
Evan
2013-10-28 14:54:16 -04:00
parent 40ede576ba
commit acebfc7dad
9 changed files with 809 additions and 386 deletions

View File

@@ -30,6 +30,7 @@ namespace pGina.Plugin.RADIUS
public byte[] NAS_IP_Address { get; set; }
public string NAS_Identifier { get; set; }
public string called_station_id { get; set; }
//identifier refers to the identifier number, unique for each new packet
private byte _id;
@@ -46,17 +47,17 @@ namespace pGina.Plugin.RADIUS
public RADIUSClient(string[] servers, int authport, int acctingport, string sharedKey, string NAS_Id) :
this(servers, authport, acctingport, sharedKey, timeout: 3000, retry: 3, sessionId:null, NAS_IP_Address:null, NAS_Identifier: NAS_Id)
this(servers, authport, acctingport, sharedKey, timeout: 3000, retry: 3, sessionId:null, NAS_IP_Address:null, NAS_Identifier: NAS_Id, called_station_id:null)
{
}
public RADIUSClient(string[] servers, int authport, int acctingport, string sharedKey, string sessionId, string NAS_Id) :
this(servers, authport, acctingport, sharedKey, timeout: 3000, retry: 3, sessionId: sessionId, NAS_IP_Address: null, NAS_Identifier: NAS_Id)
this(servers, authport, acctingport, sharedKey, timeout: 3000, retry: 3, sessionId: sessionId, NAS_IP_Address: null, NAS_Identifier: NAS_Id, called_station_id:null)
{
}
public RADIUSClient(string[] servers, int authport, int acctingport, string sharedKey,
int timeout, int retry, string sessionId, byte[] NAS_IP_Address, string NAS_Identifier)
int timeout, int retry, string sessionId, byte[] NAS_IP_Address, string NAS_Identifier, string called_station_id)
{
this.servers = servers;
this.authenticationPort = authport;
@@ -70,6 +71,7 @@ namespace pGina.Plugin.RADIUS
this.NAS_IP_Address = NAS_IP_Address;
this.NAS_Identifier = NAS_Identifier;
this.called_station_id = called_station_id;
}
//Connects to the RADIUS server and attempts to authenticate the specified user info
@@ -85,12 +87,14 @@ namespace pGina.Plugin.RADIUS
if(!String.IsNullOrEmpty(sessionId))
authPacket.addAttribute(Packet.AttributeType.Acct_Session_Id, sessionId);
if (NAS_Identifier == null && NAS_IP_Address == null)
if (String.IsNullOrEmpty(NAS_Identifier) && NAS_IP_Address == null)
throw new RADIUSException("A NAS_Identifier or NAS_IP_Address (or both) must be supplied.");
if(NAS_IP_Address != null)
authPacket.addRawAttribute(Packet.AttributeType.NAS_IP_Address, NAS_IP_Address);
if (NAS_Identifier != null)
if (!String.IsNullOrEmpty(NAS_Identifier))
authPacket.addAttribute(Packet.AttributeType.NAS_Identifier, NAS_Identifier);
if (!String.IsNullOrEmpty(called_station_id))
authPacket.addAttribute(Packet.AttributeType.Called_Station_Id, called_station_id);
m_logger.DebugFormat("Attempting to send {0} for user {1}", authPacket.code, username);
@@ -147,24 +151,25 @@ namespace pGina.Plugin.RADIUS
}
//Sends a start accounting request to the RADIUS server, returns true on acknowledge of request
public bool startAccounting(string username, Packet.Acct_AuthenticType authType)
{
public bool startAccounting(string username, Packet.Acct_Authentic authType)
{
//Create accounting request packet
Packet accountingRequest = new Packet(Packet.Code.Accounting_Request, identifier, sharedKey);
accountingRequest.addAttribute(Packet.AttributeType.User_Name, username);
accountingRequest.addAttribute(Packet.AttributeType.Acct_Status_Type, (int)Packet.Acct_Status_TypeType.Start);
if (String.IsNullOrEmpty(sessionId))
throw new RADIUSException("Session ID must be present for accounting.");
accountingRequest.addAttribute(Packet.AttributeType.Acct_Status_Type, (int)Packet.Acct_Status_Type.Start);
if (String.IsNullOrEmpty(sessionId)) //Create new guid
sessionId = Guid.NewGuid().ToString();
accountingRequest.addAttribute(Packet.AttributeType.Acct_Session_Id, sessionId);
if (NAS_Identifier == null && NAS_IP_Address == null)
if (String.IsNullOrEmpty(NAS_Identifier) && NAS_IP_Address == null)
throw new RADIUSException("A NAS_Identifier or NAS_IP_Address (or both) must be supplied.");
if (NAS_IP_Address != null)
accountingRequest.addRawAttribute(Packet.AttributeType.NAS_IP_Address, NAS_IP_Address);
if (NAS_Identifier != null)
if (!String.IsNullOrEmpty(NAS_Identifier))
accountingRequest.addAttribute(Packet.AttributeType.NAS_Identifier, NAS_Identifier);
if (authType != Packet.Acct_AuthenticType.Not_Specified)
if (authType != Packet.Acct_Authentic.Not_Specified)
accountingRequest.addAttribute(Packet.AttributeType.Acct_Authentic, (int)authType);
m_logger.DebugFormat("Attempting to send {0} for user {1}", accountingRequest.code, username);
@@ -214,18 +219,73 @@ namespace pGina.Plugin.RADIUS
throw new RADIUSException(String.Format("No response from server(s) after {0} tries.", maxRetries + 1));
}
public bool stopAccounting(string username, Packet.Acct_Terminate_CauseType? terminateCause)
public bool interimUpdate(string username)
{
Packet p = new Packet(Packet.Code.Accounting_Request, this.identifier, this.sharedKey);
p.addAttribute(Packet.AttributeType.User_Name, username);
if (String.IsNullOrEmpty(sessionId))
throw new RADIUSException("Session ID must be present for accounting.");
p.addAttribute(Packet.AttributeType.Acct_Session_Id, sessionId);
p.addAttribute(Packet.AttributeType.Acct_Status_Type, (int)Packet.Acct_Status_Type.Interim_Update);
m_logger.DebugFormat("Attempting to send interim-update for user {1}", username);
for (int retryCt = 0; retryCt <= maxRetries; retryCt++)
{
foreach (string server in servers)
{
//Accounting request packet created, sending data...
UdpClient client = new UdpClient(server, accountingPort);
client.Client.SendTimeout = timeout;
client.Client.ReceiveTimeout = timeout;
try
{
client.Send(p.toBytes(), p.length);
//Listen for response, since the server has been specified, we don't need to re-specify server
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] respBytes = client.Receive(ref RemoteIpEndPoint);
Packet responsePacket = new Packet(respBytes);
//Verify packet response is good, authenticator should be MD5(Code+ID+Length+RequestAuth+Attributes+Secret)
if (!responsePacket.verifyResponseAuthenticator(p.authenticator, sharedKey))
throw new RADIUSException(String.Format("Received response to interim-update with code: {0}, but an incorrect response authenticator was supplied.", responsePacket.code));
lastReceievedPacket = responsePacket;
client.Close();
m_logger.DebugFormat("Received interim-update response: {0} for user {1}", responsePacket.code, username);
return responsePacket.code == Packet.Code.Accounting_Response;
//SocketException is thrown if the server does not respond by end of timeout
}
catch (SocketException se)
{
m_logger.DebugFormat("Accounting interim-update attempt {0}/{1} using {2} failed. Reason: {3}", retryCt + 1, maxRetries + 1, server, se.Message);
}
catch (Exception e)
{
throw new RADIUSException("Unexpected error while sending interim-update.", e);
}
}
}
throw new RADIUSException(String.Format("No response from server(s) after {0} tries.", maxRetries + 1));
}
public bool stopAccounting(string username, Packet.Acct_Terminate_Cause? terminateCause)
{
Packet accountingRequest = new Packet(Packet.Code.Accounting_Request, identifier, sharedKey);
accountingRequest.addAttribute(Packet.AttributeType.User_Name, username);
if(String.IsNullOrEmpty(sessionId))
throw new RADIUSException("Session ID must be present for accounting.");
accountingRequest.addAttribute(Packet.AttributeType.Acct_Session_Id, sessionId);
accountingRequest.addAttribute(Packet.AttributeType.Acct_Status_Type, (int)Packet.Acct_Status_TypeType.Stop);
accountingRequest.addAttribute(Packet.AttributeType.Acct_Status_Type, (int)Packet.Acct_Status_Type.Stop);
if(terminateCause != null)
accountingRequest.addAttribute(Packet.AttributeType.Acct_Terminate_Cause, (int) Packet.Acct_Terminate_CauseType.User_Request);
accountingRequest.addAttribute(Packet.AttributeType.Acct_Terminate_Cause, (int) Packet.Acct_Terminate_Cause.User_Request);
m_logger.DebugFormat("Attempting to send {0} for user {1}", accountingRequest.code, username);
m_logger.DebugFormat("Attempting to send session-stop for user {0}", username);
for (int retryCt = 0; retryCt <= maxRetries; retryCt++)
{

File diff suppressed because it is too large Load Diff

View File

@@ -19,20 +19,21 @@ namespace pGina.Plugin.RADIUS
{
InitializeComponent();
secretTB.UseSystemPasswordChar = true;
sendNasIdentifierCB.CheckedChanged += cbDisableTBInput;
sendCalledStationCB.CheckedChanged += cbDisableTBInput;
sendNasIdentifierCB.CheckedChanged += checkboxModifyInputs;
sendCalledStationCB.CheckedChanged += checkboxModifyInputs;
enableAuthCB.CheckedChanged += checkboxModifyInputs;
enableAcctCB.CheckedChanged += checkboxModifyInputs;
sendInterimUpdatesCB.CheckedChanged += checkboxModifyInputs;
load();
}
private bool save()
{
int authport = 0;
int acctport = 0;
int timeout = 0;
int retry = 0;
int interim_time = 0;
try
{
@@ -40,8 +41,10 @@ namespace pGina.Plugin.RADIUS
acctport = Convert.ToInt32(acctPortTB.Text.Trim());
timeout = (int)(1000 * Convert.ToDouble(timeoutTB.Text.Trim()));
retry = Convert.ToInt32(retryTB.Text.Trim());
if (authport <= 0 || acctport <= 0 || timeout <= 0 || retry <= 0)
throw new FormatException("Ports, Retry and Timeout values must be values greater than 0");
interim_time = Convert.ToInt32(forceInterimUpdTB.Text.Trim());
if (authport <= 0 || acctport <= 0 || timeout <= 0 || retry <= 0 || interim_time <= 0)
throw new FormatException("Ports, Retry, Timeout and interval values must be values greater than 0");
}
catch (FormatException)
{
@@ -49,24 +52,30 @@ namespace pGina.Plugin.RADIUS
return false;
}
if (!sendNasIpAddrCB.Checked && !sendNasIdentifierCB.Checked)
if (enableAuthCB.Checked) //Settings only relevent to users with auth checked
{
MessageBox.Show("Send NAS IP Address or Send NAS Identifier must be checked under Authentication Options");
return false;
}
if (sendNasIdentifierCB.Checked && String.IsNullOrEmpty(sendNasIdentifierTB.Text.Trim()))
{
MessageBox.Show("NAS Identifier can not be blank if the option is enabled.");
return false;
}
if (sendCalledStationCB.Checked && String.IsNullOrEmpty(sendCalledStationTB.Text.Trim()))
{
MessageBox.Show("Called-Station-ID can not be blank if the option is enabled.");
return false;
if (!sendNasIpAddrCB.Checked && !sendNasIdentifierCB.Checked)
{
MessageBox.Show("Send NAS IP Address or Send NAS Identifier must be checked under Authentication Options");
return false;
}
if (sendNasIdentifierCB.Checked && String.IsNullOrEmpty(sendNasIdentifierTB.Text.Trim()))
{
MessageBox.Show("NAS Identifier can not be blank if the option is enabled.");
return false;
}
if (sendCalledStationCB.Checked && String.IsNullOrEmpty(sendCalledStationTB.Text.Trim()))
{
MessageBox.Show("Called-Station-ID can not be blank if the option is enabled.");
return false;
}
}
Settings.Store.EnableAuth = enableAuthCB.Checked;
Settings.Store.EnableAcct = enableAcctCB.Checked;
Settings.Store.Server = serverTB.Text.Trim();
Settings.Store.AuthPort = authport;
@@ -82,6 +91,9 @@ namespace pGina.Plugin.RADIUS
Settings.Store.CalledStationID = sendCalledStationTB.Text.Trim();
Settings.Store.SendInterimUpdates = sendInterimUpdatesCB.Checked;
Settings.Store.ForceInterimUpdates = forceInterimUpdCB.Checked;
Settings.Store.InterimUpdateTime = interim_time;
Settings.Store.AllowSessionTimeout = sessionTimeoutCB.Checked;
Settings.Store.WisprSessionTerminate = wisprTimeoutCB.Checked;
@@ -94,32 +106,49 @@ namespace pGina.Plugin.RADIUS
private void load()
{
enableAuthCB.Checked = (bool)Settings.Store.EnableAuth;
enableAcctCB.Checked = (bool)Settings.Store.EnableAcct;
serverTB.Text = Settings.Store.Server;
authPortTB.Text = String.Format("{0}", (int)Settings.Store.AuthPort);
acctPortTB.Text = String.Format("{0}", (int)Settings.Store.AcctPort);
authPortTB.Text = String.Format("{0}", stoi(Settings.Store.AuthPort, 1812));
acctPortTB.Text = String.Format("{0}", stoi(Settings.Store.AcctPort, 1813));
secretTB.Text = Settings.Store.GetEncryptedSetting("SharedSecret") ;
timeoutTB.Text = String.Format("{0:0.00}", (int)Settings.Store.Timeout / 1000.0);
timeoutTB.Text = String.Format("{0:0.00}", stoi(Settings.Store.Timeout, 2500) / 1000.0); //2500ms
retryTB.Text = String.Format("{0}", (int)Settings.Store.Retry);
sendNasIdentifierCB.Checked = Settings.Store.SendNASIPAddress;
sendNasIdentifierCB.Checked = Settings.Store.SendNASIdentifier;
sendNasIpAddrCB.Checked = (bool)Settings.Store.SendNASIPAddress;
sendNasIdentifierCB.Checked = (bool)Settings.Store.SendNASIdentifier;
sendNasIdentifierTB.Text = Settings.Store.NASIdentifier;
sendCalledStationCB.Checked = Settings.Store.SendCalledStationID;
sendCalledStationCB.Checked = (bool)Settings.Store.SendCalledStationID;
sendCalledStationTB.Text = Settings.Store.CalledStationID;
sendInterimUpdatesCB.Checked = Settings.Store.SendInterimUpdates;
sendInterimUpdatesCB.Checked = (bool)Settings.Store.SendInterimUpdates;
forceInterimUpdCB.Checked = (bool)Settings.Store.ForceInterimUpdates;
forceInterimUpdTB.Text = String.Format("{0}", stoi(Settings.Store.InterimUpdateTime, 900));
sessionTimeoutCB.Checked = Settings.Store.AllowSessionTimeout;
wisprTimeoutCB.Checked = Settings.Store.WisprSessionTerminate;
sessionTimeoutCB.Checked = (bool)Settings.Store.AllowSessionTimeout;
wisprTimeoutCB.Checked = (bool)Settings.Store.WisprSessionTerminate;
ipAddrSuggestionTB.Text = Settings.Store.IPSuggestion;
useModifiedNameCB.Checked = Settings.Store.UseModifiedName;
useModifiedNameCB.Checked = (bool)Settings.Store.UseModifiedName;
}
private void cbDisableTBInput(object sender, EventArgs e)
private void checkboxModifyInputs(object sender, EventArgs e)
{
//Server Settings
authPortTB.Enabled = enableAuthCB.Checked;
acctPortTB.Enabled = enableAcctCB.Checked;
//Authentication options:
authGB.Enabled = enableAuthCB.Checked;
sendNasIdentifierTB.Enabled = sendNasIdentifierCB.Checked;
sendCalledStationTB.Enabled = sendCalledStationCB.Checked;
//Accounting options
acctGB.Enabled = enableAcctCB.Checked;
forceInterimUpdCB.Enabled = sendInterimUpdatesCB.Checked;
forceInterimUpdTB.Enabled = forceInterimUpdCB.Enabled;
forceInterimUpdLbl.Enabled = forceInterimUpdCB.Enabled;
}
private void btnOk_Click(object sender, EventArgs e)
@@ -146,5 +175,13 @@ namespace pGina.Plugin.RADIUS
{
}
//Converts value to int, or returns default value.
private int stoi(Object o, int def = 0)
{
try{
return (int)o; }
catch (InvalidCastException) { return def; }
}
}
}

View File

@@ -24,6 +24,7 @@ namespace pGina.Plugin.RADIUS
public byte[] authenticator { get; private set; }
//This really needs to support multiple attribute types
private Dictionary<AttributeType, byte[]> avp = new Dictionary<AttributeType, byte[]>();
private byte[] _avpBytes = null; //Byte representation of dictionary; required to calculate length
private byte[] avpBytes //Returns a current byte[] representation of AVP dictionary
@@ -81,17 +82,23 @@ namespace pGina.Plugin.RADIUS
byte length = data[index++]; //length includes the type and length byte
byte[] value = new byte[length - 2];
System.Buffer.BlockCopy(data, index, value, 0, value.Length);
avp.Add(atype, value);
if(!avp.Keys.Contains(atype)) //TEMPORARY WORK AROUND (AVP should be a list instead of a dict)
avp.Add(atype, value);
index += value.Length;
}
}
public bool containsAttribute(AttributeType type)
{
return this.avp.ContainsKey(type);
}
//Adds the specified attribute type and corresponding string data to AVP list
public void addAttribute(AttributeType type, string value)
{
if (String.IsNullOrEmpty(value))
return; //Drop empty string value fields
throw new ArgumentException("Value can not be empty");
addRawAttribute(type, Encoding.UTF8.GetBytes(value));
}
@@ -350,11 +357,11 @@ namespace pGina.Plugin.RADIUS
Acct_Session_Time, Acct_Input_Packets, Acct_Output_Packets, Acct_Terminate_Cause, Acct_Multi_Session_Id,
Acct_Link_Count, UNASSIGNED_52, UNASSIGNED_53, UNASSIGNED_54, UNASSIGNED_55,
UNASSIGNED_56, UNASSIGNED_57, UNASSIGNED_58, UNASSIGNED_59, CHAP_Challenge,
NAS_Port_Type, Port_Limit, Login_LAT_Port
NAS_Port_Type, Port_Limit, Login_LAT_Port, Acct_Interim_Interval = (byte)84
};
public enum Acct_AuthenticType { Not_Specified = 0, RADIUS, Local, Remote }
public enum Acct_Status_TypeType { Start = 1, Stop, Interim_Update }
public enum Acct_Terminate_CauseType { User_Request = 1, Session_Timeout = 5}
public enum Acct_Authentic { Not_Specified = 0, RADIUS, Local, Remote }
public enum Acct_Status_Type { Start = 1, Stop, Interim_Update }
public enum Acct_Terminate_Cause { User_Request = 1, Idle_Timeout = 4, Session_Timeout = 5}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,7 @@
<Compile Include="Packet.cs" />
<Compile Include="PluginImpl.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SessionLimiter.cs" />
<Compile Include="SessionManager.cs" />
<Compile Include="Settings.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,85 +0,0 @@
/*
Copyright (c) 2011, pGina Team
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the pGina Team nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace pGina.Plugin.RADIUS
{
class SessionLimiter
{
private Dictionary<int, DateTime> m_cache;
public SessionLimiter()
{
m_cache = new Dictionary<int, DateTime>();
}
public void Add(int sessId, int seconds)
{
//Assume 0 means no limit
DateTime dt = seconds == 0 ? DateTime.MaxValue : DateTime.Now.AddSeconds(seconds);
lock (this)
{
if (m_cache.ContainsKey(sessId))
m_cache[sessId] = dt;
else
m_cache.Add(sessId, dt);
}
}
public void Remove(int sessId)
{
lock (this)
{
if(m_cache.Keys.Contains(sessId))
m_cache.Remove(sessId);
}
}
public int Count()
{
return m_cache.Count;
}
public List<int> ExpiredSessions()
{
lock (this)
{
List<int> sessionList = new List<int>();
foreach (int sessId in m_cache.Keys)
{
if (m_cache[sessId] <= DateTime.Now)
sessionList.Add(sessId);
}
return sessionList;
}
}
}
}

View File

@@ -0,0 +1,110 @@
/*
Copyright (c) 2011, pGina Team
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the pGina Team nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace pGina.Plugin.RADIUS
{
class Session
{
public string username { get; set; }
public Guid id { get; set; } //guid.toString()
public int? windowsSessionId { get; set; } //Windows session id
public RADIUSClient client { get; set; }
//public DateTime loginTimestamp { get; set; }
public Packet.Acct_Terminate_Cause? terminate_cause { get; set; }
private int interim_update = 0;
private Timer interim_update_timer = null;
private int session_limit = 0;
private Timer session_limit_timer = null;
private DateTime session_terminate = DateTime.MaxValue;
private Timer session_terminate_timer = null;
public Session(Guid Id, string username, RADIUSClient client) //string username,
{
this.id = Id;
this.username = username;
this.client = client;
}
public void SetInterimUpdate(int frequency, TimerCallback tcb){
this.interim_update = frequency;
this.interim_update_timer = new Timer(tcb, this, frequency * 1000, frequency);
}
public void SetSessionTimeout(int timeout, TimerCallback tcb)
{
this.session_limit = timeout;
//Create timer, signals logoff every 30 seconds after timeout is reached
this.session_limit_timer = new Timer(tcb, this, timeout*1000, 30000);
}
public void Set_Session_Terminate(DateTime time, TimerCallback tcb)
{
this.session_terminate = time;
int ms = (time - DateTime.Now).Seconds;
this.session_terminate_timer = new Timer(tcb, this, ms * 1000, 30000);
//Create timer
}
public void disableCallbacks()
{
if (interim_update_timer != null)
{
interim_update_timer.Change(Timeout.Infinite, Timeout.Infinite);
interim_update_timer.Dispose();
}
if (session_limit_timer != null)
{
session_limit_timer.Change(Timeout.Infinite, Timeout.Infinite);
session_limit_timer.Dispose();
}
if (session_terminate_timer != null)
{
session_terminate_timer.Change(Timeout.Infinite, Timeout.Infinite);
session_terminate_timer.Dispose();
}
}
}
}

View File

@@ -21,6 +21,9 @@ namespace pGina.Plugin.RADIUS
m_settings = new pGinaDynamicSettings(RADIUSPlugin.SimpleUuid);
// Set default values for settings (if not already set)
m_settings.SetDefault("EnableAuth", true);
m_settings.SetDefault("EnableAcct", false);
m_settings.SetDefault("Server", "");
m_settings.SetDefault("AuthPort", 1812); //Authentication port
m_settings.SetDefault("AcctPort", 1813); //Authorization port
@@ -35,6 +38,8 @@ namespace pGina.Plugin.RADIUS
m_settings.SetDefault("CalledStationID", "%macaddr");
m_settings.SetDefault("SendInterimUpdates", false);
m_settings.SetDefault("ForceInterimUpdates", false);
m_settings.SetDefault("InterimUpdateTime", 900); //900sec = 15 min
m_settings.SetDefault("AllowSessionTimeout", false);
m_settings.SetDefault("WisprSessionTerminate", false);