X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/c8ec92d66ce14567998b89bf587a26ac3a7b267f..c266121a2c5e1b073dcf26c1ab64bd7b5febe4f3:/radius.c?ds=inline

diff --git a/radius.c b/radius.c
index f20821c..395e7a0 100644
--- a/radius.c
+++ b/radius.c
@@ -1,6 +1,6 @@
 // L2TPNS Radius Stuff
 
-char const *cvs_id_radius = "$Id: radius.c,v 1.21 2005/01/05 13:45:49 bodea Exp $";
+char const *cvs_id_radius = "$Id: radius.c,v 1.30 2005/05/07 08:17:26 bodea Exp $";
 
 #include <time.h>
 #include <stdio.h>
@@ -42,7 +42,7 @@ void initrad(void)
 
 void radiusclear(uint16_t r, sessionidt s)
 {
-	if (s) session[s].radius = 0;
+	if (s) sess_local[s].radius = 0;
 	memset(&radius[r], 0, sizeof(radius[r])); // radius[r].state = RADIUSNULL;
 }
 
@@ -69,7 +69,7 @@ static uint16_t get_free_radius()
 
 uint16_t radiusnew(sessionidt s)
 {
-	uint16_t r = session[s].radius;
+	uint16_t r = sess_local[s].radius;
 
 	/* re-use */
 	if (r)
@@ -86,11 +86,13 @@ uint16_t radiusnew(sessionidt s)
 	};
 
 	memset(&radius[r], 0, sizeof(radius[r]));
-	session[s].radius = r;
+	sess_local[s].radius = r;
 	radius[r].session = s;
 	radius[r].state = RADIUSWAIT;
 	radius[r].retry = TIME + 1200; // Wait at least 120 seconds to re-claim this.
 
+	random_data(radius[r].auth, sizeof(radius[r].auth));
+
 	LOG(3, s, session[s].tunnel, "Allocated radius %d\n", r);
 	return r;
 }
