1/*
2 * wpa_supplicant/hostapd / OS specific functions for UNIX/POSIX systems
3 * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "os.h"
18
19#ifdef ANDROID
20#include <linux/capability.h>
21#include <linux/prctl.h>
22#include <private/android_filesystem_config.h>
23#endif
24
25void os_sleep(os_time_t sec, os_time_t usec)
26{
27	if (sec)
28		sleep(sec);
29	if (usec)
30		usleep(usec);
31}
32
33
34int os_get_time(struct os_time *t)
35{
36	int res;
37	struct timeval tv;
38	res = gettimeofday(&tv, NULL);
39	t->sec = tv.tv_sec;
40	t->usec = tv.tv_usec;
41	return res;
42}
43
44
45int os_mktime(int year, int month, int day, int hour, int min, int sec,
46	      os_time_t *t)
47{
48	struct tm tm, *tm1;
49	time_t t_local, t1, t2;
50	os_time_t tz_offset;
51
52	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
53	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
54	    sec > 60)
55		return -1;
56
57	memset(&tm, 0, sizeof(tm));
58	tm.tm_year = year - 1900;
59	tm.tm_mon = month - 1;
60	tm.tm_mday = day;
61	tm.tm_hour = hour;
62	tm.tm_min = min;
63	tm.tm_sec = sec;
64
65	t_local = mktime(&tm);
66
67	/* figure out offset to UTC */
68	tm1 = localtime(&t_local);
69	if (tm1) {
70		t1 = mktime(tm1);
71		tm1 = gmtime(&t_local);
72		if (tm1) {
73			t2 = mktime(tm1);
74			tz_offset = t2 - t1;
75		} else
76			tz_offset = 0;
77	} else
78		tz_offset = 0;
79
80	*t = (os_time_t) t_local - tz_offset;
81	return 0;
82}
83
84
85#ifdef __APPLE__
86#include <fcntl.h>
87static int os_daemon(int nochdir, int noclose)
88{
89	int devnull;
90
91	if (chdir("/") < 0)
92		return -1;
93
94	devnull = open("/dev/null", O_RDWR);
95	if (devnull < 0)
96		return -1;
97
98	if (dup2(devnull, STDIN_FILENO) < 0) {
99		close(devnull);
100		return -1;
101	}
102
103	if (dup2(devnull, STDOUT_FILENO) < 0) {
104		close(devnull);
105		return -1;
106	}
107
108	if (dup2(devnull, STDERR_FILENO) < 0) {
109		close(devnull);
110		return -1;
111	}
112
113	return 0;
114}
115#else /* __APPLE__ */
116#define os_daemon daemon
117#endif /* __APPLE__ */
118
119
120int os_daemonize(const char *pid_file)
121{
122#ifdef __uClinux__
123	return -1;
124#else /* __uClinux__ */
125	if (os_daemon(0, 0)) {
126		perror("daemon");
127		return -1;
128	}
129
130	if (pid_file) {
131		FILE *f = fopen(pid_file, "w");
132		if (f) {
133			fprintf(f, "%u\n", getpid());
134			fclose(f);
135		}
136	}
137
138	return -0;
139#endif /* __uClinux__ */
140}
141
142
143void os_daemonize_terminate(const char *pid_file)
144{
145	if (pid_file)
146		unlink(pid_file);
147}
148
149
150int os_get_random(unsigned char *buf, size_t len)
151{
152	FILE *f;
153	size_t rc;
154
155	f = fopen("/dev/urandom", "rb");
156	if (f == NULL) {
157		printf("Could not open /dev/urandom.\n");
158		return -1;
159	}
160
161	rc = fread(buf, 1, len, f);
162	fclose(f);
163
164	return rc != len ? -1 : 0;
165}
166
167
168unsigned long os_random(void)
169{
170	return random();
171}
172
173
174char * os_rel2abs_path(const char *rel_path)
175{
176	char *buf = NULL, *cwd, *ret;
177	size_t len = 128, cwd_len, rel_len, ret_len;
178	int last_errno;
179
180	if (rel_path[0] == '/')
181		return strdup(rel_path);
182
183	for (;;) {
184		buf = malloc(len);
185		if (buf == NULL)
186			return NULL;
187		cwd = getcwd(buf, len);
188		if (cwd == NULL) {
189			last_errno = errno;
190			free(buf);
191			if (last_errno != ERANGE)
192				return NULL;
193			len *= 2;
194			if (len > 2000)
195				return NULL;
196		} else {
197			buf[len - 1] = '\0';
198			break;
199		}
200	}
201
202	cwd_len = strlen(cwd);
203	rel_len = strlen(rel_path);
204	ret_len = cwd_len + 1 + rel_len + 1;
205	ret = malloc(ret_len);
206	if (ret) {
207		memcpy(ret, cwd, cwd_len);
208		ret[cwd_len] = '/';
209		memcpy(ret + cwd_len + 1, rel_path, rel_len);
210		ret[ret_len - 1] = '\0';
211	}
212	free(buf);
213	return ret;
214}
215
216
217int os_program_init(void)
218{
219#ifdef ANDROID
220	/* We ignore errors here since errors are normal if we
221	 * are already running as non-root.
222	 */
223	gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
224	setgroups(sizeof(groups)/sizeof(groups[0]), groups);
225
226	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
227
228	setgid(AID_WIFI);
229	setuid(AID_WIFI);
230
231	struct __user_cap_header_struct header;
232	struct __user_cap_data_struct cap;
233	header.version = _LINUX_CAPABILITY_VERSION;
234	header.pid = 0;
235	cap.effective = cap.permitted =
236		(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
237	cap.inheritable = 0;
238	capset(&header, &cap);
239#endif
240
241	return 0;
242}
243
244
245void os_program_deinit(void)
246{
247}
248
249
250int os_setenv(const char *name, const char *value, int overwrite)
251{
252	return setenv(name, value, overwrite);
253}
254
255
256int os_unsetenv(const char *name)
257{
258#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
259    defined(__OpenBSD__)
260	unsetenv(name);
261	return 0;
262#else
263	return unsetenv(name);
264#endif
265}
266
267
268char * os_readfile(const char *name, size_t *len)
269{
270	FILE *f;
271	char *buf;
272
273	f = fopen(name, "rb");
274	if (f == NULL)
275		return NULL;
276
277	fseek(f, 0, SEEK_END);
278	*len = ftell(f);
279	fseek(f, 0, SEEK_SET);
280
281	buf = malloc(*len);
282	if (buf == NULL) {
283		fclose(f);
284		return NULL;
285	}
286
287	if (fread(buf, 1, *len, f) != *len) {
288		fclose(f);
289		free(buf);
290		return NULL;
291	}
292
293	fclose(f);
294
295	return buf;
296}
297
298
299void * os_zalloc(size_t size)
300{
301	return calloc(1, size);
302}
303
304
305size_t os_strlcpy(char *dest, const char *src, size_t siz)
306{
307	const char *s = src;
308	size_t left = siz;
309
310	if (left) {
311		/* Copy string up to the maximum size of the dest buffer */
312		while (--left != 0) {
313			if ((*dest++ = *s++) == '\0')
314				break;
315		}
316	}
317
318	if (left == 0) {
319		/* Not enough room for the string; force NUL-termination */
320		if (siz != 0)
321			*dest = '\0';
322		while (*s++)
323			; /* determine total src string length */
324	}
325
326	return s - src - 1;
327}
328