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 29 static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list); 30 31 #define ALLOC_MAGIC 0xa84ef1b2 32 #define FREED_MAGIC 0x67fd487a 33 34 struct 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 44 void 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 53 int 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 64 int 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 101 int 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 141 int 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> 161 static 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 194 #ifdef __FreeBSD__ 195 #include <err.h> 196 #include <libutil.h> 197 #include <stdint.h> 198 #endif /* __FreeBSD__ */ 199 200 int os_daemonize(const char *pid_file) 201 { 202 #if defined(__uClinux__) || defined(__sun__) 203 return -1; 204 #else /* defined(__uClinux__) || defined(__sun__) */ 205 #ifdef __FreeBSD__ 206 pid_t otherpid; 207 struct pidfh *pfh; 208 209 pfh = pidfile_open(pid_file, 0600, &otherpid); 210 if (pfh == NULL) { 211 if (errno == EEXIST) { 212 errx(1, "Daemon already running, pid: %jd.", 213 (intmax_t)otherpid); 214 } 215 warn("Cannot open or create pidfile."); 216 } 217 #endif /* __FreeBSD__ */ 218 219 if (os_daemon(0, 0)) { 220 perror("daemon"); 221 #ifdef __FreeBSD__ 222 pidfile_remove(pfh); 223 #endif /* __FreeBSD__ */ 224 return -1; 225 } 226 227 #ifndef __FreeBSD__ 228 if (pid_file) { 229 FILE *f = fopen(pid_file, "w"); 230 if (f) { 231 fprintf(f, "%u\n", getpid()); 232 fclose(f); 233 } 234 } 235 #else /* __FreeBSD__ */ 236 pidfile_write(pfh); 237 #endif /* __FreeBSD__ */ 238 239 return -0; 240 #endif /* defined(__uClinux__) || defined(__sun__) */ 241 } 242 243 244 void os_daemonize_terminate(const char *pid_file) 245 { 246 if (pid_file) 247 unlink(pid_file); 248 } 249 250 251 int os_get_random(unsigned char *buf, size_t len) 252 { 253 FILE *f; 254 size_t rc; 255 256 f = fopen("/dev/urandom", "rb"); 257 if (f == NULL) { 258 printf("Could not open /dev/urandom.\n"); 259 return -1; 260 } 261 262 rc = fread(buf, 1, len, f); 263 fclose(f); 264 265 return rc != len ? -1 : 0; 266 } 267 268 269 unsigned long os_random(void) 270 { 271 return random(); 272 } 273 274 275 char * os_rel2abs_path(const char *rel_path) 276 { 277 char *buf = NULL, *cwd, *ret; 278 size_t len = 128, cwd_len, rel_len, ret_len; 279 int last_errno; 280 281 if (!rel_path) 282 return NULL; 283 284 if (rel_path[0] == '/') 285 return os_strdup(rel_path); 286 287 for (;;) { 288 buf = os_malloc(len); 289 if (buf == NULL) 290 return NULL; 291 cwd = getcwd(buf, len); 292 if (cwd == NULL) { 293 last_errno = errno; 294 os_free(buf); 295 if (last_errno != ERANGE) 296 return NULL; 297 len *= 2; 298 if (len > 2000) 299 return NULL; 300 } else { 301 buf[len - 1] = '\0'; 302 break; 303 } 304 } 305 306 cwd_len = os_strlen(cwd); 307 rel_len = os_strlen(rel_path); 308 ret_len = cwd_len + 1 + rel_len + 1; 309 ret = os_malloc(ret_len); 310 if (ret) { 311 os_memcpy(ret, cwd, cwd_len); 312 ret[cwd_len] = '/'; 313 os_memcpy(ret + cwd_len + 1, rel_path, rel_len); 314 ret[ret_len - 1] = '\0'; 315 } 316 os_free(buf); 317 return ret; 318 } 319 320 321 int os_program_init(void) 322 { 323 #ifdef ANDROID 324 /* 325 * We ignore errors here since errors are normal if we 326 * are already running as non-root. 327 */ 328 #ifdef ANDROID_SETGROUPS_OVERRIDE 329 gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE }; 330 #else /* ANDROID_SETGROUPS_OVERRIDE */ 331 gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE }; 332 #endif /* ANDROID_SETGROUPS_OVERRIDE */ 333 struct __user_cap_header_struct header; 334 struct __user_cap_data_struct cap; 335 336 setgroups(ARRAY_SIZE(groups), groups); 337 338 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); 339 340 setgid(AID_WIFI); 341 setuid(AID_WIFI); 342 343 header.version = _LINUX_CAPABILITY_VERSION; 344 header.pid = 0; 345 cap.effective = cap.permitted = 346 (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW); 347 cap.inheritable = 0; 348 capset(&header, &cap); 349 #endif /* ANDROID */ 350 351 return 0; 352 } 353 354 355 void os_program_deinit(void) 356 { 357 #ifdef WPA_TRACE 358 struct os_alloc_trace *a; 359 unsigned long total = 0; 360 dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) { 361 total += a->len; 362 if (a->magic != ALLOC_MAGIC) { 363 wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x " 364 "len %lu", 365 a, a->magic, (unsigned long) a->len); 366 continue; 367 } 368 wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu", 369 a, (unsigned long) a->len); 370 wpa_trace_dump("memleak", a); 371 } 372 if (total) 373 wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes", 374 (unsigned long) total); 375 #endif /* WPA_TRACE */ 376 } 377 378 379 int os_setenv(const char *name, const char *value, int overwrite) 380 { 381 return setenv(name, value, overwrite); 382 } 383 384 385 int os_unsetenv(const char *name) 386 { 387 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \ 388 defined(__OpenBSD__) 389 unsetenv(name); 390 return 0; 391 #else 392 return unsetenv(name); 393 #endif 394 } 395 396 397 char * os_readfile(const char *name, size_t *len) 398 { 399 FILE *f; 400 char *buf; 401 long pos; 402 403 f = fopen(name, "rb"); 404 if (f == NULL) 405 return NULL; 406 407 if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) { 408 fclose(f); 409 return NULL; 410 } 411 *len = pos; 412 if (fseek(f, 0, SEEK_SET) < 0) { 413 fclose(f); 414 return NULL; 415 } 416 417 buf = os_malloc(*len); 418 if (buf == NULL) { 419 fclose(f); 420 return NULL; 421 } 422 423 if (fread(buf, 1, *len, f) != *len) { 424 fclose(f); 425 os_free(buf); 426 return NULL; 427 } 428 429 fclose(f); 430 431 return buf; 432 } 433 434 435 int os_file_exists(const char *fname) 436 { 437 FILE *f = fopen(fname, "rb"); 438 if (f == NULL) 439 return 0; 440 fclose(f); 441 return 1; 442 } 443 444 445 #ifndef WPA_TRACE 446 void * os_zalloc(size_t size) 447 { 448 return calloc(1, size); 449 } 450 #endif /* WPA_TRACE */ 451 452 453 size_t os_strlcpy(char *dest, const char *src, size_t siz) 454 { 455 const char *s = src; 456 size_t left = siz; 457 458 if (left) { 459 /* Copy string up to the maximum size of the dest buffer */ 460 while (--left != 0) { 461 if ((*dest++ = *s++) == '\0') 462 break; 463 } 464 } 465 466 if (left == 0) { 467 /* Not enough room for the string; force NUL-termination */ 468 if (siz != 0) 469 *dest = '\0'; 470 while (*s++) 471 ; /* determine total src string length */ 472 } 473 474 return s - src - 1; 475 } 476 477 478 int os_memcmp_const(const void *a, const void *b, size_t len) 479 { 480 const u8 *aa = a; 481 const u8 *bb = b; 482 size_t i; 483 u8 res; 484 485 for (res = 0, i = 0; i < len; i++) 486 res |= aa[i] ^ bb[i]; 487 488 return res; 489 } 490 491 492 #ifdef WPA_TRACE 493 494 #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) 495 char wpa_trace_fail_func[256] = { 0 }; 496 unsigned int wpa_trace_fail_after; 497 498 static int testing_fail_alloc(void) 499 { 500 const char *func[WPA_TRACE_LEN]; 501 size_t i, res, len; 502 char *pos, *next; 503 int match; 504 505 if (!wpa_trace_fail_after) 506 return 0; 507 508 res = wpa_trace_calling_func(func, WPA_TRACE_LEN); 509 i = 0; 510 if (i < res && os_strcmp(func[i], __func__) == 0) 511 i++; 512 if (i < res && os_strcmp(func[i], "os_malloc") == 0) 513 i++; 514 if (i < res && os_strcmp(func[i], "os_zalloc") == 0) 515 i++; 516 if (i < res && os_strcmp(func[i], "os_calloc") == 0) 517 i++; 518 if (i < res && os_strcmp(func[i], "os_realloc") == 0) 519 i++; 520 if (i < res && os_strcmp(func[i], "os_realloc_array") == 0) 521 i++; 522 if (i < res && os_strcmp(func[i], "os_strdup") == 0) 523 i++; 524 525 pos = wpa_trace_fail_func; 526 527 match = 0; 528 while (i < res) { 529 int allow_skip = 1; 530 int maybe = 0; 531 532 if (*pos == '=') { 533 allow_skip = 0; 534 pos++; 535 } else if (*pos == '?') { 536 maybe = 1; 537 pos++; 538 } 539 next = os_strchr(pos, ';'); 540 if (next) 541 len = next - pos; 542 else 543 len = os_strlen(pos); 544 if (os_memcmp(pos, func[i], len) != 0) { 545 if (maybe && next) { 546 pos = next + 1; 547 continue; 548 } 549 if (allow_skip) { 550 i++; 551 continue; 552 } 553 return 0; 554 } 555 if (!next) { 556 match = 1; 557 break; 558 } 559 pos = next + 1; 560 i++; 561 } 562 if (!match) 563 return 0; 564 565 wpa_trace_fail_after--; 566 if (wpa_trace_fail_after == 0) { 567 wpa_printf(MSG_INFO, "TESTING: fail allocation at %s", 568 wpa_trace_fail_func); 569 for (i = 0; i < res; i++) 570 wpa_printf(MSG_INFO, "backtrace[%d] = %s", 571 (int) i, func[i]); 572 return 1; 573 } 574 575 return 0; 576 } 577 578 #else 579 580 static inline int testing_fail_alloc(void) 581 { 582 return 0; 583 } 584 #endif 585 586 void * os_malloc(size_t size) 587 { 588 struct os_alloc_trace *a; 589 590 if (testing_fail_alloc()) 591 return NULL; 592 593 a = malloc(sizeof(*a) + size); 594 if (a == NULL) 595 return NULL; 596 a->magic = ALLOC_MAGIC; 597 dl_list_add(&alloc_list, &a->list); 598 a->len = size; 599 wpa_trace_record(a); 600 return a + 1; 601 } 602 603 604 void * os_realloc(void *ptr, size_t size) 605 { 606 struct os_alloc_trace *a; 607 size_t copy_len; 608 void *n; 609 610 if (ptr == NULL) 611 return os_malloc(size); 612 613 a = (struct os_alloc_trace *) ptr - 1; 614 if (a->magic != ALLOC_MAGIC) { 615 wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s", 616 a, a->magic, 617 a->magic == FREED_MAGIC ? " (already freed)" : ""); 618 wpa_trace_show("Invalid os_realloc() call"); 619 abort(); 620 } 621 n = os_malloc(size); 622 if (n == NULL) 623 return NULL; 624 copy_len = a->len; 625 if (copy_len > size) 626 copy_len = size; 627 os_memcpy(n, a + 1, copy_len); 628 os_free(ptr); 629 return n; 630 } 631 632 633 void os_free(void *ptr) 634 { 635 struct os_alloc_trace *a; 636 637 if (ptr == NULL) 638 return; 639 a = (struct os_alloc_trace *) ptr - 1; 640 if (a->magic != ALLOC_MAGIC) { 641 wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s", 642 a, a->magic, 643 a->magic == FREED_MAGIC ? " (already freed)" : ""); 644 wpa_trace_show("Invalid os_free() call"); 645 abort(); 646 } 647 dl_list_del(&a->list); 648 a->magic = FREED_MAGIC; 649 650 wpa_trace_check_ref(ptr); 651 free(a); 652 } 653 654 655 void * os_zalloc(size_t size) 656 { 657 void *ptr = os_malloc(size); 658 if (ptr) 659 os_memset(ptr, 0, size); 660 return ptr; 661 } 662 663 664 char * os_strdup(const char *s) 665 { 666 size_t len; 667 char *d; 668 len = os_strlen(s); 669 d = os_malloc(len + 1); 670 if (d == NULL) 671 return NULL; 672 os_memcpy(d, s, len); 673 d[len] = '\0'; 674 return d; 675 } 676 677 #endif /* WPA_TRACE */ 678 679 680 int os_exec(const char *program, const char *arg, int wait_completion) 681 { 682 pid_t pid; 683 int pid_status; 684 685 pid = fork(); 686 if (pid < 0) { 687 perror("fork"); 688 return -1; 689 } 690 691 if (pid == 0) { 692 /* run the external command in the child process */ 693 const int MAX_ARG = 30; 694 char *_program, *_arg, *pos; 695 char *argv[MAX_ARG + 1]; 696 int i; 697 698 _program = os_strdup(program); 699 _arg = os_strdup(arg); 700 701 argv[0] = _program; 702 703 i = 1; 704 pos = _arg; 705 while (i < MAX_ARG && pos && *pos) { 706 while (*pos == ' ') 707 pos++; 708 if (*pos == '\0') 709 break; 710 argv[i++] = pos; 711 pos = os_strchr(pos, ' '); 712 if (pos) 713 *pos++ = '\0'; 714 } 715 argv[i] = NULL; 716 717 execv(program, argv); 718 perror("execv"); 719 os_free(_program); 720 os_free(_arg); 721 exit(0); 722 return -1; 723 } 724 725 if (wait_completion) { 726 /* wait for the child process to complete in the parent */ 727 waitpid(pid, &pid_status, 0); 728 } 729 730 return 0; 731 } 732