1/* 2 * OS specific functions for UNIX/POSIX systems 3 * Copyright (c) 2005-2009, 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 <time.h> 12#include <sys/wait.h> 13 14#ifdef ANDROID 15#include <sys/capability.h> 16#include <sys/prctl.h> 17#include <private/android_filesystem_config.h> 18#endif /* ANDROID */ 19 20#include "os.h" 21#include "common.h" 22 23#ifdef WPA_TRACE 24 25#include "wpa_debug.h" 26#include "trace.h" 27#include "list.h" 28 29static struct dl_list alloc_list; 30 31#define ALLOC_MAGIC 0xa84ef1b2 32#define FREED_MAGIC 0x67fd487a 33 34struct os_alloc_trace { 35 unsigned int magic; 36 struct dl_list list; 37 size_t len; 38 WPA_TRACE_INFO 39}; 40 41#endif /* WPA_TRACE */ 42 43 44void os_sleep(os_time_t sec, os_time_t usec) 45{ 46 if (sec) 47 sleep(sec); 48 if (usec) 49 usleep(usec); 50} 51 52 53int os_get_time(struct os_time *t) 54{ 55 int res; 56 struct timeval tv; 57 res = gettimeofday(&tv, NULL); 58 t->sec = tv.tv_sec; 59 t->usec = tv.tv_usec; 60 return res; 61} 62 63 64int os_get_reltime(struct os_reltime *t) 65{ 66#if defined(CLOCK_BOOTTIME) 67 static clockid_t clock_id = CLOCK_BOOTTIME; 68#elif defined(CLOCK_MONOTONIC) 69 static clockid_t clock_id = CLOCK_MONOTONIC; 70#else 71 static clockid_t clock_id = CLOCK_REALTIME; 72#endif 73 struct timespec ts; 74 int res; 75 76 while (1) { 77 res = clock_gettime(clock_id, &ts); 78 if (res == 0) { 79 t->sec = ts.tv_sec; 80 t->usec = ts.tv_nsec / 1000; 81 return 0; 82 } 83 switch (clock_id) { 84#ifdef CLOCK_BOOTTIME 85 case CLOCK_BOOTTIME: 86 clock_id = CLOCK_MONOTONIC; 87 break; 88#endif 89#ifdef CLOCK_MONOTONIC 90 case CLOCK_MONOTONIC: 91 clock_id = CLOCK_REALTIME; 92 break; 93#endif 94 case CLOCK_REALTIME: 95 return -1; 96 } 97 } 98} 99 100 101int os_mktime(int year, int month, int day, int hour, int min, int sec, 102 os_time_t *t) 103{ 104 struct tm tm, *tm1; 105 time_t t_local, t1, t2; 106 os_time_t tz_offset; 107 108 if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || 109 hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || 110 sec > 60) 111 return -1; 112 113 memset(&tm, 0, sizeof(tm)); 114 tm.tm_year = year - 1900; 115 tm.tm_mon = month - 1; 116 tm.tm_mday = day; 117 tm.tm_hour = hour; 118 tm.tm_min = min; 119 tm.tm_sec = sec; 120 121 t_local = mktime(&tm); 122 123 /* figure out offset to UTC */ 124 tm1 = localtime(&t_local); 125 if (tm1) { 126 t1 = mktime(tm1); 127 tm1 = gmtime(&t_local); 128 if (tm1) { 129 t2 = mktime(tm1); 130 tz_offset = t2 - t1; 131 } else 132 tz_offset = 0; 133 } else 134 tz_offset = 0; 135 136 *t = (os_time_t) t_local - tz_offset; 137 return 0; 138} 139 140 141int os_gmtime(os_time_t t, struct os_tm *tm) 142{ 143 struct tm *tm2; 144 time_t t2 = t; 145 146 tm2 = gmtime(&t2); 147 if (tm2 == NULL) 148 return -1; 149 tm->sec = tm2->tm_sec; 150 tm->min = tm2->tm_min; 151 tm->hour = tm2->tm_hour; 152 tm->day = tm2->tm_mday; 153 tm->month = tm2->tm_mon + 1; 154 tm->year = tm2->tm_year + 1900; 155 return 0; 156} 157 158 159#ifdef __APPLE__ 160#include <fcntl.h> 161static int os_daemon(int nochdir, int noclose) 162{ 163 int devnull; 164 165 if (chdir("/") < 0) 166 return -1; 167 168 devnull = open("/dev/null", O_RDWR); 169 if (devnull < 0) 170 return -1; 171 172 if (dup2(devnull, STDIN_FILENO) < 0) { 173 close(devnull); 174 return -1; 175 } 176 177 if (dup2(devnull, STDOUT_FILENO) < 0) { 178 close(devnull); 179 return -1; 180 } 181 182 if (dup2(devnull, STDERR_FILENO) < 0) { 183 close(devnull); 184 return -1; 185 } 186 187 return 0; 188} 189#else /* __APPLE__ */ 190#define os_daemon daemon 191#endif /* __APPLE__ */ 192 193 194int os_daemonize(const char *pid_file) 195{ 196#if defined(__uClinux__) || defined(__sun__) 197 return -1; 198#else /* defined(__uClinux__) || defined(__sun__) */ 199 if (os_daemon(0, 0)) { 200 perror("daemon"); 201 return -1; 202 } 203 204 if (pid_file) { 205 FILE *f = fopen(pid_file, "w"); 206 if (f) { 207 fprintf(f, "%u\n", getpid()); 208 fclose(f); 209 } 210 } 211 212 return -0; 213#endif /* defined(__uClinux__) || defined(__sun__) */ 214} 215 216 217void os_daemonize_terminate(const char *pid_file) 218{ 219 if (pid_file) 220 unlink(pid_file); 221} 222 223 224int os_get_random(unsigned char *buf, size_t len) 225{ 226 FILE *f; 227 size_t rc; 228 229 f = fopen("/dev/urandom", "rb"); 230 if (f == NULL) { 231 printf("Could not open /dev/urandom.\n"); 232 return -1; 233 } 234 235 rc = fread(buf, 1, len, f); 236 fclose(f); 237 238 return rc != len ? -1 : 0; 239} 240 241 242unsigned long os_random(void) 243{ 244 return random(); 245} 246 247 248char * os_rel2abs_path(const char *rel_path) 249{ 250 char *buf = NULL, *cwd, *ret; 251 size_t len = 128, cwd_len, rel_len, ret_len; 252 int last_errno; 253 254 if (!rel_path) 255 return NULL; 256 257 if (rel_path[0] == '/') 258 return os_strdup(rel_path); 259 260 for (;;) { 261 buf = os_malloc(len); 262 if (buf == NULL) 263 return NULL; 264 cwd = getcwd(buf, len); 265 if (cwd == NULL) { 266 last_errno = errno; 267 os_free(buf); 268 if (last_errno != ERANGE) 269 return NULL; 270 len *= 2; 271 if (len > 2000) 272 return NULL; 273 } else { 274 buf[len - 1] = '\0'; 275 break; 276 } 277 } 278 279 cwd_len = os_strlen(cwd); 280 rel_len = os_strlen(rel_path); 281 ret_len = cwd_len + 1 + rel_len + 1; 282 ret = os_malloc(ret_len); 283 if (ret) { 284 os_memcpy(ret, cwd, cwd_len); 285 ret[cwd_len] = '/'; 286 os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 287 ret[ret_len - 1] = '\0'; 288 } 289 os_free(buf); 290 return ret; 291} 292 293 294int os_program_init(void) 295{ 296#ifdef ANDROID 297 /* 298 * We ignore errors here since errors are normal if we 299 * are already running as non-root. 300 */ 301#ifdef ANDROID_SETGROUPS_OVERRIDE 302 gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE }; 303#else /* ANDROID_SETGROUPS_OVERRIDE */ 304 gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; 305#endif /* ANDROID_SETGROUPS_OVERRIDE */ 306 struct __user_cap_header_struct header; 307 struct __user_cap_data_struct cap; 308 309 setgroups(ARRAY_SIZE(groups), groups); 310 311 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); 312 313 setgid(AID_WIFI); 314 setuid(AID_WIFI); 315 316 header.version = _LINUX_CAPABILITY_VERSION; 317 header.pid = 0; 318 cap.effective = cap.permitted = 319 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); 320 cap.inheritable = 0; 321 capset(&header, &cap); 322#endif /* ANDROID */ 323 324#ifdef WPA_TRACE 325 dl_list_init(&alloc_list); 326#endif /* WPA_TRACE */ 327 return 0; 328} 329 330 331void os_program_deinit(void) 332{ 333#ifdef WPA_TRACE 334 struct os_alloc_trace *a; 335 unsigned long total = 0; 336 dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { 337 total += a->len; 338 if (a->magic != ALLOC_MAGIC) { 339 wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " 340 "len %lu", 341 a, a->magic, (unsigned long) a->len); 342 continue; 343 } 344 wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", 345 a, (unsigned long) a->len); 346 wpa_trace_dump("memleak", a); 347 } 348 if (total) 349 wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", 350 (unsigned long) total); 351#endif /* WPA_TRACE */ 352} 353 354 355int os_setenv(const char *name, const char *value, int overwrite) 356{ 357 return setenv(name, value, overwrite); 358} 359 360 361int os_unsetenv(const char *name) 362{ 363#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ 364 defined(__OpenBSD__) 365 unsetenv(name); 366 return 0; 367#else 368 return unsetenv(name); 369#endif 370} 371 372 373char * os_readfile(const char *name, size_t *len) 374{ 375 FILE *f; 376 char *buf; 377 long pos; 378 379 f = fopen(name, "rb"); 380 if (f == NULL) 381 return NULL; 382 383 if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) { 384 fclose(f); 385 return NULL; 386 } 387 *len = pos; 388 if (fseek(f, 0, SEEK_SET) < 0) { 389 fclose(f); 390 return NULL; 391 } 392 393 buf = os_malloc(*len); 394 if (buf == NULL) { 395 fclose(f); 396 return NULL; 397 } 398 399 if (fread(buf, 1, *len, f) != *len) { 400 fclose(f); 401 os_free(buf); 402 return NULL; 403 } 404 405 fclose(f); 406 407 return buf; 408} 409 410 411int os_file_exists(const char *fname) 412{ 413 FILE *f = fopen(fname, "rb"); 414 if (f == NULL) 415 return 0; 416 fclose(f); 417 return 1; 418} 419 420 421#ifndef WPA_TRACE 422void * os_zalloc(size_t size) 423{ 424 return calloc(1, size); 425} 426#endif /* WPA_TRACE */ 427 428 429size_t os_strlcpy(char *dest, const char *src, size_t siz) 430{ 431 const char *s = src; 432 size_t left = siz; 433 434 if (left) { 435 /* Copy string up to the maximum size of the dest buffer */ 436 while (--left != 0) { 437 if ((*dest++ = *s++) == '\0') 438 break; 439 } 440 } 441 442 if (left == 0) { 443 /* Not enough room for the string; force NUL-termination */ 444 if (siz != 0) 445 *dest = '\0'; 446 while (*s++) 447 ; /* determine total src string length */ 448 } 449 450 return s - src - 1; 451} 452 453 454int os_memcmp_const(const void *a, const void *b, size_t len) 455{ 456 const u8 *aa = a; 457 const u8 *bb = b; 458 size_t i; 459 u8 res; 460 461 for (res = 0, i = 0; i < len; i++) 462 res |= aa[i] ^ bb[i]; 463 464 return res; 465} 466 467 468#ifdef WPA_TRACE 469 470void * os_malloc(size_t size) 471{ 472 struct os_alloc_trace *a; 473 a = malloc(sizeof(*a) + size); 474 if (a == NULL) 475 return NULL; 476 a->magic = ALLOC_MAGIC; 477 dl_list_add(&alloc_list, &a->list); 478 a->len = size; 479 wpa_trace_record(a); 480 return a + 1; 481} 482 483 484void * os_realloc(void *ptr, size_t size) 485{ 486 struct os_alloc_trace *a; 487 size_t copy_len; 488 void *n; 489 490 if (ptr == NULL) 491 return os_malloc(size); 492 493 a = (struct os_alloc_trace *) ptr - 1; 494 if (a->magic != ALLOC_MAGIC) { 495 wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", 496 a, a->magic, 497 a->magic == FREED_MAGIC ? " (already freed)" : ""); 498 wpa_trace_show("Invalid os_realloc() call"); 499 abort(); 500 } 501 n = os_malloc(size); 502 if (n == NULL) 503 return NULL; 504 copy_len = a->len; 505 if (copy_len > size) 506 copy_len = size; 507 os_memcpy(n, a + 1, copy_len); 508 os_free(ptr); 509 return n; 510} 511 512 513void os_free(void *ptr) 514{ 515 struct os_alloc_trace *a; 516 517 if (ptr == NULL) 518 return; 519 a = (struct os_alloc_trace *) ptr - 1; 520 if (a->magic != ALLOC_MAGIC) { 521 wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", 522 a, a->magic, 523 a->magic == FREED_MAGIC ? " (already freed)" : ""); 524 wpa_trace_show("Invalid os_free() call"); 525 abort(); 526 } 527 dl_list_del(&a->list); 528 a->magic = FREED_MAGIC; 529 530 wpa_trace_check_ref(ptr); 531 free(a); 532} 533 534 535void * os_zalloc(size_t size) 536{ 537 void *ptr = os_malloc(size); 538 if (ptr) 539 os_memset(ptr, 0, size); 540 return ptr; 541} 542 543 544char * os_strdup(const char *s) 545{ 546 size_t len; 547 char *d; 548 len = os_strlen(s); 549 d = os_malloc(len + 1); 550 if (d == NULL) 551 return NULL; 552 os_memcpy(d, s, len); 553 d[len] = '\0'; 554 return d; 555} 556 557#endif /* WPA_TRACE */ 558 559 560int os_exec(const char *program, const char *arg, int wait_completion) 561{ 562 pid_t pid; 563 int pid_status; 564 565 pid = fork(); 566 if (pid < 0) { 567 perror("fork"); 568 return -1; 569 } 570 571 if (pid == 0) { 572 /* run the external command in the child process */ 573 const int MAX_ARG = 30; 574 char *_program, *_arg, *pos; 575 char *argv[MAX_ARG + 1]; 576 int i; 577 578 _program = os_strdup(program); 579 _arg = os_strdup(arg); 580 581 argv[0] = _program; 582 583 i = 1; 584 pos = _arg; 585 while (i < MAX_ARG && pos && *pos) { 586 while (*pos == ' ') 587 pos++; 588 if (*pos == '\0') 589 break; 590 argv[i++] = pos; 591 pos = os_strchr(pos, ' '); 592 if (pos) 593 *pos++ = '\0'; 594 } 595 argv[i] = NULL; 596 597 execv(program, argv); 598 perror("execv"); 599 os_free(_program); 600 os_free(_arg); 601 exit(0); 602 return -1; 603 } 604 605 if (wait_completion) { 606 /* wait for the child process to complete in the parent */ 607 waitpid(pid, &pid_status, 0); 608 } 609 610 return 0; 611} 612