Ключевые слова:SQL, radius, (найти похожие документы)
From: Harris Vaegan-Lloyd <harris@hightide.net.au>
To: miquels@cistron.nl
Subject: SQL for radiusd patch.
Message-ID: <35CEC1CA.C54AEEDE@hightide.net.au>
Date: Mon, 10 Aug 1998 09:47:54 +0000
Organization: Hightide Internet
I hada a desperate need to further destory my little free time and make
my gf hate me so I've added the ability to authenticate and log to a
PostgreSQL databse from radiusd-cistron. I hope you like it ;). It's a
bit hairy at the moment but a fair few people seem to want it as much as
I did.
--
Harris Vaegan-Lloyd. PSTN: +61-02-9557-2638
SMTP: harris@hightide.net.au
- Linux - Perl - Deveolpment - Admin - Web Programming - Databases -
diff -ur -N radiusd-cistron-1.5.4.3/doc/README.sql radiusd-sql/doc/README.sql
--- radiusd-cistron-1.5.4.3/doc/README.sql Thu Jan 1 10:00:00 1970
+++ radiusd-sql/doc/README.sql Mon Aug 10 19:24:02 1998
@@ -0,0 +1,46 @@
+Greetings dear valued customer..
+
+All the addition to radiusd-cistron to add authentication and logging with an postgresql databse are copyright Harris Vaegan-Lloyd and placed under the current version of the GPL.
+
+This is messy at the moment and I wouldn't reccomend it for use in a production environment. However
+if your marketting department has though up some completly insane pricing scheme for dialup you should
+find it useful ;). All the radius log analysis stuff I've use so far has been very nice but, well. I
+like SQL and think everything is improved by being able to work with a database ;).
+
+Radiusd expects two tables, one with username and passwords, and one to hold the logs. usernames and passwords are self-explanatory. The logs table holds the username, time logged in, time logged out, data in and data out. Time logged in is calculated by subtracting the Acct-Time-Session value. bwin and bwout are calculated from the Acct-Input-Octets and Acct-Output-Octets values. User name is from, well , User-Name, strangely enough.
+
+Example SQL code -
+
+To create the table.
+\connect radiusd -
+CREATE TABLE users (pass varchar(16), username varchar(8));
+CREATE TABLE logs (bwin int4, bwout int4, name varchar(32), start datetime, stop datetime);
+
+To find the total bandwidth use in megs for a user -
+select (sum(bwin) + sum(bwout)) /1024) from logs where name='user'
+
+To find the total time use in seconds for a user.
+select sum(date_part('epoch',age(stop,start))) from logs where name='user';
+
+To get it for a specific time period add something like -
+where (date_part('month', start) = 8) and (date_part('year', start) = 1998)
+
+So say if you wanted to find out the total cost for a user considering you charged 35 cents a megabyte and 1.1 cents a minutes with 5 hours a month and 20 megs free youc could use this line to find out the total cost for the user..
+
+select int4larger(sum(bwin + bwout) / 1024 - 20, 0) * 35 +
+ int4larger(((sum(date_part('epoch',age(stop,start))) / 60) - 300)::int4,0) * 1.1
+ where name = 'user' and date_part('month', start) = 8 and date_part('year', start) = 1998;
+
+Not exactly a simple SQL statment but it took me a quarter of an hour to get the same thing that took me four days off and on to do in perl.
+
+TODO -
+- Make the authentication part check a boolean variable to see if the user is locked out or not, maybe a way to set the reason for lockout as well.
+- Throw together a web interface to get user status info for admins and user alike, generate reports etc etc etc. This is the kind of boring cruft I do for a living so it shouldn't take too long but will be ages before I actually get around to it.
+- Do some checks to see if the database connection is OK before each insert, and if it's not reconnect.
+- Give it some real testing. The perl scripts I used to send the accounting packets don't really count.
+- Find a new job where I can get some real time to work on it ;).
+
+
+Compilation instructions.
+
+Uncomment the lines that begin with SQL and SQLLIB in the Makefile as per PAM support. Then make as usual.
diff -ur -N radiusd-cistron-1.5.4.3/src/Make.inc radiusd-sql/src/Make.inc
--- radiusd-cistron-1.5.4.3/src/Make.inc Sat Jul 4 23:49:25 1998
+++ radiusd-sql/src/Make.inc Sun Aug 9 18:41:46 1998
@@ -7,6 +7,8 @@
BINDIR = /usr/local/bin
SBINDIR = /usr/local/sbin
+SERVERSQL_OBJS = radiusd.o dict.o files.o util.o md5.o attrprint.o acct.o \
+ misc.o pam.o log.o version.o pgsql.o
SERVER_OBJS = radiusd.o dict.o files.o util.o md5.o attrprint.o acct.o \
misc.o pam.o log.o version.o
SERVERDBM_OBJS = radiusd.o dict.o filesdbm.o util.o md5.o attrprint.o acct.o \
@@ -20,17 +22,21 @@
dbm: radiusd.dbm builddbm
radiusd: $(SERVER_OBJS)
- $(CC) $(LDFLAGS) -o radiusd $(SERVER_OBJS) $(LIBS) $(LCRYPT) $(PAMLIB)
+ $(CC) $(LDFLAGS) -o radiusd $(SERVER_OBJS) $(LIBS) $(LCRYPT) $(PAMLIB) $(SQLLIB)
radiusd.dbm: $(SERVERDBM_OBJS)
$(CC) $(LDFLAGS) -o radiusd.dbm $(SERVERDBM_OBJS) $(LIBS) $(LCRYPT) \
- $(DBMLIB) $(PAMLIB)
+ $(DBMLIB) $(PAMLIB) $(SQLLIB)
+
+radiusd.sql: $(SERVERSQL_OBJS)
+ $(CC) $(LDFLAGS) -o radiusd $(SERVERSQL_OBJS) $(LIBS) $(LCRYPT) \
+ $(DBMLIB) $(PAMLIB) $(SQLLIB)
radiusd.o: radiusd.c $(INCLUDES)
- $(CC) $(CFLAGS) $(PAM) -c radiusd.c
+ $(CC) $(CFLAGS) $(PAM) $(SQL) -c radiusd.c
acct.o: acct.c $(INCLUDES)
- $(CC) $(CFLAGS) -c acct.c
+ $(CC) $(CFLAGS) $(SQL) -c acct.c
attrprint.o: attrprint.c $(INCLUDES)
$(CC) $(CFLAGS) -c attrprint.c
@@ -52,6 +58,9 @@
pam.o: pam.c $(INCLUDES)
$(CC) $(CFLAGS) $(PAM) -c pam.c
+
+pgsql.o: pgsql.c $(INCLUDES)
+ $(CC) $(CFLAGS) $(SQL) -c pgsql.c
version.o: version.c $(INCLUDES)
$(CC) $(CFLAGS) -o version.o -c version.c
diff -ur -N radiusd-cistron-1.5.4.3/src/Makefile radiusd-sql/src/Makefile
--- radiusd-cistron-1.5.4.3/src/Makefile Sun Nov 23 01:51:42 1997
+++ radiusd-sql/src/Makefile Sun Aug 9 18:40:08 1998
@@ -14,15 +14,20 @@
endif
CC = gcc
-CFLAGS = -Wall -g # -DNOSHADOW
+CFLAGS = -Wall -g -I/usr/local/pgsql/include# -DNOSHADOW
LDFLAGS = # -s # tatic
-LIBS = $(LSHADOW)
+LIBS = $(LSHADOW) -lcrypt
+INCLUDES =
+
DBM = -DNDBM
DBMLIB = -ldb
#PAM = -DPAM
#PAMLIB = -lpam -ldl
+
+SQL = -DUSE_SQL
+SQLLIB = -lpq -L/usr/local/pgsql/lib
BINDIR = /usr/local/bin
SBINDIR = /usr/local/sbin
diff -ur -N radiusd-cistron-1.5.4.3/src/acct.c radiusd-sql/src/acct.c
--- radiusd-cistron-1.5.4.3/src/acct.c Wed Jun 24 00:13:24 1998
+++ radiusd-sql/src/acct.c Sun Aug 9 18:28:39 1998
@@ -27,7 +27,9 @@
#include "radiusd.h"
#include "radutmp.h"
-
+#if USE_SQL
+#include "/usr/local/pgsql/include/libpq-fe.h"
+#endif
/*
* FIXME: this should be configurable.
*/
@@ -40,7 +42,9 @@
static char porttypes[] = "ASITX";
#define LOCK_LEN sizeof(struct radutmp)
-
+#ifdef USE_SQL
+PGconn *PSQLconn;
+#endif
/*
* UUencode 4 bits base64. We use this to turn a 4 byte field
* (an IP adres) into 6 bytes of ASCII. This is used for the
@@ -455,8 +459,88 @@
return ret;
}
+#if USE_SQL
+int rad_accounting_sql(AUTH_REQ *auth_req)
+{
+ VALUE_PAIR *pair;
+ time_t curtime;
+ struct tm *tm;
+ char *start_time;
+ char *stop_time;
+ ulong sess_time;
+ char *name;
+ UINT4 bwin;
+ UINT4 bwout;
+ char *sql;
+ PGresult* res;
+
+
+ curtime = time(0);
+ start_time = malloc(32);
+ stop_time = malloc(32);
+ name = malloc(32);
+
+ /* next we use gmtime() to take this time and get it into a format
+ * suitable for SQL. */
+ tm = gmtime(&curtime);
+
+ snprintf(stop_time, 32, "%d-%d-%d %d:%d:%d",
+ (1900 + tm->tm_year),
+ (tm->tm_mon + 1),
+ tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ /* Init the SQL string. */
+ sql = malloc(256);
+
+ pair = auth_req->request;
+ while(pair != (VALUE_PAIR *)NULL) {
+ if (! strcmp(pair->name, "Acct-Status-Type")) {
+ if (pair->lvalue != PW_STATUS_STOP ) {
+ return 0; // We only need the stop packets for
+ } // the sql accounting. */
+ } else if (! strcmp(pair->name, "Acct-Input-Octets")) {
+ bwin = pair->lvalue;
+ } else if (! strcmp(pair->name, "Acct-Output-Octets")) {
+ bwout = pair->lvalue;
+ } else if (! strcmp(pair->name, "User-Name")) {
+ sprintf(name, "%s", pair->strvalue);
+ } else if (! strcmp(pair->name, "Acct-Session-Time")) {
+ sess_time = pair->lvalue;
+ }
+ pair = pair->next;
+ }
+
+ /* O.K. Now we have the time that the session ended, we use the
+ * Acct-Session-Time to work out when it started
+ * We got the length of the session from the accouning request and
+ * the time that it ended form when we received this request.
+ */
+ curtime = curtime - sess_time;
+ tm = gmtime(&curtime);
+ snprintf(start_time, 32, "%d-%d-%d %d:%d:%d",
+ (1900 + tm->tm_year),
+ (tm->tm_mon + 1),
+ tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ /* Hey rocky! Watch me pull an insert statement out of my hat! */
+
+ snprintf(sql, 256, "insert into logs values ( %ld, %ld, '%s', '%s', '%s')", bwin, bwout, name, start_time, stop_time);
+
+ res = PQexec(PSQLconn, sql);
+ if (PQresultStatus(res) != PGRES_COMMAND_OK ){
+ log(L_ERR, "Insert failed: %s\n", PQerrorMessage(PSQLconn));
+ }
+ free(sql);
+ free(name);
+ free(start_time);
+ free(stop_time);
+
+ return 0;
+}
+#endif /* USE_SQL */
int rad_accounting_orig(AUTH_REQ *authreq, int authtype, char *f)
{
@@ -638,6 +722,10 @@
* we run it first, the stripped info will also
* get into the "details" file.
*/
+#if USE_SQL
+ if (rad_accounting_sql(authreq) == 0)
+ reply = 1;
+#endif
if (rad_accounting_new(authreq, 1) == 0)
reply = 1;
if (rad_accounting_orig(authreq, auth, NULL) == 0)
@@ -647,6 +735,10 @@
* First log into the details file, before the
* username gets stripped by rad_accounting_new.
*/
+#if USE_SQL
+ if (rad_accounting_sql(authreq) == 0)
+ reply = 1;
+#endif
if (rad_accounting_orig(authreq, auth, NULL) == 0)
reply = 1;
if (rad_accounting_new(authreq, 1) == 0)
diff -ur -N radiusd-cistron-1.5.4.3/src/pgsql.c radiusd-sql/src/pgsql.c
--- radiusd-cistron-1.5.4.3/src/pgsql.c Thu Jan 1 10:00:00 1970
+++ radiusd-sql/src/pgsql.c Mon Aug 3 23:51:41 1998
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include "/usr/local/pgsql/include/libpq-fe.h"
+#include <unistd.h>
+#include "radiusd.h"
+
+PGconn *PSQLconn;
+
+void exit_nicely(PGconn* conn)
+{
+ PQfinish(conn);
+ exit(1);
+}
+
+int psql_pass(char *user, char *pass) {
+ PGresult* res;
+ char *passbuff;
+ char *sql;
+
+ passbuff = malloc(8);
+
+ sql = malloc(sizeof("select pass from users where username = ''") + sizeof(user));
+ sprintf(sql, "select pass from users where username = '%s'", user);
+ res = PQexec(PSQLconn, sql);
+ if (PQresultStatus(res) != PGRES_TUPLES_OK) {
+ log(L_ERR, "No such user in SQL db.");
+ PQclear(res);
+ }
+ free(sql);
+ snprintf(passbuff,8,"%s",PQgetvalue(res,0,0));
+ PQclear(res);
+ return(strncmp(pass, passbuff, 8));
+}
diff -ur -N radiusd-cistron-1.5.4.3/src/radius.h radiusd-sql/src/radius.h
--- radiusd-cistron-1.5.4.3/src/radius.h Sat Jul 4 23:54:46 1998
+++ radiusd-sql/src/radius.h Wed Jul 15 20:16:15 1998
@@ -164,6 +164,7 @@
#define PW_AUTHTYPE_SECURID 2
#define PW_AUTHTYPE_CRYPT 3
#define PW_AUTHTYPE_REJECT 4
+#define PW_AUTHTYPE_SQL 252
#define PW_AUTHTYPE_PAM 253
#define PW_AUTHTYPE_ACCEPT 254
diff -ur -N radiusd-cistron-1.5.4.3/src/radiusd.c radiusd-sql/src/radiusd.c
--- radiusd-cistron-1.5.4.3/src/radiusd.c Sat Jul 4 23:54:26 1998
+++ radiusd-sql/src/radiusd.c Sun Aug 9 18:27:28 1998
@@ -93,7 +93,9 @@
UINT4 expiration_seconds;
UINT4 warning_seconds;
static AUTH_REQ *first_request;
-
+#if USE_SQL
+PGconn *PSQLconn;
+#endif
#if !defined(__linux__) && !defined(__GNU_LIBRARY__)
extern int errno;
#endif
@@ -160,6 +162,13 @@
int main(int argc, char **argv)
{
+#if USE_SQL
+ char *pghost = "localhost";
+ char *pgport = NULL;
+ char *pgoptions = NULL;
+ char *pgtty = NULL;
+ char *dBname = "radiusd";
+#endif
int salen;
int result;
struct sockaddr salocal;
@@ -334,6 +343,16 @@
perror ("acct bind");
exit(1);
}
+#if USE_SQL
+ /*
+ * Start that funky SQL thang happening.
+ */
+ PSQLconn = PQsetdb(pghost,pgport,pgoptions,pgtty,dBname);
+ if (PQstatus(PSQLconn) == CONNECTION_BAD) {
+ log(L_INFO, "Connection to the database failed.");
+ exit_nicely(PSQLconn);
+ }
+#endif
/*
* Disconnect from session
@@ -961,7 +980,7 @@
strcpy(userpass, string);
}
-#if 0 /* DEBUG */
+#if 1 /* DEBUG */
printf("auth_type=%d, string=%s, namepair=%s, password_pair=%s\n",
auth_type, string, name,
password_pair ? password_pair->strvalue : "");
@@ -1049,6 +1068,14 @@
CHAP_VALUE_LENGTH) != 0)
result = -1;
break;
+#if USE_SQL
+ case PW_AUTHTYPE_SQL:
+ printf("Entering Auth For SQL");
+ if(psql_pass(name, string) != 0) {
+ result = -1;
+ }
+ break;
+#endif /* USEUSE_SQL */
default:
result = -1;
break;
diff -ur -N radiusd-cistron-1.5.4.3/src/radiusd.h radiusd-sql/src/radiusd.h
--- radiusd-cistron-1.5.4.3/src/radiusd.h Wed Jun 24 00:41:10 1998
+++ radiusd-sql/src/radiusd.h Sun Aug 9 18:28:10 1998
@@ -33,7 +33,9 @@
#include "sysdep.h"
#include "radius.h"
#include "conf.h"
-
+#if USE_SQL
+#include "/usr/local/pgsql/include/libpq-fe.h"
+#endif
/* Server data structures */
typedef struct dict_attr {
@@ -121,7 +123,9 @@
extern int radius_pid;
extern int use_dbm;
extern int log_stripped_names;
-
+#if USE_SQL
+extern PGconn *PSQLconn;
+#endif
/*
* Function prototypes.
*/
@@ -197,3 +201,8 @@
int pam_pass(char *name, char *passwd);
#endif
+#ifdef USE_SQL
+/* pgsql.c */
+void exit_nicely(PGconn *conn);
+int psql_pass(char *user, char *pass);
+#endif