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