2007-06-09 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-util-unix.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps-util-unix.c Would be in dbus-sysdeps-unix.c, but not used in libdbus
3  * 
4  * Copyright (C) 2002, 2003, 2004, 2005  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 #include "dbus-sysdeps.h"
25 #include "dbus-sysdeps-unix.h"
26 #include "dbus-internals.h"
27 #include "dbus-protocol.h"
28 #include "dbus-string.h"
29 #define DBUS_USERDB_INCLUDES_PRIVATE 1
30 #include "dbus-userdb.h"
31 #include "dbus-test.h"
32
33 #include <sys/types.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <sys/stat.h>
42 #include <grp.h>
43 #include <sys/socket.h>
44 #include <dirent.h>
45 #include <sys/un.h>
46
47 #ifdef HAVE_SYS_SYSLIMITS_H
48 #include <sys/syslimits.h>
49 #endif
50
51 #ifndef O_BINARY
52 #define O_BINARY 0
53 #endif
54
55 /**
56  * @addtogroup DBusInternalsUtils
57  * @{
58  */
59
60 /**
61  * Does the chdir, fork, setsid, etc. to become a daemon process.
62  *
63  * @param pidfile #NULL, or pidfile to create
64  * @param print_pid_pipe pipe to print daemon's pid to, or -1 for none
65  * @param error return location for errors
66  * @returns #FALSE on failure
67  */
68 dbus_bool_t
69 _dbus_become_daemon (const DBusString *pidfile,
70                      DBusPipe         *print_pid_pipe,
71                      DBusError        *error)
72 {
73   const char *s;
74   pid_t child_pid;
75   int dev_null_fd;
76
77   _dbus_verbose ("Becoming a daemon...\n");
78
79   _dbus_verbose ("chdir to /\n");
80   if (chdir ("/") < 0)
81     {
82       dbus_set_error (error, DBUS_ERROR_FAILED,
83                       "Could not chdir() to root directory");
84       return FALSE;
85     }
86
87   _dbus_verbose ("forking...\n");
88   switch ((child_pid = fork ()))
89     {
90     case -1:
91       _dbus_verbose ("fork failed\n");
92       dbus_set_error (error, _dbus_error_from_errno (errno),
93                       "Failed to fork daemon: %s", _dbus_strerror (errno));
94       return FALSE;
95       break;
96
97     case 0:
98       _dbus_verbose ("in child, closing std file descriptors\n");
99
100       /* silently ignore failures here, if someone
101        * doesn't have /dev/null we may as well try
102        * to continue anyhow
103        */
104       
105       dev_null_fd = open ("/dev/null", O_RDWR);
106       if (dev_null_fd >= 0)
107         {
108           dup2 (dev_null_fd, 0);
109           dup2 (dev_null_fd, 1);
110           
111           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
112           if (s == NULL || *s == '\0')
113             dup2 (dev_null_fd, 2);
114           else
115             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
116         }
117
118       /* Get a predictable umask */
119       _dbus_verbose ("setting umask\n");
120       umask (022);
121       break;
122
123     default:
124       if (pidfile)
125         {
126           _dbus_verbose ("parent writing pid file\n");
127           if (!_dbus_write_pid_file (pidfile,
128                                      child_pid,
129                                      error))
130             {
131               _dbus_verbose ("pid file write failed, killing child\n");
132               kill (child_pid, SIGTERM);
133               return FALSE;
134             }
135         }
136
137       /* Write PID if requested */
138       if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
139         {
140           DBusString pid;
141           int bytes;
142           
143           if (!_dbus_string_init (&pid))
144             {
145               _DBUS_SET_OOM (error);
146               kill (child_pid, SIGTERM);
147               return FALSE;
148             }
149           
150           if (!_dbus_string_append_int (&pid, child_pid) ||
151               !_dbus_string_append (&pid, "\n"))
152             {
153               _dbus_string_free (&pid);
154               _DBUS_SET_OOM (error);
155               kill (child_pid, SIGTERM);
156               return FALSE;
157             }
158           
159           bytes = _dbus_string_get_length (&pid);
160           if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
161             {
162               /* _dbus_pipe_write sets error only on failure, not short write */
163               if (error != NULL && !dbus_error_is_set(error))
164                 {
165                   dbus_set_error (error, DBUS_ERROR_FAILED,
166                                   "Printing message bus PID: did not write enough bytes\n");
167                 }
168               _dbus_string_free (&pid);
169               kill (child_pid, SIGTERM);
170               return FALSE;
171             }
172           
173           _dbus_string_free (&pid);
174         }
175       _dbus_verbose ("parent exiting\n");
176       _exit (0);
177       break;
178     }
179
180   _dbus_verbose ("calling setsid()\n");
181   if (setsid () == -1)
182     _dbus_assert_not_reached ("setsid() failed");
183   
184   return TRUE;
185 }
186
187
188 /**
189  * Creates a file containing the process ID.
190  *
191  * @param filename the filename to write to
192  * @param pid our process ID
193  * @param error return location for errors
194  * @returns #FALSE on failure
195  */
196 dbus_bool_t
197 _dbus_write_pid_file (const DBusString *filename,
198                       unsigned long     pid,
199                       DBusError        *error)
200 {
201   const char *cfilename;
202   int fd;
203   FILE *f;
204
205   cfilename = _dbus_string_get_const_data (filename);
206   
207   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
208   
209   if (fd < 0)
210     {
211       dbus_set_error (error, _dbus_error_from_errno (errno),
212                       "Failed to open \"%s\": %s", cfilename,
213                       _dbus_strerror (errno));
214       return FALSE;
215     }
216
217   if ((f = fdopen (fd, "w")) == NULL)
218     {
219       dbus_set_error (error, _dbus_error_from_errno (errno),
220                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
221       _dbus_close (fd, NULL);
222       return FALSE;
223     }
224   
225   if (fprintf (f, "%lu\n", pid) < 0)
226     {
227       dbus_set_error (error, _dbus_error_from_errno (errno),
228                       "Failed to write to \"%s\": %s", cfilename,
229                       _dbus_strerror (errno));
230       
231       fclose (f);
232       return FALSE;
233     }
234
235   if (fclose (f) == EOF)
236     {
237       dbus_set_error (error, _dbus_error_from_errno (errno),
238                       "Failed to close \"%s\": %s", cfilename,
239                       _dbus_strerror (errno));
240       return FALSE;
241     }
242   
243   return TRUE;
244 }
245
246 /**
247  * Verify that after the fork we can successfully change to this user.
248  *
249  * @param user the username given in the daemon configuration
250  * @returns #TRUE if username is valid
251  */
252 dbus_bool_t
253 _dbus_verify_daemon_user (const char *user)
254 {
255   DBusString u;
256
257   _dbus_string_init_const (&u, user);
258
259   return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
260 }
261
262 /**
263  * Changes the user and group the bus is running as.
264  *
265  * @param user the user to become
266  * @param error return location for errors
267  * @returns #FALSE on failure
268  */
269 dbus_bool_t
270 _dbus_change_to_daemon_user  (const char    *user,
271                               DBusError     *error)
272 {
273   dbus_uid_t uid;
274   dbus_gid_t gid;
275   DBusString u;
276
277   _dbus_string_init_const (&u, user);
278   
279   if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
280     {
281       dbus_set_error (error, DBUS_ERROR_FAILED,
282                       "User '%s' does not appear to exist?",
283                       user);
284       return FALSE;
285     }
286   
287   /* setgroups() only works if we are a privileged process,
288    * so we don't return error on failure; the only possible
289    * failure is that we don't have perms to do it.
290    *
291    * not sure this is right, maybe if setuid()
292    * is going to work then setgroups() should also work.
293    */
294   if (setgroups (0, NULL) < 0)
295     _dbus_warn ("Failed to drop supplementary groups: %s\n",
296                 _dbus_strerror (errno));
297   
298   /* Set GID first, or the setuid may remove our permission
299    * to change the GID
300    */
301   if (setgid (gid) < 0)
302     {
303       dbus_set_error (error, _dbus_error_from_errno (errno),
304                       "Failed to set GID to %lu: %s", gid,
305                       _dbus_strerror (errno));
306       return FALSE;
307     }
308   
309   if (setuid (uid) < 0)
310     {
311       dbus_set_error (error, _dbus_error_from_errno (errno),
312                       "Failed to set UID to %lu: %s", uid,
313                       _dbus_strerror (errno));
314       return FALSE;
315     }
316   
317   return TRUE;
318 }
319
320 /** Installs a UNIX signal handler
321  *
322  * @param sig the signal to handle
323  * @param handler the handler
324  */
325 void
326 _dbus_set_signal_handler (int               sig,
327                           DBusSignalHandler handler)
328 {
329   struct sigaction act;
330   sigset_t empty_mask;
331   
332   sigemptyset (&empty_mask);
333   act.sa_handler = handler;
334   act.sa_mask    = empty_mask;
335   act.sa_flags   = 0;
336   sigaction (sig,  &act, NULL);
337 }
338
339
340 /**
341  * Removes a directory; Directory must be empty
342  * 
343  * @param filename directory filename
344  * @param error initialized error object
345  * @returns #TRUE on success
346  */
347 dbus_bool_t
348 _dbus_delete_directory (const DBusString *filename,
349                         DBusError        *error)
350 {
351   const char *filename_c;
352   
353   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
354
355   filename_c = _dbus_string_get_const_data (filename);
356
357   if (rmdir (filename_c) != 0)
358     {
359       dbus_set_error (error, DBUS_ERROR_FAILED,
360                       "Failed to remove directory %s: %s\n",
361                       filename_c, _dbus_strerror (errno));
362       return FALSE;
363     }
364   
365   return TRUE;
366 }
367
368 /** Checks if a file exists
369 *
370 * @param file full path to the file
371 * @returns #TRUE if file exists
372 */
373 dbus_bool_t 
374 _dbus_file_exists (const char *file)
375 {
376   return (access (file, F_OK) == 0);
377 }
378
379 /** Checks if user is at the console
380 *
381 * @param username user to check
382 * @param error return location for errors
383 * @returns #TRUE is the user is at the consolei and there are no errors
384 */
385 dbus_bool_t 
386 _dbus_user_at_console (const char *username,
387                        DBusError  *error)
388 {
389
390   DBusString f;
391   dbus_bool_t result;
392
393   result = FALSE;
394   if (!_dbus_string_init (&f))
395     {
396       _DBUS_SET_OOM (error);
397       return FALSE;
398     }
399
400   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
401     {
402       _DBUS_SET_OOM (error);
403       goto out;
404     }
405
406
407   if (!_dbus_string_append (&f, username))
408     {
409       _DBUS_SET_OOM (error);
410       goto out;
411     }
412
413   result = _dbus_file_exists (_dbus_string_get_const_data (&f));
414
415  out:
416   _dbus_string_free (&f);
417
418   return result;
419 }
420
421
422 /**
423  * Checks whether the filename is an absolute path
424  *
425  * @param filename the filename
426  * @returns #TRUE if an absolute path
427  */
428 dbus_bool_t
429 _dbus_path_is_absolute (const DBusString *filename)
430 {
431   if (_dbus_string_get_length (filename) > 0)
432     return _dbus_string_get_byte (filename, 0) == '/';
433   else
434     return FALSE;
435 }
436
437 /**
438  * stat() wrapper.
439  *
440  * @param filename the filename to stat
441  * @param statbuf the stat info to fill in
442  * @param error return location for error
443  * @returns #FALSE if error was set
444  */
445 dbus_bool_t
446 _dbus_stat (const DBusString *filename,
447             DBusStat         *statbuf,
448             DBusError        *error)
449 {
450   const char *filename_c;
451   struct stat sb;
452
453   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
454   
455   filename_c = _dbus_string_get_const_data (filename);
456
457   if (stat (filename_c, &sb) < 0)
458     {
459       dbus_set_error (error, _dbus_error_from_errno (errno),
460                       "%s", _dbus_strerror (errno));
461       return FALSE;
462     }
463
464   statbuf->mode = sb.st_mode;
465   statbuf->nlink = sb.st_nlink;
466   statbuf->uid = sb.st_uid;
467   statbuf->gid = sb.st_gid;
468   statbuf->size = sb.st_size;
469   statbuf->atime = sb.st_atime;
470   statbuf->mtime = sb.st_mtime;
471   statbuf->ctime = sb.st_ctime;
472
473   return TRUE;
474 }
475
476
477 /**
478  * Internals of directory iterator
479  */
480 struct DBusDirIter
481 {
482   DIR *d; /**< The DIR* from opendir() */
483   
484 };
485
486 /**
487  * Open a directory to iterate over.
488  *
489  * @param filename the directory name
490  * @param error exception return object or #NULL
491  * @returns new iterator, or #NULL on error
492  */
493 DBusDirIter*
494 _dbus_directory_open (const DBusString *filename,
495                       DBusError        *error)
496 {
497   DIR *d;
498   DBusDirIter *iter;
499   const char *filename_c;
500
501   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
502   
503   filename_c = _dbus_string_get_const_data (filename);
504
505   d = opendir (filename_c);
506   if (d == NULL)
507     {
508       dbus_set_error (error, _dbus_error_from_errno (errno),
509                       "Failed to read directory \"%s\": %s",
510                       filename_c,
511                       _dbus_strerror (errno));
512       return NULL;
513     }
514   iter = dbus_new0 (DBusDirIter, 1);
515   if (iter == NULL)
516     {
517       closedir (d);
518       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
519                       "Could not allocate memory for directory iterator");
520       return NULL;
521     }
522
523   iter->d = d;
524
525   return iter;
526 }
527
528 /* Calculate the required buffer size (in bytes) for directory
529  * entries read from the given directory handle.  Return -1 if this
530  * this cannot be done. 
531  *
532  * If you use autoconf, include fpathconf and dirfd in your
533  * AC_CHECK_FUNCS list.  Otherwise use some other method to detect
534  * and use them where available.
535  */
536 static dbus_bool_t
537 dirent_buf_size(DIR * dirp, size_t *size)
538 {
539  long name_max;
540 #   if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
541 #      if defined(HAVE_DIRFD)
542           name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
543 #      elif defined(HAVE_DDFD)
544           name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
545 #      else
546           name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
547 #      endif /* HAVE_DIRFD */
548      if (name_max == -1)
549 #           if defined(NAME_MAX)
550              name_max = NAME_MAX;
551 #           else
552              return FALSE;
553 #           endif
554 #   elif defined(MAXNAMELEN)
555      name_max = MAXNAMELEN;
556 #   else
557 #       if defined(NAME_MAX)
558          name_max = NAME_MAX;
559 #       else
560 #           error "buffer size for readdir_r cannot be determined"
561 #       endif
562 #   endif
563   if (size)
564     *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
565   else
566     return FALSE;
567
568   return TRUE;
569 }
570
571 /**
572  * Get next file in the directory. Will not return "." or ".."  on
573  * UNIX. If an error occurs, the contents of "filename" are
574  * undefined. The error is never set if the function succeeds.
575  *
576  * @param iter the iterator
577  * @param filename string to be set to the next file in the dir
578  * @param error return location for error
579  * @returns #TRUE if filename was filled in with a new filename
580  */
581 dbus_bool_t
582 _dbus_directory_get_next_file (DBusDirIter      *iter,
583                                DBusString       *filename,
584                                DBusError        *error)
585 {
586   struct dirent *d, *ent;
587   size_t buf_size;
588   int err;
589
590   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
591  
592   if (!dirent_buf_size (iter->d, &buf_size))
593     {
594       dbus_set_error (error, DBUS_ERROR_FAILED,
595                       "Can't calculate buffer size when reading directory");
596       return FALSE;
597     }
598
599   d = (struct dirent *)dbus_malloc (buf_size);
600   if (!d)
601     {
602       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
603                       "No memory to read directory entry");
604       return FALSE;
605     }
606
607  again:
608   err = readdir_r (iter->d, d, &ent);
609   if (err || !ent)
610     {
611       if (err != 0)
612         dbus_set_error (error,
613                         _dbus_error_from_errno (err),
614                         "%s", _dbus_strerror (err));
615
616       dbus_free (d);
617       return FALSE;
618     }
619   else if (ent->d_name[0] == '.' &&
620            (ent->d_name[1] == '\0' ||
621             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
622     goto again;
623   else
624     {
625       _dbus_string_set_length (filename, 0);
626       if (!_dbus_string_append (filename, ent->d_name))
627         {
628           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
629                           "No memory to read directory entry");
630           dbus_free (d);
631           return FALSE;
632         }
633       else
634         {
635           dbus_free (d);
636           return TRUE;
637         }
638     }
639 }
640
641 /**
642  * Closes a directory iteration.
643  */
644 void
645 _dbus_directory_close (DBusDirIter *iter)
646 {
647   closedir (iter->d);
648   dbus_free (iter);
649 }
650
651 static dbus_bool_t
652 fill_user_info_from_group (struct group  *g,
653                            DBusGroupInfo *info,
654                            DBusError     *error)
655 {
656   _dbus_assert (g->gr_name != NULL);
657   
658   info->gid = g->gr_gid;
659   info->groupname = _dbus_strdup (g->gr_name);
660
661   /* info->members = dbus_strdupv (g->gr_mem) */
662   
663   if (info->groupname == NULL)
664     {
665       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
666       return FALSE;
667     }
668
669   return TRUE;
670 }
671
672 static dbus_bool_t
673 fill_group_info (DBusGroupInfo    *info,
674                  dbus_gid_t        gid,
675                  const DBusString *groupname,
676                  DBusError        *error)
677 {
678   const char *group_c_str;
679
680   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
681   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
682
683   if (groupname)
684     group_c_str = _dbus_string_get_const_data (groupname);
685   else
686     group_c_str = NULL;
687   
688   /* For now assuming that the getgrnam() and getgrgid() flavors
689    * always correspond to the pwnam flavors, if not we have
690    * to add more configure checks.
691    */
692   
693 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
694   {
695     struct group *g;
696     int result;
697     char buf[1024];
698     struct group g_str;
699
700     g = NULL;
701 #ifdef HAVE_POSIX_GETPWNAM_R
702
703     if (group_c_str)
704       result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
705                            &g);
706     else
707       result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
708                            &g);
709 #else
710     g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
711     result = 0;
712 #endif /* !HAVE_POSIX_GETPWNAM_R */
713     if (result == 0 && g == &g_str)
714       {
715         return fill_user_info_from_group (g, info, error);
716       }
717     else
718       {
719         dbus_set_error (error, _dbus_error_from_errno (errno),
720                         "Group %s unknown or failed to look it up\n",
721                         group_c_str ? group_c_str : "???");
722         return FALSE;
723       }
724   }
725 #else /* ! HAVE_GETPWNAM_R */
726   {
727     /* I guess we're screwed on thread safety here */
728     struct group *g;
729
730     g = getgrnam (group_c_str);
731
732     if (g != NULL)
733       {
734         return fill_user_info_from_group (g, info, error);
735       }
736     else
737       {
738         dbus_set_error (error, _dbus_error_from_errno (errno),
739                         "Group %s unknown or failed to look it up\n",
740                         group_c_str ? group_c_str : "???");
741         return FALSE;
742       }
743   }
744 #endif  /* ! HAVE_GETPWNAM_R */
745 }
746
747 /**
748  * Initializes the given DBusGroupInfo struct
749  * with information about the given group name.
750  *
751  * @param info the group info struct
752  * @param groupname name of group
753  * @param error the error return
754  * @returns #FALSE if error is set
755  */
756 dbus_bool_t
757 _dbus_group_info_fill (DBusGroupInfo    *info,
758                        const DBusString *groupname,
759                        DBusError        *error)
760 {
761   return fill_group_info (info, DBUS_GID_UNSET,
762                           groupname, error);
763
764 }
765
766 /**
767  * Initializes the given DBusGroupInfo struct
768  * with information about the given group ID.
769  *
770  * @param info the group info struct
771  * @param gid group ID
772  * @param error the error return
773  * @returns #FALSE if error is set
774  */
775 dbus_bool_t
776 _dbus_group_info_fill_gid (DBusGroupInfo *info,
777                            dbus_gid_t     gid,
778                            DBusError     *error)
779 {
780   return fill_group_info (info, gid, NULL, error);
781 }
782
783 /**
784  * Parse a UNIX user from the bus config file. On Windows, this should
785  * simply always fail (just return #FALSE).
786  *
787  * @param username the username text
788  * @param uid_p place to return the uid
789  * @returns #TRUE on success
790  */
791 dbus_bool_t
792 _dbus_parse_unix_user_from_config (const DBusString  *username,
793                                    dbus_uid_t        *uid_p)
794 {
795   return _dbus_get_user_id (username, uid_p);
796
797 }
798
799 /**
800  * Parse a UNIX group from the bus config file. On Windows, this should
801  * simply always fail (just return #FALSE).
802  *
803  * @param groupname the groupname text
804  * @param gid_p place to return the gid
805  * @returns #TRUE on success
806  */
807 dbus_bool_t
808 _dbus_parse_unix_group_from_config (const DBusString  *groupname,
809                                     dbus_gid_t        *gid_p)
810 {
811   return _dbus_get_group_id (groupname, gid_p);
812 }
813
814 /**
815  * Gets all groups corresponding to the given UNIX user ID. On UNIX,
816  * just calls _dbus_groups_from_uid(). On Windows, should always
817  * fail since we don't know any UNIX groups.
818  *
819  * @param uid the UID
820  * @param group_ids return location for array of group IDs
821  * @param n_group_ids return location for length of returned array
822  * @returns #TRUE if the UID existed and we got some credentials
823  */
824 dbus_bool_t
825 _dbus_unix_groups_from_uid (dbus_uid_t            uid,
826                             dbus_gid_t          **group_ids,
827                             int                  *n_group_ids)
828 {
829   return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
830 }
831
832 /**
833  * Checks to see if the UNIX user ID is at the console.
834  * Should always fail on Windows (set the error to
835  * #DBUS_ERROR_NOT_SUPPORTED).
836  *
837  * @param uid UID of person to check 
838  * @param error return location for errors
839  * @returns #TRUE if the UID is the same as the console user and there are no errors
840  */
841 dbus_bool_t
842 _dbus_unix_user_is_at_console (dbus_uid_t         uid,
843                                DBusError         *error)
844 {
845   return _dbus_is_console_user (uid, error);
846
847 }
848
849 /**
850  * Checks to see if the UNIX user ID matches the UID of
851  * the process. Should always return #FALSE on Windows.
852  *
853  * @param uid the UNIX user ID
854  * @returns #TRUE if this uid owns the process.
855  */
856 dbus_bool_t
857 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
858 {
859   return uid == _dbus_getuid ();
860 }
861
862 /**
863  * Checks to see if the Windows user SID matches the owner of
864  * the process. Should always return #FALSE on UNIX.
865  *
866  * @param windows_sid the Windows user SID
867  * @returns #TRUE if this user owns the process.
868  */
869 dbus_bool_t
870 _dbus_windows_user_is_process_owner (const char *windows_sid)
871 {
872   return FALSE;
873 }
874
875 /** @} */ /* End of DBusInternalsUtils functions */
876
877 /**
878  * @addtogroup DBusString
879  *
880  * @{
881  */
882 /**
883  * Get the directory name from a complete filename
884  * @param filename the filename
885  * @param dirname string to append directory name to
886  * @returns #FALSE if no memory
887  */
888 dbus_bool_t
889 _dbus_string_get_dirname  (const DBusString *filename,
890                            DBusString       *dirname)
891 {
892   int sep;
893   
894   _dbus_assert (filename != dirname);
895   _dbus_assert (filename != NULL);
896   _dbus_assert (dirname != NULL);
897
898   /* Ignore any separators on the end */
899   sep = _dbus_string_get_length (filename);
900   if (sep == 0)
901     return _dbus_string_append (dirname, "."); /* empty string passed in */
902     
903   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
904     --sep;
905
906   _dbus_assert (sep >= 0);
907   
908   if (sep == 0)
909     return _dbus_string_append (dirname, "/");
910   
911   /* Now find the previous separator */
912   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
913   if (sep < 0)
914     return _dbus_string_append (dirname, ".");
915   
916   /* skip multiple separators */
917   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
918     --sep;
919
920   _dbus_assert (sep >= 0);
921   
922   if (sep == 0 &&
923       _dbus_string_get_byte (filename, 0) == '/')
924     return _dbus_string_append (dirname, "/");
925   else
926     return _dbus_string_copy_len (filename, 0, sep - 0,
927                                   dirname, _dbus_string_get_length (dirname));
928 }
929 /** @} */ /* DBusString stuff */
930