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