/* * Do the statistics */ static rlm_rcode_t CC_HINT(nonnull) mod_stats(void *instance, void *thread, REQUEST *request) { int i; uint32_t stats_type; rlm_stats_thread_t *t = thread; rlm_stats_t *inst = instance; VALUE_PAIR *vp; rlm_stats_data_t mydata, *stats; fr_cursor_t cursor; char buffer[64]; uint64_t local_stats[sizeof(inst->stats) / sizeof(inst->stats[0])]; /* * Increment counters only in "send foo" sections. * * i.e. only when we have a reply to send. */ if (request->request_state == REQUEST_SEND) { int src_code, dst_code; src_code = request->packet->code; if (src_code >= FR_MAX_PACKET_CODE) src_code = 0; dst_code = request->reply->code; if (dst_code >= FR_MAX_PACKET_CODE) dst_code = 0; t->stats[src_code]++; t->stats[dst_code]++; /* * Update source statistics */ mydata.ipaddr = request->packet->src_ipaddr; stats = rbtree_finddata(t->src, &mydata); if (!stats) { MEM(stats = talloc_zero(t, rlm_stats_data_t)); stats->ipaddr = request->packet->src_ipaddr; stats->created = request->async->recv_time; (void) rbtree_insert(t->src, stats); } stats->last_packet = request->async->recv_time; stats->stats[src_code]++; stats->stats[dst_code]++; /* * Update destination statistics */ mydata.ipaddr = request->packet->dst_ipaddr; stats = rbtree_finddata(t->dst, &mydata); if (!stats) { MEM(stats = talloc_zero(t, rlm_stats_data_t)); stats->ipaddr = request->packet->dst_ipaddr; stats->created = request->async->recv_time; (void) rbtree_insert(t->dst, stats); } stats->last_packet = request->async->recv_time; stats->stats[src_code]++; stats->stats[dst_code]++; /* * @todo - periodically clean up old entries. */ if ((t->last_global_update + NANOSEC) > request->async->recv_time) { return RLM_MODULE_UPDATED; } t->last_global_update = request->async->recv_time; pthread_mutex_lock(&inst->mutex); for (i = 0; i < FR_MAX_PACKET_CODE; i++) { inst->stats[i] += t->stats[i]; t->stats[i] = 0; } pthread_mutex_unlock(&inst->mutex); return RLM_MODULE_UPDATED; } /* * Ignore "authenticate" and anything other than Status-Server */ if ((request->request_state != REQUEST_RECV) || (request->packet->code != FR_CODE_STATUS_SERVER)) { return RLM_MODULE_NOOP; } vp = fr_pair_find_by_da(request->packet->vps, attr_freeradius_stats4_type, TAG_ANY); if (!vp) { stats_type = FR_FREERADIUS_STATS4_TYPE_VALUE_GLOBAL; } else { stats_type = vp->vp_uint32; } /* * Create attributes based on the statistics. */ fr_cursor_init(&cursor, &request->reply->vps); MEM(pair_update_reply(&vp, attr_freeradius_stats4_type) >= 0); vp->vp_uint32 = stats_type; switch (stats_type) { case FR_FREERADIUS_STATS4_TYPE_VALUE_GLOBAL: /* global */ /* * Merge our stats with the global stats, and then copy * the global stats to a thread-local variable. * * The copy helps minimize mutex contention. */ pthread_mutex_lock(&inst->mutex); for (i = 0; i < FR_MAX_PACKET_CODE; i++) { inst->stats[i] += t->stats[i]; t->stats[i] = 0; } memcpy(&local_stats, inst->stats, sizeof(inst->stats)); pthread_mutex_unlock(&inst->mutex); vp = NULL; break; case FR_FREERADIUS_STATS4_TYPE_VALUE_CLIENT: /* src */ vp = fr_pair_find_by_da(request->packet->vps, attr_freeradius_stats4_ipv4_address, TAG_ANY); if (!vp) vp = fr_pair_find_by_da(request->packet->vps, attr_freeradius_stats4_ipv6_address, TAG_ANY); if (!vp) return RLM_MODULE_NOOP; mydata.ipaddr = vp->vp_ip; coalesce(local_stats, t, offsetof(rlm_stats_thread_t, src), &mydata); break; case FR_FREERADIUS_STATS4_TYPE_VALUE_LISTENER: /* dst */ vp = fr_pair_find_by_da(request->packet->vps, attr_freeradius_stats4_ipv4_address, TAG_ANY); if (!vp) vp = fr_pair_find_by_da(request->packet->vps, attr_freeradius_stats4_ipv6_address, TAG_ANY); if (!vp) return RLM_MODULE_NOOP; mydata.ipaddr = vp->vp_ip; coalesce(local_stats, t, offsetof(rlm_stats_thread_t, dst), &mydata); break; default: REDEBUG("Invalid value '%d' for FreeRADIUS-Stats4-type", stats_type); return RLM_MODULE_FAIL; } if (vp ) { vp = fr_pair_copy(request->reply, vp); if (vp) { fr_cursor_append(&cursor, vp); (void) fr_cursor_tail(&cursor); } } strcpy(buffer, "FreeRADIUS-Stats4-"); for (i = 0; i < FR_MAX_PACKET_CODE; i++) { fr_dict_attr_t const *da; if (!local_stats[i]) continue; strlcpy(buffer + 18, fr_packet_codes[i], sizeof(buffer) - 18); da = fr_dict_attr_by_name(dict_radius, buffer); if (!da) continue; vp = fr_pair_afrom_da(request->reply, da); if (!vp) return RLM_MODULE_FAIL; vp->vp_uint64 = local_stats[i]; fr_cursor_append(&cursor, vp); (void) fr_cursor_tail(&cursor); } return RLM_MODULE_OK; }
/* * Authenticate the user via one of any well-known password. */ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, UNUSED void *thread, REQUEST *request) { int rcode; rlm_securid_t const *inst = instance; char buffer[FR_MAX_STRING_LEN]=""; char const *username=NULL, *password=NULL; VALUE_PAIR *vp; /* * We can only authenticate user requests which HAVE * a User-Name attribute. */ if (!request->username) { REDEBUG("Attribute \"User-Name\" is required for authentication"); return RLM_MODULE_INVALID; } if (!request->password) { REDEBUG("Attribute \"Password\" is required for authentication"); return RLM_MODULE_INVALID; } /* * Clear-text passwords are the only ones we support. */ if (request->password->da != attr_user_password) { REDEBUG("Attribute \"User-Password\" is required for authentication. Cannot use \"%s\"", request->password->da->name); return RLM_MODULE_INVALID; } /* * The user MUST supply a non-zero-length password. */ if (request->password->vp_length == 0) { REDEBUG("Password should not be empty"); return RLM_MODULE_INVALID; } /* * shortcuts */ username = request->username->vp_strvalue; password = request->password->vp_strvalue; if (RDEBUG_ENABLED3) { RDEBUG3("Login attempt with password \"%s\"", password); } else { RDEBUG2("Login attempt with password"); } rcode = securidAuth(inst, request, username, password, buffer, sizeof(buffer)); switch (rcode) { case RC_SECURID_AUTH_SUCCESS: rcode = RLM_MODULE_OK; break; case RC_SECURID_AUTH_CHALLENGE: /* reply with Access-challenge message code (11) */ /* Generate Prompt attribute */ MEM(pair_update_reply(&vp, attr_prompt) >= 0); vp->vp_uint32 = 0; /* no echo */ /* Mark the packet as a Acceess-Challenge Packet */ request->reply->code = FR_CODE_ACCESS_CHALLENGE; RDEBUG2("Sending Access-Challenge"); rcode = RLM_MODULE_HANDLED; break; case RC_SECURID_AUTH_FAILURE: case RC_SECURID_AUTH_ACCESS_DENIED_FAILURE: case RC_SECURID_AUTH_INVALID_SERVER_FAILURE: default: rcode = RLM_MODULE_REJECT; break; } if (*buffer) { MEM(pair_update_reply(&vp, attr_reply_message) >= 0); fr_pair_value_strcpy(vp, buffer); } return rcode; }