static void handle_request(REQUEST *request, VALUE_PAIR *vp) { char *input_data; int input_len; char *output_data; int output_len; char *smime_msg; ATTR_REQ_OUT *outstruct; input_len = unpack_mime_text((char *)vp->data.octets, vp->length, &input_data); ATTR_REQ_IN *attr_request = parse_attr_req(input_data, input_len); if (!attr_request) { return; } X509 *cert = get_matching_certificate(request, attr_request->proxydn); if (!cert) { return; } outstruct = get_attr_req_out(attr_request); output_len = attr_req_out_to_string(outstruct, &output_data); smime_msg = pack_smime_text(output_data, private_key, cert); VALUE_PAIR *avp_smime = pairmake("Moonshot-Request",smime_msg, T_OP_EQ); pairadd(&request->reply->vps, avp_smime); return; }
/* * Set the SQL user name. * * We don't call the escape function here. The resulting string * will be escaped later in the queries xlat so we don't need to * escape it twice. (it will make things wrong if we have an * escape candidate character in the username) */ static int sql_set_user(SQL_INST *inst, REQUEST *request, char *sqlusername, const char *username) { VALUE_PAIR *vp=NULL; char tmpuser[MAX_STRING_LEN]; tmpuser[0] = '\0'; sqlusername[0]= '\0'; /* Remove any user attr we added previously */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); if (username != NULL) { strNcpy(tmpuser, username, MAX_STRING_LEN); } else if (strlen(inst->config->query_user)) { radius_xlat(tmpuser, sizeof(tmpuser), inst->config->query_user, request, NULL); } else { return 0; } if (*tmpuser) { strNcpy(sqlusername, tmpuser, MAX_STRING_LEN); DEBUG2("rlm_sql (%s): sql_set_user escaped user --> '%s'", inst->config->xlat_name, sqlusername); vp = pairmake("SQL-User-Name", sqlusername, 0); if (vp == NULL) { radlog(L_ERR, "%s", librad_errstr); return -1; } pairadd(&request->packet->vps, vp); return 0; } return -1; }
/* * First, look for Exec-Program && Exec-Program-Wait. * * Then, call exec_dispatch. */ static int exec_postauth(void *instance, REQUEST *request) { int result; int exec_wait = 0; VALUE_PAIR *vp, *tmp; rlm_exec_t *inst = (rlm_exec_t *) instance; vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM, 0); if (vp) { exec_wait = 0; } else if ((vp = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT, 0)) != NULL) { exec_wait = 1; } if (!vp) { if (!inst->program) return RLM_MODULE_NOOP; return exec_dispatch(instance, request); } tmp = NULL; result = radius_exec_program(vp->vp_strvalue, request, exec_wait, NULL, 0, request->packet->vps, &tmp, inst->shell_escape); /* * Always add the value-pairs to the reply. */ pairmove(&request->reply->vps, &tmp); pairfree(&tmp); if (result < 0) { /* * Error. radius_exec_program() returns -1 on * fork/exec errors. */ tmp = pairmake("Reply-Message", "Access denied (external check failed)", T_OP_SET); pairadd(&request->reply->vps, tmp); RDEBUG2("Login incorrect (external check failed)"); request->reply->code = PW_AUTHENTICATION_REJECT; return RLM_MODULE_REJECT; } if (result > 0) { /* * Reject. radius_exec_program() returns >0 * if the exec'ed program had a non-zero * exit status. */ request->reply->code = PW_AUTHENTICATION_REJECT; RDEBUG2("Login incorrect (external check said so)"); return RLM_MODULE_REJECT; } return RLM_MODULE_OK; }
void cbtls_info(const SSL *s, int where, int ret) { const char *str, *state; int w; REQUEST *request = SSL_get_ex_data(s, FR_TLS_EX_INDEX_REQUEST); char buffer[1024]; w = where & ~SSL_ST_MASK; if (w & SSL_ST_CONNECT) str=" TLS_connect"; else if (w & SSL_ST_ACCEPT) str=" TLS_accept"; else str=" (other)"; state = SSL_state_string_long(s); state = state ? state : "NULL"; buffer[0] = '\0'; if (where & SSL_CB_LOOP) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_HANDSHAKE_START) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_HANDSHAKE_DONE) { RDEBUG2("%s: %s", str, state); } else if (where & SSL_CB_ALERT) { str=(where & SSL_CB_READ)?"read":"write"; snprintf(buffer, sizeof(buffer), "TLS Alert %s:%s:%s", str, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if (where & SSL_CB_EXIT) { if (ret == 0) { snprintf(buffer, sizeof(buffer), "%s: failed in %s", str, state); } else if (ret < 0) { if (SSL_want_read(s)) { RDEBUG2("%s: Need to read more data: %s", str, state); } else { snprintf(buffer, sizeof(buffer), "%s: error in %s", str, state); } } } if (buffer[0]) { radlog(L_ERR, "%s", buffer); if (request) { VALUE_PAIR *vp; vp = pairmake("Module-Failure-Message", buffer, T_OP_ADD); if (vp) pairadd(&request->packet->vps, vp); } } }
static int eap_post_auth(void *instance, REQUEST *request) { rlm_eap_t *inst = instance; VALUE_PAIR *vp; EAP_HANDLER *handler; eap_packet_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->packet->vps); if (eap_packet == NULL) { radlog_request(L_ERR, 0, request, "Malformed EAP Message"); return RLM_MODULE_FAIL; } handler = eap_handler(inst, &eap_packet, request); if (handler == NULL) { 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) { vp = pairmake("Message-Authenticator", "0x00", T_OP_EQ); rad_assert(vp != NULL); pairadd(&(request->reply->vps), vp); } return RLM_MODULE_UPDATED; }
/* * 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 int testing_authorize(void *instance, REQUEST *request) { VALUE_PAIR *state; VALUE_PAIR *reply; VALUE_PAIR *reply2; /* quiet the compiler */ instance = instance; request = request; /* * Look for the 'state' attribute. */ state = pairfind(request->packet->vps, PW_STATE); if (state != NULL) { RDEBUG("Found reply to access challenge"); return RLM_MODULE_OK; } /* * Create the challenge, and add it to the reply. */ reply = pairmake("Reply-Message", "This is a challenge", T_OP_EQ); reply2 = pairmake("Reply-Message", "This is a second challenge", T_OP_EQ); pairadd(&request->reply->vps, reply); pairadd(&request->reply->vps, reply2); state = pairmake("State", "0", T_OP_EQ); pairadd(&request->reply->vps, state); /* * Mark the packet as an Access-Challenge packet. * * The server will take care of sending it to the user. */ request->reply->code = PW_ACCESS_CHALLENGE; RDEBUG("Sending Access-Challenge."); return RLM_MODULE_HANDLED; }
/** Create a pair, and add it to a particular list of VPs * * Note that this function ALWAYS returns. If we're OOM, then it causes the * server to exit! * * @param[in] request current request. * @param[in] vps to modify. * @param[in] attribute name. * @param[in] value attribute value. * @param[in] operator fr_tokens value. * @return a new VALUE_PAIR. */ VALUE_PAIR *radius_pairmake(UNUSED REQUEST *request, VALUE_PAIR **vps, const char *attribute, const char *value, int operator) { VALUE_PAIR *vp; vp = pairmake(attribute, value, operator); if (!vp) return NULL; if (vps) pairadd(vps, vp); return vp; }
static int remotedb_answer_builder(REQUEST *request, const char *password, const char *vlan) { VALUE_PAIR *pair; radlog(L_DBG, "Building answer : password = %s, vlan = %s\n", password, vlan); pair = pairmake("NT-Password", password, T_OP_SET); pairmove(&request->config_items, &pair); pairfree(&pair); pair = pairmake("Tunnel-Private-Group-Id", vlan, T_OP_SET); pairadd(&request->reply->vps, pair); pair = pairmake("Tunnel-Medium-Type", "6", T_OP_SET); pairadd(&request->reply->vps, pair); pair = pairmake("Tunnel-Type", "13", T_OP_SET); pairadd(&request->reply->vps, pair); return RLM_MODULE_OK; }
/* * Write accounting information to this modules database. */ static int stg_accounting(void *, REQUEST * request) { const STG_PAIR * pairs; const STG_PAIR * pair; size_t count = 0; instance = instance; DEBUG("rlm_stg: stg_accounting()"); VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE); VALUE_PAIR * sessid = pairfind(request->packet->vps, PW_ACCT_SESSION_ID); VALUE_PAIR * sttype = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE); if (!sessid) { DEBUG("rlm_stg: stg_accounting() Acct-Session-ID undefined"); return RLM_MODULE_FAIL; } if (sttype) { DEBUG("Acct-Status-Type := %s", sttype->vp_strvalue); if (svc) { DEBUG("rlm_stg: stg_accounting() Service-Type defined as '%s'", svc->vp_strvalue); pairs = stgAccountingImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue, (const char *)sttype->vp_strvalue, (const char *)sessid->vp_strvalue); } else { DEBUG("rlm_stg: stg_accounting() Service-Type undefined"); pairs = stgAccountingImpl((const char *)request->username->vp_strvalue, "", (const char *)sttype->vp_strvalue, (const char *)sessid->vp_strvalue); } } else { DEBUG("rlm_stg: stg_accounting() Acct-Status-Type := NULL"); return RLM_MODULE_OK; } if (!pairs) { DEBUG("rlm_stg: stg_accounting() failed."); return RLM_MODULE_REJECT; } pair = pairs; while (!emptyPair(pair)) { VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET); pairadd(&request->reply->vps, pwd); ++pair; ++count; } deletePairs(pairs); if (count) return RLM_MODULE_UPDATED; return RLM_MODULE_OK; }
int proxy_handle_request(REQUEST *request) { char *cert_message; VALUE_PAIR *vp; switch (request->packet->code) //it's allowed to handle multiple requests, the request type is based on radius responses { case PW_AUTHENTICATION_REQUEST: pack_mime_cert(public_certificate, &cert_message); VALUE_PAIR *avp_certificate; avp_certificate = pairmake("AVP_CERTIFICATE_RADIUS", cert_message, T_OP_EQ); //AVP_CERTIFICATE_RADIUS is an AVP that stores the certificate chain pairadd(&request->reply->vps, avp_certificate); //add AVP return RLM_MODULE_UPDATED; //we are basically saying that our AVPs are updated case PW_AUTHENTICATION_ACK: vp = request->packet->vps; do { if (vp->attribute == ATTR_SMIME_REQUEST) //detect if AVP_PROXY_REQUEST is sent by the idp module { char *message_attributes = unpack_smime_text((char *)vp->data.octets, private_key, private_certificate); char *out_message = obtain_attributes(message_attributes); VALUE_PAIR *avp_attributes; avp_attributes = pairmake("AVP_PROXY_ATTRIBUTES", out_message, T_OP_EQ); //AVP_PROXY_ATTRIBUTES is an AVP that stores the attributes pairadd(&request->reply->vps, avp_attributes); //add AVP return RLM_MODULE_UPDATED; //return statement that is needed when AVPs are updated } } while ((vp = vp -> next) != 0); } }
/* * 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 int yubikey_authorize(void *instance, REQUEST *request) { // VALUE_PAIR *state; // VALUE_PAIR *reply; if (pairfind(request->config_items, PW_AUTHTYPE) != NULL) { RDEBUG2("WARNING: Auth-Type already set. Not setting to YUBIKEY"); return RLM_MODULE_NOOP; } RDEBUG("Setting 'Auth-Type := YUBIKEY'"); pairadd(&request->config_items, pairmake("Auth-Type", "YUBIKEY", T_OP_EQ)); return RLM_MODULE_OK; /* quiet the compiler */ instance = instance; request = request; DEBUG("rlm_yubikey: Authorizing user %s", request->username->vp_strvalue); return RLM_MODULE_OK; /* * Look for the 'state' attribute. */ /* state = pairfind(request->packet->vps, PW_STATE); if (state != NULL) { RDEBUG("Found reply to access challenge"); return RLM_MODULE_OK; } */ /* * Create the challenge, and add it to the reply. */ /* reply = pairmake("Reply-Message", "This is a challenge", T_OP_EQ); pairadd(&request->reply->vps, reply); state = pairmake("State", "0", T_OP_EQ); pairadd(&request->reply->vps, state); */ /* * Mark the packet as an Access-Challenge packet. * * The server will take care of sending it to the user. */ /* request->reply->code = PW_ACCESS_CHALLENGE; RDEBUG("Sending Access-Challenge."); return RLM_MODULE_OK; */ }
/* * add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error * attribute to reply packet */ void mschap_add_reply(REQUEST *request, VALUE_PAIR** vp, unsigned char ident, const char* name, const char* value, int len) { VALUE_PAIR *reply_attr; reply_attr = pairmake(name, "", T_OP_EQ); if (!reply_attr) { RDEBUG("Failed to create attribute %s: %s\n", name, fr_strerror()); return; } reply_attr->vp_octets[0] = ident; memcpy(reply_attr->vp_octets + 1, value, len); reply_attr->length = len + 1; pairadd(vp, reply_attr); }
int rad_set_eap_id(RADIUS_PACKET* rp) { VALUE_PAIR* vp = NULL; char eap_id[8] = {0}; bzero(eap_id,sizeof(eap_id)); snprintf(eap_id,sizeof(eap_id),"%d",rp->id); vp = pairmake("EAP-Id",eap_id,T_OP_SET); if(vp == NULL) { return -1; } pairadd(&rp->vps,vp); return 0; }
/* * Add value pair to reply */ static void add_reply(VALUE_PAIR** vp, const char* name, const uint8_t *value, size_t len) { VALUE_PAIR *reply_attr; reply_attr = pairmake(name, "", T_OP_EQ); if (!reply_attr) { DEBUG("rlm_eap_sim: " "add_reply failed to create attribute %s: %s\n", name, fr_strerror()); return; } memcpy(reply_attr->vp_strvalue, value, len); reply_attr->length = len; pairadd(vp, reply_attr); }
/* * Make a VALUE_PAIR from a policy_assignment_t* * * The assignment operator has to be '='. */ static VALUE_PAIR *assign2vp(REQUEST *request, const policy_assignment_t *assign) { VALUE_PAIR *vp; FR_TOKEN operator = T_OP_EQ; const char *value = assign->rhs; char buffer[2048]; if ((assign->rhs_type == POLICY_LEX_DOUBLE_QUOTED_STRING) && (strchr(assign->rhs, '%') != NULL)) { radius_xlat(buffer, sizeof(buffer), assign->rhs, request, NULL, NULL); value = buffer; } /* * This is crappy.. fix it. */ switch (assign->assign) { case POLICY_LEX_ASSIGN: operator = T_OP_EQ; break; case POLICY_LEX_SET_EQUALS: operator = T_OP_SET; break; case POLICY_LEX_PLUS_EQUALS: operator = T_OP_ADD; break; default: fprintf(stderr, "Expected '=' for operator, not '%s' at line %d\n", fr_int2str(rlm_policy_tokens, assign->assign, "?"), assign->item.lineno); return NULL; } vp = pairmake(assign->lhs, value, operator); if (!vp) { fprintf(stderr, "Failed creating pair: %s %s\n", value, fr_strerror()); } return vp; }
/* * * Verify that a Perl SV is a string and save it in FreeRadius * Value Pair Format * */ static int pairadd_sv(TALLOC_CTX *ctx, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op) { char *val; VALUE_PAIR *vp; if (SvOK(sv)) { val = SvPV_nolen(sv); vp = pairmake(ctx, vps, key, val, op); if (vp != NULL) { DEBUG("rlm_perl: Added pair %s = %s", key, val); return 1; } else { EDEBUG("rlm_perl: Failed to create pair %s = %s", key, val); } } return 0; }
/* * 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 int stg_authorize(void *, REQUEST *request) { const STG_PAIR * pairs; const STG_PAIR * pair; size_t count = 0; instance = instance; DEBUG("rlm_stg: stg_authorize()"); if (request->username) { DEBUG("rlm_stg: stg_authorize() request username field: '%s'", request->username->vp_strvalue); } if (request->password) { DEBUG("rlm_stg: stg_authorize() request password field: '%s'", request->password->vp_strvalue); } // Here we need to define Framed-Protocol VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE); if (svc) { DEBUG("rlm_stg: stg_authorize() Service-Type defined as '%s'", svc->vp_strvalue); pairs = stgAuthorizeImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue); } else { DEBUG("rlm_stg: stg_authorize() Service-Type undefined"); pairs = stgAuthorizeImpl((const char *)request->username->vp_strvalue, ""); } if (!pairs) { DEBUG("rlm_stg: stg_authorize() failed."); return RLM_MODULE_REJECT; } pair = pairs; while (!emptyPair(pair)) { VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET); pairadd(&request->config_items, pwd); DEBUG("Adding pair '%s': '%s'", pair->key, pair->value); ++pair; ++count; } deletePairs(pairs); if (count) return RLM_MODULE_UPDATED; return RLM_MODULE_NOOP; }
/* * Add a "Proxy-To-Realm" attribute to the request. */ static void add_proxy_to_realm(VALUE_PAIR **vps, REALM *realm) { VALUE_PAIR *vp; /* * Tell the server to proxy this request to another * realm. */ vp = pairmake("Proxy-To-Realm", realm->name, T_OP_EQ); if (!vp) { radlog(L_ERR, "no memory"); exit(1); } /* * Add it, even if it's already present. */ pairadd(vps, vp); }
/* * * Verify that a Perl SV is a string and save it in FreeRadius * Value Pair Format * */ static int pairadd_sv(VALUE_PAIR **vp, char *key, SV *sv, int operator) { char *val; VALUE_PAIR *vpp; if (SvOK(sv)) { val = SvPV_nolen(sv); vpp = pairmake(key, val, operator); if (vpp != NULL) { pairadd(vp, vpp); radlog(L_DBG, "rlm_perl: Added pair %s = %s", key, val); return 1; } else { radlog(L_DBG, "rlm_perl: ERROR: Failed to create pair %s = %s", key, val); } } return 0; }
static int chap_authorize(void *instance, REQUEST *request) { /* quiet the compiler */ instance = instance; request = request; if (!pairfind(request->packet->vps, PW_CHAP_PASSWORD)) { return RLM_MODULE_NOOP; } if (pairfind(request->config_items, PW_AUTHTYPE) != NULL) { RDEBUG2("WARNING: Auth-Type already set. Not setting to CHAP"); return RLM_MODULE_NOOP; } RDEBUG("Setting 'Auth-Type := CHAP'"); pairadd(&request->config_items, pairmake("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 smsotp_authorize(void *instance, REQUEST *request) { VALUE_PAIR *state; rlm_smsotp_t *opt = instance; /* quiet the compiler */ instance = instance; request = request; /* * 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'",opt->smsotp_authtype); pairdelete(&request->config_items, PW_AUTH_TYPE, 0, TAG_ANY); /* delete old auth-type */ pairadd(&request->config_items, pairmake("Auth-Type", opt->smsotp_authtype, T_OP_SET)); } return RLM_MODULE_OK; }
static int stg_postauth(void *, REQUEST *request) { const STG_PAIR * pairs; const STG_PAIR * pair; size_t count = 0; instance = instance; DEBUG("rlm_stg: stg_postauth()"); VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE); if (svc) { DEBUG("rlm_stg: stg_postauth() Service-Type defined as '%s'", svc->vp_strvalue); pairs = stgPostAuthImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue); } else { DEBUG("rlm_stg: stg_postauth() Service-Type undefined"); pairs = stgPostAuthImpl((const char *)request->username->vp_strvalue, ""); } if (!pairs) { DEBUG("rlm_stg: stg_postauth() failed."); return RLM_MODULE_REJECT; } pair = pairs; while (!emptyPair(pair)) { VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET); pairadd(&request->reply->vps, pwd); ++pair; ++count; } deletePairs(pairs); if (count) return RLM_MODULE_UPDATED; return RLM_MODULE_NOOP; }
static int mongo_authorize(void *instance, REQUEST *request) { if (request->username == NULL) return RLM_MODULE_NOOP; rlm_mongo_t *data = (rlm_mongo_t *) instance; char password[MONGO_STRING_LENGTH] = ""; char mac[MONGO_STRING_LENGTH] = ""; if (strcmp(data->mac_field, "") != 0) { char mac_temp[MONGO_STRING_LENGTH] = ""; radius_xlat(mac_temp, MONGO_STRING_LENGTH, "%{Calling-Station-Id}", request, NULL); format_mac(mac_temp, mac); } if (!find_radius_options(data, request->username->vp_strvalue, mac, password)) { return RLM_MODULE_REJECT; } RDEBUG("Authorisation request by username -> \"%s\"\n", request->username->vp_strvalue); RDEBUG("Password found in MongoDB -> \"%s\"\n\n", password); VALUE_PAIR *vp; /* quiet the compiler */ instance = instance; request = request; vp = pairmake("Cleartext-Password", password, T_OP_SET); if (!vp) return RLM_MODULE_FAIL; pairmove(&request->config_items, &vp); pairfree(&vp); return RLM_MODULE_OK; }
/* * Add the 'SQL-User-Name' attribute to the packet. */ static int sql_set_user(rlm_sql_log_t *inst, REQUEST *request, char *sqlusername, const char *username) { VALUE_PAIR *vp=NULL; char tmpuser[MAX_STRING_LEN]; tmpuser[0] = '\0'; sqlusername[0] = '\0'; rad_assert(request != NULL); rad_assert(request->packet != NULL); /* Remove any user attr we added previously */ pairdelete(&request->packet->vps, PW_SQL_USER_NAME); if (username != NULL) { strlcpy(tmpuser, username, MAX_STRING_LEN); } else if (inst->sql_user_name[0] != '\0') { radius_xlat(tmpuser, sizeof(tmpuser), inst->sql_user_name, request, NULL); } else { return 0; } if (tmpuser[0] != '\0') { strlcpy(sqlusername, tmpuser, sizeof(tmpuser)); RDEBUG2("sql_set_user escaped user --> '%s'", sqlusername); vp = pairmake("SQL-User-Name", sqlusername, 0); if (vp == NULL) { radlog(L_ERR, "%s", fr_strerror()); return -1; } pairadd(&request->packet->vps, vp); return 0; } return -1; }
/* * * Verify that a Perl SV is a string and save it in FreeRadius * Value Pair Format * */ static int pairadd_sv(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **vps, char *key, SV *sv, FR_TOKEN op, const char *hashname, const char *list_name) { char *val; VALUE_PAIR *vp; if (SvOK(sv)) { STRLEN len; val = SvPV(sv, len); vp = pairmake(ctx, vps, key, NULL, op); if (!vp) { fail: REDEBUG("Failed to create pair %s:%s %s %s", list_name, key, fr_int2str(fr_tokens, op, "<INVALID>"), val); return -1; } switch (vp->da->type) { case PW_TYPE_STRING: pairstrncpy(vp, val, len); break; case PW_TYPE_OCTETS: pairmemcpy(vp, (uint8_t const *)val, len); break; default: if (pairparsevalue(vp, val, len) < 0) goto fail; } RDEBUG("&%s:%s %s $%s{'%s'} -> '%s'", list_name, key, fr_int2str(fr_tokens, op, "<INVALID>"), hashname, key, val); return 0; } return -1; }
/* * Do EAP. */ static rlm_rcode_t eap_authenticate(void *instance, REQUEST *request) { rlm_eap_t *inst; EAP_HANDLER *handler; void *data; int data_len; rlm_rcode_t rcode; VALUE_PAIR *vp; inst = (rlm_eap_t *) instance; vp = pairfind(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY); if (!vp) { RDEBUG("No EAP-Message. Not doing EAP."); return RLM_MODULE_FAIL; } /* * Get the eap packet to start with */ data = NULL; data_len = 0; if (eap_vp2data(request->packet->vps, &data, &data_len) < 0) { radlog(L_ERR, "rlm_eap2: Malformed EAP Message"); return RLM_MODULE_FAIL; } vp = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY); if (vp) { handler = eaplist_find(inst, request); if (!handler) { RDEBUG("No handler found"); return RLM_MODULE_FAIL; } } else { handler = malloc(sizeof(*handler)); if (!handler) return RLM_MODULE_FAIL; memset(handler, 0, sizeof(*handler)); handler->inst = inst; handler->eap_cb.get_eap_user = server_get_eap_user; handler->eap_cb.get_eap_req_id_text = server_get_eap_req_id_text; handler->eap_conf.eap_server = 1; handler->eap_conf.ssl_ctx = inst->tls_ctx; /* * Copy EAP-FAST parameters. */ handler->eap_conf.pac_opaque_encr_key = inst->pac_opaque_encr_key; handler->eap_conf.eap_fast_a_id = inst->eap_fast_a_id; handler->eap_conf.eap_fast_a_id_len = strlen(inst->eap_fast_a_id); handler->eap_conf.eap_fast_a_id_info = inst->eap_fast_a_id_info; handler->eap_conf.eap_fast_prov = inst->eap_fast_prov; handler->eap_conf.pac_key_lifetime = inst->pac_key_lifetime; handler->eap_conf.pac_key_refresh_time = inst->pac_key_refresh_time; handler->eap_conf.backend_auth = inst->backend_auth; handler->server_ctx.eap = eap_server_sm_init(handler, &handler->eap_cb, &handler->eap_conf); if (handler->server_ctx.eap == NULL) { free(handler); return RLM_MODULE_FAIL; } handler->server_ctx.eap_if = eap_get_interface(handler->server_ctx.eap); /* Enable "port" and request EAP to start authentication. */ handler->server_ctx.eap_if->portEnabled = TRUE; handler->server_ctx.eap_if->eapRestart = TRUE; } handler->request = request; wpabuf_free(handler->server_ctx.eap_if->eapRespData); handler->server_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len); if (handler->server_ctx.eap_if->eapRespData) { handler->server_ctx.eap_if->eapResp = TRUE; } if (eap_example_server_step(handler) < 0) { RDEBUG("Failed in EAP library"); goto fail; } if (handler->server_ctx.eap_if->eapSuccess) { request->reply->code = PW_AUTHENTICATION_ACK; rcode = RLM_MODULE_OK; } else if (handler->server_ctx.eap_if->eapFail) { fail: request->reply->code = PW_AUTHENTICATION_REJECT; rcode = RLM_MODULE_REJECT; } else { request->reply->code = PW_ACCESS_CHALLENGE; rcode = RLM_MODULE_HANDLED; } if (handler->server_ctx.eap_if->eapFail || handler->server_ctx.eap_if->eapSuccess) { RDEBUG2("Freeing handler"); /* handler is not required any more, free it now */ eap_handler_free(handler); handler = NULL; } else { eaplist_add(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) { vp = pairmake("User-Name", request->username->vp_strvalue, T_OP_EQ); rad_assert(vp != NULL); pairadd(&(request->reply->vps), vp); } /* * Cisco AP1230 has a bug and needs a zero * terminated string in Access-Accept. */ if ((inst->cisco_accounting_username_bug) && (vp->length < (int) sizeof(vp->vp_strvalue))) { vp->vp_strvalue[vp->length] = '\0'; vp->length++; } } vp = pairfind(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); if (!vp) { vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS); memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN); vp->length = AUTH_VECTOR_LEN; pairadd(&(request->reply->vps), vp); } 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. */ static int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler) { int i, status; uint32_t lvalue; VALUE_PAIR *state; rad_assert(handler != NULL); rad_assert(handler->request != NULL); /* * Generate State, since we've been asked to add it to * the list. */ state = pairmake("State", "0x00", T_OP_EQ); if (!state) return 0; pairadd(&(handler->request->reply->vps), state); 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) { radlog(L_ERR, "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 int sqlcounter_authorize(void *instance, REQUEST *request) { rlm_sqlcounter_t *data = (rlm_sqlcounter_t *) instance; int ret=RLM_MODULE_NOOP; int counter=0; int res=0; DICT_ATTR *dattr; VALUE_PAIR *key_vp, *check_vp; VALUE_PAIR *reply_item; char msg[128]; char querystr[MAX_QUERY_LEN]; char responsestr[MAX_QUERY_LEN]; /* quiet the compiler */ instance = instance; request = request; /* * Before doing anything else, see if we have to reset * the counters. */ if (data->reset_time && (data->reset_time <= request->timestamp)) { /* * Re-set the next time and prev_time for this counters range */ data->last_reset = data->reset_time; find_next_reset(data,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 = (data->key_attr == PW_USER_NAME) ? request->username : pairfind(request->packet->vps, data->key_attr); if (key_vp == NULL) { DEBUG2("rlm_sqlcounter: Could not find Key value pair"); return ret; } /* * Look for the check item */ if ((dattr = dict_attrbyname(data->check_name)) == NULL) { return ret; } /* DEBUG2("rlm_sqlcounter: Found Check item attribute %d", dattr->attr); */ if ((check_vp= pairfind(request->config_items, dattr->attr)) == NULL) { DEBUG2("rlm_sqlcounter: Could not find Check item value pair"); return ret; } /* first, expand %k, %b and %e in query */ sqlcounter_expand(querystr, MAX_QUERY_LEN, data->query, instance); /* second, xlat any request attribs in query */ radius_xlat(responsestr, MAX_QUERY_LEN, querystr, request, sql_escape_func); /* third, wrap query with sql module & expand */ snprintf(querystr, sizeof(querystr), "%%{%%S:%s}", responsestr); sqlcounter_expand(responsestr, MAX_QUERY_LEN, querystr, instance); /* Finally, xlat resulting SQL query */ radius_xlat(querystr, MAX_QUERY_LEN, responsestr, request, sql_escape_func); counter = atoi(querystr); /* * Check if check item > counter */ res=check_vp->lvalue - counter; if (res > 0) { DEBUG2("rlm_sqlcounter: (Check item - counter) is greater than zero"); /* * 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 */ if (data->reset_time && ( res >= (data->reset_time - request->timestamp))) { res = data->reset_time - request->timestamp; res += check_vp->lvalue; } if ((reply_item = pairfind(request->reply->vps, PW_SESSION_TIMEOUT)) != NULL) { if (reply_item->lvalue > res) reply_item->lvalue = res; } else { if ((reply_item = paircreate(PW_SESSION_TIMEOUT, PW_TYPE_INTEGER)) == NULL) { radlog(L_ERR|L_CONS, "no memory"); return RLM_MODULE_NOOP; } reply_item->lvalue = res; pairadd(&request->reply->vps, reply_item); } ret=RLM_MODULE_OK; DEBUG2("rlm_sqlcounter: Authorized user %s, check_item=%d, counter=%d", key_vp->strvalue,check_vp->lvalue,counter); DEBUG2("rlm_sqlcounter: Sent Reply-Item for user %s, Type=Session-Timeout, value=%d", key_vp->strvalue,reply_item->lvalue); } else{ char module_fmsg[MAX_STRING_LEN]; VALUE_PAIR *module_fmsg_vp; 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", data->reset); reply_item=pairmake("Reply-Message", msg, T_OP_EQ); pairadd(&request->reply->vps, reply_item); snprintf(module_fmsg, sizeof(module_fmsg), "rlm_sqlcounter: Maximum %s usage time reached", data->reset); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); ret=RLM_MODULE_REJECT; DEBUG2("rlm_sqlcounter: Rejected user %s, check_item=%d, counter=%d", key_vp->strvalue,check_vp->lvalue,counter); } return ret; }
/* * 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; rad_assert(session != NULL); rad_assert(request != NULL); /* * 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("State", session->state, T_OP_EQ); if (!state) return -1; state->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); radlog(L_ERR, "rlm_securid: Failed to store session"); return -1; } pairadd(&(request->reply->vps), state); return 0; }
/* * *presult is "did comparison match or not" */ static int radius_do_cmp(REQUEST *request, int *presult, FR_TOKEN lt, const char *pleft, FR_TOKEN token, FR_TOKEN rt, const char *pright, int cflags, int modreturn) { int result; uint32_t lint, rint; VALUE_PAIR *vp = NULL; #ifdef HAVE_REGEX_H char buffer[8192]; #else cflags = cflags; /* -Wunused */ #endif rt = rt; /* -Wunused */ if (lt == T_BARE_WORD) { /* * Maybe check the last return code. */ if (token == T_OP_CMP_TRUE) { int isreturn; /* * Looks like a return code, treat is as such. */ isreturn = fr_str2int(modreturn_table, pleft, -1); if (isreturn != -1) { *presult = (modreturn == isreturn); return TRUE; } } /* * Bare words on the left can be attribute names. */ if (radius_get_vp(request, pleft, &vp)) { VALUE_PAIR myvp; /* * VP exists, and that's all we're looking for. */ if (token == T_OP_CMP_TRUE) { *presult = (vp != NULL); return TRUE; } if (!vp) { DICT_ATTR *da; /* * The attribute on the LHS may * have been a dynamically * registered callback. i.e. it * doesn't exist as a VALUE_PAIR. * If so, try looking for it. */ da = dict_attrbyname(pleft); if (da && (da->vendor == 0) && radius_find_compare(da->attr)) { VALUE_PAIR *check = pairmake(pleft, pright, token); *presult = (radius_callback_compare(request, NULL, check, NULL, NULL) == 0); RDEBUG3(" Callback returns %d", *presult); pairfree(&check); return TRUE; } RDEBUG2(" (Attribute %s was not found)", pleft); *presult = 0; return TRUE; } #ifdef HAVE_REGEX_H /* * Regex comparisons treat everything as * strings. */ if ((token == T_OP_REG_EQ) || (token == T_OP_REG_NE)) { vp_prints_value(buffer, sizeof(buffer), vp, 0); pleft = buffer; goto do_checks; } #endif memcpy(&myvp, vp, sizeof(myvp)); if (!pairparsevalue(&myvp, pright)) { RDEBUG2("Failed parsing \"%s\": %s", pright, fr_strerror()); return FALSE; } myvp.operator = token; *presult = paircmp(&myvp, vp); RDEBUG3(" paircmp -> %d", *presult); return TRUE; } /* else it's not a VP in a list */ } #ifdef HAVE_REGEX_H do_checks: #endif switch (token) { case T_OP_GE: case T_OP_GT: case T_OP_LE: case T_OP_LT: if (!all_digits(pright)) { RDEBUG2(" (Right field is not a number at: %s)", pright); return FALSE; } rint = strtoul(pright, NULL, 0); if (!all_digits(pleft)) { RDEBUG2(" (Left field is not a number at: %s)", pleft); return FALSE; } lint = strtoul(pleft, NULL, 0); break; default: lint = rint = 0; /* quiet the compiler */ break; } switch (token) { case T_OP_CMP_TRUE: /* * Check for truth or falsehood. */ if (all_digits(pleft)) { lint = strtoul(pleft, NULL, 0); result = (lint != 0); } else { result = (*pleft != '\0'); } break; case T_OP_CMP_EQ: result = (strcmp(pleft, pright) == 0); break; case T_OP_NE: result = (strcmp(pleft, pright) != 0); break; case T_OP_GE: result = (lint >= rint); break; case T_OP_GT: result = (lint > rint); break; case T_OP_LE: result = (lint <= rint); break; case T_OP_LT: result = (lint < rint); break; #ifdef HAVE_REGEX_H case T_OP_REG_EQ: { int i, compare; regex_t reg; regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; /* * Include substring matches. */ compare = regcomp(®, pright, cflags); if (compare != 0) { if (debug_flag) { char errbuf[128]; regerror(compare, ®, errbuf, sizeof(errbuf)); DEBUG("ERROR: Failed compiling regular expression: %s", errbuf); } return FALSE; } compare = regexec(®, pleft, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); /* * Add new %{0}, %{1}, etc. */ if (compare == 0) for (i = 0; i <= REQUEST_MAX_REGEX; i++) { char *r; free(request_data_get(request, request, REQUEST_DATA_REGEX | i)); /* * No %{i}, skip it. * We MAY have %{2} without %{1}. */ if (rxmatch[i].rm_so == -1) continue; /* * Copy substring into allocated buffer */ r = rad_malloc(rxmatch[i].rm_eo -rxmatch[i].rm_so + 1); memcpy(r, pleft + rxmatch[i].rm_so, rxmatch[i].rm_eo - rxmatch[i].rm_so); r[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0'; request_data_add(request, request, REQUEST_DATA_REGEX | i, r, free); } result = (compare == 0); } break; case T_OP_REG_NE: { int compare; regex_t reg; regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; /* * Include substring matches. */ compare = regcomp(®, pright, cflags); if (compare != 0) { if (debug_flag) { char errbuf[128]; regerror(compare, ®, errbuf, sizeof(errbuf)); DEBUG("ERROR: Failed compiling regular expression: %s", errbuf); } return FALSE; } compare = regexec(®, pleft, REQUEST_MAX_REGEX + 1, rxmatch, 0); regfree(®); result = (compare != 0); } break; #endif default: DEBUG("ERROR: Comparison operator %s is not supported", fr_token_name(token)); result = FALSE; break; } *presult = result; return TRUE; }