diff options
Diffstat (limited to 'contrib/wpa/src/utils')
42 files changed, 2233 insertions, 208 deletions
diff --git a/contrib/wpa/src/utils/base64.c b/contrib/wpa/src/utils/base64.c index d44f290..53a92f4 100644 --- a/contrib/wpa/src/utils/base64.c +++ b/contrib/wpa/src/utils/base64.c @@ -1,41 +1,38 @@ /* * Base64 encoding/decoding (RFC1341) - * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" +#include <stdint.h> #include "os.h" #include "base64.h" static const unsigned char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const unsigned char base64_url_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; -/** - * base64_encode - Base64 encode - * @src: Data to be encoded - * @len: Length of the data to be encoded - * @out_len: Pointer to output length variable, or %NULL if not used - * Returns: Allocated buffer of out_len bytes of encoded data, - * or %NULL on failure - * - * Caller is responsible for freeing the returned buffer. Returned buffer is - * nul terminated to make it easier to use as a C string. The nul terminator is - * not included in out_len. - */ -unsigned char * base64_encode(const unsigned char *src, size_t len, - size_t *out_len) + +static unsigned char * base64_gen_encode(const unsigned char *src, size_t len, + size_t *out_len, + const unsigned char *table, + int add_pad) { unsigned char *out, *pos; const unsigned char *end, *in; size_t olen; int line_len; + if (len >= SIZE_MAX / 4) + return NULL; olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ - olen += olen / 72; /* line feeds */ + if (add_pad) + olen += olen / 72; /* line feeds */ olen++; /* nul termination */ if (olen < len) return NULL; /* integer overflow */ @@ -48,35 +45,35 @@ unsigned char * base64_encode(const unsigned char *src, size_t len, pos = out; line_len = 0; while (end - in >= 3) { - *pos++ = base64_table[(in[0] >> 2) & 0x3f]; - *pos++ = base64_table[(((in[0] & 0x03) << 4) | - (in[1] >> 4)) & 0x3f]; - *pos++ = base64_table[(((in[1] & 0x0f) << 2) | - (in[2] >> 6)) & 0x3f]; - *pos++ = base64_table[in[2] & 0x3f]; + *pos++ = table[(in[0] >> 2) & 0x3f]; + *pos++ = table[(((in[0] & 0x03) << 4) | (in[1] >> 4)) & 0x3f]; + *pos++ = table[(((in[1] & 0x0f) << 2) | (in[2] >> 6)) & 0x3f]; + *pos++ = table[in[2] & 0x3f]; in += 3; line_len += 4; - if (line_len >= 72) { + if (add_pad && line_len >= 72) { *pos++ = '\n'; line_len = 0; } } if (end - in) { - *pos++ = base64_table[(in[0] >> 2) & 0x3f]; + *pos++ = table[(in[0] >> 2) & 0x3f]; if (end - in == 1) { - *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f]; - *pos++ = '='; + *pos++ = table[((in[0] & 0x03) << 4) & 0x3f]; + if (add_pad) + *pos++ = '='; } else { - *pos++ = base64_table[(((in[0] & 0x03) << 4) | - (in[1] >> 4)) & 0x3f]; - *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f]; + *pos++ = table[(((in[0] & 0x03) << 4) | + (in[1] >> 4)) & 0x3f]; + *pos++ = table[((in[1] & 0x0f) << 2) & 0x3f]; } - *pos++ = '='; + if (add_pad) + *pos++ = '='; line_len += 4; } - if (line_len) + if (add_pad && line_len) *pos++ = '\n'; *pos = '\0'; @@ -86,26 +83,18 @@ unsigned char * base64_encode(const unsigned char *src, size_t len, } -/** - * base64_decode - Base64 decode - * @src: Data to be decoded - * @len: Length of the data to be decoded - * @out_len: Pointer to output length variable - * Returns: Allocated buffer of out_len bytes of decoded data, - * or %NULL on failure - * - * Caller is responsible for freeing the returned buffer. - */ -unsigned char * base64_decode(const unsigned char *src, size_t len, - size_t *out_len) +static unsigned char * base64_gen_decode(const unsigned char *src, size_t len, + size_t *out_len, + const unsigned char *table) { unsigned char dtable[256], *out, *pos, block[4], tmp; size_t i, count, olen; int pad = 0; + size_t extra_pad; os_memset(dtable, 0x80, 256); for (i = 0; i < sizeof(base64_table) - 1; i++) - dtable[base64_table[i]] = (unsigned char) i; + dtable[table[i]] = (unsigned char) i; dtable['='] = 0; count = 0; @@ -114,21 +103,28 @@ unsigned char * base64_decode(const unsigned char *src, size_t len, count++; } - if (count == 0 || count % 4) + if (count == 0) return NULL; + extra_pad = (4 - count % 4) % 4; - olen = count / 4 * 3; + olen = (count + extra_pad) / 4 * 3; pos = out = os_malloc(olen); if (out == NULL) return NULL; count = 0; - for (i = 0; i < len; i++) { - tmp = dtable[src[i]]; + for (i = 0; i < len + extra_pad; i++) { + unsigned char val; + + if (i >= len) + val = '='; + else + val = src[i]; + tmp = dtable[val]; if (tmp == 0x80) continue; - if (src[i] == '=') + if (val == '=') pad++; block[count] = tmp; count++; @@ -155,3 +151,53 @@ unsigned char * base64_decode(const unsigned char *src, size_t len, *out_len = pos - out; return out; } + + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable, or %NULL if not used + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. Returned buffer is + * nul terminated to make it easier to use as a C string. The nul terminator is + * not included in out_len. + */ +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len) +{ + return base64_gen_encode(src, len, out_len, base64_table, 1); +} + + +unsigned char * base64_url_encode(const unsigned char *src, size_t len, + size_t *out_len, int add_pad) +{ + return base64_gen_encode(src, len, out_len, base64_url_table, add_pad); +} + + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. + */ +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len) +{ + return base64_gen_decode(src, len, out_len, base64_table); +} + + +unsigned char * base64_url_decode(const unsigned char *src, size_t len, + size_t *out_len) +{ + return base64_gen_decode(src, len, out_len, base64_url_table); +} diff --git a/contrib/wpa/src/utils/base64.h b/contrib/wpa/src/utils/base64.h index aa21fd0..5a72c3e 100644 --- a/contrib/wpa/src/utils/base64.h +++ b/contrib/wpa/src/utils/base64.h @@ -13,5 +13,9 @@ unsigned char * base64_encode(const unsigned char *src, size_t len, size_t *out_len); unsigned char * base64_decode(const unsigned char *src, size_t len, size_t *out_len); +unsigned char * base64_url_encode(const unsigned char *src, size_t len, + size_t *out_len, int add_pad); +unsigned char * base64_url_decode(const unsigned char *src, size_t len, + size_t *out_len); #endif /* BASE64_H */ diff --git a/contrib/wpa/src/utils/browser-android.c b/contrib/wpa/src/utils/browser-android.c index 9ce1a5c..71a1652 100644 --- a/contrib/wpa/src/utils/browser-android.c +++ b/contrib/wpa/src/utils/browser-android.c @@ -95,7 +95,7 @@ int hs20_web_browser(const char *url) if (pid == 0) { /* run the external command in the child process */ - char *argv[9]; + char *argv[7]; argv[0] = "browser-android"; argv[1] = "start"; @@ -103,9 +103,7 @@ int hs20_web_browser(const char *url) argv[3] = "android.intent.action.VIEW"; argv[4] = "-d"; argv[5] = (void *) url; - argv[6] = "-n"; - argv[7] = "com.android.browser/.BrowserActivity"; - argv[8] = NULL; + argv[6] = NULL; execv("/system/bin/am", argv); wpa_printf(MSG_ERROR, "execv: %s", strerror(errno)); diff --git a/contrib/wpa/src/utils/browser-wpadebug.c b/contrib/wpa/src/utils/browser-wpadebug.c index 59ba4d1..dfb4b67 100644 --- a/contrib/wpa/src/utils/browser-wpadebug.c +++ b/contrib/wpa/src/utils/browser-wpadebug.c @@ -52,7 +52,7 @@ static void http_req(void *ctx, struct http_request *req) eloop_terminate(); return; } - wpabuf_put_str(resp, "User input completed"); + wpabuf_put_str(resp, "HTTP/1.1\r\n\r\nUser input completed"); if (done) { eloop_cancel_timeout(browser_timeout, NULL, NULL); @@ -97,6 +97,7 @@ int hs20_web_browser(const char *url) if (pid == 0) { /* run the external command in the child process */ char *argv[14]; + char *envp[] = { "PATH=/system/bin:/vendor/bin", NULL }; argv[0] = "browser-wpadebug"; argv[1] = "start"; @@ -113,8 +114,8 @@ int hs20_web_browser(const char *url) argv[12] = "-3"; /* USER_CURRENT_OR_SELF */ argv[13] = NULL; - execv("/system/bin/am", argv); - wpa_printf(MSG_ERROR, "execv: %s", strerror(errno)); + execve("/system/bin/am", argv, envp); + wpa_printf(MSG_ERROR, "execve: %s", strerror(errno)); exit(0); return -1; } diff --git a/contrib/wpa/src/utils/browser.c b/contrib/wpa/src/utils/browser.c index 9cf6152..ad0b382 100644 --- a/contrib/wpa/src/utils/browser.c +++ b/contrib/wpa/src/utils/browser.c @@ -166,8 +166,7 @@ int hs20_web_browser(const char *url) g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL); ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_wmclass(GTK_WINDOW(ctx.win), "Hotspot 2.0 client", - "Hotspot 2.0 client"); + gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client"); gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600); scroll = gtk_scrolled_window_new(NULL, NULL); diff --git a/contrib/wpa/src/utils/common.c b/contrib/wpa/src/utils/common.c index 660e9fc..b9c8bfd 100644 --- a/contrib/wpa/src/utils/common.c +++ b/contrib/wpa/src/utils/common.c @@ -1,6 +1,6 @@ /* * wpa_supplicant/hostapd / common helper functions, etc. - * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -86,7 +86,7 @@ int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable) return -1; /* check for optional mask */ - if (*r == '\0' || isspace(*r)) { + if (*r == '\0' || isspace((unsigned char) *r)) { /* no mask specified, assume default */ os_memset(mask, 0xff, ETH_ALEN); } else if (maskable && *r == '/') { @@ -498,7 +498,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) *txt++ = 't'; break; default: - if (data[i] >= 32 && data[i] <= 127) { + if (data[i] >= 32 && data[i] <= 126) { *txt++ = data[i]; } else { txt += os_snprintf(txt, end - txt, "\\x%02x", @@ -697,6 +697,29 @@ int is_hex(const u8 *data, size_t len) } +int has_ctrl_char(const u8 *data, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (data[i] < 32 || data[i] == 127) + return 1; + } + return 0; +} + + +int has_newline(const char *str) +{ + while (*str) { + if (*str == '\n' || *str == '\r') + return 1; + str++; + } + return 0; +} + + size_t merge_byte_arrays(u8 *res, size_t res_len, const u8 *src1, size_t src1_len, const u8 *src2, size_t src2_len) @@ -978,7 +1001,7 @@ int random_mac_addr_keep_oui(u8 *addr) * @delim: a string of delimiters * @last: a pointer to a character following the returned token * It has to be set to NULL for the first call and passed for any - * futher call. + * further call. * Returns: a pointer to token position in str or NULL * * This function is similar to str_token, but it can be used with both @@ -1050,7 +1073,8 @@ size_t utf8_unescape(const char *inp, size_t in_size, in_size--; } - while (in_size--) { + while (in_size) { + in_size--; if (res_size >= out_size) return 0; @@ -1061,8 +1085,9 @@ size_t utf8_unescape(const char *inp, size_t in_size, return res_size; case '\\': - if (!in_size--) + if (!in_size) return 0; + in_size--; inp++; /* fall through */ @@ -1093,7 +1118,8 @@ size_t utf8_escape(const char *inp, size_t in_size, if (!in_size) in_size = os_strlen(inp); - while (in_size--) { + while (in_size) { + in_size--; if (res_size++ >= out_size) return 0; @@ -1123,3 +1149,103 @@ int is_ctrl_char(char c) { return c > 0 && c < 32; } + + +/** + * ssid_parse - Parse a string that contains SSID in hex or text format + * @buf: Input NULL terminated string that contains the SSID + * @ssid: Output SSID + * Returns: 0 on success, -1 otherwise + * + * The SSID has to be enclosed in double quotes for the text format or space + * or NULL terminated string of hex digits for the hex format. buf can include + * additional arguments after the SSID. + */ +int ssid_parse(const char *buf, struct wpa_ssid_value *ssid) +{ + char *tmp, *res, *end; + size_t len; + + ssid->ssid_len = 0; + + tmp = os_strdup(buf); + if (!tmp) + return -1; + + if (*tmp != '"') { + end = os_strchr(tmp, ' '); + if (end) + *end = '\0'; + } else { + end = os_strchr(tmp + 1, '"'); + if (!end) { + os_free(tmp); + return -1; + } + + end[1] = '\0'; + } + + res = wpa_config_parse_string(tmp, &len); + if (res && len <= SSID_MAX_LEN) { + ssid->ssid_len = len; + os_memcpy(ssid->ssid, res, len); + } + + os_free(tmp); + os_free(res); + + return ssid->ssid_len ? 0 : -1; +} + + +int str_starts(const char *str, const char *start) +{ + return os_strncmp(str, start, os_strlen(start)) == 0; +} + + +/** + * rssi_to_rcpi - Convert RSSI to RCPI + * @rssi: RSSI to convert + * Returns: RCPI corresponding to the given RSSI value, or 255 if not available. + * + * It's possible to estimate RCPI based on RSSI in dBm. This calculation will + * not reflect the correct value for high rates, but it's good enough for Action + * frames which are transmitted with up to 24 Mbps rates. + */ +u8 rssi_to_rcpi(int rssi) +{ + if (!rssi) + return 255; /* not available */ + if (rssi < -110) + return 0; + if (rssi > 0) + return 220; + return (rssi + 110) * 2; +} + + +char * get_param(const char *cmd, const char *param) +{ + const char *pos, *end; + char *val; + size_t len; + + pos = os_strstr(cmd, param); + if (!pos) + return NULL; + + pos += os_strlen(param); + end = os_strchr(pos, ' '); + if (end) + len = end - pos; + else + len = os_strlen(pos); + val = os_malloc(len + 1); + if (!val) + return NULL; + os_memcpy(val, pos, len); + val[len] = '\0'; + return val; +} diff --git a/contrib/wpa/src/utils/common.h b/contrib/wpa/src/utils/common.h index 0b9cc3d..792a30a 100644 --- a/contrib/wpa/src/utils/common.h +++ b/contrib/wpa/src/utils/common.h @@ -53,6 +53,15 @@ static inline unsigned int bswap_32(unsigned int v) } #endif /* __APPLE__ */ +#ifdef __rtems__ +#include <rtems/endian.h> +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#define bswap_16 CPU_swap_u16 +#define bswap_32 CPU_swap_u32 +#endif /* __rtems__ */ + #ifdef CONFIG_NATIVE_WINDOWS #include <winsock.h> @@ -141,6 +150,7 @@ static inline unsigned int wpa_swap_32(unsigned int v) #define host_to_le32(n) (n) #define be_to_host32(n) wpa_swap_32(n) #define host_to_be32(n) wpa_swap_32(n) +#define host_to_le64(n) (n) #define WPA_BYTE_SWAP_DEFINED @@ -313,6 +323,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val) #ifndef ETH_P_ALL #define ETH_P_ALL 0x0003 #endif +#ifndef ETH_P_IP +#define ETH_P_IP 0x0800 +#endif #ifndef ETH_P_80211_ENCAP #define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ #endif @@ -328,6 +341,9 @@ static inline void WPA_PUT_LE64(u8 *a, u64 val) #ifndef ETH_P_RRB #define ETH_P_RRB 0x890D #endif /* ETH_P_RRB */ +#ifndef ETH_P_OUI +#define ETH_P_OUI 0x88B7 +#endif /* ETH_P_OUI */ #ifdef __GNUC__ @@ -416,9 +432,11 @@ void perror(const char *s); */ #ifdef __CHECKER__ #define __force __attribute__((force)) +#undef __bitwise #define __bitwise __attribute__((bitwise)) #else #define __force +#undef __bitwise #define __bitwise #endif @@ -445,6 +463,13 @@ typedef u64 __bitwise le64; #endif /* __GNUC__ */ #endif /* __must_check */ +#define SSID_MAX_LEN 32 + +struct wpa_ssid_value { + u8 ssid[SSID_MAX_LEN]; + size_t ssid_len; +}; + int hwaddr_aton(const char *txt, u8 *addr); int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); int hwaddr_compact_aton(const char *txt, u8 *addr); @@ -461,6 +486,7 @@ int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, size_t len); int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask); +int ssid_parse(const char *buf, struct wpa_ssid_value *ssid); #ifdef CONFIG_NATIVE_WINDOWS void wpa_unicode2ascii_inplace(TCHAR *str); @@ -477,6 +503,8 @@ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); char * wpa_config_parse_string(const char *value, size_t *len); int is_hex(const u8 *data, size_t len); +int has_ctrl_char(const u8 *data, size_t len); +int has_newline(const char *str); size_t merge_byte_arrays(u8 *res, size_t res_len, const u8 *src1, size_t src1_len, const u8 *src2, size_t src2_len); @@ -536,6 +564,10 @@ size_t utf8_unescape(const char *inp, size_t in_size, char *outp, size_t out_size); int is_ctrl_char(char c); +int str_starts(const char *str, const char *start); + +u8 rssi_to_rcpi(int rssi); +char * get_param(const char *cmd, const char *param); /* * gcc 4.4 ends up generating strict-aliasing warnings about some very common diff --git a/contrib/wpa/src/utils/const_time.h b/contrib/wpa/src/utils/const_time.h new file mode 100644 index 0000000..ab8f611 --- /dev/null +++ b/contrib/wpa/src/utils/const_time.h @@ -0,0 +1,191 @@ +/* + * Helper functions for constant time operations + * Copyright (c) 2019, The Linux Foundation + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + * + * These helper functions can be used to implement logic that needs to minimize + * externally visible differences in execution path by avoiding use of branches, + * avoiding early termination or other time differences, and forcing same memory + * access pattern regardless of values. + */ + +#ifndef CONST_TIME_H +#define CONST_TIME_H + + +#if defined(__clang__) +#define NO_UBSAN_UINT_OVERFLOW \ + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#else +#define NO_UBSAN_UINT_OVERFLOW +#endif + + +/** + * const_time_fill_msb - Fill all bits with MSB value + * @val: Input value + * Returns: Value with all the bits set to the MSB of the input val + */ +static inline unsigned int const_time_fill_msb(unsigned int val) +{ + /* Move the MSB to LSB and multiple by -1 to fill in all bits. */ + return (val >> (sizeof(val) * 8 - 1)) * ~0U; +} + + +/* Returns: -1 if val is zero; 0 if val is not zero */ +static inline unsigned int const_time_is_zero(unsigned int val) + NO_UBSAN_UINT_OVERFLOW +{ + /* Set MSB to 1 for 0 and fill rest of bits with the MSB value */ + return const_time_fill_msb(~val & (val - 1)); +} + + +/* Returns: -1 if a == b; 0 if a != b */ +static inline unsigned int const_time_eq(unsigned int a, unsigned int b) +{ + return const_time_is_zero(a ^ b); +} + + +/* Returns: -1 if a == b; 0 if a != b */ +static inline u8 const_time_eq_u8(unsigned int a, unsigned int b) +{ + return (u8) const_time_eq(a, b); +} + + +/** + * const_time_eq_bin - Constant time memory comparison + * @a: First buffer to compare + * @b: Second buffer to compare + * @len: Number of octets to compare + * Returns: -1 if buffers are equal, 0 if not + * + * This function is meant for comparing passwords or hash values where + * difference in execution time or memory access pattern could provide external + * observer information about the location of the difference in the memory + * buffers. The return value does not behave like memcmp(), i.e., + * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike + * memcmp(), the execution time of const_time_eq_bin() does not depend on the + * contents of the compared memory buffers, but only on the total compared + * length. + */ +static inline unsigned int const_time_eq_bin(const void *a, const void *b, + size_t len) +{ + const u8 *aa = a; + const u8 *bb = b; + size_t i; + u8 res = 0; + + for (i = 0; i < len; i++) + res |= aa[i] ^ bb[i]; + + return const_time_is_zero(res); +} + + +/** + * const_time_select - Constant time unsigned int selection + * @mask: 0 (false) or -1 (true) to identify which value to select + * @true_val: Value to select for the true case + * @false_val: Value to select for the false case + * Returns: true_val if mask == -1, false_val if mask == 0 + */ +static inline unsigned int const_time_select(unsigned int mask, + unsigned int true_val, + unsigned int false_val) +{ + return (mask & true_val) | (~mask & false_val); +} + + +/** + * const_time_select_int - Constant time int selection + * @mask: 0 (false) or -1 (true) to identify which value to select + * @true_val: Value to select for the true case + * @false_val: Value to select for the false case + * Returns: true_val if mask == -1, false_val if mask == 0 + */ +static inline int const_time_select_int(unsigned int mask, int true_val, + int false_val) +{ + return (int) const_time_select(mask, (unsigned int) true_val, + (unsigned int) false_val); +} + + +/** + * const_time_select_u8 - Constant time u8 selection + * @mask: 0 (false) or -1 (true) to identify which value to select + * @true_val: Value to select for the true case + * @false_val: Value to select for the false case + * Returns: true_val if mask == -1, false_val if mask == 0 + */ +static inline u8 const_time_select_u8(u8 mask, u8 true_val, u8 false_val) +{ + return (u8) const_time_select(mask, true_val, false_val); +} + + +/** + * const_time_select_s8 - Constant time s8 selection + * @mask: 0 (false) or -1 (true) to identify which value to select + * @true_val: Value to select for the true case + * @false_val: Value to select for the false case + * Returns: true_val if mask == -1, false_val if mask == 0 + */ +static inline s8 const_time_select_s8(u8 mask, s8 true_val, s8 false_val) +{ + return (s8) const_time_select(mask, (unsigned int) true_val, + (unsigned int) false_val); +} + + +/** + * const_time_select_bin - Constant time binary buffer selection copy + * @mask: 0 (false) or -1 (true) to identify which value to copy + * @true_val: Buffer to copy for the true case + * @false_val: Buffer to copy for the false case + * @len: Number of octets to copy + * @dst: Destination buffer for the copy + * + * This function copies the specified buffer into the destination buffer using + * operations with identical memory access pattern regardless of which buffer + * is being copied. + */ +static inline void const_time_select_bin(u8 mask, const u8 *true_val, + const u8 *false_val, size_t len, + u8 *dst) +{ + size_t i; + + for (i = 0; i < len; i++) + dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]); +} + + +static inline int const_time_memcmp(const void *a, const void *b, size_t len) +{ + const u8 *aa = a; + const u8 *bb = b; + int diff, res = 0; + unsigned int mask; + + if (len == 0) + return 0; + do { + len--; + diff = (int) aa[len] - (int) bb[len]; + mask = const_time_is_zero((unsigned int) diff); + res = const_time_select_int(mask, res, diff); + } while (len); + + return res; +} + +#endif /* CONST_TIME_H */ diff --git a/contrib/wpa/src/utils/crc32.c b/contrib/wpa/src/utils/crc32.c new file mode 100644 index 0000000..12d9e2a --- /dev/null +++ b/contrib/wpa/src/utils/crc32.c @@ -0,0 +1,85 @@ +/* + * 32-bit CRC for FCS calculation + * Copyright (c) 2010, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/crc32.h" + +/* + * IEEE 802.11 FCS CRC32 + * G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + + * x^5 + x^4 + x^2 + x + 1 + */ +static const u32 crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; + + +u32 crc32(const u8 *frame, size_t frame_len) +{ + size_t i; + u32 crc; + + crc = 0xFFFFFFFF; + for (i = 0; i < frame_len; i++) + crc = crc32_table[(crc ^ frame[i]) & 0xff] ^ (crc >> 8); + + return ~crc; +} diff --git a/contrib/wpa/src/utils/crc32.h b/contrib/wpa/src/utils/crc32.h new file mode 100644 index 0000000..dc31399 --- /dev/null +++ b/contrib/wpa/src/utils/crc32.h @@ -0,0 +1,14 @@ +/* + * 32-bit CRC for FCS calculation + * Copyright (c) 2010, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef CRC32_H +#define CRC32_H + +u32 crc32(const u8 *frame, size_t frame_len); + +#endif /* CRC32_H */ diff --git a/contrib/wpa/src/utils/edit_simple.c b/contrib/wpa/src/utils/edit_simple.c index 13173cb..2ffd1a2 100644 --- a/contrib/wpa/src/utils/edit_simple.c +++ b/contrib/wpa/src/utils/edit_simple.c @@ -47,6 +47,12 @@ static void edit_read_char(int sock, void *eloop_ctx, void *sock_ctx) return; } + if (c == '\b') { + if (cmdbuf_pos > 0) + cmdbuf_pos--; + return; + } + if (c >= 32 && c <= 255) { if (cmdbuf_pos < (int) sizeof(cmdbuf) - 1) { cmdbuf[cmdbuf_pos++] = c; diff --git a/contrib/wpa/src/utils/eloop.c b/contrib/wpa/src/utils/eloop.c index 8647229..bb375be 100644 --- a/contrib/wpa/src/utils/eloop.c +++ b/contrib/wpa/src/utils/eloop.c @@ -18,7 +18,12 @@ #error Do not define both of poll and epoll #endif -#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) +#if defined(CONFIG_ELOOP_POLL) && defined(CONFIG_ELOOP_KQUEUE) +#error Do not define both of poll and kqueue +#endif + +#if !defined(CONFIG_ELOOP_POLL) && !defined(CONFIG_ELOOP_EPOLL) && \ + !defined(CONFIG_ELOOP_KQUEUE) #define CONFIG_ELOOP_SELECT #endif @@ -30,6 +35,10 @@ #include <sys/epoll.h> #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE +#include <sys/event.h> +#endif /* CONFIG_ELOOP_KQUEUE */ + struct eloop_sock { int sock; void *eloop_data; @@ -75,13 +84,20 @@ struct eloop_data { struct pollfd *pollfds; struct pollfd **pollfds_map; #endif /* CONFIG_ELOOP_POLL */ +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) + int max_fd; + struct eloop_sock *fd_table; +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ #ifdef CONFIG_ELOOP_EPOLL int epollfd; int epoll_max_event_num; - int epoll_max_fd; - struct eloop_sock *epoll_table; struct epoll_event *epoll_events; #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + int kqueuefd; + int kqueue_nevents; + struct kevent *kqueue_events; +#endif /* CONFIG_ELOOP_KQUEUE */ struct eloop_sock_table readers; struct eloop_sock_table writers; struct eloop_sock_table exceptions; @@ -149,14 +165,24 @@ int eloop_init(void) #ifdef CONFIG_ELOOP_EPOLL eloop.epollfd = epoll_create1(0); if (eloop.epollfd < 0) { - wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s\n", + wpa_printf(MSG_ERROR, "%s: epoll_create1 failed. %s", __func__, strerror(errno)); return -1; } +#endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + eloop.kqueuefd = kqueue(); + if (eloop.kqueuefd < 0) { + wpa_printf(MSG_ERROR, "%s: kqueue failed: %s", + __func__, strerror(errno)); + return -1; + } +#endif /* CONFIG_ELOOP_KQUEUE */ +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) eloop.readers.type = EVENT_TYPE_READ; eloop.writers.type = EVENT_TYPE_WRITE; eloop.exceptions.type = EVENT_TYPE_EXCEPTION; -#endif /* CONFIG_ELOOP_EPOLL */ +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ #ifdef WPA_TRACE signal(SIGSEGV, eloop_sigsegv_handler); #endif /* WPA_TRACE */ @@ -164,15 +190,84 @@ int eloop_init(void) } +#ifdef CONFIG_ELOOP_EPOLL +static int eloop_sock_queue(int sock, eloop_event_type type) +{ + struct epoll_event ev; + + os_memset(&ev, 0, sizeof(ev)); + switch (type) { + case EVENT_TYPE_READ: + ev.events = EPOLLIN; + break; + case EVENT_TYPE_WRITE: + ev.events = EPOLLOUT; + break; + /* + * Exceptions are always checked when using epoll, but I suppose it's + * possible that someone registered a socket *only* for exception + * handling. + */ + case EVENT_TYPE_EXCEPTION: + ev.events = EPOLLERR | EPOLLHUP; + break; + } + ev.data.fd = sock; + if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) { + wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d failed: %s", + __func__, sock, strerror(errno)); + return -1; + } + return 0; +} +#endif /* CONFIG_ELOOP_EPOLL */ + + +#ifdef CONFIG_ELOOP_KQUEUE + +static short event_type_kevent_filter(eloop_event_type type) +{ + switch (type) { + case EVENT_TYPE_READ: + return EVFILT_READ; + case EVENT_TYPE_WRITE: + return EVFILT_WRITE; + default: + return 0; + } +} + + +static int eloop_sock_queue(int sock, eloop_event_type type) +{ + struct kevent ke; + + EV_SET(&ke, sock, event_type_kevent_filter(type), EV_ADD, 0, 0, 0); + if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) == -1) { + wpa_printf(MSG_ERROR, "%s: kevent(ADD) for fd=%d failed: %s", + __func__, sock, strerror(errno)); + return -1; + } + return 0; +} + +#endif /* CONFIG_ELOOP_KQUEUE */ + + static int eloop_sock_table_add_sock(struct eloop_sock_table *table, int sock, eloop_sock_handler handler, void *eloop_data, void *user_data) { #ifdef CONFIG_ELOOP_EPOLL + struct epoll_event *temp_events; +#endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + struct kevent *temp_events; +#endif /* CONFIG_ELOOP_EPOLL */ +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) struct eloop_sock *temp_table; - struct epoll_event ev, *temp_events; int next; -#endif /* CONFIG_ELOOP_EPOLL */ +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ struct eloop_sock *tmp; int new_max_sock; @@ -208,26 +303,28 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, eloop.pollfds = n; } #endif /* CONFIG_ELOOP_POLL */ -#ifdef CONFIG_ELOOP_EPOLL - if (new_max_sock >= eloop.epoll_max_fd) { - next = eloop.epoll_max_fd == 0 ? 16 : eloop.epoll_max_fd * 2; - temp_table = os_realloc_array(eloop.epoll_table, next, +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) + if (new_max_sock >= eloop.max_fd) { + next = new_max_sock + 16; + temp_table = os_realloc_array(eloop.fd_table, next, sizeof(struct eloop_sock)); if (temp_table == NULL) return -1; - eloop.epoll_max_fd = next; - eloop.epoll_table = temp_table; + eloop.max_fd = next; + eloop.fd_table = temp_table; } +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ +#ifdef CONFIG_ELOOP_EPOLL if (eloop.count + 1 > eloop.epoll_max_event_num) { next = eloop.epoll_max_event_num == 0 ? 8 : eloop.epoll_max_event_num * 2; temp_events = os_realloc_array(eloop.epoll_events, next, sizeof(struct epoll_event)); if (temp_events == NULL) { - wpa_printf(MSG_ERROR, "%s: malloc for epoll failed. " - "%s\n", __func__, strerror(errno)); + wpa_printf(MSG_ERROR, "%s: malloc for epoll failed: %s", + __func__, strerror(errno)); return -1; } @@ -235,6 +332,22 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, eloop.epoll_events = temp_events; } #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + if (eloop.count + 1 > eloop.kqueue_nevents) { + next = eloop.kqueue_nevents == 0 ? 8 : eloop.kqueue_nevents * 2; + temp_events = os_malloc(next * sizeof(*temp_events)); + if (!temp_events) { + wpa_printf(MSG_ERROR, + "%s: malloc for kqueue failed: %s", + __func__, strerror(errno)); + return -1; + } + + os_free(eloop.kqueue_events); + eloop.kqueue_events = temp_events; + eloop.kqueue_nevents = next; + } +#endif /* CONFIG_ELOOP_KQUEUE */ eloop_trace_sock_remove_ref(table); tmp = os_realloc_array(table->table, table->count + 1, @@ -256,33 +369,12 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, table->changed = 1; eloop_trace_sock_add_ref(table); -#ifdef CONFIG_ELOOP_EPOLL - os_memset(&ev, 0, sizeof(ev)); - switch (table->type) { - case EVENT_TYPE_READ: - ev.events = EPOLLIN; - break; - case EVENT_TYPE_WRITE: - ev.events = EPOLLOUT; - break; - /* - * Exceptions are always checked when using epoll, but I suppose it's - * possible that someone registered a socket *only* for exception - * handling. - */ - case EVENT_TYPE_EXCEPTION: - ev.events = EPOLLERR | EPOLLHUP; - break; - } - ev.data.fd = sock; - if (epoll_ctl(eloop.epollfd, EPOLL_CTL_ADD, sock, &ev) < 0) { - wpa_printf(MSG_ERROR, "%s: epoll_ctl(ADD) for fd=%d " - "failed. %s\n", __func__, sock, strerror(errno)); +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) + if (eloop_sock_queue(sock, table->type) < 0) return -1; - } - os_memcpy(&eloop.epoll_table[sock], &table->table[table->count - 1], + os_memcpy(&eloop.fd_table[sock], &table->table[table->count - 1], sizeof(struct eloop_sock)); -#endif /* CONFIG_ELOOP_EPOLL */ +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ return 0; } @@ -290,6 +382,9 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, int sock) { +#ifdef CONFIG_ELOOP_KQUEUE + struct kevent ke; +#endif /* CONFIG_ELOOP_KQUEUE */ int i; if (table == NULL || table->table == NULL || table->count == 0) @@ -313,12 +408,22 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, eloop_trace_sock_add_ref(table); #ifdef CONFIG_ELOOP_EPOLL if (epoll_ctl(eloop.epollfd, EPOLL_CTL_DEL, sock, NULL) < 0) { - wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d " - "failed. %s\n", __func__, sock, strerror(errno)); + wpa_printf(MSG_ERROR, "%s: epoll_ctl(DEL) for fd=%d failed: %s", + __func__, sock, strerror(errno)); return; } - os_memset(&eloop.epoll_table[sock], 0, sizeof(struct eloop_sock)); + os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock)); #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + EV_SET(&ke, sock, event_type_kevent_filter(table->type), EV_DELETE, 0, + 0, 0); + if (kevent(eloop.kqueuefd, &ke, 1, NULL, 0, NULL) < 0) { + wpa_printf(MSG_ERROR, "%s: kevent(DEL) for fd=%d failed: %s", + __func__, sock, strerror(errno)); + return; + } + os_memset(&eloop.fd_table[sock], 0, sizeof(struct eloop_sock)); +#endif /* CONFIG_ELOOP_KQUEUE */ } @@ -511,7 +616,7 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds) int i; for (i = 0; i < nfds; i++) { - table = &eloop.epoll_table[events[i].data.fd]; + table = &eloop.fd_table[events[i].data.fd]; if (table->handler == NULL) continue; table->handler(table->sock, table->eloop_data, @@ -525,6 +630,67 @@ static void eloop_sock_table_dispatch(struct epoll_event *events, int nfds) #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + +static void eloop_sock_table_dispatch(struct kevent *events, int nfds) +{ + struct eloop_sock *table; + int i; + + for (i = 0; i < nfds; i++) { + table = &eloop.fd_table[events[i].ident]; + if (table->handler == NULL) + continue; + table->handler(table->sock, table->eloop_data, + table->user_data); + if (eloop.readers.changed || + eloop.writers.changed || + eloop.exceptions.changed) + break; + } +} + + +static int eloop_sock_table_requeue(struct eloop_sock_table *table) +{ + int i, r; + + r = 0; + for (i = 0; i < table->count && table->table; i++) { + if (eloop_sock_queue(table->table[i].sock, table->type) == -1) + r = -1; + } + return r; +} + +#endif /* CONFIG_ELOOP_KQUEUE */ + + +int eloop_sock_requeue(void) +{ + int r = 0; + +#ifdef CONFIG_ELOOP_KQUEUE + close(eloop.kqueuefd); + eloop.kqueuefd = kqueue(); + if (eloop.kqueuefd < 0) { + wpa_printf(MSG_ERROR, "%s: kqueue failed: %s", + __func__, strerror(errno)); + return -1; + } + + if (eloop_sock_table_requeue(&eloop.readers) < 0) + r = -1; + if (eloop_sock_table_requeue(&eloop.writers) < 0) + r = -1; + if (eloop_sock_table_requeue(&eloop.exceptions) < 0) + r = -1; +#endif /* CONFIG_ELOOP_KQUEUE */ + + return r; +} + + static void eloop_sock_table_destroy(struct eloop_sock_table *table) { if (table) { @@ -905,6 +1071,9 @@ void eloop_run(void) #ifdef CONFIG_ELOOP_EPOLL int timeout_ms = -1; #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + struct timespec ts; +#endif /* CONFIG_ELOOP_KQUEUE */ int res; struct os_reltime tv, now; @@ -949,6 +1118,10 @@ void eloop_run(void) _tv.tv_sec = tv.sec; _tv.tv_usec = tv.usec; #endif /* CONFIG_ELOOP_SELECT */ +#ifdef CONFIG_ELOOP_KQUEUE + ts.tv_sec = tv.sec; + ts.tv_nsec = tv.usec * 1000L; +#endif /* CONFIG_ELOOP_KQUEUE */ } #ifdef CONFIG_ELOOP_POLL @@ -974,6 +1147,15 @@ void eloop_run(void) eloop.count, timeout_ms); } #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + if (eloop.count == 0) { + res = 0; + } else { + res = kevent(eloop.kqueuefd, NULL, 0, + eloop.kqueue_events, eloop.kqueue_nevents, + timeout ? &ts : NULL); + } +#endif /* CONFIG_ELOOP_KQUEUE */ if (res < 0 && errno != EINTR && errno != 0) { wpa_printf(MSG_ERROR, "eloop: %s: %s", #ifdef CONFIG_ELOOP_POLL @@ -985,6 +1167,10 @@ void eloop_run(void) #ifdef CONFIG_ELOOP_EPOLL "epoll" #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + "kqueue" +#endif /* CONFIG_ELOOP_EKQUEUE */ + , strerror(errno)); goto out; } @@ -995,6 +1181,7 @@ void eloop_run(void) eloop_process_pending_signals(); + /* check if some registered timeouts have occurred */ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list); @@ -1040,6 +1227,9 @@ void eloop_run(void) #ifdef CONFIG_ELOOP_EPOLL eloop_sock_table_dispatch(eloop.epoll_events, res); #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + eloop_sock_table_dispatch(eloop.kqueue_events, res); +#endif /* CONFIG_ELOOP_KQUEUE */ } eloop.terminate = 0; @@ -1092,11 +1282,17 @@ void eloop_destroy(void) os_free(eloop.pollfds); os_free(eloop.pollfds_map); #endif /* CONFIG_ELOOP_POLL */ +#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) + os_free(eloop.fd_table); +#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ #ifdef CONFIG_ELOOP_EPOLL - os_free(eloop.epoll_table); os_free(eloop.epoll_events); close(eloop.epollfd); #endif /* CONFIG_ELOOP_EPOLL */ +#ifdef CONFIG_ELOOP_KQUEUE + os_free(eloop.kqueue_events); + close(eloop.kqueuefd); +#endif /* CONFIG_ELOOP_KQUEUE */ } @@ -1135,6 +1331,17 @@ void eloop_wait_for_read_sock(int sock) FD_SET(sock, &rfds); select(sock + 1, &rfds, NULL, NULL, NULL); #endif /* defined(CONFIG_ELOOP_SELECT) || defined(CONFIG_ELOOP_EPOLL) */ +#ifdef CONFIG_ELOOP_KQUEUE + int kfd; + struct kevent ke1, ke2; + + kfd = kqueue(); + if (kfd == -1) + return; + EV_SET(&ke1, sock, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0); + kevent(kfd, &ke1, 1, &ke2, 1, NULL); + close(kfd); +#endif /* CONFIG_ELOOP_KQUEUE */ } #ifdef CONFIG_ELOOP_SELECT diff --git a/contrib/wpa/src/utils/eloop.h b/contrib/wpa/src/utils/eloop.h index 07b8c0d..04ee6d1 100644 --- a/contrib/wpa/src/utils/eloop.h +++ b/contrib/wpa/src/utils/eloop.h @@ -45,16 +45,16 @@ typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx); /** * eloop_event_handler - eloop generic event callback type * @eloop_ctx: Registered callback context data (eloop_data) - * @sock_ctx: Registered callback context data (user_data) + * @user_ctx: Registered callback context data (user_data) */ -typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx); +typedef void (*eloop_event_handler)(void *eloop_ctx, void *user_ctx); /** * eloop_timeout_handler - eloop timeout event callback type * @eloop_ctx: Registered callback context data (eloop_data) - * @sock_ctx: Registered callback context data (user_data) + * @user_ctx: Registered callback context data (user_data) */ -typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx); +typedef void (*eloop_timeout_handler)(void *eloop_ctx, void *user_ctx); /** * eloop_signal_handler - eloop signal event callback type @@ -313,6 +313,14 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler, void *user_data); /** + * eloop_sock_requeue - Requeue sockets + * + * Requeue sockets after forking because some implementations require this, + * such as epoll and kqueue. + */ +int eloop_sock_requeue(void); + +/** * eloop_run - Start the event loop * * Start the event loop and continue running as long as there are any diff --git a/contrib/wpa/src/utils/eloop_win.c b/contrib/wpa/src/utils/eloop_win.c index de47fb2..9c8b12b 100644 --- a/contrib/wpa/src/utils/eloop_win.c +++ b/contrib/wpa/src/utils/eloop_win.c @@ -692,3 +692,9 @@ void eloop_wait_for_read_sock(int sock) WSAEventSelect(sock, event, 0); WSACloseEvent(event); } + + +int eloop_sock_requeue(void) +{ + return 0; +} diff --git a/contrib/wpa/src/utils/ext_password.c b/contrib/wpa/src/utils/ext_password.c index 0613119..5615bd7 100644 --- a/contrib/wpa/src/utils/ext_password.c +++ b/contrib/wpa/src/utils/ext_password.c @@ -16,10 +16,6 @@ #include "ext_password_i.h" -#ifdef CONFIG_EXT_PASSWORD_TEST -extern struct ext_password_backend ext_password_test; -#endif /* CONFIG_EXT_PASSWORD_TEST */ - static const struct ext_password_backend *backends[] = { #ifdef CONFIG_EXT_PASSWORD_TEST &ext_password_test, diff --git a/contrib/wpa/src/utils/ext_password_i.h b/contrib/wpa/src/utils/ext_password_i.h index 043e731..948eaf5 100644 --- a/contrib/wpa/src/utils/ext_password_i.h +++ b/contrib/wpa/src/utils/ext_password_i.h @@ -20,4 +20,10 @@ struct ext_password_backend { struct wpabuf * ext_password_alloc(size_t len); +/* Available ext_password backends */ + +#ifdef CONFIG_EXT_PASSWORD_TEST +extern const struct ext_password_backend ext_password_test; +#endif /* CONFIG_EXT_PASSWORD_TEST */ + #endif /* EXT_PASSWORD_I_H */ diff --git a/contrib/wpa/src/utils/http_curl.c b/contrib/wpa/src/utils/http_curl.c index 653eb54..e62fbf9 100644 --- a/contrib/wpa/src/utils/http_curl.c +++ b/contrib/wpa/src/utils/http_curl.c @@ -26,6 +26,17 @@ #include "common.h" #include "xml-utils.h" #include "http-utils.h" +#ifdef EAP_TLS_OPENSSL +#include "crypto/tls_openssl.h" +#endif /* EAP_TLS_OPENSSL */ + + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x) +{ + return ASN1_STRING_data((ASN1_STRING *) x); +} +#endif /* OpenSSL < 1.1.0 */ struct http_ctx { @@ -421,6 +432,29 @@ ASN1_SEQUENCE(LogotypeExtn) = { IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn); +#ifdef OPENSSL_IS_BORINGSSL +#define sk_LogotypeInfo_num(st) \ +sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeInfo) *, (st))) +#define sk_LogotypeInfo_value(st, i) (LogotypeInfo *) \ +sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeInfo) *, (st)), (i)) +#define sk_LogotypeImage_num(st) \ +sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeImage) *, (st))) +#define sk_LogotypeImage_value(st, i) (LogotypeImage *) \ +sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeImage) *, (st)), (i)) +#define sk_LogotypeAudio_num(st) \ +sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeAudio) *, (st))) +#define sk_LogotypeAudio_value(st, i) (LogotypeAudio *) \ +sk_value(CHECK_CAST(_STACK *, const STACK_OF(LogotypeAudio) *, (st)), (i)) +#define sk_HashAlgAndValue_num(st) \ +sk_num(CHECKED_CAST(_STACK *, STACK_OF(HashAlgAndValue) *, (st))) +#define sk_HashAlgAndValue_value(st, i) (HashAlgAndValue *) \ +sk_value(CHECKED_CAST(_STACK *, const STACK_OF(HashAlgAndValue) *, (st)), (i)) +#define sk_ASN1_IA5STRING_num(st) \ +sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_IA5STRING) *, (st))) +#define sk_ASN1_IA5STRING_value(st, i) (ASN1_IA5STRING *) \ +sk_value(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_IA5STRING) *, (st)), (i)) +#else /* OPENSSL_IS_BORINGSSL */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L #define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st)) #define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i)) #define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st)) @@ -431,6 +465,14 @@ IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn); #define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i)) #define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st)) #define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i)) +#else +DEFINE_STACK_OF(LogotypeInfo) +DEFINE_STACK_OF(LogotypeImage) +DEFINE_STACK_OF(LogotypeAudio) +DEFINE_STACK_OF(HashAlgAndValue) +DEFINE_STACK_OF(ASN1_IA5STRING) +#endif +#endif /* OPENSSL_IS_BORINGSSL */ static void add_logo(struct http_ctx *ctx, struct http_cert *hcert, @@ -460,12 +502,12 @@ static void add_logo(struct http_ctx *ctx, struct http_cert *hcert, return; n->hash_len = ASN1_STRING_length(hash->hashValue); - n->hash = os_malloc(n->hash_len); + n->hash = os_memdup(ASN1_STRING_get0_data(hash->hashValue), + n->hash_len); if (n->hash == NULL) { os_free(n->alg_oid); return; } - os_memcpy(n->hash, ASN1_STRING_data(hash->hashValue), n->hash_len); len = ASN1_STRING_length(uri); n->uri = os_malloc(len + 1); @@ -474,7 +516,7 @@ static void add_logo(struct http_ctx *ctx, struct http_cert *hcert, os_free(n->hash); return; } - os_memcpy(n->uri, ASN1_STRING_data(uri), len); + os_memcpy(n->uri, ASN1_STRING_get0_data(uri), len); n->uri[len] = '\0'; hcert->num_logo++; @@ -618,13 +660,25 @@ static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent) } else { BIO_printf(out, "%*stype: default (1)\n", indent, ""); } + val = ASN1_INTEGER_get(info->fileSize); + BIO_printf(out, "%*sfileSize: %ld\n", indent, "", val); val = ASN1_INTEGER_get(info->xSize); BIO_printf(out, "%*sxSize: %ld\n", indent, "", val); val = ASN1_INTEGER_get(info->ySize); BIO_printf(out, "%*sySize: %ld\n", indent, "", val); if (info->resolution) { - BIO_printf(out, "%*sresolution\n", indent, ""); - /* TODO */ + BIO_printf(out, "%*sresolution [%d]\n", indent, "", + info->resolution->type); + switch (info->resolution->type) { + case 0: + val = ASN1_INTEGER_get(info->resolution->d.numBits); + BIO_printf(out, "%*snumBits: %ld\n", indent, "", val); + break; + case 1: + val = ASN1_INTEGER_get(info->resolution->d.tableSize); + BIO_printf(out, "%*stableSize: %ld\n", indent, "", val); + break; + } } if (info->language) { BIO_printf(out, "%*slanguage: ", indent, ""); @@ -777,9 +831,9 @@ static void add_logotype_ext(struct http_ctx *ctx, struct http_cert *hcert, } wpa_hexdump(MSG_DEBUG, "logotypeExtn", - ASN1_STRING_data(os), ASN1_STRING_length(os)); + ASN1_STRING_get0_data(os), ASN1_STRING_length(os)); - data = ASN1_STRING_data(os); + data = ASN1_STRING_get0_data(os); logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os)); if (logo == NULL) { wpa_printf(MSG_INFO, "Failed to parse logotypeExtn"); @@ -949,7 +1003,7 @@ static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); - ssl_ctx = ssl->ctx; + ssl_ctx = SSL_get_SSL_CTX(ssl); ctx = SSL_CTX_get_app_data(ssl_ctx); wpa_printf(MSG_DEBUG, "curl_cb_ssl_verify, preverify_ok: %d", @@ -981,6 +1035,26 @@ static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx) if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0) return 0; +#ifdef OPENSSL_IS_BORINGSSL + if (depth == 0 && ctx->ocsp != NO_OCSP && preverify_ok) { + enum ocsp_result res; + + res = check_ocsp_resp(ssl_ctx, ssl, cert, ctx->peer_issuer, + ctx->peer_issuer_issuer); + if (res == OCSP_REVOKED) { + preverify_ok = 0; + wpa_printf(MSG_INFO, "OCSP: certificate revoked"); + if (err == X509_V_OK) + X509_STORE_CTX_set_error( + x509_ctx, X509_V_ERR_CERT_REVOKED); + } else if (res != OCSP_GOOD && (ctx->ocsp == MANDATORY_OCSP)) { + preverify_ok = 0; + wpa_printf(MSG_INFO, + "OCSP: bad certificate status response"); + } + } +#endif /* OPENSSL_IS_BORINGSSL */ + if (!preverify_ok) ctx->last_err = "TLS validation failed"; @@ -1037,7 +1111,7 @@ static int ocsp_resp_cb(SSL *s, void *arg) { struct http_ctx *ctx = arg; const unsigned char *p; - int len, status, reason; + int len, status, reason, res; OCSP_RESPONSE *rsp; OCSP_BASICRESP *basic; OCSP_CERTID *id; @@ -1079,7 +1153,7 @@ static int ocsp_resp_cb(SSL *s, void *arg) return 0; } - store = SSL_CTX_get_cert_store(s->ctx); + store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)); if (ctx->peer_issuer) { wpa_printf(MSG_DEBUG, "OpenSSL: Add issuer"); debug_dump_cert("OpenSSL: Issuer certificate", @@ -1142,20 +1216,40 @@ static int ocsp_resp_cb(SSL *s, void *arg) return 0; } - id = OCSP_cert_to_id(NULL, ctx->peer_cert, ctx->peer_issuer); + id = OCSP_cert_to_id(EVP_sha256(), ctx->peer_cert, ctx->peer_issuer); if (!id) { - wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier"); + wpa_printf(MSG_DEBUG, + "OpenSSL: Could not create OCSP certificate identifier (SHA256)"); OCSP_BASICRESP_free(basic); OCSP_RESPONSE_free(rsp); ctx->last_err = "Could not create OCSP certificate identifier"; return 0; } - if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, - &this_update, &next_update)) { + res = OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, + &this_update, &next_update); + if (!res) { + id = OCSP_cert_to_id(NULL, ctx->peer_cert, ctx->peer_issuer); + if (!id) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Could not create OCSP certificate identifier (SHA1)"); + OCSP_BASICRESP_free(basic); + OCSP_RESPONSE_free(rsp); + ctx->last_err = + "Could not create OCSP certificate identifier"; + return 0; + } + + res = OCSP_resp_find_status(basic, id, &status, &reason, + &produced_at, &this_update, + &next_update); + } + + if (!res) { wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", (ctx->ocsp == MANDATORY_OCSP) ? "" : " (OCSP not required)"); + OCSP_CERTID_free(id); OCSP_BASICRESP_free(basic); OCSP_RESPONSE_free(rsp); if (ctx->ocsp == MANDATORY_OCSP) @@ -1163,6 +1257,7 @@ static int ocsp_resp_cb(SSL *s, void *arg) ctx->last_err = "Could not find current server certificate from OCSP response"; return (ctx->ocsp == MANDATORY_OCSP) ? 0 : 1; } + OCSP_CERTID_free(id); if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { tls_show_errors(__func__, "OpenSSL: OCSP status times invalid"); @@ -1194,12 +1289,13 @@ static int ocsp_resp_cb(SSL *s, void *arg) } +#if OPENSSL_VERSION_NUMBER < 0x10100000L static SSL_METHOD patch_ssl_method; static const SSL_METHOD *real_ssl_method; static int curl_patch_ssl_new(SSL *s) { - SSL_CTX *ssl = s->ctx; + SSL_CTX *ssl = SSL_get_SSL_CTX(s); int ret; ssl->method = real_ssl_method; @@ -1210,6 +1306,7 @@ static int curl_patch_ssl_new(SSL *s) return ret; } +#endif /* OpenSSL < 1.1.0 */ #endif /* HAVE_OCSP */ @@ -1228,6 +1325,7 @@ static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm) SSL_CTX_set_tlsext_status_cb(ssl, ocsp_resp_cb); SSL_CTX_set_tlsext_status_arg(ssl, ctx); +#if OPENSSL_VERSION_NUMBER < 0x10100000L /* * Use a temporary SSL_METHOD to get a callback on SSL_new() * from libcurl since there is no proper callback registration @@ -1237,6 +1335,7 @@ static CURLcode curl_cb_ssl(CURL *curl, void *sslctx, void *parm) patch_ssl_method.ssl_new = curl_patch_ssl_new; real_ssl_method = ssl->method; ssl->method = &patch_ssl_method; +#endif /* OpenSSL < 1.1.0 */ } #endif /* HAVE_OCSP */ @@ -1273,6 +1372,16 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address, #ifdef EAP_TLS_OPENSSL curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_cb_ssl); curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, ctx); +#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER >= 0x10100000L) + /* For now, using the CURLOPT_SSL_VERIFYSTATUS option only + * with BoringSSL since the OpenSSL specific callback hack to + * enable OCSP is not available with BoringSSL. The OCSP + * implementation within libcurl is not sufficient for the + * Hotspot 2.0 OSU needs, so cannot use this with OpenSSL. + */ + if (ctx->ocsp != NO_OCSP) + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); +#endif /* OPENSSL_IS_BORINGSSL */ #endif /* EAP_TLS_OPENSSL */ } else { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); diff --git a/contrib/wpa/src/utils/json.c b/contrib/wpa/src/utils/json.c new file mode 100644 index 0000000..b644339 --- /dev/null +++ b/contrib/wpa/src/utils/json.c @@ -0,0 +1,576 @@ +/* + * JavaScript Object Notation (JSON) parser (RFC7159) + * Copyright (c) 2017, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "base64.h" +#include "json.h" + +#define JSON_MAX_DEPTH 10 +#define JSON_MAX_TOKENS 500 + + +void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len) +{ + char *end = txt + maxlen; + size_t i; + + for (i = 0; i < len; i++) { + if (txt + 4 >= end) + break; + + switch (data[i]) { + case '\"': + *txt++ = '\\'; + *txt++ = '\"'; + break; + case '\\': + *txt++ = '\\'; + *txt++ = '\\'; + break; + case '\n': + *txt++ = '\\'; + *txt++ = 'n'; + break; + case '\r': + *txt++ = '\\'; + *txt++ = 'r'; + break; + case '\t': + *txt++ = '\\'; + *txt++ = 't'; + break; + default: + if (data[i] >= 32 && data[i] <= 126) { + *txt++ = data[i]; + } else { + txt += os_snprintf(txt, end - txt, "\\u%04x", + data[i]); + } + break; + } + } + + *txt = '\0'; +} + + +static char * json_parse_string(const char **json_pos, const char *end) +{ + const char *pos = *json_pos; + char *str, *spos, *s_end; + size_t max_len, buf_len; + u8 bin[2]; + + pos++; /* skip starting quote */ + + max_len = end - pos + 1; + buf_len = max_len > 10 ? 10 : max_len; + str = os_malloc(buf_len); + if (!str) + return NULL; + spos = str; + s_end = str + buf_len; + + for (; pos < end; pos++) { + if (buf_len < max_len && s_end - spos < 3) { + char *tmp; + int idx; + + idx = spos - str; + buf_len *= 2; + if (buf_len > max_len) + buf_len = max_len; + tmp = os_realloc(str, buf_len); + if (!tmp) + goto fail; + str = tmp; + spos = str + idx; + s_end = str + buf_len; + } + + switch (*pos) { + case '\"': /* end string */ + *spos = '\0'; + /* caller will move to the next position */ + *json_pos = pos; + return str; + case '\\': + pos++; + if (pos >= end) { + wpa_printf(MSG_DEBUG, + "JSON: Truncated \\ escape"); + goto fail; + } + switch (*pos) { + case '"': + case '\\': + case '/': + *spos++ = *pos; + break; + case 'n': + *spos++ = '\n'; + break; + case 'r': + *spos++ = '\r'; + break; + case 't': + *spos++ = '\t'; + break; + case 'u': + if (end - pos < 5 || + hexstr2bin(pos + 1, bin, 2) < 0 || + bin[1] == 0x00) { + wpa_printf(MSG_DEBUG, + "JSON: Invalid \\u escape"); + goto fail; + } + if (bin[0] == 0x00) { + *spos++ = bin[1]; + } else { + *spos++ = bin[0]; + *spos++ = bin[1]; + } + pos += 4; + break; + default: + wpa_printf(MSG_DEBUG, + "JSON: Unknown escape '%c'", *pos); + goto fail; + } + break; + default: + *spos++ = *pos; + break; + } + } + +fail: + os_free(str); + return NULL; +} + + +static int json_parse_number(const char **json_pos, const char *end, + int *ret_val) +{ + const char *pos = *json_pos; + size_t len; + char *str; + + for (; pos < end; pos++) { + if (*pos != '-' && (*pos < '0' || *pos > '9')) { + pos--; + break; + } + } + if (pos == end) + pos--; + if (pos < *json_pos) + return -1; + len = pos - *json_pos + 1; + str = os_malloc(len + 1); + if (!str) + return -1; + os_memcpy(str, *json_pos, len); + str[len] = '\0'; + + *ret_val = atoi(str); + os_free(str); + *json_pos = pos; + return 0; +} + + +static int json_check_tree_state(struct json_token *token) +{ + if (!token) + return 0; + if (json_check_tree_state(token->child) < 0 || + json_check_tree_state(token->sibling) < 0) + return -1; + if (token->state != JSON_COMPLETED) { + wpa_printf(MSG_DEBUG, + "JSON: Unexpected token state %d (name=%s type=%d)", + token->state, token->name ? token->name : "N/A", + token->type); + return -1; + } + return 0; +} + + +static struct json_token * json_alloc_token(unsigned int *tokens) +{ + (*tokens)++; + if (*tokens > JSON_MAX_TOKENS) { + wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded"); + return NULL; + } + return os_zalloc(sizeof(struct json_token)); +} + + +struct json_token * json_parse(const char *data, size_t data_len) +{ + struct json_token *root = NULL, *curr_token = NULL, *token = NULL; + const char *pos, *end; + char *str; + int num; + unsigned int depth = 0; + unsigned int tokens = 0; + + pos = data; + end = data + data_len; + + for (; pos < end; pos++) { + switch (*pos) { + case '[': /* start array */ + case '{': /* start object */ + if (!curr_token) { + token = json_alloc_token(&tokens); + if (!token) + goto fail; + if (!root) + root = token; + } else if (curr_token->state == JSON_WAITING_VALUE) { + token = curr_token; + } else if (curr_token->parent && + curr_token->parent->type == JSON_ARRAY && + curr_token->parent->state == JSON_STARTED && + curr_token->state == JSON_EMPTY) { + token = curr_token; + } else { + wpa_printf(MSG_DEBUG, + "JSON: Invalid state for start array/object"); + goto fail; + } + depth++; + if (depth > JSON_MAX_DEPTH) { + wpa_printf(MSG_DEBUG, + "JSON: Max depth exceeded"); + goto fail; + } + token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT; + token->state = JSON_STARTED; + token->child = json_alloc_token(&tokens); + if (!token->child) + goto fail; + curr_token = token->child; + curr_token->parent = token; + curr_token->state = JSON_EMPTY; + break; + case ']': /* end array */ + case '}': /* end object */ + if (!curr_token || !curr_token->parent || + curr_token->parent->state != JSON_STARTED) { + wpa_printf(MSG_DEBUG, + "JSON: Invalid state for end array/object"); + goto fail; + } + depth--; + curr_token = curr_token->parent; + if ((*pos == ']' && + curr_token->type != JSON_ARRAY) || + (*pos == '}' && + curr_token->type != JSON_OBJECT)) { + wpa_printf(MSG_DEBUG, + "JSON: Array/Object mismatch"); + goto fail; + } + if (curr_token->child->state == JSON_EMPTY && + !curr_token->child->child && + !curr_token->child->sibling) { + /* Remove pending child token since the + * array/object was empty. */ + json_free(curr_token->child); + curr_token->child = NULL; + } + curr_token->state = JSON_COMPLETED; + break; + case '\"': /* string */ + str = json_parse_string(&pos, end); + if (!str) + goto fail; + if (!curr_token) { + token = json_alloc_token(&tokens); + if (!token) + goto fail; + token->type = JSON_STRING; + token->string = str; + token->state = JSON_COMPLETED; + } else if (curr_token->parent && + curr_token->parent->type == JSON_ARRAY && + curr_token->parent->state == JSON_STARTED && + curr_token->state == JSON_EMPTY) { + curr_token->string = str; + curr_token->state = JSON_COMPLETED; + curr_token->type = JSON_STRING; + wpa_printf(MSG_MSGDUMP, + "JSON: String value: '%s'", + curr_token->string); + } else if (curr_token->state == JSON_EMPTY) { + curr_token->type = JSON_VALUE; + curr_token->name = str; + curr_token->state = JSON_STARTED; + } else if (curr_token->state == JSON_WAITING_VALUE) { + curr_token->string = str; + curr_token->state = JSON_COMPLETED; + curr_token->type = JSON_STRING; + wpa_printf(MSG_MSGDUMP, + "JSON: String value: '%s' = '%s'", + curr_token->name, + curr_token->string); + } else { + wpa_printf(MSG_DEBUG, + "JSON: Invalid state for a string"); + os_free(str); + goto fail; + } + break; + case ' ': + case '\t': + case '\r': + case '\n': + /* ignore whitespace */ + break; + case ':': /* name/value separator */ + if (!curr_token || curr_token->state != JSON_STARTED) + goto fail; + curr_token->state = JSON_WAITING_VALUE; + break; + case ',': /* member separator */ + if (!curr_token) + goto fail; + curr_token->sibling = json_alloc_token(&tokens); + if (!curr_token->sibling) + goto fail; + curr_token->sibling->parent = curr_token->parent; + curr_token = curr_token->sibling; + curr_token->state = JSON_EMPTY; + break; + case 't': /* true */ + case 'f': /* false */ + case 'n': /* null */ + if (!((end - pos >= 4 && + os_strncmp(pos, "true", 4) == 0) || + (end - pos >= 5 && + os_strncmp(pos, "false", 5) == 0) || + (end - pos >= 4 && + os_strncmp(pos, "null", 4) == 0))) { + wpa_printf(MSG_DEBUG, + "JSON: Invalid literal name"); + goto fail; + } + if (!curr_token) { + token = json_alloc_token(&tokens); + if (!token) + goto fail; + curr_token = token; + } else if (curr_token->state == JSON_WAITING_VALUE) { + wpa_printf(MSG_MSGDUMP, + "JSON: Literal name: '%s' = %c", + curr_token->name, *pos); + } else if (curr_token->parent && + curr_token->parent->type == JSON_ARRAY && + curr_token->parent->state == JSON_STARTED && + curr_token->state == JSON_EMPTY) { + wpa_printf(MSG_MSGDUMP, + "JSON: Literal name: %c", *pos); + } else { + wpa_printf(MSG_DEBUG, + "JSON: Invalid state for a literal name"); + goto fail; + } + switch (*pos) { + case 't': + curr_token->type = JSON_BOOLEAN; + curr_token->number = 1; + pos += 3; + break; + case 'f': + curr_token->type = JSON_BOOLEAN; + curr_token->number = 0; + pos += 4; + break; + case 'n': + curr_token->type = JSON_NULL; + pos += 3; + break; + } + curr_token->state = JSON_COMPLETED; + break; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + /* number */ + if (json_parse_number(&pos, end, &num) < 0) + goto fail; + if (!curr_token) { + token = json_alloc_token(&tokens); + if (!token) + goto fail; + token->type = JSON_NUMBER; + token->number = num; + token->state = JSON_COMPLETED; + } else if (curr_token->state == JSON_WAITING_VALUE) { + curr_token->number = num; + curr_token->state = JSON_COMPLETED; + curr_token->type = JSON_NUMBER; + wpa_printf(MSG_MSGDUMP, + "JSON: Number value: '%s' = '%d'", + curr_token->name, + curr_token->number); + } else if (curr_token->parent && + curr_token->parent->type == JSON_ARRAY && + curr_token->parent->state == JSON_STARTED && + curr_token->state == JSON_EMPTY) { + curr_token->number = num; + curr_token->state = JSON_COMPLETED; + curr_token->type = JSON_NUMBER; + wpa_printf(MSG_MSGDUMP, + "JSON: Number value: %d", + curr_token->number); + } else { + wpa_printf(MSG_DEBUG, + "JSON: Invalid state for a number"); + goto fail; + } + break; + default: + wpa_printf(MSG_DEBUG, + "JSON: Unexpected JSON character: %c", *pos); + goto fail; + } + + if (!root) + root = token; + if (!curr_token) + curr_token = token; + } + + if (json_check_tree_state(root) < 0) { + wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree"); + goto fail; + } + + return root; +fail: + wpa_printf(MSG_DEBUG, "JSON: Parsing failed"); + json_free(root); + return NULL; +} + + +void json_free(struct json_token *json) +{ + if (!json) + return; + json_free(json->child); + json_free(json->sibling); + os_free(json->name); + os_free(json->string); + os_free(json); +} + + +struct json_token * json_get_member(struct json_token *json, const char *name) +{ + struct json_token *token, *ret = NULL; + + if (!json || json->type != JSON_OBJECT) + return NULL; + /* Return last matching entry */ + for (token = json->child; token; token = token->sibling) { + if (token->name && os_strcmp(token->name, name) == 0) + ret = token; + } + return ret; +} + + +struct wpabuf * json_get_member_base64url(struct json_token *json, + const char *name) +{ + struct json_token *token; + unsigned char *buf; + size_t buflen; + struct wpabuf *ret; + + token = json_get_member(json, name); + if (!token || token->type != JSON_STRING) + return NULL; + buf = base64_url_decode((const unsigned char *) token->string, + os_strlen(token->string), &buflen); + if (!buf) + return NULL; + ret = wpabuf_alloc_ext_data(buf, buflen); + if (!ret) + os_free(buf); + + return ret; +} + + +static const char * json_type_str(enum json_type type) +{ + switch (type) { + case JSON_VALUE: + return "VALUE"; + case JSON_OBJECT: + return "OBJECT"; + case JSON_ARRAY: + return "ARRAY"; + case JSON_STRING: + return "STRING"; + case JSON_NUMBER: + return "NUMBER"; + case JSON_BOOLEAN: + return "BOOLEAN"; + case JSON_NULL: + return "NULL"; + } + return "??"; +} + + +static void json_print_token(struct json_token *token, int depth, + char *buf, size_t buflen) +{ + size_t len; + int ret; + + if (!token) + return; + len = os_strlen(buf); + ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]", + depth, json_type_str(token->type), + token->name ? token->name : ""); + if (os_snprintf_error(buflen - len, ret)) { + buf[len] = '\0'; + return; + } + json_print_token(token->child, depth + 1, buf, buflen); + json_print_token(token->sibling, depth, buf, buflen); +} + + +void json_print_tree(struct json_token *root, char *buf, size_t buflen) +{ + buf[0] = '\0'; + json_print_token(root, 1, buf, buflen); +} diff --git a/contrib/wpa/src/utils/json.h b/contrib/wpa/src/utils/json.h new file mode 100644 index 0000000..8faa95d --- /dev/null +++ b/contrib/wpa/src/utils/json.h @@ -0,0 +1,42 @@ +/* + * JavaScript Object Notation (JSON) parser (RFC7159) + * Copyright (c) 2017, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef JSON_H +#define JSON_H + +struct json_token { + enum json_type { + JSON_VALUE, + JSON_OBJECT, + JSON_ARRAY, + JSON_STRING, + JSON_NUMBER, + JSON_BOOLEAN, + JSON_NULL, + } type; + enum json_parsing_state { + JSON_EMPTY, + JSON_STARTED, + JSON_WAITING_VALUE, + JSON_COMPLETED, + } state; + char *name; + char *string; + int number; + struct json_token *parent, *child, *sibling; +}; + +void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len); +struct json_token * json_parse(const char *data, size_t data_len); +void json_free(struct json_token *json); +struct json_token * json_get_member(struct json_token *json, const char *name); +struct wpabuf * json_get_member_base64url(struct json_token *json, + const char *name); +void json_print_tree(struct json_token *root, char *buf, size_t buflen); + +#endif /* JSON_H */ diff --git a/contrib/wpa/src/utils/list.h b/contrib/wpa/src/utils/list.h index ee2f485..85aa5e3 100644 --- a/contrib/wpa/src/utils/list.h +++ b/contrib/wpa/src/utils/list.h @@ -1,6 +1,6 @@ /* * Doubly-linked list - * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -76,8 +76,8 @@ static inline unsigned int dl_list_len(struct dl_list *list) dl_list_entry((list)->prev, type, member)) #define dl_list_for_each(item, list, type, member) \ - for (item = dl_list_entry((list)->next, type, member); \ - &item->member != (list); \ + for (item = dl_list_first((list), type, member); \ + item && item != dl_list_entry((list), type, member); \ item = dl_list_entry(item->member.next, type, member)) #define dl_list_for_each_safe(item, n, list, type, member) \ diff --git a/contrib/wpa/src/utils/module_tests.h b/contrib/wpa/src/utils/module_tests.h new file mode 100644 index 0000000..3bfe4ad --- /dev/null +++ b/contrib/wpa/src/utils/module_tests.h @@ -0,0 +1,20 @@ +/* + * Module tests + * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef MODULE_TESTS_H +#define MODULE_TESTS_H + +int wpas_module_tests(void); +int hapd_module_tests(void); + +int utils_module_tests(void); +int wps_module_tests(void); +int common_module_tests(void); +int crypto_module_tests(void); + +#endif /* MODULE_TESTS_H */ diff --git a/contrib/wpa/src/utils/os.h b/contrib/wpa/src/utils/os.h index 9e496fb..21ba5c3 100644 --- a/contrib/wpa/src/utils/os.h +++ b/contrib/wpa/src/utils/os.h @@ -614,6 +614,18 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz); */ int os_memcmp_const(const void *a, const void *b, size_t len); + +/** + * os_memdup - Allocate duplicate of passed memory chunk + * @src: Source buffer to duplicate + * @len: Length of source buffer + * Returns: %NULL if allocation failed, copy of src buffer otherwise + * + * This function allocates a memory block like os_malloc() would, and + * copies the given source buffer into it. + */ +void * os_memdup(const void *src, size_t len); + /** * os_exec - Execute an external program * @program: Path to the program @@ -657,6 +669,10 @@ int os_exec(const char *program, const char *arg, int wait_completion); #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) #define TEST_FAIL() testing_test_fail() int testing_test_fail(void); +extern char wpa_trace_fail_func[256]; +extern unsigned int wpa_trace_fail_after; +extern char wpa_trace_test_fail_func[256]; +extern unsigned int wpa_trace_test_fail_after; #else #define TEST_FAIL() 0 #endif diff --git a/contrib/wpa/src/utils/os_internal.c b/contrib/wpa/src/utils/os_internal.c index ed6eb3c..474c8a3 100644 --- a/contrib/wpa/src/utils/os_internal.c +++ b/contrib/wpa/src/utils/os_internal.c @@ -430,22 +430,6 @@ int os_strncmp(const char *s1, const char *s2, size_t n) } -char * os_strncpy(char *dest, const char *src, size_t n) -{ - char *d = dest; - - while (n--) { - *d = *src; - if (*src == '\0') - break; - d++; - src++; - } - - return dest; -} - - size_t os_strlcpy(char *dest, const char *src, size_t siz) { const char *s = src; diff --git a/contrib/wpa/src/utils/os_none.c b/contrib/wpa/src/utils/os_none.c index 0c3214d..5e0a3ad 100644 --- a/contrib/wpa/src/utils/os_none.c +++ b/contrib/wpa/src/utils/os_none.c @@ -114,6 +114,12 @@ void * os_zalloc(size_t size) } +void * os_memdup(const void *src, size_t n) +{ + return NULL; +} + + #ifdef OS_NO_C_LIB_DEFINES void * os_malloc(size_t size) { @@ -212,12 +218,6 @@ int os_strncmp(const char *s1, const char *s2, size_t n) } -char * os_strncpy(char *dest, const char *src, size_t n) -{ - return dest; -} - - size_t os_strlcpy(char *dest, const char *src, size_t size) { return 0; diff --git a/contrib/wpa/src/utils/os_unix.c b/contrib/wpa/src/utils/os_unix.c index 488995c..ce1cf12 100644 --- a/contrib/wpa/src/utils/os_unix.c +++ b/contrib/wpa/src/utils/os_unix.c @@ -1,6 +1,6 @@ /* * OS specific functions for UNIX/POSIX systems - * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -80,6 +80,9 @@ int os_get_reltime(struct os_reltime *t) struct timespec ts; int res; + if (TEST_FAIL()) + return -1; + while (1) { res = clock_gettime(clock_id, &ts); if (res == 0) { @@ -274,6 +277,13 @@ void os_daemonize_terminate(const char *pid_file) int os_get_random(unsigned char *buf, size_t len) { +#ifdef TEST_FUZZ + size_t i; + + for (i = 0; i < len; i++) + buf[i] = i & 0xff; + return 0; +#else /* TEST_FUZZ */ FILE *f; size_t rc; @@ -290,6 +300,7 @@ int os_get_random(unsigned char *buf, size_t len) fclose(f); return rc != len ? -1 : 0; +#endif /* TEST_FUZZ */ } @@ -399,6 +410,7 @@ void os_program_deinit(void) if (total) wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", (unsigned long) total); + wpa_trace_deinit(); #endif /* WPA_TRACE */ } @@ -461,11 +473,7 @@ char * os_readfile(const char *name, size_t *len) int os_file_exists(const char *fname) { - FILE *f = fopen(fname, "rb"); - if (f == NULL) - return 0; - fclose(f); - return 1; + return access(fname, F_OK) == 0; } @@ -535,6 +543,16 @@ int os_memcmp_const(const void *a, const void *b, size_t len) } +void * os_memdup(const void *src, size_t len) +{ + void *r = os_malloc(len); + + if (r && src) + os_memcpy(r, src, len); + return r; +} + + #ifdef WPA_TRACE #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) @@ -567,6 +585,8 @@ static int testing_fail_alloc(void) i++; if (i < res && os_strcmp(func[i], "os_strdup") == 0) i++; + if (i < res && os_strcmp(func[i], "os_memdup") == 0) + i++; pos = wpa_trace_fail_func; diff --git a/contrib/wpa/src/utils/os_win32.c b/contrib/wpa/src/utils/os_win32.c index dea27b9..f9e4b30 100644 --- a/contrib/wpa/src/utils/os_win32.c +++ b/contrib/wpa/src/utils/os_win32.c @@ -283,3 +283,13 @@ int os_exec(const char *program, const char *arg, int wait_completion) { return -1; } + + +void * os_memdup(const void *src, size_t len) +{ + void *r = os_malloc(len); + + if (r) + os_memcpy(r, src, len); + return r; +} diff --git a/contrib/wpa/src/utils/pcsc_funcs.c b/contrib/wpa/src/utils/pcsc_funcs.c index 6f5ea93..383ed3d 100644 --- a/contrib/wpa/src/utils/pcsc_funcs.c +++ b/contrib/wpa/src/utils/pcsc_funcs.c @@ -11,7 +11,11 @@ */ #include "includes.h" +#ifdef __APPLE__ +#include <PCSC/winscard.h> +#else #include <winscard.h> +#endif #include "common.h" #include "pcsc_funcs.h" @@ -110,7 +114,11 @@ typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types; struct scard_data { SCARDCONTEXT ctx; SCARDHANDLE card; +#ifdef __APPLE__ + uint32_t protocol; +#else DWORD protocol; +#endif sim_types sim_type; int pin1_required; }; @@ -275,7 +283,7 @@ static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len, pos++; if (pos >= end) return -1; - if ((pos + pos[0]) < end) + if (pos[0] < end - pos) end = pos + 1 + pos[0]; pos++; wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template", @@ -504,7 +512,12 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid, struct scard_data * scard_init(const char *reader) { long ret; - unsigned long len, pos; +#ifdef __APPLE__ + uint32_t len; +#else + unsigned long len; +#endif + unsigned long pos; struct scard_data *scard; #ifdef CONFIG_NATIVE_WINDOWS TCHAR *readers = NULL; @@ -605,7 +618,7 @@ struct scard_data * scard_init(const char *reader) readers = NULL; wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)", - (unsigned int) scard->card, scard->protocol, + (unsigned int) scard->card, (unsigned long) scard->protocol, scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1"); ret = SCardBeginTransaction(scard->card); @@ -764,7 +777,11 @@ static long scard_transmit(struct scard_data *scard, unsigned char *_recv, size_t *recv_len) { long ret; +#ifdef __APPLE__ + uint32_t rlen; +#else unsigned long rlen; +#endif wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send", _send, send_len); @@ -1385,7 +1402,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, end = buf + len; /* RES */ - if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) { + if (pos[0] > RES_MAX_LEN || pos[0] > end - pos) { wpa_printf(MSG_DEBUG, "SCARD: Invalid RES"); return -1; } @@ -1395,7 +1412,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len); /* CK */ - if (pos[0] != CK_LEN || pos + CK_LEN > end) { + if (pos[0] != CK_LEN || CK_LEN > end - pos) { wpa_printf(MSG_DEBUG, "SCARD: Invalid CK"); return -1; } @@ -1405,7 +1422,7 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN); /* IK */ - if (pos[0] != IK_LEN || pos + IK_LEN > end) { + if (pos[0] != IK_LEN || IK_LEN > end - pos) { wpa_printf(MSG_DEBUG, "SCARD: Invalid IK"); return -1; } diff --git a/contrib/wpa/src/utils/platform.h b/contrib/wpa/src/utils/platform.h index 46cfe78..813987e 100644 --- a/contrib/wpa/src/utils/platform.h +++ b/contrib/wpa/src/utils/platform.h @@ -15,7 +15,7 @@ \ __ptr->__val; \ }) -#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((uint16_t *)(p))) -#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((uint32_t *)(p))) +#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((le16 *)(p))) +#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((le32 *)(p))) #endif /* PLATFORM_H */ diff --git a/contrib/wpa/src/utils/radiotap.c b/contrib/wpa/src/utils/radiotap.c index c9a5023..71996eb 100644 --- a/contrib/wpa/src/utils/radiotap.c +++ b/contrib/wpa/src/utils/radiotap.c @@ -13,8 +13,8 @@ * * See COPYING for more details. */ -#include "radiotap_iter.h" #include "platform.h" +#include "radiotap_iter.h" /* function prototypes and related defs are in radiotap_iter.h */ diff --git a/contrib/wpa/src/utils/radiotap.h b/contrib/wpa/src/utils/radiotap.h index 0572e7c..460af23 100644 --- a/contrib/wpa/src/utils/radiotap.h +++ b/contrib/wpa/src/utils/radiotap.h @@ -65,12 +65,12 @@ struct ieee80211_radiotap_header { * new fields does not count. */ uint8_t it_pad; - uint16_t it_len; /* length of the whole + le16 it_len; /* length of the whole * header in bytes, including * it_version, it_pad, * it_len, and data fields. */ - uint32_t it_present; /* A bitmap telling which + le32 it_present; /* A bitmap telling which * fields are present. Set bit 31 * (0x80000000) to extend the * bitmap by another 32 bits. diff --git a/contrib/wpa/src/utils/radiotap_iter.h b/contrib/wpa/src/utils/radiotap_iter.h index b768c85..6ea07e3 100644 --- a/contrib/wpa/src/utils/radiotap_iter.h +++ b/contrib/wpa/src/utils/radiotap_iter.h @@ -67,7 +67,7 @@ struct ieee80211_radiotap_iterator { const struct ieee80211_radiotap_namespace *current_namespace; unsigned char *_arg, *_next_ns_data; - uint32_t *_next_bitmap; + le32 *_next_bitmap; unsigned char *this_arg; #ifdef RADIOTAP_SUPPORT_OVERRIDES diff --git a/contrib/wpa/src/utils/trace.c b/contrib/wpa/src/utils/trace.c index 8484d27..e0b5b0b 100644 --- a/contrib/wpa/src/utils/trace.c +++ b/contrib/wpa/src/utils/trace.c @@ -6,6 +6,10 @@ * See README for more details. */ +#ifdef WPA_TRACE_BFD +#define _GNU_SOURCE +#include <link.h> +#endif /* WPA_TRACE_BCD */ #include "includes.h" #include "common.h" @@ -25,6 +29,28 @@ static struct dl_list active_references = static char *prg_fname = NULL; static bfd *cached_abfd = NULL; static asymbol **syms = NULL; +static unsigned long start_offset; +static int start_offset_looked_up; + + +static int callback(struct dl_phdr_info *info, size_t size, void *data) +{ + /* + * dl_iterate_phdr(3): + * "The first object visited by callback is the main program." + */ + start_offset = info->dlpi_addr; + + /* + * dl_iterate_phdr(3): + * "The dl_iterate_phdr() function walks through the list of an + * application's shared objects and calls the function callback + * once for each object, until either all shared objects have + * been processed or callback returns a nonzero value." + */ + return 1; +} + static void get_prg_fname(void) { @@ -160,7 +186,7 @@ static void wpa_trace_bfd_addr(void *pc) if (abfd == NULL) return; - data.pc = (bfd_hostptr_t) pc; + data.pc = (bfd_hostptr_t) (pc - start_offset); data.found = FALSE; bfd_map_over_sections(abfd, find_addr_sect, &data); @@ -201,7 +227,7 @@ static const char * wpa_trace_bfd_addr2func(void *pc) if (abfd == NULL) return NULL; - data.pc = (bfd_hostptr_t) pc; + data.pc = (bfd_hostptr_t) (pc - start_offset); data.found = FALSE; bfd_map_over_sections(abfd, find_addr_sect, &data); @@ -233,6 +259,11 @@ static void wpa_trace_bfd_init(void) wpa_printf(MSG_INFO, "Failed to read symbols"); return; } + + if (!start_offset_looked_up) { + dl_iterate_phdr(callback, NULL); + start_offset_looked_up = 1; + } } @@ -268,7 +299,7 @@ size_t wpa_trace_calling_func(const char *buf[], size_t len) for (i = 0; i < btrace_num; i++) { struct bfd_data data; - data.pc = (bfd_hostptr_t) btrace_res[i]; + data.pc = (bfd_hostptr_t) (btrace_res[i] - start_offset); data.found = FALSE; bfd_map_over_sections(abfd, find_addr_sect, &data); @@ -366,4 +397,13 @@ void wpa_trace_check_ref(const void *addr) } } + +void wpa_trace_deinit(void) +{ +#ifdef WPA_TRACE_BFD + free(syms); + syms = NULL; +#endif /* WPA_TRACE_BFD */ +} + #endif /* WPA_TRACE */ diff --git a/contrib/wpa/src/utils/trace.h b/contrib/wpa/src/utils/trace.h index 43ed86c..d1636de 100644 --- a/contrib/wpa/src/utils/trace.h +++ b/contrib/wpa/src/utils/trace.h @@ -66,4 +66,6 @@ void wpa_trace_dump_funcname(const char *title, void *pc); #endif /* WPA_TRACE_BFD */ +void wpa_trace_deinit(void); + #endif /* TRACE_H */ diff --git a/contrib/wpa/src/utils/utils_module_tests.c b/contrib/wpa/src/utils/utils_module_tests.c index 41511b9..3af4fcd 100644 --- a/contrib/wpa/src/utils/utils_module_tests.c +++ b/contrib/wpa/src/utils/utils_module_tests.c @@ -9,6 +9,7 @@ #include "utils/includes.h" #include "utils/common.h" +#include "utils/const_time.h" #include "common/ieee802_11_defs.h" #include "utils/bitfield.h" #include "utils/ext_password.h" @@ -16,6 +17,8 @@ #include "utils/base64.h" #include "utils/ip_addr.h" #include "utils/eloop.h" +#include "utils/json.h" +#include "utils/module_tests.h" struct printf_test_data { @@ -838,6 +841,373 @@ static int eloop_tests(void) } +#ifdef CONFIG_JSON +struct json_test_data { + const char *json; + const char *tree; +}; + +static const struct json_test_data json_test_cases[] = { + { "{}", "[1:OBJECT:]" }, + { "[]", "[1:ARRAY:]" }, + { "{", NULL }, + { "[", NULL }, + { "}", NULL }, + { "]", NULL }, + { "[[]]", "[1:ARRAY:][2:ARRAY:]" }, + { "{\"t\":\"test\"}", "[1:OBJECT:][2:STRING:t]" }, + { "{\"t\":123}", "[1:OBJECT:][2:NUMBER:t]" }, + { "{\"t\":true}", "[1:OBJECT:][2:BOOLEAN:t]" }, + { "{\"t\":false}", "[1:OBJECT:][2:BOOLEAN:t]" }, + { "{\"t\":null}", "[1:OBJECT:][2:NULL:t]" }, + { "{\"t\":truetrue}", NULL }, + { "\"test\"", "[1:STRING:]" }, + { "123", "[1:NUMBER:]" }, + { "true", "[1:BOOLEAN:]" }, + { "false", "[1:BOOLEAN:]" }, + { "null", "[1:NULL:]" }, + { "truetrue", NULL }, + { " {\t\n\r\"a\"\n:\r1\n,\n\"b\":3\n}\n", + "[1:OBJECT:][2:NUMBER:a][2:NUMBER:b]" }, + { ",", NULL }, + { "{,}", NULL }, + { "[,]", NULL }, + { ":", NULL }, + { "{:}", NULL }, + { "[:]", NULL }, + { "{ \"\\u005c\" : \"\\u005c\" }", "[1:OBJECT:][2:STRING:\\]" }, + { "[{},{}]", "[1:ARRAY:][2:OBJECT:][2:OBJECT:]" }, + { "[1,2]", "[1:ARRAY:][2:NUMBER:][2:NUMBER:]" }, + { "[\"1\",\"2\"]", "[1:ARRAY:][2:STRING:][2:STRING:]" }, + { "[true,false]", "[1:ARRAY:][2:BOOLEAN:][2:BOOLEAN:]" }, +}; +#endif /* CONFIG_JSON */ + + +static int json_tests(void) +{ +#ifdef CONFIG_JSON + unsigned int i; + struct json_token *root; + char buf[1000]; + + wpa_printf(MSG_INFO, "JSON tests"); + + for (i = 0; i < ARRAY_SIZE(json_test_cases); i++) { + const struct json_test_data *test = &json_test_cases[i]; + int res = 0; + + root = json_parse(test->json, os_strlen(test->json)); + if ((root && !test->tree) || (!root && test->tree)) { + wpa_printf(MSG_INFO, "JSON test %u failed", i); + res = -1; + } else if (root) { + json_print_tree(root, buf, sizeof(buf)); + if (os_strcmp(buf, test->tree) != 0) { + wpa_printf(MSG_INFO, + "JSON test %u tree mismatch: %s %s", + i, buf, test->tree); + res = -1; + } + } + json_free(root); + if (res < 0) + return -1; + + } +#endif /* CONFIG_JSON */ + return 0; +} + + +static int const_time_tests(void) +{ + struct const_time_fill_msb_test { + unsigned int val; + unsigned int expected; + } const_time_fill_msb_tests[] = { + { 0, 0 }, + { 1, 0 }, + { 2, 0 }, + { 1 << (sizeof(unsigned int) * 8 - 1), ~0 }, + { ~0 - 1, ~0 }, + { ~0, ~0 } + }; + struct const_time_is_zero_test { + unsigned int val; + unsigned int expected; + } const_time_is_zero_tests[] = { + { 0, ~0 }, + { 1, 0 }, + { 2, 0 }, + { 1 << (sizeof(unsigned int) * 8 - 1), 0 }, + { ~0 - 1, 0 }, + { ~0, 0 } + }; + struct const_time_eq_test { + unsigned int a; + unsigned int b; + unsigned int expected; + unsigned int expected_u8; + } const_time_eq_tests[] = { + { 0, 1, 0, 0 }, + { 1, 2, 0, 0 }, + { 1, 1, ~0, 0xff }, + { ~0, ~0, ~0, 0xff }, + { ~0, ~0 - 1, 0, 0 }, + { 0, 0, ~0, 0xff } + }; + struct const_time_eq_bin_test { + u8 *a; + u8 *b; + size_t len; + unsigned int expected; + } const_time_eq_bin_tests[] = { + { (u8 *) "", (u8 *) "", 0, ~0 }, + { (u8 *) "abcde", (u8 *) "abcde", 5, ~0 }, + { (u8 *) "abcde", (u8 *) "Abcde", 5, 0 }, + { (u8 *) "abcde", (u8 *) "aBcde", 5, 0 }, + { (u8 *) "abcde", (u8 *) "abCde", 5, 0 }, + { (u8 *) "abcde", (u8 *) "abcDe", 5, 0 }, + { (u8 *) "abcde", (u8 *) "abcdE", 5, 0 }, + { (u8 *) "\x00", (u8 *) "\x01", 1, 0 }, + { (u8 *) "\x00", (u8 *) "\x80", 1, 0 }, + { (u8 *) "\x00", (u8 *) "\x00", 1, ~0 } + }; + struct const_time_select_test { + unsigned int mask; + unsigned int true_val; + unsigned int false_val; + unsigned int expected; + } const_time_select_tests[] = { + { ~0, ~0, ~0, ~0 }, + { 0, ~0, ~0, ~0 }, + { ~0, ~0, 0, ~0 }, + { 0, ~0, 0, 0 }, + { ~0, 0xaaaaaaaa, 0x55555555, 0xaaaaaaaa }, + { 0, 0xaaaaaaaa, 0x55555555, 0x55555555 }, + { ~0, 3, 3, 3 }, + { 0, 3, 3, 3 }, + { ~0, 1, 2, 1 }, + { 0, 1, 2, 2 } + }; + struct const_time_select_int_test { + unsigned int mask; + int true_val; + int false_val; + int expected; + } const_time_select_int_tests[] = { + { ~0, -128, 127, -128 }, + { 0, -128, 127, 127 }, + { ~0, -2147483648, 2147483647, -2147483648 }, + { 0, -2147483648, 2147483647, 2147483647 }, + { ~0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { ~0, -1, 1, -1 }, + { 0, -1, 1, 1 } + }; + struct const_time_select_u8_test { + u8 mask; + u8 true_val; + u8 false_val; + u8 expected; + } const_time_select_u8_tests[] = { + { ~0, ~0, ~0, ~0 }, + { 0, ~0, ~0, ~0 }, + { ~0, ~0, 0, ~0 }, + { 0, ~0, 0, 0 }, + { ~0, 0xaa, 0x55, 0xaa }, + { 0, 0xaa, 0x55, 0x55 }, + { ~0, 1, 2, 1 }, + { 0, 1, 2, 2 } + }; + struct const_time_select_s8_test { + u8 mask; + s8 true_val; + s8 false_val; + s8 expected; + } const_time_select_s8_tests[] = { + { ~0, -128, 127, -128 }, + { 0, -128, 127, 127 }, + { ~0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { ~0, -1, 1, -1 }, + { 0, -1, 1, 1 } + }; + struct const_time_select_bin_test { + u8 mask; + u8 *true_val; + u8 *false_val; + size_t len; + u8 *expected; + } const_time_select_bin_tests[] = { + { ~0, (u8 *) "abcde", (u8 *) "ABCDE", 5, (u8 *) "abcde" }, + { 0, (u8 *) "abcde", (u8 *) "ABCDE", 5, (u8 *) "ABCDE" }, + { ~0, (u8 *) "", (u8 *) "", 0, (u8 *) "" }, + { 0, (u8 *) "", (u8 *) "", 0, (u8 *) "" } + }; + struct const_time_memcmp_test { + char *a; + char *b; + size_t len; + int expected; + } const_time_memcmp_tests[] = { + { "abcde", "abcde", 5, 0 }, + { "abcde", "bbcde", 5, -1 }, + { "bbcde", "abcde", 5, 1 }, + { "accde", "abcde", 5, 1 }, + { "abcee", "abcde", 5, 1 }, + { "abcdf", "abcde", 5, 1 }, + { "cbcde", "aXXXX", 5, 2 }, + { "a", "d", 1, -3 }, + { "", "", 0, 0 } + }; + unsigned int i; + int ret = 0; + + wpa_printf(MSG_INFO, "constant time tests"); + + for (i = 0; i < ARRAY_SIZE(const_time_fill_msb_tests); i++) { + struct const_time_fill_msb_test *test; + + test = &const_time_fill_msb_tests[i]; + if (const_time_fill_msb(test->val) != test->expected) { + wpa_printf(MSG_ERROR, + "const_time_fill_msb(0x%x) test failed", + test->val); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_is_zero_tests); i++) { + struct const_time_is_zero_test *test; + + test = &const_time_is_zero_tests[i]; + if (const_time_is_zero(test->val) != test->expected) { + wpa_printf(MSG_ERROR, + "const_time_is_zero(0x%x) test failed", + test->val); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_eq_tests); i++) { + struct const_time_eq_test *test; + + test = &const_time_eq_tests[i]; + if (const_time_eq(test->a, test->b) != test->expected) { + wpa_printf(MSG_ERROR, + "const_time_eq(0x%x,0x%x) test failed", + test->a, test->b); + ret = -1; + } + if (const_time_eq_u8(test->a, test->b) != test->expected_u8) { + wpa_printf(MSG_ERROR, + "const_time_eq_u8(0x%x,0x%x) test failed", + test->a, test->b); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_eq_bin_tests); i++) { + struct const_time_eq_bin_test *test; + + test = &const_time_eq_bin_tests[i]; + if (const_time_eq_bin(test->a, test->b, test->len) != + test->expected) { + wpa_printf(MSG_ERROR, + "const_time_eq_bin(len=%u) test failed", + (unsigned int) test->len); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_select_tests); i++) { + struct const_time_select_test *test; + + test = &const_time_select_tests[i]; + if (const_time_select(test->mask, test->true_val, + test->false_val) != test->expected) { + wpa_printf(MSG_ERROR, + "const_time_select(0x%x,0x%x,0x%x) test failed", + test->mask, test->true_val, test->false_val); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_select_int_tests); i++) { + struct const_time_select_int_test *test; + + test = &const_time_select_int_tests[i]; + if (const_time_select_int(test->mask, test->true_val, + test->false_val) != test->expected) { + wpa_printf(MSG_ERROR, + "const_time_select_int(0x%x,%d,%d) test failed", + test->mask, test->true_val, test->false_val); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_select_u8_tests); i++) { + struct const_time_select_u8_test *test; + + test = &const_time_select_u8_tests[i]; + if (const_time_select_u8(test->mask, test->true_val, + test->false_val) != test->expected) { + wpa_printf(MSG_ERROR, + "const_time_select_u8(0x%x,0x%x,0x%x) test failed", + test->mask, test->true_val, test->false_val); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_select_s8_tests); i++) { + struct const_time_select_s8_test *test; + + test = &const_time_select_s8_tests[i]; + if (const_time_select_s8(test->mask, test->true_val, + test->false_val) != test->expected) { + wpa_printf(MSG_ERROR, + "const_time_select_s8(0x%x,0x%x,0x%x) test failed", + test->mask, test->true_val, test->false_val); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_select_bin_tests); i++) { + struct const_time_select_bin_test *test; + u8 dst[100]; + + test = &const_time_select_bin_tests[i]; + const_time_select_bin(test->mask, test->true_val, + test->false_val, test->len, dst); + if (os_memcmp(dst, test->expected, test->len) != 0) { + wpa_printf(MSG_ERROR, + "const_time_select_bin(0x%x,%u) test failed", + test->mask, (unsigned int) test->len); + ret = -1; + } + } + + for (i = 0; i < ARRAY_SIZE(const_time_memcmp_tests); i++) { + struct const_time_memcmp_test *test; + int res; + + test = &const_time_memcmp_tests[i]; + res = const_time_memcmp(test->a, test->b, test->len); + if (res != test->expected) { + wpa_printf(MSG_ERROR, + "const_time_memcmp(%s,%s,%d) test failed (%d != %d)", + test->a, test->b, (int) test->len, + res, test->expected); + ret = -1; + } + } + + return ret; +} + + int utils_module_tests(void) { int ret = 0; @@ -854,6 +1224,8 @@ int utils_module_tests(void) wpabuf_tests() < 0 || ip_addr_tests() < 0 || eloop_tests() < 0 || + json_tests() < 0 || + const_time_tests() < 0 || int_array_tests() < 0) ret = -1; diff --git a/contrib/wpa/src/utils/uuid.c b/contrib/wpa/src/utils/uuid.c index 0f224f9..98e43d0 100644 --- a/contrib/wpa/src/utils/uuid.c +++ b/contrib/wpa/src/utils/uuid.c @@ -9,6 +9,7 @@ #include "includes.h" #include "common.h" +#include "crypto/sha256.h" #include "uuid.h" int uuid_str2bin(const char *str, u8 *bin) @@ -69,3 +70,27 @@ int is_nil_uuid(const u8 *uuid) return 0; return 1; } + + +int uuid_random(u8 *uuid) +{ + struct os_time t; + u8 hash[SHA256_MAC_LEN]; + + /* Use HMAC-SHA256 and timestamp as context to avoid exposing direct + * os_get_random() output in the UUID field. */ + os_get_time(&t); + if (os_get_random(uuid, UUID_LEN) < 0 || + hmac_sha256(uuid, UUID_LEN, (const u8 *) &t, sizeof(t), hash) < 0) + return -1; + + os_memcpy(uuid, hash, UUID_LEN); + + /* Version: 4 = random */ + uuid[6] = (4 << 4) | (uuid[6] & 0x0f); + + /* Variant specified in RFC 4122 */ + uuid[8] = 0x80 | (uuid[8] & 0x3f); + + return 0; +} diff --git a/contrib/wpa/src/utils/uuid.h b/contrib/wpa/src/utils/uuid.h index 5e860cb..6e20210 100644 --- a/contrib/wpa/src/utils/uuid.h +++ b/contrib/wpa/src/utils/uuid.h @@ -14,5 +14,6 @@ int uuid_str2bin(const char *str, u8 *bin); int uuid_bin2str(const u8 *bin, char *str, size_t max_len); int is_nil_uuid(const u8 *uuid); +int uuid_random(u8 *uuid); #endif /* UUID_H */ diff --git a/contrib/wpa/src/utils/wpa_debug.c b/contrib/wpa/src/utils/wpa_debug.c index 61c0d5c..c437000 100644 --- a/contrib/wpa/src/utils/wpa_debug.c +++ b/contrib/wpa/src/utils/wpa_debug.c @@ -13,7 +13,7 @@ #ifdef CONFIG_DEBUG_SYSLOG #include <syslog.h> -static int wpa_debug_syslog = 0; +int wpa_debug_syslog = 0; #endif /* CONFIG_DEBUG_SYSLOG */ #ifdef CONFIG_DEBUG_LINUX_TRACING @@ -58,6 +58,10 @@ static int wpa_to_android_level(int level) #ifndef CONFIG_NO_STDOUT_DEBUG #ifdef CONFIG_DEBUG_FILE +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + static FILE *out_file = NULL; #endif /* CONFIG_DEBUG_FILE */ @@ -148,7 +152,7 @@ int wpa_debug_open_linux_tracing(void) strtok_r(line, " ", &tmp2); tmp_path = strtok_r(NULL, " ", &tmp2); fstype = strtok_r(NULL, " ", &tmp2); - if (strcmp(fstype, "debugfs") == 0) { + if (fstype && strcmp(fstype, "debugfs") == 0) { path = tmp_path; break; } @@ -418,6 +422,12 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, #ifdef CONFIG_ANDROID_LOG _wpa_hexdump(level, title, buf, len, show); #else /* CONFIG_ANDROID_LOG */ +#ifdef CONFIG_DEBUG_SYSLOG + if (wpa_debug_syslog) { + _wpa_hexdump(level, title, buf, len, show); + return; + } +#endif /* CONFIG_DEBUG_SYSLOG */ wpa_debug_print_timestamp(); #ifdef CONFIG_DEBUG_FILE if (out_file) { @@ -517,16 +527,18 @@ int wpa_debug_reopen_file(void) { #ifdef CONFIG_DEBUG_FILE int rv; - if (last_path) { - char *tmp = os_strdup(last_path); - wpa_debug_close_file(); - rv = wpa_debug_open_file(tmp); - os_free(tmp); - } else { - wpa_printf(MSG_ERROR, "Last-path was not set, cannot " - "re-open log file."); - rv = -1; - } + char *tmp; + + if (!last_path) + return 0; /* logfile not used */ + + tmp = os_strdup(last_path); + if (!tmp) + return -1; + + wpa_debug_close_file(); + rv = wpa_debug_open_file(tmp); + os_free(tmp); return rv; #else /* CONFIG_DEBUG_FILE */ return 0; @@ -537,6 +549,8 @@ int wpa_debug_reopen_file(void) int wpa_debug_open_file(const char *path) { #ifdef CONFIG_DEBUG_FILE + int out_fd; + if (!path) return 0; @@ -546,10 +560,28 @@ int wpa_debug_open_file(const char *path) last_path = os_strdup(path); } - out_file = fopen(path, "a"); + out_fd = open(path, O_CREAT | O_APPEND | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP); + if (out_fd < 0) { + wpa_printf(MSG_ERROR, + "%s: Failed to open output file descriptor, using standard output", + __func__); + return -1; + } + +#ifdef __linux__ + if (fcntl(out_fd, F_SETFD, FD_CLOEXEC) < 0) { + wpa_printf(MSG_DEBUG, + "%s: Failed to set FD_CLOEXEC - continue without: %s", + __func__, strerror(errno)); + } +#endif /* __linux__ */ + + out_file = fdopen(out_fd, "a"); if (out_file == NULL) { wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open " "output file, using standard output"); + close(out_fd); return -1; } #ifndef _WIN32 diff --git a/contrib/wpa/src/utils/wpa_debug.h b/contrib/wpa/src/utils/wpa_debug.h index 17d8f96..1fe0b7d 100644 --- a/contrib/wpa/src/utils/wpa_debug.h +++ b/contrib/wpa/src/utils/wpa_debug.h @@ -14,6 +14,9 @@ extern int wpa_debug_level; extern int wpa_debug_show_keys; extern int wpa_debug_timestamp; +#ifdef CONFIG_DEBUG_SYSLOG +extern int wpa_debug_syslog; +#endif /* CONFIG_DEBUG_SYSLOG */ /* Debugging function - conditional printf and hex dump. Driver wrappers can * use these for debugging purposes. */ diff --git a/contrib/wpa/src/utils/wpabuf.c b/contrib/wpa/src/utils/wpabuf.c index 11e7323..77ee472 100644 --- a/contrib/wpa/src/utils/wpabuf.c +++ b/contrib/wpa/src/utils/wpabuf.c @@ -244,15 +244,13 @@ struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) if (a) len += wpabuf_len(a); - if (b) - len += wpabuf_len(b); + len += wpabuf_len(b); n = wpabuf_alloc(len); if (n) { if (a) wpabuf_put_buf(n, a); - if (b) - wpabuf_put_buf(n, b); + wpabuf_put_buf(n, b); } wpabuf_free(a); @@ -310,3 +308,33 @@ void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) wpabuf_overflow(buf, res); buf->used += res; } + + +/** + * wpabuf_parse_bin - Parse a null terminated string of binary data to a wpabuf + * @buf: Buffer with null terminated string (hexdump) of binary data + * Returns: wpabuf or %NULL on failure + * + * The string len must be a multiple of two and contain only hexadecimal digits. + */ +struct wpabuf * wpabuf_parse_bin(const char *buf) +{ + size_t len; + struct wpabuf *ret; + + len = os_strlen(buf); + if (len & 0x01) + return NULL; + len /= 2; + + ret = wpabuf_alloc(len); + if (ret == NULL) + return NULL; + + if (hexstr2bin(buf, wpabuf_put(ret, len), len)) { + wpabuf_free(ret); + return NULL; + } + + return ret; +} diff --git a/contrib/wpa/src/utils/wpabuf.h b/contrib/wpa/src/utils/wpabuf.h index c3ef1ba..01da41b 100644 --- a/contrib/wpa/src/utils/wpabuf.h +++ b/contrib/wpa/src/utils/wpabuf.h @@ -37,6 +37,7 @@ void * wpabuf_put(struct wpabuf *buf, size_t len); struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); +struct wpabuf * wpabuf_parse_bin(const char *buf); /** @@ -81,7 +82,7 @@ static inline const void * wpabuf_head(const struct wpabuf *buf) static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) { - return wpabuf_head(buf); + return (const u8 *) wpabuf_head(buf); } /** @@ -96,42 +97,42 @@ static inline void * wpabuf_mhead(struct wpabuf *buf) static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) { - return wpabuf_mhead(buf); + return (u8 *) wpabuf_mhead(buf); } static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) { - u8 *pos = wpabuf_put(buf, 1); + u8 *pos = (u8 *) wpabuf_put(buf, 1); *pos = data; } static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) { - u8 *pos = wpabuf_put(buf, 2); + u8 *pos = (u8 *) wpabuf_put(buf, 2); WPA_PUT_LE16(pos, data); } static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) { - u8 *pos = wpabuf_put(buf, 4); + u8 *pos = (u8 *) wpabuf_put(buf, 4); WPA_PUT_LE32(pos, data); } static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) { - u8 *pos = wpabuf_put(buf, 2); + u8 *pos = (u8 *) wpabuf_put(buf, 2); WPA_PUT_BE16(pos, data); } static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) { - u8 *pos = wpabuf_put(buf, 3); + u8 *pos = (u8 *) wpabuf_put(buf, 3); WPA_PUT_BE24(pos, data); } static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) { - u8 *pos = wpabuf_put(buf, 4); + u8 *pos = (u8 *) wpabuf_put(buf, 4); WPA_PUT_BE32(pos, data); } diff --git a/contrib/wpa/src/utils/xml-utils.c b/contrib/wpa/src/utils/xml-utils.c index 4916d29..dae91fe 100644 --- a/contrib/wpa/src/utils/xml-utils.c +++ b/contrib/wpa/src/utils/xml-utils.c @@ -246,10 +246,10 @@ static void node_to_tnds(struct xml_node_ctx *ctx, xml_node_t *out, xml_node_create_text(ctx, tnds, NULL, "Path", uri); val = get_val(ctx, node); - if (val) { - xml_node_create_text(ctx, tnds, NULL, "Value", val); - xml_node_get_text_free(ctx, val); - } + if (val || !xml_node_first_child(ctx, node)) + xml_node_create_text(ctx, tnds, NULL, "Value", + val ? val : ""); + xml_node_get_text_free(ctx, val); new_uri = add_path(uri, name); node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri); diff --git a/contrib/wpa/src/utils/xml_libxml2.c b/contrib/wpa/src/utils/xml_libxml2.c index c928394..7b6d276 100644 --- a/contrib/wpa/src/utils/xml_libxml2.c +++ b/contrib/wpa/src/utils/xml_libxml2.c @@ -212,6 +212,8 @@ char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node) xmlDocSetRootElement(doc, n); xmlDocDumpFormatMemory(doc, &buf, &bufsiz, 0); xmlFreeDoc(doc); + if (!buf) + return NULL; pos = (char *) buf; if (strncmp(pos, "<?xml", 5) == 0) { pos = strchr(pos, '>'); |