static void handle_reload(int sig, void *eloop_ctx, void *signal_ctx) { struct hapd_interfaces *hapds = (struct hapd_interfaces *) eloop_ctx; struct hostapd_config *newconf; int i; printf("Signal %d received - reloading configuration\n", sig); for (i = 0; i < hapds->count; i++) { hostapd *hapd = hapds->hapd[i]; newconf = hostapd_config_read(hapd->config_fname); if (newconf == NULL) { printf("Failed to read new configuration file - " "continuing with old.\n"); continue; } /* TODO: update dynamic data based on changed configuration * items (e.g., open/close sockets, remove stations added to * deny list, etc.) */ radius_client_flush(hapd->radius); hostapd_config_free(hapd->conf); hapd->conf = newconf; #ifdef JUMPSTART hostapd_setup_interface(hapd); #endif /* JUMSTART */ } }
int hostapd_reload_config(struct hostapd_iface *iface) { struct hostapd_data *hapd = iface->bss[0]; struct hostapd_config *newconf, *oldconf; size_t j; if (iface->interfaces == NULL || iface->interfaces->config_read_cb == NULL) return -1; newconf = iface->interfaces->config_read_cb(iface->config_fname); if (newconf == NULL) return -1; /* * Deauthenticate all stations since the new configuration may not * allow them to use the BSS anymore. */ for (j = 0; j < iface->num_bss; j++) { hostapd_flush_old_stations(iface->bss[j], WLAN_REASON_PREV_AUTH_NOT_VALID); hostapd_broadcast_wep_clear(iface->bss[j]); #ifndef CONFIG_NO_RADIUS /* TODO: update dynamic data based on changed configuration * items (e.g., open/close sockets, etc.) */ radius_client_flush(iface->bss[j]->radius, 0); #endif /* CONFIG_NO_RADIUS */ } oldconf = hapd->iconf; iface->conf = newconf; hostapd_select_hw_mode(iface); iface->freq = hostapd_hw_get_freq(hapd, newconf->channel); if (hostapd_set_freq(hapd, newconf->hw_mode, iface->freq, newconf->channel, newconf->ieee80211n, newconf->secondary_channel)) { wpa_printf(MSG_ERROR, "Could not set channel for " "kernel driver"); } if (iface->current_mode) hostapd_prepare_rates(iface, iface->current_mode); for (j = 0; j < iface->num_bss; j++) { hapd = iface->bss[j]; hapd->iconf = newconf; hapd->conf = &newconf->bss[j]; hostapd_reload_bss(hapd); } hostapd_config_free(oldconf); return 0; }
static int radius_change_server(struct radius_client_data *radius, struct hostapd_radius_server *nserv, struct hostapd_radius_server *oserv, int sock, int auth) { struct hostapd_data *hapd = radius->hapd; struct sockaddr_in serv; hostapd_logger(hapd, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "%s server %s:%d", auth ? "Authentication" : "Accounting", inet_ntoa(nserv->addr), nserv->port); if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len || memcmp(nserv->shared_secret, oserv->shared_secret, nserv->shared_secret_len) != 0) { /* Pending RADIUS packets used different shared * secret, so they would need to be modified. Could * update all message authenticators and * User-Passwords, etc. and retry with new server. For * now, just drop all pending packets. */ radius_client_flush(radius); } else { /* Reset retry counters for the new server */ struct radius_msg_list *entry; entry = radius->msgs; while (entry) { entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; entry->attempts = 0; entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; entry = entry->next; } if (radius->msgs) { eloop_cancel_timeout(radius_client_timer, radius, NULL); eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, radius_client_timer, radius, NULL); } } memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_addr.s_addr = nserv->addr.s_addr; serv.sin_port = htons(nserv->port); if (connect(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0) { perror("connect[radius]"); return -1; } return 0; }
void radius_client_deinit(struct radius_client_data *radius) { if (!radius) return; eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL); radius_client_flush(radius); free(radius->auth_handlers); free(radius->acct_handlers); free(radius); }
void radius_client_deinit(hostapd *hapd) { if (!hapd->radius) return; eloop_cancel_timeout(radius_retry_primary_timer, hapd, NULL); radius_client_flush(hapd); free(hapd->radius->auth_handlers); free(hapd->radius->acct_handlers); free(hapd->radius); hapd->radius = NULL; }
void radius_client_deinit(struct wpa_supplicant *wpa_s) { if (!wpa_s->radius) return; eloop_cancel_timeout(radius_retry_primary_timer, wpa_s, NULL); radius_client_flush(wpa_s); free(wpa_s->radius->auth_handlers); free(wpa_s->radius->acct_handlers); free(wpa_s->radius); wpa_s->radius = NULL; }
void radius_client_deinit(struct radius_client_data *radius) { if (!radius) return; if (radius->auth_serv_sock >= 0) eloop_unregister_read_sock(radius->auth_serv_sock); if (radius->acct_serv_sock >= 0) eloop_unregister_read_sock(radius->acct_serv_sock); eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL); radius_client_flush(radius, 0); os_free(radius->auth_handlers); os_free(radius->acct_handlers); os_free(radius); }
int hostapd_reload_config(struct hostapd_iface *iface) { struct hostapd_data *hapd = iface->bss[0]; struct hostapd_config *newconf, *oldconf; size_t j; if (iface->config_read_cb == NULL) return -1; newconf = iface->config_read_cb(iface->config_fname); if (newconf == NULL) return -1; /* * Deauthenticate all stations since the new configuration may not * allow them to use the BSS anymore. */ for (j = 0; j < iface->num_bss; j++) { hostapd_flush_old_stations(iface->bss[j], WLAN_REASON_PREV_AUTH_NOT_VALID); hostapd_broadcast_wep_clear(iface->bss[j]); #ifndef CONFIG_NO_RADIUS /* TODO: update dynamic data based on changed configuration * items (e.g., open/close sockets, etc.) */ radius_client_flush(iface->bss[j]->radius, 0); #endif /* CONFIG_NO_RADIUS */ } oldconf = hapd->iconf; iface->conf = newconf; for (j = 0; j < iface->num_bss; j++) { hapd = iface->bss[j]; hapd->iconf = newconf; hapd->conf = &newconf->bss[j]; hostapd_reload_bss(hapd); } hostapd_config_free(oldconf); return 0; }
static void hostapd_clear_old(struct hostapd_iface *iface) { size_t j; /* * Deauthenticate all stations since the new configuration may not * allow them to use the BSS anymore. */ for (j = 0; j < iface->num_bss; j++) { hostapd_flush_old_stations(iface->bss[j], WLAN_REASON_PREV_AUTH_NOT_VALID); hostapd_broadcast_wep_clear(iface->bss[j]); #ifndef CONFIG_NO_RADIUS /* TODO: update dynamic data based on changed configuration * items (e.g., open/close sockets, etc.) */ radius_client_flush(iface->bss[j]->radius, 0); #endif /* CONFIG_NO_RADIUS */ } }
struct radius_client_data * radius_client_reconfig(struct radius_client_data *old, void *ctx, struct hostapd_radius_servers *oldconf, struct hostapd_radius_servers *newconf) { radius_client_flush(old, 0); if (newconf->retry_primary_interval != oldconf->retry_primary_interval || newconf->num_auth_servers != oldconf->num_auth_servers || newconf->num_acct_servers != oldconf->num_acct_servers || radius_servers_diff(newconf->auth_servers, oldconf->auth_servers, newconf->num_auth_servers) || radius_servers_diff(newconf->acct_servers, oldconf->acct_servers, newconf->num_acct_servers)) { hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Reconfiguring RADIUS client"); radius_client_deinit(old); return radius_client_init(ctx, newconf); } return old; }
static int radius_change_server(struct radius_client_data *radius, struct hostapd_radius_server *nserv, struct hostapd_radius_server *oserv, int sock, int sock6, int auth) { struct sockaddr_in serv, claddr; #ifdef CONFIG_IPV6 struct sockaddr_in6 serv6, claddr6; #endif /* CONFIG_IPV6 */ struct sockaddr *addr, *cl_addr; socklen_t addrlen, claddrlen; char abuf[50]; int sel_sock; struct radius_msg_list *entry; struct hostapd_radius_servers *conf = radius->conf; struct sockaddr_in disconnect_addr = { .sin_family = AF_UNSPEC, }; hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "%s server %s:%d", auth ? "Authentication" : "Accounting", hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), nserv->port); if (oserv && oserv == nserv) { /* Reconnect to same server, flush */ if (auth) radius_client_flush(radius, 1); } if (oserv && oserv != nserv && (nserv->shared_secret_len != oserv->shared_secret_len || os_memcmp(nserv->shared_secret, oserv->shared_secret, nserv->shared_secret_len) != 0)) { /* Pending RADIUS packets used different shared secret, so * they need to be modified. Update accounting message * authenticators here. Authentication messages are removed * since they would require more changes and the new RADIUS * server may not be prepared to receive them anyway due to * missing state information. Client will likely retry * authentication, so this should not be an issue. */ if (auth) radius_client_flush(radius, 1); else { radius_client_update_acct_msgs( radius, nserv->shared_secret, nserv->shared_secret_len); } } /* Reset retry counters for the new server */ for (entry = radius->msgs; oserv && oserv != nserv && entry; entry = entry->next) { if ((auth && entry->msg_type != RADIUS_AUTH) || (!auth && entry->msg_type != RADIUS_ACCT)) continue; entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; entry->attempts = 0; entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; } if (radius->msgs) { eloop_cancel_timeout(radius_client_timer, radius, NULL); eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, radius_client_timer, radius, NULL); } switch (nserv->addr.af) { case AF_INET: os_memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr; serv.sin_port = htons(nserv->port); addr = (struct sockaddr *) &serv; addrlen = sizeof(serv); sel_sock = sock; break; #ifdef CONFIG_IPV6 case AF_INET6: os_memset(&serv6, 0, sizeof(serv6)); serv6.sin6_family = AF_INET6; os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6, sizeof(struct in6_addr)); serv6.sin6_port = htons(nserv->port); addr = (struct sockaddr *) &serv6; addrlen = sizeof(serv6); sel_sock = sock6; break; #endif /* CONFIG_IPV6 */ default: return -1; } if (sel_sock < 0) { wpa_printf(MSG_INFO, "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d", nserv->addr.af, sock, sock6, auth); return -1; } if (conf->force_client_addr) { switch (conf->client_addr.af) { case AF_INET: os_memset(&claddr, 0, sizeof(claddr)); claddr.sin_family = AF_INET; claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr; claddr.sin_port = htons(0); cl_addr = (struct sockaddr *) &claddr; claddrlen = sizeof(claddr); break; #ifdef CONFIG_IPV6 case AF_INET6: os_memset(&claddr6, 0, sizeof(claddr6)); claddr6.sin6_family = AF_INET6; os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6, sizeof(struct in6_addr)); claddr6.sin6_port = htons(0); cl_addr = (struct sockaddr *) &claddr6; claddrlen = sizeof(claddr6); break; #endif /* CONFIG_IPV6 */ default: return -1; } if (bind(sel_sock, cl_addr, claddrlen) < 0) { wpa_printf(MSG_INFO, "bind[radius]: %s", strerror(errno)); return -1; } } /* Force a reconnect by disconnecting the socket first */ if (connect(sel_sock, (struct sockaddr *) &disconnect_addr, sizeof(disconnect_addr)) < 0) wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno)); if (connect(sel_sock, addr, addrlen) < 0) { wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno)); return -1; } #ifndef CONFIG_NATIVE_WINDOWS switch (nserv->addr.af) { case AF_INET: claddrlen = sizeof(claddr); if (getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen) == 0) { wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port)); } break; #ifdef CONFIG_IPV6 case AF_INET6: { claddrlen = sizeof(claddr6); if (getsockname(sel_sock, (struct sockaddr *) &claddr6, &claddrlen) == 0) { wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", inet_ntop(AF_INET6, &claddr6.sin6_addr, abuf, sizeof(abuf)), ntohs(claddr6.sin6_port)); } break; } #endif /* CONFIG_IPV6 */ } #endif /* CONFIG_NATIVE_WINDOWS */ if (auth) radius->auth_sock = sel_sock; else radius->acct_sock = sel_sock; return 0; }
static int radius_change_server(struct radius_client_data *radius, struct hostapd_radius_server *nserv, struct hostapd_radius_server *oserv, int sock, int sock6, int auth) { struct sockaddr_in serv; #ifdef CONFIG_IPV6 struct sockaddr_in6 serv6; #endif /* CONFIG_IPV6 */ struct sockaddr *addr; socklen_t addrlen; char abuf[50]; int sel_sock; struct radius_msg_list *entry; hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "%s server %s:%d", auth ? "Authentication" : "Accounting", hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), nserv->port); if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len || os_memcmp(nserv->shared_secret, oserv->shared_secret, nserv->shared_secret_len) != 0) { /* Pending RADIUS packets used different shared secret, so * they need to be modified. Update accounting message * authenticators here. Authentication messages are removed * since they would require more changes and the new RADIUS * server may not be prepared to receive them anyway due to * missing state information. Client will likely retry * authentication, so this should not be an issue. */ if (auth) radius_client_flush(radius, 1); else { radius_client_update_acct_msgs( radius, nserv->shared_secret, nserv->shared_secret_len); } } /* Reset retry counters for the new server */ for (entry = radius->msgs; entry; entry = entry->next) { if ((auth && entry->msg_type != RADIUS_AUTH) || (!auth && entry->msg_type != RADIUS_ACCT)) continue; entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; entry->attempts = 0; entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; } if (radius->msgs) { eloop_cancel_timeout(radius_client_timer, radius, NULL); eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, radius_client_timer, radius, NULL); } switch (nserv->addr.af) { case AF_INET: os_memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr; serv.sin_port = htons(nserv->port); addr = (struct sockaddr *) &serv; addrlen = sizeof(serv); sel_sock = sock; break; #ifdef CONFIG_IPV6 case AF_INET6: os_memset(&serv6, 0, sizeof(serv6)); serv6.sin6_family = AF_INET6; os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6, sizeof(struct in6_addr)); serv6.sin6_port = htons(nserv->port); addr = (struct sockaddr *) &serv6; addrlen = sizeof(serv6); sel_sock = sock6; break; #endif /* CONFIG_IPV6 */ default: return -1; } if (connect(sel_sock, addr, addrlen) < 0) { perror("connect[radius]"); return -1; } if (auth) radius->auth_sock = sel_sock; else radius->acct_sock = sel_sock; return 0; }
static void hostapd_reconfig_bss(struct hostapd_data *hapd, struct hostapd_bss_config *newbss, struct hostapd_bss_config *oldbss, struct hostapd_config *oldconf, int beacon_changed) { struct hostapd_config_change change; int encr_changed = 0; struct radius_client_data *old_radius; radius_client_flush(hapd->radius, 0); if (hostapd_set_dtim_period(hapd, newbss->dtim_period)) printf("Could not set DTIM period for kernel driver\n"); if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len || memcmp(newbss->ssid.ssid, oldbss->ssid.ssid, newbss->ssid.ssid_len) != 0) { if (hostapd_set_ssid(hapd, (u8 *) newbss->ssid.ssid, newbss->ssid.ssid_len)) printf("Could not set SSID for kernel driver\n"); beacon_changed++; } if (newbss->ignore_broadcast_ssid != oldbss->ignore_broadcast_ssid) beacon_changed++; if (hostapd_wep_key_cmp(&newbss->ssid.wep, &oldbss->ssid.wep)) { encr_changed++; beacon_changed++; } vlan_reconfig(hapd, oldconf, oldbss); if (beacon_changed) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Updating beacon frame " "information\n"); ieee802_11_set_beacon(hapd); } change.hapd = hapd; change.oldconf = oldconf; change.newconf = hapd->iconf; change.oldbss = oldbss; change.newbss = newbss; change.mac_acl_changed = hostapd_acl_diff(newbss, oldbss); if (newbss->max_num_sta != oldbss->max_num_sta && newbss->max_num_sta < hapd->num_sta) { change.num_sta_remove = hapd->num_sta - newbss->max_num_sta; } else change.num_sta_remove = 0; ap_for_each_sta(hapd, hostapd_config_reload_sta, &change); old_radius = hapd->radius; hapd->radius = radius_client_reconfig(hapd->radius, hapd, oldbss->radius, newbss->radius); hapd->radius_client_reconfigured = old_radius != hapd->radius || hostapd_ip_diff(&newbss->own_ip_addr, &oldbss->own_ip_addr); ieee802_1x_reconfig(hapd, oldconf, oldbss); iapp_reconfig(hapd, oldconf, oldbss); hostapd_acl_reconfig(hapd, oldconf); accounting_reconfig(hapd, oldconf); }
static int radius_change_server(struct radius_client_data *radius, struct hostapd_radius_server *nserv, struct hostapd_radius_server *oserv, int sock, int sock6, int auth) { struct sockaddr_in serv; #ifdef CONFIG_IPV6 struct sockaddr_in6 serv6; #endif /* CONFIG_IPV6 */ struct sockaddr *addr; socklen_t addrlen; char abuf[50]; int sel_sock; hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "%s server %s:%d", auth ? "Authentication" : "Accounting", hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), nserv->port); if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len || memcmp(nserv->shared_secret, oserv->shared_secret, nserv->shared_secret_len) != 0) { /* Pending RADIUS packets used different shared * secret, so they would need to be modified. Could * update all message authenticators and * User-Passwords, etc. and retry with new server. For * now, just drop all pending packets. */ radius_client_flush(radius); } else { /* Reset retry counters for the new server */ struct radius_msg_list *entry; entry = radius->msgs; while (entry) { entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; entry->attempts = 0; entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; entry = entry->next; } if (radius->msgs) { eloop_cancel_timeout(radius_client_timer, radius, NULL); eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, radius_client_timer, radius, NULL); } } switch (nserv->addr.af) { case AF_INET: memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr; serv.sin_port = htons(nserv->port); addr = (struct sockaddr *) &serv; addrlen = sizeof(serv); sel_sock = sock; break; #ifdef CONFIG_IPV6 case AF_INET6: memset(&serv6, 0, sizeof(serv6)); serv6.sin6_family = AF_INET6; memcpy(&serv6.sin6_addr, &nserv->addr.u.v6, sizeof(struct in6_addr)); serv6.sin6_port = htons(nserv->port); addr = (struct sockaddr *) &serv6; addrlen = sizeof(serv6); sel_sock = sock6; break; #endif /* CONFIG_IPV6 */ default: return -1; } if (connect(sel_sock, addr, addrlen) < 0) { perror("connect[radius]"); return -1; } if (auth) radius->auth_sock = sel_sock; else radius->acct_sock = sel_sock; return 0; }