/* * If we have something to log, then we log it. * Otherwise we return the retcode as soon as possible */ static int do_logging(REQUEST *request, char const *str, int rcode) { char *expanded = NULL; if (!str || !*str) return rcode; if (radius_axlat(&expanded, request, str, NULL, NULL) < 0) { return rcode; } pair_make_config("Module-Success-Message", expanded, T_OP_SET); talloc_free(expanded); return rcode; }
static rlm_rcode_t CC_HINT(nonnull) mod_authorize(UNUSED void *instance, REQUEST *request) { if (!fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) { return RLM_MODULE_NOOP; } if (fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY) != NULL) { RWDEBUG2("&control:Auth-Type already set. Not setting to CHAP"); return RLM_MODULE_NOOP; } RINDENT(); RDEBUG("&control:Auth-Type := CHAP"); REXDENT(); pair_make_config("Auth-Type", "CHAP", T_OP_EQ); 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(void *instance, REQUEST *request) { VALUE_PAIR *state; rlm_smsotp_t *inst = instance; /* * Look for the 'state' attribute. */ state = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY); if (state != NULL) { DEBUG("rlm_smsotp: Found reply to access challenge (AUTZ), Adding Auth-Type '%s'",inst->authtype); fr_pair_delete_by_num(&request->config, PW_AUTH_TYPE, 0, TAG_ANY); /* delete old auth-type */ pair_make_config("Auth-Type", inst->authtype, T_OP_SET); } return RLM_MODULE_OK; }
/* * Run a virtual server auth and postauth * */ int rad_virtual_server(REQUEST *request) { VALUE_PAIR *vp; int result; RDEBUG("Virtual server %s received request", request->server); rdebug_pair_list(L_DBG_LVL_1, request, request->packet->vps, NULL); RDEBUG("server %s {", request->server); RINDENT(); /* * We currently only handle AUTH packets here. * This could be expanded to handle other packets as well if required. */ rad_assert(request->packet->code == PW_CODE_ACCESS_REQUEST); result = rad_authenticate(request); if (request->reply->code == PW_CODE_ACCESS_REJECT) { fr_pair_delete_by_num(&request->config, PW_POST_AUTH_TYPE, 0, TAG_ANY); vp = pair_make_config("Post-Auth-Type", "Reject", T_OP_SET); if (vp) rad_postauth(request); } if (request->reply->code == PW_CODE_ACCESS_ACCEPT) { rad_postauth(request); } REXDENT(); RDEBUG("} # server %s", request->server); RDEBUG("Virtual server sending reply"); rdebug_pair_list(L_DBG_LVL_1, request, request->reply->vps, NULL); return result; }
/* * Generate a challenge to be presented to the user. */ static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request) { rlm_otp_t *inst = (rlm_otp_t *) instance; char challenge[OTP_MAX_CHALLENGE_LEN + 1]; /* +1 for '\0' terminator */ int auth_type_found; /* Early exit if Auth-Type != inst->name */ { VALUE_PAIR *vp; auth_type_found = 0; vp = fr_pair_find_by_num(request->config, PW_AUTH_TYPE, 0, TAG_ANY); if (vp) { auth_type_found = 1; if (strcmp(vp->vp_strvalue, inst->name)) { return RLM_MODULE_NOOP; } } } /* The State attribute will be present if this is a response. */ if (fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY) != NULL) { DEBUG("rlm_otp: autz: Found response to Access-Challenge"); return RLM_MODULE_OK; } /* User-Name attribute required. */ if (!request->username) { RWDEBUG("Attribute \"User-Name\" " "required for authentication"); return RLM_MODULE_INVALID; } if (otp_pwe_present(request) == 0) { RWDEBUG("Attribute " "\"User-Password\" or equivalent required " "for authentication"); return RLM_MODULE_INVALID; } /* * We used to check for special "challenge" and "resync" passcodes * here, but these are complicated to explain and application is * limited. More importantly, since we've removed all actual OTP * code (now we ask otpd), it's awkward for us to support them. * Should the need arise to reinstate these options, the most * likely choice is to duplicate some otpd code here. */ if (inst->allow_sync && !inst->allow_async) { /* This is the token sync response. */ if (!auth_type_found) { pair_make_config("Auth-Type", inst->name, T_OP_EQ); } return RLM_MODULE_OK; } /* * Generate a random challenge. */ otp_async_challenge(challenge, inst->challenge_len); /* * Create the State attribute, which will be returned to * us along with the response. * * We will need this to verify the response. * * It must be hmac protected to prevent insertion of arbitrary * State by an inside attacker. * * If we won't actually use the State (server config doesn't * allow async), we just use a trivial State. * * We always create at least a trivial State, so mod_authorize() * can quickly pass on to mod_authenticate(). */ { int32_t now = htonl(time(NULL)); //!< Low-order 32 bits on LP64. char gen_state[OTP_MAX_RADSTATE_LEN]; size_t len; VALUE_PAIR *vp; len = otp_gen_state(gen_state, challenge, inst->challenge_len, 0, now, inst->hmac_key); vp = fr_pair_afrom_num(request->reply, PW_STATE, 0); if (!vp) { return RLM_MODULE_FAIL; } fr_pair_value_memcpy(vp, (uint8_t const *) gen_state, len); fr_pair_add(&request->reply->vps, vp); } /* * Add the challenge to the reply. */ { VALUE_PAIR *vp; char *expanded = NULL; ssize_t len; /* * First add the internal OTP challenge attribute to * the reply list. */ vp = fr_pair_afrom_num(request->reply, PW_OTP_CHALLENGE, 0); if (!vp) { return RLM_MODULE_FAIL; } fr_pair_value_strcpy(vp, challenge); vp->op = T_OP_SET; fr_pair_add(&request->reply->vps, vp); /* * Then add the message to the user to they known * what the challenge value is. */ len = radius_axlat(&expanded, request, inst->chal_prompt, NULL, NULL); if (len < 0) { return RLM_MODULE_FAIL; } vp = fr_pair_afrom_num(request->reply, PW_REPLY_MESSAGE, 0); if (!vp) { talloc_free(expanded); return RLM_MODULE_FAIL; } (void) talloc_steal(vp, expanded); vp->vp_strvalue = expanded; vp->vp_length = len; vp->op = T_OP_SET; vp->type = VT_DATA; fr_pair_add(&request->reply->vps, vp); } /* * 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_otp: Sending Access-Challenge"); if (!auth_type_found) { pair_make_config("Auth-Type", inst->name, T_OP_EQ); } return RLM_MODULE_HANDLED; }
/** 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. * @return One of the RLM_MODULE_* values. */ rlm_rcode_t rlm_ldap_cacheable_groupobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn) { rlm_rcode_t rcode = RLM_MODULE_OK; ldap_rcode_t status; int ldap_errno; LDAPMessage *result = NULL; LDAPMessage *entry; char const *base_dn; char base_dn_buff[LDAP_MAX_DN_STR_LEN]; char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter }; char filter[LDAP_MAX_FILTER_STR_LEN + 1]; char const *attrs[] = { inst->groupobj_name_attr, NULL }; VALUE_PAIR *vp; char *dn; rad_assert(inst->groupobj_base_dn); if (!inst->groupobj_membership_filter) { RDEBUG2("Skipping caching group objects as directive 'group.membership_filter' is not set"); return RLM_MODULE_OK; } if (rlm_ldap_xlat_filter(request, filters, sizeof(filters) / sizeof(*filters), filter, sizeof(filter)) < 0) { return RLM_MODULE_INVALID; } if (tmpl_expand(&base_dn, base_dn_buff, sizeof(base_dn_buff), request, inst->groupobj_base_dn, rlm_ldap_escape_func, NULL) < 0) { REDEBUG("Failed creating base_dn"); return RLM_MODULE_INVALID; } status = rlm_ldap_search(&result, inst, request, pconn, base_dn, inst->groupobj_scope, filter, attrs, NULL, NULL); switch (status) { case LDAP_PROC_SUCCESS: break; case LDAP_PROC_NO_RESULT: RDEBUG2("No cacheable group memberships found in group objects"); goto finish; default: rcode = RLM_MODULE_FAIL; goto finish; } entry = ldap_first_entry((*pconn)->handle, result); if (!entry) { ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno); REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno)); goto finish; } RDEBUG("Adding cacheable group object memberships"); do { if (inst->cacheable_group_dn) { dn = ldap_get_dn((*pconn)->handle, entry); if (!dn) { ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno); REDEBUG("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno)); goto finish; } rlm_ldap_normalise_dn(dn, dn); MEM(vp = pair_make_config(inst->cache_da->name, NULL, T_OP_ADD)); fr_pair_value_strcpy(vp, dn); RINDENT(); RDEBUG("&control:%s += \"%s\"", inst->cache_da->name, dn); REXDENT(); ldap_memfree(dn); } if (inst->cacheable_group_name) { struct berval **values; values = ldap_get_values_len((*pconn)->handle, entry, inst->groupobj_name_attr); if (!values) continue; MEM(vp = pair_make_config(inst->cache_da->name, NULL, T_OP_ADD)); fr_pair_value_bstrncpy(vp, values[0]->bv_val, values[0]->bv_len); RINDENT(); RDEBUG("&control:%s += \"%.*s\"", inst->cache_da->name, (int)values[0]->bv_len, values[0]->bv_val); REXDENT(); ldap_value_free_len(values); } } while ((entry = ldap_next_entry((*pconn)->handle, entry))); finish: if (result) ldap_msgfree(result); return rcode; }