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