1189251Ssam/* 2214734Srpaulo * OS specific functions for UNIX/POSIX systems 3214734Srpaulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11252726Srpaulo#include <time.h> 12252726Srpaulo 13252726Srpaulo#ifdef ANDROID 14252726Srpaulo#include <linux/capability.h> 15252726Srpaulo#include <linux/prctl.h> 16252726Srpaulo#include <private/android_filesystem_config.h> 17252726Srpaulo#endif /* ANDROID */ 18252726Srpaulo 19189251Ssam#include "os.h" 20189251Ssam 21214734Srpaulo#ifdef WPA_TRACE 22214734Srpaulo 23214734Srpaulo#include "common.h" 24214734Srpaulo#include "wpa_debug.h" 25214734Srpaulo#include "trace.h" 26252726Srpaulo#include "list.h" 27214734Srpaulo 28214734Srpaulostatic struct dl_list alloc_list; 29214734Srpaulo 30214734Srpaulo#define ALLOC_MAGIC 0xa84ef1b2 31214734Srpaulo#define FREED_MAGIC 0x67fd487a 32214734Srpaulo 33214734Srpaulostruct os_alloc_trace { 34214734Srpaulo unsigned int magic; 35214734Srpaulo struct dl_list list; 36214734Srpaulo size_t len; 37214734Srpaulo WPA_TRACE_INFO 38214734Srpaulo}; 39214734Srpaulo 40214734Srpaulo#endif /* WPA_TRACE */ 41214734Srpaulo 42214734Srpaulo 43189251Ssamvoid os_sleep(os_time_t sec, os_time_t usec) 44189251Ssam{ 45189251Ssam if (sec) 46189251Ssam sleep(sec); 47189251Ssam if (usec) 48189251Ssam usleep(usec); 49189251Ssam} 50189251Ssam 51189251Ssam 52189251Ssamint os_get_time(struct os_time *t) 53189251Ssam{ 54189251Ssam int res; 55189251Ssam struct timeval tv; 56189251Ssam res = gettimeofday(&tv, NULL); 57189251Ssam t->sec = tv.tv_sec; 58189251Ssam t->usec = tv.tv_usec; 59189251Ssam return res; 60189251Ssam} 61189251Ssam 62189251Ssam 63189251Ssamint os_mktime(int year, int month, int day, int hour, int min, int sec, 64189251Ssam os_time_t *t) 65189251Ssam{ 66189251Ssam struct tm tm, *tm1; 67189251Ssam time_t t_local, t1, t2; 68189251Ssam os_time_t tz_offset; 69189251Ssam 70189251Ssam if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || 71189251Ssam hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || 72189251Ssam sec > 60) 73189251Ssam return -1; 74189251Ssam 75189251Ssam memset(&tm, 0, sizeof(tm)); 76189251Ssam tm.tm_year = year - 1900; 77189251Ssam tm.tm_mon = month - 1; 78189251Ssam tm.tm_mday = day; 79189251Ssam tm.tm_hour = hour; 80189251Ssam tm.tm_min = min; 81189251Ssam tm.tm_sec = sec; 82189251Ssam 83189251Ssam t_local = mktime(&tm); 84189251Ssam 85189251Ssam /* figure out offset to UTC */ 86189251Ssam tm1 = localtime(&t_local); 87189251Ssam if (tm1) { 88189251Ssam t1 = mktime(tm1); 89189251Ssam tm1 = gmtime(&t_local); 90189251Ssam if (tm1) { 91189251Ssam t2 = mktime(tm1); 92189251Ssam tz_offset = t2 - t1; 93189251Ssam } else 94189251Ssam tz_offset = 0; 95189251Ssam } else 96189251Ssam tz_offset = 0; 97189251Ssam 98189251Ssam *t = (os_time_t) t_local - tz_offset; 99189251Ssam return 0; 100189251Ssam} 101189251Ssam 102189251Ssam 103252726Srpauloint os_gmtime(os_time_t t, struct os_tm *tm) 104252726Srpaulo{ 105252726Srpaulo struct tm *tm2; 106252726Srpaulo time_t t2 = t; 107252726Srpaulo 108252726Srpaulo tm2 = gmtime(&t2); 109252726Srpaulo if (tm2 == NULL) 110252726Srpaulo return -1; 111252726Srpaulo tm->sec = tm2->tm_sec; 112252726Srpaulo tm->min = tm2->tm_min; 113252726Srpaulo tm->hour = tm2->tm_hour; 114252726Srpaulo tm->day = tm2->tm_mday; 115252726Srpaulo tm->month = tm2->tm_mon + 1; 116252726Srpaulo tm->year = tm2->tm_year + 1900; 117252726Srpaulo return 0; 118252726Srpaulo} 119252726Srpaulo 120252726Srpaulo 121189251Ssam#ifdef __APPLE__ 122189251Ssam#include <fcntl.h> 123189251Ssamstatic int os_daemon(int nochdir, int noclose) 124189251Ssam{ 125189251Ssam int devnull; 126189251Ssam 127189251Ssam if (chdir("/") < 0) 128189251Ssam return -1; 129189251Ssam 130189251Ssam devnull = open("/dev/null", O_RDWR); 131189251Ssam if (devnull < 0) 132189251Ssam return -1; 133189251Ssam 134189251Ssam if (dup2(devnull, STDIN_FILENO) < 0) { 135189251Ssam close(devnull); 136189251Ssam return -1; 137189251Ssam } 138189251Ssam 139189251Ssam if (dup2(devnull, STDOUT_FILENO) < 0) { 140189251Ssam close(devnull); 141189251Ssam return -1; 142189251Ssam } 143189251Ssam 144189251Ssam if (dup2(devnull, STDERR_FILENO) < 0) { 145189251Ssam close(devnull); 146189251Ssam return -1; 147189251Ssam } 148189251Ssam 149189251Ssam return 0; 150189251Ssam} 151189251Ssam#else /* __APPLE__ */ 152189251Ssam#define os_daemon daemon 153189251Ssam#endif /* __APPLE__ */ 154189251Ssam 155189251Ssam 156189251Ssamint os_daemonize(const char *pid_file) 157189251Ssam{ 158252726Srpaulo#if defined(__uClinux__) || defined(__sun__) 159189251Ssam return -1; 160252726Srpaulo#else /* defined(__uClinux__) || defined(__sun__) */ 161189251Ssam if (os_daemon(0, 0)) { 162189251Ssam perror("daemon"); 163189251Ssam return -1; 164189251Ssam } 165189251Ssam 166189251Ssam if (pid_file) { 167189251Ssam FILE *f = fopen(pid_file, "w"); 168189251Ssam if (f) { 169189251Ssam fprintf(f, "%u\n", getpid()); 170189251Ssam fclose(f); 171189251Ssam } 172189251Ssam } 173189251Ssam 174189251Ssam return -0; 175252726Srpaulo#endif /* defined(__uClinux__) || defined(__sun__) */ 176189251Ssam} 177189251Ssam 178189251Ssam 179189251Ssamvoid os_daemonize_terminate(const char *pid_file) 180189251Ssam{ 181189251Ssam if (pid_file) 182189251Ssam unlink(pid_file); 183189251Ssam} 184189251Ssam 185189251Ssam 186189251Ssamint os_get_random(unsigned char *buf, size_t len) 187189251Ssam{ 188189251Ssam FILE *f; 189189251Ssam size_t rc; 190189251Ssam 191189251Ssam f = fopen("/dev/urandom", "rb"); 192189251Ssam if (f == NULL) { 193189251Ssam printf("Could not open /dev/urandom.\n"); 194189251Ssam return -1; 195189251Ssam } 196189251Ssam 197189251Ssam rc = fread(buf, 1, len, f); 198189251Ssam fclose(f); 199189251Ssam 200189251Ssam return rc != len ? -1 : 0; 201189251Ssam} 202189251Ssam 203189251Ssam 204189251Ssamunsigned long os_random(void) 205189251Ssam{ 206189251Ssam return random(); 207189251Ssam} 208189251Ssam 209189251Ssam 210189251Ssamchar * os_rel2abs_path(const char *rel_path) 211189251Ssam{ 212189251Ssam char *buf = NULL, *cwd, *ret; 213189251Ssam size_t len = 128, cwd_len, rel_len, ret_len; 214189251Ssam int last_errno; 215189251Ssam 216189251Ssam if (rel_path[0] == '/') 217214734Srpaulo return os_strdup(rel_path); 218189251Ssam 219189251Ssam for (;;) { 220214734Srpaulo buf = os_malloc(len); 221189251Ssam if (buf == NULL) 222189251Ssam return NULL; 223189251Ssam cwd = getcwd(buf, len); 224189251Ssam if (cwd == NULL) { 225189251Ssam last_errno = errno; 226214734Srpaulo os_free(buf); 227189251Ssam if (last_errno != ERANGE) 228189251Ssam return NULL; 229189251Ssam len *= 2; 230189251Ssam if (len > 2000) 231189251Ssam return NULL; 232189251Ssam } else { 233189251Ssam buf[len - 1] = '\0'; 234189251Ssam break; 235189251Ssam } 236189251Ssam } 237189251Ssam 238214734Srpaulo cwd_len = os_strlen(cwd); 239214734Srpaulo rel_len = os_strlen(rel_path); 240189251Ssam ret_len = cwd_len + 1 + rel_len + 1; 241214734Srpaulo ret = os_malloc(ret_len); 242189251Ssam if (ret) { 243214734Srpaulo os_memcpy(ret, cwd, cwd_len); 244189251Ssam ret[cwd_len] = '/'; 245214734Srpaulo os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 246189251Ssam ret[ret_len - 1] = '\0'; 247189251Ssam } 248214734Srpaulo os_free(buf); 249189251Ssam return ret; 250189251Ssam} 251189251Ssam 252189251Ssam 253189251Ssamint os_program_init(void) 254189251Ssam{ 255252726Srpaulo#ifdef ANDROID 256252726Srpaulo /* 257252726Srpaulo * We ignore errors here since errors are normal if we 258252726Srpaulo * are already running as non-root. 259252726Srpaulo */ 260252726Srpaulo gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; 261252726Srpaulo struct __user_cap_header_struct header; 262252726Srpaulo struct __user_cap_data_struct cap; 263252726Srpaulo 264252726Srpaulo setgroups(sizeof(groups)/sizeof(groups[0]), groups); 265252726Srpaulo 266252726Srpaulo prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); 267252726Srpaulo 268252726Srpaulo setgid(AID_WIFI); 269252726Srpaulo setuid(AID_WIFI); 270252726Srpaulo 271252726Srpaulo header.version = _LINUX_CAPABILITY_VERSION; 272252726Srpaulo header.pid = 0; 273252726Srpaulo cap.effective = cap.permitted = 274252726Srpaulo (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); 275252726Srpaulo cap.inheritable = 0; 276252726Srpaulo capset(&header, &cap); 277252726Srpaulo#endif /* ANDROID */ 278252726Srpaulo 279214734Srpaulo#ifdef WPA_TRACE 280214734Srpaulo dl_list_init(&alloc_list); 281214734Srpaulo#endif /* WPA_TRACE */ 282189251Ssam return 0; 283189251Ssam} 284189251Ssam 285189251Ssam 286189251Ssamvoid os_program_deinit(void) 287189251Ssam{ 288214734Srpaulo#ifdef WPA_TRACE 289214734Srpaulo struct os_alloc_trace *a; 290214734Srpaulo unsigned long total = 0; 291214734Srpaulo dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { 292214734Srpaulo total += a->len; 293214734Srpaulo if (a->magic != ALLOC_MAGIC) { 294214734Srpaulo wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " 295214734Srpaulo "len %lu", 296214734Srpaulo a, a->magic, (unsigned long) a->len); 297214734Srpaulo continue; 298214734Srpaulo } 299214734Srpaulo wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", 300214734Srpaulo a, (unsigned long) a->len); 301214734Srpaulo wpa_trace_dump("memleak", a); 302214734Srpaulo } 303214734Srpaulo if (total) 304214734Srpaulo wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", 305214734Srpaulo (unsigned long) total); 306214734Srpaulo#endif /* WPA_TRACE */ 307189251Ssam} 308189251Ssam 309189251Ssam 310189251Ssamint os_setenv(const char *name, const char *value, int overwrite) 311189251Ssam{ 312189251Ssam return setenv(name, value, overwrite); 313189251Ssam} 314189251Ssam 315189251Ssam 316189251Ssamint os_unsetenv(const char *name) 317189251Ssam{ 318209158Srpaulo#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ 319209158Srpaulo defined(__OpenBSD__) 320189251Ssam unsetenv(name); 321189251Ssam return 0; 322189251Ssam#else 323189251Ssam return unsetenv(name); 324189251Ssam#endif 325189251Ssam} 326189251Ssam 327189251Ssam 328189251Ssamchar * os_readfile(const char *name, size_t *len) 329189251Ssam{ 330189251Ssam FILE *f; 331189251Ssam char *buf; 332252726Srpaulo long pos; 333189251Ssam 334189251Ssam f = fopen(name, "rb"); 335189251Ssam if (f == NULL) 336189251Ssam return NULL; 337189251Ssam 338252726Srpaulo if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) { 339252726Srpaulo fclose(f); 340252726Srpaulo return NULL; 341252726Srpaulo } 342252726Srpaulo *len = pos; 343252726Srpaulo if (fseek(f, 0, SEEK_SET) < 0) { 344252726Srpaulo fclose(f); 345252726Srpaulo return NULL; 346252726Srpaulo } 347189251Ssam 348214734Srpaulo buf = os_malloc(*len); 349189251Ssam if (buf == NULL) { 350189251Ssam fclose(f); 351189251Ssam return NULL; 352189251Ssam } 353189251Ssam 354189251Ssam if (fread(buf, 1, *len, f) != *len) { 355189251Ssam fclose(f); 356214734Srpaulo os_free(buf); 357189251Ssam return NULL; 358189251Ssam } 359189251Ssam 360189251Ssam fclose(f); 361189251Ssam 362189251Ssam return buf; 363189251Ssam} 364189251Ssam 365189251Ssam 366214734Srpaulo#ifndef WPA_TRACE 367189251Ssamvoid * os_zalloc(size_t size) 368189251Ssam{ 369189251Ssam return calloc(1, size); 370189251Ssam} 371214734Srpaulo#endif /* WPA_TRACE */ 372189251Ssam 373189251Ssam 374189251Ssamsize_t os_strlcpy(char *dest, const char *src, size_t siz) 375189251Ssam{ 376189251Ssam const char *s = src; 377189251Ssam size_t left = siz; 378189251Ssam 379189251Ssam if (left) { 380189251Ssam /* Copy string up to the maximum size of the dest buffer */ 381189251Ssam while (--left != 0) { 382189251Ssam if ((*dest++ = *s++) == '\0') 383189251Ssam break; 384189251Ssam } 385189251Ssam } 386189251Ssam 387189251Ssam if (left == 0) { 388189251Ssam /* Not enough room for the string; force NUL-termination */ 389189251Ssam if (siz != 0) 390189251Ssam *dest = '\0'; 391189251Ssam while (*s++) 392189251Ssam ; /* determine total src string length */ 393189251Ssam } 394189251Ssam 395189251Ssam return s - src - 1; 396189251Ssam} 397214734Srpaulo 398214734Srpaulo 399214734Srpaulo#ifdef WPA_TRACE 400214734Srpaulo 401214734Srpaulovoid * os_malloc(size_t size) 402214734Srpaulo{ 403214734Srpaulo struct os_alloc_trace *a; 404214734Srpaulo a = malloc(sizeof(*a) + size); 405214734Srpaulo if (a == NULL) 406214734Srpaulo return NULL; 407214734Srpaulo a->magic = ALLOC_MAGIC; 408214734Srpaulo dl_list_add(&alloc_list, &a->list); 409214734Srpaulo a->len = size; 410214734Srpaulo wpa_trace_record(a); 411214734Srpaulo return a + 1; 412214734Srpaulo} 413214734Srpaulo 414214734Srpaulo 415214734Srpaulovoid * os_realloc(void *ptr, size_t size) 416214734Srpaulo{ 417214734Srpaulo struct os_alloc_trace *a; 418214734Srpaulo size_t copy_len; 419214734Srpaulo void *n; 420214734Srpaulo 421214734Srpaulo if (ptr == NULL) 422214734Srpaulo return os_malloc(size); 423214734Srpaulo 424214734Srpaulo a = (struct os_alloc_trace *) ptr - 1; 425214734Srpaulo if (a->magic != ALLOC_MAGIC) { 426214734Srpaulo wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", 427214734Srpaulo a, a->magic, 428214734Srpaulo a->magic == FREED_MAGIC ? " (already freed)" : ""); 429214734Srpaulo wpa_trace_show("Invalid os_realloc() call"); 430214734Srpaulo abort(); 431214734Srpaulo } 432214734Srpaulo n = os_malloc(size); 433214734Srpaulo if (n == NULL) 434214734Srpaulo return NULL; 435214734Srpaulo copy_len = a->len; 436214734Srpaulo if (copy_len > size) 437214734Srpaulo copy_len = size; 438214734Srpaulo os_memcpy(n, a + 1, copy_len); 439214734Srpaulo os_free(ptr); 440214734Srpaulo return n; 441214734Srpaulo} 442214734Srpaulo 443214734Srpaulo 444214734Srpaulovoid os_free(void *ptr) 445214734Srpaulo{ 446214734Srpaulo struct os_alloc_trace *a; 447214734Srpaulo 448214734Srpaulo if (ptr == NULL) 449214734Srpaulo return; 450214734Srpaulo a = (struct os_alloc_trace *) ptr - 1; 451214734Srpaulo if (a->magic != ALLOC_MAGIC) { 452214734Srpaulo wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", 453214734Srpaulo a, a->magic, 454214734Srpaulo a->magic == FREED_MAGIC ? " (already freed)" : ""); 455214734Srpaulo wpa_trace_show("Invalid os_free() call"); 456214734Srpaulo abort(); 457214734Srpaulo } 458214734Srpaulo dl_list_del(&a->list); 459214734Srpaulo a->magic = FREED_MAGIC; 460214734Srpaulo 461214734Srpaulo wpa_trace_check_ref(ptr); 462214734Srpaulo free(a); 463214734Srpaulo} 464214734Srpaulo 465214734Srpaulo 466214734Srpaulovoid * os_zalloc(size_t size) 467214734Srpaulo{ 468214734Srpaulo void *ptr = os_malloc(size); 469214734Srpaulo if (ptr) 470214734Srpaulo os_memset(ptr, 0, size); 471214734Srpaulo return ptr; 472214734Srpaulo} 473214734Srpaulo 474214734Srpaulo 475214734Srpaulochar * os_strdup(const char *s) 476214734Srpaulo{ 477214734Srpaulo size_t len; 478214734Srpaulo char *d; 479214734Srpaulo len = os_strlen(s); 480214734Srpaulo d = os_malloc(len + 1); 481214734Srpaulo if (d == NULL) 482214734Srpaulo return NULL; 483214734Srpaulo os_memcpy(d, s, len); 484214734Srpaulo d[len] = '\0'; 485214734Srpaulo return d; 486214734Srpaulo} 487214734Srpaulo 488214734Srpaulo#endif /* WPA_TRACE */ 489