• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-file-style: "gnu" -*- */
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24 
25 #include "dbus-internals.h"
26 #include "dbus-sysdeps.h"
27 #include "dbus-threads.h"
28 #include "dbus-protocol.h"
29 #include "dbus-string.h"
30 
31 /* NOTE: If you include any unix/windows-specific headers here, you are probably doing something
32  * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c.
33  *
34  * These are the standard ANSI C headers...
35  */
36 #include <locale.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdio.h>
40 
41 /* This is UNIX-specific (on windows it's just in stdlib.h I believe)
42  * but OK since the same stuff does exist on Windows in stdlib.h
43  * and covered by a configure check.
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 
52 /**
53  * @defgroup DBusSysdeps Internal system-dependent API
54  * @ingroup DBusInternals
55  * @brief Internal system-dependent API available on UNIX and Windows
56  *
57  * The system-dependent API has a dual purpose. First, it encapsulates
58  * all usage of operating system APIs for ease of auditing and to
59  * avoid cluttering the rest of the code with bizarre OS quirks and
60  * headers. Second, it abstracts different operating system APIs for
61  * portability.
62  *
63  * @{
64  */
65 
66 /**
67  * Aborts the program with SIGABRT (dumping core).
68  */
69 void
_dbus_abort(void)70 _dbus_abort (void)
71 {
72   const char *s;
73 
74   _dbus_print_backtrace ();
75 
76   s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT");
77   if (s && *s)
78     {
79       /* don't use _dbus_warn here since it can _dbus_abort() */
80       fprintf (stderr, "  Process %lu sleeping for gdb attach\n", (unsigned long) _dbus_getpid());
81       _dbus_sleep_milliseconds (1000 * 180);
82     }
83 
84   abort ();
85   _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */
86 }
87 
88 /**
89  * Wrapper for setenv(). If the value is #NULL, unsets
90  * the environment variable.
91  *
92  * There is an unfixable memleak in that it is unsafe to
93  * free memory malloced for use with setenv. This is because
94  * we can not rely on internal implementation details of
95  * the underlying libc library.
96  *
97  * @param varname name of environment variable
98  * @param value value of environment variable
99  * @returns #TRUE on success.
100  */
101 dbus_bool_t
_dbus_setenv(const char * varname,const char * value)102 _dbus_setenv (const char *varname,
103               const char *value)
104 {
105   _dbus_assert (varname != NULL);
106 
107   if (value == NULL)
108     {
109 #ifdef HAVE_UNSETENV
110       unsetenv (varname);
111       return TRUE;
112 #else
113       char *putenv_value;
114       size_t len;
115 
116       len = strlen (varname);
117 
118       /* Use system malloc to avoid memleaks that dbus_malloc
119        * will get upset about.
120        */
121 
122       putenv_value = malloc (len + 1);
123       if (putenv_value == NULL)
124         return FALSE;
125 
126       strcpy (putenv_value, varname);
127 
128       return (putenv (putenv_value) == 0);
129 #endif
130     }
131   else
132     {
133 #ifdef HAVE_SETENV
134       return (setenv (varname, value, TRUE) == 0);
135 #else
136       char *putenv_value;
137       size_t len;
138       size_t varname_len;
139       size_t value_len;
140 
141       varname_len = strlen (varname);
142       value_len = strlen (value);
143 
144       len = varname_len + value_len + 1 /* '=' */ ;
145 
146       /* Use system malloc to avoid memleaks that dbus_malloc
147        * will get upset about.
148        */
149 
150       putenv_value = malloc (len + 1);
151       if (putenv_value == NULL)
152         return FALSE;
153 
154       strcpy (putenv_value, varname);
155       strcpy (putenv_value + varname_len, "=");
156       strcpy (putenv_value + varname_len + 1, value);
157 
158       return (putenv (putenv_value) == 0);
159 #endif
160     }
161 }
162 
163 /**
164  * Wrapper for getenv().
165  *
166  * @param varname name of environment variable
167  * @returns value of environment variable or #NULL if unset
168  */
169 const char*
_dbus_getenv(const char * varname)170 _dbus_getenv (const char *varname)
171 {
172   return getenv (varname);
173 }
174 
175 /** @} */
176 
177 /**
178  * @addtogroup DBusString
179  *
180  * @{
181  */
182 /**
183  * Appends an integer to a DBusString.
184  *
185  * @param str the string
186  * @param value the integer value
187  * @returns #FALSE if not enough memory or other failure.
188  */
189 dbus_bool_t
_dbus_string_append_int(DBusString * str,long value)190 _dbus_string_append_int (DBusString *str,
191                          long        value)
192 {
193   /* this calculation is from comp.lang.c faq */
194 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
195   int orig_len;
196   int i;
197   char *buf;
198 
199   orig_len = _dbus_string_get_length (str);
200 
201   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
202     return FALSE;
203 
204   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
205 
206   snprintf (buf, MAX_LONG_LEN, "%ld", value);
207 
208   i = 0;
209   while (*buf)
210     {
211       ++buf;
212       ++i;
213     }
214 
215   _dbus_string_shorten (str, MAX_LONG_LEN - i);
216 
217   return TRUE;
218 }
219 
220 /**
221  * Appends an unsigned integer to a DBusString.
222  *
223  * @param str the string
224  * @param value the integer value
225  * @returns #FALSE if not enough memory or other failure.
226  */
227 dbus_bool_t
_dbus_string_append_uint(DBusString * str,unsigned long value)228 _dbus_string_append_uint (DBusString    *str,
229                           unsigned long  value)
230 {
231   /* this is wrong, but definitely on the high side. */
232 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
233   int orig_len;
234   int i;
235   char *buf;
236 
237   orig_len = _dbus_string_get_length (str);
238 
239   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
240     return FALSE;
241 
242   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
243 
244   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
245 
246   i = 0;
247   while (*buf)
248     {
249       ++buf;
250       ++i;
251     }
252 
253   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
254 
255   return TRUE;
256 }
257 
258 #ifdef DBUS_BUILD_TESTS
259 /**
260  * Appends a double to a DBusString.
261  *
262  * @param str the string
263  * @param value the floating point value
264  * @returns #FALSE if not enough memory or other failure.
265  */
266 dbus_bool_t
_dbus_string_append_double(DBusString * str,double value)267 _dbus_string_append_double (DBusString *str,
268                             double      value)
269 {
270 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
271   int orig_len;
272   char *buf;
273   int i;
274 
275   orig_len = _dbus_string_get_length (str);
276 
277   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
278     return FALSE;
279 
280   buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
281 
282   snprintf (buf, MAX_LONG_LEN, "%g", value);
283 
284   i = 0;
285   while (*buf)
286     {
287       ++buf;
288       ++i;
289     }
290 
291   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
292 
293   return TRUE;
294 }
295 #endif /* DBUS_BUILD_TESTS */
296 
297 /**
298  * Parses an integer contained in a DBusString. Either return parameter
299  * may be #NULL if you aren't interested in it. The integer is parsed
300  * and stored in value_return. Return parameters are not initialized
301  * if the function returns #FALSE.
302  *
303  * @param str the string
304  * @param start the byte index of the start of the integer
305  * @param value_return return location of the integer value or #NULL
306  * @param end_return return location of the end of the integer, or #NULL
307  * @returns #TRUE on success
308  */
309 dbus_bool_t
_dbus_string_parse_int(const DBusString * str,int start,long * value_return,int * end_return)310 _dbus_string_parse_int (const DBusString *str,
311                         int               start,
312                         long             *value_return,
313                         int              *end_return)
314 {
315   long v;
316   const char *p;
317   char *end;
318 
319   p = _dbus_string_get_const_data_len (str, start,
320                                        _dbus_string_get_length (str) - start);
321 
322   end = NULL;
323   errno = 0;
324   v = strtol (p, &end, 0);
325   if (end == NULL || end == p || errno != 0)
326     return FALSE;
327 
328   if (value_return)
329     *value_return = v;
330   if (end_return)
331     *end_return = start + (end - p);
332 
333   return TRUE;
334 }
335 
336 /**
337  * Parses an unsigned integer contained in a DBusString. Either return
338  * parameter may be #NULL if you aren't interested in it. The integer
339  * is parsed and stored in value_return. Return parameters are not
340  * initialized if the function returns #FALSE.
341  *
342  * @param str the string
343  * @param start the byte index of the start of the integer
344  * @param value_return return location of the integer value or #NULL
345  * @param end_return return location of the end of the integer, or #NULL
346  * @returns #TRUE on success
347  */
348 dbus_bool_t
_dbus_string_parse_uint(const DBusString * str,int start,unsigned long * value_return,int * end_return)349 _dbus_string_parse_uint (const DBusString *str,
350                          int               start,
351                          unsigned long    *value_return,
352                          int              *end_return)
353 {
354   unsigned long v;
355   const char *p;
356   char *end;
357 
358   p = _dbus_string_get_const_data_len (str, start,
359                                        _dbus_string_get_length (str) - start);
360 
361   end = NULL;
362   errno = 0;
363   v = strtoul (p, &end, 0);
364   if (end == NULL || end == p || errno != 0)
365     return FALSE;
366 
367   if (value_return)
368     *value_return = v;
369   if (end_return)
370     *end_return = start + (end - p);
371 
372   return TRUE;
373 }
374 
375 #ifdef DBUS_BUILD_TESTS
376 static dbus_bool_t
ascii_isspace(char c)377 ascii_isspace (char c)
378 {
379   return (c == ' ' ||
380 	  c == '\f' ||
381 	  c == '\n' ||
382 	  c == '\r' ||
383 	  c == '\t' ||
384 	  c == '\v');
385 }
386 #endif /* DBUS_BUILD_TESTS */
387 
388 #ifdef DBUS_BUILD_TESTS
389 static dbus_bool_t
ascii_isdigit(char c)390 ascii_isdigit (char c)
391 {
392   return c >= '0' && c <= '9';
393 }
394 #endif /* DBUS_BUILD_TESTS */
395 
396 #ifdef DBUS_BUILD_TESTS
397 static dbus_bool_t
ascii_isxdigit(char c)398 ascii_isxdigit (char c)
399 {
400   return (ascii_isdigit (c) ||
401 	  (c >= 'a' && c <= 'f') ||
402 	  (c >= 'A' && c <= 'F'));
403 }
404 #endif /* DBUS_BUILD_TESTS */
405 
406 #ifdef DBUS_BUILD_TESTS
407 /* Calls strtod in a locale-independent fashion, by looking at
408  * the locale data and patching the decimal comma to a point.
409  *
410  * Relicensed from glib.
411  */
412 static double
ascii_strtod(const char * nptr,char ** endptr)413 ascii_strtod (const char *nptr,
414 	      char      **endptr)
415 {
416   char *fail_pos;
417   double val;
418   struct lconv *locale_data;
419   const char *decimal_point;
420   int decimal_point_len;
421   const char *p, *decimal_point_pos;
422   const char *end = NULL; /* Silence gcc */
423 
424   fail_pos = NULL;
425 
426   locale_data = localeconv ();
427   decimal_point = locale_data->decimal_point;
428   decimal_point_len = strlen (decimal_point);
429 
430   _dbus_assert (decimal_point_len != 0);
431 
432   decimal_point_pos = NULL;
433   if (decimal_point[0] != '.' ||
434       decimal_point[1] != 0)
435     {
436       p = nptr;
437       /* Skip leading space */
438       while (ascii_isspace (*p))
439 	p++;
440 
441       /* Skip leading optional sign */
442       if (*p == '+' || *p == '-')
443 	p++;
444 
445       if (p[0] == '0' &&
446 	  (p[1] == 'x' || p[1] == 'X'))
447 	{
448 	  p += 2;
449 	  /* HEX - find the (optional) decimal point */
450 
451 	  while (ascii_isxdigit (*p))
452 	    p++;
453 
454 	  if (*p == '.')
455 	    {
456 	      decimal_point_pos = p++;
457 
458 	      while (ascii_isxdigit (*p))
459 		p++;
460 
461 	      if (*p == 'p' || *p == 'P')
462 		p++;
463 	      if (*p == '+' || *p == '-')
464 		p++;
465 	      while (ascii_isdigit (*p))
466 		p++;
467 	      end = p;
468 	    }
469 	}
470       else
471 	{
472 	  while (ascii_isdigit (*p))
473 	    p++;
474 
475 	  if (*p == '.')
476 	    {
477 	      decimal_point_pos = p++;
478 
479 	      while (ascii_isdigit (*p))
480 		p++;
481 
482 	      if (*p == 'e' || *p == 'E')
483 		p++;
484 	      if (*p == '+' || *p == '-')
485 		p++;
486 	      while (ascii_isdigit (*p))
487 		p++;
488 	      end = p;
489 	    }
490 	}
491       /* For the other cases, we need not convert the decimal point */
492     }
493 
494   /* Set errno to zero, so that we can distinguish zero results
495      and underflows */
496   errno = 0;
497 
498   if (decimal_point_pos)
499     {
500       char *copy, *c;
501 
502       /* We need to convert the '.' to the locale specific decimal point */
503       copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
504 
505       c = copy;
506       memcpy (c, nptr, decimal_point_pos - nptr);
507       c += decimal_point_pos - nptr;
508       memcpy (c, decimal_point, decimal_point_len);
509       c += decimal_point_len;
510       memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
511       c += end - (decimal_point_pos + 1);
512       *c = 0;
513 
514       val = strtod (copy, &fail_pos);
515 
516       if (fail_pos)
517 	{
518 	  if (fail_pos > decimal_point_pos)
519 	    fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
520 	  else
521 	    fail_pos = (char *)nptr + (fail_pos - copy);
522 	}
523 
524       dbus_free (copy);
525 
526     }
527   else
528     val = strtod (nptr, &fail_pos);
529 
530   if (endptr)
531     *endptr = fail_pos;
532 
533   return val;
534 }
535 #endif /* DBUS_BUILD_TESTS */
536 
537 #ifdef DBUS_BUILD_TESTS
538 /**
539  * Parses a floating point number contained in a DBusString. Either
540  * return parameter may be #NULL if you aren't interested in it. The
541  * integer is parsed and stored in value_return. Return parameters are
542  * not initialized if the function returns #FALSE.
543  *
544  * @param str the string
545  * @param start the byte index of the start of the float
546  * @param value_return return location of the float value or #NULL
547  * @param end_return return location of the end of the float, or #NULL
548  * @returns #TRUE on success
549  */
550 dbus_bool_t
_dbus_string_parse_double(const DBusString * str,int start,double * value_return,int * end_return)551 _dbus_string_parse_double (const DBusString *str,
552                            int               start,
553                            double           *value_return,
554                            int              *end_return)
555 {
556   double v;
557   const char *p;
558   char *end;
559 
560   p = _dbus_string_get_const_data_len (str, start,
561                                        _dbus_string_get_length (str) - start);
562 
563   end = NULL;
564   errno = 0;
565   v = ascii_strtod (p, &end);
566   if (end == NULL || end == p || errno != 0)
567     return FALSE;
568 
569   if (value_return)
570     *value_return = v;
571   if (end_return)
572     *end_return = start + (end - p);
573 
574   return TRUE;
575 }
576 #endif /* DBUS_BUILD_TESTS */
577 
578 /** @} */ /* DBusString group */
579 
580 /**
581  * @addtogroup DBusInternalsUtils
582  * @{
583  */
584 
585 /**
586  * Frees the members of info
587  * (but not info itself)
588  * @param info the user info struct
589  */
590 void
_dbus_user_info_free(DBusUserInfo * info)591 _dbus_user_info_free (DBusUserInfo *info)
592 {
593   dbus_free (info->group_ids);
594   dbus_free (info->username);
595   dbus_free (info->homedir);
596 }
597 
598 /**
599  * Frees the members of info (but not info itself).
600  *
601  * @param info the group info
602  */
603 void
_dbus_group_info_free(DBusGroupInfo * info)604 _dbus_group_info_free (DBusGroupInfo    *info)
605 {
606   dbus_free (info->groupname);
607 }
608 
609 /**
610  * Sets fields in DBusCredentials to DBUS_PID_UNSET,
611  * DBUS_UID_UNSET, DBUS_GID_UNSET.
612  *
613  * @param credentials the credentials object to fill in
614  */
615 void
_dbus_credentials_clear(DBusCredentials * credentials)616 _dbus_credentials_clear (DBusCredentials *credentials)
617 {
618   credentials->pid = DBUS_PID_UNSET;
619   credentials->uid = DBUS_UID_UNSET;
620   credentials->gid = DBUS_GID_UNSET;
621 }
622 
623 /**
624  * Checks whether the provided_credentials are allowed to log in
625  * as the expected_credentials.
626  *
627  * @param expected_credentials credentials we're trying to log in as
628  * @param provided_credentials credentials we have
629  * @returns #TRUE if we can log in
630  */
631 dbus_bool_t
_dbus_credentials_match(const DBusCredentials * expected_credentials,const DBusCredentials * provided_credentials)632 _dbus_credentials_match (const DBusCredentials *expected_credentials,
633                          const DBusCredentials *provided_credentials)
634 {
635   if (provided_credentials->uid == DBUS_UID_UNSET)
636     return FALSE;
637   else if (expected_credentials->uid == DBUS_UID_UNSET)
638     return FALSE;
639   else if (provided_credentials->uid == 0)
640     return TRUE;
641   else if (provided_credentials->uid == expected_credentials->uid)
642     return TRUE;
643   else
644     return FALSE;
645 }
646 
647 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
648 
649 #ifdef DBUS_USE_ATOMIC_INT_486
650 /* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
651 /* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
652 static inline dbus_int32_t
atomic_exchange_and_add(DBusAtomic * atomic,volatile dbus_int32_t val)653 atomic_exchange_and_add (DBusAtomic            *atomic,
654                          volatile dbus_int32_t  val)
655 {
656   register dbus_int32_t result;
657 
658   __asm__ __volatile__ ("lock; xaddl %0,%1"
659                         : "=r" (result), "=m" (atomic->value)
660 			: "0" (val), "m" (atomic->value));
661   return result;
662 }
663 #endif
664 
665 /**
666  * Atomically increments an integer
667  *
668  * @param atomic pointer to the integer to increment
669  * @returns the value before incrementing
670  *
671  * @todo implement arch-specific faster atomic ops
672  */
673 dbus_int32_t
_dbus_atomic_inc(DBusAtomic * atomic)674 _dbus_atomic_inc (DBusAtomic *atomic)
675 {
676 #ifdef DBUS_USE_ATOMIC_INT_486
677   return atomic_exchange_and_add (atomic, 1);
678 #else
679   dbus_int32_t res;
680   _DBUS_LOCK (atomic);
681   res = atomic->value;
682   atomic->value += 1;
683   _DBUS_UNLOCK (atomic);
684   return res;
685 #endif
686 }
687 
688 /**
689  * Atomically decrement an integer
690  *
691  * @param atomic pointer to the integer to decrement
692  * @returns the value before decrementing
693  *
694  * @todo implement arch-specific faster atomic ops
695  */
696 dbus_int32_t
_dbus_atomic_dec(DBusAtomic * atomic)697 _dbus_atomic_dec (DBusAtomic *atomic)
698 {
699 #ifdef DBUS_USE_ATOMIC_INT_486
700   return atomic_exchange_and_add (atomic, -1);
701 #else
702   dbus_int32_t res;
703 
704   _DBUS_LOCK (atomic);
705   res = atomic->value;
706   atomic->value -= 1;
707   _DBUS_UNLOCK (atomic);
708   return res;
709 #endif
710 }
711 
712 void
_dbus_generate_pseudorandom_bytes_buffer(char * buffer,int n_bytes)713 _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
714                                           int   n_bytes)
715 {
716   long tv_usec;
717   int i;
718 
719   /* fall back to pseudorandom */
720   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
721                  n_bytes);
722 
723   _dbus_get_current_time (NULL, &tv_usec);
724   srand (tv_usec);
725 
726   i = 0;
727   while (i < n_bytes)
728     {
729       double r;
730       unsigned int b;
731 
732       r = rand ();
733       b = (r / (double) RAND_MAX) * 255.0;
734 
735       buffer[i] = b;
736 
737       ++i;
738     }
739 }
740 
741 /**
742  * Fills n_bytes of the given buffer with random bytes.
743  *
744  * @param buffer an allocated buffer
745  * @param n_bytes the number of bytes in buffer to write to
746  */
747 void
_dbus_generate_random_bytes_buffer(char * buffer,int n_bytes)748 _dbus_generate_random_bytes_buffer (char *buffer,
749                                     int   n_bytes)
750 {
751   DBusString str;
752 
753   if (!_dbus_string_init (&str))
754     {
755       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
756       return;
757     }
758 
759   if (!_dbus_generate_random_bytes (&str, n_bytes))
760     {
761       _dbus_string_free (&str);
762       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
763       return;
764     }
765 
766   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
767 
768   _dbus_string_free (&str);
769 }
770 
771 /**
772  * Generates the given number of random bytes, where the bytes are
773  * chosen from the alphanumeric ASCII subset.
774  *
775  * @param str the string
776  * @param n_bytes the number of random ASCII bytes to append to string
777  * @returns #TRUE on success, #FALSE if no memory or other failure
778  */
779 dbus_bool_t
_dbus_generate_random_ascii(DBusString * str,int n_bytes)780 _dbus_generate_random_ascii (DBusString *str,
781                              int         n_bytes)
782 {
783   static const char letters[] =
784     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
785   int i;
786   int len;
787 
788   if (!_dbus_generate_random_bytes (str, n_bytes))
789     return FALSE;
790 
791   len = _dbus_string_get_length (str);
792   i = len - n_bytes;
793   while (i < len)
794     {
795       _dbus_string_set_byte (str, i,
796                              letters[_dbus_string_get_byte (str, i) %
797                                      (sizeof (letters) - 1)]);
798 
799       ++i;
800     }
801 
802   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
803                                              n_bytes));
804 
805   return TRUE;
806 }
807 
808 /**
809  * Gets a UID from a UID string.
810  *
811  * @param uid_str the UID in string form
812  * @param uid UID to fill in
813  * @returns #TRUE if successfully filled in UID
814  */
815 dbus_bool_t
_dbus_parse_uid(const DBusString * uid_str,dbus_uid_t * uid)816 _dbus_parse_uid (const DBusString      *uid_str,
817                  dbus_uid_t            *uid)
818 {
819   int end;
820   long val;
821 
822   if (_dbus_string_get_length (uid_str) == 0)
823     {
824       _dbus_verbose ("UID string was zero length\n");
825       return FALSE;
826     }
827 
828   val = -1;
829   end = 0;
830   if (!_dbus_string_parse_int (uid_str, 0, &val,
831                                &end))
832     {
833       _dbus_verbose ("could not parse string as a UID\n");
834       return FALSE;
835     }
836 
837   if (end != _dbus_string_get_length (uid_str))
838     {
839       _dbus_verbose ("string contained trailing stuff after UID\n");
840       return FALSE;
841     }
842 
843   *uid = val;
844 
845   return TRUE;
846 }
847 
848 /**
849  * Converts a UNIX or Windows errno
850  * into a #DBusError name.
851  *
852  * @todo should cover more errnos, specifically those
853  * from open().
854  *
855  * @param error_number the errno.
856  * @returns an error name
857  */
858 const char*
_dbus_error_from_errno(int error_number)859 _dbus_error_from_errno (int error_number)
860 {
861   switch (error_number)
862     {
863     case 0:
864       return DBUS_ERROR_FAILED;
865 
866 #ifdef EPROTONOSUPPORT
867     case EPROTONOSUPPORT:
868       return DBUS_ERROR_NOT_SUPPORTED;
869 #endif
870 #ifdef EAFNOSUPPORT
871     case EAFNOSUPPORT:
872       return DBUS_ERROR_NOT_SUPPORTED;
873 #endif
874 #ifdef ENFILE
875     case ENFILE:
876       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
877 #endif
878 #ifdef EMFILE
879     case EMFILE:
880       return DBUS_ERROR_LIMITS_EXCEEDED;
881 #endif
882 #ifdef EACCES
883     case EACCES:
884       return DBUS_ERROR_ACCESS_DENIED;
885 #endif
886 #ifdef EPERM
887     case EPERM:
888       return DBUS_ERROR_ACCESS_DENIED;
889 #endif
890 #ifdef ENOBUFS
891     case ENOBUFS:
892       return DBUS_ERROR_NO_MEMORY;
893 #endif
894 #ifdef ENOMEM
895     case ENOMEM:
896       return DBUS_ERROR_NO_MEMORY;
897 #endif
898 #ifdef EINVAL
899     case EINVAL:
900       return DBUS_ERROR_FAILED;
901 #endif
902 #ifdef EBADF
903     case EBADF:
904       return DBUS_ERROR_FAILED;
905 #endif
906 #ifdef EFAULT
907     case EFAULT:
908       return DBUS_ERROR_FAILED;
909 #endif
910 #ifdef ENOTSOCK
911     case ENOTSOCK:
912       return DBUS_ERROR_FAILED;
913 #endif
914 #ifdef EISCONN
915     case EISCONN:
916       return DBUS_ERROR_FAILED;
917 #endif
918 #ifdef ECONNREFUSED
919     case ECONNREFUSED:
920       return DBUS_ERROR_NO_SERVER;
921 #endif
922 #ifdef ETIMEDOUT
923     case ETIMEDOUT:
924       return DBUS_ERROR_TIMEOUT;
925 #endif
926 #ifdef ENETUNREACH
927     case ENETUNREACH:
928       return DBUS_ERROR_NO_NETWORK;
929 #endif
930 #ifdef EADDRINUSE
931     case EADDRINUSE:
932       return DBUS_ERROR_ADDRESS_IN_USE;
933 #endif
934 #ifdef EEXIST
935     case EEXIST:
936       return DBUS_ERROR_FILE_EXISTS;
937 #endif
938 #ifdef ENOENT
939     case ENOENT:
940       return DBUS_ERROR_FILE_NOT_FOUND;
941 #endif
942     }
943 
944   return DBUS_ERROR_FAILED;
945 }
946 
947 /** @} end of sysdeps */
948 
949 /* tests in dbus-sysdeps-util.c */
950