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