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