2007-03-11 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-util-unix.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
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
47 #ifdef HAVE_SYS_SYSLIMITS_H
48 #include <sys/syslimits.h>
49 #endif
50
51 #ifndef O_BINARY
52 #define O_BINARY 0
53 #endif
54
55 /**
56  * @addtogroup DBusInternalsUtils
57  * @{
58  */
59
60 /**
61  * Does the chdir, fork, setsid, etc. to become a daemon process.
62  *
63  * @param pidfile #NULL, or pidfile to create
64  * @param print_pid_pipe pipe to print daemon's pid to, or -1 for none
65  * @param error return location for errors
66  * @returns #FALSE on failure
67  */
68 dbus_bool_t
69 _dbus_become_daemon (const DBusString *pidfile,
70                      DBusPipe         *print_pid_pipe,
71                      DBusError        *error)
72 {
73   const char *s;
74   pid_t child_pid;
75   int dev_null_fd;
76
77   _dbus_verbose ("Becoming a daemon...\n");
78
79   _dbus_verbose ("chdir to /\n");
80   if (chdir ("/") < 0)
81     {
82       dbus_set_error (error, DBUS_ERROR_FAILED,
83                       "Could not chdir() to root directory");
84       return FALSE;
85     }
86
87   _dbus_verbose ("forking...\n");
88   switch ((child_pid = fork ()))
89     {
90     case -1:
91       _dbus_verbose ("fork failed\n");
92       dbus_set_error (error, _dbus_error_from_errno (errno),
93                       "Failed to fork daemon: %s", _dbus_strerror (errno));
94       return FALSE;
95       break;
96
97     case 0:
98       _dbus_verbose ("in child, closing std file descriptors\n");
99
100       /* silently ignore failures here, if someone
101        * doesn't have /dev/null we may as well try
102        * to continue anyhow
103        */
104       
105       dev_null_fd = open ("/dev/null", O_RDWR);
106       if (dev_null_fd >= 0)
107         {
108           dup2 (dev_null_fd, 0);
109           dup2 (dev_null_fd, 1);
110           
111           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
112           if (s == NULL || *s == '\0')
113             dup2 (dev_null_fd, 2);
114           else
115             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
116         }
117
118       /* Get a predictable umask */
119       _dbus_verbose ("setting umask\n");
120       umask (022);
121       break;
122
123     default:
124       if (pidfile)
125         {
126           _dbus_verbose ("parent writing pid file\n");
127           if (!_dbus_write_pid_file (pidfile,
128                                      child_pid,
129                                      error))
130             {
131               _dbus_verbose ("pid file write failed, killing child\n");
132               kill (child_pid, SIGTERM);
133               return FALSE;
134             }
135         }
136
137       /* Write PID if requested */
138       if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
139         {
140           DBusString pid;
141           int bytes;
142           
143           if (!_dbus_string_init (&pid))
144             {
145               _DBUS_SET_OOM (error);
146               kill (child_pid, SIGTERM);
147               return FALSE;
148             }
149           
150           if (!_dbus_string_append_int (&pid, child_pid) ||
151               !_dbus_string_append (&pid, "\n"))
152             {
153               _dbus_string_free (&pid);
154               _DBUS_SET_OOM (error);
155               kill (child_pid, SIGTERM);
156               return FALSE;
157             }
158           
159           bytes = _dbus_string_get_length (&pid);
160           if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
161             {
162               /* _dbus_pipe_write sets error only on failure, not short write */
163               if (error != NULL && !dbus_error_is_set(error))
164                 {
165                   dbus_set_error (error, DBUS_ERROR_FAILED,
166                                   "Printing message bus PID: did not write enough bytes\n");
167                 }
168               _dbus_string_free (&pid);
169               kill (child_pid, SIGTERM);
170               return FALSE;
171             }
172           
173           _dbus_string_free (&pid);
174         }
175       _dbus_verbose ("parent exiting\n");
176       _exit (0);
177       break;
178     }
179
180   _dbus_verbose ("calling setsid()\n");
181   if (setsid () == -1)
182     _dbus_assert_not_reached ("setsid() failed");
183   
184   return TRUE;
185 }
186
187
188 /**
189  * Creates a file containing the process ID.
190  *
191  * @param filename the filename to write to
192  * @param pid our process ID
193  * @param error return location for errors
194  * @returns #FALSE on failure
195  */
196 dbus_bool_t
197 _dbus_write_pid_file (const DBusString *filename,
198                       unsigned long     pid,
199                       DBusError        *error)
200 {
201   const char *cfilename;
202   int fd;
203   FILE *f;
204
205   cfilename = _dbus_string_get_const_data (filename);
206   
207   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
208   
209   if (fd < 0)
210     {
211       dbus_set_error (error, _dbus_error_from_errno (errno),
212                       "Failed to open \"%s\": %s", cfilename,
213                       _dbus_strerror (errno));
214       return FALSE;
215     }
216
217   if ((f = fdopen (fd, "w")) == NULL)
218     {
219       dbus_set_error (error, _dbus_error_from_errno (errno),
220                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
221       _dbus_close (fd, NULL);
222       return FALSE;
223     }
224   
225   if (fprintf (f, "%lu\n", pid) < 0)
226     {
227       dbus_set_error (error, _dbus_error_from_errno (errno),
228                       "Failed to write to \"%s\": %s", cfilename,
229                       _dbus_strerror (errno));
230       
231       fclose (f);
232       return FALSE;
233     }
234
235   if (fclose (f) == EOF)
236     {
237       dbus_set_error (error, _dbus_error_from_errno (errno),
238                       "Failed to close \"%s\": %s", cfilename,
239                       _dbus_strerror (errno));
240       return FALSE;
241     }
242   
243   return TRUE;
244 }
245
246
247 /**
248  * Changes the user and group the bus is running as.
249  *
250  * @param uid the new user ID
251  * @param gid the new group ID
252  * @param error return location for errors
253  * @returns #FALSE on failure
254  */
255 dbus_bool_t
256 _dbus_change_identity  (dbus_uid_t     uid,
257                         dbus_gid_t     gid,
258                         DBusError     *error)
259 {
260   /* setgroups() only works if we are a privileged process,
261    * so we don't return error on failure; the only possible
262    * failure is that we don't have perms to do it.
263    *
264    * not sure this is right, maybe if setuid()
265    * is going to work then setgroups() should also work.
266    */
267   if (setgroups (0, NULL) < 0)
268     _dbus_warn ("Failed to drop supplementary groups: %s\n",
269                 _dbus_strerror (errno));
270   
271   /* Set GID first, or the setuid may remove our permission
272    * to change the GID
273    */
274   if (setgid (gid) < 0)
275     {
276       dbus_set_error (error, _dbus_error_from_errno (errno),
277                       "Failed to set GID to %lu: %s", gid,
278                       _dbus_strerror (errno));
279       return FALSE;
280     }
281   
282   if (setuid (uid) < 0)
283     {
284       dbus_set_error (error, _dbus_error_from_errno (errno),
285                       "Failed to set UID to %lu: %s", uid,
286                       _dbus_strerror (errno));
287       return FALSE;
288     }
289   
290   return TRUE;
291 }
292
293 /** Installs a UNIX signal handler
294  *
295  * @param sig the signal to handle
296  * @param handler the handler
297  */
298 void
299 _dbus_set_signal_handler (int               sig,
300                           DBusSignalHandler handler)
301 {
302   struct sigaction act;
303   sigset_t empty_mask;
304   
305   sigemptyset (&empty_mask);
306   act.sa_handler = handler;
307   act.sa_mask    = empty_mask;
308   act.sa_flags   = 0;
309   sigaction (sig,  &act, NULL);
310 }
311
312
313 /**
314  * Removes a directory; Directory must be empty
315  * 
316  * @param filename directory filename
317  * @param error initialized error object
318  * @returns #TRUE on success
319  */
320 dbus_bool_t
321 _dbus_delete_directory (const DBusString *filename,
322                         DBusError        *error)
323 {
324   const char *filename_c;
325   
326   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
327
328   filename_c = _dbus_string_get_const_data (filename);
329
330   if (rmdir (filename_c) != 0)
331     {
332       dbus_set_error (error, DBUS_ERROR_FAILED,
333                       "Failed to remove directory %s: %s\n",
334                       filename_c, _dbus_strerror (errno));
335       return FALSE;
336     }
337   
338   return TRUE;
339 }
340
341 /** Checks if a file exists
342 *
343 * @param file full path to the file
344 * @returns #TRUE if file exists
345 */
346 dbus_bool_t 
347 _dbus_file_exists (const char *file)
348 {
349   return (access (file, F_OK) == 0);
350 }
351
352 /** Checks if user is at the console
353 *
354 * @param username user to check
355 * @param error return location for errors
356 * @returns #TRUE is the user is at the consolei and there are no errors
357 */
358 dbus_bool_t 
359 _dbus_user_at_console (const char *username,
360                        DBusError  *error)
361 {
362
363   DBusString f;
364   dbus_bool_t result;
365
366   result = FALSE;
367   if (!_dbus_string_init (&f))
368     {
369       _DBUS_SET_OOM (error);
370       return FALSE;
371     }
372
373   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
374     {
375       _DBUS_SET_OOM (error);
376       goto out;
377     }
378
379
380   if (!_dbus_string_append (&f, username))
381     {
382       _DBUS_SET_OOM (error);
383       goto out;
384     }
385
386   result = _dbus_file_exists (_dbus_string_get_const_data (&f));
387
388  out:
389   _dbus_string_free (&f);
390
391   return result;
392 }
393
394
395 /**
396  * Checks whether the filename is an absolute path
397  *
398  * @param filename the filename
399  * @returns #TRUE if an absolute path
400  */
401 dbus_bool_t
402 _dbus_path_is_absolute (const DBusString *filename)
403 {
404   if (_dbus_string_get_length (filename) > 0)
405     return _dbus_string_get_byte (filename, 0) == '/';
406   else
407     return FALSE;
408 }
409
410 /**
411  * stat() wrapper.
412  *
413  * @param filename the filename to stat
414  * @param statbuf the stat info to fill in
415  * @param error return location for error
416  * @returns #FALSE if error was set
417  */
418 dbus_bool_t
419 _dbus_stat (const DBusString *filename,
420             DBusStat         *statbuf,
421             DBusError        *error)
422 {
423   const char *filename_c;
424   struct stat sb;
425
426   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
427   
428   filename_c = _dbus_string_get_const_data (filename);
429
430   if (stat (filename_c, &sb) < 0)
431     {
432       dbus_set_error (error, _dbus_error_from_errno (errno),
433                       "%s", _dbus_strerror (errno));
434       return FALSE;
435     }
436
437   statbuf->mode = sb.st_mode;
438   statbuf->nlink = sb.st_nlink;
439   statbuf->uid = sb.st_uid;
440   statbuf->gid = sb.st_gid;
441   statbuf->size = sb.st_size;
442   statbuf->atime = sb.st_atime;
443   statbuf->mtime = sb.st_mtime;
444   statbuf->ctime = sb.st_ctime;
445
446   return TRUE;
447 }
448
449
450 /**
451  * Internals of directory iterator
452  */
453 struct DBusDirIter
454 {
455   DIR *d; /**< The DIR* from opendir() */
456   
457 };
458
459 /**
460  * Open a directory to iterate over.
461  *
462  * @param filename the directory name
463  * @param error exception return object or #NULL
464  * @returns new iterator, or #NULL on error
465  */
466 DBusDirIter*
467 _dbus_directory_open (const DBusString *filename,
468                       DBusError        *error)
469 {
470   DIR *d;
471   DBusDirIter *iter;
472   const char *filename_c;
473
474   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
475   
476   filename_c = _dbus_string_get_const_data (filename);
477
478   d = opendir (filename_c);
479   if (d == NULL)
480     {
481       dbus_set_error (error, _dbus_error_from_errno (errno),
482                       "Failed to read directory \"%s\": %s",
483                       filename_c,
484                       _dbus_strerror (errno));
485       return NULL;
486     }
487   iter = dbus_new0 (DBusDirIter, 1);
488   if (iter == NULL)
489     {
490       closedir (d);
491       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
492                       "Could not allocate memory for directory iterator");
493       return NULL;
494     }
495
496   iter->d = d;
497
498   return iter;
499 }
500
501 /* Calculate the required buffer size (in bytes) for directory
502  * entries read from the given directory handle.  Return -1 if this
503  * this cannot be done. 
504  *
505  * If you use autoconf, include fpathconf and dirfd in your
506  * AC_CHECK_FUNCS list.  Otherwise use some other method to detect
507  * and use them where available.
508  */
509 static dbus_bool_t
510 dirent_buf_size(DIR * dirp, size_t *size)
511 {
512  long name_max;
513 #   if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
514 #      if defined(HAVE_DIRFD)
515           name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
516 #      elif defined(HAVE_DDFD)
517           name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
518 #      else
519           name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
520 #      endif /* HAVE_DIRFD */
521      if (name_max == -1)
522 #           if defined(NAME_MAX)
523              name_max = NAME_MAX;
524 #           else
525              return FALSE;
526 #           endif
527 #   elif defined(MAXNAMELEN)
528      name_max = MAXNAMELEN;
529 #   else
530 #       if defined(NAME_MAX)
531          name_max = NAME_MAX;
532 #       else
533 #           error "buffer size for readdir_r cannot be determined"
534 #       endif
535 #   endif
536   if (size)
537     *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
538   else
539     return FALSE;
540
541   return TRUE;
542 }
543
544 /**
545  * Get next file in the directory. Will not return "." or ".."  on
546  * UNIX. If an error occurs, the contents of "filename" are
547  * undefined. The error is never set if the function succeeds.
548  *
549  * @param iter the iterator
550  * @param filename string to be set to the next file in the dir
551  * @param error return location for error
552  * @returns #TRUE if filename was filled in with a new filename
553  */
554 dbus_bool_t
555 _dbus_directory_get_next_file (DBusDirIter      *iter,
556                                DBusString       *filename,
557                                DBusError        *error)
558 {
559   struct dirent *d, *ent;
560   size_t buf_size;
561   int err;
562
563   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
564  
565   if (!dirent_buf_size (iter->d, &buf_size))
566     {
567       dbus_set_error (error, DBUS_ERROR_FAILED,
568                       "Can't calculate buffer size when reading directory");
569       return FALSE;
570     }
571
572   d = (struct dirent *)dbus_malloc (buf_size);
573   if (!d)
574     {
575       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
576                       "No memory to read directory entry");
577       return FALSE;
578     }
579
580  again:
581   err = readdir_r (iter->d, d, &ent);
582   if (err || !ent)
583     {
584       if (err != 0)
585         dbus_set_error (error,
586                         _dbus_error_from_errno (err),
587                         "%s", _dbus_strerror (err));
588
589       dbus_free (d);
590       return FALSE;
591     }
592   else if (ent->d_name[0] == '.' &&
593            (ent->d_name[1] == '\0' ||
594             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
595     goto again;
596   else
597     {
598       _dbus_string_set_length (filename, 0);
599       if (!_dbus_string_append (filename, ent->d_name))
600         {
601           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
602                           "No memory to read directory entry");
603           dbus_free (d);
604           return FALSE;
605         }
606       else
607         {
608           dbus_free (d);
609           return TRUE;
610         }
611     }
612 }
613
614 /**
615  * Closes a directory iteration.
616  */
617 void
618 _dbus_directory_close (DBusDirIter *iter)
619 {
620   closedir (iter->d);
621   dbus_free (iter);
622 }
623
624 static dbus_bool_t
625 fill_user_info_from_group (struct group  *g,
626                            DBusGroupInfo *info,
627                            DBusError     *error)
628 {
629   _dbus_assert (g->gr_name != NULL);
630   
631   info->gid = g->gr_gid;
632   info->groupname = _dbus_strdup (g->gr_name);
633
634   /* info->members = dbus_strdupv (g->gr_mem) */
635   
636   if (info->groupname == NULL)
637     {
638       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
639       return FALSE;
640     }
641
642   return TRUE;
643 }
644
645 static dbus_bool_t
646 fill_group_info (DBusGroupInfo    *info,
647                  dbus_gid_t        gid,
648                  const DBusString *groupname,
649                  DBusError        *error)
650 {
651   const char *group_c_str;
652
653   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
654   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
655
656   if (groupname)
657     group_c_str = _dbus_string_get_const_data (groupname);
658   else
659     group_c_str = NULL;
660   
661   /* For now assuming that the getgrnam() and getgrgid() flavors
662    * always correspond to the pwnam flavors, if not we have
663    * to add more configure checks.
664    */
665   
666 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
667   {
668     struct group *g;
669     int result;
670     char buf[1024];
671     struct group g_str;
672
673     g = NULL;
674 #ifdef HAVE_POSIX_GETPWNAM_R
675
676     if (group_c_str)
677       result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
678                            &g);
679     else
680       result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
681                            &g);
682 #else
683     g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
684     result = 0;
685 #endif /* !HAVE_POSIX_GETPWNAM_R */
686     if (result == 0 && g == &g_str)
687       {
688         return fill_user_info_from_group (g, info, error);
689       }
690     else
691       {
692         dbus_set_error (error, _dbus_error_from_errno (errno),
693                         "Group %s unknown or failed to look it up\n",
694                         group_c_str ? group_c_str : "???");
695         return FALSE;
696       }
697   }
698 #else /* ! HAVE_GETPWNAM_R */
699   {
700     /* I guess we're screwed on thread safety here */
701     struct group *g;
702
703     g = getgrnam (group_c_str);
704
705     if (g != NULL)
706       {
707         return fill_user_info_from_group (g, info, error);
708       }
709     else
710       {
711         dbus_set_error (error, _dbus_error_from_errno (errno),
712                         "Group %s unknown or failed to look it up\n",
713                         group_c_str ? group_c_str : "???");
714         return FALSE;
715       }
716   }
717 #endif  /* ! HAVE_GETPWNAM_R */
718 }
719
720 /**
721  * Initializes the given DBusGroupInfo struct
722  * with information about the given group name.
723  *
724  * @param info the group info struct
725  * @param groupname name of group
726  * @param error the error return
727  * @returns #FALSE if error is set
728  */
729 dbus_bool_t
730 _dbus_group_info_fill (DBusGroupInfo    *info,
731                        const DBusString *groupname,
732                        DBusError        *error)
733 {
734   return fill_group_info (info, DBUS_GID_UNSET,
735                           groupname, error);
736
737 }
738
739 /**
740  * Initializes the given DBusGroupInfo struct
741  * with information about the given group ID.
742  *
743  * @param info the group info struct
744  * @param gid group ID
745  * @param error the error return
746  * @returns #FALSE if error is set
747  */
748 dbus_bool_t
749 _dbus_group_info_fill_gid (DBusGroupInfo *info,
750                            dbus_gid_t     gid,
751                            DBusError     *error)
752 {
753   return fill_group_info (info, gid, NULL, error);
754 }
755
756 /** @} */ /* End of DBusInternalsUtils functions */
757
758 /**
759  * @addtogroup DBusString
760  *
761  * @{
762  */
763 /**
764  * Get the directory name from a complete filename
765  * @param filename the filename
766  * @param dirname string to append directory name to
767  * @returns #FALSE if no memory
768  */
769 dbus_bool_t
770 _dbus_string_get_dirname  (const DBusString *filename,
771                            DBusString       *dirname)
772 {
773   int sep;
774   
775   _dbus_assert (filename != dirname);
776   _dbus_assert (filename != NULL);
777   _dbus_assert (dirname != NULL);
778
779   /* Ignore any separators on the end */
780   sep = _dbus_string_get_length (filename);
781   if (sep == 0)
782     return _dbus_string_append (dirname, "."); /* empty string passed in */
783     
784   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
785     --sep;
786
787   _dbus_assert (sep >= 0);
788   
789   if (sep == 0)
790     return _dbus_string_append (dirname, "/");
791   
792   /* Now find the previous separator */
793   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
794   if (sep < 0)
795     return _dbus_string_append (dirname, ".");
796   
797   /* skip multiple separators */
798   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
799     --sep;
800
801   _dbus_assert (sep >= 0);
802   
803   if (sep == 0 &&
804       _dbus_string_get_byte (filename, 0) == '/')
805     return _dbus_string_append (dirname, "/");
806   else
807     return _dbus_string_copy_len (filename, 0, sep - 0,
808                                   dirname, _dbus_string_get_length (dirname));
809 }
810 /** @} */ /* DBusString stuff */
811