X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_radutmp%2Frlm_radutmp.c;h=65fe1c08692ed2ddf023e2a97dc0ad337e1e3c9b;hb=8dcf3e2a2b53342b0d6a65d7078b6c4629548321;hp=b8bd938b4adc21765d978a61d3e59b7d5c278449;hpb=2728eb5f43780f9d4f461fd4e59ba0ee64b23425;p=freeradius.git diff --git a/src/modules/rlm_radutmp/rlm_radutmp.c b/src/modules/rlm_radutmp/rlm_radutmp.c index b8bd938..65fe1c0 100644 --- a/src/modules/rlm_radutmp/rlm_radutmp.c +++ b/src/modules/rlm_radutmp/rlm_radutmp.c @@ -1,5 +1,5 @@ /* - * rlm_radutmp.c + * rlm_radutmp.c * * Version: $Id$ * @@ -15,30 +15,25 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * Copyright 2000 The FreeRADIUS server project + * Copyright 2000,2006 The FreeRADIUS server project * FIXME add copyrights */ -#include "autoconf.h" +#include +RCSID("$Id$") + +#include +#include +#include +#include -#include -#include -#include -#include -#include #include -#include -#include #include #include "config.h" -#include "radiusd.h" -#include "radutmp.h" -#include "modules.h" - #define LOCK_LEN sizeof(struct radutmp) static const char porttypes[] = "ASITX"; @@ -64,7 +59,7 @@ typedef struct rlm_radutmp_t { int callerid_ok; } rlm_radutmp_t; -static CONF_PARSER module_config[] = { +static const CONF_PARSER module_config[] = { { "filename", PW_TYPE_STRING_PTR, offsetof(rlm_radutmp_t,filename), NULL, RADUTMP }, { "username", PW_TYPE_STRING_PTR, @@ -113,8 +108,6 @@ static int radutmp_detach(void *instance) next = p->next; free(p); } - if (inst->filename) free(inst->filename); - if (inst->username) free(inst->username); free(inst); return 0; } @@ -122,7 +115,7 @@ static int radutmp_detach(void *instance) /* * Zap all users on a NAS from the radutmp file. */ -static int radutmp_zap(rlm_radutmp_t *inst, +static int radutmp_zap(UNUSED rlm_radutmp_t *inst, const char *filename, uint32_t nasaddr, time_t t) @@ -143,7 +136,7 @@ static int radutmp_zap(rlm_radutmp_t *inst, * Lock the utmp file, prefer lockf() over flock(). */ rad_lockfd(fd, LOCK_LEN); - + /* * Find the entry for this NAS / portno combination. */ @@ -182,6 +175,7 @@ static NAS_PORT *nas_port_find(NAS_PORT *nas_port_list, uint32_t nasaddr, unsign } +#ifdef WITH_ACCOUNTING /* * Store logins in the RADIUS utmp file. */ @@ -190,14 +184,10 @@ static int radutmp_accounting(void *instance, REQUEST *request) struct radutmp ut, u; VALUE_PAIR *vp; int status = -1; - uint32_t nas_address = 0; - uint32_t framed_address = 0; int protocol = -1; time_t t; int fd; - int just_an_update = 0; int port_seen = 0; - int nas_port_type = 0; int off; rlm_radutmp_t *inst = instance; char buffer[256]; @@ -207,14 +197,19 @@ static int radutmp_accounting(void *instance, REQUEST *request) NAS_PORT *cache; int r; + if (request->packet->src_ipaddr.af != AF_INET) { + DEBUG("rlm_radutmp: IPv6 not supported!"); + return RLM_MODULE_NOOP; + } + /* * Which type is this. */ - if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) { + if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0)) == NULL) { radlog(L_ERR, "rlm_radutmp: No Accounting-Status-Type record."); return RLM_MODULE_NOOP; } - status = vp->lvalue; + status = vp->vp_integer; /* * Look for weird reboot packets. @@ -233,12 +228,12 @@ static int radutmp_accounting(void *instance, REQUEST *request) int check1 = 0; int check2 = 0; - if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME)) - == NULL || vp->lvalue == 0) + if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME, 0)) + == NULL || vp->vp_date == 0) check1 = 1; - if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID)) + if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID, 0)) != NULL && vp->length == 8 && - memcmp(vp->strvalue, "00000000", 8) == 0) + memcmp(vp->vp_strvalue, "00000000", 8) == 0) check2 = 1; if (check1 == 0 || check2 == 0) { #if 0 /* Cisco sometimes sends START records without username. */ @@ -258,6 +253,7 @@ static int radutmp_accounting(void *instance, REQUEST *request) time(&t); memset(&ut, 0, sizeof(ut)); ut.porttype = 'A'; + ut.nas_address = htonl(INADDR_NONE); /* * First, find the interesting attributes. @@ -266,22 +262,20 @@ static int radutmp_accounting(void *instance, REQUEST *request) switch (vp->attribute) { case PW_LOGIN_IP_HOST: case PW_FRAMED_IP_ADDRESS: - framed_address = vp->lvalue; - ut.framed_address = vp->lvalue; + ut.framed_address = vp->vp_ipaddr; break; case PW_FRAMED_PROTOCOL: - protocol = vp->lvalue; + protocol = vp->vp_integer; break; case PW_NAS_IP_ADDRESS: - nas_address = vp->lvalue; - ut.nas_address = vp->lvalue; + ut.nas_address = vp->vp_ipaddr; break; case PW_NAS_PORT: - ut.nas_port = vp->lvalue; + ut.nas_port = vp->vp_integer; port_seen = 1; break; case PW_ACCT_DELAY_TIME: - ut.delay = vp->lvalue; + ut.delay = vp->vp_integer; break; case PW_ACCT_SESSION_ID: /* @@ -295,21 +289,20 @@ static int radutmp_accounting(void *instance, REQUEST *request) * Compensate. */ if (vp->length > 0 && - vp->strvalue[vp->length - 1] == 0) + vp->vp_strvalue[vp->length - 1] == 0) off--; if (off < 0) off = 0; - memcpy(ut.session_id, vp->strvalue + off, + memcpy(ut.session_id, vp->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; + if (vp->vp_integer <= 4) + ut.porttype = porttypes[vp->vp_integer]; break; case PW_CALLING_STATION_ID: if(inst->callerid_ok) - strNcpy(ut.caller_id, - (char *)vp->strvalue, + strlcpy(ut.caller_id, + (char *)vp->vp_strvalue, sizeof(ut.caller_id)); break; } @@ -319,33 +312,20 @@ static int radutmp_accounting(void *instance, REQUEST *request) * 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; - nas = client_name(nas_address); /* MUST be a valid client */ + if (ut.nas_address == htonl(INADDR_NONE)) { + ut.nas_address = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr; + nas = request->client->shortname; - } else { /* might be a client, might not be. */ - RADCLIENT *cl; + } else if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr == ut.nas_address) { /* might be a client, might not be. */ + nas = request->client->shortname; + } else { /* - * Hack like 'client_name()', but with sane - * fall-back. + * The NAS isn't a client, it's behind + * a proxy server. In that case, just + * get the IP address. */ - cl = client_find(nas_address); - if (cl) { - if (cl->shortname[0]) { - nas = cl->shortname; - } else { - nas = cl->longname; - } - } else { - /* - * The NAS isn't a client, it's behind - * a proxy server. In that case, just - * get the IP address. - */ - nas = ip_ntoa(ip_name, nas_address); - } + nas = ip_ntoa(ip_name, ut.nas_address); } /* @@ -371,17 +351,19 @@ static int radutmp_accounting(void *instance, REQUEST *request) * the NAS comes up, because of issues with receiving * UDP packets out of order. */ - if (status == PW_STATUS_ACCOUNTING_ON && nas_address) { + if (status == PW_STATUS_ACCOUNTING_ON && + (ut.nas_address != htonl(INADDR_NONE))) { radlog(L_INFO, "rlm_radutmp: NAS %s restarted (Accounting-On packet seen)", nas); - radutmp_zap(inst, filename, nas_address, ut.time); + radutmp_zap(inst, filename, ut.nas_address, ut.time); return RLM_MODULE_OK; } - if (status == PW_STATUS_ACCOUNTING_OFF && nas_address) { + if (status == PW_STATUS_ACCOUNTING_OFF && + (ut.nas_address != htonl(INADDR_NONE))) { radlog(L_INFO, "rlm_radutmp: NAS %s rebooted (Accounting-Off packet seen)", nas); - radutmp_zap(inst, filename, nas_address, ut.time); + radutmp_zap(inst, filename, ut.nas_address, ut.time); return RLM_MODULE_OK; } @@ -406,7 +388,7 @@ static int radutmp_accounting(void *instance, REQUEST *request) /* * Copy the previous translated user name. */ - strncpy(ut.login, buffer, RUT_NAMESIZE); + strlcpy(ut.login, buffer, RUT_NAMESIZE); /* * Perhaps we don't want to store this record into @@ -441,7 +423,7 @@ static int radutmp_accounting(void *instance, REQUEST *request) * Lock the utmp file, prefer lockf() over flock(). */ rad_lockfd(fd, LOCK_LEN); - + /* * Find the entry for this NAS / portno combination. */ @@ -449,7 +431,7 @@ static int radutmp_accounting(void *instance, REQUEST *request) ut.nas_port)) != NULL) { lseek(fd, (off_t)cache->offset, SEEK_SET); } - + r = 0; off = 0; while (read(fd, &u, sizeof(u)) == sizeof(u)) { @@ -457,7 +439,15 @@ static int radutmp_accounting(void *instance, REQUEST *request) if (u.nas_address != ut.nas_address || u.nas_port != ut.nas_port) continue; - + + /* + * Don't compare stop records to unused entries. + */ + if (status == PW_STATUS_STOP && + u.type == P_IDLE) { + continue; + } + if (status == PW_STATUS_STOP && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) != 0) { @@ -472,7 +462,7 @@ static int radutmp_accounting(void *instance, REQUEST *request) r = -1; break; } - + if (status == PW_STATUS_START && strncmp(ut.session_id, u.session_id, sizeof(u.session_id)) == 0 && @@ -488,7 +478,7 @@ static int radutmp_accounting(void *instance, REQUEST *request) r = -1; break; } - + /* * FIXME: the ALIVE record could need * some more checking, but anyway I'd @@ -502,10 +492,8 @@ static int radutmp_accounting(void *instance, REQUEST *request) * 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, "rlm_radutmp: negative lseek!"); lseek(fd, (off_t)0, SEEK_SET); @@ -534,11 +522,11 @@ static int radutmp_accounting(void *instance, REQUEST *request) cache->next = inst->nas_port_list; inst->nas_port_list = cache; } - + ut.type = P_LOGIN; write(fd, &ut, sizeof(u)); } - + /* * The user has logged off, delete the entry by * re-writing it in place. @@ -552,14 +540,15 @@ static int radutmp_accounting(void *instance, REQUEST *request) } else if (r == 0) { radlog(L_ERR, "rlm_radutmp: Logout for NAS %s port %u, but no Login record", nas, ut.nas_port); - r = -1; } } close(fd); /* and implicitely release the locks */ return RLM_MODULE_OK; } +#endif +#ifdef WITH_SESSION_MGMT /* * 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 @@ -644,10 +633,10 @@ static int radutmp_checksimul(void *instance, REQUEST *request) /* * Setup some stuff, like for MPP detection. */ - if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL) - ipno = vp->lvalue; - if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL) - call_num = vp->strvalue; + if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS, 0)) != NULL) + ipno = vp->vp_ipaddr; + if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0)) != NULL) + call_num = vp->vp_strvalue; /* * lock the file while reading/writing. @@ -669,7 +658,7 @@ static int radutmp_checksimul(void *instance, REQUEST *request) char session_id[sizeof(u.session_id) + 1]; char utmp_login[sizeof(u.login) + 1]; - strNcpy(session_id, u.session_id, sizeof(session_id)); + strlcpy(session_id, u.session_id, sizeof(session_id)); /* * The login name MAY fill the whole field, @@ -687,7 +676,7 @@ static int radutmp_checksimul(void *instance, REQUEST *request) * and the NAS says "no", because "BOB" * is using the port. */ - strNcpy(utmp_login, u.login, sizeof(u.login)); + strlcpy(utmp_login, u.login, sizeof(u.login)); /* * rad_check_ts may take seconds @@ -698,17 +687,19 @@ static int radutmp_checksimul(void *instance, REQUEST *request) rcode = rad_check_ts(u.nas_address, u.nas_port, utmp_login, session_id); rad_lockfd(fd, LOCK_LEN); - - /* - * Failed to check the terminal server for - * duplicate logins: Return an error. - */ - if (rcode < 0) { - close(fd); - return RLM_MODULE_FAIL; - } - if (rcode == 1) { + if (rcode == 0) { + /* + * Stale record - zap it. + */ + session_zap(request, u.nas_address, + u.nas_port, login, session_id, + u.framed_address, u.proto,0); + } + else if (rcode == 1) { + /* + * User is still logged in. + */ ++request->simul_count; /* @@ -723,12 +714,13 @@ static int radutmp_checksimul(void *instance, REQUEST *request) } else { /* - * False record - zap it. + * Failed to check the terminal + * server for duplicate logins: + * Return an error. */ - session_zap(request, - u.nas_address, u.nas_port, login, - session_id, u.framed_address, - u.proto); + close(fd); + radlog(L_ERR, "rlm_radutmp: Failed to check the terminal server for user '%s'.", utmp_login); + return RLM_MODULE_FAIL; } } } @@ -736,24 +728,32 @@ static int radutmp_checksimul(void *instance, REQUEST *request) return RLM_MODULE_OK; } +#endif /* globally exported name */ module_t rlm_radutmp = { - "radutmp", - 0, /* type: reserved */ - NULL, /* initialization */ - radutmp_instantiate, /* instantiation */ - { - NULL, /* authentication */ - NULL, /* authorization */ - NULL, /* preaccounting */ - radutmp_accounting, /* accounting */ - radutmp_checksimul, /* checksimul */ - NULL, /* pre-proxy */ - NULL, /* post-proxy */ - NULL /* post-auth */ - }, - radutmp_detach, /* detach */ - NULL, /* destroy */ + RLM_MODULE_INIT, + "radutmp", + RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */ + radutmp_instantiate, /* instantiation */ + radutmp_detach, /* detach */ + { + NULL, /* authentication */ + NULL, /* authorization */ + NULL, /* preaccounting */ +#ifdef WITH_ACCOUNTING + radutmp_accounting, /* accounting */ +#else + NULL, +#endif +#ifdef WITH_SESSION_MGMT + radutmp_checksimul, /* checksimul */ +#else + NULL, +#endif + NULL, /* pre-proxy */ + NULL, /* post-proxy */ + NULL /* post-auth */ + }, };