📄 wps_registrar.c
字号:
/* * Wi-Fi Protected Setup - Registrar * Copyright (c) 2008, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include "common.h"#include "sha256.h"#include "base64.h"#include "ieee802_11_defs.h"#include "eloop.h"#include "wps_i.h"#include "wps_dev_attr.h"#include "wps_upnp.h"struct wps_uuid_pin { struct wps_uuid_pin *next; u8 uuid[WPS_UUID_LEN]; int wildcard_uuid; u8 *pin; size_t pin_len; int locked;};static void wps_free_pin(struct wps_uuid_pin *pin){ os_free(pin->pin); os_free(pin);}static void wps_free_pins(struct wps_uuid_pin *pins){ struct wps_uuid_pin *pin, *prev; pin = pins; while (pin) { prev = pin; pin = pin->next; wps_free_pin(prev); }}struct wps_pbc_session { struct wps_pbc_session *next; u8 addr[ETH_ALEN]; u8 uuid_e[WPS_UUID_LEN]; struct os_time timestamp;};static void wps_free_pbc_sessions(struct wps_pbc_session *pbc){ struct wps_pbc_session *prev; while (pbc) { prev = pbc; pbc = pbc->next; os_free(prev); }}struct wps_registrar { struct wps_context *wps; int pbc; int selected_registrar; int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk, size_t psk_len); int (*set_ie_cb)(void *ctx, const u8 *beacon_ie, size_t beacon_ie_len, const u8 *probe_resp_ie, size_t probe_resp_ie_len); void (*pin_needed_cb)(void *ctx, const u8 *uuid_e, const struct wps_device_data *dev); void (*reg_success_cb)(void *ctx, const u8 *mac_addr, const u8 *uuid_e); void *cb_ctx; struct wps_uuid_pin *pins; struct wps_pbc_session *pbc_sessions; int skip_cred_build; struct wpabuf *extra_cred; int disable_auto_conf; int sel_reg_dev_password_id_override; int sel_reg_config_methods_override; int static_wep_only;};static int wps_set_ie(struct wps_registrar *reg);static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);static void wps_registrar_set_selected_timeout(void *eloop_ctx, void *timeout_ctx);static void wps_registrar_add_pbc_session(struct wps_registrar *reg, const u8 *addr, const u8 *uuid_e){ struct wps_pbc_session *pbc, *prev = NULL; struct os_time now; os_get_time(&now); pbc = reg->pbc_sessions; while (pbc) { if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 && os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) { if (prev) prev->next = pbc->next; else reg->pbc_sessions = pbc->next; break; } prev = pbc; pbc = pbc->next; } if (!pbc) { pbc = os_zalloc(sizeof(*pbc)); if (pbc == NULL) return; os_memcpy(pbc->addr, addr, ETH_ALEN); if (uuid_e) os_memcpy(pbc->uuid_e, uuid_e, WPS_UUID_LEN); } pbc->next = reg->pbc_sessions; reg->pbc_sessions = pbc; pbc->timestamp = now; /* remove entries that have timed out */ prev = pbc; pbc = pbc->next; while (pbc) { if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) { prev->next = NULL; wps_free_pbc_sessions(pbc); break; } prev = pbc; pbc = pbc->next; }}static void wps_registrar_remove_pbc_session(struct wps_registrar *reg, const u8 *addr, const u8 *uuid_e){ struct wps_pbc_session *pbc, *prev = NULL; pbc = reg->pbc_sessions; while (pbc) { if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 && os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) { if (prev) prev->next = pbc->next; else reg->pbc_sessions = pbc->next; os_free(pbc); break; } prev = pbc; pbc = pbc->next; }}static int wps_registrar_pbc_overlap(struct wps_registrar *reg, const u8 *addr, const u8 *uuid_e){ int count = 0; struct wps_pbc_session *pbc; struct os_time now; os_get_time(&now); for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) { if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) break; if (addr == NULL || os_memcmp(addr, pbc->addr, ETH_ALEN) || uuid_e == NULL || os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN)) count++; } if (addr || uuid_e) count++; return count > 1 ? 1 : 0;}static int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg){ wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)", wps->wps_state); wpabuf_put_be16(msg, ATTR_WPS_STATE); wpabuf_put_be16(msg, 1); wpabuf_put_u8(msg, wps->wps_state); return 0;}#ifdef CONFIG_WPS_UPNPstatic void wps_registrar_free_pending_m2(struct wps_context *wps){ struct upnp_pending_message *p, *p2, *prev = NULL; p = wps->upnp_msgs; while (p) { if (p->type == WPS_M2 || p->type == WPS_M2D) { if (prev == NULL) wps->upnp_msgs = p->next; else prev->next = p->next; wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D"); p2 = p; p = p->next; wpabuf_free(p2->msg); os_free(p2); continue; } prev = p; p = p->next; }}#endif /* CONFIG_WPS_UPNP */static int wps_build_ap_setup_locked(struct wps_context *wps, struct wpabuf *msg){ if (wps->ap_setup_locked) { wpa_printf(MSG_DEBUG, "WPS: * AP Setup Locked"); wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED); wpabuf_put_be16(msg, 1); wpabuf_put_u8(msg, 1); } return 0;}static int wps_build_selected_registrar(struct wps_registrar *reg, struct wpabuf *msg){ if (!reg->selected_registrar) return 0; wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar"); wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR); wpabuf_put_be16(msg, 1); wpabuf_put_u8(msg, 1); return 0;}static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg, struct wpabuf *msg){ u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT; if (!reg->selected_registrar) return 0; if (reg->sel_reg_dev_password_id_override >= 0) id = reg->sel_reg_dev_password_id_override; wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id); wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); wpabuf_put_be16(msg, 2); wpabuf_put_be16(msg, id); return 0;}static int wps_build_sel_reg_config_methods(struct wps_registrar *reg, struct wpabuf *msg){ u16 methods; if (!reg->selected_registrar) return 0; methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; if (reg->pbc) methods |= WPS_CONFIG_PUSHBUTTON; if (reg->sel_reg_config_methods_override >= 0) methods = reg->sel_reg_config_methods_override; wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar Config Methods (%x)", methods); wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS); wpabuf_put_be16(msg, 2); wpabuf_put_be16(msg, methods); return 0;}static int wps_build_probe_config_methods(struct wps_registrar *reg, struct wpabuf *msg){ u16 methods; methods = 0; wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); wpabuf_put_be16(msg, 2); wpabuf_put_be16(msg, methods); return 0;}static int wps_build_config_methods_r(struct wps_registrar *reg, struct wpabuf *msg){ u16 methods; methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; if (reg->pbc) methods |= WPS_CONFIG_PUSHBUTTON; return wps_build_config_methods(msg, methods);}static int wps_build_resp_type(struct wps_registrar *reg, struct wpabuf *msg){ u8 resp = reg->wps->ap ? WPS_RESP_AP : WPS_RESP_REGISTRAR; wpa_printf(MSG_DEBUG, "WPS: * Response Type (%d)", resp); wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE); wpabuf_put_be16(msg, 1); wpabuf_put_u8(msg, resp); return 0;}/** * wps_registrar_init - Initialize WPS Registrar data * @wps: Pointer to longterm WPS context * @cfg: Registrar configuration * Returns: Pointer to allocated Registrar data or %NULL on failure * * This function is used to initialize WPS Registrar functionality. It can be * used for a single Registrar run (e.g., when run in a supplicant) or multiple * runs (e.g., when run as an internal Registrar in an AP). Caller is * responsible for freeing the returned data with wps_registrar_deinit() when * Registrar functionality is not needed anymore. */struct wps_registrar *wps_registrar_init(struct wps_context *wps, const struct wps_registrar_config *cfg){ struct wps_registrar *reg = os_zalloc(sizeof(*reg)); if (reg == NULL) return NULL; reg->wps = wps; reg->new_psk_cb = cfg->new_psk_cb; reg->set_ie_cb = cfg->set_ie_cb; reg->pin_needed_cb = cfg->pin_needed_cb; reg->reg_success_cb = cfg->reg_success_cb; reg->cb_ctx = cfg->cb_ctx; reg->skip_cred_build = cfg->skip_cred_build; if (cfg->extra_cred) { reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred, cfg->extra_cred_len); if (reg->extra_cred == NULL) { os_free(reg); return NULL; } } reg->disable_auto_conf = cfg->disable_auto_conf; reg->sel_reg_dev_password_id_override = -1; reg->sel_reg_config_methods_override = -1; reg->static_wep_only = cfg->static_wep_only; if (wps_set_ie(reg)) { wps_registrar_deinit(reg); return NULL; } return reg;}/** * wps_registrar_deinit - Deinitialize WPS Registrar data * @reg: Registrar data from wps_registrar_init() */void wps_registrar_deinit(struct wps_registrar *reg){ if (reg == NULL) return; eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); wps_free_pins(reg->pins); wps_free_pbc_sessions(reg->pbc_sessions); wpabuf_free(reg->extra_cred); os_free(reg);}/** * wps_registrar_add_pin - Configure a new PIN for Registrar * @reg: Registrar data from wps_registrar_init() * @uuid: UUID-E or %NULL for wildcard (any UUID) * @pin: PIN (Device Password) * @pin_len: Length of pin in octets * Returns: 0 on success, -1 on failure */int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid, const u8 *pin, size_t pin_len){ struct wps_uuid_pin *p; p = os_zalloc(sizeof(*p)); if (p == NULL) return -1; if (uuid == NULL) p->wildcard_uuid = 1; else os_memcpy(p->uuid, uuid, WPS_UUID_LEN); p->pin = os_malloc(pin_len); if (p->pin == NULL) { os_free(p); return -1; } os_memcpy(p->pin, pin, pin_len); p->pin_len = pin_len; p->next = reg->pins; reg->pins = p; wpa_printf(MSG_DEBUG, "WPS: A new PIN configured"); wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN); wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len); reg->selected_registrar = 1; reg->pbc = 0; wps_set_ie(reg); return 0;}/** * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E * @reg: Registrar data from wps_registrar_init() * @uuid: UUID-E * Returns: 0 on success, -1 on failure (e.g., PIN not found) */int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid){ struct wps_uuid_pin *pin, *prev; prev = NULL; pin = reg->pins; while (pin) { if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) { if (prev == NULL) reg->pins = pin->next; else prev->next = pin->next; wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID", pin->uuid, WPS_UUID_LEN); wps_free_pin(pin); return 0; } prev = pin; pin = pin->next; } return -1;}static const u8 * wps_registrar_get_pin(struct wps_registrar *reg, const u8 *uuid, size_t *pin_len){ struct wps_uuid_pin *pin; pin = reg->pins; while (pin) { if (!pin->wildcard_uuid && os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) break; pin = pin->next; } if (!pin) { /* Check for wildcard UUIDs since none of the UUID-specific
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -