dbus-sysdeps-util-unix.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-sysdeps-util-unix.c Would be in dbus-sysdeps-unix.c, but not used in libdbus
00003  * 
00004  * Copyright (C) 2002, 2003, 2004, 2005  Red Hat, Inc.
00005  * Copyright (C) 2003 CodeFactory AB
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 #include "dbus-sysdeps.h"
00025 #include "dbus-sysdeps-unix.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-protocol.h"
00028 #include "dbus-string.h"
00029 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00030 #include "dbus-userdb.h"
00031 #include "dbus-test.h"
00032 
00033 #include <sys/types.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <signal.h>
00037 #include <unistd.h>
00038 #include <stdio.h>
00039 #include <errno.h>
00040 #include <fcntl.h>
00041 #include <sys/stat.h>
00042 #include <grp.h>
00043 #include <sys/socket.h>
00044 #include <dirent.h>
00045 #include <sys/un.h>
00046 #include <glob.h>
00047 
00048 #ifdef HAVE_SYS_SYSLIMITS_H
00049 #include <sys/syslimits.h>
00050 #endif
00051 
00052 #ifndef O_BINARY
00053 #define O_BINARY 0
00054 #endif
00055 
00069 dbus_bool_t
00070 _dbus_become_daemon (const DBusString *pidfile,
00071                      int               print_pid_fd,
00072                      DBusError        *error)
00073 {
00074   const char *s;
00075   pid_t child_pid;
00076   int dev_null_fd;
00077 
00078   _dbus_verbose ("Becoming a daemon...\n");
00079 
00080   _dbus_verbose ("chdir to /\n");
00081   if (chdir ("/") < 0)
00082     {
00083       dbus_set_error (error, DBUS_ERROR_FAILED,
00084                       "Could not chdir() to root directory");
00085       return FALSE;
00086     }
00087 
00088   _dbus_verbose ("forking...\n");
00089   switch ((child_pid = fork ()))
00090     {
00091     case -1:
00092       _dbus_verbose ("fork failed\n");
00093       dbus_set_error (error, _dbus_error_from_errno (errno),
00094                       "Failed to fork daemon: %s", _dbus_strerror (errno));
00095       return FALSE;
00096       break;
00097 
00098     case 0:
00099       _dbus_verbose ("in child, closing std file descriptors\n");
00100 
00101       /* silently ignore failures here, if someone
00102        * doesn't have /dev/null we may as well try
00103        * to continue anyhow
00104        */
00105       
00106       dev_null_fd = open ("/dev/null", O_RDWR);
00107       if (dev_null_fd >= 0)
00108         {
00109           dup2 (dev_null_fd, 0);
00110           dup2 (dev_null_fd, 1);
00111           
00112           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00113           if (s == NULL || *s == '\0')
00114             dup2 (dev_null_fd, 2);
00115           else
00116             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00117         }
00118 
00119       /* Get a predictable umask */
00120       _dbus_verbose ("setting umask\n");
00121       umask (022);
00122       break;
00123 
00124     default:
00125       if (pidfile)
00126         {
00127           _dbus_verbose ("parent writing pid file\n");
00128           if (!_dbus_write_pid_file (pidfile,
00129                                      child_pid,
00130                                      error))
00131             {
00132               _dbus_verbose ("pid file write failed, killing child\n");
00133               kill (child_pid, SIGTERM);
00134               return FALSE;
00135             }
00136         }
00137 
00138       /* Write PID if requested */
00139       if (print_pid_fd >= 0)
00140         {
00141           DBusString pid;
00142           int bytes;
00143           
00144           if (!_dbus_string_init (&pid))
00145             {
00146               _DBUS_SET_OOM (error);
00147               kill (child_pid, SIGTERM);
00148               return FALSE;
00149             }
00150           
00151           if (!_dbus_string_append_int (&pid, child_pid) ||
00152               !_dbus_string_append (&pid, "\n"))
00153             {
00154               _dbus_string_free (&pid);
00155               _DBUS_SET_OOM (error);
00156               kill (child_pid, SIGTERM);
00157               return FALSE;
00158             }
00159           
00160           bytes = _dbus_string_get_length (&pid);
00161           if (_dbus_write_socket (print_pid_fd, &pid, 0, bytes) != bytes)
00162             {
00163               dbus_set_error (error, DBUS_ERROR_FAILED,
00164                               "Printing message bus PID: %s\n",
00165                               _dbus_strerror (errno));
00166               _dbus_string_free (&pid);
00167               kill (child_pid, SIGTERM);
00168               return FALSE;
00169             }
00170           
00171           _dbus_string_free (&pid);
00172         }
00173       _dbus_verbose ("parent exiting\n");
00174       _exit (0);
00175       break;
00176     }
00177 
00178   _dbus_verbose ("calling setsid()\n");
00179   if (setsid () == -1)
00180     _dbus_assert_not_reached ("setsid() failed");
00181   
00182   return TRUE;
00183 }
00184 
00185 
00194 dbus_bool_t
00195 _dbus_write_pid_file (const DBusString *filename,
00196                       unsigned long     pid,
00197                       DBusError        *error)
00198 {
00199   const char *cfilename;
00200   int fd;
00201   FILE *f;
00202 
00203   cfilename = _dbus_string_get_const_data (filename);
00204   
00205   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00206   
00207   if (fd < 0)
00208     {
00209       dbus_set_error (error, _dbus_error_from_errno (errno),
00210                       "Failed to open \"%s\": %s", cfilename,
00211                       _dbus_strerror (errno));
00212       return FALSE;
00213     }
00214 
00215   if ((f = fdopen (fd, "w")) == NULL)
00216     {
00217       dbus_set_error (error, _dbus_error_from_errno (errno),
00218                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00219       _dbus_close (fd, NULL);
00220       return FALSE;
00221     }
00222   
00223   if (fprintf (f, "%lu\n", pid) < 0)
00224     {
00225       dbus_set_error (error, _dbus_error_from_errno (errno),
00226                       "Failed to write to \"%s\": %s", cfilename,
00227                       _dbus_strerror (errno));
00228       
00229       fclose (f);
00230       return FALSE;
00231     }
00232 
00233   if (fclose (f) == EOF)
00234     {
00235       dbus_set_error (error, _dbus_error_from_errno (errno),
00236                       "Failed to close \"%s\": %s", cfilename,
00237                       _dbus_strerror (errno));
00238       return FALSE;
00239     }
00240   
00241   return TRUE;
00242 }
00243 
00244 
00253 dbus_bool_t
00254 _dbus_change_identity  (dbus_uid_t     uid,
00255                         dbus_gid_t     gid,
00256                         DBusError     *error)
00257 {
00258   /* setgroups() only works if we are a privileged process,
00259    * so we don't return error on failure; the only possible
00260    * failure is that we don't have perms to do it.
00261    *
00262    * not sure this is right, maybe if setuid()
00263    * is going to work then setgroups() should also work.
00264    */
00265   if (setgroups (0, NULL) < 0)
00266     _dbus_warn ("Failed to drop supplementary groups: %s\n",
00267                 _dbus_strerror (errno));
00268   
00269   /* Set GID first, or the setuid may remove our permission
00270    * to change the GID
00271    */
00272   if (setgid (gid) < 0)
00273     {
00274       dbus_set_error (error, _dbus_error_from_errno (errno),
00275                       "Failed to set GID to %lu: %s", gid,
00276                       _dbus_strerror (errno));
00277       return FALSE;
00278     }
00279   
00280   if (setuid (uid) < 0)
00281     {
00282       dbus_set_error (error, _dbus_error_from_errno (errno),
00283                       "Failed to set UID to %lu: %s", uid,
00284                       _dbus_strerror (errno));
00285       return FALSE;
00286     }
00287   
00288   return TRUE;
00289 }
00290 
00296 void
00297 _dbus_set_signal_handler (int               sig,
00298                           DBusSignalHandler handler)
00299 {
00300   struct sigaction act;
00301   sigset_t empty_mask;
00302   
00303   sigemptyset (&empty_mask);
00304   act.sa_handler = handler;
00305   act.sa_mask    = empty_mask;
00306   act.sa_flags   = 0;
00307   sigaction (sig,  &act, NULL);
00308 }
00309 
00310 
00318 dbus_bool_t
00319 _dbus_delete_directory (const DBusString *filename,
00320                         DBusError        *error)
00321 {
00322   const char *filename_c;
00323   
00324   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00325 
00326   filename_c = _dbus_string_get_const_data (filename);
00327 
00328   if (rmdir (filename_c) != 0)
00329     {
00330       dbus_set_error (error, DBUS_ERROR_FAILED,
00331                       "Failed to remove directory %s: %s\n",
00332                       filename_c, _dbus_strerror (errno));
00333       return FALSE;
00334     }
00335   
00336   return TRUE;
00337 }
00338 
00344 dbus_bool_t 
00345 _dbus_file_exists (const char *file)
00346 {
00347   return (access (file, F_OK) == 0);
00348 }
00349 
00356 dbus_bool_t 
00357 _dbus_user_at_console (const char *username,
00358                        DBusError  *error)
00359 {
00360 
00361   DBusString f;
00362   dbus_bool_t result;
00363   glob_t gl;
00364 
00365   result = FALSE;
00366   if (!_dbus_string_init (&f))
00367     {
00368       _DBUS_SET_OOM (error);
00369       return FALSE;
00370     }
00371 
00372   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00373     {
00374       _DBUS_SET_OOM (error);
00375       goto out;
00376     }
00377 
00378 
00379   if (!_dbus_string_append (&f, username))
00380     {
00381       _DBUS_SET_OOM (error);
00382       goto out;
00383     }
00384 
00385   /* check whether the user is at  any console */
00386   if (!_dbus_string_append (&f, ":*"))
00387     {
00388       _DBUS_SET_OOM (error);
00389       goto out;
00390     }
00391 
00392   if (glob (_dbus_string_get_const_data (&f), 0, NULL, &gl))
00393       goto out;
00394 
00395   result = gl.gl_pathc > 0;
00396   globfree (&gl);
00397 
00398  out:
00399   _dbus_string_free (&f);
00400 
00401   return result;
00402 }
00403 
00404 
00411 dbus_bool_t
00412 _dbus_path_is_absolute (const DBusString *filename)
00413 {
00414   if (_dbus_string_get_length (filename) > 0)
00415     return _dbus_string_get_byte (filename, 0) == '/';
00416   else
00417     return FALSE;
00418 }
00419 
00428 dbus_bool_t
00429 _dbus_stat (const DBusString *filename,
00430             DBusStat         *statbuf,
00431             DBusError        *error)
00432 {
00433   const char *filename_c;
00434   struct stat sb;
00435 
00436   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00437   
00438   filename_c = _dbus_string_get_const_data (filename);
00439 
00440   if (stat (filename_c, &sb) < 0)
00441     {
00442       dbus_set_error (error, _dbus_error_from_errno (errno),
00443                       "%s", _dbus_strerror (errno));
00444       return FALSE;
00445     }
00446 
00447   statbuf->mode = sb.st_mode;
00448   statbuf->nlink = sb.st_nlink;
00449   statbuf->uid = sb.st_uid;
00450   statbuf->gid = sb.st_gid;
00451   statbuf->size = sb.st_size;
00452   statbuf->atime = sb.st_atime;
00453   statbuf->mtime = sb.st_mtime;
00454   statbuf->ctime = sb.st_ctime;
00455 
00456   return TRUE;
00457 }
00458 
00459 
00463 struct DBusDirIter
00464 {
00465   DIR *d; 
00467 };
00468 
00476 DBusDirIter*
00477 _dbus_directory_open (const DBusString *filename,
00478                       DBusError        *error)
00479 {
00480   DIR *d;
00481   DBusDirIter *iter;
00482   const char *filename_c;
00483 
00484   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00485   
00486   filename_c = _dbus_string_get_const_data (filename);
00487 
00488   d = opendir (filename_c);
00489   if (d == NULL)
00490     {
00491       dbus_set_error (error, _dbus_error_from_errno (errno),
00492                       "Failed to read directory \"%s\": %s",
00493                       filename_c,
00494                       _dbus_strerror (errno));
00495       return NULL;
00496     }
00497   iter = dbus_new0 (DBusDirIter, 1);
00498   if (iter == NULL)
00499     {
00500       closedir (d);
00501       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00502                       "Could not allocate memory for directory iterator");
00503       return NULL;
00504     }
00505 
00506   iter->d = d;
00507 
00508   return iter;
00509 }
00510 
00511 /* Calculate the required buffer size (in bytes) for directory
00512  * entries read from the given directory handle.  Return -1 if this
00513  * this cannot be done. 
00514  *
00515  * If you use autoconf, include fpathconf and dirfd in your
00516  * AC_CHECK_FUNCS list.  Otherwise use some other method to detect
00517  * and use them where available.
00518  */
00519 static dbus_bool_t
00520 dirent_buf_size(DIR * dirp, size_t *size)
00521 {
00522  long name_max;
00523 #   if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
00524 #      if defined(HAVE_DIRFD)
00525           name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
00526 #      elif defined(HAVE_DDFD)
00527           name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
00528 #      else
00529           name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
00530 #      endif /* HAVE_DIRFD */
00531      if (name_max == -1)
00532 #           if defined(NAME_MAX)
00533              name_max = NAME_MAX;
00534 #           else
00535              return FALSE;
00536 #           endif
00537 #   elif defined(MAXNAMELEN)
00538      name_max = MAXNAMELEN;
00539 #   else
00540 #       if defined(NAME_MAX)
00541          name_max = NAME_MAX;
00542 #       else
00543 #           error "buffer size for readdir_r cannot be determined"
00544 #       endif
00545 #   endif
00546   if (size)
00547     *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
00548   else
00549     return FALSE;
00550 
00551   return TRUE;
00552 }
00553 
00564 dbus_bool_t
00565 _dbus_directory_get_next_file (DBusDirIter      *iter,
00566                                DBusString       *filename,
00567                                DBusError        *error)
00568 {
00569   struct dirent *d, *ent;
00570   size_t buf_size;
00571   int err;
00572 
00573   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00574  
00575   if (!dirent_buf_size (iter->d, &buf_size))
00576     {
00577       dbus_set_error (error, DBUS_ERROR_FAILED,
00578                       "Can't calculate buffer size when reading directory");
00579       return FALSE;
00580     }
00581 
00582   d = (struct dirent *)dbus_malloc (buf_size);
00583   if (!d)
00584     {
00585       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00586                       "No memory to read directory entry");
00587       return FALSE;
00588     }
00589 
00590  again:
00591   err = readdir_r (iter->d, d, &ent);
00592   if (err || !ent)
00593     {
00594       if (err != 0)
00595         dbus_set_error (error,
00596                         _dbus_error_from_errno (err),
00597                         "%s", _dbus_strerror (err));
00598 
00599       dbus_free (d);
00600       return FALSE;
00601     }
00602   else if (ent->d_name[0] == '.' &&
00603            (ent->d_name[1] == '\0' ||
00604             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00605     goto again;
00606   else
00607     {
00608       _dbus_string_set_length (filename, 0);
00609       if (!_dbus_string_append (filename, ent->d_name))
00610         {
00611           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00612                           "No memory to read directory entry");
00613           dbus_free (d);
00614           return FALSE;
00615         }
00616       else
00617         {
00618           dbus_free (d);
00619           return TRUE;
00620         }
00621     }
00622 }
00623 
00627 void
00628 _dbus_directory_close (DBusDirIter *iter)
00629 {
00630   closedir (iter->d);
00631   dbus_free (iter);
00632 }
00633 
00634 static dbus_bool_t
00635 fill_user_info_from_group (struct group  *g,
00636                            DBusGroupInfo *info,
00637                            DBusError     *error)
00638 {
00639   _dbus_assert (g->gr_name != NULL);
00640   
00641   info->gid = g->gr_gid;
00642   info->groupname = _dbus_strdup (g->gr_name);
00643 
00644   /* info->members = dbus_strdupv (g->gr_mem) */
00645   
00646   if (info->groupname == NULL)
00647     {
00648       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00649       return FALSE;
00650     }
00651 
00652   return TRUE;
00653 }
00654 
00655 static dbus_bool_t
00656 fill_group_info (DBusGroupInfo    *info,
00657                  dbus_gid_t        gid,
00658                  const DBusString *groupname,
00659                  DBusError        *error)
00660 {
00661   const char *group_c_str;
00662 
00663   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00664   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00665 
00666   if (groupname)
00667     group_c_str = _dbus_string_get_const_data (groupname);
00668   else
00669     group_c_str = NULL;
00670   
00671   /* For now assuming that the getgrnam() and getgrgid() flavors
00672    * always correspond to the pwnam flavors, if not we have
00673    * to add more configure checks.
00674    */
00675   
00676 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00677   {
00678     struct group *g;
00679     int result;
00680     char buf[1024];
00681     struct group g_str;
00682 
00683     g = NULL;
00684 #ifdef HAVE_POSIX_GETPWNAM_R
00685 
00686     if (group_c_str)
00687       result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
00688                            &g);
00689     else
00690       result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
00691                            &g);
00692 #else
00693     g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
00694     result = 0;
00695 #endif /* !HAVE_POSIX_GETPWNAM_R */
00696     if (result == 0 && g == &g_str)
00697       {
00698         return fill_user_info_from_group (g, info, error);
00699       }
00700     else
00701       {
00702         dbus_set_error (error, _dbus_error_from_errno (errno),
00703                         "Group %s unknown or failed to look it up\n",
00704                         group_c_str ? group_c_str : "???");
00705         return FALSE;
00706       }
00707   }
00708 #else /* ! HAVE_GETPWNAM_R */
00709   {
00710     /* I guess we're screwed on thread safety here */
00711     struct group *g;
00712 
00713     g = getgrnam (group_c_str);
00714 
00715     if (g != NULL)
00716       {
00717         return fill_user_info_from_group (g, info, error);
00718       }
00719     else
00720       {
00721         dbus_set_error (error, _dbus_error_from_errno (errno),
00722                         "Group %s unknown or failed to look it up\n",
00723                         group_c_str ? group_c_str : "???");
00724         return FALSE;
00725       }
00726   }
00727 #endif  /* ! HAVE_GETPWNAM_R */
00728 }
00729 
00739 dbus_bool_t
00740 _dbus_group_info_fill (DBusGroupInfo    *info,
00741                        const DBusString *groupname,
00742                        DBusError        *error)
00743 {
00744   return fill_group_info (info, DBUS_GID_UNSET,
00745                           groupname, error);
00746 
00747 }
00748 
00758 dbus_bool_t
00759 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00760                            dbus_gid_t     gid,
00761                            DBusError     *error)
00762 {
00763   return fill_group_info (info, gid, NULL, error);
00764 }
00765  /* End of DBusInternalsUtils functions */
00767 
00779 dbus_bool_t
00780 _dbus_string_get_dirname  (const DBusString *filename,
00781                            DBusString       *dirname)
00782 {
00783   int sep;
00784   
00785   _dbus_assert (filename != dirname);
00786   _dbus_assert (filename != NULL);
00787   _dbus_assert (dirname != NULL);
00788 
00789   /* Ignore any separators on the end */
00790   sep = _dbus_string_get_length (filename);
00791   if (sep == 0)
00792     return _dbus_string_append (dirname, "."); /* empty string passed in */
00793     
00794   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00795     --sep;
00796 
00797   _dbus_assert (sep >= 0);
00798   
00799   if (sep == 0)
00800     return _dbus_string_append (dirname, "/");
00801   
00802   /* Now find the previous separator */
00803   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
00804   if (sep < 0)
00805     return _dbus_string_append (dirname, ".");
00806   
00807   /* skip multiple separators */
00808   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00809     --sep;
00810 
00811   _dbus_assert (sep >= 0);
00812   
00813   if (sep == 0 &&
00814       _dbus_string_get_byte (filename, 0) == '/')
00815     return _dbus_string_append (dirname, "/");
00816   else
00817     return _dbus_string_copy_len (filename, 0, sep - 0,
00818                                   dirname, _dbus_string_get_length (dirname));
00819 } /* DBusString stuff */
00821 

Generated on Fri Jul 17 07:22:16 2009 for D-Bus by  doxygen 1.5.1