static fr_io_final_t mod_process(UNUSED void const *instance, REQUEST *request, fr_io_action_t action) { rlm_rcode_t rcode; CONF_SECTION *unlang; REQUEST_VERIFY(request); /* * Pass this through asynchronously to the module which * is waiting for something to happen. */ if (action != FR_IO_ACTION_RUN) { unlang_signal(request, (fr_state_signal_t) action); return FR_IO_DONE; } switch (request->request_state) { case REQUEST_INIT: request->component = "radius"; unlang = cf_section_find(request->server_cs, "new", "client"); if (!unlang) { RWDEBUG("Failed to find 'new client' section"); request->reply->code = FR_CODE_ACCESS_REJECT; goto send_reply; } RDEBUG("Running 'new client' from file %s", cf_filename(unlang)); unlang_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME); request->request_state = REQUEST_RECV; /* FALL-THROUGH */ case REQUEST_RECV: rcode = unlang_interpret_resume(request); if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE; if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD; rad_assert(request->log.unlang_indent == 0); switch (rcode) { case RLM_MODULE_OK: case RLM_MODULE_UPDATED: request->reply->code = FR_CODE_ACCESS_ACCEPT; break; case RLM_MODULE_FAIL: case RLM_MODULE_HANDLED: request->reply->code = 0; /* don't reply */ break; default: case RLM_MODULE_REJECT: request->reply->code = FR_CODE_ACCESS_REJECT; break; } unlang = cf_section_find(request->server_cs, "add", "client"); if (!unlang) goto send_reply; rerun_nak: RDEBUG("Running '%s client' from file %s", cf_section_name1(unlang), cf_filename(unlang)); unlang_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME); request->request_state = REQUEST_SEND; /* FALL-THROUGH */ case REQUEST_SEND: rcode = unlang_interpret_resume(request); if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE; if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD; rad_assert(request->log.unlang_indent == 0); switch (rcode) { case RLM_MODULE_NOOP: case RLM_MODULE_OK: case RLM_MODULE_UPDATED: case RLM_MODULE_HANDLED: /* reply is already set */ break; default: /* * If we over-ride an ACK with a NAK, run * the NAK section. */ if (request->reply->code != FR_CODE_ACCESS_REJECT) { RWDEBUG("Failed running 'add client', trying 'deny client'."); deny: request->reply->code = FR_CODE_ACCESS_REJECT; unlang = cf_section_find(request->server_cs, "deny", "client"); if (unlang) goto rerun_nak; RWDEBUG("Not running 'deny client' section as it does not exist"); } break; } if (request->reply->code == FR_CODE_ACCESS_ACCEPT) { VALUE_PAIR *vp; vp = fr_pair_find_by_da(request->control, attr_freeradius_client_ip_address, TAG_ANY); if (!vp) fr_pair_find_by_da(request->control, attr_freeradius_client_ipv6_address, TAG_ANY); if (!vp) fr_pair_find_by_da(request->control, attr_freeradius_client_ip_prefix, TAG_ANY); if (!vp) fr_pair_find_by_da(request->control, attr_freeradius_client_ipv6_prefix, TAG_ANY); if (!vp) { ERROR("The 'control' list MUST contain a FreeRADIUS-Client.. IP address attribute"); goto deny; } vp = fr_pair_find_by_da(request->control, attr_freeradius_client_secret, TAG_ANY); if (!vp) { ERROR("The 'control' list MUST contain a FreeRADIUS-Client-Secret attribute"); goto deny; } /* * Else we're flexible. */ } send_reply: /* * This is an internally generated request. Don't print IP addresses. */ if (request->reply->code == FR_CODE_ACCESS_ACCEPT) { RDEBUG("Adding client"); } else { RDEBUG("Denying client"); } break; default: return FR_IO_FAIL; } return FR_IO_REPLY; }
static fr_io_final_t mod_process(UNUSED void const *instance, REQUEST *request, fr_io_action_t action) { VALUE_PAIR *vp; rlm_rcode_t rcode; CONF_SECTION *unlang; REQUEST_VERIFY(request); /* * Pass this through asynchronously to the module which * is waiting for something to happen. */ if (action != FR_IO_ACTION_RUN) { unlang_signal(request, (fr_state_signal_t) action); return FR_IO_DONE; } switch (request->request_state) { case REQUEST_INIT: RDEBUG("Received %s ID %i", fr_dict_enum_alias_by_value(attr_packet_type, fr_box_uint32(request->reply->code)), request->packet->id); log_request_pair_list(L_DBG_LVL_1, request, request->packet->vps, ""); request->component = "radius"; unlang = cf_section_find(request->server_cs, "recv", NULL); if (!unlang) { REDEBUG("Failed to find 'recv' section"); return FR_IO_FAIL; } RDEBUG("Running 'recv' from file %s", cf_filename(unlang)); unlang_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME); request->request_state = REQUEST_RECV; /* FALL-THROUGH */ case REQUEST_RECV: rcode = unlang_interpret_continue(request); if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE; if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD; rad_assert(request->log.unlang_indent == 0); switch (rcode) { /* * The module has a number of OK return codes. */ case RLM_MODULE_OK: case RLM_MODULE_UPDATED: switch (request->packet->code) { case FR_CODE_ACCOUNTING_REQUEST: request->reply->code = FR_CODE_ACCOUNTING_RESPONSE; break; case FR_CODE_COA_REQUEST: request->reply->code = FR_CODE_COA_ACK; break; case FR_CODE_DISCONNECT_REQUEST: request->reply->code = FR_CODE_DISCONNECT_ACK; break; default: request->reply->code = 0; break; } break; case RLM_MODULE_HANDLED: break; /* * The module failed, or said the request is * invalid, therefore we stop here. */ case RLM_MODULE_NOOP: case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_NOTFOUND: case RLM_MODULE_REJECT: case RLM_MODULE_USERLOCK: default: request->reply->code = 0; break; } /* * Allow for over-ride of reply code. */ vp = fr_pair_find_by_da(request->reply->vps, attr_packet_type, TAG_ANY); if (vp) request->reply->code = vp->vp_uint32; if (request->reply->code == FR_CODE_DO_NOT_RESPOND) { RWARN("Ignoring 'do_not_respond' as it does not apply to detail files"); } unlang = cf_section_find(request->server_cs, "send", "ok"); if (!unlang) goto send_reply; RDEBUG("Running 'send %s { ... }' from file %s", cf_section_name2(unlang), cf_filename(unlang)); unlang_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME); request->request_state = REQUEST_SEND; /* FALL-THROUGH */ case REQUEST_SEND: rcode = unlang_interpret_continue(request); if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE; if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD; rad_assert(request->log.unlang_indent == 0); switch (rcode) { case RLM_MODULE_NOOP: case RLM_MODULE_OK: case RLM_MODULE_UPDATED: case RLM_MODULE_HANDLED: /* reply is already set */ break; default: request->reply->code = 0; break; } send_reply: /* * Failed, but we still reply with a magic code, * so that the reader can retransmit. */ if (!request->reply->code) { REDEBUG("Failed ID %i", request->reply->id); } else { RDEBUG("Sent %s ID %i", fr_dict_enum_alias_by_value(attr_packet_type, fr_box_uint32(request->reply->code)), request->reply->id); } log_request_proto_pair_list(L_DBG_LVL_1, request, request->reply->vps, ""); break; default: return FR_IO_FAIL; } return FR_IO_REPLY; }
/** Very simple state machine to process requests * * Unlike normal protocol requests which may have multiple distinct states, * we really only have REQUEST_INIT and REQUEST_RECV phases. * * Conversion of LDAPMessage to VALUE_PAIR structs is done in the listener * because we cannot easily duplicate the LDAPMessage to send it across to * the worker for parsing. * * Most LDAP directories can only handle between 2000-5000 modifications a second * so we're unlikely to be I/O or CPU bound using this division of responsibilities. * * @param[in] request to process. * @param[in] action If something has signalled that the request should stop * being processed. */ static void request_running(REQUEST *request, fr_state_signal_t action) { CONF_SECTION *unlang; char const *verb; char const *state; rlm_rcode_t rcode = RLM_MODULE_FAIL; REQUEST_VERIFY(request); /* * Async (in the same thread, tho) signal to be done. */ if (action == FR_SIGNAL_CANCEL) goto done; /* * We ignore all other actions. */ if (action != FR_SIGNAL_RUN) return; switch (request->request_state) { case REQUEST_INIT: if (RDEBUG_ENABLED) proto_ldap_packet_debug(request, request->packet, true); log_request_proto_pair_list(L_DBG_LVL_1, request, request->packet->vps, ""); request->server_cs = request->listener->server_cs; request->component = "ldap"; switch (request->packet->code) { case LDAP_SYNC_CODE_PRESENT: verb = "recv"; state = "Present"; break; case LDAP_SYNC_CODE_ADD: verb = "recv"; state = "Add"; break; case LDAP_SYNC_CODE_MODIFY: verb = "recv"; state = "Modify"; break; case LDAP_SYNC_CODE_DELETE: verb = "recv"; state = "Delete"; break; case LDAP_SYNC_CODE_COOKIE_LOAD: verb = "load"; state = "Cookie"; break; case LDAP_SYNC_CODE_COOKIE_STORE: verb = "store"; state = "Cookie"; break; default: rad_assert(0); return; } unlang = cf_section_find(request->server_cs, verb, state); if (!unlang) unlang = cf_section_find(request->server_cs, "recv", "*"); if (!unlang) { RDEBUG2("Ignoring %s operation. Add \"%s %s {}\" to virtual-server \"%s\"" " to handle", fr_int2str(ldap_sync_code_table, request->packet->code, "<INVALID>"), verb, state, cf_section_name2(request->server_cs)); rcode = RLM_MODULE_NOOP; goto done; } RDEBUG("Running '%s %s' from file %s", cf_section_name1(unlang), cf_section_name2(unlang), cf_filename(unlang)); unlang_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME); request->request_state = REQUEST_RECV; /* FALL-THROUGH */ case REQUEST_RECV: rcode = unlang_interpret_resume(request); if (request->master_state == REQUEST_STOP_PROCESSING) goto done; if (rcode == RLM_MODULE_YIELD) return; /* FALL-THROUGH */ default: done: switch (rcode) { case RLM_MODULE_UPDATED: case RLM_MODULE_OK: { } default: break; } rad_assert(request->log.unlang_indent == 0); //request_delete(request); break; } }
static fr_io_final_t mod_process(UNUSED void const *instance, REQUEST *request, UNUSED fr_io_action_t action) { rlm_rcode_t rcode; CONF_SECTION *unlang; fr_dict_enum_t const *dv; fr_dict_attr_t const *da = NULL; VALUE_PAIR *vp; REQUEST_VERIFY(request); rad_assert(request->packet->code > 0); rad_assert(request->packet->code <= FR_DHCP_INFORM); switch (request->request_state) { case REQUEST_INIT: RDEBUG("Received %s ID %08x", dhcp_message_types[request->packet->code], request->packet->id); log_request_proto_pair_list(L_DBG_LVL_1, request, request->packet->vps, ""); request->component = "dhcpv4"; dv = fr_dict_enum_by_value(attr_message_type, fr_box_uint8(request->packet->code)); if (!dv) { REDEBUG("Failed to find value for &request:DHCP-Message-Type"); return FR_IO_FAIL; } unlang = cf_section_find(request->server_cs, "recv", dv->alias); if (!unlang) { RWDEBUG("Failed to find 'recv %s' section", dv->alias); request->reply->code = FR_DHCP_MESSAGE_TYPE_VALUE_DHCP_DO_NOT_RESPOND; goto send_reply; } RDEBUG("Running 'recv %s' from file %s", cf_section_name2(unlang), cf_filename(unlang)); unlang_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME); request->request_state = REQUEST_RECV; /* FALL-THROUGH */ case REQUEST_RECV: rcode = unlang_interpret_continue(request); if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE; if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD; rad_assert(request->log.unlang_indent == 0); /* * Allow the admin to explicitly set the reply * type. */ vp = fr_pair_find_by_da(request->reply->vps, attr_message_type, TAG_ANY); if (vp) { request->reply->code = vp->vp_uint8; } else switch (rcode) { case RLM_MODULE_NOOP: case RLM_MODULE_OK: case RLM_MODULE_UPDATED: request->reply->code = reply_ok[request->packet->code]; break; default: case RLM_MODULE_REJECT: case RLM_MODULE_FAIL: request->reply->code = reply_fail[request->packet->code]; break; case RLM_MODULE_HANDLED: if (!request->reply->code) request->reply->code = FR_DHCP_MESSAGE_TYPE_VALUE_DHCP_DO_NOT_RESPOND; break; } /* * DHCP-Release / Decline doesn't send a reply, and doesn't run "send DHCP-Do-Not-Respond" */ if (!request->reply->code) { return FR_IO_DONE; } /* * Offer and ACK MUST have YIADDR. */ if ((request->reply->code == FR_DHCP_OFFER) || (request->reply->code == FR_DHCP_ACK)) { vp = fr_pair_find_by_da(request->reply->vps, attr_yiaddr, TAG_ANY); if (!vp) { REDEBUG("%s packet does not have YIADDR. The client will not receive an IP address.", dhcp_message_types[request->reply->code]); } } dv = fr_dict_enum_by_value(da, fr_box_uint8(request->reply->code)); unlang = NULL; if (dv) unlang = cf_section_find(request->server_cs, "send", dv->alias); if (!unlang) goto send_reply; rerun_nak: RDEBUG("Running 'send %s' from file %s", cf_section_name2(unlang), cf_filename(unlang)); unlang_push_section(request, unlang, RLM_MODULE_NOOP, UNLANG_TOP_FRAME); request->request_state = REQUEST_SEND; /* FALL-THROUGH */ case REQUEST_SEND: rcode = unlang_interpret_continue(request); if (request->master_state == REQUEST_STOP_PROCESSING) return FR_IO_DONE; if (rcode == RLM_MODULE_YIELD) return FR_IO_YIELD; rad_assert(request->log.unlang_indent == 0); switch (rcode) { case RLM_MODULE_NOOP: case RLM_MODULE_OK: case RLM_MODULE_UPDATED: case RLM_MODULE_HANDLED: /* reply is already set */ break; default: /* * If we over-ride an ACK with a NAK, run * the NAK section. */ if (request->reply->code != FR_DHCP_MESSAGE_TYPE_VALUE_DHCP_DO_NOT_RESPOND) { dv = fr_dict_enum_by_value(attr_message_type, fr_box_uint8(request->reply->code)); RWDEBUG("Failed running 'send %s', trying 'send Do-Not-Respond'", dv->alias); request->reply->code = FR_DHCP_MESSAGE_TYPE_VALUE_DHCP_DO_NOT_RESPOND; dv = fr_dict_enum_by_value(da, fr_box_uint8(request->reply->code)); unlang = NULL; if (!dv) goto send_reply; unlang = cf_section_find(request->server_cs, "send", dv->alias); if (unlang) goto rerun_nak; RWDEBUG("Not running 'send %s' section as it does not exist", dv->alias); } break; } send_reply: /* * Check for "do not respond". */ if (request->reply->code == FR_DHCP_MESSAGE_TYPE_VALUE_DHCP_DO_NOT_RESPOND) { RDEBUG("Not sending reply to client"); return FR_IO_DONE; } if (RDEBUG_ENABLED) common_packet_debug(request, request->reply, false); break; default: return FR_IO_FAIL; } return FR_IO_REPLY; }