Home | History | Annotate | Download | only in dbus
      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