📄 event.c
字号:
* Delete any reply we had accumulated until now. */ pairfree(&request->reply->vps); /* * Run the packet through the post-proxy stage, * BEFORE playing games with the attributes. */ vp = pairfind(request->config_items, PW_POST_PROXY_TYPE); if (vp) { DEBUG2(" Found Post-Proxy-Type %s", vp->vp_strvalue); post_proxy_type = vp->vp_integer; } rad_assert(request->home_pool != NULL); if (request->home_pool->virtual_server) { const char *old_server = request->server; request->server = request->home_pool->virtual_server; DEBUG2(" server %s {", request->server); rcode = module_post_proxy(post_proxy_type, request); DEBUG2(" }"); request->server = old_server; } else { rcode = module_post_proxy(post_proxy_type, request); } /* * There may NOT be a proxy reply, as we may be * running Post-Proxy-Type = Fail. */ if (request->proxy_reply) { /* * Delete the Proxy-State Attributes from * the reply. These include Proxy-State * attributes from us and remote server. */ pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE); /* * Add the attributes left in the proxy * reply to the reply list. */ pairadd(&request->reply->vps, request->proxy_reply->vps); request->proxy_reply->vps = NULL; /* * Free proxy request pairs. */ pairfree(&request->proxy->vps); } switch (rcode) { default: /* Don't do anything */ break; case RLM_MODULE_FAIL: /* FIXME: debug print stuff */ request->child_state = REQUEST_DONE; return 0; case RLM_MODULE_HANDLED: /* FIXME: debug print stuff */ request->child_state = REQUEST_DONE; return 0; } } return 1;}/* * Do state handling when we proxy a request. */static int proxy_request(REQUEST *request){ struct timeval when; char buffer[128]; if (!insert_into_proxy_hash(request)) { DEBUG("ERROR: Failed inserting request into proxy hash."); return 0; } request->proxy_listener->encode(request->proxy_listener, request); when = request->received; when.tv_sec += request->root->max_request_time; gettimeofday(&request->proxy_when, NULL); request->next_when = request->proxy_when; request->next_when.tv_sec += request->home_server->response_window; rad_assert(request->home_server->response_window > 0); if (timercmp(&when, &request->next_when, <)) { request->next_when = when; } request->next_callback = no_response_to_proxied_request; DEBUG2("Proxying request %d to home server %s port %d", request->number, inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), request->proxy->dst_port); /* * Note that we set proxied BEFORE sending the packet. * * Once we send it, the request is tainted, as * another thread may have picked it up. Don't * touch it! */ request->num_proxied_requests = 1; request->num_proxied_responses = 0; request->child_pid = NO_SUCH_CHILD_PID; request->child_state = REQUEST_PROXIED; request->proxy_listener->send(request->proxy_listener, request); return 1;}/* * "Proxy" the request by sending it to a new virtual server. */static int proxy_to_virtual_server(REQUEST *request){ REQUEST *fake; if (!request->home_server || !request->home_server->server) return 0; if (request->parent) { DEBUG2("WARNING: Cancelling proxy request to virtual server %s as this request was itself proxied.", request->home_server->server); return 0; } fake = request_alloc_fake(request); if (!fake) { DEBUG2("WARNING: Out of memory"); return 0; } fake->packet->vps = paircopy(request->proxy->vps); fake->server = request->home_server->server; DEBUG2(">>> Sending proxied request internally to virtual server."); radius_handle_request(fake, rad_authenticate); DEBUG2("<<< Received proxied response from internal virtual server."); request->proxy_reply = fake->reply; fake->reply = NULL; /* * And run it through the post-proxy section... */ rad_authenticate(request); return 2; /* success, but NOT '1' !*/}/* * Return 1 if we did proxy it, or the proxy attempt failed * completely. Either way, the caller doesn't touch the request * any more if we return 1. */static int successfully_proxied_request(REQUEST *request){ int rcode; int pre_proxy_type = 0; VALUE_PAIR *realmpair; VALUE_PAIR *strippedname; VALUE_PAIR *vp; char *realmname; home_server *home; REALM *realm = NULL; home_pool_t *pool; /* * If it was already proxied, do nothing. * * FIXME: This should really be a serious error. */ if (request->in_proxy_hash) { return 0; } realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM); if (!realmpair || (realmpair->length == 0)) { return 0; } realmname = (char *) realmpair->vp_strvalue; realm = realm_find2(realmname); if (!realm) { DEBUG2("ERROR: Cannot proxy to unknown realm %s", realmname); return 0; } /* * Figure out which pool to use. */ if (request->packet->code == PW_AUTHENTICATION_REQUEST) { pool = realm->auth_pool; } else if (request->packet->code == PW_ACCOUNTING_REQUEST) { pool = realm->acct_pool; } else { rad_panic("Internal sanity check failed"); } if (!pool) { DEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.", realmname); return 0; } home = home_server_ldb(realmname, pool, request); if (!home) { DEBUG2("ERROR: Failed to find live home server for realm %s", realmname); return -1; } request->home_pool = pool; /* * Remember that we sent the request to a Realm. */ pairadd(&request->packet->vps, pairmake("Realm", realmname, T_OP_EQ)); /* * We read the packet from a detail file, AND it came from * the server we're about to send it to. Don't do that. */ if ((request->packet->code == PW_ACCOUNTING_REQUEST) && (request->listener->type == RAD_LISTEN_DETAIL) && (home->ipaddr.af == AF_INET) && (request->packet->src_ipaddr.af == AF_INET) && (home->ipaddr.ipaddr.ip4addr.s_addr == request->packet->src_ipaddr.ipaddr.ip4addr.s_addr)) { DEBUG2(" rlm_realm: Packet came from realm %s, proxy cancelled", realmname); return 0; } /* * Allocate the proxy packet, only if it wasn't already * allocated by a module. This check is mainly to support * the proxying of EAP-TTLS and EAP-PEAP tunneled requests. * * In those cases, the EAP module creates a "fake" * request, and recursively passes it through the * authentication stage of the server. The module then * checks if the request was supposed to be proxied, and * if so, creates a proxy packet from the TUNNELED request, * and not from the EAP request outside of the tunnel. * * The proxy then works like normal, except that the response * packet is "eaten" by the EAP module, and encapsulated into * an EAP packet. */ if (!request->proxy) { if ((request->proxy = rad_alloc(TRUE)) == NULL) { radlog(L_ERR|L_CONS, "no memory"); exit(1); } /* * Copy the request, then look up name and * plain-text password in the copy. * * Note that the User-Name attribute is the * *original* as sent over by the client. The * Stripped-User-Name attribute is the one hacked * through the 'hints' file. */ request->proxy->vps = paircopy(request->packet->vps); } /* * Strip the name, if told to. * * Doing it here catches the case of proxied tunneled * requests. */ if (realm->striprealm == TRUE && (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) { /* * If there's a Stripped-User-Name attribute in * the request, then use THAT as the User-Name * for the proxied request, instead of the * original name. * * This is done by making a copy of the * Stripped-User-Name attribute, turning it into * a User-Name attribute, deleting the * Stripped-User-Name and User-Name attributes * from the vps list, and making the new * User-Name the head of the vps list. */ vp = pairfind(request->proxy->vps, PW_USER_NAME); if (!vp) { vp = radius_paircreate(request, NULL, PW_USER_NAME, PW_TYPE_STRING); rad_assert(vp != NULL); /* handled by above function */ /* Insert at the START of the list */ vp->next = request->proxy->vps; request->proxy->vps = vp; } memcpy(vp->vp_strvalue, strippedname->vp_strvalue, sizeof(vp->vp_strvalue)); vp->length = strippedname->length; /* * Do NOT delete Stripped-User-Name. */ } /* * If there is no PW_CHAP_CHALLENGE attribute but * there is a PW_CHAP_PASSWORD we need to add it * since we can't use the request authenticator * anymore - we changed it. */ if (pairfind(request->proxy->vps, PW_CHAP_PASSWORD) && pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) { vp = radius_paircreate(request, &request->proxy->vps, PW_CHAP_CHALLENGE, PW_TYPE_OCTETS); vp->length = AUTH_VECTOR_LEN; memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN); } /* * The RFC's say we have to do this, but FreeRADIUS * doesn't need it. */ vp = radius_paircreate(request, &request->proxy->vps, PW_PROXY_STATE, PW_TYPE_OCTETS); snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), "%d", request->packet->id); vp->length = strlen(vp->vp_strvalue); /* * Should be done BEFORE inserting into proxy hash, as * pre-proxy may use this information, or change it. */ request->proxy->code = request->packet->code; request->proxy->dst_ipaddr = home->ipaddr; request->proxy->dst_port = home->port; request->home_server = home; /* * Call the pre-proxy routines. */ vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE); if (vp) { DEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue); pre_proxy_type = vp->vp_integer; } rad_assert(request->home_pool != NULL); if (request->home_pool->virtual_server) { const char *old_server = request->server; request->server = request->home_pool->virtual_server; DEBUG2(" server %s {", request->server); rcode = module_pre_proxy(pre_proxy_type, request); DEBUG2(" }"); request->server = old_server; } else { rcode = module_pre_proxy(pre_proxy_type, request); } switch (rcode) { case RLM_MODULE_FAIL: case RLM_MODULE_INVALID: case RLM_MODULE_NOTFOUND: case RLM_MODULE_USERLOCK: default: /* FIXME: debug print failed stuff */ return -1; case RLM_MODULE_REJECT: case RLM_MODULE_HANDLED: return 0; /* * Only proxy the packet if the pre-proxy code succeeded. */ case RLM_MODULE_NOOP: case RLM_MODULE_OK: case RLM_MODULE_UPDATED: break; } /* * If it's a fake request, don't send the proxy * packet. The outer tunnel session will take * care of doing that. */ if (request->packet->dst_port == 0) { request->home_server = NULL; return 1; } if (request->home_server->server) { return proxy_to_virtual_server(request); } if (!proxy_request(request)) { DEBUG("ERROR: Failed to proxy request %d", request->number); return -1; } return 1;}static void request_post_handler(REQUEST *request){ int child_state = -1; struct timeval when; VALUE_PAIR *vp; if ((request->master_state == REQUEST_STOP_PROCESSING) || (request->parent && (request->parent->master_state == REQUEST_STOP_PROCESSING))) { DEBUG2("Request %d was cancelled.", request->number); request->child_pid = NO_SUCH_CHILD_PID; request->child_state = REQUEST_DONE; return; } if (request->child_state != REQUEST_RUNNING) { rad_panic("Internal sanity check failed"); } if ((request->reply->code == 0) && ((vp = pairfind(request->config_items, PW_AUTH_TYPE)) != NULL) && (vp->vp_integer == PW_AUTHTYPE_REJECT)) { request->reply->code = PW_AUTHENTICATION_REJECT; } if (request->root->proxy_requests && !request->in_proxy_hash && (request->reply->code == 0) && (request->packet->dst_port != 0) && (request->packet->code != PW_STATUS_SERVER)) { int rcode = successfully_proxied_request(request); if (rcode == 1) return; /* * Failed proxying it (dead home servers, etc.) * Run it through Post-Proxy-Type = Fail, and * respond to the request. * * Note that we're in a child thread here, so we * do NOT re-schedule the request. Instead, we * do what we would have done, which is run the * pre-handler, a NULL request handler, and then * the post handler. */ if ((rcode < 0) && setup_post_proxy_fail(request)) { request_pre_handler(request); } /* * Else we weren't supposed to proxy it, * OR we proxied it internally to a virutal server. */ } /* * Fake requests don't get encoded or signed. The caller * also requires the reply VP's, so we don't free them * here! */ if (request->packet->dst_port == 0) { /* FIXME: DEBUG going to the next request */ request->child_pid = NO_SUCH_CHILD_PID; request->child_state = REQUEST_DONE; return; } /* * Copy Proxy-State from the request to the reply. */ vp = paircopy2(request->packet->vps, PW_PROXY_STATE); if (vp) pairadd(&request->reply->vps, vp); /* * Access-Requests get delayed or cached. */ switch (request->packet->code) { case PW_AUTHENTICATION_REQUEST: gettimeofday(&request->next_when, NULL); if (request->reply->code == 0) { /* * Check if the lack of response is intentional. */ vp = pairfind(request->config_items, PW_RESPONSE_PACKET_TYPE); if (!vp || (vp->vp_integer != 256)) { DEBUG2("There was no response configured: rejecting request %d", request->number); request->reply->code = PW_AUTHENTICATION_REJECT; } else { DEBUG2("Not responding to request %d", request->number); } } /* * Run rejected packets through * * Post-Auth-Type = Reject
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -