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