sqltrace = no
}
+ radutmp {
+ filename = ${logdir}/radutmp
+ perm = 0600
+ callerid = "yes"
+ }
+
+ # "Safe" radutmp - does not contain caller ID, so it can be
+ # world-readable, and radwho can work for normal users, without
+ # exposing any information that isn't already exposed by who(1).
+ #
+ # This is another instance of the radutmp module, but it is given
+ # then name "sradutmp" to identify it later in the "accounting"
+ # section.
+ radutmp sradutmp {
+ filename = ${logdir}/sradutmp
+ perm = 0644
+ callerid = "no"
+ }
+
#
# The "always" module is here for debugging purposes. Each instance simply
# returns the same result, always, without doing anything.
preprocess
}
-# Accounting. Log to detail file, and to the radwtmp file.
+# Accounting. Log to detail file, and to the radwtmp file, and maintain
+# radutmp.
accounting {
#acct_unique
detail
unix
+ radutmp
+ #sradutmp
}
# Session database, used for checking Simultaneous-Use. The radutmp module
# handles this
session {
- #radutmp
+ radutmp
}
#define RADIUS_REALMS "realms"
#define RADUTMP LOGDIR "/radutmp"
+#define SRADUTMP LOGDIR "/sradutmp"
#define RADWTMP LOGDIR "/radwtmp"
+#define SRADWTMP LOGDIR "/sradwtmp"
#define CHECKRAD SBINDIR "/checkrad"
extern int log_auth_detail;
extern int auth_port;
extern int acct_port;
+extern int acctfd;
extern int proxy_port;
extern int proxyfd;
extern int proxy_retry_count;
extern int proxy_retry_delay;
+extern int spawn_flag;
/* Define a global config structure */
extern struct main_config_t mainconfig;
/* acct.c */
int rad_accounting(REQUEST *);
-/* radutmp.c */
-int radutmp_add(REQUEST *);
-int radutmp_zap(uint32_t nas, int port, char *user, time_t t);
-int radutmp_checksimul(char *name, VALUE_PAIR *, int maxsimul);
-
/* session.c */
int rad_check_ts(uint32_t nasaddr, int port, const char *user,
const char *sessionid);
void debug_pair(FILE *, VALUE_PAIR *);
int log_err (char *);
void sig_cleanup(int);
+int rad_process(REQUEST *, int);
int rad_respond(REQUEST *, RAD_REQUEST_FUNP fun);
/* util.c */
* Take the size of the structure from the actual structure definition.
*/
#define RUT_NAMESIZE sizeof(((struct radutmp *) NULL)->login)
+#define RUT_SESSSIZE sizeof(((struct radutmp *) NULL)->session_id)
#endif /* _RADUTMP_H */
SERVER_OBJS = radiusd.o files.o util.o acct.o nas.o log.o valuepair.o \
version.o proxy.o exec.o auth.o timestr.o conffile.o \
- modules.o modcall.o radutmp.o xlat.o threads.o smux.o \
+ modules.o modcall.o session.o xlat.o threads.o smux.o \
radius_snmp.o client.o request_list.o
INCLUDES = ../include/radiusd.h ../include/conf.h ../include/autoconf.h
modcall.o: modcall.c $(INCLUDES)
$(CC) $(CFLAGS) $(INCLTDL) -c modcall.c
-radutmp.o: radutmp.c $(INCLUDES)
- $(CC) $(CFLAGS) -c radutmp.c
-
session.o: session.c $(INCLUDES) ../include/modules.h
$(CC) $(CFLAGS) -c session.c
radzap.o: radzap.c $(INCLUDES)
$(CC) $(CFLAGS) -c radzap.c
-radzap: radzap.o util.o nas.o radutmp.o log.o client.o
- $(CC) $(CFLAGS) $(LDFLAGS) -o radzap radzap.o util.o nas.o radutmp.o log.o client.o $(LIBS)
+radzap: radzap.o util.o nas.o log.o client.o
+ $(CC) $(CFLAGS) $(LDFLAGS) -o radzap radzap.o util.o nas.o log.o client.o $(LIBS)
clean:
rm -rf *.o *.so *~ modules_static.h radiusd radwho raduse \
reply = RLM_MODULE_OK;
if (!request->proxy) {
/*
- * Keep the radutmp file in sync.
- */
- radutmp_add(request);
-
- /*
* Do accounting and if OK, reply.
*/
reply = module_accounting(request);
* for the Simultaneous-Use parameter.
*/
if (namepair &&
- (r = radutmp_checksimul((char *)namepair->strvalue,
- request->packet->vps, check_item->lvalue)) != 0) {
+ (r = module_checksimul(request, check_item->lvalue)) != 0) {
if (check_item->lvalue > 1) {
sprintf(umsg,
static int got_child = FALSE;
static int authfd;
-static int acctfd;
+int acctfd;
int proxyfd;
static pid_t radius_pid;
static int request_num_counter = 0; /* per-request unique ID */
static const char *uid_name = NULL;
static const char *gid_name = NULL;
static int proxy_requests = TRUE;
-static int spawn_flag = TRUE;
+int spawn_flag = TRUE;
static struct rlimit core_limits;
static void usage(void);
static void sig_hup (int);
static void rad_reject(REQUEST *request);
-static int rad_process (REQUEST *, int);
static struct timeval *rad_clean_list(time_t curtime);
static REQUEST *rad_check_list(REQUEST *);
static REQUEST *proxy_check_list(REQUEST *request);
* Note that we do this CPU-intensive work in
* a child thread, not the master. This helps to
* spread the load a little bit.
+ *
+ * Internal requests (ones that never go on the
+ * wire) have ->data==NULL (data is the wire
+ * format) and don't need to be "decoded"
*/
- if (rad_decode(packet, original, secret) != 0) {
+ if (packet->data && rad_decode(packet, original, secret) != 0) {
radlog(L_ERR, "%s", librad_errstr);
rad_reject(request);
goto finished_request;
+++ /dev/null
-/*
- * radutmp.c Radius session management.
- *
- * Version: $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Copyright 2000 The FreeRADIUS server project
- * Copyright 2000 Alan DeKok <aland@ox.org>
- */
-
-static const char rcsid[] =
-"$Id$";
-
-#include "autoconf.h"
-#include "libradius.h"
-
-#include <sys/file.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <signal.h>
-
-#if HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
-#endif
-
-#include "radiusd.h"
-#include "radutmp.h"
-
-static const char porttypes[] = "ASITX";
-
-#define LOCK_LEN sizeof(struct radutmp)
-
-/*
- * used for caching radutmp lookups.
- */
-typedef struct nas_port {
- uint32_t nasaddr;
- int port;
- off_t offset;
- struct nas_port *next;
-} NAS_PORT;
-static NAS_PORT *nas_port_list = NULL;
-
-/*
- * Internal wrapper for locking, to minimize the number of ifdef's
- * in the source.
- *
- * Lock the utmp file, prefer lockf() over flock()
- */
-static void radutmp_lock(int fd)
-{
-#if defined(F_LOCK) && !defined(BSD)
- (void)lockf(fd, F_LOCK, LOCK_LEN);
-#else
- (void)flock(fd, LOCK_EX);
-#endif
-}
-
-/*
- * Internal wrapper for unlocking, to minimize the number of ifdef's
- * in the source.
- *
- * Unlock the utmp file, prefer lockf() over flock()
- */
-static void radutmp_unlock(int fd)
-{
-#if defined(F_LOCK) && !defined(BSD)
- (void)lockf(fd, F_ULOCK, LOCK_LEN);
-#else
- (void)flock(fd, LOCK_UN);
-#endif
-}
-
-/*
- * Lookup a NAS_PORT in the nas_port_list
- */
-static NAS_PORT *nas_port_find(uint32_t nasaddr, int port)
-{
- NAS_PORT *cl;
-
- for(cl = nas_port_list; cl; cl = cl->next)
- if (nasaddr == cl->nasaddr &&
- port == cl->port)
- break;
- return cl;
-}
-
-
-/*
- * Zap a user, or all users on a NAS, from the radutmp file.
- */
-int radutmp_zap(uint32_t nasaddr, int port, char *user, time_t t)
-{
- struct radutmp u;
- FILE *fp;
- int fd;
-
- if (t == 0) time(&t);
- fp = fopen(RADWTMP, "a");
-
- if ((fd = open(RADUTMP, O_RDWR|O_CREAT, 0644)) >= 0) {
- int r;
-
- radutmp_lock(fd);
-
- /*
- * Find the entry for this NAS / portno combination.
- */
- r = 0;
- while (read(fd, &u, sizeof(u)) == sizeof(u)) {
- if (((nasaddr != 0 && nasaddr != u.nas_address) ||
- (port >= 0 && port != u.nas_port) ||
- (user != NULL &&
- strncmp(u.login, user, sizeof(u.login)) != 0) ||
- u.type != P_LOGIN))
- continue;
- /*
- * Match. Zap it.
- */
- if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
- radlog(L_ERR, "Accounting: radutmp_zap: "
- "negative lseek!\n");
- lseek(fd, (off_t)0, SEEK_SET);
- }
- u.type = P_IDLE;
- u.time = t;
- write(fd, &u, sizeof(u));
-
-#if 0 /* FIXME: should we fixup radwtmp as well or not ? */
- /*
- * Add a logout entry to the wtmp file.
- */
- if (fp != NULL) {
- make_wtmp(&u, &wt, PW_STATUS_STOP);
- fwrite(&wt, sizeof(wt), 1, fp);
- }
-#endif
- }
- close(fd);
- }
- if (fp) fclose(fp);
-
- return 0;
-}
-
-
-/*
- * Store logins in the RADIUS utmp file.
- */
-int radutmp_add(REQUEST *request)
-{
- struct radutmp ut, u;
- VALUE_PAIR *vp;
- int rb_record = 0;
- int status = -1;
- int nas_address = 0;
- int framed_address = 0;
- int protocol = -1;
- time_t t;
- int fd;
- int ret = 0;
- int just_an_update = 0;
- int port_seen = 0;
- int nas_port_type = 0;
- int off;
-
- /*
- * Which type is this.
- */
- if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) {
- radlog(L_ERR, "Accounting: no Accounting-Status-Type record.");
- return -1;
- }
- status = vp->lvalue;
- if (status == PW_STATUS_ACCOUNTING_ON ||
- status == PW_STATUS_ACCOUNTING_OFF) rb_record = 1;
-
- if (!rb_record &&
- (vp = pairfind(request->packet->vps, PW_USER_NAME)) == NULL) do {
- int check1 = 0;
- int check2 = 0;
-
- /*
- * ComOS (up to and including 3.5.1b20) does not send
- * standard PW_STATUS_ACCOUNTING_XXX messages.
- *
- * Check for: o no Acct-Session-Time, or time of 0
- * o Acct-Session-Id of "00000000".
- *
- * We could also check for NAS-Port, that attribute
- * should NOT be present (but we don't right now).
- */
- if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME))
- == NULL || vp->lvalue == 0)
- check1 = 1;
- if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID))
- != NULL && vp->length == 8 &&
- memcmp(vp->strvalue, "00000000", 8) == 0)
- check2 = 1;
- if (check1 == 0 || check2 == 0) {
-#if 0 /* Cisco sometimes sends START records without username. */
- radlog(L_ERR, "Accounting: no username in record");
- return -1;
-#else
- break;
-#endif
- }
- radlog(L_INFO, "Accounting: converting reboot records.");
- if (status == PW_STATUS_STOP)
- status = PW_STATUS_ACCOUNTING_OFF;
- if (status == PW_STATUS_START)
- status = PW_STATUS_ACCOUNTING_ON;
- rb_record = 1;
- } while(0);
-
- time(&t);
- memset(&ut, 0, sizeof(ut));
- ut.porttype = 'A';
-
- /*
- * First, find the interesting attributes.
- */
- for (vp = request->packet->vps; vp; vp = vp->next) {
- switch (vp->attribute) {
- case PW_USER_NAME:
- strncpy(ut.login, (char *)vp->strvalue,
- RUT_NAMESIZE);
- break;
- case PW_LOGIN_IP_HOST:
- case PW_FRAMED_IP_ADDRESS:
- framed_address = vp->lvalue;
- ut.framed_address = vp->lvalue;
- break;
- case PW_FRAMED_PROTOCOL:
- protocol = vp->lvalue;
- break;
- case PW_NAS_IP_ADDRESS:
- nas_address = vp->lvalue;
- ut.nas_address = vp->lvalue;
- break;
- case PW_NAS_PORT_ID:
- ut.nas_port = vp->lvalue;
- port_seen = 1;
- break;
- case PW_ACCT_DELAY_TIME:
- ut.delay = vp->lvalue;
- break;
- case PW_ACCT_SESSION_ID:
- /*
- * If length > 8, only store the
- * last 8 bytes.
- */
- off = vp->length - sizeof(ut.session_id);
- if (off < 0) off = 0;
- memcpy(ut.session_id, vp->strvalue + off,
- sizeof(ut.session_id));
- break;
- case PW_NAS_PORT_TYPE:
- if (vp->lvalue >= 0 && vp->lvalue <= 4)
- ut.porttype = porttypes[vp->lvalue];
- nas_port_type = vp->lvalue;
- break;
- case PW_CALLING_STATION_ID:
- strncpy(ut.caller_id, (char *)vp->strvalue,
- sizeof(ut.caller_id));
- ut.caller_id[sizeof(ut.caller_id) - 1] = 0;
- break;
- }
- }
-
- /*
- * If we didn't find out the NAS address, use the
- * originator's IP address.
- */
- if (nas_address == 0) {
- nas_address = request->packet->src_ipaddr;
- ut.nas_address = nas_address;
- }
-
- if (protocol == PW_PPP)
- ut.proto = 'P';
- else if (protocol == PW_SLIP)
- ut.proto = 'S';
- else
- ut.proto = 'T';
- ut.time = t - ut.delay;
-
- /*
- * See if this was a portmaster reboot.
- */
- if (status == PW_STATUS_ACCOUNTING_ON && nas_address) {
- radlog(L_INFO, "NAS %s restarted (Accounting-On packet seen)",
- nas_name(nas_address));
- radutmp_zap(nas_address, -1, NULL, ut.time);
- return 0;
- }
- if (status == PW_STATUS_ACCOUNTING_OFF && nas_address) {
- radlog(L_INFO, "NAS %s rebooted (Accounting-Off packet seen)",
- nas_name(nas_address));
- radutmp_zap(nas_address, -1, NULL, ut.time);
- return 0;
- }
-
- /*
- * If we don't know this type of entry pretend we succeeded.
- */
- if (status != PW_STATUS_START &&
- status != PW_STATUS_STOP &&
- status != PW_STATUS_ALIVE) {
- radlog(L_ERR, "NAS %s port %d unknown packet type %d)",
- nas_name(nas_address), ut.nas_port, status);
- return 0;
- }
-
- /*
- * Perhaps we don't want to store this record into
- * radutmp. We skip records:
- *
- * - without a NAS-Port-Id (telnet / tcp access)
- * - with the username "!root" (console admin login)
- */
- if (!port_seen || strncmp(ut.login, "!root", RUT_NAMESIZE) == 0)
- return 0;
-
- /*
- * Enter into the radutmp file.
- */
- if ((fd = open(RADUTMP, O_RDWR|O_CREAT, 0644)) >= 0) {
- NAS_PORT *cache;
- int r;
-
- radutmp_lock(fd);
-
- /*
- * Find the entry for this NAS / portno combination.
- */
- if ((cache = nas_port_find(ut.nas_address, ut.nas_port)) != NULL)
- lseek(fd, (off_t)cache->offset, SEEK_SET);
-
- r = 0;
- off = 0;
- while (read(fd, &u, sizeof(u)) == sizeof(u)) {
- off += sizeof(u);
- if (u.nas_address != ut.nas_address ||
- u.nas_port != ut.nas_port)
- continue;
-
- if (status == PW_STATUS_STOP &&
- strncmp(ut.session_id, u.session_id,
- sizeof(u.session_id)) != 0) {
- /*
- * Don't complain if this is not a
- * login record (some clients can
- * send _only_ logout records).
- */
- if (u.type == P_LOGIN)
- radlog(L_ERR,
- "Accounting: logout: entry for NAS %s port %d has wrong ID",
- nas_name(nas_address), u.nas_port);
- r = -1;
- break;
- }
-
- if (status == PW_STATUS_START &&
- strncmp(ut.session_id, u.session_id,
- sizeof(u.session_id)) == 0 &&
- u.time >= ut.time) {
- if (u.type == P_LOGIN) {
- radlog(L_INFO,
- "Accounting: login: entry for NAS %s port %d duplicate",
- nas_name(nas_address), u.nas_port);
- r = -1;
- break;
- }
- radlog(L_ERR,
- "Accounting: login: entry for NAS %s port %d wrong order",
- nas_name(nas_address), u.nas_port);
- r = -1;
- break;
- }
-
- /*
- * FIXME: the ALIVE record could need
- * some more checking, but anyway I'd
- * rather rewrite this mess -- miquels.
- */
- if (status == PW_STATUS_ALIVE &&
- strncmp(ut.session_id, u.session_id,
- sizeof(u.session_id)) == 0 &&
- u.type == P_LOGIN) {
- /*
- * Keep the original login time.
- */
- ut.time = u.time;
- if (u.login[0] != 0)
- just_an_update = 1;
- }
-
- if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
- radlog(L_ERR, "Accounting: negative lseek!\n");
- lseek(fd, (off_t)0, SEEK_SET);
- off = 0;
- } else
- off -= sizeof(u);
- r = 1;
- break;
- }
-
- if (r >= 0 && (status == PW_STATUS_START ||
- status == PW_STATUS_ALIVE)) {
- if (cache == NULL) {
- cache = rad_malloc(sizeof(NAS_PORT));
- cache->nasaddr = ut.nas_address;
- cache->port = ut.nas_port;
- cache->offset = off;
- cache->next = nas_port_list;
- nas_port_list = cache;
- }
- ut.type = P_LOGIN;
- write(fd, &ut, sizeof(u));
- }
- if (status == PW_STATUS_STOP) {
- if (r > 0) {
- u.type = P_IDLE;
- u.time = ut.time;
- u.delay = ut.delay;
- write(fd, &u, sizeof(u));
- } else if (r == 0) {
- radlog(L_ERR,
- "Accounting: logout: login entry for NAS %s port %d not found",
- nas_name(nas_address), ut.nas_port);
- r = -1;
- }
- }
- close(fd);
- } else {
- radlog(L_ERR, "Accounting: %s: %s", RADUTMP, strerror(errno));
- ret = -1;
- }
-
- return ret;
-}
-
-
-/*
- * Timeout handler (10 secs)
- */
-static int got_alrm;
-static void alrm_handler(int sig)
-{
- sig = sig; /* -Wunused */
- got_alrm = 1;
-}
-
-/*
- * Check one terminal server to see if a user is logged in.
- */
-int rad_check_ts(uint32_t nasaddr, int portnum, const char *user,
- const char *session_id)
-{
- int pid, st, e;
- int n;
- NAS *nas;
- char address[16];
- char port[8];
- void (*handler)(int);
-
- /*
- * Find NAS type.
- */
- if ((nas = nas_find(nasaddr)) == NULL) {
- radlog(L_ERR, "Accounting: unknown NAS");
- return -1;
- }
-
- /*
- * Fork.
- */
- handler = signal(SIGCHLD, SIG_DFL);
- if ((pid = fork()) < 0) {
- radlog(L_ERR, "Accounting: fork: %s", strerror(errno));
- signal(SIGCHLD, handler);
- return -1;
- }
-
- if (pid > 0) {
- /*
- * Parent - Wait for checkrad to terminate.
- * We timeout in 10 seconds.
- */
- got_alrm = 0;
- signal(SIGALRM, alrm_handler);
- alarm(10);
- while((e = waitpid(pid, &st, 0)) != pid)
- if (e < 0 && (errno != EINTR || got_alrm))
- break;
- alarm(0);
- signal(SIGCHLD, handler);
- if (got_alrm) {
- kill(pid, SIGTERM);
- sleep(1);
- kill(pid, SIGKILL);
- radlog(L_ERR, "Check-TS: timeout waiting for checkrad");
- return 2;
- }
- if (e < 0) {
- radlog(L_ERR, "Check-TS: unknown error in waitpid()");
- return 2;
- }
- return WEXITSTATUS(st);
- }
-
- /*
- * Child - exec checklogin with the right parameters.
- */
- for (n = 32; n >= 3; n--)
- close(n);
-
- ip_ntoa(address, nasaddr);
- sprintf(port, "%d", portnum);
-
-#ifdef __EMX__
- /* OS/2 can't directly execute scripts then we call the command
- processor to execute checkrad
- */
- execl(getenv("COMSPEC"), "", "/C","checkrad",nas->nastype, address, port,
- user, session_id, NULL);
-#else
- execl(CHECKRAD, "checkrad",nas->nastype, address, port,
- user, session_id, NULL);
-#endif
- radlog(L_ERR, "Check-TS: exec %s: %s", CHECKRAD, strerror(errno));
-
- /*
- * Exit - 2 means "some error occured".
- */
- exit(2);
-}
-
-/*
- * See if a user is already logged in.
- *
- * Check twice. If on the first pass the user exceeds his
- * max. number of logins, do a second pass and validate all
- * logins by querying the terminal server (using eg. SNMP).
- *
- * Returns: 0 == OK, 1 == double logins, 2 == multilink attempt
- */
-int radutmp_checksimul(char *name, VALUE_PAIR *request, int maxsimul)
-{
- VALUE_PAIR *fra;
- struct radutmp u;
- uint32_t ipno = 0;
- int fd;
- int count;
- int mpp = 1;
- int rcode;
-
- if ((fd = open(RADUTMP, O_CREAT|O_RDWR, 0644)) < 0)
- return 0;
-
- /*
- * We don't lock in the first pass.
- */
- count = 0;
- while(read(fd, &u, sizeof(u)) == sizeof(u))
- if (strncmp(name, u.login, RUT_NAMESIZE) == 0
- && u.type == P_LOGIN)
- count++;
-
- if (count < maxsimul) {
- close(fd);
- return 0;
- }
- lseek(fd, (off_t)0, SEEK_SET);
-
- /*
- * Setup some stuff, like for MPP detection.
- */
- if ((fra = pairfind(request, PW_FRAMED_IP_ADDRESS)) != NULL)
- ipno = fra->lvalue;
-
- radutmp_lock(fd);
-
- /*
- * Allright, there are too many concurrent logins.
- * Check all registered logins by querying the
- * terminal server directly.
- * FIXME: rad_check_ts() runs with locked radutmp file!
- */
- count = 0;
- while (read(fd, &u, sizeof(u)) == sizeof(u)) {
- if (strncmp(name, u.login, RUT_NAMESIZE) == 0
- && u.type == P_LOGIN) {
- char session_id[sizeof u.session_id+1];
- strNcpy(session_id, u.session_id, sizeof session_id);
-
- /*
- * rad_check_ts may take seconds to return,
- * and we don't want to block everyone else
- * while that's happening.
- */
- radutmp_unlock(fd);
- rcode = rad_check_ts(u.nas_address, u.nas_port,
- u.login, session_id);
- radutmp_lock(fd);
-
- if (rcode == 1) {
- count++;
- /*
- * Does it look like a MPP attempt?
- */
- if (strchr("SCPA", u.proto) &&
- ipno && u.framed_address == ipno)
- mpp = 2;
- }
- else {
- /*
- * False record - zap it.
- */
-
- lseek(fd, -(off_t)sizeof(u), SEEK_CUR);
- u.type = P_IDLE;
- write(fd, &u, sizeof(u));
-
-#if 0 /* FIXME: should we fixup radwtmp as well or not ? */
- if ((wfp = fopen(RADWTMP, "a")) != NULL) {
- make_wtmp(&u, &wt, PW_STATUS_STOP);
- fwrite(&wt, sizeof(wt), 1, wfp);
- fclose(wfp);
- }
-#endif
- }
- }
- }
- close(fd);
-
- return (count < maxsimul) ? 0 : mpp;
-}
-
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <fcntl.h>
+#include <netdb.h>
+#include <limits.h>
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
#if HAVE_MALLOC_H
# include <malloc.h>
#endif
#include "radiusd.h"
+#include "radutmp.h"
+/* FIXME: Some of the following are unused and just there to make the linker
+ * happy. Also all of log.o is linked in mainly to make the linker happy. */
int debug_flag = 0;
-const char *progname = "radzap";
+const char *progname;
const char *radlog_dir = NULL;
+const char *radius_dir = NULL;
+#if 0
+int auth_port; /* Not really used */
+#endif
+int acct_port = 0;
+
+#define LOCK_LEN sizeof(struct radutmp)
+
+/*
+ * Internal wrapper for locking, to minimize the number of ifdef's
+ * in the source. Copied from rlm_radutmp.c (was src/main/radutmp.c),
+ * perhaps these wrappers should be #defined in radutmp.h
+ *
+ * Lock the utmp file, prefer lockf() over flock()
+ */
+static void radutmp_lock(int fd)
+{
+#if defined(F_LOCK) && !defined(BSD)
+ (void)lockf(fd, F_LOCK, LOCK_LEN);
+#else
+ (void)flock(fd, LOCK_EX);
+#endif
+}
+
+/*
+ * Internal wrapper for unlocking, to minimize the number of ifdef's
+ * in the source.
+ *
+ * Unlock the utmp file, prefer lockf() over flock()
+ */
+static void radutmp_unlock(int fd)
+{
+#if defined(F_LOCK) && !defined(BSD)
+ (void)lockf(fd, F_ULOCK, LOCK_LEN);
+#else
+ (void)flock(fd, LOCK_UN);
+#endif
+}
+
+static int radutmp_lookup(struct radutmp *u, uint32_t nasaddr, int port,
+ const char *user)
+{
+ int fd;
+
+ if ((fd = open(RADUTMP, O_RDONLY|O_CREAT, 0644)) >= 0) {
+ /*
+ * Lock the utmp file, prefer lockf() over flock().
+ */
+ radutmp_lock(fd);
+
+ /*
+ * Find the entry for this NAS / portno combination.
+ */
+ while (read(fd, u, sizeof(*u)) == sizeof(*u)) {
+ if ((nasaddr != 0 && nasaddr != u->nas_address) ||
+ (port >= 0 && port != u->nas_port) ||
+ (user != NULL &&
+ strncmp(u->login, user, sizeof u->login) != 0) ||
+ u->type != P_LOGIN)
+ continue;
+ /*
+ * Match. Zap it.
+ */
+ close(fd);
+ return 1;
+ }
+ close(fd);
+ }
+ return 0;
+}
+static int do_accton_packet(uint32_t nasaddr);
+static int do_stop_packet(const struct radutmp *u);
/*
* Zap a user from the radutmp and radwtmp file.
int nas_port = -1;
char *user = NULL;
char *s;
- time_t t;
char buf[256];
+ struct radutmp u;
- if (argc < 2 || argc > 4 || (argc > 1 && argv[1][0] == '-')) {
+ progname = argv[0];
+ --argc, ++argv;
+ if (argc > 1 && !strcmp(argv[0], "-p")) {
+ acct_port = atoi(argv[1]);
+ argc -= 2, argv+=2;
+ }
+ if (argc < 1 || argc > 3 || argv[1][0] == '-') {
fprintf(stderr, "Usage: radzap termserver [port] [user]\n");
fprintf(stderr, " radzap is only an admin tool to clean the radutmp file!\n");
exit(1);
}
- if (argc > 2) {
- s = argv[2];
+ if (argc > 1) {
+ s = argv[1];
if (*s == 's' || *s == 'S') s++;
nas_port = atoi(s);
}
- if (argc > 3) user = argv[3];
+ if (argc > 2) user = argv[2];
+
+ radius_dir = strdup(RADIUS_DIR);
/*
* Read the "naslist" file.
/*
* Find the IP address of the terminal server.
*/
- if ((nas = nas_findbyname(argv[1])) == NULL && argv[1][0] != 0) {
- if ((ip = ip_getaddr(argv[1])) == INADDR_NONE) {
- fprintf(stderr, "%s: host not found.\n", argv[1]);
+ if ((nas = nas_findbyname(argv[0])) == NULL && argv[0][0] != 0) {
+ if ((ip = ip_getaddr(argv[0])) == INADDR_NONE) {
+ fprintf(stderr, "%s: host not found.\n", argv[0]);
exit(1);
}
}
if (user) printf(", user %s", user);
printf("\n");
- t = time(NULL);
- radutmp_zap(ip, nas_port, user, t);
+ if(nas_port < 0) {
+ return do_accton_packet(ip);
+ }
+
+ if(!radutmp_lookup(&u, ip, nas_port, user)) {
+ fprintf(stderr, "Entry not found\n");
+ return 1;
+ }
+
+ return do_stop_packet(&u);
+}
+
+static int getport(const char *name)
+{
+ struct servent *svp;
+
+ svp = getservbyname (name, "udp");
+ if (!svp) {
+ return 0;
+ }
+
+ return ntohs(svp->s_port);
+}
+
+static const char *getlocalhostsecret(void)
+{
+ RADCLIENT *cl;
+ char fn[PATH_MAX];
+ snprintf(fn, sizeof fn, "%s/%s", radius_dir, RADIUS_CLIENTS);
+ if(read_clients_file(fn)<0) {
+ radlog(L_ERR|L_CONS, "Errors reading clients");
+ exit(1);
+ }
+ cl=client_find(htonl(INADDR_LOOPBACK));
+ if(!cl) {
+ radlog(L_ERR|L_CONS, "No clients entry for localhost");
+ exit(1);
+ }
+ return (const char *)cl->secret;
+}
+
+/* Packet-fabrication macros. Don't stare directly at them without protective
+ * eye gear */
+#define PAIR(n,v,t,e) do { \
+ if(!(vp=paircreate(n, t))) { \
+ radlog(L_ERR|L_CONS, "no memory"); \
+ pairfree(&req->vps); \
+ return 1; \
+ } \
+ vp->e=v; \
+ pairadd(&req->vps, vp); \
+} while(0)
+#define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,lvalue)
+#define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,lvalue)
+#define STRINGPAIR(n,v) do { \
+ if(!(vp=paircreate(n, PW_TYPE_STRING))) { \
+ radlog(L_ERR|L_CONS, "no memory"); \
+ pairfree(&req->vps); \
+ return 1; \
+ } \
+ strNcpy((char *)vp->strvalue, v, sizeof vp->strvalue); \
+ vp->length=strlen(v); \
+ pairadd(&req->vps, vp); \
+} while(0)
+
+static int do_packet(int allports, uint32_t nasaddr, const struct radutmp *u)
+{
+ int i, retries=5, timeout=3;
+ struct timeval tv;
+ RADIUS_PACKET *req, *rep;
+ VALUE_PAIR *vp;
+ const char *secret=getlocalhostsecret();
+
+ if ((req = rad_alloc(1)) == NULL) {
+ librad_perror("radzap");
+ exit(1);
+ }
+ req->id = getpid() & 0xFF;
+ req->code = PW_ACCOUNTING_REQUEST;
+ req->dst_port = acct_port;
+ if(req->dst_port == 0) req->dst_port = getport("radacct");
+ if(req->dst_port == 0) req->dst_port = PW_ACCT_UDP_PORT;
+ req->dst_ipaddr = ip_getaddr("localhost");
+ if(!req->dst_ipaddr) req->dst_ipaddr = 0x7f000001;
+ req->vps = NULL;
+
+ if(allports) {
+ INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_ACCOUNTING_OFF);
+ IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
+ INTPAIR(PW_ACCT_DELAY_TIME, 0);
+ } else {
+ char login[sizeof u->login+1];
+ char session_id[sizeof u->session_id+1];
+ strNcpy(login, u->login, sizeof login);
+ strNcpy(session_id, u->session_id, sizeof session_id);
+ INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
+ IPPAIR(PW_NAS_IP_ADDRESS, u->nas_address);
+ INTPAIR(PW_ACCT_DELAY_TIME, 0);
+ STRINGPAIR(PW_USER_NAME, login);
+ INTPAIR(PW_NAS_PORT_ID, u->nas_port);
+ STRINGPAIR(PW_ACCT_SESSION_ID, session_id);
+ if(u->proto=='P') {
+ INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
+ INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
+ } else if(u->proto=='S') {
+ INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
+ INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
+ } else {
+ INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
+ }
+ IPPAIR(PW_FRAMED_IP_ADDRESS, u->framed_address);
+ INTPAIR(PW_ACCT_SESSION_TIME, 0);
+ INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
+ INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
+ INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
+ INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
+ }
+ if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("radzap: socket: ");
+ exit(1);
+ }
+
+ for (i = 0; i < retries; i++) {
+ fd_set rdfdesc;
+
+ rad_send(req, secret);
+
+ /* And wait for reply, timing out as necessary */
+ FD_ZERO(&rdfdesc);
+ FD_SET(req->sockfd, &rdfdesc);
+ tv.tv_sec = (int)timeout;
+ tv.tv_usec = 1000000 * (timeout - (int)timeout);
+
+ /* Something's wrong if we don't get exactly one fd. */
+ if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) {
+ continue;
+ }
+
+ rep = rad_recv(req->sockfd);
+ if (rep != NULL) {
+ break;
+ } else { /* NULL: couldn't receive the packet */
+ librad_perror("radzap:");
+ exit(1);
+ }
+ }
+
+ /* No response or no data read (?) */
+ if (i == retries) {
+ fprintf(stderr, "radzap: no response from server\n");
+ exit(1);
+ }
+
+ if (rad_decode(rep, req, secret) != 0) {
+ librad_perror("rad_decode");
+ exit(1);
+ }
+
+ vp_printlist(stdout, rep->vps);
return 0;
}
+
+static int do_accton_packet(uint32_t nasaddr)
+{
+ return do_packet(1, nasaddr, 0);
+}
+
+static int do_stop_packet(const struct radutmp *u)
+{
+ return do_packet(0, 0, u);
+}
+
+#if 0
+/* FIXME: Not called. Needed for files.o to link. Ick */
+int setup_modules(void); /* -Wmissing-prototypes */
+int setup_modules(void)
+{
+ abort();
+}
+
+/* FIXME: Not called. Needed for files.o to link. Ick */
+int read_radius_conf_file(void); /* -Wmissing-prototypes */
+int read_radius_conf_file(void)
+{
+ abort();
+}
+#endif
int session_zap(uint32_t nasaddr, int port, const char *user,
const char *sessionid, uint32_t cliaddr, char proto, time_t t)
{
- static unsigned char id=0;
+ static unsigned char id = 0;
- REQUEST stopreq;
- RADIUS_PACKET stoppkt;
+ REQUEST *stopreq;
+ RADIUS_PACKET *stoppkt;
VALUE_PAIR *vp, *userpair;
- int modret;
int ret;
- memset(&stoppkt, 0, sizeof stoppkt);
- stoppkt.data=0;
- stoppkt.sockfd=-1;
- stoppkt.code=PW_ACCOUNTING_REQUEST;
- stoppkt.id=id++;
- stoppkt.timestamp=t?t:time(0);
- stoppkt.vps=0;
+ stoppkt = rad_malloc(sizeof *stoppkt);
+ memset(stoppkt, 0, sizeof stoppkt);
+ stoppkt->data = NULL;
+ stoppkt->sockfd = acctfd;
+ stoppkt->code = PW_ACCOUNTING_REQUEST;
+ stoppkt->id = id++;
+ stoppkt->timestamp = t?t:time(0);
+ stoppkt->vps = NULL;
/* Hold your breath */
#define PAIR(n,v,t,e) do { \
- if(!(vp=paircreate(n, t))) { \
+ if(!(vp = paircreate(n, t))) { \
radlog(L_ERR|L_CONS, "no memory"); \
- pairfree(&stoppkt.vps); \
+ pairfree(&stoppkt->vps); \
return 0; \
} \
- vp->e=v; \
- pairadd(&stoppkt.vps, vp); \
+ vp->e = v; \
+ pairadd(&stoppkt->vps, vp); \
} while(0)
#define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,lvalue)
#define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,lvalue)
#define STRINGPAIR(n,v) do { \
- if(!(vp=paircreate(n, PW_TYPE_STRING))) { \
+ if(!(vp = paircreate(n, PW_TYPE_STRING))) { \
radlog(L_ERR|L_CONS, "no memory"); \
- pairfree(&stoppkt.vps); \
+ pairfree(&stoppkt->vps); \
return 0; \
} \
strNcpy((char *)vp->strvalue, v, sizeof vp->strvalue); \
- vp->length=strlen(v); \
- pairadd(&stoppkt.vps, vp); \
+ vp->length = strlen(v); \
+ pairadd(&stoppkt->vps, vp); \
} while(0)
INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
INTPAIR(PW_ACCT_DELAY_TIME, 0);
STRINGPAIR(PW_USER_NAME, user);
- userpair=vp;
+ userpair = vp;
INTPAIR(PW_NAS_PORT_ID, port);
STRINGPAIR(PW_ACCT_SESSION_ID, sessionid);
- if(proto=='P') {
+ if(proto == 'P') {
INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
- } else if(proto=='S') {
+ } else if(proto == 'S') {
INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
} else {
INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
- memset(&stopreq, 0, sizeof stopreq);
- stopreq.packet=&stoppkt;
- stopreq.proxy=0;
- stopreq.reply=0;
- stopreq.config_items=0;
- stopreq.username=userpair;
- stopreq.child_pid=-1;
- stopreq.timestamp=stoppkt.timestamp;
- stopreq.next=0;
-
- /* FIXME: Need to run preaccouting, so replication can work */
- modret = module_accounting(&stopreq);
- if(modret==RLM_MODULE_NOOP ||
- modret==RLM_MODULE_OK ||
- modret==RLM_MODULE_UPDATED ||
- modret==RLM_MODULE_HANDLED)
- ret=1;
- else
- ret=0;
-
- pairfree(&stoppkt.vps);
+ stopreq = rad_malloc(sizeof *stopreq);
+ memset(stopreq, 0, sizeof *stopreq);
+#ifndef NDEBUG
+ stopreq->magic = REQUEST_MAGIC;
+#endif
+ stopreq->packet = stoppkt;
+ stopreq->proxy = NULL;
+ stopreq->reply = NULL;
+ stopreq->proxy_reply = NULL;
+ stopreq->config_items = NULL;
+ stopreq->username = userpair;
+ stopreq->password = NULL;
+ stopreq->timestamp = stoppkt->timestamp;
+ stopreq->number = 0; /* FIXME */
+ stopreq->child_pid = NO_SUCH_CHILD_PID;
+ stopreq->container = NULL;
+ ret = rad_process(stopreq, spawn_flag);
+
return ret;
}
include config.mak
-#
-# This module is NOT built by default, as it's in a REALLY alpha
-# development stage, and doesn't integrate well with the rest of the
-# system.
-#
-#TARGET = rlm_radutmp
-#SRCS = rlm_radutmp.c
+TARGET = rlm_radutmp
+SRCS = rlm_radutmp.c
include ../rules.mak
#define LOCK_LEN sizeof(struct radutmp)
-static char porttypes[] = "ASITX";
+static const char porttypes[] = "ASITX";
+
+/*
+ * Internal wrapper for locking, to minimize the number of ifdef's
+ * in the source.
+ *
+ * Lock the utmp file, prefer lockf() over flock()
+ */
+static void radutmp_lock(int fd)
+{
+#if defined(F_LOCK) && !defined(BSD)
+ (void)lockf(fd, F_LOCK, LOCK_LEN);
+#else
+ (void)flock(fd, LOCK_EX);
+#endif
+}
+
+/*
+ * Internal wrapper for unlocking, to minimize the number of ifdef's
+ * in the source.
+ *
+ * Unlock the utmp file, prefer lockf() over flock()
+ */
+static void radutmp_unlock(int fd)
+{
+#if defined(F_LOCK) && !defined(BSD)
+ (void)lockf(fd, F_ULOCK, LOCK_LEN);
+#else
+ (void)flock(fd, LOCK_UN);
+#endif
+}
/*
* used for caching radutmp lookups in the accounting component. The
* session (checksimul) component doesn't use it, but probably should.
*/
typedef struct nas_port {
- UINT4 nasaddr;
+ uint32_t nasaddr;
int port;
off_t offset;
struct nas_port *next;
} NAS_PORT;
-struct acct_instance {
+struct radutmp_instance {
NAS_PORT *nas_port_list;
- char radutmp_fn[PATH_MAX];
+ char *radutmp_fn;
int permission;
- int callerid_ok:1;
+ int callerid_ok;
};
-struct sess_instance {
- char radutmp_fn[PATH_MAX];
-};
+/*
+ * A temporary holding area for config values to be extracted
+ * into, before they are copied into the instance data
+ */
+static struct radutmp_instance config;
+static CONF_PARSER module_config[] = {
+ { "filename", PW_TYPE_STRING_PTR, &config.radutmp_fn, RADUTMP },
+ { "perm", PW_TYPE_INTEGER, &config.permission, "0644" },
+ { "callerid", PW_TYPE_BOOLEAN, &config.callerid_ok, "no" },
+ { NULL, -1, NULL, NULL } /* end the list */
+};
-/* RADDB/modules syntax for radutmp accounting:
- * accounting rlm_radutmp.so [filename] [permission] [option...]
- * filename defaults to the old location (usually /var/log/radutmp)
- * permission defaults to 644, but the umask radiusd was started with applies
- * current options are "callerid" and "nocallerid". default is nocallerid
- * unless a restrictive permission is specified.
- *
- * For session component:
- * session rlm_radutmp.so [filename] */
-static int radutmp_instantiate(int component, int argc, char **argv,
- void **instance)
+static int radutmp_instantiate(CONF_SECTION *conf, void **instance)
{
- switch(component) {
- case RLM_COMPONENT_ACCT:
- {
- const char *fn=RADUTMP;
- unsigned int perm=0644;
- int callerid=-1;
-
- if(argc) {
- fn=argv[0];
- --argc,++argv;
- }
- if(argc) {
- if(sscanf(argv[0], "%o", &perm)!=1) {
- log(L_ERR, "Invalid permission %s",
- argv[0]);
- }
- --argc,++argv;
- }
- while(argc) {
- if(!strcmp(argv[0], "callerid")) {
- callerid=1;
- } else if(!strcmp(argv[0], "nocallerid")) {
- callerid=0;
- } else {
- log(L_ERR, "Unknown option %s",
- argv[0]);
- return -1;
- }
- --argc,++argv;
- }
-
- if(callerid==-1)
- callerid = !(perm & 004);
-
- *instance = malloc(sizeof(struct acct_instance));
- if (!*instance) {
- log(L_ERR|L_CONS, "Out of memory\n");
- return -1;
- }
-#define ru_instance ((struct acct_instance *)(*instance))
- ru_instance->nas_port_list=0;
- if(*fn=='/')
- strNcpy(ru_instance->radutmp_fn, fn, PATH_MAX);
- else
- snprintf(ru_instance->radutmp_fn, PATH_MAX,
- "%s/%s", LOGDIR, fn);
- ru_instance->permission=perm;
- ru_instance->callerid_ok=callerid;
-#undef ru_instance
- }
- break;
- case RLM_COMPONENT_SESS:
- {
- const char *fn=RADUTMP;
-
- if(argc) {
- fn=argv[0];
- --argc,++argv;
- }
- if(argc) {
- log(L_ERR,
- "Too many args in radutmp session config\n");
- return -1;
- }
-
- *instance = malloc(sizeof(struct sess_instance));
- if (!*instance) {
- log(L_ERR|L_CONS, "Out of memory\n");
- return -1;
- }
-#define ru_instance ((struct sess_instance *)(*instance))
- if(*fn=='/')
- strNcpy(ru_instance->radutmp_fn, fn, PATH_MAX);
- else
- snprintf(ru_instance->radutmp_fn, PATH_MAX,
- "%s/%s", LOGDIR, fn);
-#undef ru_instance
- }
- break;
- default:
- *instance=0;
- break;
+ *instance = rad_malloc(sizeof(struct radutmp_instance));
+ if (cf_section_parse(conf, module_config)) {
+ free(*instance);
+ return -1;
}
+#define ru_instance ((struct radutmp_instance *)(*instance))
+ ru_instance->nas_port_list = NULL;
+ ru_instance->radutmp_fn = config.radutmp_fn;
+ ru_instance->permission = config.permission;
+ ru_instance->callerid_ok = config.callerid_ok;
+ config.radutmp_fn = NULL;
+#undef ru_instance
return 0;
}
/*
* Detach.
*/
-static int radutmp_detach(int component, void *instance)
+static int radutmp_detach(void *instance)
{
- switch(component) {
- case RLM_COMPONENT_ACCT:
- {
- NAS_PORT *p, *next;
- struct acct_instance *inst = instance;
-
- for(p=inst->nas_port_list ; p ; p=next) {
- next=p->next;
- free(p);
- }
- free(instance);
- }
- break;
- case RLM_COMPONENT_SESS:
- free(instance);
- break;
+ NAS_PORT *p, *next;
+ struct radutmp_instance *inst = instance;
+
+ for(p=inst->nas_port_list ; p ; p=next) {
+ next=p->next;
+ free(p);
}
+ free(inst->radutmp_fn);
+ free(inst);
return 0;
}
/*
* Zap all users on a NAS from the radutmp file.
*/
-static int radutmp_zap(struct acct_instance *inst, UINT4 nasaddr, time_t t)
+static int radutmp_zap(struct radutmp_instance *inst, uint32_t nasaddr, time_t t)
{
struct radutmp u;
int fd;
/*
* Lock the utmp file, prefer lockf() over flock().
*/
-#if defined(F_LOCK) && !defined(BSD)
- (void)lockf(fd, F_LOCK, LOCK_LEN);
-#else
- (void)flock(fd, LOCK_EX);
-#endif
+ radutmp_lock(fd);
+
/*
* Find the entry for this NAS / portno combination.
*/
* Match. Zap it.
*/
if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
- log(L_ERR, "Accounting: radutmp_zap: "
- "negative lseek!\n");
+ radlog(L_ERR, "Accounting: radutmp_zap: "
+ "negative lseek!\n");
lseek(fd, (off_t)0, SEEK_SET);
}
u.type = P_IDLE;
write(fd, &u, sizeof(u));
}
close(fd);
+ } else {
+ radlog(L_ERR, "Accounting: %s: %m", inst->radutmp_fn);
}
return 0;
/*
* Lookup a NAS_PORT in the nas_port_list
*/
-static NAS_PORT *nas_port_find(NAS_PORT *nas_port_list, UINT4 nasaddr, int port)
+static NAS_PORT *nas_port_find(NAS_PORT *nas_port_list, uint32_t nasaddr, int port)
{
NAS_PORT *cl;
VALUE_PAIR *vp;
int rb_record = 0;
int status = -1;
- int nas_address = 0;
- int framed_address = 0;
+ uint32_t nas_address = 0;
+ uint32_t framed_address = 0;
int protocol = -1;
time_t t;
int fd;
int port_seen = 0;
int nas_port_type = 0;
int off;
- struct acct_instance *inst = instance;
+ struct radutmp_instance *inst = instance;
/*
* Which type is this.
*/
if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) {
- log(L_ERR, "Accounting: no Accounting-Status-Type record.");
- return RLM_ACCT_FAIL;
+ radlog(L_ERR, "Accounting: no Accounting-Status-Type record.");
+ return RLM_MODULE_NOOP;
}
status = vp->lvalue;
if (status == PW_STATUS_ACCOUNTING_ON ||
check2 = 1;
if (check1 == 0 || check2 == 0) {
#if 0 /* Cisco sometimes sends START records without username. */
- log(L_ERR, "Accounting: no username in record");
- return RLM_ACCT_FAIL;
+ radlog(L_ERR, "Accounting: no username in record");
+ return RLM_MODULE_FAIL;
#else
break;
#endif
}
- log(L_INFO, "Accounting: converting reboot records.");
+ radlog(L_INFO, "Accounting: converting reboot records.");
if (status == PW_STATUS_STOP)
status = PW_STATUS_ACCOUNTING_OFF;
if (status == PW_STATUS_START)
break;
case PW_CALLING_STATION_ID:
if(inst->callerid_ok)
- strNcpy(ut.caller_id, vp->strvalue,
+ strNcpy(ut.caller_id,
+ (char *)vp->strvalue,
sizeof(ut.caller_id));
break;
}
* See if this was a portmaster reboot.
*/
if (status == PW_STATUS_ACCOUNTING_ON && nas_address) {
- log(L_INFO, "NAS %s restarted (Accounting-On packet seen)",
+ radlog(L_INFO, "NAS %s restarted (Accounting-On packet seen)",
nas_name(nas_address));
radutmp_zap(inst, nas_address, ut.time);
- return RLM_ACCT_OK;
+ return RLM_MODULE_OK;
}
if (status == PW_STATUS_ACCOUNTING_OFF && nas_address) {
- log(L_INFO, "NAS %s rebooted (Accounting-Off packet seen)",
+ radlog(L_INFO, "NAS %s rebooted (Accounting-Off packet seen)",
nas_name(nas_address));
radutmp_zap(inst, nas_address, ut.time);
- return RLM_ACCT_OK;
+ return RLM_MODULE_OK;
}
/*
if (status != PW_STATUS_START &&
status != PW_STATUS_STOP &&
status != PW_STATUS_ALIVE) {
- log(L_ERR, "NAS %s port %d unknown packet type %d)",
+ radlog(L_ERR, "NAS %s port %d unknown packet type %d)",
nas_name(nas_address), ut.nas_port, status);
- return RLM_ACCT_FAIL_SOFT;
+ return RLM_MODULE_NOOP;
}
/*
* - with the username "!root" (console admin login)
*/
if (!port_seen || strncmp(ut.login, "!root", RUT_NAMESIZE) == 0)
- return RLM_ACCT_OK;
+ return RLM_MODULE_NOOP;
/*
* Enter into the radutmp file.
/*
* Lock the utmp file, prefer lockf() over flock().
*/
-#if defined(F_LOCK) && !defined(BSD)
- (void)lockf(fd, F_LOCK, LOCK_LEN);
-#else
- (void)flock(fd, LOCK_EX);
-#endif
+ radutmp_lock(fd);
+
/*
* Find the entry for this NAS / portno combination.
*/
* send _only_ logout records).
*/
if (u.type == P_LOGIN)
- log(L_ERR,
+ radlog(L_ERR,
"Accounting: logout: entry for NAS %s port %d has wrong ID",
nas_name(nas_address), u.nas_port);
r = -1;
sizeof(u.session_id)) == 0 &&
u.time >= ut.time) {
if (u.type == P_LOGIN) {
- log(L_INFO,
+ radlog(L_INFO,
"Accounting: login: entry for NAS %s port %d duplicate",
nas_name(nas_address), u.nas_port);
r = -1;
break;
}
- log(L_ERR,
+ radlog(L_ERR,
"Accounting: login: entry for NAS %s port %d wrong order",
nas_name(nas_address), u.nas_port);
r = -1;
}
if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {
- log(L_ERR, "Accounting: negative lseek!\n");
+ radlog(L_ERR, "Accounting: negative lseek!\n");
lseek(fd, (off_t)0, SEEK_SET);
off = 0;
} else
u.delay = ut.delay;
write(fd, &u, sizeof(u));
} else if (r == 0) {
- log(L_ERR,
+ radlog(L_ERR,
"Accounting: logout: login entry for NAS %s port %d not found",
nas_name(nas_address), ut.nas_port);
r = -1;
}
close(fd);
} else {
- log(L_ERR, "Accounting: %s: %s", inst->radutmp_fn, strerror(errno));
- return RLM_ACCT_FAIL;
+ radlog(L_ERR, "Accounting: %s: %m", inst->radutmp_fn);
+ return RLM_MODULE_FAIL;
}
- return RLM_ACCT_OK;
+ return RLM_MODULE_OK;
}
/*
- * See if a user is already logged in. Sets *count to the current
- * session count for this user and sets *mpp to 2 if it looks like a
- * multilink attempt based on the requested ipno, otherwise leaves it
- * alone.
+ * See if a user is already logged in. Sets request->simul_count to the
+ * current session count for this user and sets request->simul_mpp to 2
+ * if it looks like a multilink attempt based on the requested IP
+ * address, otherwise leaves request->simul_mpp alone.
+ *
+ * Check twice. If on the first pass the user exceeds his
+ * max. number of logins, do a second pass and validate all
+ * logins by querying the terminal server (using eg. SNMP).
*/
-static int radutmp_checksimul(void *instance, const char *name, int *count,
- int doradcheck, UINT4 ipno, int *mpp)
+static int radutmp_checksimul(void *instance, REQUEST *request)
{
struct radutmp u;
int fd;
- struct sess_instance *inst = instance;
+ VALUE_PAIR *fra;
+ uint32_t ipno = 0;
+ int rcode;
+ const char *name = (char *)request->username->strvalue;
+ struct radutmp_instance *inst = instance;
if ((fd = open(inst->radutmp_fn, O_RDWR)) < 0) {
if(errno!=ENOENT)
- return RLM_CSIM_FAIL;
- *count=0;
- return RLM_CSIM_OK;
+ return RLM_MODULE_FAIL;
+ request->simul_count=0;
+ return RLM_MODULE_OK;
}
- if(!doradcheck) {
- *count = 0;
- while(read(fd, &u, sizeof(u)) == sizeof(u))
- if (strncmp(name, u.login, RUT_NAMESIZE) == 0
- && u.type == P_LOGIN)
- ++*count;
+ request->simul_count = 0;
+ while(read(fd, &u, sizeof(u)) == sizeof(u)) {
+ if (strncmp(name, u.login, RUT_NAMESIZE) == 0
+ && u.type == P_LOGIN)
+ ++request->simul_count;
+ }
+
+ if(request->simul_count < request->simul_max) {
close(fd);
- return RLM_CSIM_OK;
+ return RLM_MODULE_OK;
}
+ lseek(fd, (off_t)0, SEEK_SET);
/*
- * lockf() the file while reading/writing.
+ * Setup some stuff, like for MPP detection.
*/
-#if defined(F_LOCK) && !defined(BSD)
- (void)lockf(fd, F_LOCK, LOCK_LEN);
-#else
- (void)flock(fd, LOCK_EX);
-#endif
+ if ((fra = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL)
+ ipno = fra->lvalue;
/*
- * Check all registered logins by querying the
- * terminal server directly.
- * FIXME: rad_check_ts() runs with locked radutmp file!
+ * lockf() the file while reading/writing.
*/
- *count = 0;
+ radutmp_lock(fd);
+
+ request->simul_count = 0;
while (read(fd, &u, sizeof(u)) == sizeof(u)) {
if (strncmp(name, u.login, RUT_NAMESIZE) == 0
&& u.type == P_LOGIN) {
char session_id[sizeof u.session_id+1];
strNcpy(login, u.login, sizeof login);
strNcpy(session_id, u.session_id, sizeof session_id);
- if (rad_check_ts(u.nas_address, u.nas_port, login,
- session_id) == 1) {
- ++*count;
+
+ /*
+ * rad_check_ts may take seconds to return,
+ * and we don't want to block everyone else
+ * while that's happening.
+ */
+ radutmp_unlock(fd);
+ rcode = rad_check_ts(u.nas_address, u.nas_port, login,
+ session_id);
+ radutmp_lock(fd);
+
+ if (rcode == 1) {
+ ++request->simul_count;
/*
* Does it look like a MPP attempt?
*/
if (strchr("SCPA", u.proto) &&
ipno && u.framed_address == ipno)
- *mpp = 2;
+ request->simul_mpp = 2;
}
else {
/*
}
close(fd);
- return RLM_CSIM_OK;
+ return RLM_MODULE_OK;
}
/* globally exported name */
"radutmp",
0, /* type: reserved */
NULL, /* initialization */
- radutmp_instantiate, /* initialization */
+ radutmp_instantiate, /* instantiation */
NULL, /* authorization */
NULL, /* authentication */
+ NULL, /* preaccounting */
radutmp_accounting, /* accounting */
radutmp_checksimul, /* checksimul */
radutmp_detach, /* detach */