xref: /freebsd/contrib/wpa/src/utils/os_unix.c (revision 780fb4a2fa9a9aee5ac48a60b790f567c0dc13e9)
139beb93cSSam Leffler /*
2e28a4053SRui Paulo  * OS specific functions for UNIX/POSIX systems
3e28a4053SRui Paulo  * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
11f05cddf9SRui Paulo #include <time.h>
125b9c547cSRui Paulo #include <sys/wait.h>
13f05cddf9SRui Paulo 
14f05cddf9SRui Paulo #ifdef ANDROID
155b9c547cSRui Paulo #include <sys/capability.h>
165b9c547cSRui Paulo #include <sys/prctl.h>
17f05cddf9SRui Paulo #include <private/android_filesystem_config.h>
18f05cddf9SRui Paulo #endif /* ANDROID */
19f05cddf9SRui Paulo 
20325151a3SRui Paulo #ifdef __MACH__
21325151a3SRui Paulo #include <CoreServices/CoreServices.h>
22325151a3SRui Paulo #include <mach/mach.h>
23325151a3SRui Paulo #include <mach/mach_time.h>
24325151a3SRui Paulo #endif /* __MACH__ */
25325151a3SRui Paulo 
2639beb93cSSam Leffler #include "os.h"
275b9c547cSRui Paulo #include "common.h"
2839beb93cSSam Leffler 
29e28a4053SRui Paulo #ifdef WPA_TRACE
30e28a4053SRui Paulo 
31e28a4053SRui Paulo #include "wpa_debug.h"
32e28a4053SRui Paulo #include "trace.h"
33f05cddf9SRui Paulo #include "list.h"
34e28a4053SRui Paulo 
355b9c547cSRui Paulo static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
36e28a4053SRui Paulo 
37e28a4053SRui Paulo #define ALLOC_MAGIC 0xa84ef1b2
38e28a4053SRui Paulo #define FREED_MAGIC 0x67fd487a
39e28a4053SRui Paulo 
40e28a4053SRui Paulo struct os_alloc_trace {
41e28a4053SRui Paulo 	unsigned int magic;
42e28a4053SRui Paulo 	struct dl_list list;
43e28a4053SRui Paulo 	size_t len;
44e28a4053SRui Paulo 	WPA_TRACE_INFO
45325151a3SRui Paulo } __attribute__((aligned(16)));
46e28a4053SRui Paulo 
47e28a4053SRui Paulo #endif /* WPA_TRACE */
48e28a4053SRui Paulo 
49e28a4053SRui Paulo 
5039beb93cSSam Leffler void os_sleep(os_time_t sec, os_time_t usec)
5139beb93cSSam Leffler {
5239beb93cSSam Leffler 	if (sec)
5339beb93cSSam Leffler 		sleep(sec);
5439beb93cSSam Leffler 	if (usec)
5539beb93cSSam Leffler 		usleep(usec);
5639beb93cSSam Leffler }
5739beb93cSSam Leffler 
5839beb93cSSam Leffler 
5939beb93cSSam Leffler int os_get_time(struct os_time *t)
6039beb93cSSam Leffler {
6139beb93cSSam Leffler 	int res;
6239beb93cSSam Leffler 	struct timeval tv;
6339beb93cSSam Leffler 	res = gettimeofday(&tv, NULL);
6439beb93cSSam Leffler 	t->sec = tv.tv_sec;
6539beb93cSSam Leffler 	t->usec = tv.tv_usec;
6639beb93cSSam Leffler 	return res;
6739beb93cSSam Leffler }
6839beb93cSSam Leffler 
6939beb93cSSam Leffler 
705b9c547cSRui Paulo int os_get_reltime(struct os_reltime *t)
715b9c547cSRui Paulo {
72325151a3SRui Paulo #ifndef __MACH__
735b9c547cSRui Paulo #if defined(CLOCK_BOOTTIME)
745b9c547cSRui Paulo 	static clockid_t clock_id = CLOCK_BOOTTIME;
755b9c547cSRui Paulo #elif defined(CLOCK_MONOTONIC)
765b9c547cSRui Paulo 	static clockid_t clock_id = CLOCK_MONOTONIC;
775b9c547cSRui Paulo #else
785b9c547cSRui Paulo 	static clockid_t clock_id = CLOCK_REALTIME;
795b9c547cSRui Paulo #endif
805b9c547cSRui Paulo 	struct timespec ts;
815b9c547cSRui Paulo 	int res;
825b9c547cSRui Paulo 
835b9c547cSRui Paulo 	while (1) {
845b9c547cSRui Paulo 		res = clock_gettime(clock_id, &ts);
855b9c547cSRui Paulo 		if (res == 0) {
865b9c547cSRui Paulo 			t->sec = ts.tv_sec;
875b9c547cSRui Paulo 			t->usec = ts.tv_nsec / 1000;
885b9c547cSRui Paulo 			return 0;
895b9c547cSRui Paulo 		}
905b9c547cSRui Paulo 		switch (clock_id) {
915b9c547cSRui Paulo #ifdef CLOCK_BOOTTIME
925b9c547cSRui Paulo 		case CLOCK_BOOTTIME:
935b9c547cSRui Paulo 			clock_id = CLOCK_MONOTONIC;
945b9c547cSRui Paulo 			break;
955b9c547cSRui Paulo #endif
965b9c547cSRui Paulo #ifdef CLOCK_MONOTONIC
975b9c547cSRui Paulo 		case CLOCK_MONOTONIC:
985b9c547cSRui Paulo 			clock_id = CLOCK_REALTIME;
995b9c547cSRui Paulo 			break;
1005b9c547cSRui Paulo #endif
1015b9c547cSRui Paulo 		case CLOCK_REALTIME:
1025b9c547cSRui Paulo 			return -1;
1035b9c547cSRui Paulo 		}
1045b9c547cSRui Paulo 	}
105325151a3SRui Paulo #else /* __MACH__ */
106325151a3SRui Paulo 	uint64_t abstime, nano;
107325151a3SRui Paulo 	static mach_timebase_info_data_t info = { 0, 0 };
108325151a3SRui Paulo 
109325151a3SRui Paulo 	if (!info.denom) {
110325151a3SRui Paulo 		if (mach_timebase_info(&info) != KERN_SUCCESS)
111325151a3SRui Paulo 			return -1;
112325151a3SRui Paulo 	}
113325151a3SRui Paulo 
114325151a3SRui Paulo 	abstime = mach_absolute_time();
115325151a3SRui Paulo 	nano = (abstime * info.numer) / info.denom;
116325151a3SRui Paulo 
117325151a3SRui Paulo 	t->sec = nano / NSEC_PER_SEC;
118325151a3SRui Paulo 	t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC;
119325151a3SRui Paulo 
120325151a3SRui Paulo 	return 0;
121325151a3SRui Paulo #endif /* __MACH__ */
1225b9c547cSRui Paulo }
1235b9c547cSRui Paulo 
1245b9c547cSRui Paulo 
12539beb93cSSam Leffler int os_mktime(int year, int month, int day, int hour, int min, int sec,
12639beb93cSSam Leffler 	      os_time_t *t)
12739beb93cSSam Leffler {
12839beb93cSSam Leffler 	struct tm tm, *tm1;
12939beb93cSSam Leffler 	time_t t_local, t1, t2;
13039beb93cSSam Leffler 	os_time_t tz_offset;
13139beb93cSSam Leffler 
13239beb93cSSam Leffler 	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
13339beb93cSSam Leffler 	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
13439beb93cSSam Leffler 	    sec > 60)
13539beb93cSSam Leffler 		return -1;
13639beb93cSSam Leffler 
13739beb93cSSam Leffler 	memset(&tm, 0, sizeof(tm));
13839beb93cSSam Leffler 	tm.tm_year = year - 1900;
13939beb93cSSam Leffler 	tm.tm_mon = month - 1;
14039beb93cSSam Leffler 	tm.tm_mday = day;
14139beb93cSSam Leffler 	tm.tm_hour = hour;
14239beb93cSSam Leffler 	tm.tm_min = min;
14339beb93cSSam Leffler 	tm.tm_sec = sec;
14439beb93cSSam Leffler 
14539beb93cSSam Leffler 	t_local = mktime(&tm);
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 	/* figure out offset to UTC */
14839beb93cSSam Leffler 	tm1 = localtime(&t_local);
14939beb93cSSam Leffler 	if (tm1) {
15039beb93cSSam Leffler 		t1 = mktime(tm1);
15139beb93cSSam Leffler 		tm1 = gmtime(&t_local);
15239beb93cSSam Leffler 		if (tm1) {
15339beb93cSSam Leffler 			t2 = mktime(tm1);
15439beb93cSSam Leffler 			tz_offset = t2 - t1;
15539beb93cSSam Leffler 		} else
15639beb93cSSam Leffler 			tz_offset = 0;
15739beb93cSSam Leffler 	} else
15839beb93cSSam Leffler 		tz_offset = 0;
15939beb93cSSam Leffler 
16039beb93cSSam Leffler 	*t = (os_time_t) t_local - tz_offset;
16139beb93cSSam Leffler 	return 0;
16239beb93cSSam Leffler }
16339beb93cSSam Leffler 
16439beb93cSSam Leffler 
165f05cddf9SRui Paulo int os_gmtime(os_time_t t, struct os_tm *tm)
166f05cddf9SRui Paulo {
167f05cddf9SRui Paulo 	struct tm *tm2;
168f05cddf9SRui Paulo 	time_t t2 = t;
169f05cddf9SRui Paulo 
170f05cddf9SRui Paulo 	tm2 = gmtime(&t2);
171f05cddf9SRui Paulo 	if (tm2 == NULL)
172f05cddf9SRui Paulo 		return -1;
173f05cddf9SRui Paulo 	tm->sec = tm2->tm_sec;
174f05cddf9SRui Paulo 	tm->min = tm2->tm_min;
175f05cddf9SRui Paulo 	tm->hour = tm2->tm_hour;
176f05cddf9SRui Paulo 	tm->day = tm2->tm_mday;
177f05cddf9SRui Paulo 	tm->month = tm2->tm_mon + 1;
178f05cddf9SRui Paulo 	tm->year = tm2->tm_year + 1900;
179f05cddf9SRui Paulo 	return 0;
180f05cddf9SRui Paulo }
181f05cddf9SRui Paulo 
182f05cddf9SRui Paulo 
18339beb93cSSam Leffler #ifdef __APPLE__
18439beb93cSSam Leffler #include <fcntl.h>
18539beb93cSSam Leffler static int os_daemon(int nochdir, int noclose)
18639beb93cSSam Leffler {
18739beb93cSSam Leffler 	int devnull;
18839beb93cSSam Leffler 
18939beb93cSSam Leffler 	if (chdir("/") < 0)
19039beb93cSSam Leffler 		return -1;
19139beb93cSSam Leffler 
19239beb93cSSam Leffler 	devnull = open("/dev/null", O_RDWR);
19339beb93cSSam Leffler 	if (devnull < 0)
19439beb93cSSam Leffler 		return -1;
19539beb93cSSam Leffler 
19639beb93cSSam Leffler 	if (dup2(devnull, STDIN_FILENO) < 0) {
19739beb93cSSam Leffler 		close(devnull);
19839beb93cSSam Leffler 		return -1;
19939beb93cSSam Leffler 	}
20039beb93cSSam Leffler 
20139beb93cSSam Leffler 	if (dup2(devnull, STDOUT_FILENO) < 0) {
20239beb93cSSam Leffler 		close(devnull);
20339beb93cSSam Leffler 		return -1;
20439beb93cSSam Leffler 	}
20539beb93cSSam Leffler 
20639beb93cSSam Leffler 	if (dup2(devnull, STDERR_FILENO) < 0) {
20739beb93cSSam Leffler 		close(devnull);
20839beb93cSSam Leffler 		return -1;
20939beb93cSSam Leffler 	}
21039beb93cSSam Leffler 
21139beb93cSSam Leffler 	return 0;
21239beb93cSSam Leffler }
21339beb93cSSam Leffler #else /* __APPLE__ */
21439beb93cSSam Leffler #define os_daemon daemon
21539beb93cSSam Leffler #endif /* __APPLE__ */
21639beb93cSSam Leffler 
21739beb93cSSam Leffler 
218a061720cSJohn-Mark Gurney #ifdef __FreeBSD__
219a061720cSJohn-Mark Gurney #include <err.h>
220a061720cSJohn-Mark Gurney #include <libutil.h>
221a061720cSJohn-Mark Gurney #include <stdint.h>
222a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */
223a061720cSJohn-Mark Gurney 
22439beb93cSSam Leffler int os_daemonize(const char *pid_file)
22539beb93cSSam Leffler {
226f05cddf9SRui Paulo #if defined(__uClinux__) || defined(__sun__)
22739beb93cSSam Leffler 	return -1;
228f05cddf9SRui Paulo #else /* defined(__uClinux__) || defined(__sun__) */
229a061720cSJohn-Mark Gurney #ifdef __FreeBSD__
230a061720cSJohn-Mark Gurney 	pid_t otherpid;
231a061720cSJohn-Mark Gurney 	struct pidfh *pfh;
232a061720cSJohn-Mark Gurney 
233a061720cSJohn-Mark Gurney 	pfh = pidfile_open(pid_file, 0600, &otherpid);
234a061720cSJohn-Mark Gurney 	if (pfh == NULL) {
235a061720cSJohn-Mark Gurney 		if (errno == EEXIST) {
236a061720cSJohn-Mark Gurney 			errx(1, "Daemon already running, pid: %jd.",
237a061720cSJohn-Mark Gurney 			    (intmax_t)otherpid);
238a061720cSJohn-Mark Gurney 		}
239a061720cSJohn-Mark Gurney 		warn("Cannot open or create pidfile.");
240a061720cSJohn-Mark Gurney 	}
241a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */
242a061720cSJohn-Mark Gurney 
24339beb93cSSam Leffler 	if (os_daemon(0, 0)) {
24439beb93cSSam Leffler 		perror("daemon");
245a061720cSJohn-Mark Gurney #ifdef __FreeBSD__
246a061720cSJohn-Mark Gurney 		pidfile_remove(pfh);
247a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */
24839beb93cSSam Leffler 		return -1;
24939beb93cSSam Leffler 	}
25039beb93cSSam Leffler 
251a061720cSJohn-Mark Gurney #ifndef __FreeBSD__
25239beb93cSSam Leffler 	if (pid_file) {
25339beb93cSSam Leffler 		FILE *f = fopen(pid_file, "w");
25439beb93cSSam Leffler 		if (f) {
25539beb93cSSam Leffler 			fprintf(f, "%u\n", getpid());
25639beb93cSSam Leffler 			fclose(f);
25739beb93cSSam Leffler 		}
25839beb93cSSam Leffler 	}
259a061720cSJohn-Mark Gurney #else /* __FreeBSD__ */
260a061720cSJohn-Mark Gurney 	pidfile_write(pfh);
261a061720cSJohn-Mark Gurney #endif /* __FreeBSD__ */
26239beb93cSSam Leffler 
26339beb93cSSam Leffler 	return -0;
264f05cddf9SRui Paulo #endif /* defined(__uClinux__) || defined(__sun__) */
26539beb93cSSam Leffler }
26639beb93cSSam Leffler 
26739beb93cSSam Leffler 
26839beb93cSSam Leffler void os_daemonize_terminate(const char *pid_file)
26939beb93cSSam Leffler {
27039beb93cSSam Leffler 	if (pid_file)
27139beb93cSSam Leffler 		unlink(pid_file);
27239beb93cSSam Leffler }
27339beb93cSSam Leffler 
27439beb93cSSam Leffler 
27539beb93cSSam Leffler int os_get_random(unsigned char *buf, size_t len)
27639beb93cSSam Leffler {
27739beb93cSSam Leffler 	FILE *f;
27839beb93cSSam Leffler 	size_t rc;
27939beb93cSSam Leffler 
280325151a3SRui Paulo 	if (TEST_FAIL())
281325151a3SRui Paulo 		return -1;
282325151a3SRui Paulo 
28339beb93cSSam Leffler 	f = fopen("/dev/urandom", "rb");
28439beb93cSSam Leffler 	if (f == NULL) {
28539beb93cSSam Leffler 		printf("Could not open /dev/urandom.\n");
28639beb93cSSam Leffler 		return -1;
28739beb93cSSam Leffler 	}
28839beb93cSSam Leffler 
28939beb93cSSam Leffler 	rc = fread(buf, 1, len, f);
29039beb93cSSam Leffler 	fclose(f);
29139beb93cSSam Leffler 
29239beb93cSSam Leffler 	return rc != len ? -1 : 0;
29339beb93cSSam Leffler }
29439beb93cSSam Leffler 
29539beb93cSSam Leffler 
29639beb93cSSam Leffler unsigned long os_random(void)
29739beb93cSSam Leffler {
29839beb93cSSam Leffler 	return random();
29939beb93cSSam Leffler }
30039beb93cSSam Leffler 
30139beb93cSSam Leffler 
30239beb93cSSam Leffler char * os_rel2abs_path(const char *rel_path)
30339beb93cSSam Leffler {
30439beb93cSSam Leffler 	char *buf = NULL, *cwd, *ret;
30539beb93cSSam Leffler 	size_t len = 128, cwd_len, rel_len, ret_len;
30639beb93cSSam Leffler 	int last_errno;
30739beb93cSSam Leffler 
3085b9c547cSRui Paulo 	if (!rel_path)
3095b9c547cSRui Paulo 		return NULL;
3105b9c547cSRui Paulo 
31139beb93cSSam Leffler 	if (rel_path[0] == '/')
312e28a4053SRui Paulo 		return os_strdup(rel_path);
31339beb93cSSam Leffler 
31439beb93cSSam Leffler 	for (;;) {
315e28a4053SRui Paulo 		buf = os_malloc(len);
31639beb93cSSam Leffler 		if (buf == NULL)
31739beb93cSSam Leffler 			return NULL;
31839beb93cSSam Leffler 		cwd = getcwd(buf, len);
31939beb93cSSam Leffler 		if (cwd == NULL) {
32039beb93cSSam Leffler 			last_errno = errno;
321e28a4053SRui Paulo 			os_free(buf);
32239beb93cSSam Leffler 			if (last_errno != ERANGE)
32339beb93cSSam Leffler 				return NULL;
32439beb93cSSam Leffler 			len *= 2;
32539beb93cSSam Leffler 			if (len > 2000)
32639beb93cSSam Leffler 				return NULL;
32739beb93cSSam Leffler 		} else {
32839beb93cSSam Leffler 			buf[len - 1] = '\0';
32939beb93cSSam Leffler 			break;
33039beb93cSSam Leffler 		}
33139beb93cSSam Leffler 	}
33239beb93cSSam Leffler 
333e28a4053SRui Paulo 	cwd_len = os_strlen(cwd);
334e28a4053SRui Paulo 	rel_len = os_strlen(rel_path);
33539beb93cSSam Leffler 	ret_len = cwd_len + 1 + rel_len + 1;
336e28a4053SRui Paulo 	ret = os_malloc(ret_len);
33739beb93cSSam Leffler 	if (ret) {
338e28a4053SRui Paulo 		os_memcpy(ret, cwd, cwd_len);
33939beb93cSSam Leffler 		ret[cwd_len] = '/';
340e28a4053SRui Paulo 		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
34139beb93cSSam Leffler 		ret[ret_len - 1] = '\0';
34239beb93cSSam Leffler 	}
343e28a4053SRui Paulo 	os_free(buf);
34439beb93cSSam Leffler 	return ret;
34539beb93cSSam Leffler }
34639beb93cSSam Leffler 
34739beb93cSSam Leffler 
34839beb93cSSam Leffler int os_program_init(void)
34939beb93cSSam Leffler {
350f05cddf9SRui Paulo #ifdef ANDROID
351f05cddf9SRui Paulo 	/*
352f05cddf9SRui Paulo 	 * We ignore errors here since errors are normal if we
353f05cddf9SRui Paulo 	 * are already running as non-root.
354f05cddf9SRui Paulo 	 */
3555b9c547cSRui Paulo #ifdef ANDROID_SETGROUPS_OVERRIDE
3565b9c547cSRui Paulo 	gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
3575b9c547cSRui Paulo #else /* ANDROID_SETGROUPS_OVERRIDE */
358f05cddf9SRui Paulo 	gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
3595b9c547cSRui Paulo #endif /* ANDROID_SETGROUPS_OVERRIDE */
360f05cddf9SRui Paulo 	struct __user_cap_header_struct header;
361f05cddf9SRui Paulo 	struct __user_cap_data_struct cap;
362f05cddf9SRui Paulo 
3635b9c547cSRui Paulo 	setgroups(ARRAY_SIZE(groups), groups);
364f05cddf9SRui Paulo 
365f05cddf9SRui Paulo 	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
366f05cddf9SRui Paulo 
367f05cddf9SRui Paulo 	setgid(AID_WIFI);
368f05cddf9SRui Paulo 	setuid(AID_WIFI);
369f05cddf9SRui Paulo 
370f05cddf9SRui Paulo 	header.version = _LINUX_CAPABILITY_VERSION;
371f05cddf9SRui Paulo 	header.pid = 0;
372f05cddf9SRui Paulo 	cap.effective = cap.permitted =
373f05cddf9SRui Paulo 		(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
374f05cddf9SRui Paulo 	cap.inheritable = 0;
375f05cddf9SRui Paulo 	capset(&header, &cap);
376f05cddf9SRui Paulo #endif /* ANDROID */
377f05cddf9SRui Paulo 
37839beb93cSSam Leffler 	return 0;
37939beb93cSSam Leffler }
38039beb93cSSam Leffler 
38139beb93cSSam Leffler 
38239beb93cSSam Leffler void os_program_deinit(void)
38339beb93cSSam Leffler {
384e28a4053SRui Paulo #ifdef WPA_TRACE
385e28a4053SRui Paulo 	struct os_alloc_trace *a;
386e28a4053SRui Paulo 	unsigned long total = 0;
387e28a4053SRui Paulo 	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
388e28a4053SRui Paulo 		total += a->len;
389e28a4053SRui Paulo 		if (a->magic != ALLOC_MAGIC) {
390e28a4053SRui Paulo 			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
391e28a4053SRui Paulo 				   "len %lu",
392e28a4053SRui Paulo 				   a, a->magic, (unsigned long) a->len);
393e28a4053SRui Paulo 			continue;
394e28a4053SRui Paulo 		}
395e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
396e28a4053SRui Paulo 			   a, (unsigned long) a->len);
397e28a4053SRui Paulo 		wpa_trace_dump("memleak", a);
398e28a4053SRui Paulo 	}
399e28a4053SRui Paulo 	if (total)
400e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
401e28a4053SRui Paulo 			   (unsigned long) total);
402*780fb4a2SCy Schubert 	wpa_trace_deinit();
403e28a4053SRui Paulo #endif /* WPA_TRACE */
40439beb93cSSam Leffler }
40539beb93cSSam Leffler 
40639beb93cSSam Leffler 
40739beb93cSSam Leffler int os_setenv(const char *name, const char *value, int overwrite)
40839beb93cSSam Leffler {
40939beb93cSSam Leffler 	return setenv(name, value, overwrite);
41039beb93cSSam Leffler }
41139beb93cSSam Leffler 
41239beb93cSSam Leffler 
41339beb93cSSam Leffler int os_unsetenv(const char *name)
41439beb93cSSam Leffler {
4153157ba21SRui Paulo #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
4163157ba21SRui Paulo     defined(__OpenBSD__)
41739beb93cSSam Leffler 	unsetenv(name);
41839beb93cSSam Leffler 	return 0;
41939beb93cSSam Leffler #else
42039beb93cSSam Leffler 	return unsetenv(name);
42139beb93cSSam Leffler #endif
42239beb93cSSam Leffler }
42339beb93cSSam Leffler 
42439beb93cSSam Leffler 
42539beb93cSSam Leffler char * os_readfile(const char *name, size_t *len)
42639beb93cSSam Leffler {
42739beb93cSSam Leffler 	FILE *f;
42839beb93cSSam Leffler 	char *buf;
429f05cddf9SRui Paulo 	long pos;
43039beb93cSSam Leffler 
43139beb93cSSam Leffler 	f = fopen(name, "rb");
43239beb93cSSam Leffler 	if (f == NULL)
43339beb93cSSam Leffler 		return NULL;
43439beb93cSSam Leffler 
435f05cddf9SRui Paulo 	if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
436f05cddf9SRui Paulo 		fclose(f);
437f05cddf9SRui Paulo 		return NULL;
438f05cddf9SRui Paulo 	}
439f05cddf9SRui Paulo 	*len = pos;
440f05cddf9SRui Paulo 	if (fseek(f, 0, SEEK_SET) < 0) {
441f05cddf9SRui Paulo 		fclose(f);
442f05cddf9SRui Paulo 		return NULL;
443f05cddf9SRui Paulo 	}
44439beb93cSSam Leffler 
445e28a4053SRui Paulo 	buf = os_malloc(*len);
44639beb93cSSam Leffler 	if (buf == NULL) {
44739beb93cSSam Leffler 		fclose(f);
44839beb93cSSam Leffler 		return NULL;
44939beb93cSSam Leffler 	}
45039beb93cSSam Leffler 
45139beb93cSSam Leffler 	if (fread(buf, 1, *len, f) != *len) {
45239beb93cSSam Leffler 		fclose(f);
453e28a4053SRui Paulo 		os_free(buf);
45439beb93cSSam Leffler 		return NULL;
45539beb93cSSam Leffler 	}
45639beb93cSSam Leffler 
45739beb93cSSam Leffler 	fclose(f);
45839beb93cSSam Leffler 
45939beb93cSSam Leffler 	return buf;
46039beb93cSSam Leffler }
46139beb93cSSam Leffler 
46239beb93cSSam Leffler 
4635b9c547cSRui Paulo int os_file_exists(const char *fname)
4645b9c547cSRui Paulo {
465*780fb4a2SCy Schubert 	return access(fname, F_OK) == 0;
4665b9c547cSRui Paulo }
4675b9c547cSRui Paulo 
4685b9c547cSRui Paulo 
469325151a3SRui Paulo int os_fdatasync(FILE *stream)
470325151a3SRui Paulo {
471325151a3SRui Paulo 	if (!fflush(stream)) {
472325151a3SRui Paulo #ifdef __linux__
473325151a3SRui Paulo 		return fdatasync(fileno(stream));
474325151a3SRui Paulo #else /* !__linux__ */
475325151a3SRui Paulo #ifdef F_FULLFSYNC
476325151a3SRui Paulo 		/* OS X does not implement fdatasync(). */
477325151a3SRui Paulo 		return fcntl(fileno(stream), F_FULLFSYNC);
478325151a3SRui Paulo #else /* F_FULLFSYNC */
479325151a3SRui Paulo 		return fsync(fileno(stream));
480325151a3SRui Paulo #endif /* F_FULLFSYNC */
481325151a3SRui Paulo #endif /* __linux__ */
482325151a3SRui Paulo 	}
483325151a3SRui Paulo 
484325151a3SRui Paulo 	return -1;
485325151a3SRui Paulo }
486325151a3SRui Paulo 
487325151a3SRui Paulo 
488e28a4053SRui Paulo #ifndef WPA_TRACE
48939beb93cSSam Leffler void * os_zalloc(size_t size)
49039beb93cSSam Leffler {
49139beb93cSSam Leffler 	return calloc(1, size);
49239beb93cSSam Leffler }
493e28a4053SRui Paulo #endif /* WPA_TRACE */
49439beb93cSSam Leffler 
49539beb93cSSam Leffler 
49639beb93cSSam Leffler size_t os_strlcpy(char *dest, const char *src, size_t siz)
49739beb93cSSam Leffler {
49839beb93cSSam Leffler 	const char *s = src;
49939beb93cSSam Leffler 	size_t left = siz;
50039beb93cSSam Leffler 
50139beb93cSSam Leffler 	if (left) {
50239beb93cSSam Leffler 		/* Copy string up to the maximum size of the dest buffer */
50339beb93cSSam Leffler 		while (--left != 0) {
50439beb93cSSam Leffler 			if ((*dest++ = *s++) == '\0')
50539beb93cSSam Leffler 				break;
50639beb93cSSam Leffler 		}
50739beb93cSSam Leffler 	}
50839beb93cSSam Leffler 
50939beb93cSSam Leffler 	if (left == 0) {
51039beb93cSSam Leffler 		/* Not enough room for the string; force NUL-termination */
51139beb93cSSam Leffler 		if (siz != 0)
51239beb93cSSam Leffler 			*dest = '\0';
51339beb93cSSam Leffler 		while (*s++)
51439beb93cSSam Leffler 			; /* determine total src string length */
51539beb93cSSam Leffler 	}
51639beb93cSSam Leffler 
51739beb93cSSam Leffler 	return s - src - 1;
51839beb93cSSam Leffler }
519e28a4053SRui Paulo 
520e28a4053SRui Paulo 
5215b9c547cSRui Paulo int os_memcmp_const(const void *a, const void *b, size_t len)
5225b9c547cSRui Paulo {
5235b9c547cSRui Paulo 	const u8 *aa = a;
5245b9c547cSRui Paulo 	const u8 *bb = b;
5255b9c547cSRui Paulo 	size_t i;
5265b9c547cSRui Paulo 	u8 res;
5275b9c547cSRui Paulo 
5285b9c547cSRui Paulo 	for (res = 0, i = 0; i < len; i++)
5295b9c547cSRui Paulo 		res |= aa[i] ^ bb[i];
5305b9c547cSRui Paulo 
5315b9c547cSRui Paulo 	return res;
5325b9c547cSRui Paulo }
5335b9c547cSRui Paulo 
5345b9c547cSRui Paulo 
535e28a4053SRui Paulo #ifdef WPA_TRACE
536e28a4053SRui Paulo 
5375b9c547cSRui Paulo #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
5385b9c547cSRui Paulo char wpa_trace_fail_func[256] = { 0 };
5395b9c547cSRui Paulo unsigned int wpa_trace_fail_after;
5405b9c547cSRui Paulo 
5415b9c547cSRui Paulo static int testing_fail_alloc(void)
5425b9c547cSRui Paulo {
5435b9c547cSRui Paulo 	const char *func[WPA_TRACE_LEN];
5445b9c547cSRui Paulo 	size_t i, res, len;
5455b9c547cSRui Paulo 	char *pos, *next;
5465b9c547cSRui Paulo 	int match;
5475b9c547cSRui Paulo 
5485b9c547cSRui Paulo 	if (!wpa_trace_fail_after)
5495b9c547cSRui Paulo 		return 0;
5505b9c547cSRui Paulo 
5515b9c547cSRui Paulo 	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
5525b9c547cSRui Paulo 	i = 0;
5535b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], __func__) == 0)
5545b9c547cSRui Paulo 		i++;
5555b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_malloc") == 0)
5565b9c547cSRui Paulo 		i++;
5575b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
5585b9c547cSRui Paulo 		i++;
5595b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_calloc") == 0)
5605b9c547cSRui Paulo 		i++;
5615b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_realloc") == 0)
5625b9c547cSRui Paulo 		i++;
5635b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
5645b9c547cSRui Paulo 		i++;
5655b9c547cSRui Paulo 	if (i < res && os_strcmp(func[i], "os_strdup") == 0)
5665b9c547cSRui Paulo 		i++;
5675b9c547cSRui Paulo 
5685b9c547cSRui Paulo 	pos = wpa_trace_fail_func;
5695b9c547cSRui Paulo 
5705b9c547cSRui Paulo 	match = 0;
5715b9c547cSRui Paulo 	while (i < res) {
5725b9c547cSRui Paulo 		int allow_skip = 1;
5735b9c547cSRui Paulo 		int maybe = 0;
5745b9c547cSRui Paulo 
5755b9c547cSRui Paulo 		if (*pos == '=') {
5765b9c547cSRui Paulo 			allow_skip = 0;
5775b9c547cSRui Paulo 			pos++;
5785b9c547cSRui Paulo 		} else if (*pos == '?') {
5795b9c547cSRui Paulo 			maybe = 1;
5805b9c547cSRui Paulo 			pos++;
5815b9c547cSRui Paulo 		}
5825b9c547cSRui Paulo 		next = os_strchr(pos, ';');
5835b9c547cSRui Paulo 		if (next)
5845b9c547cSRui Paulo 			len = next - pos;
5855b9c547cSRui Paulo 		else
5865b9c547cSRui Paulo 			len = os_strlen(pos);
5875b9c547cSRui Paulo 		if (os_memcmp(pos, func[i], len) != 0) {
5885b9c547cSRui Paulo 			if (maybe && next) {
5895b9c547cSRui Paulo 				pos = next + 1;
5905b9c547cSRui Paulo 				continue;
5915b9c547cSRui Paulo 			}
5925b9c547cSRui Paulo 			if (allow_skip) {
5935b9c547cSRui Paulo 				i++;
5945b9c547cSRui Paulo 				continue;
5955b9c547cSRui Paulo 			}
5965b9c547cSRui Paulo 			return 0;
5975b9c547cSRui Paulo 		}
5985b9c547cSRui Paulo 		if (!next) {
5995b9c547cSRui Paulo 			match = 1;
6005b9c547cSRui Paulo 			break;
6015b9c547cSRui Paulo 		}
6025b9c547cSRui Paulo 		pos = next + 1;
6035b9c547cSRui Paulo 		i++;
6045b9c547cSRui Paulo 	}
6055b9c547cSRui Paulo 	if (!match)
6065b9c547cSRui Paulo 		return 0;
6075b9c547cSRui Paulo 
6085b9c547cSRui Paulo 	wpa_trace_fail_after--;
6095b9c547cSRui Paulo 	if (wpa_trace_fail_after == 0) {
6105b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
6115b9c547cSRui Paulo 			   wpa_trace_fail_func);
6125b9c547cSRui Paulo 		for (i = 0; i < res; i++)
6135b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
6145b9c547cSRui Paulo 				   (int) i, func[i]);
6155b9c547cSRui Paulo 		return 1;
6165b9c547cSRui Paulo 	}
6175b9c547cSRui Paulo 
6185b9c547cSRui Paulo 	return 0;
6195b9c547cSRui Paulo }
6205b9c547cSRui Paulo 
621325151a3SRui Paulo 
622325151a3SRui Paulo char wpa_trace_test_fail_func[256] = { 0 };
623325151a3SRui Paulo unsigned int wpa_trace_test_fail_after;
624325151a3SRui Paulo 
625325151a3SRui Paulo int testing_test_fail(void)
626325151a3SRui Paulo {
627325151a3SRui Paulo 	const char *func[WPA_TRACE_LEN];
628325151a3SRui Paulo 	size_t i, res, len;
629325151a3SRui Paulo 	char *pos, *next;
630325151a3SRui Paulo 	int match;
631325151a3SRui Paulo 
632325151a3SRui Paulo 	if (!wpa_trace_test_fail_after)
633325151a3SRui Paulo 		return 0;
634325151a3SRui Paulo 
635325151a3SRui Paulo 	res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
636325151a3SRui Paulo 	i = 0;
637325151a3SRui Paulo 	if (i < res && os_strcmp(func[i], __func__) == 0)
638325151a3SRui Paulo 		i++;
639325151a3SRui Paulo 
640325151a3SRui Paulo 	pos = wpa_trace_test_fail_func;
641325151a3SRui Paulo 
642325151a3SRui Paulo 	match = 0;
643325151a3SRui Paulo 	while (i < res) {
644325151a3SRui Paulo 		int allow_skip = 1;
645325151a3SRui Paulo 		int maybe = 0;
646325151a3SRui Paulo 
647325151a3SRui Paulo 		if (*pos == '=') {
648325151a3SRui Paulo 			allow_skip = 0;
649325151a3SRui Paulo 			pos++;
650325151a3SRui Paulo 		} else if (*pos == '?') {
651325151a3SRui Paulo 			maybe = 1;
652325151a3SRui Paulo 			pos++;
653325151a3SRui Paulo 		}
654325151a3SRui Paulo 		next = os_strchr(pos, ';');
655325151a3SRui Paulo 		if (next)
656325151a3SRui Paulo 			len = next - pos;
657325151a3SRui Paulo 		else
658325151a3SRui Paulo 			len = os_strlen(pos);
659325151a3SRui Paulo 		if (os_memcmp(pos, func[i], len) != 0) {
660325151a3SRui Paulo 			if (maybe && next) {
661325151a3SRui Paulo 				pos = next + 1;
662325151a3SRui Paulo 				continue;
663325151a3SRui Paulo 			}
664325151a3SRui Paulo 			if (allow_skip) {
665325151a3SRui Paulo 				i++;
666325151a3SRui Paulo 				continue;
667325151a3SRui Paulo 			}
668325151a3SRui Paulo 			return 0;
669325151a3SRui Paulo 		}
670325151a3SRui Paulo 		if (!next) {
671325151a3SRui Paulo 			match = 1;
672325151a3SRui Paulo 			break;
673325151a3SRui Paulo 		}
674325151a3SRui Paulo 		pos = next + 1;
675325151a3SRui Paulo 		i++;
676325151a3SRui Paulo 	}
677325151a3SRui Paulo 	if (!match)
678325151a3SRui Paulo 		return 0;
679325151a3SRui Paulo 
680325151a3SRui Paulo 	wpa_trace_test_fail_after--;
681325151a3SRui Paulo 	if (wpa_trace_test_fail_after == 0) {
682325151a3SRui Paulo 		wpa_printf(MSG_INFO, "TESTING: fail at %s",
683325151a3SRui Paulo 			   wpa_trace_test_fail_func);
684325151a3SRui Paulo 		for (i = 0; i < res; i++)
685325151a3SRui Paulo 			wpa_printf(MSG_INFO, "backtrace[%d] = %s",
686325151a3SRui Paulo 				   (int) i, func[i]);
687325151a3SRui Paulo 		return 1;
688325151a3SRui Paulo 	}
689325151a3SRui Paulo 
690325151a3SRui Paulo 	return 0;
691325151a3SRui Paulo }
692325151a3SRui Paulo 
6935b9c547cSRui Paulo #else
6945b9c547cSRui Paulo 
6955b9c547cSRui Paulo static inline int testing_fail_alloc(void)
6965b9c547cSRui Paulo {
6975b9c547cSRui Paulo 	return 0;
6985b9c547cSRui Paulo }
6995b9c547cSRui Paulo #endif
7005b9c547cSRui Paulo 
701e28a4053SRui Paulo void * os_malloc(size_t size)
702e28a4053SRui Paulo {
703e28a4053SRui Paulo 	struct os_alloc_trace *a;
7045b9c547cSRui Paulo 
7055b9c547cSRui Paulo 	if (testing_fail_alloc())
7065b9c547cSRui Paulo 		return NULL;
7075b9c547cSRui Paulo 
708e28a4053SRui Paulo 	a = malloc(sizeof(*a) + size);
709e28a4053SRui Paulo 	if (a == NULL)
710e28a4053SRui Paulo 		return NULL;
711e28a4053SRui Paulo 	a->magic = ALLOC_MAGIC;
712e28a4053SRui Paulo 	dl_list_add(&alloc_list, &a->list);
713e28a4053SRui Paulo 	a->len = size;
714e28a4053SRui Paulo 	wpa_trace_record(a);
715e28a4053SRui Paulo 	return a + 1;
716e28a4053SRui Paulo }
717e28a4053SRui Paulo 
718e28a4053SRui Paulo 
719e28a4053SRui Paulo void * os_realloc(void *ptr, size_t size)
720e28a4053SRui Paulo {
721e28a4053SRui Paulo 	struct os_alloc_trace *a;
722e28a4053SRui Paulo 	size_t copy_len;
723e28a4053SRui Paulo 	void *n;
724e28a4053SRui Paulo 
725e28a4053SRui Paulo 	if (ptr == NULL)
726e28a4053SRui Paulo 		return os_malloc(size);
727e28a4053SRui Paulo 
728e28a4053SRui Paulo 	a = (struct os_alloc_trace *) ptr - 1;
729e28a4053SRui Paulo 	if (a->magic != ALLOC_MAGIC) {
730e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
731e28a4053SRui Paulo 			   a, a->magic,
732e28a4053SRui Paulo 			   a->magic == FREED_MAGIC ? " (already freed)" : "");
733e28a4053SRui Paulo 		wpa_trace_show("Invalid os_realloc() call");
734e28a4053SRui Paulo 		abort();
735e28a4053SRui Paulo 	}
736e28a4053SRui Paulo 	n = os_malloc(size);
737e28a4053SRui Paulo 	if (n == NULL)
738e28a4053SRui Paulo 		return NULL;
739e28a4053SRui Paulo 	copy_len = a->len;
740e28a4053SRui Paulo 	if (copy_len > size)
741e28a4053SRui Paulo 		copy_len = size;
742e28a4053SRui Paulo 	os_memcpy(n, a + 1, copy_len);
743e28a4053SRui Paulo 	os_free(ptr);
744e28a4053SRui Paulo 	return n;
745e28a4053SRui Paulo }
746e28a4053SRui Paulo 
747e28a4053SRui Paulo 
748e28a4053SRui Paulo void os_free(void *ptr)
749e28a4053SRui Paulo {
750e28a4053SRui Paulo 	struct os_alloc_trace *a;
751e28a4053SRui Paulo 
752e28a4053SRui Paulo 	if (ptr == NULL)
753e28a4053SRui Paulo 		return;
754e28a4053SRui Paulo 	a = (struct os_alloc_trace *) ptr - 1;
755e28a4053SRui Paulo 	if (a->magic != ALLOC_MAGIC) {
756e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
757e28a4053SRui Paulo 			   a, a->magic,
758e28a4053SRui Paulo 			   a->magic == FREED_MAGIC ? " (already freed)" : "");
759e28a4053SRui Paulo 		wpa_trace_show("Invalid os_free() call");
760e28a4053SRui Paulo 		abort();
761e28a4053SRui Paulo 	}
762e28a4053SRui Paulo 	dl_list_del(&a->list);
763e28a4053SRui Paulo 	a->magic = FREED_MAGIC;
764e28a4053SRui Paulo 
765e28a4053SRui Paulo 	wpa_trace_check_ref(ptr);
766e28a4053SRui Paulo 	free(a);
767e28a4053SRui Paulo }
768e28a4053SRui Paulo 
769e28a4053SRui Paulo 
770e28a4053SRui Paulo void * os_zalloc(size_t size)
771e28a4053SRui Paulo {
772e28a4053SRui Paulo 	void *ptr = os_malloc(size);
773e28a4053SRui Paulo 	if (ptr)
774e28a4053SRui Paulo 		os_memset(ptr, 0, size);
775e28a4053SRui Paulo 	return ptr;
776e28a4053SRui Paulo }
777e28a4053SRui Paulo 
778e28a4053SRui Paulo 
779e28a4053SRui Paulo char * os_strdup(const char *s)
780e28a4053SRui Paulo {
781e28a4053SRui Paulo 	size_t len;
782e28a4053SRui Paulo 	char *d;
783e28a4053SRui Paulo 	len = os_strlen(s);
784e28a4053SRui Paulo 	d = os_malloc(len + 1);
785e28a4053SRui Paulo 	if (d == NULL)
786e28a4053SRui Paulo 		return NULL;
787e28a4053SRui Paulo 	os_memcpy(d, s, len);
788e28a4053SRui Paulo 	d[len] = '\0';
789e28a4053SRui Paulo 	return d;
790e28a4053SRui Paulo }
791e28a4053SRui Paulo 
792e28a4053SRui Paulo #endif /* WPA_TRACE */
7935b9c547cSRui Paulo 
7945b9c547cSRui Paulo 
7955b9c547cSRui Paulo int os_exec(const char *program, const char *arg, int wait_completion)
7965b9c547cSRui Paulo {
7975b9c547cSRui Paulo 	pid_t pid;
7985b9c547cSRui Paulo 	int pid_status;
7995b9c547cSRui Paulo 
8005b9c547cSRui Paulo 	pid = fork();
8015b9c547cSRui Paulo 	if (pid < 0) {
8025b9c547cSRui Paulo 		perror("fork");
8035b9c547cSRui Paulo 		return -1;
8045b9c547cSRui Paulo 	}
8055b9c547cSRui Paulo 
8065b9c547cSRui Paulo 	if (pid == 0) {
8075b9c547cSRui Paulo 		/* run the external command in the child process */
8085b9c547cSRui Paulo 		const int MAX_ARG = 30;
8095b9c547cSRui Paulo 		char *_program, *_arg, *pos;
8105b9c547cSRui Paulo 		char *argv[MAX_ARG + 1];
8115b9c547cSRui Paulo 		int i;
8125b9c547cSRui Paulo 
8135b9c547cSRui Paulo 		_program = os_strdup(program);
8145b9c547cSRui Paulo 		_arg = os_strdup(arg);
8155b9c547cSRui Paulo 
8165b9c547cSRui Paulo 		argv[0] = _program;
8175b9c547cSRui Paulo 
8185b9c547cSRui Paulo 		i = 1;
8195b9c547cSRui Paulo 		pos = _arg;
8205b9c547cSRui Paulo 		while (i < MAX_ARG && pos && *pos) {
8215b9c547cSRui Paulo 			while (*pos == ' ')
8225b9c547cSRui Paulo 				pos++;
8235b9c547cSRui Paulo 			if (*pos == '\0')
8245b9c547cSRui Paulo 				break;
8255b9c547cSRui Paulo 			argv[i++] = pos;
8265b9c547cSRui Paulo 			pos = os_strchr(pos, ' ');
8275b9c547cSRui Paulo 			if (pos)
8285b9c547cSRui Paulo 				*pos++ = '\0';
8295b9c547cSRui Paulo 		}
8305b9c547cSRui Paulo 		argv[i] = NULL;
8315b9c547cSRui Paulo 
8325b9c547cSRui Paulo 		execv(program, argv);
8335b9c547cSRui Paulo 		perror("execv");
8345b9c547cSRui Paulo 		os_free(_program);
8355b9c547cSRui Paulo 		os_free(_arg);
8365b9c547cSRui Paulo 		exit(0);
8375b9c547cSRui Paulo 		return -1;
8385b9c547cSRui Paulo 	}
8395b9c547cSRui Paulo 
8405b9c547cSRui Paulo 	if (wait_completion) {
8415b9c547cSRui Paulo 		/* wait for the child process to complete in the parent */
8425b9c547cSRui Paulo 		waitpid(pid, &pid_status, 0);
8435b9c547cSRui Paulo 	}
8445b9c547cSRui Paulo 
8455b9c547cSRui Paulo 	return 0;
8465b9c547cSRui Paulo }
847