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