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
_dbus_abort(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
_dbus_setenv(const char * varname,const char * value)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*
_dbus_getenv(const char * varname)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
_dbus_clearenv(void)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
_dbus_split_paths_and_append(DBusString * dirs,const char * suffix,DBusList ** dir_list)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
_dbus_string_append_int(DBusString * str,long value)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
_dbus_string_append_uint(DBusString * str,unsigned long value)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
_dbus_string_parse_int(const DBusString * str,int start,long * value_return,int * end_return)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
_dbus_string_parse_uint(const DBusString * str,int start,unsigned long * value_return,int * end_return)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
_dbus_generate_pseudorandom_bytes_buffer(char * buffer,int n_bytes)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
_dbus_generate_random_bytes_buffer(char * buffer,int n_bytes)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
_dbus_generate_random_ascii(DBusString * str,int n_bytes)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*
_dbus_error_from_errno(int error_number)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*
_dbus_error_from_system_errno(void)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
_dbus_set_errno_to_zero(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
_dbus_get_is_errno_nonzero(void)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
_dbus_get_is_errno_enomem(void)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
_dbus_get_is_errno_eintr(void)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
_dbus_get_is_errno_epipe(void)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*
_dbus_strerror_from_errno(void)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