/*
* 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_authenticate(UNUSED void *instance,
REQUEST *request)
{
VALUE_PAIR *passwd_item, *chap;
uint8_t pass_str[MAX_STRING_LEN];
if (!request->username) {
RWDEBUG("Attribute 'User-Name' is required for authentication.\n");
return RLM_MODULE_INVALID;
}
chap = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
if (!chap) {
REDEBUG("You set 'Auth-Type = CHAP' for a request that does not contain a CHAP-Password attribute!");
return RLM_MODULE_INVALID;
}
if (chap->vp_length == 0) {
REDEBUG("CHAP-Password is empty");
return RLM_MODULE_INVALID;
}
if (chap->vp_length != CHAP_VALUE_LENGTH + 1) {
REDEBUG("CHAP-Password has invalid length");
return RLM_MODULE_INVALID;
}
/*
* Don't print out the CHAP password here. It's binary crap.
*/
RDEBUG("Login attempt by \"%s\" with CHAP password",
request->username->vp_strvalue);
if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL){
if (pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY) != NULL){
REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
REDEBUG("!!! Please update your configuration so that the \"known !!!");
REDEBUG("!!! good\" cleartext password is in Cleartext-Password, !!!");
REDEBUG("!!! and NOT in User-Password. !!!");
REDEBUG("!!! !!!");
REDEBUG("!!! Authentication will fail because of this. !!!");
REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
REDEBUG("Cleartext password is required for authentication");
return RLM_MODULE_INVALID;
}
rad_chap_encode(request->packet, pass_str,
chap->vp_octets[0], passwd_item);
if (RDEBUG_ENABLED3) {
uint8_t const *p;
size_t length;
VALUE_PAIR *vp;
char buffer[CHAP_VALUE_LENGTH * 2 + 1];
RDEBUG3("Comparing with \"known good\" Cleartext-Password \"%s\"", passwd_item->vp_strvalue);
vp = pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
if (vp) {
p = vp->vp_octets;
length = vp->vp_length;
} else {
p = request->packet->vector;
length = sizeof(request->packet->vector);
}
fr_bin2hex(buffer, p, length);
RINDENT();
RDEBUG3("CHAP challenge : %s", buffer);
fr_bin2hex(buffer, chap->vp_octets + 1, CHAP_VALUE_LENGTH);
RDEBUG3("Client sent : %s", buffer);
fr_bin2hex(buffer, pass_str + 1, CHAP_VALUE_LENGTH);
RDEBUG3("We calculated : %s", buffer);
REXDENT();
} else {
RDEBUG2("Comparing with \"known good\" Cleartext-Password");
}
if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1,
CHAP_VALUE_LENGTH) != 0) {
REDEBUG("Password comparison failed: password is incorrect");
return RLM_MODULE_REJECT;
}
RDEBUG("CHAP user \"%s\" authenticated successfully",
request->username->vp_strvalue);
return RLM_MODULE_OK;
}
/*
* Dispatch an exec method
*/
static int exec_dispatch(void *instance, REQUEST *request)
{
rlm_exec_t *inst = (rlm_exec_t *) instance;
int result;
VALUE_PAIR **input_pairs, **output_pairs;
VALUE_PAIR *answer = NULL;
char msg[1024];
size_t len;
/*
* We need a program to execute.
*/
if (!inst->program) {
radlog(L_ERR, "rlm_exec (%s): We require a program to execute",
inst->xlat_name);
return RLM_MODULE_FAIL;
}
/*
* See if we're supposed to execute it now.
*/
if (!((inst->packet_code == 0) ||
(request->packet->code == inst->packet_code) ||
(request->reply->code == inst->packet_code)
#ifdef WITH_PROXY
|| (request->proxy &&
(request->proxy->code == inst->packet_code)) ||
(request->proxy_reply &&
(request->proxy_reply->code == inst->packet_code))
#endif
)) {
RDEBUG2("Packet type is not %s. Not executing.",
inst->packet_type);
return RLM_MODULE_NOOP;
}
/*
* Decide what input/output the program takes.
*/
input_pairs = decode_string(request, inst->input);
output_pairs = decode_string(request, inst->output);
if (!input_pairs) {
RDEBUG2("WARNING: Possible parse error in %s",
inst->input);
return RLM_MODULE_NOOP;
}
/*
* It points to the attribute list, but the attribute
* list is empty.
*/
if (!*input_pairs) {
RDEBUG2("WARNING! Input pairs are empty. No attributes will be passed to the script");
}
/*
* This function does it's own xlat of the input program
* to execute.
*
* FIXME: if inst->program starts with %{, then
* do an xlat ourselves. This will allow us to do
* program = %{Exec-Program}, which this module
* xlat's into it's string value, and then the
* exec program function xlat's it's string value
* into something else.
*/
result = radius_exec_program(inst->program, request,
inst->wait, msg, sizeof(msg),
*input_pairs, &answer, inst->shell_escape);
if (result < 0) {
radlog(L_ERR, "rlm_exec (%s): External script failed",
inst->xlat_name);
return RLM_MODULE_FAIL;
}
/*
* Move the answer over to the output pairs.
*
* If we're not waiting, then there are no output pairs.
*/
if (output_pairs) pairmove(output_pairs, &answer);
pairfree(&answer);
if (result == 0) {
return RLM_MODULE_OK;
}
if (result > RLM_MODULE_NUMCODES) {
return RLM_MODULE_FAIL;
}
/*
* Write any exec output to module failure message
*/
if (*msg) {
/* Trim off returns and newlines */
//.........这里部分代码省略.........
/** Convert group membership information into attributes
*
* @param[in] inst rlm_ldap configuration.
* @param[in] request Current request.
* @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
* @param[in] entry retrieved by rlm_ldap_find_user or rlm_ldap_search.
* @return One of the RLM_MODULE_* values.
*/
rlm_rcode_t rlm_ldap_cacheable_userobj(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
LDAPMessage *entry)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
char **vals;
char *group_name[LDAP_MAX_CACHEABLE + 1];
char **name_p = group_name;
char *group_dn[LDAP_MAX_CACHEABLE + 1];
char **dn_p;
char *name;
int is_dn, i;
/*
* Parse the membership information we got in the initial user query.
*/
vals = ldap_get_values((*pconn)->handle, entry, inst->userobj_membership_attr);
if (!vals) {
RDEBUG2("No cacheable group memberships found in user object");
return RLM_MODULE_OK;
}
for (i = 0; (vals[i] != NULL) && (i < LDAP_MAX_CACHEABLE); i++) {
is_dn = rlm_ldap_is_dn(vals[i]);
if (inst->cacheable_group_dn) {
/*
* The easy case, were caching DNs and we got a DN.
*/
if (is_dn) {
pairmake(request, &request->config_items, inst->group_da->name, vals[i], T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, vals[i]);
/*
* We were told to cache DNs but we got a name, we now need to resolve
* this to a DN. Store all the group names in an array so we can do one query.
*/
} else {
*name_p++ = vals[i];
}
}
if (inst->cacheable_group_name) {
/*
* The easy case, were caching names and we got a name.
*/
if (!is_dn) {
pairmake(request, &request->config_items, inst->group_da->name, vals[i], T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, vals[i]);
/*
* We were told to cache names but we got a DN, we now need to resolve
* this to a name.
* Only Active Directory supports filtering on DN, so we have to search
* for each individual group.
*/
} else {
rcode = rlm_ldap_group_dn2name(inst, request, pconn, vals[i], &name);
if (rcode != RLM_MODULE_OK) {
ldap_value_free(vals);
return rcode;
}
pairmake(request, &request->config_items, inst->group_da->name, name, T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, name);
talloc_free(name);
}
}
}
*name_p = NULL;
rcode = rlm_ldap_group_name2dn(inst, request, pconn, group_name, group_dn, sizeof(group_dn));
ldap_value_free(vals);
if (rcode != RLM_MODULE_OK) {
return rcode;
}
dn_p = group_dn;
while(*dn_p) {
pairmake(request, &request->config_items, inst->group_da->name, *dn_p, T_OP_ADD);
RDEBUG("Added %s with value \"%s\" to control list", inst->group_da->name, *dn_p);
ldap_memfree(*dn_p);
dn_p++;
}
//.........这里部分代码省略.........
/** Query the LDAP directory to check if a group object includes a user object as a member
*
* @param[in] inst rlm_ldap configuration.
* @param[in] request Current request.
* @param[in,out] pconn to use. May change as this function calls functions which auto re-connect.
* @param[in] check vp containing the group value (name or dn).
* @return One of the RLM_MODULE_* values.
*/
rlm_rcode_t rlm_ldap_check_groupobj_dynamic(ldap_instance_t const *inst, REQUEST *request, ldap_handle_t **pconn,
VALUE_PAIR *check)
{
ldap_rcode_t status;
char base_dn[LDAP_MAX_DN_STR_LEN + 1];
char filter[LDAP_MAX_FILTER_STR_LEN + 1];
char const *dn = base_dn;
char const *name = check->vp_strvalue;
RDEBUG2("Checking for user in group objects");
if (rlm_ldap_is_dn(name)) {
char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
if (rlm_ldap_xlat_filter(request,
filters, sizeof(filters) / sizeof(*filters),
filter, sizeof(filter)) < 0) {
return RLM_MODULE_INVALID;
}
dn = name;
} else {
char name_filter[LDAP_MAX_FILTER_STR_LEN];
char const *filters[] = { name_filter, inst->groupobj_filter, inst->groupobj_membership_filter };
if (!inst->groupobj_name_attr) {
REDEBUG("Told to search for group by name, but missing 'group.name_attribute' "
"directive");
return RLM_MODULE_INVALID;
}
snprintf(name_filter, sizeof(name_filter), "(%s=%s)", inst->groupobj_name_attr, name);
if (rlm_ldap_xlat_filter(request,
filters, sizeof(filters) / sizeof(*filters),
filter, sizeof(filter)) < 0) {
return RLM_MODULE_INVALID;
}
/*
* rlm_ldap_find_user does this, too. Oh well.
*/
if (radius_xlat(base_dn, sizeof(base_dn), request, inst->groupobj_base_dn,
rlm_ldap_escape_func, NULL) < 0) {
REDEBUG("Failed creating base_dn");
return RLM_MODULE_INVALID;
}
}
status = rlm_ldap_search(inst, request, pconn, dn, inst->groupobj_scope, filter, NULL, NULL);
switch (status) {
case LDAP_PROC_SUCCESS:
RDEBUG("User found in group object");
break;
case LDAP_PROC_NO_RESULT:
RDEBUG("Search returned not found");
return RLM_MODULE_NOTFOUND;
default:
return RLM_MODULE_FAIL;
}
return RLM_MODULE_OK;
}
//.........这里部分代码省略.........
case VPT_TYPE_DATA:
vp = pairalloc(request, da);
if (!vp) return -1;
vp->op = map->op;
break;
default:
break;
}
/*
* And parse the RHS
*/
switch (map->src->type) {
ssize_t slen;
char *str;
case VPT_TYPE_XLAT_STRUCT:
rad_assert(map->dst->da); /* Need to know where were going to write the new attribute */
rad_assert(map->src->xlat != NULL);
str = NULL;
slen = radius_axlat_struct(&str, request, map->src->xlat, NULL, NULL);
if (slen < 0) {
rcode = slen;
goto error;
}
/*
* We do the debug printing because radius_axlat_struct
* doesn't have access to the original string. It's been
* mangled during the parsing to xlat_exp_t
*/
RDEBUG2("EXPAND %s", map->src->name);
RDEBUG2(" --> %s", str);
rcode = pairparsevalue(vp, str);
talloc_free(str);
if (!rcode) {
pairfree(&vp);
rcode = -1;
goto error;
}
break;
case VPT_TYPE_XLAT:
rad_assert(map->dst->da); /* Need to know where were going to write the new attribute */
str = NULL;
slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
if (slen < 0) {
rcode = slen;
goto error;
}
rcode = pairparsevalue(vp, str);
talloc_free(str);
if (!rcode) {
pairfree(&vp);
rcode = -1;
goto error;
}
break;
case VPT_TYPE_LITERAL:
if (!pairparsevalue(vp, map->src->name)) {
rcode = -2;
static int get_number(REQUEST *request, const char **string, int64_t *answer)
{
int i, found;
int64_t result;
int64_t x;
const char *p;
expr_token_t this;
/*
* Loop over the input.
*/
result = 0;
this = TOKEN_NONE;
for (p = *string; *p != '\0'; /* nothing */) {
if ((*p == ' ') ||
(*p == '\t')) {
p++;
continue;
}
/*
* Discover which token it is.
*/
found = FALSE;
for (i = 0; map[i].token != TOKEN_LAST; i++) {
if (*p == map[i].op) {
if (this != TOKEN_NONE) {
RDEBUG2("Invalid operator at \"%s\"", p);
return -1;
}
this = map[i].token;
p++;
found = TRUE;
break;
}
}
/*
* Found the algebraic operator. Get the next number.
*/
if (found) {
continue;
}
/*
* End of a group. Stop.
*/
if (*p == ')') {
if (this != TOKEN_NONE) {
RDEBUG2("Trailing operator before end sub-expression at \"%s\"", p);
return -1;
}
p++;
break;
}
/*
* Start of a group. Call ourselves recursively.
*/
if (*p == '(') {
p++;
found = get_number(request, &p, &x);
if (found < 0) {
return -1;
}
} else {
/*
* No algrebraic operator found, the next thing
* MUST be a number.
*
* If it isn't, then we die.
*/
if ((*p == '0') && (p[1] == 'x')) {
char *end;
x = strtoul(p, &end, 16);
p = end;
goto calc;
}
if ((*p < '0') || (*p > '9')) {
RDEBUG2("Not a number at \"%s\"", p);
return -1;
}
/*
* This is doing it the hard way, but it also allows
* us to increment 'p'.
*/
x = 0;
while ((*p >= '0') && (*p <= '9')) {
x *= 10;
x += (*p - '0');
p++;
}
}
//.........这里部分代码省略.........
/*
* 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(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, *check_vp;
VALUE_PAIR *reply_item;
char msg[128];
char *p;
char query[MAX_QUERY_LEN];
char *expanded = NULL;
size_t len;
rad_assert(instance != NULL);
rad_assert(request != NULL);
/*
* 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 ((da = dict_attrbyname(inst->check_name)) == NULL) {
return rcode;
}
/* DEBUG2("rlm_sqlcounter: Found Check item attribute %d", da->attr); */
if ((check_vp = pairfind(request->config_items, da->attr, da->vendor, TAG_ANY)) == NULL) {
RDEBUG2("Could not find Check item value pair");
return rcode;
}
len = snprintf(query, sizeof(query), "%%{%s:%s}", inst->sqlmod_inst, 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;
}
//.........这里部分代码省略.........
/** Process the Peer's response and advantage the state machine
*
*/
static rlm_rcode_t mod_process(UNUSED void *instance, eap_session_t *eap_session)
{
REQUEST *request = eap_session->request;
eap_aka_session_t *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
fr_sim_decode_ctx_t ctx = {
.keys = &eap_aka_session->keys,
};
VALUE_PAIR *vp, *vps, *subtype_vp;
fr_cursor_t cursor;
eap_aka_subtype_t subtype;
int ret;
/*
* RFC 4187 says we ignore the contents of the
* next packet after we send our success notification
* and always send a success.
*/
if (eap_aka_session->state == EAP_AKA_SERVER_SUCCESS_NOTIFICATION) {
eap_aka_state_enter(eap_session, EAP_AKA_SERVER_SUCCESS);
return RLM_MODULE_HANDLED;
}
/* vps is the data from the client */
vps = request->packet->vps;
fr_cursor_init(&cursor, &request->packet->vps);
fr_cursor_tail(&cursor);
ret = fr_sim_decode(eap_session->request,
&cursor,
dict_eap_aka,
eap_session->this_round->response->type.data,
eap_session->this_round->response->type.length,
&ctx);
/*
* RFC 4187 says we *MUST* notify, not just
* send an EAP-Failure in this case where
* we cannot decode an EAP-AKA packet.
*/
if (ret < 0) {
RPEDEBUG2("Failed decoding EAP-AKA attributes");
eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
return RLM_MODULE_HANDLED; /* We need to process more packets */
}
vp = fr_cursor_current(&cursor);
if (vp && RDEBUG_ENABLED2) {
RDEBUG2("EAP-AKA decoded attributes");
log_request_pair_list(L_DBG_LVL_2, request, vp, NULL);
}
subtype_vp = fr_pair_find_by_da(vps, attr_eap_aka_subtype, TAG_ANY);
if (!subtype_vp) {
REDEBUG("Missing EAP-AKA-Subtype");
eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
return RLM_MODULE_HANDLED; /* We need to process more packets */
}
subtype = subtype_vp->vp_uint16;
switch (eap_aka_session->state) {
/*
* Here we expected the peer to send
* us identities for validation.
*/
case EAP_AKA_SERVER_IDENTITY:
switch (subtype) {
case EAP_AKA_IDENTITY:
if (process_eap_aka_identity(eap_session, vps) == 0) return RLM_MODULE_HANDLED;
eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE_NOTIFICATION);
return RLM_MODULE_HANDLED; /* We need to process more packets */
/*
* Case 1 where we're allowed to send an EAP-Failure
*
* This can happen in the case of a conservative
* peer, where it refuses to provide the permanent
* identity.
*/
case EAP_AKA_CLIENT_ERROR:
{
char buff[20];
vp = fr_pair_find_by_da(vps, attr_eap_aka_client_error_code, TAG_ANY);
if (!vp) {
REDEBUG("EAP-AKA Peer rejected AKA-Identity (%s) with client-error message but "
"has not supplied a client error code",
fr_int2str(sim_id_request_table, eap_aka_session->id_req, "<INVALID>"));
} else {
REDEBUG("Client rejected AKA-Identity (%s) with error: %s (%i)",
fr_int2str(sim_id_request_table, eap_aka_session->id_req, "<INVALID>"),
fr_pair_value_enum(vp, buff), vp->vp_uint16);
}
eap_aka_state_enter(eap_session, EAP_AKA_SERVER_FAILURE);
return RLM_MODULE_REJECT;
//.........这里部分代码省略.........
/** Send the challenge itself
*
* Challenges will come from one of three places eventually:
*
* 1 from attributes like FR_EAP_AKA_RANDx
* (these might be retrieved from a database)
*
* 2 from internally implemented SIM authenticators
* (a simple one based upon XOR will be provided)
*
* 3 from some kind of SS7 interface.
*
* For now, they only come from attributes.
* It might be that the best way to do 2/3 will be with a different
* module to generate/calculate things.
*/
static int eap_aka_send_challenge(eap_session_t *eap_session)
{
REQUEST *request = eap_session->request;
eap_aka_session_t *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
VALUE_PAIR **to_peer, *vp;
RADIUS_PACKET *packet;
fr_sim_vector_src_t src = SIM_VECTOR_SRC_AUTO;
rad_assert(request);
rad_assert(request->reply);
/*
* to_peer is the data to the client
*/
packet = eap_session->request->reply;
to_peer = &packet->vps;
RDEBUG2("Acquiring UMTS vector(s)");
/*
* Toggle the AMF high bit to indicate we're doing AKA'
*/
if (eap_aka_session->type == FR_EAP_AKA_PRIME) {
uint8_t amf_buff[2] = { 0x80, 0x00 }; /* Set the AMF separation bit high */
MEM(pair_update_control(&vp, attr_sim_amf) >= 0);
fr_pair_value_memcpy(vp, amf_buff, sizeof(amf_buff));
}
/*
* Get vectors from attribute or generate
* them using COMP128-* or Milenage.
*/
if (fr_sim_vector_umts_from_attrs(eap_session, request->control, &eap_aka_session->keys, &src) != 0) {
REDEBUG("Failed retrieving UMTS vectors");
return RLM_MODULE_FAIL;
}
/*
* Don't leave the AMF hanging around
*/
if (eap_aka_session->type == FR_EAP_AKA_PRIME) pair_delete_control(attr_sim_amf);
/*
* All set, calculate keys!
*/
switch (eap_aka_session->kdf) {
case FR_EAP_AKA_KDF_VALUE_EAP_AKA_PRIME_WITH_CK_PRIME_IK_PRIME:
fr_sim_crypto_kdf_1_umts(&eap_aka_session->keys);
break;
default:
fr_sim_crypto_kdf_0_umts(&eap_aka_session->keys);
break;
}
if (RDEBUG_ENABLED3) fr_sim_crypto_keys_log(request, &eap_aka_session->keys);
RDEBUG2("Sending AKA-Challenge");
eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
/*
* Set the subtype to challenge
*/
MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_subtype));
vp->vp_uint16 = FR_EAP_AKA_SUBTYPE_VALUE_AKA_CHALLENGE;
fr_pair_replace(to_peer, vp);
/*
* Indicate we'd like to use protected success messages
*/
if (eap_aka_session->send_result_ind) {
MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_result_ind));
vp->vp_bool = true;
fr_pair_replace(to_peer, vp);
}
/*
* We support EAP-AKA' and the peer should use that
* if it's able to...
*/
if (eap_aka_session->send_at_bidding) {
MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_bidding));
vp->vp_uint16 = FR_EAP_AKA_BIDDING_VALUE_PREFER_AKA_PRIME;
fr_pair_replace(to_peer, vp);
//.........这里部分代码省略.........
static int eap_aka_compose(eap_session_t *eap_session)
{
eap_aka_session_t *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
fr_cursor_t cursor;
fr_cursor_t to_encode;
VALUE_PAIR *head = NULL, *vp;
REQUEST *request = eap_session->request;
ssize_t ret;
fr_sim_encode_ctx_t encoder_ctx = {
.root = fr_dict_root(dict_eap_aka),
.keys = &eap_aka_session->keys,
.iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
.iv_included = false,
.hmac_md = eap_aka_session->mac_md,
.eap_packet = eap_session->this_round->request,
.hmac_extra = NULL,
.hmac_extra_len = 0
};
fr_cursor_init(&cursor, &eap_session->request->reply->vps);
fr_cursor_init(&to_encode, &head);
while ((vp = fr_cursor_current(&cursor))) {
if (!fr_dict_parent_common(encoder_ctx.root, vp->da, true)) {
fr_cursor_next(&cursor);
continue;
}
vp = fr_cursor_remove(&cursor);
/*
* Silently discard encrypted attributes until
* the peer should have k_encr. These can be
* added by policy, and seem to cause
* wpa_supplicant to fail if sent before the challenge.
*/
if (!eap_aka_session->allow_encrypted && fr_dict_parent_common(attr_eap_aka_encr_data, vp->da, true)) {
RWDEBUG("Silently discarding &reply:%s: Encrypted attributes not allowed in this round",
vp->da->name);
talloc_free(vp);
continue;
}
fr_cursor_append(&to_encode, vp);
}
RDEBUG2("Encoding EAP-AKA attributes");
log_request_pair_list(L_DBG_LVL_2, request, head, NULL);
eap_session->this_round->request->type.num = eap_aka_session->type;
eap_session->this_round->request->id = eap_aka_session->aka_id++ & 0xff;
eap_session->this_round->set_request_id = true;
ret = fr_sim_encode(eap_session->request, head, &encoder_ctx);
fr_cursor_head(&to_encode);
fr_cursor_free_list(&to_encode);
if (ret < 0) {
RPEDEBUG("Failed encoding EAP-AKA data");
return -1;
}
return 0;
}
/** Send an EAP-AKA identity request to the supplicant
*
* There are three types of user identities that can be implemented
* - Permanent identities such as [email protected]
* Permanent identities can be identified by the leading zero followed by
* by 15 digits (the IMSI number).
* - Ephemeral identities (pseudonyms). These are identities assigned for
* identity privacy so the user can't be tracked. These can identities
* can either be generated as per the 3GPP 'Security aspects of non-3GPP accesses'
* document section 14, where a set of up to 16 encryption keys are used
* to reversibly encrypt the IMSI. Alternatively the pseudonym can be completely
* randomised and stored in a datastore.
* - A fast resumption ID which resolves to data used for fast resumption.
*
* In order to perform full authentication the original IMSI is required for
* forwarding to the HLR. In the case where we can't match/decrypt the pseudonym,
* or can't perform fast resumption, we need to request the full identity from
* the supplicant.
*
* @param[in] eap_session to continue.
* @return
* - 0 on success.
* - <0 on failure.
*/
static int eap_aka_send_identity_request(eap_session_t *eap_session)
{
REQUEST *request = eap_session->request;
eap_aka_session_t *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t);
VALUE_PAIR *vp;
RADIUS_PACKET *packet;
fr_cursor_t cursor;
RDEBUG2("Sending AKA-Identity (%s)", fr_int2str(sim_id_request_table, eap_aka_session->id_req, "<INVALID>"));
eap_session->this_round->request->code = FR_EAP_CODE_REQUEST;
//.........这里部分代码省略.........
/*
* Generic function for failing between a bunch of queries.
*
* Uses the same principle as rlm_linelog, expanding the 'reference' config
* item using xlat to figure out what query it should execute.
*
* If the reference matches multiple config items, and a query fails or
* doesn't update any rows, the next matching config item is used.
*
*/
static int acct_redundant(rlm_sql_t *inst, REQUEST *request, sql_acct_section_t *section)
{
rlm_rcode_t rcode = RLM_MODULE_OK;
rlm_sql_handle_t *handle = NULL;
int sql_ret;
int numaffected = 0;
CONF_ITEM *item;
CONF_PAIR *pair;
char const *attr = NULL;
char const *value;
char path[MAX_STRING_LEN];
char *p = path;
char *expanded = NULL;
rad_assert(section);
if (section->reference[0] != '.') {
*p++ = '.';
}
if (radius_xlat(p, sizeof(path) - (p - path), request, section->reference, NULL, NULL) < 0) {
rcode = RLM_MODULE_FAIL;
goto finish;
}
item = cf_reference_item(NULL, section->cs, path);
if (!item) {
rcode = RLM_MODULE_FAIL;
goto finish;
}
if (cf_item_is_section(item)){
REDEBUG("Sections are not supported as references");
rcode = RLM_MODULE_FAIL;
goto finish;
}
pair = cf_itemtopair(item);
attr = cf_pair_attr(pair);
RDEBUG2("Using query template '%s'", attr);
handle = sql_get_socket(inst);
if (!handle) {
rcode = RLM_MODULE_FAIL;
goto finish;
}
sql_set_user(inst, request, NULL);
while (true) {
value = cf_pair_value(pair);
if (!value) {
RDEBUG("Ignoring null query");
rcode = RLM_MODULE_NOOP;
goto finish;
}
if (radius_axlat(&expanded, request, value, sql_escape_func, inst) < 0) {
rcode = RLM_MODULE_FAIL;
goto finish;
}
if (!*expanded) {
RDEBUG("Ignoring null query");
rcode = RLM_MODULE_NOOP;
talloc_free(expanded);
goto finish;
}
rlm_sql_query_log(inst, request, section, expanded);
/*
* If rlm_sql_query cannot use the socket it'll try and
* reconnect. Reconnecting will automatically release
* the current socket, and try to select a new one.
*
* If we get RLM_SQL_RECONNECT it means all connections in the pool
* were exhausted, and we couldn't create a new connection,
* so we do not need to call sql_release_socket.
//.........这里部分代码省略.........
请发表评论