@@ -140,7 +142,7 @@ void radiussend(uint16_t r, uint8_t state)
 		if (s)
 		{
 			if (state == RADIUSAUTH)
-				sessionshutdown(s, "RADIUS timeout");
+				sessionshutdown(s, "RADIUS timeout.", 3, 0);
 			else
 			{
 				LOG(1, s, session[s].tunnel, "RADIUS timeout, but in state %s so don't timeout session\n",
@@ -165,6 +167,7 @@ void radiussend(uint16_t r, uint8_t state)
 			break;
 		case RADIUSSTART:
 		case RADIUSSTOP:
+		case RADIUSINTERIM:
 			b[0] = 4;               // accounting request
 			break;
 		default:
@@ -229,20 +232,28 @@ void radiussend(uint16_t r, uint8_t state)
 			p += p[1];
 		}
 	}
-	else if (state == RADIUSSTART || state == RADIUSSTOP)
+	else if (state == RADIUSSTART || state == RADIUSSTOP || state == RADIUSINTERIM)
 	{                          // accounting
 		*p = 40;                // accounting type
 		p[1] = 6;
-		*(uint32_t *) (p + 2) = htonl((state == RADIUSSTART) ? 1 : 2);
+		*(uint32_t *) (p + 2) = htonl(state - RADIUSSTART + 1); // start=1, stop=2, interim=3
 		p += p[1];
 		if (s)
 		{
 			*p = 44;           // session ID
 			p[1] = 18;
-			sprintf(p + 2, "%08X%08X", session[s].id, session[s].opened);
+			sprintf(p + 2, "%08X%08X", session[s].unique_id, session[s].opened);
 			p += p[1];
-			if (state == RADIUSSTOP)
-			{                // stop
+			if (state == RADIUSSTART)
+			{                // start
+				*p = 41;      // delay
+				p[1] = 6;
+				*(uint32_t *) (p + 2) = htonl(time(NULL) - session[s].opened);
+				p += p[1];
+				sess_local[s].last_interim = time_now; // Setup "first" Interim
+			}
+			else
+			{                // stop, interim
 				*p = 42;      // input octets
 				p[1] = 6;
 				*(uint32_t *) (p + 2) = htonl(session[s].cin);
@@ -264,11 +275,16 @@ void radiussend(uint16_t r, uint8_t state)
 				*(uint32_t *) (p + 2) = htonl(session[s].pout);
 				p += p[1];
 			}
-			else
-			{                // start
-				*p = 41;      // delay
-				p[1] = 6;
-				*(uint32_t *) (p + 2) = htonl(time(NULL) - session[s].opened);
+
+			if (session[s].snoop_ip && session[s].snoop_port)
+			{
+				*p = 26;				// vendor-specific
+				*(uint32_t *) (p + 2) = htonl(9);	// Cisco
+				p[6] = 1;				// Cisco-Avpair
+				p[7] = 2 + sprintf(p + 8, "intercept=%s:%d",
+					fmtaddr(session[s].snoop_ip, 0), session[s].snoop_port);
+
+				p[1] = p[7] + 6;
 				p += p[1];
 			}
 		}
@@ -337,9 +353,7 @@ void radiussend(uint16_t r, uint8_t state)
 	{
 		// get radius port
 		uint16_t port = config->radiusport[(radius[r].try - 1) % config->numradiusservers];
-		// no need to define the accounting port for itself:
-		//  the accounting port is as far as I know always one more
-		//  than the auth port    JK 20040713
+		// assume RADIUS accounting port is the authentication port +1
 		addr.sin_port = htons((state == RADIUSAUTH) ? port : port+1);
 	}
 
@@ -383,7 +397,8 @@ void processrad(uint8_t *buf, int len, char socket_index)
 		LOG(1, s, session[s].tunnel, "   Unexpected RADIUS response\n");
 		return;
 	}
-	if (radius[r].state != RADIUSAUTH && radius[r].state != RADIUSSTART && radius[r].state != RADIUSSTOP)
+	if (radius[r].state != RADIUSAUTH && radius[r].state != RADIUSSTART
+	    && radius[r].state != RADIUSSTOP && radius[r].state != RADIUSINTERIM)
 	{
 		LOG(1, s, session[s].tunnel, "   Unexpected RADIUS response\n");
 		return;
@@ -403,7 +418,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
 		}
 
 		if ((radius[r].state == RADIUSAUTH && r_code != AccessAccept && r_code != AccessReject) ||
-			((radius[r].state == RADIUSSTART || radius[r].state == RADIUSSTOP) && r_code != AccountingResponse))
+			((radius[r].state == RADIUSSTART || radius[r].state == RADIUSSTOP || radius[r].state == RADIUSINTERIM) && r_code != AccountingResponse))
 		{
 			LOG(1, s, session[s].tunnel, "   Unexpected RADIUS response %s\n", radius_code(r_code));
 			return; // We got something we didn't expect. Let the timeouts take
@@ -472,6 +487,9 @@ void processrad(uint8_t *buf, int len, char socket_index)
 						session[s].ip_pool_index = -1;
 						LOG(3, s, session[s].tunnel, "   Radius reply contains IP address %s\n",
 							fmtaddr(htonl(session[s].ip), 0));
+
+						if (session[s].ip == 0xFFFFFFFE)
+							session[s].ip = 0; // assign from pool
 					}
 					else if (*p == 135)
 					{
@@ -580,7 +598,7 @@ void processrad(uint8_t *buf, int len, char socket_index)
 						// Vendor-Specific Attribute
 						int vendor = ntohl(*(int *)(p + 2));
 						char attrib = *(p + 6);
-						char attrib_length = *(p + 7) - 2;
+						int attrib_length = *(p + 7) - 2;
 						char *avpair, *value, *key, *newp;
 
 						LOG(3, s, session[s].tunnel, "   Radius reply contains Vendor-Specific.  Vendor=%d Attrib=%d Length=%d\n", vendor, attrib, attrib_length);
@@ -621,12 +639,38 @@ void processrad(uint8_t *buf, int len, char socket_index)
 						} while (newp);
 						free(avpair);
 					}
+					else if (*p == 99)
+					{
+						// Framed-IPv6-Route
+						struct in6_addr r6;
+						int prefixlen;
+						uint8_t *n = p + 2;
+						uint8_t *e = p + p[1];
+						uint8_t *m = strchr(n, '/');
+
+						*m++ = 0;
+						inet_pton(AF_INET6, n, &r6);
+
+						prefixlen = 0;
+						while (m < e && isdigit(*m)) {
+							prefixlen = prefixlen * 10 + *m++ - '0';
+						}
+
+						if (prefixlen)
+						{
+							LOG(3, s, session[s].tunnel,
+								"   Radius reply contains route for %s/%d\n",
+								n, prefixlen);
+							session[s].ipv6route = r6;
+							session[s].ipv6prefixlen = prefixlen;
+						}
+					}
 				}
 			}
 			else if (r_code == AccessReject)
 			{
-				LOG(2, s, session[s].tunnel, "   Authentication denied for %s\n", session[s].user);
-//FIXME: We should tear down the session here!
+				LOG(2, s, session[s].tunnel, "   Authentication rejected for %s\n", session[s].user);
+				sessionkill(s, "Authentication rejected");
 				break;
 			}
 
@@ -670,24 +714,27 @@ void radiusretry(uint16_t r)
 	radius[r].retry = backoff(radius[r].try + 1);
 	switch (radius[r].state)
 	{
-		case RADIUSCHAP:           // sending CHAP down PPP
+		case RADIUSCHAP:	// sending CHAP down PPP
 			sendchap(t, s);
 			break;
 		case RADIUSIPCP:
-			sendipcp(t, s);         // send IPCP
+			sendipcp(t, s);	// send IPCP
 			break;
-		case RADIUSAUTH:           // sending auth to RADIUS server
+		case RADIUSAUTH:	// sending auth to RADIUS server
 			radiussend(r, RADIUSAUTH);
 			break;
-		case RADIUSSTART:          // sending start accounting to RADIUS server
+		case RADIUSSTART:	// sending start accounting to RADIUS server
 			radiussend(r, RADIUSSTART);
 			break;
-		case RADIUSSTOP:           // sending stop accounting to RADIUS server
+		case RADIUSSTOP:	// sending stop accounting to RADIUS server
 			radiussend(r, RADIUSSTOP);
 			break;
+		case RADIUSINTERIM:	// sending interim accounting to RADIUS server
+			radiussend(r, RADIUSINTERIM);
+			break;
 		default:
-		case RADIUSNULL:           // Not in use
-		case RADIUSWAIT:           // waiting timeout before available, in case delayed reply from RADIUS server
+		case RADIUSNULL:	// Not in use
+		case RADIUSWAIT:	// waiting timeout before available, in case delayed reply from RADIUS server
 			// free up RADIUS task
 			radiusclear(r, s);
 			LOG(3, s, session[s].tunnel, "Freeing up radius session %d\n", r);