(RADIUS) Enhancement for Livingston RADIUS 2.0.1

Todd R. Eigenschink (todd@tekinteractive.com)
Fri, 24 Apr 1998 09:33:21 -0500 (EST)

I put the following together in two evenings, one of which was last
night. It's two distinct enhancements for Livingston RADIUS...which
are, of course, lumped into one patch. :)

The first allows use of operators other than =: <, >, <=, >=, and !=.
They work for both strings and integers/ipaddrs, although most don't
mean much for ipaddrs.

The second adds a new check item, Time-Restriction. With this, you
can specify a user such as

bob Password = "bobob", Time-Restriction = "08:00 17:00 MTWRF"
Framed-IP-Address = 255.255.255.254
<etc.>

The format of the string is "hh:mm hh:mm <days>", which specify a
start time, an end time, and days when that's valid (MTWRFSaSu,
case-sensitive). If no days are specified, the restriction is applied
every day.

If the user attempts to log in outside the permitted window, access is
denied (or, more specifically, that user entry is determined not to
match--it's a check item, after all). We plan to use this for comp
accounts and the like, where they shouldn't be using the account at
home after-hours or on weekends.

If the user logs in within the specified window *and* there is a
Session-Timeout specified in the reply items, the session timeout is
changed to reflect the time until the end of the login window. If
there is no Session-Timeout, one is not added. For example, if your
time is 08:00-17:00 and you log in at 16:45, you get 15 minutes.

We plan to use it like this: Normally, we don't have session timeouts.
If we provide a comp account and want to make sure that access is
limited to the defined times, we'll set a session timeout equal to the
difference between the start and the end--9 hours, say. Then, if a
comp account logs in, the timeout will be adjusted. If not, we just
want to make sure they don't start *new* logins outside the window.

It would be pretty simple to (a) set the session timeout to the
*lesser* of the time remaining or whatever the timeout was, (b) add a
flag to the time-restriction string to specify the behavior, or (c)
add a session timeout even if there isn't one.

(What's kind of funny is that I originally added the other operators
to help *do* the time restriction, and then I realized how convoluted
that was going to be--`Password = "", Current-Time > ..., Current-Time
< ...'. Ugh. If you want only the time-restriction parts, you need
only (a) the Time-Restriction dictionary entry, (b) the
PW_SESSION_TIMEOUT and PW_TIME_RESTRICTION #defines from radius.h, and
(c) the big case PW_TIME_RESTRICTION block. The other stuff is for
the operators.)

I'm *very* interested in comments, suggestions, bugfixes, etc. The
patch is pretty simple, but hasn't been extensively tested. Even
though the code for time restriction is a lot more complicated than
the operators, I trust it more. And the operator code is a little
gruesome-looking due to the massive indentation.

*Please* look at the code, try it out, fix it, whatever--let me know
what you think. I added one dictionary attribute, Time-Restriction,
with value 1100. It can be anything, since it's internal-only. Just
make sure the dictionary and the #define in radius.h match.

(And yes, I changed the version string.)

diff -ur radius-2.0.1/raddb/dictionary radius-2.0.1.oper/raddb/dictionary
--- radius-2.0.1/raddb/dictionary Tue May 20 11:34:41 1997
+++ radius-2.0.1.oper/raddb/dictionary Thu Apr 23 18:33:02 1998
@@ -99,6 +99,8 @@
ATTRIBUTE Port-Limit 62 integer
ATTRIBUTE Connect-Info 65 string

+ATTRIBUTE Time-Restriction 1100 string
+
#
# Non-Protocol Attributes
# These attributes are used internally by the server
diff -ur radius-2.0.1/src/radius.h radius-2.0.1.oper/src/radius.h
--- radius-2.0.1/src/radius.h Thu Dec 18 17:38:24 1997
+++ radius-2.0.1.oper/src/radius.h Thu Apr 23 22:57:06 1998
@@ -62,6 +62,15 @@
#define PW_TYPE_DATE 3


+/* User file operator types. */
+#define PW_OPER_EQ 0
+#define PW_OPER_NEQ 1
+#define PW_OPER_LT 2
+#define PW_OPER_GT 3
+#define PW_OPER_LEQ 4
+#define PW_OPER_GEQ 5
+
+
#define PW_AUTHENTICATION_REQUEST 1
#define PW_AUTHENTICATION_ACK 2
#define PW_AUTHENTICATION_REJECT 3
@@ -99,6 +108,7 @@
#define PW_FRAMED_ROUTE 22
#define PW_FRAMED_IPXNET 23
#define PW_STATE 24
+#define PW_SESSION_TIMEOUT 27
#define PW_TERMINATION 29

#define PW_ACCT_STATUS_TYPE 40
@@ -110,6 +120,9 @@
#define PW_ACCT_SESSION_TIME 46
#
#define PW_CONNECT_INFO 65
+
+#define PW_TIME_RESTRICTION 1100
+
/*
* Non-Protocol Attributes
*/
@@ -212,6 +225,7 @@
char name[32];
int attribute;
int type;
+ int oper;
UINT4 lvalue; /* length of strvalue if present */
char strvalue[AUTH_STRING_LEN];
struct value_pair *next;
diff -ur radius-2.0.1/src/radiusd.c radius-2.0.1.oper/src/radiusd.c
--- radius-2.0.1/src/radiusd.c Thu Jun 5 04:52:27 1997
+++ radius-2.0.1.oper/src/radiusd.c Thu Apr 23 22:56:22 1998
@@ -1222,6 +1222,7 @@
int authtype;
int i;
int j;
+ int cmpresult;
int passlen;
int result;
int retval;
@@ -1367,6 +1368,58 @@
}
break;

+ case PW_TIME_RESTRICTION:
+ {
+ int h1, h2, m1, m2;
+ char days[20];
+ static char *dow[] = {"Su", "M", "T", "W", "R",
+ "F", "Sa"};
+ days[0] = '\0';
+
+ if (sscanf(check_item->strvalue,
+ "%d:%d %d:%d %s", &h1, &m1,
+ &h2, &m2, days) >= 4) {
+ VALUE_PAIR *sesslim;
+ struct tm tm, *conv;
+ time_t start, end, midnight, diff;
+ time_t now = time(NULL);
+
+ /* start and end are seconds since midnight. */
+ start = (h1 * 60 * 60) + (m1 * 60);
+ end = (h2 * 60 * 60) + (m2 * 60);
+
+ conv = localtime(&now);
+ conv->tm_sec = 0;
+ conv->tm_min = 0;
+ conv->tm_hour = 0;
+
+ midnight = mktime(conv);
+
+ diff = now - midnight;
+
+ if (diff < start || diff > end ||
+ (strlen(days) > 0 &&
+ strstr(days, dow[conv->tm_wday]) == NULL)) {
+ log_err("login attempted outside permitted time");
+ result = -1;
+ break;
+ }
+
+ /* Set the session timeout to end - diff. */
+ if ((sesslim = get_attribute(user_reply,
+ PW_SESSION_TIMEOUT)) != NULL) {
+ sesslim->lvalue = end - diff;
+ }
+ }
+ else {
+ /* Couldn't parse the string. */
+ log_err("couldn't parse time restriction %s",
+ check_item->strvalue);
+ }
+ }
+ break;
+
+
default:
if(auth_item == (VALUE_PAIR *)NULL) {
result = -1;
@@ -1376,16 +1429,45 @@
switch(check_item->type) {

case PW_TYPE_STRING:
- if(strcmp(check_item->strvalue,
- auth_item->strvalue) != 0) {
+ cmpresult =
+ strcmp(auth_item->strvalue,
+ check_item->strvalue);
+ if ((check_item->oper == PW_OPER_EQ &&
+ cmpresult != 0) ||
+ (check_item->oper == PW_OPER_NEQ &&
+ cmpresult == 0) ||
+ (check_item->oper == PW_OPER_LT &&
+ cmpresult != -1) ||
+ (check_item->oper == PW_OPER_GT &&
+ cmpresult != 1) ||
+ (check_item->oper == PW_OPER_LEQ &&
+ cmpresult == 1) ||
+ (check_item->oper == PW_OPER_GEQ &&
+ cmpresult == -1)) {
result = -1;
}
break;

case PW_TYPE_INTEGER:
case PW_TYPE_IPADDR:
- if(check_item->lvalue
- != auth_item->lvalue) {
+ if ((check_item->oper == PW_OPER_EQ &&
+ auth_item->lvalue
+ != check_item->lvalue) ||
+ (check_item->oper == PW_OPER_NEQ &&
+ auth_item->lvalue
+ == check_item->lvalue) ||
+ (check_item->oper == PW_OPER_LT &&
+ auth_item->lvalue
+ >= check_item->lvalue) ||
+ (check_item->oper == PW_OPER_GT &&
+ auth_item->lvalue
+ <= check_item->lvalue) ||
+ (check_item->oper == PW_OPER_LEQ &&
+ auth_item->lvalue
+ > check_item->lvalue) ||
+ (check_item->oper == PW_OPER_GEQ &&
+ auth_item->lvalue
+ < check_item->lvalue)) {
result = -1;
}
break;
diff -ur radius-2.0.1/src/users.c radius-2.0.1.oper/src/users.c
--- radius-2.0.1/src/users.c Thu Jun 5 04:52:28 1997
+++ radius-2.0.1.oper/src/users.c Thu Apr 23 22:58:14 1998
@@ -361,6 +361,7 @@
UINT4 user_gettime();
struct tm *tm;
time_t timeval;
+ int oper;

mode = PARSE_MODE_NAME;
while(*buffer != '\n' && *buffer != '\0') {
@@ -386,8 +387,28 @@
/* Equal sign */
if(*buffer == '=') {
mode = PARSE_MODE_VALUE;
+ oper = PW_OPER_EQ;
buffer++;
}
+ else if ((*buffer == '>' || *buffer == '<') &&
+ *(buffer + 1) && *(buffer + 1) == '=') {
+ mode = PARSE_MODE_VALUE;
+ oper = (*buffer == '>' ?
+ PW_OPER_GEQ : PW_OPER_LEQ);
+ buffer += 2;
+ }
+ else if (*buffer == '>' || *buffer == '<') {
+ mode = PARSE_MODE_VALUE;
+ oper = (*buffer == '>' ?
+ PW_OPER_GT : PW_OPER_LT);
+ buffer++;
+ }
+ else if (*buffer == '!' && *(buffer + 1) &&
+ *(buffer + 1) == '=') {
+ mode = PARSE_MODE_VALUE;
+ oper = PW_OPER_NEQ;
+ buffer += 2;
+ }
else {
return(-1);
}
@@ -405,6 +426,7 @@
strcpy(pair->name, attr->name);
pair->attribute = attr->value;
pair->type = attr->type;
+ pair->oper = oper;

switch(pair->type) {

diff -ur radius-2.0.1/src/version.c radius-2.0.1.oper/src/version.c
--- radius-2.0.1/src/version.c Thu Jun 5 04:52:28 1997
+++ radius-2.0.1.oper/src/version.c Fri Apr 24 09:04:56 1998
@@ -46,7 +46,7 @@
* would like a range of versions allocated for your use.
*/

-#define VERSION "Livingston RADIUS 2.0.1 97/5/22"
+#define VERSION "Livingston RADIUS 2.0.1(TEK) 98/4/24"

/*************************************************************************
*

Todd

-- 
Todd R. Eigenschink             TEK Interactive Group, Inc.
todd@tekinteractive.com         http://www.tekinteractive.com/
System Administrator            (219) 459-2521
-
To unsubscribe, email 'majordomo@livingston.com' with
'unsubscribe portmaster-radius' in the body of the message.
Searchable list archive: <URL:http://www.livingston.com/Tech/archive/>