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