/** Copy packet to multiple servers * * Create a duplicate of the packet and send it to a list of realms * defined by the presence of the Replicate-To-Realm VP in the control * list of the current request. * * This is pretty hacky and is 100% fire and forget. If you're looking * to forward authentication requests to multiple realms and process * the responses, this function will not allow you to do that. * * @param[in] instance of this module. * @param[in] request The current request. * @param[in] list of attributes to copy to the duplicate packet. * @param[in] code to write into the code field of the duplicate packet. * @return RCODE fail on error, invalid if list does not exist, noop if no * replications succeeded, else ok. */ static int replicate_packet(UNUSED void *instance, REQUEST *request, pair_lists_t list, unsigned int code) { int rcode = RLM_MODULE_NOOP; VALUE_PAIR *vp, **vps, *last; home_server *home; REALM *realm; home_pool_t *pool; RADIUS_PACKET *packet = NULL; last = request->config_items; /* * Send as many packets as necessary to different * destinations. */ while (1) { vp = pairfind(last, PW_REPLICATE_TO_REALM, 0, TAG_ANY); if (!vp) break; last = vp->next; realm = realm_find2(vp->vp_strvalue); if (!realm) { RDEBUG2E("Cannot Replicate to unknown realm %s", realm); continue; } /* * We shouldn't really do this on every loop. */ switch (request->packet->code) { default: RDEBUG2E("Cannot replicate unknown packet code %d", request->packet->code); cleanup(packet); return RLM_MODULE_FAIL; case PW_AUTHENTICATION_REQUEST: pool = realm->auth_pool; break; #ifdef WITH_ACCOUNTING case PW_ACCOUNTING_REQUEST: pool = realm->acct_pool; break; #endif #ifdef WITH_COA case PW_COA_REQUEST: case PW_DISCONNECT_REQUEST: pool = realm->acct_pool; break; #endif } if (!pool) { RDEBUG2W("Cancelling replication to Realm %s, as the realm is local.", realm->name); continue; } home = home_server_ldb(realm->name, pool, request); if (!home) { RDEBUG2E("Failed to find live home server for realm %s", realm->name); continue; } /* * For replication to multiple servers we re-use the packet * we built here. */ if (!packet) { packet = rad_alloc(NULL, 1); if (!packet) return RLM_MODULE_FAIL; packet->sockfd = -1; packet->code = code; packet->id = fr_rand() & 0xff; packet->sockfd = fr_socket(&home->src_ipaddr, 0); if (packet->sockfd < 0) { RDEBUGE("Failed opening socket: %s", fr_strerror()); rcode = RLM_MODULE_FAIL; goto done; } vps = radius_list(request, list); if (!vps) { RDEBUGW("List '%s' doesn't exist for " "this packet", fr_int2str(pair_lists, list, "?unknown?")); rcode = RLM_MODULE_INVALID; goto done; } /* * Don't assume the list actually contains any * attributes. */ if (*vps) { packet->vps = paircopy(packet, *vps); if (!packet->vps) { rcode = RLM_MODULE_FAIL; goto done; } } /* * For CHAP, create the CHAP-Challenge if * it doesn't exist. */ if ((code == PW_AUTHENTICATION_REQUEST) && (pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY) != NULL) && (pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY) == NULL)) { vp = radius_paircreate(request, &packet->vps, PW_CHAP_CHALLENGE, 0); vp->length = AUTH_VECTOR_LEN; memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN); } } else { size_t i; for (i = 0; i < sizeof(packet->vector); i++) { packet->vector[i] = fr_rand() & 0xff; } packet->id++; free(packet->data); packet->data = NULL; packet->data_len = 0; } /* * (Re)-Write these. */ packet->dst_ipaddr = home->ipaddr; packet->dst_port = home->port; memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr)); packet->src_port = 0; /* * Encode, sign and then send the packet. */ RDEBUG("Replicating list '%s' to Realm '%s'", fr_int2str(pair_lists, list, "¿unknown?"),realm->name); if (rad_send(packet, NULL, home->secret) < 0) { RDEBUGE("Failed replicating packet: %s", fr_strerror()); rcode = RLM_MODULE_FAIL; goto done; } /* * We've sent it to at least one destination. */ rcode = RLM_MODULE_OK; } done: cleanup(packet); return rcode; }
/* * Write accounting information to this modules database. */ static int replicate_packet(void *instance, REQUEST *request) { int rcode = RLM_MODULE_NOOP; VALUE_PAIR *vp, *last; home_server *home; REALM *realm; home_pool_t *pool; RADIUS_PACKET *packet = NULL; instance = instance; /* -Wunused */ last = request->config_items; /* * Send as many packets as necessary to different * destinations. */ while (1) { vp = pairfind(last, PW_REPLICATE_TO_REALM, 0); if (!vp) break; last = vp->next; realm = realm_find2(vp->vp_strvalue); if (!realm) { RDEBUG2("ERROR: Cannot Replicate to unknown realm %s", realm); continue; } /* * We shouldn't really do this on every loop. */ switch (request->packet->code) { default: RDEBUG2("ERROR: Cannot replicate unknown packet code %d", request->packet->code); cleanup(packet); return RLM_MODULE_FAIL; case PW_AUTHENTICATION_REQUEST: pool = realm->auth_pool; break; #ifdef WITH_ACCOUNTING case PW_ACCOUNTING_REQUEST: pool = realm->acct_pool; break; #endif #ifdef WITH_COA case PW_COA_REQUEST: case PW_DISCONNECT_REQUEST: pool = realm->acct_pool; break; #endif } if (!pool) { RDEBUG2(" WARNING: Cancelling replication to Realm %s, as the realm is local.", realm->name); continue; } home = home_server_ldb(realm->name, pool, request); if (!home) { RDEBUG2("ERROR: Failed to find live home server for realm %s", realm->name); continue; } if (!packet) { packet = rad_alloc(1); if (!packet) return RLM_MODULE_FAIL; packet->sockfd = -1; packet->code = request->packet->code; packet->id = fr_rand() & 0xff; packet->sockfd = fr_socket(&home->src_ipaddr, 0); if (packet->sockfd < 0) { RDEBUG("ERROR: Failed opening socket: %s", fr_strerror()); cleanup(packet); return RLM_MODULE_FAIL; } packet->vps = paircopy(request->packet->vps); if (!packet->vps) { RDEBUG("ERROR: Out of memory!"); cleanup(packet); return RLM_MODULE_FAIL; } /* * For CHAP, create the CHAP-Challenge if * it doesn't exist. */ if ((request->packet->code == PW_AUTHENTICATION_REQUEST) && (pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0) != NULL) && (pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0) == NULL)) { vp = radius_paircreate(request, &packet->vps, PW_CHAP_CHALLENGE, 0, PW_TYPE_OCTETS); vp->length = AUTH_VECTOR_LEN; memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN); } } else { size_t i; for (i = 0; i < sizeof(packet->vector); i++) { packet->vector[i] = fr_rand() & 0xff; } packet->id++; free(packet->data); packet->data = NULL; packet->data_len = 0; } /* * (Re)-Write these. */ packet->dst_ipaddr = home->ipaddr; packet->dst_port = home->port; memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr)); packet->src_port = 0; /* * Encode, sign and then send the packet. */ RDEBUG("Replicating packet to Realm %s", realm->name); if (rad_send(packet, NULL, home->secret) < 0) { RDEBUG("ERROR: Failed replicating packet: %s", fr_strerror()); cleanup(packet); return RLM_MODULE_FAIL; } /* * We've sent it to at least one destination. */ rcode = RLM_MODULE_OK; } cleanup(packet); return rcode; }
/** Copy packet to multiple servers * * Create a duplicate of the packet and send it to a list of realms * defined by the presence of the Replicate-To-Realm VP in the control * list of the current request. * * This is pretty hacky and is 100% fire and forget. If you're looking * to forward authentication requests to multiple realms and process * the responses, this function will not allow you to do that. * * @param[in] instance of this module. * @param[in] request The current request. * @param[in] list of attributes to copy to the duplicate packet. * @param[in] code to write into the code field of the duplicate packet. * @return RCODE fail on error, invalid if list does not exist, noop if no replications succeeded, else ok. */ static rlm_rcode_t replicate_packet(UNUSED void *instance, REQUEST *request, pair_lists_t list, PW_CODE code) { int rcode = RLM_MODULE_NOOP; bool pass1 = true; vp_cursor_t cursor; VALUE_PAIR *vp; RADIUS_PACKET *packet = NULL; rcode = rlm_replicate_alloc(&packet, request, list, code); if (rcode != RLM_MODULE_OK) { return rcode; } /* * Send as many packets as necessary to different destinations. */ fr_cursor_init(&cursor, &request->config_items); while ((vp = fr_cursor_next_by_num(&cursor, PW_REPLICATE_TO_REALM, 0, TAG_ANY))) { home_server_t *home; REALM *realm; home_pool_t *pool; realm = realm_find2(vp->vp_strvalue); if (!realm) { REDEBUG2("Cannot Replicate to unknown realm \"%s\"", vp->vp_strvalue); continue; } /* * We shouldn't really do this on every loop. */ switch (request->packet->code) { default: REDEBUG2("Cannot replicate unknown packet code %d", request->packet->code); rcode = RLM_MODULE_FAIL; goto done; case PW_CODE_ACCESS_REQUEST: pool = realm->auth_pool; break; #ifdef WITH_ACCOUNTING case PW_CODE_ACCOUNTING_REQUEST: pool = realm->acct_pool; break; #endif #ifdef WITH_COA case PW_CODE_COA_REQUEST: case PW_CODE_DISCONNECT_REQUEST: pool = realm->acct_pool; break; #endif } if (!pool) { RWDEBUG2("Cancelling replication to Realm %s, as the realm is local", realm->name); continue; } home = home_server_ldb(realm->name, pool, request); if (!home) { REDEBUG2("Failed to find live home server for realm %s", realm->name); continue; } /* * For replication to multiple servers we re-use the packet * we built here. */ if (pass1) { packet->id = fr_rand() & 0xff; packet->sockfd = fr_socket(&home->src_ipaddr, 0); if (packet->sockfd < 0) { REDEBUG("Failed opening socket: %s", fr_strerror()); rcode = RLM_MODULE_FAIL; goto done; } pass1 = false; } else { size_t i; for (i = 0; i < sizeof(packet->vector); i++) { packet->vector[i] = fr_rand() & 0xff; } packet->id++; TALLOC_FREE(packet->data); packet->data_len = 0; } /* * (Re)-Write these. */ packet->dst_ipaddr = home->ipaddr; packet->dst_port = home->port; memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr)); packet->src_port = 0; /* * Encode, sign and then send the packet. */ RDEBUG("Replicating list '%s' to Realm '%s'", fr_int2str(pair_lists, list, "<INVALID>"), realm->name); if (rad_send(packet, NULL, home->secret) < 0) { REDEBUG("Failed replicating packet: %s", fr_strerror()); rcode = RLM_MODULE_FAIL; goto done; } /* * We've sent it to at least one destination. */ rcode = RLM_MODULE_OK; } done: talloc_free(packet); return rcode; }