summaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/Makefile1
-rw-r--r--src/utils/base64.c139
-rw-r--r--src/utils/base64.h4
-rw-r--r--src/utils/browser-wpadebug.c7
-rw-r--r--src/utils/common.c21
-rw-r--r--src/utils/common.h15
-rw-r--r--src/utils/crc32.c85
-rw-r--r--src/utils/crc32.h14
-rw-r--r--src/utils/eloop.h8
-rw-r--r--src/utils/http_curl.c34
-rw-r--r--src/utils/json.c569
-rw-r--r--src/utils/json.h42
-rw-r--r--src/utils/os.h12
-rw-r--r--src/utils/os_none.c6
-rw-r--r--src/utils/os_unix.c15
-rw-r--r--src/utils/os_win32.c10
-rw-r--r--src/utils/trace.c37
-rw-r--r--src/utils/utils_module_tests.c81
-rw-r--r--src/utils/uuid.c25
-rw-r--r--src/utils/uuid.h1
-rw-r--r--src/utils/wpa_debug.c28
-rw-r--r--src/utils/wpa_debug.h3
-rw-r--r--src/utils/wpabuf.c6
-rw-r--r--src/utils/xml-utils.c8
24 files changed, 1095 insertions, 76 deletions
diff --git a/src/utils/Makefile b/src/utils/Makefile
index 8aad813cfc85..52efc5321fca 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -17,6 +17,7 @@ LIB_OBJS= \
base64.o \
bitfield.o \
common.o \
+ crc32.o \
ip_addr.o \
radiotap.o \
trace.o \
diff --git a/src/utils/base64.c b/src/utils/base64.c
index d44f290e5684..8eb4ba127d48 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -13,21 +13,14 @@
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;
@@ -35,7 +28,8 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
int line_len;
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 +42,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 +80,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 +100,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 +148,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/src/utils/base64.h b/src/utils/base64.h
index aa21fd0fc1b7..5a72c3ebf522 100644
--- a/src/utils/base64.h
+++ b/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/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index 59ba4d1e02d8..dfb4b67977f8 100644
--- a/src/utils/browser-wpadebug.c
+++ b/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/src/utils/common.c b/src/utils/common.c
index 04a533a05902..1eb33705bef3 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -1200,3 +1200,24 @@ 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;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 77856774d215..f824d001aeab 100644
--- a/src/utils/common.h
+++ b/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
@@ -331,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__
@@ -423,6 +436,7 @@ void perror(const char *s);
#define __bitwise __attribute__((bitwise))
#else
#define __force
+#undef __bitwise
#define __bitwise
#endif
@@ -552,6 +566,7 @@ int is_ctrl_char(char c);
int str_starts(const char *str, const char *start);
+u8 rssi_to_rcpi(int rssi);
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/src/utils/crc32.c b/src/utils/crc32.c
new file mode 100644
index 000000000000..12d9e2a7008e
--- /dev/null
+++ b/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/src/utils/crc32.h b/src/utils/crc32.h
new file mode 100644
index 000000000000..dc31399beb63
--- /dev/null
+++ b/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/src/utils/eloop.h b/src/utils/eloop.h
index 97af16f0130a..04ee6d1837b6 100644
--- a/src/utils/eloop.h
+++ b/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
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index a06aae8d9b9d..58519ea8d248 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -486,12 +486,11 @@ 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_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);
@@ -987,7 +986,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",
@@ -1095,7 +1094,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;
@@ -1200,17 +1199,36 @@ 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)");
diff --git a/src/utils/json.c b/src/utils/json.c
new file mode 100644
index 000000000000..b9130d3a65ab
--- /dev/null
+++ b/src/utils/json.c
@@ -0,0 +1,569 @@
+/*
+ * 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++;
+ 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 < *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/src/utils/json.h b/src/utils/json.h
new file mode 100644
index 000000000000..8faa95d8bf20
--- /dev/null
+++ b/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/src/utils/os.h b/src/utils/os.h
index e8f0b792738a..21ba5c3ff85b 100644
--- a/src/utils/os.h
+++ b/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
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index 0c3214d32ce5..e74f206a2c5a 100644
--- a/src/utils/os_none.c
+++ b/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)
{
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 65c6fa412f20..1894fcdb0cf2 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -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) {
@@ -505,6 +508,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)
+ os_memcpy(r, src, len);
+ return r;
+}
+
+
#ifdef WPA_TRACE
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
@@ -537,6 +550,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/src/utils/os_win32.c b/src/utils/os_win32.c
index dea27b9f2ad8..f9e4b308ea5f 100644
--- a/src/utils/os_win32.c
+++ b/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/src/utils/trace.c b/src/utils/trace.c
index d72cf604f8e9..e0b5b0bb99f5 100644
--- a/src/utils/trace.c
+++ b/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);
diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c
index abdb79c9879c..1b8ff82b4173 100644
--- a/src/utils/utils_module_tests.c
+++ b/src/utils/utils_module_tests.c
@@ -16,6 +16,7 @@
#include "utils/base64.h"
#include "utils/ip_addr.h"
#include "utils/eloop.h"
+#include "utils/json.h"
#include "utils/module_tests.h"
@@ -839,6 +840,85 @@ 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;
+}
+
+
int utils_module_tests(void)
{
int ret = 0;
@@ -855,6 +935,7 @@ int utils_module_tests(void)
wpabuf_tests() < 0 ||
ip_addr_tests() < 0 ||
eloop_tests() < 0 ||
+ json_tests() < 0 ||
int_array_tests() < 0)
ret = -1;
diff --git a/src/utils/uuid.c b/src/utils/uuid.c
index 0f224f976b80..98e43d02f68b 100644
--- a/src/utils/uuid.c
+++ b/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/src/utils/uuid.h b/src/utils/uuid.h
index 5e860cbc5936..6e20210f99b9 100644
--- a/src/utils/uuid.h
+++ b/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/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index f7acf6b9f698..a56462b8bbdc 100644
--- a/src/utils/wpa_debug.c
+++ b/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 */
@@ -539,6 +543,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;
@@ -548,10 +554,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/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 17d8f963802e..1fe0b7db7482 100644
--- a/src/utils/wpa_debug.h
+++ b/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/src/utils/wpabuf.c b/src/utils/wpabuf.c
index 96cb25cc1764..77ee47288007 100644
--- a/src/utils/wpabuf.c
+++ b/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);
diff --git a/src/utils/xml-utils.c b/src/utils/xml-utils.c
index 4916d29765f9..dae91fee46f6 100644
--- a/src/utils/xml-utils.c
+++ b/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);