dbus-sysdeps-util-unix.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
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 <syslog.h>
00047 #ifdef HAVE_LIBAUDIT
00048 #include <sys/prctl.h>
00049 #include <sys/capability.h>
00050 #include <libaudit.h>
00051 #endif /* HAVE_LIBAUDIT */
00052 
00053 #ifdef HAVE_SYS_SYSLIMITS_H
00054 #include <sys/syslimits.h>
00055 #endif
00056 
00057 #ifndef O_BINARY
00058 #define O_BINARY 0
00059 #endif
00060 
00076 dbus_bool_t
00077 _dbus_become_daemon (const DBusString *pidfile,
00078                      DBusPipe         *print_pid_pipe,
00079                      DBusError        *error,
00080                      dbus_bool_t       keep_umask)
00081 {
00082   const char *s;
00083   pid_t child_pid;
00084   int dev_null_fd;
00085 
00086   _dbus_verbose ("Becoming a daemon...\n");
00087 
00088   _dbus_verbose ("chdir to /\n");
00089   if (chdir ("/") < 0)
00090     {
00091       dbus_set_error (error, DBUS_ERROR_FAILED,
00092                       "Could not chdir() to root directory");
00093       return FALSE;
00094     }
00095 
00096   _dbus_verbose ("forking...\n");
00097   switch ((child_pid = fork ()))
00098     {
00099     case -1:
00100       _dbus_verbose ("fork failed\n");
00101       dbus_set_error (error, _dbus_error_from_errno (errno),
00102                       "Failed to fork daemon: %s", _dbus_strerror (errno));
00103       return FALSE;
00104       break;
00105 
00106     case 0:
00107       _dbus_verbose ("in child, closing std file descriptors\n");
00108 
00109       /* silently ignore failures here, if someone
00110        * doesn't have /dev/null we may as well try
00111        * to continue anyhow
00112        */
00113       
00114       dev_null_fd = open ("/dev/null", O_RDWR);
00115       if (dev_null_fd >= 0)
00116         {
00117           dup2 (dev_null_fd, 0);
00118           dup2 (dev_null_fd, 1);
00119           
00120           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00121           if (s == NULL || *s == '\0')
00122             dup2 (dev_null_fd, 2);
00123           else
00124             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00125         }
00126 
00127       if (!keep_umask)
00128         {
00129           /* Get a predictable umask */
00130           _dbus_verbose ("setting umask\n");
00131           umask (022);
00132         }
00133 
00134       _dbus_verbose ("calling setsid()\n");
00135       if (setsid () == -1)
00136         _dbus_assert_not_reached ("setsid() failed");
00137       
00138       break;
00139 
00140     default:
00141       if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe,
00142                                              child_pid, error))
00143         {
00144           _dbus_verbose ("pid file or pipe write failed: %s\n",
00145                          error->message);
00146           kill (child_pid, SIGTERM);
00147           return FALSE;
00148         }
00149 
00150       _dbus_verbose ("parent exiting\n");
00151       _exit (0);
00152       break;
00153     }
00154   
00155   return TRUE;
00156 }
00157 
00158 
00167 static dbus_bool_t
00168 _dbus_write_pid_file (const DBusString *filename,
00169                       unsigned long     pid,
00170                       DBusError        *error)
00171 {
00172   const char *cfilename;
00173   int fd;
00174   FILE *f;
00175 
00176   cfilename = _dbus_string_get_const_data (filename);
00177   
00178   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00179   
00180   if (fd < 0)
00181     {
00182       dbus_set_error (error, _dbus_error_from_errno (errno),
00183                       "Failed to open \"%s\": %s", cfilename,
00184                       _dbus_strerror (errno));
00185       return FALSE;
00186     }
00187 
00188   if ((f = fdopen (fd, "w")) == NULL)
00189     {
00190       dbus_set_error (error, _dbus_error_from_errno (errno),
00191                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00192       _dbus_close (fd, NULL);
00193       return FALSE;
00194     }
00195   
00196   if (fprintf (f, "%lu\n", pid) < 0)
00197     {
00198       dbus_set_error (error, _dbus_error_from_errno (errno),
00199                       "Failed to write to \"%s\": %s", cfilename,
00200                       _dbus_strerror (errno));
00201       
00202       fclose (f);
00203       return FALSE;
00204     }
00205 
00206   if (fclose (f) == EOF)
00207     {
00208       dbus_set_error (error, _dbus_error_from_errno (errno),
00209                       "Failed to close \"%s\": %s", cfilename,
00210                       _dbus_strerror (errno));
00211       return FALSE;
00212     }
00213   
00214   return TRUE;
00215 }
00216 
00228 dbus_bool_t
00229 _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
00230                                   DBusPipe         *print_pid_pipe,
00231                                   dbus_pid_t        pid_to_write,
00232                                   DBusError        *error)
00233 {
00234   if (pidfile)
00235     {
00236       _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile));
00237       if (!_dbus_write_pid_file (pidfile,
00238                                  pid_to_write,
00239                                  error))
00240         {
00241           _dbus_verbose ("pid file write failed\n");
00242           _DBUS_ASSERT_ERROR_IS_SET(error);
00243           return FALSE;
00244         }
00245     }
00246   else
00247     {
00248       _dbus_verbose ("No pid file requested\n");
00249     }
00250 
00251   if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
00252     {
00253       DBusString pid;
00254       int bytes;
00255 
00256       _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd_or_handle);
00257       
00258       if (!_dbus_string_init (&pid))
00259         {
00260           _DBUS_SET_OOM (error);
00261           return FALSE;
00262         }
00263           
00264       if (!_dbus_string_append_int (&pid, pid_to_write) ||
00265           !_dbus_string_append (&pid, "\n"))
00266         {
00267           _dbus_string_free (&pid);
00268           _DBUS_SET_OOM (error);
00269           return FALSE;
00270         }
00271           
00272       bytes = _dbus_string_get_length (&pid);
00273       if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
00274         {
00275           /* _dbus_pipe_write sets error only on failure, not short write */
00276           if (error != NULL && !dbus_error_is_set(error))
00277             {
00278               dbus_set_error (error, DBUS_ERROR_FAILED,
00279                               "Printing message bus PID: did not write enough bytes\n");
00280             }
00281           _dbus_string_free (&pid);
00282           return FALSE;
00283         }
00284           
00285       _dbus_string_free (&pid);
00286     }
00287   else
00288     {
00289       _dbus_verbose ("No pid pipe to write to\n");
00290     }
00291 
00292   return TRUE;
00293 }
00294 
00301 dbus_bool_t
00302 _dbus_verify_daemon_user (const char *user)
00303 {
00304   DBusString u;
00305 
00306   _dbus_string_init_const (&u, user);
00307 
00308   return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
00309 }
00310 
00318 dbus_bool_t
00319 _dbus_change_to_daemon_user  (const char    *user,
00320                               DBusError     *error)
00321 {
00322   dbus_uid_t uid;
00323   dbus_gid_t gid;
00324   DBusString u;
00325 #ifdef HAVE_LIBAUDIT
00326   dbus_bool_t we_were_root;
00327   cap_t new_caps;
00328 #endif
00329   
00330   _dbus_string_init_const (&u, user);
00331   
00332   if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
00333     {
00334       dbus_set_error (error, DBUS_ERROR_FAILED,
00335                       "User '%s' does not appear to exist?",
00336                       user);
00337       return FALSE;
00338     }
00339   
00340 #ifdef HAVE_LIBAUDIT
00341   we_were_root = _dbus_geteuid () == 0;
00342   new_caps = NULL;
00343   /* have a tmp set of caps that we use to transition to the usr/grp dbus should
00344    * run as ... doesn't really help. But keeps people happy.
00345    */
00346     
00347   if (we_were_root)
00348     {
00349       cap_value_t new_cap_list[] = { CAP_AUDIT_WRITE };
00350       cap_value_t tmp_cap_list[] = { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
00351       cap_t tmp_caps = cap_init();
00352         
00353       if (!tmp_caps || !(new_caps = cap_init ()))
00354         {
00355           dbus_set_error (error, DBUS_ERROR_FAILED,
00356                           "Failed to initialize drop of capabilities: %s\n",
00357                           _dbus_strerror (errno));
00358 
00359           if (tmp_caps)
00360             cap_free (tmp_caps);
00361 
00362           return FALSE;
00363         }
00364 
00365       /* assume these work... */
00366       cap_set_flag (new_caps, CAP_PERMITTED, 1, new_cap_list, CAP_SET);
00367       cap_set_flag (new_caps, CAP_EFFECTIVE, 1, new_cap_list, CAP_SET);
00368       cap_set_flag (tmp_caps, CAP_PERMITTED, 3, tmp_cap_list, CAP_SET);
00369       cap_set_flag (tmp_caps, CAP_EFFECTIVE, 3, tmp_cap_list, CAP_SET);
00370       
00371       if (prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
00372         {
00373           dbus_set_error (error, _dbus_error_from_errno (errno),
00374                           "Failed to set keep-capabilities: %s\n",
00375                           _dbus_strerror (errno));
00376           cap_free (tmp_caps);
00377           goto fail;
00378         }
00379         
00380       if (cap_set_proc (tmp_caps) == -1)
00381         {
00382           dbus_set_error (error, DBUS_ERROR_FAILED,
00383                           "Failed to drop capabilities: %s\n",
00384                           _dbus_strerror (errno));
00385           cap_free (tmp_caps);
00386           goto fail;
00387         }
00388       cap_free (tmp_caps);
00389     }
00390 #endif /* HAVE_LIBAUDIT */
00391   
00392   /* setgroups() only works if we are a privileged process,
00393    * so we don't return error on failure; the only possible
00394    * failure is that we don't have perms to do it.
00395    *
00396    * not sure this is right, maybe if setuid()
00397    * is going to work then setgroups() should also work.
00398    */
00399   if (setgroups (0, NULL) < 0)
00400     _dbus_warn ("Failed to drop supplementary groups: %s\n",
00401                 _dbus_strerror (errno));
00402   
00403   /* Set GID first, or the setuid may remove our permission
00404    * to change the GID
00405    */
00406   if (setgid (gid) < 0)
00407     {
00408       dbus_set_error (error, _dbus_error_from_errno (errno),
00409                       "Failed to set GID to %lu: %s", gid,
00410                       _dbus_strerror (errno));
00411       goto fail;
00412     }
00413   
00414   if (setuid (uid) < 0)
00415     {
00416       dbus_set_error (error, _dbus_error_from_errno (errno),
00417                       "Failed to set UID to %lu: %s", uid,
00418                       _dbus_strerror (errno));
00419       goto fail;
00420     }
00421   
00422 #ifdef HAVE_LIBAUDIT
00423   if (we_were_root)
00424     {
00425       if (cap_set_proc (new_caps))
00426         {
00427           dbus_set_error (error, DBUS_ERROR_FAILED,
00428                           "Failed to drop capabilities: %s\n",
00429                           _dbus_strerror (errno));
00430           goto fail;
00431         }
00432       cap_free (new_caps);
00433 
00434       /* should always work, if it did above */      
00435       if (prctl (PR_SET_KEEPCAPS, 0, 0, 0, 0) == -1)
00436         {
00437           dbus_set_error (error, _dbus_error_from_errno (errno),
00438                           "Failed to unset keep-capabilities: %s\n",
00439                           _dbus_strerror (errno));
00440           return FALSE;
00441         }
00442     }
00443 #endif
00444 
00445  return TRUE;
00446 
00447  fail:
00448 #ifdef HAVE_LIBAUDIT
00449  if (!we_were_root)
00450    {
00451      /* should always work, if it did above */
00452      prctl (PR_SET_KEEPCAPS, 0, 0, 0, 0);
00453      cap_free (new_caps);
00454    }
00455 #endif
00456 
00457  return FALSE;
00458 }
00459 
00460 void 
00461 _dbus_init_system_log (void)
00462 {
00463   openlog ("dbus", LOG_PID, LOG_DAEMON);
00464 }
00465 
00473 void 
00474 _dbus_log_info (const char *msg, va_list args)
00475 {
00476   vsyslog (LOG_DAEMON|LOG_NOTICE, msg, args);
00477 }
00478 
00486 void 
00487 _dbus_log_security (const char *msg, va_list args)
00488 {
00489   vsyslog (LOG_AUTH|LOG_NOTICE, msg, args);
00490 }
00491 
00497 void
00498 _dbus_set_signal_handler (int               sig,
00499                           DBusSignalHandler handler)
00500 {
00501   struct sigaction act;
00502   sigset_t empty_mask;
00503   
00504   sigemptyset (&empty_mask);
00505   act.sa_handler = handler;
00506   act.sa_mask    = empty_mask;
00507   act.sa_flags   = 0;
00508   sigaction (sig,  &act, NULL);
00509 }
00510 
00511 
00519 dbus_bool_t
00520 _dbus_delete_directory (const DBusString *filename,
00521                         DBusError        *error)
00522 {
00523   const char *filename_c;
00524   
00525   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00526 
00527   filename_c = _dbus_string_get_const_data (filename);
00528 
00529   if (rmdir (filename_c) != 0)
00530     {
00531       dbus_set_error (error, DBUS_ERROR_FAILED,
00532                       "Failed to remove directory %s: %s\n",
00533                       filename_c, _dbus_strerror (errno));
00534       return FALSE;
00535     }
00536   
00537   return TRUE;
00538 }
00539 
00545 dbus_bool_t 
00546 _dbus_file_exists (const char *file)
00547 {
00548   return (access (file, F_OK) == 0);
00549 }
00550 
00557 dbus_bool_t 
00558 _dbus_user_at_console (const char *username,
00559                        DBusError  *error)
00560 {
00561 
00562   DBusString f;
00563   dbus_bool_t result;
00564 
00565   result = FALSE;
00566   if (!_dbus_string_init (&f))
00567     {
00568       _DBUS_SET_OOM (error);
00569       return FALSE;
00570     }
00571 
00572   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00573     {
00574       _DBUS_SET_OOM (error);
00575       goto out;
00576     }
00577 
00578 
00579   if (!_dbus_string_append (&f, username))
00580     {
00581       _DBUS_SET_OOM (error);
00582       goto out;
00583     }
00584 
00585   result = _dbus_file_exists (_dbus_string_get_const_data (&f));
00586 
00587  out:
00588   _dbus_string_free (&f);
00589 
00590   return result;
00591 }
00592 
00593 
00600 dbus_bool_t
00601 _dbus_path_is_absolute (const DBusString *filename)
00602 {
00603   if (_dbus_string_get_length (filename) > 0)
00604     return _dbus_string_get_byte (filename, 0) == '/';
00605   else
00606     return FALSE;
00607 }
00608 
00617 dbus_bool_t
00618 _dbus_stat (const DBusString *filename,
00619             DBusStat         *statbuf,
00620             DBusError        *error)
00621 {
00622   const char *filename_c;
00623   struct stat sb;
00624 
00625   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00626   
00627   filename_c = _dbus_string_get_const_data (filename);
00628 
00629   if (stat (filename_c, &sb) < 0)
00630     {
00631       dbus_set_error (error, _dbus_error_from_errno (errno),
00632                       "%s", _dbus_strerror (errno));
00633       return FALSE;
00634     }
00635 
00636   statbuf->mode = sb.st_mode;
00637   statbuf->nlink = sb.st_nlink;
00638   statbuf->uid = sb.st_uid;
00639   statbuf->gid = sb.st_gid;
00640   statbuf->size = sb.st_size;
00641   statbuf->atime = sb.st_atime;
00642   statbuf->mtime = sb.st_mtime;
00643   statbuf->ctime = sb.st_ctime;
00644 
00645   return TRUE;
00646 }
00647 
00648 
00652 struct DBusDirIter
00653 {
00654   DIR *d; 
00656 };
00657 
00665 DBusDirIter*
00666 _dbus_directory_open (const DBusString *filename,
00667                       DBusError        *error)
00668 {
00669   DIR *d;
00670   DBusDirIter *iter;
00671   const char *filename_c;
00672 
00673   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00674   
00675   filename_c = _dbus_string_get_const_data (filename);
00676 
00677   d = opendir (filename_c);
00678   if (d == NULL)
00679     {
00680       dbus_set_error (error, _dbus_error_from_errno (errno),
00681                       "Failed to read directory \"%s\": %s",
00682                       filename_c,
00683                       _dbus_strerror (errno));
00684       return NULL;
00685     }
00686   iter = dbus_new0 (DBusDirIter, 1);
00687   if (iter == NULL)
00688     {
00689       closedir (d);
00690       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00691                       "Could not allocate memory for directory iterator");
00692       return NULL;
00693     }
00694 
00695   iter->d = d;
00696 
00697   return iter;
00698 }
00699 
00700 /* Calculate the required buffer size (in bytes) for directory
00701  * entries read from the given directory handle.  Return -1 if this
00702  * this cannot be done. 
00703  *
00704  * If you use autoconf, include fpathconf and dirfd in your
00705  * AC_CHECK_FUNCS list.  Otherwise use some other method to detect
00706  * and use them where available.
00707  */
00708 static dbus_bool_t
00709 dirent_buf_size(DIR * dirp, size_t *size)
00710 {
00711  long name_max;
00712 #   if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
00713 #      if defined(HAVE_DIRFD)
00714           name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
00715 #      elif defined(HAVE_DDFD)
00716           name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
00717 #      else
00718           name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
00719 #      endif /* HAVE_DIRFD */
00720      if (name_max == -1)
00721 #           if defined(NAME_MAX)
00722              name_max = NAME_MAX;
00723 #           else
00724              return FALSE;
00725 #           endif
00726 #   elif defined(MAXNAMELEN)
00727      name_max = MAXNAMELEN;
00728 #   else
00729 #       if defined(NAME_MAX)
00730          name_max = NAME_MAX;
00731 #       else
00732 #           error "buffer size for readdir_r cannot be determined"
00733 #       endif
00734 #   endif
00735   if (size)
00736     *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
00737   else
00738     return FALSE;
00739 
00740   return TRUE;
00741 }
00742 
00753 dbus_bool_t
00754 _dbus_directory_get_next_file (DBusDirIter      *iter,
00755                                DBusString       *filename,
00756                                DBusError        *error)
00757 {
00758   struct dirent *d, *ent;
00759   size_t buf_size;
00760   int err;
00761 
00762   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00763  
00764   if (!dirent_buf_size (iter->d, &buf_size))
00765     {
00766       dbus_set_error (error, DBUS_ERROR_FAILED,
00767                       "Can't calculate buffer size when reading directory");
00768       return FALSE;
00769     }
00770 
00771   d = (struct dirent *)dbus_malloc (buf_size);
00772   if (!d)
00773     {
00774       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00775                       "No memory to read directory entry");
00776       return FALSE;
00777     }
00778 
00779  again:
00780   err = readdir_r (iter->d, d, &ent);
00781   if (err || !ent)
00782     {
00783       if (err != 0)
00784         dbus_set_error (error,
00785                         _dbus_error_from_errno (err),
00786                         "%s", _dbus_strerror (err));
00787 
00788       dbus_free (d);
00789       return FALSE;
00790     }
00791   else if (ent->d_name[0] == '.' &&
00792            (ent->d_name[1] == '\0' ||
00793             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00794     goto again;
00795   else
00796     {
00797       _dbus_string_set_length (filename, 0);
00798       if (!_dbus_string_append (filename, ent->d_name))
00799         {
00800           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00801                           "No memory to read directory entry");
00802           dbus_free (d);
00803           return FALSE;
00804         }
00805       else
00806         {
00807           dbus_free (d);
00808           return TRUE;
00809         }
00810     }
00811 }
00812 
00816 void
00817 _dbus_directory_close (DBusDirIter *iter)
00818 {
00819   closedir (iter->d);
00820   dbus_free (iter);
00821 }
00822 
00823 static dbus_bool_t
00824 fill_user_info_from_group (struct group  *g,
00825                            DBusGroupInfo *info,
00826                            DBusError     *error)
00827 {
00828   _dbus_assert (g->gr_name != NULL);
00829   
00830   info->gid = g->gr_gid;
00831   info->groupname = _dbus_strdup (g->gr_name);
00832 
00833   /* info->members = dbus_strdupv (g->gr_mem) */
00834   
00835   if (info->groupname == NULL)
00836     {
00837       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00838       return FALSE;
00839     }
00840 
00841   return TRUE;
00842 }
00843 
00844 static dbus_bool_t
00845 fill_group_info (DBusGroupInfo    *info,
00846                  dbus_gid_t        gid,
00847                  const DBusString *groupname,
00848                  DBusError        *error)
00849 {
00850   const char *group_c_str;
00851 
00852   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00853   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00854 
00855   if (groupname)
00856     group_c_str = _dbus_string_get_const_data (groupname);
00857   else
00858     group_c_str = NULL;
00859   
00860   /* For now assuming that the getgrnam() and getgrgid() flavors
00861    * always correspond to the pwnam flavors, if not we have
00862    * to add more configure checks.
00863    */
00864   
00865 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00866   {
00867     struct group *g;
00868     int result;
00869     size_t buflen;
00870     char *buf;
00871     struct group g_str;
00872     dbus_bool_t b;
00873 
00874     /* retrieve maximum needed size for buf */
00875     buflen = sysconf (_SC_GETGR_R_SIZE_MAX);
00876 
00877     /* sysconf actually returns a long, but everything else expects size_t,
00878      * so just recast here.
00879      * https://bugs.freedesktop.org/show_bug.cgi?id=17061
00880      */
00881     if ((long) buflen <= 0)
00882       buflen = 1024;
00883 
00884     result = -1;
00885     while (1)
00886       {
00887         buf = dbus_malloc (buflen);
00888         if (buf == NULL)
00889           {
00890             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00891             return FALSE;
00892           }
00893 
00894         g = NULL;
00895 #ifdef HAVE_POSIX_GETPWNAM_R
00896         if (group_c_str)
00897           result = getgrnam_r (group_c_str, &g_str, buf, buflen,
00898                                &g);
00899         else
00900           result = getgrgid_r (gid, &g_str, buf, buflen,
00901                                &g);
00902 #else
00903         g = getgrnam_r (group_c_str, &g_str, buf, buflen);
00904         result = 0;
00905 #endif /* !HAVE_POSIX_GETPWNAM_R */
00906         /* Try a bigger buffer if ERANGE was returned:
00907            https://bugs.freedesktop.org/show_bug.cgi?id=16727
00908         */
00909         if (result == ERANGE && buflen < 512 * 1024)
00910           {
00911             dbus_free (buf);
00912             buflen *= 2;
00913           }
00914         else
00915           {
00916             break;
00917           }
00918       }
00919 
00920     if (result == 0 && g == &g_str)
00921       {
00922         b = fill_user_info_from_group (g, info, error);
00923         dbus_free (buf);
00924         return b;
00925       }
00926     else
00927       {
00928         dbus_set_error (error, _dbus_error_from_errno (errno),
00929                         "Group %s unknown or failed to look it up\n",
00930                         group_c_str ? group_c_str : "???");
00931         dbus_free (buf);
00932         return FALSE;
00933       }
00934   }
00935 #else /* ! HAVE_GETPWNAM_R */
00936   {
00937     /* I guess we're screwed on thread safety here */
00938     struct group *g;
00939 
00940     g = getgrnam (group_c_str);
00941 
00942     if (g != NULL)
00943       {
00944         return fill_user_info_from_group (g, info, error);
00945       }
00946     else
00947       {
00948         dbus_set_error (error, _dbus_error_from_errno (errno),
00949                         "Group %s unknown or failed to look it up\n",
00950                         group_c_str ? group_c_str : "???");
00951         return FALSE;
00952       }
00953   }
00954 #endif  /* ! HAVE_GETPWNAM_R */
00955 }
00956 
00966 dbus_bool_t
00967 _dbus_group_info_fill (DBusGroupInfo    *info,
00968                        const DBusString *groupname,
00969                        DBusError        *error)
00970 {
00971   return fill_group_info (info, DBUS_GID_UNSET,
00972                           groupname, error);
00973 
00974 }
00975 
00985 dbus_bool_t
00986 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00987                            dbus_gid_t     gid,
00988                            DBusError     *error)
00989 {
00990   return fill_group_info (info, gid, NULL, error);
00991 }
00992 
01001 dbus_bool_t
01002 _dbus_parse_unix_user_from_config (const DBusString  *username,
01003                                    dbus_uid_t        *uid_p)
01004 {
01005   return _dbus_get_user_id (username, uid_p);
01006 
01007 }
01008 
01017 dbus_bool_t
01018 _dbus_parse_unix_group_from_config (const DBusString  *groupname,
01019                                     dbus_gid_t        *gid_p)
01020 {
01021   return _dbus_get_group_id (groupname, gid_p);
01022 }
01023 
01034 dbus_bool_t
01035 _dbus_unix_groups_from_uid (dbus_uid_t            uid,
01036                             dbus_gid_t          **group_ids,
01037                             int                  *n_group_ids)
01038 {
01039   return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
01040 }
01041 
01051 dbus_bool_t
01052 _dbus_unix_user_is_at_console (dbus_uid_t         uid,
01053                                DBusError         *error)
01054 {
01055   return _dbus_is_console_user (uid, error);
01056 
01057 }
01058 
01066 dbus_bool_t
01067 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
01068 {
01069   return uid == _dbus_geteuid ();
01070 }
01071 
01079 dbus_bool_t
01080 _dbus_windows_user_is_process_owner (const char *windows_sid)
01081 {
01082   return FALSE;
01083 }
01084  /* End of DBusInternalsUtils functions */
01086 
01098 dbus_bool_t
01099 _dbus_string_get_dirname  (const DBusString *filename,
01100                            DBusString       *dirname)
01101 {
01102   int sep;
01103   
01104   _dbus_assert (filename != dirname);
01105   _dbus_assert (filename != NULL);
01106   _dbus_assert (dirname != NULL);
01107 
01108   /* Ignore any separators on the end */
01109   sep = _dbus_string_get_length (filename);
01110   if (sep == 0)
01111     return _dbus_string_append (dirname, "."); /* empty string passed in */
01112     
01113   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01114     --sep;
01115 
01116   _dbus_assert (sep >= 0);
01117   
01118   if (sep == 0)
01119     return _dbus_string_append (dirname, "/");
01120   
01121   /* Now find the previous separator */
01122   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
01123   if (sep < 0)
01124     return _dbus_string_append (dirname, ".");
01125   
01126   /* skip multiple separators */
01127   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01128     --sep;
01129 
01130   _dbus_assert (sep >= 0);
01131   
01132   if (sep == 0 &&
01133       _dbus_string_get_byte (filename, 0) == '/')
01134     return _dbus_string_append (dirname, "/");
01135   else
01136     return _dbus_string_copy_len (filename, 0, sep - 0,
01137                                   dirname, _dbus_string_get_length (dirname));
01138 } /* DBusString stuff */
01140 
01141 static void
01142 string_squash_nonprintable (DBusString *str)
01143 {
01144   char *buf;
01145   int i, len; 
01146   
01147   buf = _dbus_string_get_data (str);
01148   len = _dbus_string_get_length (str);
01149   
01150   for (i = 0; i < len; i++)
01151     if (buf[i] == '\0')
01152       buf[i] = ' ';
01153     else if (buf[i] < 0x20 || buf[i] > 127)
01154       buf[i] = '?';
01155 }
01156 
01171 dbus_bool_t 
01172 _dbus_command_for_pid (unsigned long  pid,
01173                        DBusString    *str,
01174                        int            max_len,
01175                        DBusError     *error)
01176 {
01177   /* This is all Linux-specific for now */
01178   DBusString path;
01179   DBusString cmdline;
01180   int fd;
01181   
01182   if (!_dbus_string_init (&path)) 
01183     {
01184       _DBUS_SET_OOM (error);
01185       return FALSE;
01186     }
01187   
01188   if (!_dbus_string_init (&cmdline))
01189     {
01190       _DBUS_SET_OOM (error);
01191       _dbus_string_free (&path);
01192       return FALSE;
01193     }
01194   
01195   if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid))
01196     goto oom;
01197   
01198   fd = open (_dbus_string_get_const_data (&path), O_RDONLY);
01199   if (fd < 0) 
01200     {
01201       dbus_set_error (error,
01202                       _dbus_error_from_errno (errno),
01203                       "Failed to open \"%s\": %s",
01204                       _dbus_string_get_const_data (&path),
01205                       _dbus_strerror (errno));
01206       goto fail;
01207     }
01208   
01209   if (!_dbus_read (fd, &cmdline, max_len))
01210     {
01211       dbus_set_error (error,
01212                       _dbus_error_from_errno (errno),
01213                       "Failed to read from \"%s\": %s",
01214                       _dbus_string_get_const_data (&path),
01215                       _dbus_strerror (errno));      
01216       goto fail;
01217     }
01218   
01219   if (!_dbus_close (fd, error))
01220     goto fail;
01221   
01222   string_squash_nonprintable (&cmdline);  
01223   
01224   if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
01225     goto oom;
01226   
01227   _dbus_string_free (&cmdline);  
01228   _dbus_string_free (&path);
01229   return TRUE;
01230 oom:
01231   _DBUS_SET_OOM (error);
01232 fail:
01233   _dbus_string_free (&cmdline);
01234   _dbus_string_free (&path);
01235   return FALSE;
01236 }

Generated on Tue Feb 24 16:40:40 2009 for D-Bus by  doxygen 1.5.1