1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2 /* dbus-sysdeps.c Wrappers around system/libc features shared between UNIX and Windows (internal to D-Bus implementation) 3 * 4 * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. 5 * Copyright (C) 2003 CodeFactory AB 6 * 7 * Licensed under the Academic Free License version 2.1 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25 #include <config.h> 26 #include "dbus-internals.h" 27 #include "dbus-sysdeps.h" 28 #include "dbus-threads.h" 29 #include "dbus-protocol.h" 30 #include "dbus-string.h" 31 #include "dbus-list.h" 32 33 /* NOTE: If you include any unix/windows-specific headers here, you are probably doing something 34 * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c. 35 * 36 * These are the standard ANSI C headers... 37 */ 38 #if HAVE_LOCALE_H 39 #include <locale.h> 40 #endif 41 #include <stdlib.h> 42 #include <string.h> 43 #include <stdio.h> 44 45 #ifdef HAVE_ERRNO_H 46 #include <errno.h> 47 #endif 48 49 _DBUS_DEFINE_GLOBAL_LOCK (win_fds); 50 _DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache); 51 _DBUS_DEFINE_GLOBAL_LOCK (system_users); 52 53 #ifdef DBUS_WIN 54 #include <stdlib.h> 55 #elif (defined __APPLE__) 56 # include <crt_externs.h> 57 # define environ (*_NSGetEnviron()) 58 #else 59 extern char **environ; 60 #endif 61 62 /** 63 * @defgroup DBusSysdeps Internal system-dependent API 64 * @ingroup DBusInternals 65 * @brief Internal system-dependent API available on UNIX and Windows 66 * 67 * The system-dependent API has a dual purpose. First, it encapsulates 68 * all usage of operating system APIs for ease of auditing and to 69 * avoid cluttering the rest of the code with bizarre OS quirks and 70 * headers. Second, it abstracts different operating system APIs for 71 * portability. 72 * 73 * @{ 74 */ 75 76 /** 77 * Aborts the program with SIGABRT (dumping core). 78 */ 79 void 80 _dbus_abort (void) 81 { 82 const char *s; 83 84 _dbus_print_backtrace (); 85 86 s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT"); 87 if (s && *s) 88 { 89 /* don't use _dbus_warn here since it can _dbus_abort() */ 90 fprintf (stderr, " Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ()); 91 _dbus_sleep_milliseconds (1000 * 180); 92 } 93 94 abort (); 95 _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */ 96 } 97 98 /** 99 * Wrapper for setenv(). If the value is #NULL, unsets 100 * the environment variable. 101 * 102 * There is an unfixable memleak in that it is unsafe to 103 * free memory malloced for use with setenv. This is because 104 * we can not rely on internal implementation details of 105 * the underlying libc library. 106 * 107 * @param varname name of environment variable 108 * @param value value of environment variable 109 * @returns #TRUE on success. 110 */ 111 dbus_bool_t 112 _dbus_setenv (const char *varname, 113 const char *value) 114 { 115 _dbus_assert (varname != NULL); 116 117 if (value == NULL) 118 { 119 #ifdef HAVE_UNSETENV 120 unsetenv (varname); 121 return TRUE; 122 #else 123 char *putenv_value; 124 size_t len; 125 126 len = strlen (varname); 127 128 /* Use system malloc to avoid memleaks that dbus_malloc 129 * will get upset about. 130 */ 131 132 putenv_value = malloc (len + 2); 133 if (putenv_value == NULL) 134 return FALSE; 135 136 strcpy (putenv_value, varname); 137 #if defined(DBUS_WIN) 138 strcat (putenv_value, "="); 139 #endif 140 141 return (putenv (putenv_value) == 0); 142 #endif 143 } 144 else 145 { 146 #ifdef HAVE_SETENV 147 return (setenv (varname, value, TRUE) == 0); 148 #else 149 char *putenv_value; 150 size_t len; 151 size_t varname_len; 152 size_t value_len; 153 154 varname_len = strlen (varname); 155 value_len = strlen (value); 156 157 len = varname_len + value_len + 1 /* '=' */ ; 158 159 /* Use system malloc to avoid memleaks that dbus_malloc 160 * will get upset about. 161 */ 162 163 putenv_value = malloc (len + 1); 164 if (putenv_value == NULL) 165 return FALSE; 166 167 strcpy (putenv_value, varname); 168 strcpy (putenv_value + varname_len, "="); 169 strcpy (putenv_value + varname_len + 1, value); 170 171 return (putenv (putenv_value) == 0); 172 #endif 173 } 174 } 175 176 /** 177 * Wrapper for getenv(). 178 * 179 * @param varname name of environment variable 180 * @returns value of environment variable or #NULL if unset 181 */ 182 const char* 183 _dbus_getenv (const char *varname) 184 { 185 /* Don't respect any environment variables if the current process is 186 * setuid. This is the equivalent of glibc's __secure_getenv(). 187 */ 188 if (_dbus_check_setuid ()) 189 return NULL; 190 return getenv (varname); 191 } 192 193 /** 194 * Wrapper for clearenv(). 195 * 196 * @returns #TRUE on success. 197 */ 198 dbus_bool_t 199 _dbus_clearenv (void) 200 { 201 dbus_bool_t rc = TRUE; 202 203 #ifdef HAVE_CLEARENV 204 if (clearenv () != 0) 205 rc = FALSE; 206 #else 207 208 if (environ != NULL) 209 environ[0] = NULL; 210 #endif 211 212 return rc; 213 } 214 215 /** 216 * Split paths into a list of char strings 217 * 218 * @param dirs string with pathes 219 * @param suffix string concated to each path in dirs 220 * @param dir_list contains a list of splitted pathes 221 * return #TRUE is pathes could be splittes,#FALSE in oom case 222 */ 223 dbus_bool_t 224 _dbus_split_paths_and_append (DBusString *dirs, 225 const char *suffix, 226 DBusList **dir_list) 227 { 228 int start; 229 int i; 230 int len; 231 char *cpath; 232 DBusString file_suffix; 233 234 start = 0; 235 i = 0; 236 237 _dbus_string_init_const (&file_suffix, suffix); 238 239 len = _dbus_string_get_length (dirs); 240 241 while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i)) 242 { 243 DBusString path; 244 245 if (!_dbus_string_init (&path)) 246 goto oom; 247 248 if (!_dbus_string_copy_len (dirs, 249 start, 250 i - start, 251 &path, 252 0)) 253 { 254 _dbus_string_free (&path); 255 goto oom; 256 } 257 258 _dbus_string_chop_white (&path); 259 260 /* check for an empty path */ 261 if (_dbus_string_get_length (&path) == 0) 262 goto next; 263 264 if (!_dbus_concat_dir_and_file (&path, 265 &file_suffix)) 266 { 267 _dbus_string_free (&path); 268 goto oom; 269 } 270 271 if (!_dbus_string_copy_data(&path, &cpath)) 272 { 273 _dbus_string_free (&path); 274 goto oom; 275 } 276 277 if (!_dbus_list_append (dir_list, cpath)) 278 { 279 _dbus_string_free (&path); 280 dbus_free (cpath); 281 goto oom; 282 } 283 284 next: 285 _dbus_string_free (&path); 286 start = i + 1; 287 } 288 289 if (start != len) 290 { 291 DBusString path; 292 293 if (!_dbus_string_init (&path)) 294 goto oom; 295 296 if (!_dbus_string_copy_len (dirs, 297 start, 298 len - start, 299 &path, 300 0)) 301 { 302 _dbus_string_free (&path); 303 goto oom; 304 } 305 306 if (!_dbus_concat_dir_and_file (&path, 307 &file_suffix)) 308 { 309 _dbus_string_free (&path); 310 goto oom; 311 } 312 313 if (!_dbus_string_copy_data(&path, &cpath)) 314 { 315 _dbus_string_free (&path); 316 goto oom; 317 } 318 319 if (!_dbus_list_append (dir_list, cpath)) 320 { 321 _dbus_string_free (&path); 322 dbus_free (cpath); 323 goto oom; 324 } 325 326 _dbus_string_free (&path); 327 } 328 329 return TRUE; 330 331 oom: 332 _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); 333 _dbus_list_clear (dir_list); 334 return FALSE; 335 } 336 337 /** @} */ 338 339 /** 340 * @addtogroup DBusString 341 * 342 * @{ 343 */ 344 /** 345 * Appends an integer to a DBusString. 346 * 347 * @param str the string 348 * @param value the integer value 349 * @returns #FALSE if not enough memory or other failure. 350 */ 351 dbus_bool_t 352 _dbus_string_append_int (DBusString *str, 353 long value) 354 { 355 /* this calculation is from comp.lang.c faq */ 356 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1) /* +1 for '-' */ 357 int orig_len; 358 int i; 359 char *buf; 360 361 orig_len = _dbus_string_get_length (str); 362 363 if (!_dbus_string_lengthen (str, MAX_LONG_LEN)) 364 return FALSE; 365 366 buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN); 367 368 snprintf (buf, MAX_LONG_LEN, "%ld", value); 369 370 i = 0; 371 while (*buf) 372 { 373 ++buf; 374 ++i; 375 } 376 377 _dbus_string_shorten (str, MAX_LONG_LEN - i); 378 379 return TRUE; 380 } 381 382 /** 383 * Appends an unsigned integer to a DBusString. 384 * 385 * @param str the string 386 * @param value the integer value 387 * @returns #FALSE if not enough memory or other failure. 388 */ 389 dbus_bool_t 390 _dbus_string_append_uint (DBusString *str, 391 unsigned long value) 392 { 393 /* this is wrong, but definitely on the high side. */ 394 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2) 395 int orig_len; 396 int i; 397 char *buf; 398 399 orig_len = _dbus_string_get_length (str); 400 401 if (!_dbus_string_lengthen (str, MAX_ULONG_LEN)) 402 return FALSE; 403 404 buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN); 405 406 snprintf (buf, MAX_ULONG_LEN, "%lu", value); 407 408 i = 0; 409 while (*buf) 410 { 411 ++buf; 412 ++i; 413 } 414 415 _dbus_string_shorten (str, MAX_ULONG_LEN - i); 416 417 return TRUE; 418 } 419 420 /** 421 * Parses an integer contained in a DBusString. Either return parameter 422 * may be #NULL if you aren't interested in it. The integer is parsed 423 * and stored in value_return. Return parameters are not initialized 424 * if the function returns #FALSE. 425 * 426 * @param str the string 427 * @param start the byte index of the start of the integer 428 * @param value_return return location of the integer value or #NULL 429 * @param end_return return location of the end of the integer, or #NULL 430 * @returns #TRUE on success 431 */ 432 dbus_bool_t 433 _dbus_string_parse_int (const DBusString *str, 434 int start, 435 long *value_return, 436 int *end_return) 437 { 438 long v; 439 const char *p; 440 char *end; 441 442 p = _dbus_string_get_const_data_len (str, start, 443 _dbus_string_get_length (str) - start); 444 445 end = NULL; 446 _dbus_set_errno_to_zero (); 447 v = strtol (p, &end, 0); 448 if (end == NULL || end == p || errno != 0) 449 return FALSE; 450 451 if (value_return) 452 *value_return = v; 453 if (end_return) 454 *end_return = start + (end - p); 455 456 return TRUE; 457 } 458 459 /** 460 * Parses an unsigned integer contained in a DBusString. Either return 461 * parameter may be #NULL if you aren't interested in it. The integer 462 * is parsed and stored in value_return. Return parameters are not 463 * initialized if the function returns #FALSE. 464 * 465 * @param str the string 466 * @param start the byte index of the start of the integer 467 * @param value_return return location of the integer value or #NULL 468 * @param end_return return location of the end of the integer, or #NULL 469 * @returns #TRUE on success 470 */ 471 dbus_bool_t 472 _dbus_string_parse_uint (const DBusString *str, 473 int start, 474 unsigned long *value_return, 475 int *end_return) 476 { 477 unsigned long v; 478 const char *p; 479 char *end; 480 481 p = _dbus_string_get_const_data_len (str, start, 482 _dbus_string_get_length (str) - start); 483 484 end = NULL; 485 _dbus_set_errno_to_zero (); 486 v = strtoul (p, &end, 0); 487 if (end == NULL || end == p || errno != 0) 488 return FALSE; 489 490 if (value_return) 491 *value_return = v; 492 if (end_return) 493 *end_return = start + (end - p); 494 495 return TRUE; 496 } 497 498 /** @} */ /* DBusString group */ 499 500 /** 501 * @addtogroup DBusInternalsUtils 502 * @{ 503 */ 504 505 void 506 _dbus_generate_pseudorandom_bytes_buffer (char *buffer, 507 int n_bytes) 508 { 509 long tv_usec; 510 int i; 511 512 /* fall back to pseudorandom */ 513 _dbus_verbose ("Falling back to pseudorandom for %d bytes\n", 514 n_bytes); 515 516 _dbus_get_real_time (NULL, &tv_usec); 517 srand (tv_usec); 518 519 i = 0; 520 while (i < n_bytes) 521 { 522 double r; 523 unsigned int b; 524 525 r = rand (); 526 b = (r / (double) RAND_MAX) * 255.0; 527 528 buffer[i] = b; 529 530 ++i; 531 } 532 } 533 534 /** 535 * Fills n_bytes of the given buffer with random bytes. 536 * 537 * @param buffer an allocated buffer 538 * @param n_bytes the number of bytes in buffer to write to 539 */ 540 void 541 _dbus_generate_random_bytes_buffer (char *buffer, 542 int n_bytes) 543 { 544 DBusString str; 545 546 if (!_dbus_string_init (&str)) 547 { 548 _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes); 549 return; 550 } 551 552 if (!_dbus_generate_random_bytes (&str, n_bytes)) 553 { 554 _dbus_string_free (&str); 555 _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes); 556 return; 557 } 558 559 _dbus_string_copy_to_buffer (&str, buffer, n_bytes); 560 561 _dbus_string_free (&str); 562 } 563 564 /** 565 * Generates the given number of random bytes, where the bytes are 566 * chosen from the alphanumeric ASCII subset. 567 * 568 * @param str the string 569 * @param n_bytes the number of random ASCII bytes to append to string 570 * @returns #TRUE on success, #FALSE if no memory or other failure 571 */ 572 dbus_bool_t 573 _dbus_generate_random_ascii (DBusString *str, 574 int n_bytes) 575 { 576 static const char letters[] = 577 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; 578 int i; 579 int len; 580 581 if (!_dbus_generate_random_bytes (str, n_bytes)) 582 return FALSE; 583 584 len = _dbus_string_get_length (str); 585 i = len - n_bytes; 586 while (i < len) 587 { 588 _dbus_string_set_byte (str, i, 589 letters[_dbus_string_get_byte (str, i) % 590 (sizeof (letters) - 1)]); 591 592 ++i; 593 } 594 595 _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes, 596 n_bytes)); 597 598 return TRUE; 599 } 600 601 /** 602 * Converts a UNIX errno, or Windows errno or WinSock error value into 603 * a #DBusError name. 604 * 605 * @todo should cover more errnos, specifically those 606 * from open(). 607 * 608 * @param error_number the errno. 609 * @returns an error name 610 */ 611 const char* 612 _dbus_error_from_errno (int error_number) 613 { 614 switch (error_number) 615 { 616 case 0: 617 return DBUS_ERROR_FAILED; 618 619 #ifdef EPROTONOSUPPORT 620 case EPROTONOSUPPORT: 621 return DBUS_ERROR_NOT_SUPPORTED; 622 #elif defined(WSAEPROTONOSUPPORT) 623 case WSAEPROTONOSUPPORT: 624 return DBUS_ERROR_NOT_SUPPORTED; 625 #endif 626 #ifdef EAFNOSUPPORT 627 case EAFNOSUPPORT: 628 return DBUS_ERROR_NOT_SUPPORTED; 629 #elif defined(WSAEAFNOSUPPORT) 630 case WSAEAFNOSUPPORT: 631 return DBUS_ERROR_NOT_SUPPORTED; 632 #endif 633 #ifdef ENFILE 634 case ENFILE: 635 return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */ 636 #endif 637 #ifdef EMFILE 638 case EMFILE: 639 return DBUS_ERROR_LIMITS_EXCEEDED; 640 #endif 641 #ifdef EACCES 642 case EACCES: 643 return DBUS_ERROR_ACCESS_DENIED; 644 #endif 645 #ifdef EPERM 646 case EPERM: 647 return DBUS_ERROR_ACCESS_DENIED; 648 #endif 649 #ifdef ENOBUFS 650 case ENOBUFS: 651 return DBUS_ERROR_NO_MEMORY; 652 #endif 653 #ifdef ENOMEM 654 case ENOMEM: 655 return DBUS_ERROR_NO_MEMORY; 656 #endif 657 #ifdef ECONNREFUSED 658 case ECONNREFUSED: 659 return DBUS_ERROR_NO_SERVER; 660 #elif defined(WSAECONNREFUSED) 661 case WSAECONNREFUSED: 662 return DBUS_ERROR_NO_SERVER; 663 #endif 664 #ifdef ETIMEDOUT 665 case ETIMEDOUT: 666 return DBUS_ERROR_TIMEOUT; 667 #elif defined(WSAETIMEDOUT) 668 case WSAETIMEDOUT: 669 return DBUS_ERROR_TIMEOUT; 670 #endif 671 #ifdef ENETUNREACH 672 case ENETUNREACH: 673 return DBUS_ERROR_NO_NETWORK; 674 #elif defined(WSAENETUNREACH) 675 case WSAENETUNREACH: 676 return DBUS_ERROR_NO_NETWORK; 677 #endif 678 #ifdef EADDRINUSE 679 case EADDRINUSE: 680 return DBUS_ERROR_ADDRESS_IN_USE; 681 #elif defined(WSAEADDRINUSE) 682 case WSAEADDRINUSE: 683 return DBUS_ERROR_ADDRESS_IN_USE; 684 #endif 685 #ifdef EEXIST 686 case EEXIST: 687 return DBUS_ERROR_FILE_EXISTS; 688 #endif 689 #ifdef ENOENT 690 case ENOENT: 691 return DBUS_ERROR_FILE_NOT_FOUND; 692 #endif 693 } 694 695 return DBUS_ERROR_FAILED; 696 } 697 698 /** 699 * Converts the current system errno value into a #DBusError name. 700 * 701 * @returns an error name 702 */ 703 const char* 704 _dbus_error_from_system_errno (void) 705 { 706 return _dbus_error_from_errno (errno); 707 } 708 709 /** 710 * Assign 0 to the global errno variable 711 */ 712 void 713 _dbus_set_errno_to_zero (void) 714 { 715 #ifdef DBUS_WINCE 716 SetLastError (0); 717 #else 718 errno = 0; 719 #endif 720 } 721 722 /** 723 * See if errno is set 724 * @returns #TRUE if errno is not 0 725 */ 726 dbus_bool_t 727 _dbus_get_is_errno_nonzero (void) 728 { 729 return errno != 0; 730 } 731 732 /** 733 * See if errno is ENOMEM 734 * @returns #TRUE if errno == ENOMEM 735 */ 736 dbus_bool_t 737 _dbus_get_is_errno_enomem (void) 738 { 739 return errno == ENOMEM; 740 } 741 742 /** 743 * See if errno is EINTR 744 * @returns #TRUE if errno == EINTR 745 */ 746 dbus_bool_t 747 _dbus_get_is_errno_eintr (void) 748 { 749 return errno == EINTR; 750 } 751 752 /** 753 * See if errno is EPIPE 754 * @returns #TRUE if errno == EPIPE 755 */ 756 dbus_bool_t 757 _dbus_get_is_errno_epipe (void) 758 { 759 return errno == EPIPE; 760 } 761 762 /** 763 * Get error message from errno 764 * @returns _dbus_strerror(errno) 765 */ 766 const char* 767 _dbus_strerror_from_errno (void) 768 { 769 return _dbus_strerror (errno); 770 } 771 772 /** @} end of sysdeps */ 773 774 /* tests in dbus-sysdeps-util.c */ 775