📄 rlm_radutmp.c
字号:
return RLM_MODULE_OK; } /* * 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, "rlm_radutmp: NAS %s port %u unknown packet type %d)", nas, ut.nas_port, status); return RLM_MODULE_NOOP; } /* * Translate the User-Name attribute, or whatever else * they told us to use. */ *buffer = '\0'; radius_xlat(buffer, sizeof(buffer), inst->username, request, NULL); /* * Copy the previous translated user name. */ strncpy(ut.login, buffer, RUT_NAMESIZE); /* * Perhaps we don't want to store this record into * radutmp. We skip records: * * - without a NAS-Port (telnet / tcp access) * - with the username "!root" (console admin login) */ if (!port_seen) { DEBUG2(" rlm_radutmp: No NAS-Port seen. Cannot do anything."); DEBUG2(" rlm_radumtp: WARNING: checkrad will probably not work!"); return RLM_MODULE_NOOP; } if (strncmp(ut.login, "!root", RUT_NAMESIZE) == 0) { DEBUG2(" rlm_radutmp: Not recording administrative user"); return RLM_MODULE_NOOP; } /* * Enter into the radutmp file. */ fd = open(filename, O_RDWR|O_CREAT, inst->permission); if (fd < 0) { radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s", filename, strerror(errno)); return RLM_MODULE_FAIL; } /* * Lock the utmp file, prefer lockf() over flock(). */ rad_lockfd(fd, LOCK_LEN); /* * Find the entry for this NAS / portno combination. */ if ((cache = nas_port_find(inst->nas_port_list, 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; /* * 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) { /* * 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, "rlm_radutmp: Logout entry for NAS %s port %u has wrong ID", nas, 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, "rlm_radutmp: Login entry for NAS %s port %u duplicate", nas, u.nas_port); r = -1; break; } radlog(L_ERR, "rlm_radutmp: Login entry for NAS %s port %u wrong order", nas, 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, "rlm_radutmp: negative lseek!"); lseek(fd, (off_t)0, SEEK_SET); off = 0; } else off -= sizeof(u); r = 1; break; } /* read the file until we find a match */ /* * Found the entry, do start/update it with * the information from the packet. */ if (r >= 0 && (status == PW_STATUS_START || status == PW_STATUS_ALIVE)) { /* * Remember where the entry was, because it's * easier than searching through the entire file. */ if (cache == NULL) { cache = rad_malloc(sizeof(NAS_PORT)); cache->nasaddr = ut.nas_address; cache->port = ut.nas_port; cache->offset = off; 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. */ 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, "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;}/* * 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, REQUEST *request){ struct radutmp u; int fd; VALUE_PAIR *vp; uint32_t ipno = 0; char *call_num = NULL; int rcode; rlm_radutmp_t *inst = instance; char login[256]; char filename[1024]; /* * Get the filename, via xlat. */ radius_xlat(filename, sizeof(filename), inst->filename, request, NULL); if ((fd = open(filename, O_RDWR)) < 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. */ radlog(L_ERR, "rlm_radumtp: Error accessing file %s: %s", filename, strerror(errno)); return RLM_MODULE_FAIL; } *login = '\0'; radius_xlat(login, sizeof(login), inst->username, request, NULL); if (!*login) { return RLM_MODULE_NOOP; } /* * 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(login, u.login, RUT_NAMESIZE) == 0) || (!inst->case_sensitive && (strncasecmp(login, 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) { close(fd); return RLM_MODULE_OK; } lseek(fd, (off_t)0, SEEK_SET); /* * 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; /* * 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(login, u.login, RUT_NAMESIZE) == 0) || (!inst->case_sensitive && (strncasecmp(login, u.login, RUT_NAMESIZE) == 0))) && (u.type == P_LOGIN)) { char session_id[sizeof(u.session_id) + 1]; char utmp_login[sizeof(u.login) + 1]; strNcpy(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. */ strNcpy(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); /* * Failed to check the terminal server for * duplicate logins: Return an error. */ if (rcode < 0) { close(fd); return RLM_MODULE_FAIL; } if (rcode == 1) { ++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 { /* * False record - zap it. */ session_zap(request, u.nas_address, u.nas_port, login, session_id, u.framed_address, u.proto); } } } close(fd); /* and implicitely release the locks */ return RLM_MODULE_OK;}/* 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 */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -