/* * Run a virtual server auth and postauth * */ int rad_virtual_server(REQUEST *request) { VALUE_PAIR *vp; int result; /* * 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_AUTHENTICATION_REQUEST); result = rad_authenticate(request); if (request->reply->code == PW_AUTHENTICATION_REJECT) { pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY); vp = pairmake_config("Post-Auth-Type", "Reject", T_OP_SET); if (vp) rad_postauth(request); } if (request->reply->code == PW_AUTHENTICATION_ACK) { rad_postauth(request); } return result; }
/* * This does the exact same thing as the mod_authorize, it's just called * differently. */ static rlm_rcode_t mod_preacct(void *instance, REQUEST *request) { int rcode; char const *name = request->username->vp_strvalue; REALM *realm; if (!name) return RLM_MODULE_OK; /* * Check if we've got to proxy the request. * If not, return without adding a Proxy-To-Realm * attribute. */ rcode = check_for_realm(instance, request, &realm); if (rcode != RLM_MODULE_UPDATED) return rcode; if (!realm) return RLM_MODULE_NOOP; /* * Maybe add a Proxy-To-Realm attribute to the request. */ RDEBUG2("Preparing to proxy accounting request to realm \"%s\"\n", realm->name); pairmake_config("Proxy-To-Realm", realm->name, T_OP_EQ); return RLM_MODULE_UPDATED; /* try the next module */ }
/* * Run a virtual server auth and postauth * */ int rad_virtual_server(REQUEST *request) { VALUE_PAIR *vp; int result; RDEBUG("server %s {", request->server); RDEBUG(" Request:"); debug_pair_list(request->packet->vps); /* * 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) { pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY); vp = pairmake_config("Post-Auth-Type", "Reject", T_OP_SET); if (vp) rad_postauth(request); } if (request->reply->code == PW_CODE_ACCESS_ACCEPT) { rad_postauth(request); } RDEBUG(" Reply:"); debug_pair_list(request->reply->vps); RDEBUG("} # server %s", request->server); return result; }
/* * 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; } pairmake_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 (!pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) { return RLM_MODULE_NOOP; } if (pairfind(request->config_items, PW_AUTHTYPE, 0, TAG_ANY) != NULL) { RWDEBUG2("Auth-Type already set. Not setting to CHAP"); return RLM_MODULE_NOOP; } RDEBUG("Setting 'Auth-Type := CHAP'"); pairmake_config("Auth-Type", "CHAP", T_OP_EQ); return RLM_MODULE_OK; }
/* * CoA realms via Operator-Name. Because the realm isn't in a * User-Name, concepts like "prefix" and "suffix' don't matter. */ static rlm_rcode_t realm_recv_coa(UNUSED void *instance, REQUEST *request) { VALUE_PAIR *vp; REALM *realm; if (pairfind(request->packet->vps, PW_REALM, 0, TAG_ANY) != NULL) { RDEBUG2("Request already proxied. Ignoring."); return RLM_MODULE_OK; } vp = pairfind(request->packet->vps, PW_OPERATOR_NAME, 0, TAG_ANY); if (!vp) return RLM_MODULE_NOOP; /* * Catch the case of broken dictionaries. */ if (vp->da->type != PW_TYPE_STRING) return RLM_MODULE_NOOP; /* * The string is too short. */ if (vp->length == 1) return RLM_MODULE_NOOP; /* * '1' means "the rest of the string is a realm" */ if (vp->vp_strvalue[0] != '1') return RLM_MODULE_NOOP; realm = realm_find(vp->vp_strvalue + 1); if (!realm) return RLM_MODULE_NOTFOUND; if (!realm->coa_pool) { RDEBUG2("CoA realm is LOCAL."); return RLM_MODULE_OK; } /* * Maybe add a Proxy-To-Realm attribute to the request. */ RDEBUG2("Preparing to proxy authentication request to realm \"%s\"\n", realm->name); pairmake_config("Proxy-To-Realm", realm->name, T_OP_EQ); return RLM_MODULE_UPDATED; /* try the next module */ }
/* * 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 = pairfind(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); pairdelete(&request->config, PW_AUTH_TYPE, 0, TAG_ANY); /* delete old auth-type */ pairmake_config("Auth-Type", inst->authtype, T_OP_SET); } return RLM_MODULE_OK; }
/* * Examine a request for a username with an realm, and if it * corresponds to something in the realms file, set that realm as * Proxy-To. * * This should very nearly duplicate the old proxy_send() code */ static rlm_rcode_t mod_authorize(void *instance, REQUEST *request) { rlm_rcode_t rcode; REALM *realm; /* * Check if we've got to proxy the request. * If not, return without adding a Proxy-To-Realm * attribute. */ rcode = check_for_realm(instance, request, &realm); if (rcode != RLM_MODULE_UPDATED) return rcode; if (!realm) return RLM_MODULE_NOOP; /* * Maybe add a Proxy-To-Realm attribute to the request. */ RDEBUG2("Preparing to proxy authentication request to realm \"%s\"\n", realm->name); pairmake_config("Proxy-To-Realm", realm->name, T_OP_EQ); return RLM_MODULE_UPDATED; /* try the next module */ }
/** * This function is called when a EAP_TNC_RESPONSE was received. * It basically forwards the EAP_TNC data to NAA-TNCS and forms * and appropriate EAP_RESPONSE. Furthermore, it sets the VlanID * based on the TNC_ConnectionState determined by NAA-TNCS. * * @param instance The configuration data. * @param handler The eap_handler_t. * @return True, if successfully, else false. */ static int mod_authenticate(UNUSED void *instance, eap_handler_t *handler) { TNC_ConnectionID conn_id; TNC_Result result; TNC_BufferReference data = NULL; TNC_UInt32 datalen = 0; TNC_ConnectionState connection_state; uint8_t code = 0; REQUEST *request = handler->request; if (handler->eap_ds->response->type.num != PW_EAP_TNC) { ERROR("rlm_eap_tnc: Incorrect response type"); return 0; } /* * Retrieve connection ID */ conn_id = *((TNC_ConnectionID *) (handler->opaque)); RDEBUG2("Starting authentication for connection ID %lX", conn_id); /* * Pass EAP_TNC data to NAA-EAP and get answer data */ connection_state = TNC_CONNECTION_STATE_CREATE; /* * Forwards the eap_tnc data to NAA-EAP and gets the response */ result = processEAPTNCData(conn_id, handler->eap_ds->response->type.data, handler->eap_ds->response->type.length, &data, &datalen, &connection_state); if (result != TNC_RESULT_SUCCESS) { RDEBUG("NAA-EAP processEAPTNCData returned " "an error code"); return 0; } /* * Determine eap code for the response */ switch (connection_state) { case TNC_CONNECTION_STATE_HANDSHAKE: code = PW_EAP_REQUEST; break; case TNC_CONNECTION_STATE_ACCESS_NONE: code = PW_EAP_FAILURE; pairmake_config("TNC-Status", "None", T_OP_SET); break; case TNC_CONNECTION_STATE_ACCESS_ALLOWED: code = PW_EAP_SUCCESS; pairmake_config("TNC-Status", "Access", T_OP_SET); break; case TNC_CONNECTION_STATE_ACCESS_ISOLATED: code = PW_EAP_SUCCESS; pairmake_config("TNC-Status", "Isolate", T_OP_SET); break; default: ERROR("rlm_eap_tnc: Invalid connection state"); return 0; } /* * Build the TNC EAP request */ handler->eap_ds->request->code = code; handler->eap_ds->request->type.num = PW_EAP_TNC; handler->eap_ds->request->type.length = datalen; talloc_free(handler->eap_ds->request->type.data); /* * "data" is not talloc'd memory. */ handler->eap_ds->request->type.data = talloc_array(handler->eap_ds->request, uint8_t, datalen); memcpy(handler->eap_ds->request->type.data, data, datalen); free(data); return 1; }
/* * 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 = pairfind(request->config_items, PW_AUTHTYPE, 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 (pairfind(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) { pairmake_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 = paircreate(request->reply, PW_STATE, 0); if (!vp) { return RLM_MODULE_FAIL; } pairmemcpy(vp, (uint8_t const *) gen_state, len); pairadd(&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 = paircreate(request->reply, PW_OTP_CHALLENGE, 0); if (!vp) { return RLM_MODULE_FAIL; } pairstrcpy(vp, challenge); vp->op = T_OP_SET; pairadd(&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 = paircreate(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->length = len; vp->op = T_OP_SET; vp->type = VT_DATA; pairadd(&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) { pairmake_config("Auth-Type", inst->name, T_OP_EQ); } return RLM_MODULE_HANDLED; }
/* * member of the radius group? */ static rlm_rcode_t mod_authorize(UNUSED void *instance, REQUEST *request) { struct passwd *userdata = NULL; struct group *groupdata = NULL; int ismember = 0; RADCLIENT *rad_client = NULL; uuid_t uuid; uuid_t guid_sacl; uuid_t guid_nasgroup; int err; char host_ipaddr[128] = {0}; if (!request || !request->username) { RDEBUG("OpenDirectory requires a User-Name attribute."); return RLM_MODULE_NOOP; } /* resolve SACL */ uuid_clear(guid_sacl); groupdata = getgrnam(kRadiusSACLName); if (groupdata != NULL) { err = mbr_gid_to_uuid(groupdata->gr_gid, guid_sacl); if (err != 0) { ERROR("rlm_opendirectory: The group \"%s\" does not have a GUID.", kRadiusSACLName); return RLM_MODULE_FAIL; } } else { RDEBUG("The SACL group \"%s\" does not exist on this system.", kRadiusSACLName); } /* resolve client access list */ uuid_clear(guid_nasgroup); rad_client = request->client; #if 0 if (rad_client->community[0] != '\0' ) { /* * The "community" can be a GUID (Globally Unique ID) or * a group name */ if (uuid_parse(rad_client->community, guid_nasgroup) != 0) { /* attempt to resolve the name */ groupdata = getgrnam(rad_client->community); if (!groupdata) { AUTH("rlm_opendirectory: The group \"%s\" does not exist on this system.", rad_client->community); return RLM_MODULE_FAIL; } err = mbr_gid_to_uuid(groupdata->gr_gid, guid_nasgroup); if (err != 0) { AUTH("rlm_opendirectory: The group \"%s\" does not have a GUID.", rad_client->community); return RLM_MODULE_FAIL; } } } else #endif { if (!rad_client) { RDEBUG("The client record could not be found for host %s.", ip_ntoh(&request->packet->src_ipaddr, host_ipaddr, sizeof(host_ipaddr))); } else { RDEBUG("The host %s does not have an access group.", ip_ntoh(&request->packet->src_ipaddr, host_ipaddr, sizeof(host_ipaddr))); } } if (uuid_is_null(guid_sacl) && uuid_is_null(guid_nasgroup)) { RDEBUG("no access control groups, all users allowed."); if (pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY) == NULL) { pairmake_config("Auth-Type", kAuthType, T_OP_EQ); RDEBUG("Setting Auth-Type = %s", kAuthType); } return RLM_MODULE_OK; } /* resolve user */ uuid_clear(uuid); userdata = getpwnam(request->username->vp_strvalue); if (userdata != NULL) { err = mbr_uid_to_uuid(userdata->pw_uid, uuid); if (err != 0) uuid_clear(uuid); } if (uuid_is_null(uuid)) { REDEBUG("Could not get the user's uuid", T_OP_EQ); return RLM_MODULE_NOTFOUND; } if (!uuid_is_null(guid_sacl)) { err = mbr_check_service_membership(uuid, kRadiusServiceName, &ismember); if (err != 0) { REDEBUG("Failed to check group membership", T_OP_EQ); return RLM_MODULE_FAIL; } if (ismember == 0) { REDEBUG("User is not authorized", T_OP_EQ); return RLM_MODULE_USERLOCK; } } if (!uuid_is_null(guid_nasgroup)) { err = mbr_check_membership_refresh(uuid, guid_nasgroup, &ismember); if (err != 0) { REDEBUG("Failed to check group membership", T_OP_EQ); return RLM_MODULE_FAIL; } if (ismember == 0) { REDEBUG("User is not authorized", T_OP_EQ); return RLM_MODULE_USERLOCK; } } if (pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY) == NULL) { pairmake_config("Auth-Type", kAuthType, T_OP_EQ); RDEBUG("Setting Auth-Type = %s", kAuthType); } return RLM_MODULE_OK; }
/* * EAP authorization DEPENDS on other rlm authorizations, * to check for user existance & get their configured values. * It Handles EAP-START Messages, User-Name initilization. */ static rlm_rcode_t mod_authorize(void *instance, REQUEST *request) { rlm_eap_t *inst; int status; VALUE_PAIR *vp; inst = (rlm_eap_t *)instance; #ifdef WITH_PROXY /* * We don't do authorization again, once we've seen the * proxy reply (or the proxied packet) */ if (request->proxy != NULL) return RLM_MODULE_NOOP; #endif /* * For EAP_START, send Access-Challenge with EAP Identity * request. even when we have to proxy this request * * RFC 2869, Section 2.3.1 notes that the "domain" of the * user, (i.e. where to proxy him) comes from the EAP-Identity, * so we CANNOT proxy the user, until we know his identity. * * We therefore send an EAP Identity request. */ status = eap_start(inst, request); switch(status) { case EAP_NOOP: return RLM_MODULE_NOOP; case EAP_FAIL: return RLM_MODULE_FAIL; case EAP_FOUND: return RLM_MODULE_HANDLED; case EAP_OK: case EAP_NOTFOUND: default: break; } /* * RFC 2869, Section 2.3.1. If a NAS sends an EAP-Identity, * it MUST copy the identity into the User-Name attribute. * * But we don't worry about that too much. We depend on * each EAP sub-module to look for handler->request->username, * and to get excited if it doesn't appear. */ vp = pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY); if ((!vp) || (vp->vp_integer != PW_AUTHTYPE_REJECT)) { vp = pairmake_config("Auth-Type", inst->xlat_name, T_OP_EQ); if (!vp) { RDEBUG2("Failed to create Auth-Type %s: %s\n", inst->xlat_name, fr_strerror()); return RLM_MODULE_FAIL; } } else { RDEBUG2W("Auth-Type already set. Not setting to EAP"); } if (status == EAP_OK) return RLM_MODULE_OK; return RLM_MODULE_UPDATED; }
/** 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(ldap_instance_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 base_dn[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 (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, base_dn, inst->groupobj_scope, filter, attrs, &result); switch (status) { case LDAP_PROC_SUCCESS: break; case LDAP_PROC_NO_RESULT: RDEBUG2("No cacheable group memberships found in group objects"); default: 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; } 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 = pairmake_config(inst->cache_da->name, NULL, T_OP_ADD)); pairstrcpy(vp, dn); RDEBUG("Added control:%s with value \"%s\"", inst->cache_da->name, dn); 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 = pairmake_config(inst->cache_da->name, NULL, T_OP_ADD)); pairstrncpy(vp, values[0]->bv_val, values[0]->bv_len); RDEBUG("Added control:%s with value \"%.*s\"", inst->cache_da->name, (int)values[0]->bv_len, values[0]->bv_val); ldap_value_free_len(values); } } while ((entry = ldap_next_entry((*pconn)->handle, entry))); finish: if (result) ldap_msgfree(result); return rcode; }