static char const porttypes[] = "ASITX";
/*
- * used for caching radutmp lookups in the accounting component. The
- * session (checksimul) component doesn't use it, but probably should.
+ * used for caching radutmp lookups in the accounting component.
*/
typedef struct nas_port {
uint32_t nasaddr;
}
#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
- * 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 rlm_rcode_t CC_HINT(nonnull) mod_checksimul(void *instance, UNUSED void *thread, REQUEST *request)
-{
- rlm_rcode_t rcode = RLM_MODULE_OK;
- struct radutmp u;
- int fd = -1;
- VALUE_PAIR *vp;
- uint32_t ipno = 0;
- char const *call_num = NULL;
- rlm_radutmp_t *inst = instance;
-
- char *expanded = NULL;
- ssize_t len;
-
- /*
- * Get the filename, via xlat.
- */
- if (xlat_aeval(request, &expanded, request, inst->filename, NULL, NULL) < 0) {
- return RLM_MODULE_FAIL;
- }
-
- fd = open(expanded, O_RDWR);
- if (fd < 0) {
- /*
- * If the file doesn't exist, then no users
- * are logged in.
- */
- if (errno == ENOENT) {
- request->simul_count=0;
- return RLM_MODULE_OK;
- }
-
- /*
- * Error accessing the file.
- */
- REDEBUG("Error accessing file %s: %s", expanded, fr_syserror(errno));
- rcode = RLM_MODULE_FAIL;
-
- goto finish;
- }
-
- TALLOC_FREE(expanded);
-
- len = xlat_aeval(request, &expanded, request, inst->username, NULL, NULL);
- if (len < 0) {
- rcode = RLM_MODULE_FAIL;
-
- goto finish;
- }
-
- if (!len) {
- rcode = RLM_MODULE_NOOP;
-
- goto finish;
- }
-
- /*
- * WTF? This is probably wrong... we probably want to
- * be able to check users across multiple session accounting
- * methods.
- */
- request->simul_count = 0;
-
- /*
- * Loop over utmp, counting how many people MAY be logged in.
- */
- while (read(fd, &u, sizeof(u)) == sizeof(u)) {
- if (((strncmp(expanded, u.login, RUT_NAMESIZE) == 0) ||
- (!inst->case_sensitive && (strncasecmp(expanded, u.login, RUT_NAMESIZE) == 0))) &&
- (u.type == P_LOGIN)) {
- ++request->simul_count;
- }
- }
-
- /*
- * The number of users logged in is OK,
- * OR, we've been told to not check the NAS.
- */
- if ((request->simul_count < request->simul_max) || !inst->check_nas) {
- rcode = RLM_MODULE_OK;
-
- goto finish;
- }
- lseek(fd, (off_t)0, SEEK_SET);
-
- /*
- * Setup some stuff, like for MPP detection.
- */
- if ((vp = fr_pair_find_by_num(request->packet->vps, 0, FR_FRAMED_IP_ADDRESS, TAG_ANY)) != NULL) {
- ipno = vp->vp_ipv4addr;
- }
-
- if ((vp = fr_pair_find_by_num(request->packet->vps, 0, FR_CALLING_STATION_ID, TAG_ANY)) != NULL) {
- call_num = vp->vp_strvalue;
- }
-
- /*
- * lock the file while reading/writing.
- */
- rad_lockfd(fd, LOCK_LEN);
-
- /*
- * FIXME: If we get a 'Start' for a user/nas/port which is
- * listed, but for which we did NOT get a 'Stop', then
- * it's not a duplicate session. This happens with
- * static IP's like DSL.
- */
- request->simul_count = 0;
- while (read(fd, &u, sizeof(u)) == sizeof(u)) {
- if (((strncmp(expanded, u.login, RUT_NAMESIZE) == 0) || (!inst->case_sensitive &&
- (strncasecmp(expanded, u.login, RUT_NAMESIZE) == 0))) && (u.type == P_LOGIN)) {
- char session_id[sizeof(u.session_id) + 1];
- char utmp_login[sizeof(u.login) + 1];
-
- /* Guarantee string is NULL terminated */
- u.session_id[sizeof(u.session_id) - 1] = '\0';
- strlcpy(session_id, u.session_id, sizeof(session_id));
-
- /*
- * The login name MAY fill the whole field,
- * and thus won't be zero-filled.
- *
- * Note that we take the user name from
- * the utmp file, as that's the canonical
- * form. The 'login' variable may contain
- * a string which is an upper/lowercase
- * version of u.login. When we call the
- * routine to check the terminal server,
- * the NAS may be case sensitive.
- *
- * e.g. We ask if "bob" is using a port,
- * and the NAS says "no", because "BOB"
- * is using the port.
- */
- memset(utmp_login, 0, sizeof(utmp_login));
- memcpy(utmp_login, u.login, sizeof(u.login));
-
- /*
- * rad_check_ts may take seconds
- * to return, and we don't want
- * to block everyone else while
- * that's happening. */
- rad_unlockfd(fd, LOCK_LEN);
- rcode = rad_check_ts(u.nas_address, u.nas_port, utmp_login, session_id);
- rad_lockfd(fd, LOCK_LEN);
-
- if (rcode == 0) {
- /*
- * Stale record - zap it.
- */
- session_zap(request, u.nas_address, u.nas_port, expanded, session_id,
- u.framed_address, u.proto, 0);
- }
- else if (rcode == 1) {
- /*
- * User is still logged in.
- */
- ++request->simul_count;
-
- /*
- * Does it look like a MPP attempt?
- */
- if (strchr("SCPA", u.proto) && ipno && u.framed_address == ipno) {
- request->simul_mpp = 2;
- } else if (strchr("SCPA", u.proto) && call_num && !strncmp(u.caller_id, call_num,16)) {
- request->simul_mpp = 2;
- }
- } else {
- RWDEBUG("Failed to check the terminal server for user '%s'.", utmp_login);
- rcode = RLM_MODULE_FAIL;
-
- goto finish;
- }
- }
- }
- finish:
-
- talloc_free(expanded);
-
- if (fd > -1) {
- close(fd); /* and implicitely release the locks */
- }
-
- return rcode;
-}
-#endif
-
/* globally exported name */
extern rad_module_t rlm_radutmp;
rad_module_t rlm_radutmp = {
.methods = {
#ifdef WITH_ACCOUNTING
[MOD_ACCOUNTING] = mod_accounting,
-#endif
-#ifdef WITH_SESSION_MGMT
- [MOD_SESSION] = mod_checksimul
#endif
},
};