Merge commit '3d6abf64d0abb2718e082e120f14f8f923a4af59' into dbus-1.2
[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_geteuid () == 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 void 
455 _dbus_init_system_log (void)
456 {
457   openlog ("dbus", LOG_PID, LOG_DAEMON);
458 }
459
460 /**
461  * Log an informative message.  Intended for use primarily by
462  * the system bus.
463  *
464  * @param msg a printf-style format string
465  * @param args arguments for the format string
466  */
467 void 
468 _dbus_log_info (const char *msg, va_list args)
469 {
470   vsyslog (LOG_DAEMON|LOG_NOTICE, msg, args);
471 }
472
473 /**
474  * Log a security-related message.  Intended for use primarily by
475  * the system bus.
476  *
477  * @param msg a printf-style format string
478  * @param args arguments for the format string
479  */
480 void 
481 _dbus_log_security (const char *msg, va_list args)
482 {
483   vsyslog (LOG_AUTH|LOG_NOTICE, msg, args);
484 }
485
486 /** Installs a UNIX signal handler
487  *
488  * @param sig the signal to handle
489  * @param handler the handler
490  */
491 void
492 _dbus_set_signal_handler (int               sig,
493                           DBusSignalHandler handler)
494 {
495   struct sigaction act;
496   sigset_t empty_mask;
497   
498   sigemptyset (&empty_mask);
499   act.sa_handler = handler;
500   act.sa_mask    = empty_mask;
501   act.sa_flags   = 0;
502   sigaction (sig,  &act, NULL);
503 }
504
505
506 /**
507  * Removes a directory; Directory must be empty
508  * 
509  * @param filename directory filename
510  * @param error initialized error object
511  * @returns #TRUE on success
512  */
513 dbus_bool_t
514 _dbus_delete_directory (const DBusString *filename,
515                         DBusError        *error)
516 {
517   const char *filename_c;
518   
519   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
520
521   filename_c = _dbus_string_get_const_data (filename);
522
523   if (rmdir (filename_c) != 0)
524     {
525       dbus_set_error (error, DBUS_ERROR_FAILED,
526                       "Failed to remove directory %s: %s\n",
527                       filename_c, _dbus_strerror (errno));
528       return FALSE;
529     }
530   
531   return TRUE;
532 }
533
534 /** Checks if a file exists
535 *
536 * @param file full path to the file
537 * @returns #TRUE if file exists
538 */
539 dbus_bool_t 
540 _dbus_file_exists (const char *file)
541 {
542   return (access (file, F_OK) == 0);
543 }
544
545 /** Checks if user is at the console
546 *
547 * @param username user to check
548 * @param error return location for errors
549 * @returns #TRUE is the user is at the consolei and there are no errors
550 */
551 dbus_bool_t 
552 _dbus_user_at_console (const char *username,
553                        DBusError  *error)
554 {
555
556   DBusString f;
557   dbus_bool_t result;
558
559   result = FALSE;
560   if (!_dbus_string_init (&f))
561     {
562       _DBUS_SET_OOM (error);
563       return FALSE;
564     }
565
566   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
567     {
568       _DBUS_SET_OOM (error);
569       goto out;
570     }
571
572
573   if (!_dbus_string_append (&f, username))
574     {
575       _DBUS_SET_OOM (error);
576       goto out;
577     }
578
579   result = _dbus_file_exists (_dbus_string_get_const_data (&f));
580
581  out:
582   _dbus_string_free (&f);
583
584   return result;
585 }
586
587
588 /**
589  * Checks whether the filename is an absolute path
590  *
591  * @param filename the filename
592  * @returns #TRUE if an absolute path
593  */
594 dbus_bool_t
595 _dbus_path_is_absolute (const DBusString *filename)
596 {
597   if (_dbus_string_get_length (filename) > 0)
598     return _dbus_string_get_byte (filename, 0) == '/';
599   else
600     return FALSE;
601 }
602
603 /**
604  * stat() wrapper.
605  *
606  * @param filename the filename to stat
607  * @param statbuf the stat info to fill in
608  * @param error return location for error
609  * @returns #FALSE if error was set
610  */
611 dbus_bool_t
612 _dbus_stat (const DBusString *filename,
613             DBusStat         *statbuf,
614             DBusError        *error)
615 {
616   const char *filename_c;
617   struct stat sb;
618
619   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
620   
621   filename_c = _dbus_string_get_const_data (filename);
622
623   if (stat (filename_c, &sb) < 0)
624     {
625       dbus_set_error (error, _dbus_error_from_errno (errno),
626                       "%s", _dbus_strerror (errno));
627       return FALSE;
628     }
629
630   statbuf->mode = sb.st_mode;
631   statbuf->nlink = sb.st_nlink;
632   statbuf->uid = sb.st_uid;
633   statbuf->gid = sb.st_gid;
634   statbuf->size = sb.st_size;
635   statbuf->atime = sb.st_atime;
636   statbuf->mtime = sb.st_mtime;
637   statbuf->ctime = sb.st_ctime;
638
639   return TRUE;
640 }
641
642
643 /**
644  * Internals of directory iterator
645  */
646 struct DBusDirIter
647 {
648   DIR *d; /**< The DIR* from opendir() */
649   
650 };
651
652 /**
653  * Open a directory to iterate over.
654  *
655  * @param filename the directory name
656  * @param error exception return object or #NULL
657  * @returns new iterator, or #NULL on error
658  */
659 DBusDirIter*
660 _dbus_directory_open (const DBusString *filename,
661                       DBusError        *error)
662 {
663   DIR *d;
664   DBusDirIter *iter;
665   const char *filename_c;
666
667   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
668   
669   filename_c = _dbus_string_get_const_data (filename);
670
671   d = opendir (filename_c);
672   if (d == NULL)
673     {
674       dbus_set_error (error, _dbus_error_from_errno (errno),
675                       "Failed to read directory \"%s\": %s",
676                       filename_c,
677                       _dbus_strerror (errno));
678       return NULL;
679     }
680   iter = dbus_new0 (DBusDirIter, 1);
681   if (iter == NULL)
682     {
683       closedir (d);
684       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
685                       "Could not allocate memory for directory iterator");
686       return NULL;
687     }
688
689   iter->d = d;
690
691   return iter;
692 }
693
694 /* Calculate the required buffer size (in bytes) for directory
695  * entries read from the given directory handle.  Return -1 if this
696  * this cannot be done. 
697  *
698  * If you use autoconf, include fpathconf and dirfd in your
699  * AC_CHECK_FUNCS list.  Otherwise use some other method to detect
700  * and use them where available.
701  */
702 static dbus_bool_t
703 dirent_buf_size(DIR * dirp, size_t *size)
704 {
705  long name_max;
706 #   if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
707 #      if defined(HAVE_DIRFD)
708           name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
709 #      elif defined(HAVE_DDFD)
710           name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
711 #      else
712           name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
713 #      endif /* HAVE_DIRFD */
714      if (name_max == -1)
715 #           if defined(NAME_MAX)
716              name_max = NAME_MAX;
717 #           else
718              return FALSE;
719 #           endif
720 #   elif defined(MAXNAMELEN)
721      name_max = MAXNAMELEN;
722 #   else
723 #       if defined(NAME_MAX)
724          name_max = NAME_MAX;
725 #       else
726 #           error "buffer size for readdir_r cannot be determined"
727 #       endif
728 #   endif
729   if (size)
730     *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
731   else
732     return FALSE;
733
734   return TRUE;
735 }
736
737 /**
738  * Get next file in the directory. Will not return "." or ".."  on
739  * UNIX. If an error occurs, the contents of "filename" are
740  * undefined. The error is never set if the function succeeds.
741  *
742  * @param iter the iterator
743  * @param filename string to be set to the next file in the dir
744  * @param error return location for error
745  * @returns #TRUE if filename was filled in with a new filename
746  */
747 dbus_bool_t
748 _dbus_directory_get_next_file (DBusDirIter      *iter,
749                                DBusString       *filename,
750                                DBusError        *error)
751 {
752   struct dirent *d, *ent;
753   size_t buf_size;
754   int err;
755
756   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
757  
758   if (!dirent_buf_size (iter->d, &buf_size))
759     {
760       dbus_set_error (error, DBUS_ERROR_FAILED,
761                       "Can't calculate buffer size when reading directory");
762       return FALSE;
763     }
764
765   d = (struct dirent *)dbus_malloc (buf_size);
766   if (!d)
767     {
768       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
769                       "No memory to read directory entry");
770       return FALSE;
771     }
772
773  again:
774   err = readdir_r (iter->d, d, &ent);
775   if (err || !ent)
776     {
777       if (err != 0)
778         dbus_set_error (error,
779                         _dbus_error_from_errno (err),
780                         "%s", _dbus_strerror (err));
781
782       dbus_free (d);
783       return FALSE;
784     }
785   else if (ent->d_name[0] == '.' &&
786            (ent->d_name[1] == '\0' ||
787             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
788     goto again;
789   else
790     {
791       _dbus_string_set_length (filename, 0);
792       if (!_dbus_string_append (filename, ent->d_name))
793         {
794           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
795                           "No memory to read directory entry");
796           dbus_free (d);
797           return FALSE;
798         }
799       else
800         {
801           dbus_free (d);
802           return TRUE;
803         }
804     }
805 }
806
807 /**
808  * Closes a directory iteration.
809  */
810 void
811 _dbus_directory_close (DBusDirIter *iter)
812 {
813   closedir (iter->d);
814   dbus_free (iter);
815 }
816
817 static dbus_bool_t
818 fill_user_info_from_group (struct group  *g,
819                            DBusGroupInfo *info,
820                            DBusError     *error)
821 {
822   _dbus_assert (g->gr_name != NULL);
823   
824   info->gid = g->gr_gid;
825   info->groupname = _dbus_strdup (g->gr_name);
826
827   /* info->members = dbus_strdupv (g->gr_mem) */
828   
829   if (info->groupname == NULL)
830     {
831       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
832       return FALSE;
833     }
834
835   return TRUE;
836 }
837
838 static dbus_bool_t
839 fill_group_info (DBusGroupInfo    *info,
840                  dbus_gid_t        gid,
841                  const DBusString *groupname,
842                  DBusError        *error)
843 {
844   const char *group_c_str;
845
846   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
847   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
848
849   if (groupname)
850     group_c_str = _dbus_string_get_const_data (groupname);
851   else
852     group_c_str = NULL;
853   
854   /* For now assuming that the getgrnam() and getgrgid() flavors
855    * always correspond to the pwnam flavors, if not we have
856    * to add more configure checks.
857    */
858   
859 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
860   {
861     struct group *g;
862     int result;
863     size_t buflen;
864     char *buf;
865     struct group g_str;
866     dbus_bool_t b;
867
868     /* retrieve maximum needed size for buf */
869     buflen = sysconf (_SC_GETGR_R_SIZE_MAX);
870
871     /* sysconf actually returns a long, but everything else expects size_t,
872      * so just recast here.
873      * https://bugs.freedesktop.org/show_bug.cgi?id=17061
874      */
875     if ((long) buflen <= 0)
876       buflen = 1024;
877
878     result = -1;
879     while (1)
880       {
881         buf = dbus_malloc (buflen);
882         if (buf == NULL)
883           {
884             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
885             return FALSE;
886           }
887
888         g = NULL;
889 #ifdef HAVE_POSIX_GETPWNAM_R
890         if (group_c_str)
891           result = getgrnam_r (group_c_str, &g_str, buf, buflen,
892                                &g);
893         else
894           result = getgrgid_r (gid, &g_str, buf, buflen,
895                                &g);
896 #else
897         g = getgrnam_r (group_c_str, &g_str, buf, buflen);
898         result = 0;
899 #endif /* !HAVE_POSIX_GETPWNAM_R */
900         /* Try a bigger buffer if ERANGE was returned:
901            https://bugs.freedesktop.org/show_bug.cgi?id=16727
902         */
903         if (result == ERANGE && buflen < 512 * 1024)
904           {
905             dbus_free (buf);
906             buflen *= 2;
907           }
908         else
909           {
910             break;
911           }
912       }
913
914     if (result == 0 && g == &g_str)
915       {
916         b = fill_user_info_from_group (g, info, error);
917         dbus_free (buf);
918         return b;
919       }
920     else
921       {
922         dbus_set_error (error, _dbus_error_from_errno (errno),
923                         "Group %s unknown or failed to look it up\n",
924                         group_c_str ? group_c_str : "???");
925         dbus_free (buf);
926         return FALSE;
927       }
928   }
929 #else /* ! HAVE_GETPWNAM_R */
930   {
931     /* I guess we're screwed on thread safety here */
932     struct group *g;
933
934     g = getgrnam (group_c_str);
935
936     if (g != NULL)
937       {
938         return fill_user_info_from_group (g, info, error);
939       }
940     else
941       {
942         dbus_set_error (error, _dbus_error_from_errno (errno),
943                         "Group %s unknown or failed to look it up\n",
944                         group_c_str ? group_c_str : "???");
945         return FALSE;
946       }
947   }
948 #endif  /* ! HAVE_GETPWNAM_R */
949 }
950
951 /**
952  * Initializes the given DBusGroupInfo struct
953  * with information about the given group name.
954  *
955  * @param info the group info struct
956  * @param groupname name of group
957  * @param error the error return
958  * @returns #FALSE if error is set
959  */
960 dbus_bool_t
961 _dbus_group_info_fill (DBusGroupInfo    *info,
962                        const DBusString *groupname,
963                        DBusError        *error)
964 {
965   return fill_group_info (info, DBUS_GID_UNSET,
966                           groupname, error);
967
968 }
969
970 /**
971  * Initializes the given DBusGroupInfo struct
972  * with information about the given group ID.
973  *
974  * @param info the group info struct
975  * @param gid group ID
976  * @param error the error return
977  * @returns #FALSE if error is set
978  */
979 dbus_bool_t
980 _dbus_group_info_fill_gid (DBusGroupInfo *info,
981                            dbus_gid_t     gid,
982                            DBusError     *error)
983 {
984   return fill_group_info (info, gid, NULL, error);
985 }
986
987 /**
988  * Parse a UNIX user from the bus config file. On Windows, this should
989  * simply always fail (just return #FALSE).
990  *
991  * @param username the username text
992  * @param uid_p place to return the uid
993  * @returns #TRUE on success
994  */
995 dbus_bool_t
996 _dbus_parse_unix_user_from_config (const DBusString  *username,
997                                    dbus_uid_t        *uid_p)
998 {
999   return _dbus_get_user_id (username, uid_p);
1000
1001 }
1002
1003 /**
1004  * Parse a UNIX group from the bus config file. On Windows, this should
1005  * simply always fail (just return #FALSE).
1006  *
1007  * @param groupname the groupname text
1008  * @param gid_p place to return the gid
1009  * @returns #TRUE on success
1010  */
1011 dbus_bool_t
1012 _dbus_parse_unix_group_from_config (const DBusString  *groupname,
1013                                     dbus_gid_t        *gid_p)
1014 {
1015   return _dbus_get_group_id (groupname, gid_p);
1016 }
1017
1018 /**
1019  * Gets all groups corresponding to the given UNIX user ID. On UNIX,
1020  * just calls _dbus_groups_from_uid(). On Windows, should always
1021  * fail since we don't know any UNIX groups.
1022  *
1023  * @param uid the UID
1024  * @param group_ids return location for array of group IDs
1025  * @param n_group_ids return location for length of returned array
1026  * @returns #TRUE if the UID existed and we got some credentials
1027  */
1028 dbus_bool_t
1029 _dbus_unix_groups_from_uid (dbus_uid_t            uid,
1030                             dbus_gid_t          **group_ids,
1031                             int                  *n_group_ids)
1032 {
1033   return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
1034 }
1035
1036 /**
1037  * Checks to see if the UNIX user ID is at the console.
1038  * Should always fail on Windows (set the error to
1039  * #DBUS_ERROR_NOT_SUPPORTED).
1040  *
1041  * @param uid UID of person to check 
1042  * @param error return location for errors
1043  * @returns #TRUE if the UID is the same as the console user and there are no errors
1044  */
1045 dbus_bool_t
1046 _dbus_unix_user_is_at_console (dbus_uid_t         uid,
1047                                DBusError         *error)
1048 {
1049   return _dbus_is_console_user (uid, error);
1050
1051 }
1052
1053 /**
1054  * Checks to see if the UNIX user ID matches the UID of
1055  * the process. Should always return #FALSE on Windows.
1056  *
1057  * @param uid the UNIX user ID
1058  * @returns #TRUE if this uid owns the process.
1059  */
1060 dbus_bool_t
1061 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
1062 {
1063   return uid == _dbus_geteuid ();
1064 }
1065
1066 /**
1067  * Checks to see if the Windows user SID matches the owner of
1068  * the process. Should always return #FALSE on UNIX.
1069  *
1070  * @param windows_sid the Windows user SID
1071  * @returns #TRUE if this user owns the process.
1072  */
1073 dbus_bool_t
1074 _dbus_windows_user_is_process_owner (const char *windows_sid)
1075 {
1076   return FALSE;
1077 }
1078
1079 /** @} */ /* End of DBusInternalsUtils functions */
1080
1081 /**
1082  * @addtogroup DBusString
1083  *
1084  * @{
1085  */
1086 /**
1087  * Get the directory name from a complete filename
1088  * @param filename the filename
1089  * @param dirname string to append directory name to
1090  * @returns #FALSE if no memory
1091  */
1092 dbus_bool_t
1093 _dbus_string_get_dirname  (const DBusString *filename,
1094                            DBusString       *dirname)
1095 {
1096   int sep;
1097   
1098   _dbus_assert (filename != dirname);
1099   _dbus_assert (filename != NULL);
1100   _dbus_assert (dirname != NULL);
1101
1102   /* Ignore any separators on the end */
1103   sep = _dbus_string_get_length (filename);
1104   if (sep == 0)
1105     return _dbus_string_append (dirname, "."); /* empty string passed in */
1106     
1107   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
1108     --sep;
1109
1110   _dbus_assert (sep >= 0);
1111   
1112   if (sep == 0)
1113     return _dbus_string_append (dirname, "/");
1114   
1115   /* Now find the previous separator */
1116   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
1117   if (sep < 0)
1118     return _dbus_string_append (dirname, ".");
1119   
1120   /* skip multiple separators */
1121   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
1122     --sep;
1123
1124   _dbus_assert (sep >= 0);
1125   
1126   if (sep == 0 &&
1127       _dbus_string_get_byte (filename, 0) == '/')
1128     return _dbus_string_append (dirname, "/");
1129   else
1130     return _dbus_string_copy_len (filename, 0, sep - 0,
1131                                   dirname, _dbus_string_get_length (dirname));
1132 }
1133 /** @} */ /* DBusString stuff */
1134