/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED REQUEST *request) { VALUE_PAIR *state; /* * Look for the 'state' attribute. */ state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY); if (state != NULL) { RDEBUG("Found reply to access challenge"); return RLM_MODULE_OK; } /* * Create the challenge, and add it to the reply. */ pairmake_reply("Reply-Message", "This is a challenge", T_OP_EQ); pairmake_reply("State", "0", T_OP_EQ); /* * Mark the packet as an Access-Challenge packet. * * The server will take care of sending it to the user. */ request->reply->code = PW_CODE_ACCESS_CHALLENGE; RDEBUG("Sending Access-Challenge"); return RLM_MODULE_HANDLED; }
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) { rlm_eap_t *inst = instance; VALUE_PAIR *vp; eap_handler_t *handler; eap_packet_raw_t *eap_packet; /* * Only build a failure message if something previously rejected the request */ vp = pairfind(request->config_items, PW_POSTAUTHTYPE, 0, TAG_ANY); if (!vp || (vp->vp_integer != PW_POSTAUTHTYPE_REJECT)) return RLM_MODULE_NOOP; if (!pairfind(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) { RDEBUG2("Request didn't contain an EAP-Message, not inserting EAP-Failure"); return RLM_MODULE_NOOP; } if (pairfind(request->reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) { RDEBUG2("Reply already contained an EAP-Message, not inserting EAP-Failure"); return RLM_MODULE_NOOP; } eap_packet = eap_vp2packet(request, request->packet->vps); if (!eap_packet) { radlog_request(L_ERR, 0, request, "Malformed EAP Message"); return RLM_MODULE_FAIL; } handler = eap_handler(inst, &eap_packet, request); if (!handler) { RDEBUG2("Failed to get handler, probably already removed, not inserting EAP-Failure"); return RLM_MODULE_NOOP; } RDEBUG2("Request was previously rejected, inserting EAP-Failure"); eap_fail(handler); eap_handler_free(inst, handler); /* * Make sure there's a message authenticator attribute in the response * RADIUS protocol code will calculate the correct value later... */ vp = pairfind(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); if (!vp) { pairmake_reply("Message-Authenticator", "0x00", T_OP_EQ); } return RLM_MODULE_UPDATED; }
/* * Add raw hex data to the reply. */ void eap_add_reply(REQUEST *request, char const *name, uint8_t const *value, int len) { VALUE_PAIR *vp; vp = pairmake_reply(name, NULL, T_OP_EQ); if (!vp) { REDEBUG("Did not create attribute %s: %s\n", name, fr_strerror()); return; } pairmemcpy(vp, value, len); }
/* * Check if account has expired, and if user may login now. */ static rlm_rcode_t mod_authorize(void *instance, REQUEST *request) { rlm_expiration_t *inst = instance; VALUE_PAIR *vp, *check_item = NULL; char msg[MAX_STRING_LEN]; if ((check_item = pairfind(request->config_items, PW_EXPIRATION, 0, TAG_ANY)) != NULL){ /* * Has this user's password expired? * * If so, remove ALL reply attributes, * and add our own Reply-Message, saying * why they're being rejected. */ RDEBUG("Checking Expiration time: '%s'",check_item->vp_strvalue); if (((time_t) check_item->vp_date) <= request->timestamp) { RDEBUG("Account has expired"); if (inst->msg && inst->msg[0]){ if (!radius_xlat(msg, sizeof(msg), inst->msg, request, NULL, NULL)) { radlog(L_ERR, "rlm_expiration: xlat failed."); return RLM_MODULE_FAIL; } pairfree(&request->reply->vps); pairmake_reply("Reply-Message", msg, T_OP_ADD); } RDEBUGE("Account has expired [Expiration %s]",check_item->vp_strvalue); return RLM_MODULE_USERLOCK; } /* * Else the account hasn't expired, but it may do so * in the future. Set Session-Timeout. */ vp = pairfind(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY); if (!vp) { vp = radius_paircreate(request, &request->reply->vps, PW_SESSION_TIMEOUT, 0); vp->vp_date = (uint32_t) (((time_t) check_item->vp_date) - request->timestamp); } else if (vp->vp_date > ((uint32_t) (((time_t) check_item->vp_date) - request->timestamp))) { vp->vp_date = (uint32_t) (((time_t) check_item->vp_date) - request->timestamp); } } else return RLM_MODULE_NOOP; return RLM_MODULE_OK; }
/* * Add raw hex data to the reply. */ void eap_add_reply(REQUEST *request, const char *name, const uint8_t *value, int len) { VALUE_PAIR *vp; vp = pairmake_reply(name, "", T_OP_EQ); if (!vp) { RDEBUGE("Did not create attribute %s: %s\n", name, fr_strerror()); return; } memcpy(vp->vp_octets, value, len); vp->length = len; }
/* * Authenticate the user via one of any well-known password. */ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request) { int rcode; rlm_securid_t *inst = instance; char buffer[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) { AUTH("rlm_securid: Attribute \"User-Name\" is required for authentication"); return RLM_MODULE_INVALID; } if (!request->password) { RAUTH("Attribute \"Password\" is required for authentication"); return RLM_MODULE_INVALID; } /* * Clear-text passwords are the only ones we support. */ if (request->password->da->attr != PW_USER_PASSWORD) { RAUTH("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 { RDEBUG("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 */ vp = paircreate(request->reply, PW_PROMPT, 0); rad_assert(vp != NULL); vp->vp_integer = 0; /* no echo */ pairadd(&request->reply->vps, vp); /* Mark the packet as a Acceess-Challenge Packet */ request->reply->code = PW_CODE_ACCESS_CHALLENGE; RDEBUG("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) pairmake_reply("Reply-Message", buffer, T_OP_EQ); return rcode; }
/* * Process and reply to an authentication request * * The return value of this function isn't actually used right now, so * it's not entirely clear if it is returning the right things. --Pac. */ int rad_authenticate(REQUEST *request) { #ifdef WITH_SESSION_MGMT VALUE_PAIR *check_item; #endif VALUE_PAIR *module_msg; VALUE_PAIR *tmp = NULL; int result; char autz_retry = 0; int autz_type = 0; #ifdef WITH_PROXY /* * If this request got proxied to another server, we need * to check whether it authenticated the request or not. * * request->proxy gets set only AFTER authorization, so * it's safe to check it here. If it exists, it means * we're doing a second pass through rad_authenticate(). */ if (request->proxy) { int code = 0; if (request->proxy_reply) code = request->proxy_reply->code; switch (code) { /* * Reply of ACCEPT means accept, thus set Auth-Type * accordingly. */ case PW_CODE_ACCESS_ACCEPT: tmp = radius_paircreate(request, &request->config, PW_AUTH_TYPE, 0); if (tmp) tmp->vp_integer = PW_AUTHTYPE_ACCEPT; goto authenticate; /* * Challenges are punted back to the NAS without any * further processing. */ case PW_CODE_ACCESS_CHALLENGE: request->reply->code = PW_CODE_ACCESS_CHALLENGE; fr_state_put_vps(request, request->packet, request->reply); return RLM_MODULE_OK; /* * ALL other replies mean reject. (this is fail-safe) * * Do NOT do any authorization or authentication. They * are being rejected, so we minimize the amount of work * done by the server, by rejecting them here. */ case PW_CODE_ACCESS_REJECT: rad_authlog("Login incorrect (Home Server says so)", request, 0); request->reply->code = PW_CODE_ACCESS_REJECT; fr_state_discard(request, request->packet); return RLM_MODULE_REJECT; default: rad_authlog("Login incorrect (Home Server failed to respond)", request, 0); fr_state_discard(request, request->packet); return RLM_MODULE_REJECT; } } #endif /* * Look for, and cache, passwords. */ if (!request->password) { request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY); } if (!request->password) { request->password = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY); } /* * Grab the VPS associated with the State attribute. */ fr_state_get_vps(request, request->packet); /* * Get the user's authorization information from the database */ autz_redo: result = process_authorize(autz_type, request); switch (result) { case RLM_MODULE_NOOP: case RLM_MODULE_NOTFOUND: case RLM_MODULE_OK: case RLM_MODULE_UPDATED: break; case RLM_MODULE_HANDLED: return result; case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_REJECT: case RLM_MODULE_USERLOCK: default: if ((module_msg = pairfind(request->packet->vps, PW_MODULE_FAILURE_MESSAGE, 0, TAG_ANY)) != NULL) { char msg[MAX_STRING_LEN + 16]; snprintf(msg, sizeof(msg), "Invalid user (%s)", module_msg->vp_strvalue); rad_authlog(msg,request,0); } else { rad_authlog("Invalid user", request, 0); } request->reply->code = PW_CODE_ACCESS_REJECT; return result; } if (!autz_retry) { tmp = pairfind(request->config, PW_AUTZ_TYPE, 0, TAG_ANY); if (tmp) { autz_type = tmp->vp_integer; RDEBUG2("Using Autz-Type %s", dict_valnamebyattr(PW_AUTZ_TYPE, 0, autz_type)); autz_retry = 1; goto autz_redo; } } /* * If we haven't already proxied the packet, then check * to see if we should. Maybe one of the authorize * modules has decided that a proxy should be used. If * so, get out of here and send the packet. */ if ( #ifdef WITH_PROXY (request->proxy == NULL) && #endif ((tmp = pairfind(request->config, PW_PROXY_TO_REALM, 0, TAG_ANY)) != NULL)) { REALM *realm; realm = realm_find2(tmp->vp_strvalue); /* * Don't authenticate, as the request is going to * be proxied. */ if (realm && realm->auth_pool) { return RLM_MODULE_OK; } /* * Catch users who set Proxy-To-Realm to a LOCAL * realm (sigh). But don't complain if it is * *the* LOCAL realm. */ if (realm &&(strcmp(realm->name, "LOCAL") != 0)) { RWDEBUG2("You set Proxy-To-Realm = %s, but it is a LOCAL realm! Cancelling proxy request.", realm->name); } if (!realm) { RWDEBUG2("You set Proxy-To-Realm = %s, but the realm does not exist! Cancelling invalid proxy request.", tmp->vp_strvalue); } } #ifdef WITH_PROXY authenticate: #endif /* * Validate the user */ do { result = rad_check_password(request); if (result > 0) { return RLM_MODULE_HANDLED; } } while(0); /* * Failed to validate the user. * * We PRESUME that the code which failed will clean up * request->reply->vps, to be ONLY the reply items it * wants to send back. */ if (result < 0) { RDEBUG2("Failed to authenticate the user"); request->reply->code = PW_CODE_ACCESS_REJECT; if ((module_msg = pairfind(request->packet->vps, PW_MODULE_FAILURE_MESSAGE, 0, TAG_ANY)) != NULL){ char msg[MAX_STRING_LEN+19]; snprintf(msg, sizeof(msg), "Login incorrect (%s)", module_msg->vp_strvalue); rad_authlog(msg, request, 0); } else { rad_authlog("Login incorrect", request, 0); } if (request->password) { VERIFY_VP(request->password); /* double check: maybe the secret is wrong? */ if ((debug_flag > 1) && (request->password->da->attr == PW_USER_PASSWORD)) { uint8_t const *p; p = (uint8_t const *) request->password->vp_strvalue; while (*p) { int size; size = fr_utf8_char(p); if (!size) { RWDEBUG("Unprintable characters in the password. Double-check the " "shared secret on the server and the NAS!"); break; } p += size; } } } } #ifdef WITH_SESSION_MGMT if (result >= 0 && (check_item = pairfind(request->config, PW_SIMULTANEOUS_USE, 0, TAG_ANY)) != NULL) { int r, session_type = 0; char logstr[1024]; char umsg[MAX_STRING_LEN + 1]; tmp = pairfind(request->config, PW_SESSION_TYPE, 0, TAG_ANY); if (tmp) { session_type = tmp->vp_integer; RDEBUG2("Using Session-Type %s", dict_valnamebyattr(PW_SESSION_TYPE, 0, session_type)); } /* * User authenticated O.K. Now we have to check * for the Simultaneous-Use parameter. */ if (request->username && (r = process_checksimul(session_type, request, check_item->vp_integer)) != 0) { char mpp_ok = 0; if (r == 2){ /* Multilink attempt. Check if port-limit > simultaneous-use */ VALUE_PAIR *port_limit; if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT, 0, TAG_ANY)) != NULL && port_limit->vp_integer > check_item->vp_integer){ RDEBUG2("MPP is OK"); mpp_ok = 1; } } if (!mpp_ok){ if (check_item->vp_integer > 1) { snprintf(umsg, sizeof(umsg), "%s (%u)", main_config.denied_msg, check_item->vp_integer); } else { strlcpy(umsg, main_config.denied_msg, sizeof(umsg)); } request->reply->code = PW_CODE_ACCESS_REJECT; /* * They're trying to log in too many times. * Remove ALL reply attributes. */ pairfree(&request->reply->vps); pairmake_reply("Reply-Message", umsg, T_OP_SET); snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s", check_item->vp_integer, r == 2 ? "[MPP attempt]" : ""); rad_authlog(logstr, request, 1); result = -1; } } } #endif /* * Result should be >= 0 here - if not, it means the user * is rejected, so we just process post-auth and return. */ if (result < 0) { return RLM_MODULE_REJECT; } /* * Set the reply to Access-Accept, if it hasn't already * been set to something. (i.e. Access-Challenge) */ if (request->reply->code == 0) request->reply->code = PW_CODE_ACCESS_ACCEPT; if ((module_msg = pairfind(request->packet->vps, PW_MODULE_SUCCESS_MESSAGE, 0, TAG_ANY)) != NULL){ char msg[MAX_STRING_LEN+12]; snprintf(msg, sizeof(msg), "Login OK (%s)", module_msg->vp_strvalue); rad_authlog(msg, request, 1); } else { rad_authlog("Login OK", request, 1); } return result; }
/* * If we're proxying EAP, then there may be magic we need * to do. */ static rlm_rcode_t mod_post_proxy(void *inst, REQUEST *request) { size_t i; size_t len; VALUE_PAIR *vp; eap_handler_t *handler; /* * Just in case the admin lists EAP in post-proxy-type Fail. */ if (!request->proxy_reply) return RLM_MODULE_NOOP; /* * If there was a handler associated with this request, * then it's a tunneled request which was proxied... */ handler = request_data_get(request, inst, REQUEST_DATA_eap_handler_t); if (handler != NULL) { rlm_rcode_t rcode; eap_tunnel_data_t *data; /* * Grab the tunnel callbacks from the request. */ data = (eap_tunnel_data_t *) request_data_get(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK); if (!data) { radlog_request(L_ERR, 0, request, "Failed to retrieve callback for tunneled session!"); eap_handler_free(inst, handler); return RLM_MODULE_FAIL; } /* * Do the callback... */ RDEBUG2("Doing post-proxy callback"); rcode = data->callback(handler, data->tls_session); free(data); if (rcode == 0) { RDEBUG2("Failed in post-proxy callback"); eap_fail(handler); eap_handler_free(inst, handler); return RLM_MODULE_REJECT; } /* * We are done, wrap the EAP-request in RADIUS to send * with all other required radius attributes */ eap_compose(handler); /* * Add to the list only if it is EAP-Request, OR if * it's LEAP, and a response. */ if ((handler->eap_ds->request->code == PW_EAP_REQUEST) && (handler->eap_ds->request->type.num >= PW_EAP_MD5)) { if (!eaplist_add(inst, handler)) { eap_fail(handler); eap_handler_free(inst, handler); return RLM_MODULE_FAIL; } } else { /* couldn't have been LEAP, there's no tunnel */ RDEBUG2("Freeing handler"); /* handler is not required any more, free it now */ eap_handler_free(inst, handler); } /* * If it's an Access-Accept, RFC 2869, Section 2.3.1 * says that we MUST include a User-Name attribute in the * Access-Accept. */ if ((request->reply->code == PW_AUTHENTICATION_ACK) && request->username) { /* * Doesn't exist, add it in. */ vp = pairfind(request->reply->vps, PW_USER_NAME, 0, TAG_ANY); if (!vp) { pairmake_reply("User-Name", request->username->vp_strvalue, T_OP_EQ); } } return RLM_MODULE_OK; } else { RDEBUG2("No pre-existing handler found"); } /* * There may be more than one Cisco-AVPair. * Ensure we find the one with the LEAP attribute. */ vp = request->proxy_reply->vps; for (;;) { /* * Hmm... there's got to be a better way to * discover codes for vendor attributes. * * This is vendor Cisco (9), Cisco-AVPair * attribute (1) */ vp = pairfind(vp, 1, 9, TAG_ANY); if (!vp) { return RLM_MODULE_NOOP; } /* * If it's "leap:session-key", then stop. * * The format is VERY specific! */ if (strncasecmp(vp->vp_strvalue, "leap:session-key=", 17) == 0) { break; } /* * Not this AV-pair. Go to the next one. */ vp = vp->next; } /* * The format is very specific. */ if (vp->length != 17 + 34) { RDEBUG2("Cisco-AVPair with leap:session-key has incorrect length %d: Expected %d", vp->length, 17 + 34); return RLM_MODULE_NOOP; } /* * Decrypt the session key, using the proxy data. */ i = 34; /* starts off with 34 octets */ len = rad_tunnel_pwdecode(vp->vp_octets + 17, &i, request->home_server->secret, request->proxy->vector); /* * FIXME: Assert that i == 16. */ /* * Encrypt the session key again, using the request data. */ rad_tunnel_pwencode(vp->vp_strvalue + 17, &len, request->client->secret, request->packet->vector); return RLM_MODULE_UPDATED; }
/* * For backwards compatibility. */ static rlm_rcode_t mod_authenticate(void *instance, REQUEST *request) { rlm_eap_t *inst; eap_handler_t *handler; eap_packet_raw_t *eap_packet; eap_rcode_t status; rlm_rcode_t rcode; inst = (rlm_eap_t *) instance; if (!pairfind(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY)) { RDEBUGE("You set 'Auth-Type = EAP' for a request that does " "not contain an EAP-Message attribute!"); return RLM_MODULE_INVALID; } /* * Get the eap packet to start with */ eap_packet = eap_vp2packet(request, request->packet->vps); if (!eap_packet) { radlog_request(L_ERR, 0, request, "Malformed EAP Message"); return RLM_MODULE_FAIL; } /* * Create the eap handler. The eap_packet will end up being * "swallowed" into the handler, so we can't access it after * this call. */ handler = eap_handler(inst, &eap_packet, request); if (!handler) { RDEBUG2("Failed in handler"); return RLM_MODULE_INVALID; } /* * Select the appropriate method or default to the * configured one */ status = eap_method_select(inst, handler); /* * If it failed, die. */ if (status == EAP_INVALID) { eap_fail(handler); eap_handler_free(inst, handler); RDEBUG2("Failed in EAP select"); return RLM_MODULE_INVALID; } #ifdef WITH_PROXY /* * If we're doing horrible tunneling work, remember it. */ if ((request->options & RAD_REQUEST_OPTION_PROXY_EAP) != 0) { RDEBUG2(" Not-EAP proxy set. Not composing EAP"); /* * Add the handle to the proxied list, so that we * can retrieve it in the post-proxy stage, and * send a response. */ handler->inst_holder = inst; status = request_data_add(request, inst, REQUEST_DATA_eap_handler_t, handler, (void *) eap_opaque_free); rad_assert(status == 0); return RLM_MODULE_HANDLED; } #endif #ifdef WITH_PROXY /* * Maybe the request was marked to be proxied. If so, * proxy it. */ if (request->proxy != NULL) { VALUE_PAIR *vp = NULL; rad_assert(!request->proxy_reply); /* * Add the handle to the proxied list, so that we * can retrieve it in the post-proxy stage, and * send a response. */ handler->inst_holder = inst; status = request_data_add(request, inst, REQUEST_DATA_eap_handler_t, handler, (void *) eap_opaque_free); rad_assert(status == 0); /* * Some simple sanity checks. These should really * be handled by the radius library... */ vp = pairfind(request->proxy->vps, PW_EAP_MESSAGE, 0, TAG_ANY); if (vp) { vp = pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); if (!vp) { pairmake(request->proxy, &request->proxy->vps, "Message-Authenticator", "0x00", T_OP_EQ); } } /* * Delete the "proxied to" attribute, as it's * set to 127.0.0.1 for tunneled requests, and * we don't want to tell the world that... */ pairdelete(&request->proxy->vps, PW_FREERADIUS_PROXIED_TO, VENDORPEC_FREERADIUS, TAG_ANY); RDEBUG2(" Tunneled session will be proxied. Not doing EAP."); return RLM_MODULE_HANDLED; } #endif /* * We are done, wrap the EAP-request in RADIUS to send * with all other required radius attributes */ rcode = eap_compose(handler); /* * Add to the list only if it is EAP-Request, OR if * it's LEAP, and a response. */ if (((handler->eap_ds->request->code == PW_EAP_REQUEST) && (handler->eap_ds->request->type.num >= PW_EAP_MD5)) || /* * LEAP is a little different. At Stage 4, * it sends an EAP-Success message, but we still * need to keep the State attribute & session * data structure around for the AP Challenge. * * At stage 6, LEAP sends an EAP-Response, which * isn't put into the list. */ ((handler->eap_ds->response->code == PW_EAP_RESPONSE) && (handler->eap_ds->response->type.num == PW_EAP_LEAP) && (handler->eap_ds->request->code == PW_EAP_SUCCESS) && (handler->eap_ds->request->type.num == 0))) { /* * Return FAIL if we can't remember the handler. * This is actually disallowed by the * specification, as unexpected FAILs could have * been forged. However, we want to signal to * everyone else involved that we are * intentionally failing the session, as opposed * to accidentally failing it. */ if (!eaplist_add(inst, handler)) { RDEBUG("Failed adding handler to the list"); eap_fail(handler); eap_handler_free(inst, handler); return RLM_MODULE_FAIL; } } else { RDEBUG2("Freeing handler"); /* handler is not required any more, free it now */ eap_handler_free(inst, handler); } /* * If it's an Access-Accept, RFC 2869, Section 2.3.1 * says that we MUST include a User-Name attribute in the * Access-Accept. */ if ((request->reply->code == PW_AUTHENTICATION_ACK) && request->username) { VALUE_PAIR *vp; /* * Doesn't exist, add it in. */ vp = pairfind(request->reply->vps, PW_USER_NAME, 0, TAG_ANY); if (!vp) { vp = pairmake_reply("User-Name", "", T_OP_EQ); strlcpy(vp->vp_strvalue, request->username->vp_strvalue, sizeof(vp->vp_strvalue)); vp->length = request->username->length; } /* * Cisco AP1230 has a bug and needs a zero * terminated string in Access-Accept. */ if ((inst->mod_accounting_username_bug) && (vp->length < (int) sizeof(vp->vp_strvalue))) { vp->vp_strvalue[vp->length] = '\0'; vp->length++; } } return rcode; }
/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request) { rlm_sqlcounter_t *inst = instance; int rcode = RLM_MODULE_NOOP; uint64_t counter, res; DICT_ATTR const *da; VALUE_PAIR *key_vp, *limit; VALUE_PAIR *reply_item; char msg[128]; char query[MAX_QUERY_LEN], subst[MAX_QUERY_LEN]; char *expanded = NULL; size_t len; /* * Before doing anything else, see if we have to reset * the counters. */ if (inst->reset_time && (inst->reset_time <= request->timestamp)) { /* * Re-set the next time and prev_time for this counters range */ inst->last_reset = inst->reset_time; find_next_reset(inst,request->timestamp); } /* * Look for the key. User-Name is special. It means * The REAL username, after stripping. */ if ((inst->key_attr->vendor == 0) && (inst->key_attr->attr == PW_USER_NAME)) { key_vp = request->username; } else { key_vp = pairfind(request->packet->vps, inst->key_attr->attr, inst->key_attr->vendor, TAG_ANY); } if (!key_vp) { RWDEBUG2("Couldn't find key attribute 'request:%s'", inst->key_attr->name); return rcode; } /* * Look for the check item */ if ((da = dict_attrbyname(inst->limit_name)) == NULL) { return rcode; } limit = pairfind(request->config_items, da->attr, da->vendor, TAG_ANY); if (limit == NULL) { RWDEBUG2("Couldn't find control attribute 'control:%s'", inst->limit_name); return rcode; } /* First, expand %k, %b and %e in query */ if (sqlcounter_expand(subst, sizeof(subst), inst->query, inst) <= 0) { REDEBUG("Insufficient query buffer space"); return RLM_MODULE_FAIL; } /* Then combine that with the name of the module were using to do the query */ len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, subst); if (len >= (sizeof(query) - 1)) { REDEBUG("Insufficient query buffer space"); return RLM_MODULE_FAIL; } /* Finally, xlat resulting SQL query */ if (radius_axlat(&expanded, request, query, NULL, NULL) < 0) { return RLM_MODULE_FAIL; } talloc_free(expanded); if (sscanf(expanded, "%" PRIu64, &counter) != 1) { RDEBUG2("No integer found in result string \"%s\". May be first session, setting counter to 0", expanded); counter = 0; } /* * Check if check item > counter */ if (limit->vp_integer64 <= counter) { /* User is denied access, send back a reply message */ snprintf(msg, sizeof(msg), "Your maximum %s usage time has been reached", inst->reset); pairmake_reply("Reply-Message", msg, T_OP_EQ); REDEBUG2("Maximum %s usage time reached", inst->reset); REDEBUG2("Rejecting user, control:%s value (%" PRIu64 ") is less than counter value (%" PRIu64 ")", inst->limit_name, limit->vp_integer64, counter); return RLM_MODULE_REJECT; } res = limit->vp_integer64 - counter; RDEBUG2("Allowing user, control:%s value (%" PRIu64 ") is greater than counter value (%" PRIu64 ")", inst->limit_name, limit->vp_integer64, counter); /* * We are assuming that simultaneous-use=1. But * even if that does not happen then our user * could login at max for 2*max-usage-time Is * that acceptable? */ /* * If we are near a reset then add the next * limit, so that the user will not need to login * again. Do this only for Session-Timeout. */ if (((inst->reply_attr->vendor == 0) && (inst->reply_attr->attr == PW_SESSION_TIMEOUT)) && inst->reset_time && ((int) res >= (inst->reset_time - request->timestamp))) { res = (inst->reset_time - request->timestamp); res += limit->vp_integer; } /* * Limit the reply attribute to the minimum of the existing value, or this new one. */ reply_item = pairfind(request->reply->vps, inst->reply_attr->attr, inst->reply_attr->vendor, TAG_ANY); if (reply_item) { if (reply_item->vp_integer64 <= res) { RDEBUG2("Leaving existing reply:%s value of %" PRIu64, inst->reply_attr->name, reply_item->vp_integer64); return RLM_MODULE_OK; } } else { reply_item = radius_paircreate(request->reply, &request->reply->vps, inst->reply_attr->attr, inst->reply_attr->vendor); } reply_item->vp_integer64 = res; RDEBUG2("Setting reply:%s value to %" PRIu64, inst->reply_name, reply_item->vp_integer64); return RLM_MODULE_OK; }
/* * Authenticate the user with the given password. */ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request) { rlm_smsotp_t *inst = instance; VALUE_PAIR *state; int bufsize; int *fdp; rlm_rcode_t rcode = RLM_MODULE_FAIL; char buffer[1000]; char output[1000]; fdp = fr_connection_get(inst->pool); if (!fdp) return RLM_MODULE_FAIL; /* Get greeting */ bufsize = read_all(fdp, buffer, sizeof(buffer)); if (bufsize <= 0) { REDEBUG("Failed reading from socket"); goto done; } /* * Look for the 'state' attribute. */ #define WRITE_ALL(_a,_b,_c) if (write_all(_a,_b,_c) < 0) goto done; state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY); if (state) { RDEBUG("Found reply to access challenge"); /* send username */ snprintf(output, sizeof(output), "check otp for %s\n", request->username->vp_strvalue); WRITE_ALL(fdp, output, strlen(output)); (void) read_all(fdp, buffer, sizeof(buffer)); /* send password */ snprintf(output, sizeof(output), "user otp is %s\n", request->password->vp_strvalue); WRITE_ALL(fdp, output, strlen(output)); (void) read_all(fdp, buffer, sizeof(buffer)); /* set uuid */ snprintf(output, sizeof(output), "otp id is %s\n", state->vp_strvalue); WRITE_ALL(fdp, output, strlen(output)); (void) read_all(fdp, buffer, sizeof(buffer)); /* now check the otp */ WRITE_ALL(fdp, "get check result\n", 17); (void) read_all(fdp, buffer, sizeof(buffer)); /* end the sesssion */ WRITE_ALL(fdp, "quit\n", 5); RDEBUG("answer is %s", buffer); if (strcmp(buffer,"OK") == 0) { rcode = RLM_MODULE_OK; } goto done; } RDEBUG("Generating OTP"); /* set username */ snprintf(output, sizeof(output), "generate otp for %s\n", request->username->vp_strvalue); WRITE_ALL(fdp, output, strlen(output)); (void) read_all(fdp, buffer, sizeof(buffer)); /* end the sesssion */ WRITE_ALL(fdp, "quit\n", 5); RDEBUG("Unique ID is %s", buffer); /* check the return string */ if (strcmp(buffer,"FAILED") == 0) { /* smsotp script returns a error */ goto done; } /* * Create the challenge, and add it to the reply. */ pairmake_reply("Reply-Message", inst->challenge, T_OP_EQ); pairmake_reply("State", buffer, T_OP_EQ); /* * Mark the packet as an Access-Challenge packet. * * The server will take care of sending it to the user. */ request->reply->code = PW_CODE_ACCESS_CHALLENGE; DEBUG("rlm_smsotp: Sending Access-Challenge"); rcode = RLM_MODULE_HANDLED; done: fr_connection_release(inst->pool, fdp); return rcode; }
/* * Add a session to the set of active sessions. * * Since we're adding it to the list, we guess that this means * the packet needs a State attribute. So add one. */ int securid_sessionlist_add(rlm_securid_t *inst,REQUEST *request, SECURID_SESSION *session) { int status = 0; VALUE_PAIR *state; /* * The time at which this request was made was the time * at which it was received by the RADIUS server. */ session->timestamp = request->timestamp; session->src_ipaddr = request->packet->src_ipaddr; /* * Playing with a data structure shared among threads * means that we need a lock, to avoid conflict. */ pthread_mutex_lock(&(inst->session_mutex)); /* * If we have a DoS attack, discard new sessions. */ if (rbtree_num_elements(inst->session_tree) >= inst->max_sessions) { securid_sessionlist_clean_expired(inst, request, session->timestamp); goto done; } if (session->session_id == 0) { /* this is a NEW session (we are not inserting an updated session) */ inst->last_session_id++; session->session_id = inst->last_session_id; RDEBUG2("Creating a new session with id=%d\n",session->session_id); } snprintf(session->state,sizeof(session->state)-1,"FRR-CH %d|%d",session->session_id,session->trips+1); RDEBUG2("Inserting session id=%d identity='%s' state='%s' to the session list", session->session_id,SAFE_STR(session->identity),session->state); /* * Generate State, since we've been asked to add it to * the list. */ state = pairmake_reply("State", session->state, T_OP_EQ); if (!state) return -1; state->vp_length = SECURID_STATE_LEN; status = rbtree_insert(inst->session_tree, session); if (status) { /* tree insert SUCCESS */ /* insert the session to the linked list of sessions */ SECURID_SESSION *prev; prev = inst->session_tail; if (prev) { /* insert to the tail of the list */ prev->next = session; session->prev = prev; session->next = NULL; inst->session_tail = session; } else { /* 1st time */ inst->session_head = inst->session_tail = session; session->next = session->prev = NULL; } } /* * Now that we've finished mucking with the list, * unlock it. */ done: pthread_mutex_unlock(&(inst->session_mutex)); if (!status) { pairfree(&state); ERROR("rlm_securid: Failed to store session"); return -1; } return 0; }
static int eap_example_server_step(EAP_HANDLER *handler) { int res, process = 0; REQUEST *request = handler->request; res = eap_server_sm_step(handler->server_ctx.eap); if (handler->server_ctx.eap_if->eapReq) { DEBUG("==> Request"); process = 1; handler->server_ctx.eap_if->eapReq = 0; } if (handler->server_ctx.eap_if->eapSuccess) { DEBUG("==> Success"); process = 1; res = 0; if (handler->server_ctx.eap_if->eapKeyAvailable) { int length = handler->server_ctx.eap_if->eapKeyDataLen; VALUE_PAIR *vp; if (length > 64) { length = 32; } else { length /= 2; /* * FIXME: Length is zero? */ } vp = pairmake_reply("MS-MPPE-Recv-Key", NULL, T_OP_EQ); if (vp) { pairmemcpy(vp, handler->server_ctx.eap_if->eapKeyData, length); } vp = pairmake_reply("MS-MPPE-Send-Key", NULL, T_OP_EQ); if (vp) { pairmemcpy(vp, handler->server_ctx.eap_if->eapKeyData + length, length); } } } if (handler->server_ctx.eap_if->eapFail) { DEBUG("==> Fail"); process = 1; } if (process) { if (wpabuf_head(handler->server_ctx.eap_if->eapReqData)) { if (!eap_req2vp(handler)) return -1; } else { return -1; } } return res; }
/* * Add a handler to the set of active sessions. * * Since we're adding it to the list, we guess that this means * the packet needs a State attribute. So add one. */ static int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler) { int i, status; uint32_t lvalue; VALUE_PAIR *state; REQUEST *request = handler->request; rad_assert(handler != NULL); rad_assert(handler->request != NULL); /* * Generate State, since we've been asked to add it to * the list. */ state = pairmake_reply("State", NULL, T_OP_EQ); if (!state) return 0; state->length = EAP_STATE_LEN; /* * The time at which this request was made was the time * at which it was received by the RADIUS server. */ handler->timestamp = handler->request->timestamp; handler->src_ipaddr = handler->request->packet->src_ipaddr; /* * We don't need this any more. */ handler->request = NULL; /* * Playing with a data structure shared among threads * means that we need a lock, to avoid conflict. */ pthread_mutex_lock(&(inst->session_mutex)); /* * Create a completely random state. */ for (i = 0; i < 4; i++) { lvalue = eap_rand(&inst->rand_pool); memcpy(state->vp_octets + i * 4, &lvalue, sizeof(lvalue)); } memcpy(handler->state, state->vp_strvalue, sizeof(handler->state)); /* * Big-time failure. */ status = rbtree_insert(inst->session_tree, handler); if (status) { EAP_HANDLER *prev; prev = inst->session_tail; if (prev) { prev->next = handler; handler->prev = prev; handler->next = NULL; inst->session_tail = handler; } else { inst->session_head = inst->session_tail = handler; handler->next = handler->prev = NULL; } } /* * Now that we've finished mucking with the list, * unlock it. */ pthread_mutex_unlock(&(inst->session_mutex)); if (!status) { ERROR("rlm_eap2: Failed to remember handler!"); eap_handler_free(handler); return 0; } return 1; }
/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static rlm_rcode_t mod_authorize(UNUSED void *instance, UNUSED REQUEST *request) { rlm_sqlcounter_t *inst = instance; int rcode = RLM_MODULE_NOOP; uint64_t counter, res; DICT_ATTR const *dattr; VALUE_PAIR *key_vp, *check_vp; VALUE_PAIR *reply_item; char msg[128]; char *p; char query[MAX_QUERY_LEN]; char *expanded = NULL; size_t len; /* * Before doing anything else, see if we have to reset * the counters. */ if (inst->reset_time && (inst->reset_time <= request->timestamp)) { /* * Re-set the next time and prev_time for this counters range */ inst->last_reset = inst->reset_time; find_next_reset(inst,request->timestamp); } /* * Look for the key. User-Name is special. It means * The REAL username, after stripping. */ RDEBUG2("Entering module authorize code"); key_vp = ((inst->key_attr->vendor == 0) && (inst->key_attr->attr == PW_USER_NAME)) ? request->username : pairfind(request->packet->vps, inst->key_attr->attr, inst->key_attr->vendor, TAG_ANY); if (!key_vp) { RDEBUG2("Could not find Key value pair"); return rcode; } /* * Look for the check item */ if ((dattr = dict_attrbyname(inst->check_name)) == NULL) { return rcode; } /* DEBUG2("rlm_sqlcounter: Found Check item attribute %d", dattr->attr); */ if ((check_vp = pairfind(request->config_items, dattr->attr, dattr->vendor, TAG_ANY)) == NULL) { RDEBUG2("Could not find Check item value pair"); return rcode; } len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, query); if (len >= sizeof(query) - 1) { REDEBUG("Insufficient query buffer space"); return RLM_MODULE_FAIL; } p = query + len; /* first, expand %k, %b and %e in query */ len = sqlcounter_expand(p, p - query, inst->query, inst); if (len <= 0) { REDEBUG("Insufficient query buffer space"); return RLM_MODULE_FAIL; } p += len; if ((p - query) < 2) { REDEBUG("Insufficient query buffer space"); return RLM_MODULE_FAIL; } p[0] = '}'; p[1] = '\0'; /* Finally, xlat resulting SQL query */ if (radius_axlat(&expanded, request, query, NULL, NULL) < 0) { return RLM_MODULE_FAIL; } if (sscanf(expanded, "%" PRIu64, &counter) != 1) { RDEBUG2("No integer found in string \"%s\"", expanded); return RLM_MODULE_NOOP; } talloc_free(expanded); /* * Check if check item > counter */ if (check_vp->vp_integer64 <= counter) { RDEBUG2("(Check item - counter) is less than zero"); /* * User is denied access, send back a reply message */ snprintf(msg, sizeof(msg), "Your maximum %s usage time has been reached", inst->reset); pairmake_reply("Reply-Message", msg, T_OP_EQ); REDEBUG("Maximum %s usage time reached", inst->reset); rcode = RLM_MODULE_REJECT; RDEBUG2("Rejected user %s, check_item=%" PRIu64 ", counter=%" PRIu64, key_vp->vp_strvalue, check_vp->vp_integer64, counter); return RLM_MODULE_REJECT; } res = check_vp->vp_integer64 - counter; RDEBUG2("Check item is greater than query result"); /* * We are assuming that simultaneous-use=1. But * even if that does not happen then our user * could login at max for 2*max-usage-time Is * that acceptable? */ /* * If we are near a reset then add the next * limit, so that the user will not need to login * again. Do this only for Session-Timeout. */ if ((inst->reply_attr->attr == PW_SESSION_TIMEOUT) && inst->reset_time && ((int) res >= (inst->reset_time - request->timestamp))) { res = inst->reset_time - request->timestamp; res += check_vp->vp_integer; } /* * Limit the reply attribute to the minimum of * the existing value, or this new one. */ reply_item = pairfind(request->reply->vps, inst->reply_attr->attr, inst->reply_attr->vendor, TAG_ANY); if (reply_item) { if (reply_item->vp_integer64 > res) { reply_item->vp_integer64 = res; } } else { reply_item = radius_paircreate(request, &request->reply->vps, inst->reply_attr->attr, inst->reply_attr->vendor); reply_item->vp_integer64 = res; } RDEBUG2("Authorized user %s, check_item=%" PRIu64 ", counter=%" PRIu64 , key_vp->vp_strvalue, check_vp->vp_integer64, counter); RDEBUG2("Sent Reply-Item for user %s, Type=%s, value=%" PRIu64, key_vp->vp_strvalue, inst->reply_name, reply_item->vp_integer64); return RLM_MODULE_OK; }
/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, UNUSED REQUEST *request) { rlm_counter_t *inst = instance; rlm_rcode_t rcode = RLM_MODULE_NOOP; datum key_datum; datum count_datum; rad_counter counter; VALUE_PAIR *key_vp, *check_vp; VALUE_PAIR *reply_item; char msg[128]; /* * Before doing anything else, see if we have to reset * the counters. */ if (inst->reset_time && (inst->reset_time <= request->timestamp)) { rlm_rcode_t rcode2; inst->last_reset = inst->reset_time; find_next_reset(inst,request->timestamp); pthread_mutex_lock(&inst->mutex); rcode2 = reset_db(inst); pthread_mutex_unlock(&inst->mutex); if (rcode2 != RLM_MODULE_OK) { return rcode2; } } /* * Look for the key. User-Name is special. It means * The REAL username, after stripping. */ DEBUG2("rlm_counter: Entering module authorize code"); key_vp = (inst->key_attr->attr == PW_USER_NAME) ? request->username : pair_find_by_da(request->packet->vps, inst->key_attr, TAG_ANY); if (!key_vp) { DEBUG2("rlm_counter: Could not find Key value pair"); return rcode; } /* * Look for the check item */ if ((check_vp = pair_find_by_da(request->config_items, inst->check_attr, TAG_ANY)) == NULL) { DEBUG2("rlm_counter: Could not find Check item value pair"); return rcode; } ASSIGN(key_datum.dptr, key_vp->vp_strvalue); key_datum.dsize = key_vp->length; /* * Init to be sure */ counter.user_counter = 0; DEBUG("rlm_counter: Searching the database for key '%s'",key_vp->vp_strvalue); pthread_mutex_lock(&inst->mutex); count_datum = gdbm_fetch(inst->gdbm, key_datum); pthread_mutex_unlock(&inst->mutex); if (count_datum.dptr != NULL) { DEBUG("rlm_counter: Key Found"); memcpy(&counter, count_datum.dptr, sizeof(rad_counter)); free(count_datum.dptr); } else DEBUG("rlm_counter: Could not find the requested key in the database"); /* * Check if check item > counter */ DEBUG("rlm_counter: Check item = %d, Count = %d",check_vp->vp_integer,counter.user_counter); if (check_vp->vp_integer > counter.user_counter) { unsigned int res; res = check_vp->vp_integer - counter.user_counter; DEBUG("rlm_counter: res is greater than zero"); if (inst->count_attr->attr == PW_ACCT_SESSION_TIME) { /* * Do the following only if the count attribute is * AcctSessionTime */ /* * We are assuming that simultaneous-use=1. But * even if that does not happen then our user * could login at max for 2*max-usage-time Is * that acceptable? */ /* * User is allowed, but set Session-Timeout. * Stolen from main/auth.c */ /* * If we are near a reset then add the next * limit, so that the user will not need to * login again * Before that set the return value to the time * remaining to next reset */ if (inst->reset_time && (res >= (inst->reset_time - request->timestamp))) { res = inst->reset_time - request->timestamp; res += check_vp->vp_integer; } reply_item = pairfind(request->reply->vps, PW_SESSION_TIMEOUT, 0, TAG_ANY); if (reply_item) { if (reply_item->vp_integer > res) { reply_item->vp_integer = res; } } else { reply_item = radius_paircreate(request->reply, &request->reply->vps, PW_SESSION_TIMEOUT, 0); reply_item->vp_integer = res; } } else if (inst->reply_attr) { reply_item = pair_find_by_da(request->reply->vps, inst->reply_attr, TAG_ANY); if (reply_item) { if (reply_item->vp_integer > res) { reply_item->vp_integer = res; } } else { reply_item = radius_paircreate(request->reply, &request->reply->vps, inst->reply_attr->attr, inst->reply_attr->vendor); reply_item->vp_integer = res; } } rcode = RLM_MODULE_OK; DEBUG2("rlm_counter: (Check item - counter) is greater than zero"); DEBUG2("rlm_counter: Authorized user %s, check_item=%d, counter=%d", key_vp->vp_strvalue,check_vp->vp_integer,counter.user_counter); DEBUG2("rlm_counter: Sent Reply-Item for user %s, Type=Session-Timeout, value=%d", key_vp->vp_strvalue,res); } else { /* * User is denied access, send back a reply message */ sprintf(msg, "Your maximum %s usage time has been reached", inst->reset); pairmake_reply("Reply-Message", msg, T_OP_EQ); REDEBUG("Maximum %s usage time reached", inst->reset); rcode = RLM_MODULE_REJECT; DEBUG2("rlm_counter: Rejected user %s, check_item=%d, counter=%d", key_vp->vp_strvalue,check_vp->vp_integer,counter.user_counter); } return rcode; }
/* * Add a handler to the set of active sessions. * * Since we're adding it to the list, we guess that this means * the packet needs a State attribute. So add one. */ int eaplist_add(rlm_eap_t *inst, eap_handler_t *handler) { int status = 0; VALUE_PAIR *state; REQUEST *request = handler->request; rad_assert(handler != NULL); rad_assert(request != NULL); /* * Generate State, since we've been asked to add it to * the list. */ state = pairmake_reply("State", "0x00", T_OP_EQ); if (!state) return 0; /* * The time at which this request was made was the time * at which it was received by the RADIUS server. */ handler->timestamp = request->timestamp; handler->status = 1; handler->src_ipaddr = request->packet->src_ipaddr; handler->eap_id = handler->eap_ds->request->id; /* * Playing with a data structure shared among threads * means that we need a lock, to avoid conflict. */ PTHREAD_MUTEX_LOCK(&(inst->session_mutex)); /* * If we have a DoS attack, discard new sessions. */ if (rbtree_num_elements(inst->session_tree) >= inst->max_sessions) { status = -1; eaplist_expire(inst, request, handler->timestamp); goto done; } /* * Create a unique content for the State variable. * It will be modified slightly per round trip, but less so * than in 1.x. */ if (handler->trips == 0) { int i; for (i = 0; i < 4; i++) { uint32_t lvalue; lvalue = eap_rand(&inst->rand_pool); memcpy(handler->state + i * 4, &lvalue, sizeof(lvalue)); } } memcpy(state->vp_octets, handler->state, sizeof(handler->state)); state->length = EAP_STATE_LEN; /* * Add some more data to distinguish the sessions. */ state->vp_octets[4] = handler->trips ^ handler->state[0]; state->vp_octets[5] = handler->eap_id ^ handler->state[1]; state->vp_octets[6] = handler->type ^ handler->state[2]; /* * and copy the state back again. */ memcpy(handler->state, state->vp_octets, sizeof(handler->state)); /* * Big-time failure. */ status = rbtree_insert(inst->session_tree, handler); /* * Catch Access-Challenge without response. */ if (inst->handler_tree) { check_handler_t *check = rad_malloc(sizeof(*check)); check->inst = inst; check->handler = handler; check->trips = handler->trips; request_data_add(request, inst, 0, check, check_handler); } if (status) { eap_handler_t *prev; prev = inst->session_tail; if (prev) { prev->next = handler; handler->prev = prev; handler->next = NULL; inst->session_tail = handler; } else { inst->session_head = inst->session_tail = handler; handler->next = handler->prev = NULL; } } /* * Now that we've finished mucking with the list, * unlock it. */ done: /* * We don't need this any more. */ if (status > 0) handler->request = NULL; PTHREAD_MUTEX_UNLOCK(&(inst->session_mutex)); if (status <= 0) { pairfree(&state); if (status < 0) { static time_t last_logged = 0; if (last_logged < handler->timestamp) { last_logged = handler->timestamp; radlog(L_ERR, "rlm_eap (%s): Too many open " "sessions. Try increasing " "\"max_sessions\" in the EAP module " "configuration", inst->xlat_name); } } else { radlog(L_ERR, "rlm_eap (%s): Internal error: " "failed to store handler", inst->xlat_name); } return 0; } RDEBUG("New EAP session, adding 'State' attribute to reply " "0x%02x%02x%02x%02x%02x%02x%02x%02x", state->vp_octets[0], state->vp_octets[1], state->vp_octets[2], state->vp_octets[3], state->vp_octets[4], state->vp_octets[5], state->vp_octets[6], state->vp_octets[7]); return 1; }
/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static rlm_rcode_t mod_authorize(UNUSED void *instance, UNUSED REQUEST *request) { rlm_sqlcounter_t *inst = instance; int rcode = RLM_MODULE_NOOP; unsigned int counter; const DICT_ATTR *dattr; VALUE_PAIR *key_vp, *check_vp; VALUE_PAIR *reply_item; char msg[128]; char querystr[MAX_QUERY_LEN]; char sqlxlat[MAX_QUERY_LEN]; /* * Before doing anything else, see if we have to reset * the counters. */ if (inst->reset_time && (inst->reset_time <= request->timestamp)) { /* * Re-set the next time and prev_time for this counters range */ inst->last_reset = inst->reset_time; find_next_reset(inst,request->timestamp); } /* * Look for the key. User-Name is special. It means * The REAL username, after stripping. */ DEBUG2("rlm_sqlcounter: Entering module authorize code"); key_vp = ((inst->key_attr->vendor == 0) && (inst->key_attr->attr == PW_USER_NAME)) ? request->username : pairfind(request->packet->vps, inst->key_attr->attr, inst->key_attr->vendor, TAG_ANY); if (!key_vp) { DEBUG2("rlm_sqlcounter: Could not find Key value pair"); return rcode; } /* * Look for the check item */ if ((dattr = dict_attrbyname(inst->check_name)) == NULL) { return rcode; } /* DEBUG2("rlm_sqlcounter: Found Check item attribute %d", dattr->attr); */ if ((check_vp= pairfind(request->config_items, dattr->attr, dattr->vendor, TAG_ANY)) == NULL) { DEBUG2("rlm_sqlcounter: Could not find Check item value pair"); return rcode; } /* first, expand %k, %b and %e in query */ sqlcounter_expand(querystr, MAX_QUERY_LEN, inst->query, inst); /* next, wrap query with sql module & expand */ snprintf(sqlxlat, sizeof(sqlxlat), "%%{%s:%s}", inst->sqlmod_inst, querystr); /* Finally, xlat resulting SQL query */ radius_xlat(querystr, MAX_QUERY_LEN, sqlxlat, request, NULL, NULL); if (sscanf(querystr, "%u", &counter) != 1) { DEBUG2("rlm_sqlcounter: No integer found in string \"%s\"", querystr); return RLM_MODULE_NOOP; } /* * Check if check item > counter */ if (check_vp->vp_integer > counter) { unsigned int res = check_vp->vp_integer - counter; DEBUG2("rlm_sqlcounter: Check item is greater than query result"); /* * We are assuming that simultaneous-use=1. But * even if that does not happen then our user * could login at max for 2*max-usage-time Is * that acceptable? */ /* * If we are near a reset then add the next * limit, so that the user will not need to login * again. Do this only for Session-Timeout. */ if ((inst->reply_attr->attr == PW_SESSION_TIMEOUT) && inst->reset_time && (res >= (inst->reset_time - request->timestamp))) { res = inst->reset_time - request->timestamp; res += check_vp->vp_integer; } /* * Limit the reply attribute to the minimum of * the existing value, or this new one. */ reply_item = pairfind(request->reply->vps, inst->reply_attr->attr, inst->reply_attr->vendor, TAG_ANY); if (reply_item) { if (reply_item->vp_integer > res) reply_item->vp_integer = res; } else { reply_item = radius_paircreate(request, &request->reply->vps, inst->reply_attr->attr, inst->reply_attr->vendor); reply_item->vp_integer = res; } rcode = RLM_MODULE_OK; DEBUG2("rlm_sqlcounter: Authorized user %s, check_item=%u, counter=%u", key_vp->vp_strvalue,check_vp->vp_integer,counter); DEBUG2("rlm_sqlcounter: Sent Reply-Item for user %s, Type=%s, value=%u", key_vp->vp_strvalue,inst->reply_name,reply_item->vp_integer); } else { DEBUG2("rlm_sqlcounter: (Check item - counter) is less than zero"); /* * User is denied access, send back a reply message */ snprintf(msg, sizeof(msg), "Your maximum %s usage time has been reached", inst->reset); pairmake_reply("Reply-Message", msg, T_OP_EQ); RDEBUGE("Maximum %s usage time reached", inst->reset); rcode = RLM_MODULE_REJECT; DEBUG2("rlm_sqlcounter: Rejected user %s, check_item=%u, counter=%u", key_vp->vp_strvalue,check_vp->vp_integer,counter); } return rcode; }