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