2003-01-04 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-sysdeps.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
3  * 
4  * Copyright (C) 2002  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-sysdeps.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <pwd.h>
37 #ifdef HAVE_WRITEV
38 #include <sys/uio.h>
39 #endif
40
41
42 /**
43  * @addtogroup DBusInternalsUtils
44  * @{
45  */
46 /**
47  * Aborts the program with SIGABRT (dumping core).
48  */
49 void
50 _dbus_abort (void)
51 {
52   abort ();
53   _exit (1); /* in case someone manages to ignore SIGABRT */
54 }
55
56 /**
57  * Wrapper for getenv().
58  *
59  * @param varname name of environment variable
60  * @returns value of environment variable or #NULL if unset
61  */
62 const char*
63 _dbus_getenv (const char *varname)
64 {  
65   return getenv (varname);
66 }
67
68 /**
69  * Thin wrapper around the read() system call that appends
70  * the data it reads to the DBusString buffer. It appends
71  * up to the given count, and returns the same value
72  * and same errno as read(). The only exception is that
73  * _dbus_read() handles EINTR for you.
74  *
75  * @param fd the file descriptor to read from
76  * @param buffer the buffer to append data to
77  * @param count the amount of data to read
78  * @returns the number of bytes read or -1
79  */
80 int
81 _dbus_read (int               fd,
82             DBusString       *buffer,
83             int               count)
84 {
85   int bytes_read;
86   int start;
87   char *data;
88
89   _dbus_assert (count >= 0);
90   
91   start = _dbus_string_get_length (buffer);
92
93   if (!_dbus_string_lengthen (buffer, count))
94     {
95       errno = ENOMEM;
96       return -1;
97     }
98
99   _dbus_string_get_data_len (buffer, &data, start, count);
100
101  again:
102   
103   bytes_read = read (fd, data, count);
104
105   if (bytes_read < 0)
106     {
107       if (errno == EINTR)
108         goto again;
109       else
110         {
111           /* put length back (note that this doesn't actually realloc anything) */
112           _dbus_string_set_length (buffer, start);
113           return -1;
114         }
115     }
116   else
117     {
118       /* put length back (doesn't actually realloc) */
119       _dbus_string_set_length (buffer, start + bytes_read);
120
121 #if 0
122       if (bytes_read > 0)
123         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
124 #endif
125       
126       return bytes_read;
127     }
128 }
129
130 /**
131  * Thin wrapper around the write() system call that writes a part of a
132  * DBusString and handles EINTR for you.
133  * 
134  * @param fd the file descriptor to write
135  * @param buffer the buffer to write data from
136  * @param start the first byte in the buffer to write
137  * @param len the number of bytes to try to write
138  * @returns the number of bytes written or -1 on error
139  */
140 int
141 _dbus_write (int               fd,
142              const DBusString *buffer,
143              int               start,
144              int               len)
145 {
146   const char *data;
147   int bytes_written;
148   
149   _dbus_string_get_const_data_len (buffer, &data, start, len);
150   
151  again:
152
153   bytes_written = write (fd, data, len);
154
155   if (bytes_written < 0 && errno == EINTR)
156     goto again;
157
158 #if 0
159   if (bytes_written > 0)
160     _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
161 #endif
162   
163   return bytes_written;
164 }
165
166 /**
167  * Like _dbus_write() but will use writev() if possible
168  * to write both buffers in sequence. The return value
169  * is the number of bytes written in the first buffer,
170  * plus the number written in the second. If the first
171  * buffer is written successfully and an error occurs
172  * writing the second, the number of bytes in the first
173  * is returned (i.e. the error is ignored), on systems that
174  * don't have writev. Handles EINTR for you.
175  * The second buffer may be #NULL.
176  *
177  * @param fd the file descriptor
178  * @param buffer1 first buffer
179  * @param start1 first byte to write in first buffer
180  * @param len1 number of bytes to write from first buffer
181  * @param buffer2 second buffer, or #NULL
182  * @param start2 first byte to write in second buffer
183  * @param len2 number of bytes to write in second buffer
184  * @returns total bytes written from both buffers, or -1 on error
185  */
186 int
187 _dbus_write_two (int               fd,
188                  const DBusString *buffer1,
189                  int               start1,
190                  int               len1,
191                  const DBusString *buffer2,
192                  int               start2,
193                  int               len2)
194 {
195   _dbus_assert (buffer1 != NULL);
196   _dbus_assert (start1 >= 0);
197   _dbus_assert (start2 >= 0);
198   _dbus_assert (len1 >= 0);
199   _dbus_assert (len2 >= 0);
200   
201 #ifdef HAVE_WRITEV
202   {
203     struct iovec vectors[2];
204     const char *data1;
205     const char *data2;
206     int bytes_written;
207
208     _dbus_string_get_const_data_len (buffer1, &data1, start1, len1);
209
210     if (buffer2 != NULL)
211       _dbus_string_get_const_data_len (buffer2, &data2, start2, len2);
212     else
213       {
214         data2 = NULL;
215         start2 = 0;
216         len2 = 0;
217       }
218    
219     vectors[0].iov_base = (char*) data1;
220     vectors[0].iov_len = len1;
221     vectors[1].iov_base = (char*) data2;
222     vectors[1].iov_len = len2;
223
224   again:
225    
226     bytes_written = writev (fd,
227                             vectors,
228                             data2 ? 2 : 1);
229
230     if (bytes_written < 0 && errno == EINTR)
231       goto again;
232    
233     return bytes_written;
234   }
235 #else /* HAVE_WRITEV */
236   {
237     int ret1;
238     
239     ret1 = _dbus_write (fd, buffer1, start1, len1);
240     if (ret1 == len1 && buffer2 != NULL)
241       {
242         ret2 = _dbus_write (fd, buffer2, start2, len2);
243         if (ret2 < 0)
244           ret2 = 0; /* we can't report an error as the first write was OK */
245        
246         return ret1 + ret2;
247       }
248     else
249       return ret1;
250   }
251 #endif /* !HAVE_WRITEV */   
252 }
253
254 /**
255  * Creates a socket and connects it to the UNIX domain socket at the
256  * given path.  The connection fd is returned, and is set up as
257  * nonblocking.
258  *
259  * @param path the path to UNIX domain socket
260  * @param result return location for error code
261  * @returns connection file descriptor or -1 on error
262  */
263 int
264 _dbus_connect_unix_socket (const char     *path,
265                            DBusResultCode *result)
266 {
267   int fd;
268   struct sockaddr_un addr;  
269   
270   fd = socket (AF_LOCAL, SOCK_STREAM, 0);
271
272   if (fd < 0)
273     {
274       dbus_set_result (result,
275                        _dbus_result_from_errno (errno));
276       
277       _dbus_verbose ("Failed to create socket: %s\n",
278                      _dbus_strerror (errno)); 
279       
280       return -1;
281     }
282
283   _DBUS_ZERO (addr);
284   addr.sun_family = AF_LOCAL;
285   strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
286   addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
287   
288   if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
289     {      
290       dbus_set_result (result,
291                        _dbus_result_from_errno (errno));
292
293       _dbus_verbose ("Failed to connect to socket %s: %s\n",
294                      path, _dbus_strerror (errno));
295
296       close (fd);
297       fd = -1;
298       
299       return -1;
300     }
301
302   if (!_dbus_set_fd_nonblocking (fd, result))
303     {
304       close (fd);
305       fd = -1;
306
307       return -1;
308     }
309
310   return fd;
311 }
312
313 /**
314  * Creates a socket and binds it to the given path,
315  * then listens on the socket. The socket is
316  * set to be nonblocking. 
317  *
318  * @param path the socket name
319  * @param result return location for errors
320  * @returns the listening file descriptor or -1 on error
321  */
322 int
323 _dbus_listen_unix_socket (const char     *path,
324                           DBusResultCode *result)
325 {
326   int listen_fd;
327   struct sockaddr_un addr;
328
329   listen_fd = socket (AF_LOCAL, SOCK_STREAM, 0);
330
331   if (listen_fd < 0)
332     {
333       dbus_set_result (result, _dbus_result_from_errno (errno));
334       _dbus_verbose ("Failed to create socket \"%s\": %s\n",
335                      path, _dbus_strerror (errno));
336       return -1;
337     }
338
339   _DBUS_ZERO (addr);
340   addr.sun_family = AF_LOCAL;
341   strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
342   addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
343   
344   if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)
345     {
346       dbus_set_result (result, _dbus_result_from_errno (errno));
347       _dbus_verbose ("Failed to bind socket \"%s\": %s\n",
348                      path, _dbus_strerror (errno));
349       close (listen_fd);
350       return -1;
351     }
352
353   if (listen (listen_fd, 30 /* backlog */) < 0)
354     {
355       dbus_set_result (result, _dbus_result_from_errno (errno));      
356       _dbus_verbose ("Failed to listen on socket \"%s\": %s\n",
357                      path, _dbus_strerror (errno));
358       close (listen_fd);
359       return -1;
360     }
361
362   if (!_dbus_set_fd_nonblocking (listen_fd, result))
363     {
364       close (listen_fd);
365       return -1;
366     }
367   
368   return listen_fd;
369 }
370
371 /* try to read a single byte and return #TRUE if we read it
372  * and it's equal to nul.
373  */
374 static dbus_bool_t
375 read_credentials_byte (int             client_fd,
376                        DBusResultCode *result)
377 {
378   char buf[1];
379   int bytes_read;
380
381  again:
382   bytes_read = read (client_fd, buf, 1);
383   if (bytes_read < 0)
384     {
385       if (errno == EINTR)
386         goto again;
387       else
388         {
389           dbus_set_result (result, _dbus_result_from_errno (errno));      
390           _dbus_verbose ("Failed to read credentials byte: %s\n",
391                          _dbus_strerror (errno));
392           return FALSE;
393         }
394     }
395   else if (bytes_read == 0)
396     {
397       dbus_set_result (result, DBUS_RESULT_IO_ERROR);
398       _dbus_verbose ("EOF reading credentials byte\n");
399       return FALSE;
400     }
401   else
402     {
403       _dbus_assert (bytes_read == 1);
404
405       if (buf[0] != '\0')
406         {
407           dbus_set_result (result, DBUS_RESULT_FAILED);
408           _dbus_verbose ("Credentials byte was not nul\n");
409           return FALSE;
410         }
411
412       _dbus_verbose ("read credentials byte\n");
413       
414       return TRUE;
415     }
416 }
417
418 static dbus_bool_t
419 write_credentials_byte (int             server_fd,
420                         DBusResultCode *result)
421 {
422   int bytes_written;
423   char buf[1] = { '\0' };
424   
425  again:
426
427   bytes_written = write (server_fd, buf, 1);
428
429   if (bytes_written < 0 && errno == EINTR)
430     goto again;
431
432   if (bytes_written < 0)
433     {
434       dbus_set_result (result, _dbus_result_from_errno (errno));      
435       _dbus_verbose ("Failed to write credentials byte: %s\n",
436                      _dbus_strerror (errno));
437       return FALSE;
438     }
439   else if (bytes_written == 0)
440     {
441       dbus_set_result (result, DBUS_RESULT_IO_ERROR);
442       _dbus_verbose ("wrote zero bytes writing credentials byte\n");
443       return FALSE;
444     }
445   else
446     {
447       _dbus_assert (bytes_written == 1);
448       _dbus_verbose ("wrote credentials byte\n");
449       return TRUE;
450     }
451 }
452
453 /**
454  * Reads a single byte which must be nul (an error occurs otherwise),
455  * and reads unix credentials if available. Fills in pid/uid/gid with
456  * -1 if no credentials are available. Return value indicates whether
457  * a byte was read, not whether we got valid credentials. On some
458  * systems, such as Linux, reading/writing the byte isn't actually
459  * required, but we do it anyway just to avoid multiple codepaths.
460  * 
461  * Fails if no byte is available, so you must select() first.
462  *
463  * The point of the byte is that on some systems we have to
464  * use sendmsg()/recvmsg() to transmit credentials.
465  *
466  * @param client_fd the client file descriptor
467  * @param credentials struct to fill with credentials of client
468  * @param result location to store result code
469  * @returns #TRUE on success
470  */
471 dbus_bool_t
472 _dbus_read_credentials_unix_socket  (int              client_fd,
473                                      DBusCredentials *credentials,
474                                      DBusResultCode  *result)
475 {
476   credentials->pid = -1;
477   credentials->uid = -1;
478   credentials->gid = -1;
479   
480 #ifdef SO_PEERCRED
481   if (read_credentials_byte (client_fd, result))
482     {
483       struct ucred cr;   
484       int cr_len = sizeof (cr);
485    
486       if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
487           cr_len == sizeof (cr))
488         {
489           credentials->pid = cr.pid;
490           credentials->uid = cr.uid;
491           credentials->gid = cr.gid;
492           _dbus_verbose ("Got credentials pid %d uid %d gid %d\n",
493                          credentials->pid,
494                          credentials->uid,
495                          credentials->gid);
496         }
497       else
498         {
499           _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
500                          cr_len, (int) sizeof (cr), _dbus_strerror (errno));
501         }
502
503       return TRUE;
504     }
505   else
506     return FALSE;
507 #else /* !SO_PEERCRED */
508   _dbus_verbose ("Socket credentials not supported on this OS\n");
509   return TRUE;
510 #endif
511 }
512
513 /**
514  * Sends a single nul byte with our UNIX credentials as ancillary
515  * data.  Returns #TRUE if the data was successfully written.  On
516  * systems that don't support sending credentials, just writes a byte,
517  * doesn't send any credentials.  On some systems, such as Linux,
518  * reading/writing the byte isn't actually required, but we do it
519  * anyway just to avoid multiple codepaths.
520  *
521  * Fails if no byte can be written, so you must select() first.
522  *
523  * The point of the byte is that on some systems we have to
524  * use sendmsg()/recvmsg() to transmit credentials.
525  *
526  * @param server_fd file descriptor for connection to server
527  * @param result return location for error code
528  * @returns #TRUE if the byte was sent
529  */
530 dbus_bool_t
531 _dbus_send_credentials_unix_socket  (int              server_fd,
532                                      DBusResultCode  *result)
533 {
534   if (write_credentials_byte (server_fd, result))
535     return TRUE;
536   else
537     return FALSE;
538 }
539
540 /**
541  * Accepts a connection on a listening socket.
542  * Handles EINTR for you.
543  *
544  * @param listen_fd the listen file descriptor
545  * @returns the connection fd of the client, or -1 on error
546  */
547 int
548 _dbus_accept  (int listen_fd)
549 {
550   int client_fd;
551   
552  retry:
553   client_fd = accept (listen_fd, NULL, NULL);
554   
555   if (client_fd < 0)
556     {
557       if (errno == EINTR)
558         goto retry;
559     }
560   
561   return client_fd;
562 }
563
564 /** @} */
565
566 /**
567  * @addtogroup DBusString
568  *
569  * @{
570  */
571 /**
572  * Appends an integer to a DBusString.
573  * 
574  * @param str the string
575  * @param value the integer value
576  * @returns #FALSE if not enough memory or other failure.
577  */
578 dbus_bool_t
579 _dbus_string_append_int (DBusString *str,
580                          long        value)
581 {
582   /* this calculation is from comp.lang.c faq */
583 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
584   int orig_len;
585   int i;
586   char *buf;
587   
588   orig_len = _dbus_string_get_length (str);
589
590   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
591     return FALSE;
592
593   _dbus_string_get_data_len (str, &buf, orig_len, MAX_LONG_LEN);
594
595   snprintf (buf, MAX_LONG_LEN, "%ld", value);
596
597   i = 0;
598   while (*buf)
599     {
600       ++buf;
601       ++i;
602     }
603   
604   _dbus_string_shorten (str, MAX_LONG_LEN - i);
605   
606   return TRUE;
607 }
608
609 /**
610  * Appends a double to a DBusString.
611  * 
612  * @param str the string
613  * @param value the floating point value
614  * @returns #FALSE if not enough memory or other failure.
615  */
616 dbus_bool_t
617 _dbus_string_append_double (DBusString *str,
618                             double      value)
619 {
620 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
621   int orig_len;
622   char *buf;
623   int i;
624   
625   orig_len = _dbus_string_get_length (str);
626
627   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
628     return FALSE;
629
630   _dbus_string_get_data_len (str, &buf, orig_len, MAX_DOUBLE_LEN);
631
632   snprintf (buf, MAX_LONG_LEN, "%g", value);
633
634   i = 0;
635   while (*buf)
636     {
637       ++buf;
638       ++i;
639     }
640   
641   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
642   
643   return TRUE;
644 }
645
646 /**
647  * Parses an integer contained in a DBusString. Either return parameter
648  * may be #NULL if you aren't interested in it. The integer is parsed
649  * and stored in value_return. Return parameters are not initialized
650  * if the function returns #FALSE.
651  *
652  * @param str the string
653  * @param start the byte index of the start of the integer
654  * @param value_return return location of the integer value or #NULL
655  * @param end_return return location of the end of the integer, or #NULL
656  * @returns #TRUE on success
657  */
658 dbus_bool_t
659 _dbus_string_parse_int (const DBusString *str,
660                         int               start,
661                         long             *value_return,
662                         int              *end_return)
663 {
664   long v;
665   const char *p;
666   char *end;
667
668   _dbus_string_get_const_data_len (str, &p, start,
669                                    _dbus_string_get_length (str) - start);
670
671   end = NULL;
672   errno = 0;
673   v = strtol (p, &end, 0);
674   if (end == NULL || end == p || errno != 0)
675     return FALSE;
676
677   if (value_return)
678     *value_return = v;
679   if (end_return)
680     *end_return = (end - p);
681
682   return TRUE;
683 }
684
685 /**
686  * Parses a floating point number contained in a DBusString. Either
687  * return parameter may be #NULL if you aren't interested in it. The
688  * integer is parsed and stored in value_return. Return parameters are
689  * not initialized if the function returns #FALSE.
690  *
691  * @todo this function is currently locale-dependent. Should
692  * ask alexl to relicense g_ascii_strtod() code and put that in
693  * here instead, so it's locale-independent.
694  *
695  * @param str the string
696  * @param start the byte index of the start of the float
697  * @param value_return return location of the float value or #NULL
698  * @param end_return return location of the end of the float, or #NULL
699  * @returns #TRUE on success
700  */
701 dbus_bool_t
702 _dbus_string_parse_double (const DBusString *str,
703                            int               start,
704                            double           *value_return,
705                            int              *end_return)
706 {
707   double v;
708   const char *p;
709   char *end;
710
711   _dbus_warn ("_dbus_string_parse_double() needs to be made locale-independent\n");
712   
713   _dbus_string_get_const_data_len (str, &p, start,
714                                    _dbus_string_get_length (str) - start);
715
716   end = NULL;
717   errno = 0;
718   v = strtod (p, &end);
719   if (end == NULL || end == p || errno != 0)
720     return FALSE;
721
722   if (value_return)
723     *value_return = v;
724   if (end_return)
725     *end_return = (end - p);
726
727   return TRUE;
728 }
729
730 /**
731  * Gets the credentials corresponding to the given username.
732  *
733  * @param username the username
734  * @param credentials credentials to fill in
735  * @returns #TRUE if the username existed and we got some credentials
736  */
737 dbus_bool_t
738 _dbus_credentials_from_username (const DBusString *username,
739                                  DBusCredentials  *credentials)
740 {
741   const char *username_c_str;
742   
743   credentials->pid = -1;
744   credentials->uid = -1;
745   credentials->gid = -1;
746
747   _dbus_string_get_const_data (username, &username_c_str);
748   
749 #ifdef HAVE_GETPWNAM_R
750   {
751     struct passwd *p;
752     int result;
753     char buf[1024];
754     struct passwd p_str;
755
756     p = NULL;
757     result = getpwnam_r (username_c_str, &p_str, buf, sizeof (buf),
758                          &p);
759
760     if (result == 0 && p == &p_str)
761       {
762         credentials->uid = p->pw_uid;
763         credentials->gid = p->pw_gid;
764
765         _dbus_verbose ("Username %s has uid %d gid %d\n",
766                        username_c_str, credentials->uid, credentials->gid);
767         return TRUE;
768       }
769     else
770       {
771         _dbus_verbose ("User %s unknown\n", username_c_str);
772         return FALSE;
773       }
774   }
775 #else /* ! HAVE_GETPWNAM_R */
776   {
777     /* I guess we're screwed on thread safety here */
778     struct passwd *p;
779
780     p = getpwnam (username_c_str);
781
782     if (p != NULL)
783       {
784         credentials->uid = p->pw_uid;
785         credentials->gid = p->pw_gid;
786
787         _dbus_verbose ("Username %s has uid %d gid %d\n",
788                        username_c_str, credentials->uid, credentials->gid);
789         return TRUE;
790       }
791     else
792       {
793         _dbus_verbose ("User %s unknown\n", username_c_str);
794         return FALSE;
795       }
796   }
797 #endif  
798 }
799
800 /**
801  * Gets credentials from a UID string. (Parses a string to a UID
802  * and converts to a DBusCredentials.)
803  *
804  * @param uid_str the UID in string form
805  * @param credentials credentials to fill in
806  * @returns #TRUE if successfully filled in some credentials
807  */
808 dbus_bool_t
809 _dbus_credentials_from_uid_string (const DBusString      *uid_str,
810                                    DBusCredentials       *credentials)
811 {
812   int end;
813   long uid;
814
815   credentials->pid = -1;
816   credentials->uid = -1;
817   credentials->gid = -1;
818   
819   if (_dbus_string_get_length (uid_str) == 0)
820     {
821       _dbus_verbose ("UID string was zero length\n");
822       return FALSE;
823     }
824
825   uid = -1;
826   end = 0;
827   if (!_dbus_string_parse_int (uid_str, 0, &uid,
828                                &end))
829     {
830       _dbus_verbose ("could not parse string as a UID\n");
831       return FALSE;
832     }
833   
834   if (end != _dbus_string_get_length (uid_str))
835     {
836       _dbus_verbose ("string contained trailing stuff after UID\n");
837       return FALSE;
838     }
839
840   credentials->uid = uid;
841
842   return TRUE;
843 }
844
845 /**
846  * Gets the credentials of the current process.
847  *
848  * @param credentials credentials to fill in.
849  */
850 void
851 _dbus_credentials_from_current_process (DBusCredentials *credentials)
852 {
853   credentials->pid = getpid ();
854   credentials->uid = getuid ();
855   credentials->gid = getgid ();
856 }
857
858 /**
859  * Checks whether the provided_credentials are allowed to log in
860  * as the expected_credentials.
861  *
862  * @param expected_credentials credentials we're trying to log in as
863  * @param provided_credentials credentials we have
864  * @returns #TRUE if we can log in
865  */
866 dbus_bool_t
867 _dbus_credentials_match (const DBusCredentials *expected_credentials,
868                          const DBusCredentials *provided_credentials)
869 {
870   if (provided_credentials->uid < 0)
871     return FALSE;
872   else if (expected_credentials->uid < 0)
873     return FALSE;
874   else if (provided_credentials->uid == 0)
875     return TRUE;
876   else if (provided_credentials->uid == expected_credentials->uid)
877     return TRUE;
878   else
879     return FALSE;
880 }
881
882 /**
883  * Appends the uid of the current process to the given string.
884  *
885  * @param str the string to append to
886  * @returns #TRUE on success
887  */
888 dbus_bool_t
889 _dbus_string_append_our_uid (DBusString *str)
890 {
891   return _dbus_string_append_int (str, getuid ());
892 }
893
894 /** @} end of sysdeps */