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