xref: /freebsd/contrib/wpa/src/utils/common.c (revision 38f0b757fd84d17d0fc24739a7cda160c4516d81)
1 /*
2  * wpa_supplicant/hostapd / common helper functions, etc.
3  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 
13 
14 static int hex2num(char c)
15 {
16 	if (c >= '0' && c <= '9')
17 		return c - '0';
18 	if (c >= 'a' && c <= 'f')
19 		return c - 'a' + 10;
20 	if (c >= 'A' && c <= 'F')
21 		return c - 'A' + 10;
22 	return -1;
23 }
24 
25 
26 int hex2byte(const char *hex)
27 {
28 	int a, b;
29 	a = hex2num(*hex++);
30 	if (a < 0)
31 		return -1;
32 	b = hex2num(*hex++);
33 	if (b < 0)
34 		return -1;
35 	return (a << 4) | b;
36 }
37 
38 
39 /**
40  * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
41  * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
42  * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
43  * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
44  */
45 int hwaddr_aton(const char *txt, u8 *addr)
46 {
47 	int i;
48 
49 	for (i = 0; i < 6; i++) {
50 		int a, b;
51 
52 		a = hex2num(*txt++);
53 		if (a < 0)
54 			return -1;
55 		b = hex2num(*txt++);
56 		if (b < 0)
57 			return -1;
58 		*addr++ = (a << 4) | b;
59 		if (i < 5 && *txt++ != ':')
60 			return -1;
61 	}
62 
63 	return 0;
64 }
65 
66 /**
67  * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
68  * @txt: MAC address as a string (e.g., "001122334455")
69  * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
70  * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
71  */
72 int hwaddr_compact_aton(const char *txt, u8 *addr)
73 {
74 	int i;
75 
76 	for (i = 0; i < 6; i++) {
77 		int a, b;
78 
79 		a = hex2num(*txt++);
80 		if (a < 0)
81 			return -1;
82 		b = hex2num(*txt++);
83 		if (b < 0)
84 			return -1;
85 		*addr++ = (a << 4) | b;
86 	}
87 
88 	return 0;
89 }
90 
91 /**
92  * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
93  * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
94  * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
95  * Returns: Characters used (> 0) on success, -1 on failure
96  */
97 int hwaddr_aton2(const char *txt, u8 *addr)
98 {
99 	int i;
100 	const char *pos = txt;
101 
102 	for (i = 0; i < 6; i++) {
103 		int a, b;
104 
105 		while (*pos == ':' || *pos == '.' || *pos == '-')
106 			pos++;
107 
108 		a = hex2num(*pos++);
109 		if (a < 0)
110 			return -1;
111 		b = hex2num(*pos++);
112 		if (b < 0)
113 			return -1;
114 		*addr++ = (a << 4) | b;
115 	}
116 
117 	return pos - txt;
118 }
119 
120 
121 /**
122  * hexstr2bin - Convert ASCII hex string into binary data
123  * @hex: ASCII hex string (e.g., "01ab")
124  * @buf: Buffer for the binary data
125  * @len: Length of the text to convert in bytes (of buf); hex will be double
126  * this size
127  * Returns: 0 on success, -1 on failure (invalid hex string)
128  */
129 int hexstr2bin(const char *hex, u8 *buf, size_t len)
130 {
131 	size_t i;
132 	int a;
133 	const char *ipos = hex;
134 	u8 *opos = buf;
135 
136 	for (i = 0; i < len; i++) {
137 		a = hex2byte(ipos);
138 		if (a < 0)
139 			return -1;
140 		*opos++ = a;
141 		ipos += 2;
142 	}
143 	return 0;
144 }
145 
146 
147 /**
148  * inc_byte_array - Increment arbitrary length byte array by one
149  * @counter: Pointer to byte array
150  * @len: Length of the counter in bytes
151  *
152  * This function increments the last byte of the counter by one and continues
153  * rolling over to more significant bytes if the byte was incremented from
154  * 0xff to 0x00.
155  */
156 void inc_byte_array(u8 *counter, size_t len)
157 {
158 	int pos = len - 1;
159 	while (pos >= 0) {
160 		counter[pos]++;
161 		if (counter[pos] != 0)
162 			break;
163 		pos--;
164 	}
165 }
166 
167 
168 void wpa_get_ntp_timestamp(u8 *buf)
169 {
170 	struct os_time now;
171 	u32 sec, usec;
172 	be32 tmp;
173 
174 	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
175 	os_get_time(&now);
176 	sec = now.sec + 2208988800U; /* Epoch to 1900 */
177 	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
178 	usec = now.usec;
179 	usec = 4295 * usec - (usec >> 5) - (usec >> 9);
180 	tmp = host_to_be32(sec);
181 	os_memcpy(buf, (u8 *) &tmp, 4);
182 	tmp = host_to_be32(usec);
183 	os_memcpy(buf + 4, (u8 *) &tmp, 4);
184 }
185 
186 
187 static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
188 				    size_t len, int uppercase)
189 {
190 	size_t i;
191 	char *pos = buf, *end = buf + buf_size;
192 	int ret;
193 	if (buf_size == 0)
194 		return 0;
195 	for (i = 0; i < len; i++) {
196 		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
197 				  data[i]);
198 		if (ret < 0 || ret >= end - pos) {
199 			end[-1] = '\0';
200 			return pos - buf;
201 		}
202 		pos += ret;
203 	}
204 	end[-1] = '\0';
205 	return pos - buf;
206 }
207 
208 /**
209  * wpa_snprintf_hex - Print data as a hex string into a buffer
210  * @buf: Memory area to use as the output buffer
211  * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
212  * @data: Data to be printed
213  * @len: Length of data in bytes
214  * Returns: Number of bytes written
215  */
216 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
217 {
218 	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
219 }
220 
221 
222 /**
223  * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
224  * @buf: Memory area to use as the output buffer
225  * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
226  * @data: Data to be printed
227  * @len: Length of data in bytes
228  * Returns: Number of bytes written
229  */
230 int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
231 			       size_t len)
232 {
233 	return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
234 }
235 
236 
237 #ifdef CONFIG_ANSI_C_EXTRA
238 
239 #ifdef _WIN32_WCE
240 void perror(const char *s)
241 {
242 	wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
243 		   s, (int) GetLastError());
244 }
245 #endif /* _WIN32_WCE */
246 
247 
248 int optind = 1;
249 int optopt;
250 char *optarg;
251 
252 int getopt(int argc, char *const argv[], const char *optstring)
253 {
254 	static int optchr = 1;
255 	char *cp;
256 
257 	if (optchr == 1) {
258 		if (optind >= argc) {
259 			/* all arguments processed */
260 			return EOF;
261 		}
262 
263 		if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
264 			/* no option characters */
265 			return EOF;
266 		}
267 	}
268 
269 	if (os_strcmp(argv[optind], "--") == 0) {
270 		/* no more options */
271 		optind++;
272 		return EOF;
273 	}
274 
275 	optopt = argv[optind][optchr];
276 	cp = os_strchr(optstring, optopt);
277 	if (cp == NULL || optopt == ':') {
278 		if (argv[optind][++optchr] == '\0') {
279 			optchr = 1;
280 			optind++;
281 		}
282 		return '?';
283 	}
284 
285 	if (cp[1] == ':') {
286 		/* Argument required */
287 		optchr = 1;
288 		if (argv[optind][optchr + 1]) {
289 			/* No space between option and argument */
290 			optarg = &argv[optind++][optchr + 1];
291 		} else if (++optind >= argc) {
292 			/* option requires an argument */
293 			return '?';
294 		} else {
295 			/* Argument in the next argv */
296 			optarg = argv[optind++];
297 		}
298 	} else {
299 		/* No argument */
300 		if (argv[optind][++optchr] == '\0') {
301 			optchr = 1;
302 			optind++;
303 		}
304 		optarg = NULL;
305 	}
306 	return *cp;
307 }
308 #endif /* CONFIG_ANSI_C_EXTRA */
309 
310 
311 #ifdef CONFIG_NATIVE_WINDOWS
312 /**
313  * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
314  * @str: Pointer to string to convert
315  *
316  * This function converts a unicode string to ASCII using the same
317  * buffer for output. If UNICODE is not set, the buffer is not
318  * modified.
319  */
320 void wpa_unicode2ascii_inplace(TCHAR *str)
321 {
322 #ifdef UNICODE
323 	char *dst = (char *) str;
324 	while (*str)
325 		*dst++ = (char) *str++;
326 	*dst = '\0';
327 #endif /* UNICODE */
328 }
329 
330 
331 TCHAR * wpa_strdup_tchar(const char *str)
332 {
333 #ifdef UNICODE
334 	TCHAR *buf;
335 	buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
336 	if (buf == NULL)
337 		return NULL;
338 	wsprintf(buf, L"%S", str);
339 	return buf;
340 #else /* UNICODE */
341 	return os_strdup(str);
342 #endif /* UNICODE */
343 }
344 #endif /* CONFIG_NATIVE_WINDOWS */
345 
346 
347 void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
348 {
349 	char *end = txt + maxlen;
350 	size_t i;
351 
352 	for (i = 0; i < len; i++) {
353 		if (txt + 4 > end)
354 			break;
355 
356 		switch (data[i]) {
357 		case '\"':
358 			*txt++ = '\\';
359 			*txt++ = '\"';
360 			break;
361 		case '\\':
362 			*txt++ = '\\';
363 			*txt++ = '\\';
364 			break;
365 		case '\e':
366 			*txt++ = '\\';
367 			*txt++ = 'e';
368 			break;
369 		case '\n':
370 			*txt++ = '\\';
371 			*txt++ = 'n';
372 			break;
373 		case '\r':
374 			*txt++ = '\\';
375 			*txt++ = 'r';
376 			break;
377 		case '\t':
378 			*txt++ = '\\';
379 			*txt++ = 't';
380 			break;
381 		default:
382 			if (data[i] >= 32 && data[i] <= 127) {
383 				*txt++ = data[i];
384 			} else {
385 				txt += os_snprintf(txt, end - txt, "\\x%02x",
386 						   data[i]);
387 			}
388 			break;
389 		}
390 	}
391 
392 	*txt = '\0';
393 }
394 
395 
396 size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
397 {
398 	const char *pos = str;
399 	size_t len = 0;
400 	int val;
401 
402 	while (*pos) {
403 		if (len == maxlen)
404 			break;
405 		switch (*pos) {
406 		case '\\':
407 			pos++;
408 			switch (*pos) {
409 			case '\\':
410 				buf[len++] = '\\';
411 				pos++;
412 				break;
413 			case '"':
414 				buf[len++] = '"';
415 				pos++;
416 				break;
417 			case 'n':
418 				buf[len++] = '\n';
419 				pos++;
420 				break;
421 			case 'r':
422 				buf[len++] = '\r';
423 				pos++;
424 				break;
425 			case 't':
426 				buf[len++] = '\t';
427 				pos++;
428 				break;
429 			case 'e':
430 				buf[len++] = '\e';
431 				pos++;
432 				break;
433 			case 'x':
434 				pos++;
435 				val = hex2byte(pos);
436 				if (val < 0) {
437 					val = hex2num(*pos);
438 					if (val < 0)
439 						break;
440 					buf[len++] = val;
441 					pos++;
442 				} else {
443 					buf[len++] = val;
444 					pos += 2;
445 				}
446 				break;
447 			case '0':
448 			case '1':
449 			case '2':
450 			case '3':
451 			case '4':
452 			case '5':
453 			case '6':
454 			case '7':
455 				val = *pos++ - '0';
456 				if (*pos >= '0' && *pos <= '7')
457 					val = val * 8 + (*pos++ - '0');
458 				if (*pos >= '0' && *pos <= '7')
459 					val = val * 8 + (*pos++ - '0');
460 				buf[len++] = val;
461 				break;
462 			default:
463 				break;
464 			}
465 			break;
466 		default:
467 			buf[len++] = *pos++;
468 			break;
469 		}
470 	}
471 
472 	return len;
473 }
474 
475 
476 /**
477  * wpa_ssid_txt - Convert SSID to a printable string
478  * @ssid: SSID (32-octet string)
479  * @ssid_len: Length of ssid in octets
480  * Returns: Pointer to a printable string
481  *
482  * This function can be used to convert SSIDs into printable form. In most
483  * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
484  * does not limit the used character set, so anything could be used in an SSID.
485  *
486  * This function uses a static buffer, so only one call can be used at the
487  * time, i.e., this is not re-entrant and the returned buffer must be used
488  * before calling this again.
489  */
490 const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
491 {
492 	static char ssid_txt[32 * 4 + 1];
493 
494 	if (ssid == NULL) {
495 		ssid_txt[0] = '\0';
496 		return ssid_txt;
497 	}
498 
499 	printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
500 	return ssid_txt;
501 }
502 
503 
504 void * __hide_aliasing_typecast(void *foo)
505 {
506 	return foo;
507 }
508 
509 
510 char * wpa_config_parse_string(const char *value, size_t *len)
511 {
512 	if (*value == '"') {
513 		const char *pos;
514 		char *str;
515 		value++;
516 		pos = os_strrchr(value, '"');
517 		if (pos == NULL || pos[1] != '\0')
518 			return NULL;
519 		*len = pos - value;
520 		str = os_malloc(*len + 1);
521 		if (str == NULL)
522 			return NULL;
523 		os_memcpy(str, value, *len);
524 		str[*len] = '\0';
525 		return str;
526 	} else if (*value == 'P' && value[1] == '"') {
527 		const char *pos;
528 		char *tstr, *str;
529 		size_t tlen;
530 		value += 2;
531 		pos = os_strrchr(value, '"');
532 		if (pos == NULL || pos[1] != '\0')
533 			return NULL;
534 		tlen = pos - value;
535 		tstr = os_malloc(tlen + 1);
536 		if (tstr == NULL)
537 			return NULL;
538 		os_memcpy(tstr, value, tlen);
539 		tstr[tlen] = '\0';
540 
541 		str = os_malloc(tlen + 1);
542 		if (str == NULL) {
543 			os_free(tstr);
544 			return NULL;
545 		}
546 
547 		*len = printf_decode((u8 *) str, tlen + 1, tstr);
548 		os_free(tstr);
549 
550 		return str;
551 	} else {
552 		u8 *str;
553 		size_t tlen, hlen = os_strlen(value);
554 		if (hlen & 1)
555 			return NULL;
556 		tlen = hlen / 2;
557 		str = os_malloc(tlen + 1);
558 		if (str == NULL)
559 			return NULL;
560 		if (hexstr2bin(value, str, tlen)) {
561 			os_free(str);
562 			return NULL;
563 		}
564 		str[tlen] = '\0';
565 		*len = tlen;
566 		return (char *) str;
567 	}
568 }
569 
570 
571 int is_hex(const u8 *data, size_t len)
572 {
573 	size_t i;
574 
575 	for (i = 0; i < len; i++) {
576 		if (data[i] < 32 || data[i] >= 127)
577 			return 1;
578 	}
579 	return 0;
580 }
581 
582 
583 size_t merge_byte_arrays(u8 *res, size_t res_len,
584 			 const u8 *src1, size_t src1_len,
585 			 const u8 *src2, size_t src2_len)
586 {
587 	size_t len = 0;
588 
589 	os_memset(res, 0, res_len);
590 
591 	if (src1) {
592 		if (src1_len >= res_len) {
593 			os_memcpy(res, src1, res_len);
594 			return res_len;
595 		}
596 
597 		os_memcpy(res, src1, src1_len);
598 		len += src1_len;
599 	}
600 
601 	if (src2) {
602 		if (len + src2_len >= res_len) {
603 			os_memcpy(res + len, src2, res_len - len);
604 			return res_len;
605 		}
606 
607 		os_memcpy(res + len, src2, src2_len);
608 		len += src2_len;
609 	}
610 
611 	return len;
612 }
613