D-Bus  1.6.30
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include "dbus-sysdeps.h"
00027 #include "dbus-sysdeps-unix.h"
00028 #include "dbus-internals.h"
00029 #include "dbus-pipe.h"
00030 #include "dbus-protocol.h"
00031 #include "dbus-string.h"
00032 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00033 #include "dbus-userdb.h"
00034 #include "dbus-test.h"
00035 
00036 #include <sys/types.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <signal.h>
00040 #include <unistd.h>
00041 #include <stdio.h>
00042 #include <errno.h>
00043 #include <fcntl.h>
00044 #include <sys/stat.h>
00045 #ifdef HAVE_SYS_RESOURCE_H
00046 #include <sys/resource.h>
00047 #endif
00048 #include <grp.h>
00049 #include <sys/socket.h>
00050 #include <dirent.h>
00051 #include <sys/un.h>
00052 #include <syslog.h>
00053 
00054 #ifdef HAVE_SYS_SYSLIMITS_H
00055 #include <sys/syslimits.h>
00056 #endif
00057 
00058 #ifndef O_BINARY
00059 #define O_BINARY 0
00060 #endif
00061 
00077 dbus_bool_t
00078 _dbus_become_daemon (const DBusString *pidfile,
00079                      DBusPipe         *print_pid_pipe,
00080                      DBusError        *error,
00081                      dbus_bool_t       keep_umask)
00082 {
00083   const char *s;
00084   pid_t child_pid;
00085   int dev_null_fd;
00086 
00087   _dbus_verbose ("Becoming a daemon...\n");
00088 
00089   _dbus_verbose ("chdir to /\n");
00090   if (chdir ("/") < 0)
00091     {
00092       dbus_set_error (error, DBUS_ERROR_FAILED,
00093                       "Could not chdir() to root directory");
00094       return FALSE;
00095     }
00096 
00097   _dbus_verbose ("forking...\n");
00098   switch ((child_pid = fork ()))
00099     {
00100     case -1:
00101       _dbus_verbose ("fork failed\n");
00102       dbus_set_error (error, _dbus_error_from_errno (errno),
00103                       "Failed to fork daemon: %s", _dbus_strerror (errno));
00104       return FALSE;
00105       break;
00106 
00107     case 0:
00108       _dbus_verbose ("in child, closing std file descriptors\n");
00109 
00110       /* silently ignore failures here, if someone
00111        * doesn't have /dev/null we may as well try
00112        * to continue anyhow
00113        */
00114       
00115       dev_null_fd = open ("/dev/null", O_RDWR);
00116       if (dev_null_fd >= 0)
00117         {
00118           dup2 (dev_null_fd, 0);
00119           dup2 (dev_null_fd, 1);
00120           
00121           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00122           if (s == NULL || *s == '\0')
00123             dup2 (dev_null_fd, 2);
00124           else
00125             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00126           close (dev_null_fd);
00127         }
00128 
00129       if (!keep_umask)
00130         {
00131           /* Get a predictable umask */
00132           _dbus_verbose ("setting umask\n");
00133           umask (022);
00134         }
00135 
00136       _dbus_verbose ("calling setsid()\n");
00137       if (setsid () == -1)
00138         _dbus_assert_not_reached ("setsid() failed");
00139       
00140       break;
00141 
00142     default:
00143       if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe,
00144                                              child_pid, error))
00145         {
00146           _dbus_verbose ("pid file or pipe write failed: %s\n",
00147                          error->message);
00148           kill (child_pid, SIGTERM);
00149           return FALSE;
00150         }
00151 
00152       _dbus_verbose ("parent exiting\n");
00153       _exit (0);
00154       break;
00155     }
00156   
00157   return TRUE;
00158 }
00159 
00160 
00169 static dbus_bool_t
00170 _dbus_write_pid_file (const DBusString *filename,
00171                       unsigned long     pid,
00172                       DBusError        *error)
00173 {
00174   const char *cfilename;
00175   int fd;
00176   FILE *f;
00177 
00178   cfilename = _dbus_string_get_const_data (filename);
00179   
00180   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00181   
00182   if (fd < 0)
00183     {
00184       dbus_set_error (error, _dbus_error_from_errno (errno),
00185                       "Failed to open \"%s\": %s", cfilename,
00186                       _dbus_strerror (errno));
00187       return FALSE;
00188     }
00189 
00190   if ((f = fdopen (fd, "w")) == NULL)
00191     {
00192       dbus_set_error (error, _dbus_error_from_errno (errno),
00193                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00194       _dbus_close (fd, NULL);
00195       return FALSE;
00196     }
00197   
00198   if (fprintf (f, "%lu\n", pid) < 0)
00199     {
00200       dbus_set_error (error, _dbus_error_from_errno (errno),
00201                       "Failed to write to \"%s\": %s", cfilename,
00202                       _dbus_strerror (errno));
00203       
00204       fclose (f);
00205       return FALSE;
00206     }
00207 
00208   if (fclose (f) == EOF)
00209     {
00210       dbus_set_error (error, _dbus_error_from_errno (errno),
00211                       "Failed to close \"%s\": %s", cfilename,
00212                       _dbus_strerror (errno));
00213       return FALSE;
00214     }
00215   
00216   return TRUE;
00217 }
00218 
00230 dbus_bool_t
00231 _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
00232                                   DBusPipe         *print_pid_pipe,
00233                                   dbus_pid_t        pid_to_write,
00234                                   DBusError        *error)
00235 {
00236   if (pidfile)
00237     {
00238       _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile));
00239       if (!_dbus_write_pid_file (pidfile,
00240                                  pid_to_write,
00241                                  error))
00242         {
00243           _dbus_verbose ("pid file write failed\n");
00244           _DBUS_ASSERT_ERROR_IS_SET(error);
00245           return FALSE;
00246         }
00247     }
00248   else
00249     {
00250       _dbus_verbose ("No pid file requested\n");
00251     }
00252 
00253   if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
00254     {
00255       DBusString pid;
00256       int bytes;
00257 
00258       _dbus_verbose ("writing our pid to pipe %d\n",
00259                      print_pid_pipe->fd);
00260       
00261       if (!_dbus_string_init (&pid))
00262         {
00263           _DBUS_SET_OOM (error);
00264           return FALSE;
00265         }
00266           
00267       if (!_dbus_string_append_int (&pid, pid_to_write) ||
00268           !_dbus_string_append (&pid, "\n"))
00269         {
00270           _dbus_string_free (&pid);
00271           _DBUS_SET_OOM (error);
00272           return FALSE;
00273         }
00274           
00275       bytes = _dbus_string_get_length (&pid);
00276       if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
00277         {
00278           /* _dbus_pipe_write sets error only on failure, not short write */
00279           if (error != NULL && !dbus_error_is_set(error))
00280             {
00281               dbus_set_error (error, DBUS_ERROR_FAILED,
00282                               "Printing message bus PID: did not write enough bytes\n");
00283             }
00284           _dbus_string_free (&pid);
00285           return FALSE;
00286         }
00287           
00288       _dbus_string_free (&pid);
00289     }
00290   else
00291     {
00292       _dbus_verbose ("No pid pipe to write to\n");
00293     }
00294 
00295   return TRUE;
00296 }
00297 
00304 dbus_bool_t
00305 _dbus_verify_daemon_user (const char *user)
00306 {
00307   DBusString u;
00308 
00309   _dbus_string_init_const (&u, user);
00310 
00311   return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
00312 }
00313 
00314 
00315 /* The HAVE_LIBAUDIT case lives in selinux.c */
00316 #ifndef HAVE_LIBAUDIT
00317 
00324 dbus_bool_t
00325 _dbus_change_to_daemon_user  (const char    *user,
00326                               DBusError     *error)
00327 {
00328   dbus_uid_t uid;
00329   dbus_gid_t gid;
00330   DBusString u;
00331 
00332   _dbus_string_init_const (&u, user);
00333 
00334   if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
00335     {
00336       dbus_set_error (error, DBUS_ERROR_FAILED,
00337                       "User '%s' does not appear to exist?",
00338                       user);
00339       return FALSE;
00340     }
00341 
00342   /* setgroups() only works if we are a privileged process,
00343    * so we don't return error on failure; the only possible
00344    * failure is that we don't have perms to do it.
00345    *
00346    * not sure this is right, maybe if setuid()
00347    * is going to work then setgroups() should also work.
00348    */
00349   if (setgroups (0, NULL) < 0)
00350     _dbus_warn ("Failed to drop supplementary groups: %s\n",
00351                 _dbus_strerror (errno));
00352 
00353   /* Set GID first, or the setuid may remove our permission
00354    * to change the GID
00355    */
00356   if (setgid (gid) < 0)
00357     {
00358       dbus_set_error (error, _dbus_error_from_errno (errno),
00359                       "Failed to set GID to %lu: %s", gid,
00360                       _dbus_strerror (errno));
00361       return FALSE;
00362     }
00363 
00364   if (setuid (uid) < 0)
00365     {
00366       dbus_set_error (error, _dbus_error_from_errno (errno),
00367                       "Failed to set UID to %lu: %s", uid,
00368                       _dbus_strerror (errno));
00369       return FALSE;
00370     }
00371 
00372   return TRUE;
00373 }
00374 #endif /* !HAVE_LIBAUDIT */
00375 
00376 #ifdef HAVE_SETRLIMIT
00377 
00378 /* We assume that if we have setrlimit, we also have getrlimit and
00379  * struct rlimit.
00380  */
00381 
00382 struct DBusRLimit {
00383     struct rlimit lim;
00384 };
00385 
00386 DBusRLimit *
00387 _dbus_rlimit_save_fd_limit (DBusError *error)
00388 {
00389   DBusRLimit *self;
00390 
00391   self = dbus_new0 (DBusRLimit, 1);
00392 
00393   if (self == NULL)
00394     {
00395       _DBUS_SET_OOM (error);
00396       return NULL;
00397     }
00398 
00399   if (getrlimit (RLIMIT_NOFILE, &self->lim) < 0)
00400     {
00401       dbus_set_error (error, _dbus_error_from_errno (errno),
00402                       "Failed to get fd limit: %s", _dbus_strerror (errno));
00403       dbus_free (self);
00404       return NULL;
00405     }
00406 
00407   return self;
00408 }
00409 
00410 dbus_bool_t
00411 _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int  desired,
00412                                            DBusError    *error)
00413 {
00414   struct rlimit lim;
00415 
00416   /* No point to doing this practically speaking
00417    * if we're not uid 0.  We expect the system
00418    * bus to use this before we change UID, and
00419    * the session bus takes the Linux default,
00420    * currently 1024 for cur and 4096 for max.
00421    */
00422   if (getuid () != 0)
00423     {
00424       /* not an error, we're probably the session bus */
00425       return TRUE;
00426     }
00427 
00428   if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
00429     {
00430       dbus_set_error (error, _dbus_error_from_errno (errno),
00431                       "Failed to get fd limit: %s", _dbus_strerror (errno));
00432       return FALSE;
00433     }
00434 
00435   if (lim.rlim_cur == RLIM_INFINITY || lim.rlim_cur >= desired)
00436     {
00437       /* not an error, everything is fine */
00438       return TRUE;
00439     }
00440 
00441   /* Ignore "maximum limit", assume we have the "superuser"
00442    * privileges.  On Linux this is CAP_SYS_RESOURCE.
00443    */
00444   lim.rlim_cur = lim.rlim_max = desired;
00445 
00446   if (setrlimit (RLIMIT_NOFILE, &lim) < 0)
00447     {
00448       dbus_set_error (error, _dbus_error_from_errno (errno),
00449                       "Failed to set fd limit to %u: %s",
00450                       desired, _dbus_strerror (errno));
00451       return FALSE;
00452     }
00453 
00454   return TRUE;
00455 }
00456 
00457 dbus_bool_t
00458 _dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
00459                                DBusError  *error)
00460 {
00461   if (setrlimit (RLIMIT_NOFILE, &saved->lim) < 0)
00462     {
00463       dbus_set_error (error, _dbus_error_from_errno (errno),
00464                       "Failed to restore old fd limit: %s",
00465                       _dbus_strerror (errno));
00466       return FALSE;
00467     }
00468 
00469   return TRUE;
00470 }
00471 
00472 #else /* !HAVE_SETRLIMIT */
00473 
00474 static void
00475 fd_limit_not_supported (DBusError *error)
00476 {
00477   dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
00478                   "cannot change fd limit on this platform");
00479 }
00480 
00481 DBusRLimit *
00482 _dbus_rlimit_save_fd_limit (DBusError *error)
00483 {
00484   fd_limit_not_supported (error);
00485   return NULL;
00486 }
00487 
00488 dbus_bool_t
00489 _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int  desired,
00490                                            DBusError    *error)
00491 {
00492   fd_limit_not_supported (error);
00493   return FALSE;
00494 }
00495 
00496 dbus_bool_t
00497 _dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
00498                                DBusError  *error)
00499 {
00500   fd_limit_not_supported (error);
00501   return FALSE;
00502 }
00503 
00504 #endif
00505 
00506 void
00507 _dbus_rlimit_free (DBusRLimit *lim)
00508 {
00509   dbus_free (lim);
00510 }
00511 
00512 void
00513 _dbus_init_system_log (void)
00514 {
00515 #if HAVE_DECL_LOG_PERROR
00516   openlog ("dbus", LOG_PID | LOG_PERROR, LOG_DAEMON);
00517 #else
00518   openlog ("dbus", LOG_PID, LOG_DAEMON);
00519 #endif
00520 }
00521 
00530 void
00531 _dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...)
00532 {
00533   va_list args;
00534 
00535   va_start (args, msg);
00536 
00537   _dbus_system_logv (severity, msg, args);
00538 
00539   va_end (args);
00540 }
00541 
00552 void
00553 _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args)
00554 {
00555   int flags;
00556   switch (severity)
00557     {
00558       case DBUS_SYSTEM_LOG_INFO:
00559         flags =  LOG_DAEMON | LOG_NOTICE;
00560         break;
00561       case DBUS_SYSTEM_LOG_SECURITY:
00562         flags = LOG_AUTH | LOG_NOTICE;
00563         break;
00564       case DBUS_SYSTEM_LOG_FATAL:
00565         flags = LOG_DAEMON|LOG_CRIT;
00566         break;
00567       default:
00568         return;
00569     }
00570 
00571 #ifndef HAVE_DECL_LOG_PERROR
00572     {
00573       /* vsyslog() won't write to stderr, so we'd better do it */
00574       va_list tmp;
00575 
00576       DBUS_VA_COPY (tmp, args);
00577       fprintf (stderr, "dbus[" DBUS_PID_FORMAT "]: ", _dbus_getpid ());
00578       vfprintf (stderr, msg, tmp);
00579       fputc ('\n', stderr);
00580       va_end (tmp);
00581     }
00582 #endif
00583 
00584   vsyslog (flags, msg, args);
00585 
00586   if (severity == DBUS_SYSTEM_LOG_FATAL)
00587     exit (1);
00588 }
00589 
00595 void
00596 _dbus_set_signal_handler (int               sig,
00597                           DBusSignalHandler handler)
00598 {
00599   struct sigaction act;
00600   sigset_t empty_mask;
00601   
00602   sigemptyset (&empty_mask);
00603   act.sa_handler = handler;
00604   act.sa_mask    = empty_mask;
00605   act.sa_flags   = 0;
00606   sigaction (sig,  &act, NULL);
00607 }
00608 
00614 dbus_bool_t 
00615 _dbus_file_exists (const char *file)
00616 {
00617   return (access (file, F_OK) == 0);
00618 }
00619 
00626 dbus_bool_t 
00627 _dbus_user_at_console (const char *username,
00628                        DBusError  *error)
00629 {
00630 
00631   DBusString u, f;
00632   dbus_bool_t result;
00633 
00634   result = FALSE;
00635   if (!_dbus_string_init (&f))
00636     {
00637       _DBUS_SET_OOM (error);
00638       return FALSE;
00639     }
00640 
00641   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00642     {
00643       _DBUS_SET_OOM (error);
00644       goto out;
00645     }
00646 
00647   _dbus_string_init_const (&u, username);
00648 
00649   if (!_dbus_concat_dir_and_file (&f, &u))
00650     {
00651       _DBUS_SET_OOM (error);
00652       goto out;
00653     }
00654 
00655   result = _dbus_file_exists (_dbus_string_get_const_data (&f));
00656 
00657  out:
00658   _dbus_string_free (&f);
00659 
00660   return result;
00661 }
00662 
00663 
00670 dbus_bool_t
00671 _dbus_path_is_absolute (const DBusString *filename)
00672 {
00673   if (_dbus_string_get_length (filename) > 0)
00674     return _dbus_string_get_byte (filename, 0) == '/';
00675   else
00676     return FALSE;
00677 }
00678 
00687 dbus_bool_t
00688 _dbus_stat (const DBusString *filename,
00689             DBusStat         *statbuf,
00690             DBusError        *error)
00691 {
00692   const char *filename_c;
00693   struct stat sb;
00694 
00695   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00696   
00697   filename_c = _dbus_string_get_const_data (filename);
00698 
00699   if (stat (filename_c, &sb) < 0)
00700     {
00701       dbus_set_error (error, _dbus_error_from_errno (errno),
00702                       "%s", _dbus_strerror (errno));
00703       return FALSE;
00704     }
00705 
00706   statbuf->mode = sb.st_mode;
00707   statbuf->nlink = sb.st_nlink;
00708   statbuf->uid = sb.st_uid;
00709   statbuf->gid = sb.st_gid;
00710   statbuf->size = sb.st_size;
00711   statbuf->atime = sb.st_atime;
00712   statbuf->mtime = sb.st_mtime;
00713   statbuf->ctime = sb.st_ctime;
00714 
00715   return TRUE;
00716 }
00717 
00718 
00722 struct DBusDirIter
00723 {
00724   DIR *d; 
00726 };
00727 
00735 DBusDirIter*
00736 _dbus_directory_open (const DBusString *filename,
00737                       DBusError        *error)
00738 {
00739   DIR *d;
00740   DBusDirIter *iter;
00741   const char *filename_c;
00742 
00743   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00744   
00745   filename_c = _dbus_string_get_const_data (filename);
00746 
00747   d = opendir (filename_c);
00748   if (d == NULL)
00749     {
00750       dbus_set_error (error, _dbus_error_from_errno (errno),
00751                       "Failed to read directory \"%s\": %s",
00752                       filename_c,
00753                       _dbus_strerror (errno));
00754       return NULL;
00755     }
00756   iter = dbus_new0 (DBusDirIter, 1);
00757   if (iter == NULL)
00758     {
00759       closedir (d);
00760       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00761                       "Could not allocate memory for directory iterator");
00762       return NULL;
00763     }
00764 
00765   iter->d = d;
00766 
00767   return iter;
00768 }
00769 
00783 dbus_bool_t
00784 _dbus_directory_get_next_file (DBusDirIter      *iter,
00785                                DBusString       *filename,
00786                                DBusError        *error)
00787 {
00788   struct dirent *ent;
00789   int err;
00790 
00791   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00792 
00793  again:
00794   errno = 0;
00795   ent = readdir (iter->d);
00796 
00797   if (!ent)
00798     {
00799       err = errno;
00800 
00801       if (err != 0)
00802         dbus_set_error (error,
00803                         _dbus_error_from_errno (err),
00804                         "%s", _dbus_strerror (err));
00805 
00806       return FALSE;
00807     }
00808   else if (ent->d_name[0] == '.' &&
00809            (ent->d_name[1] == '\0' ||
00810             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00811     goto again;
00812   else
00813     {
00814       _dbus_string_set_length (filename, 0);
00815       if (!_dbus_string_append (filename, ent->d_name))
00816         {
00817           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00818                           "No memory to read directory entry");
00819           return FALSE;
00820         }
00821       else
00822         {
00823           return TRUE;
00824         }
00825     }
00826 }
00827 
00831 void
00832 _dbus_directory_close (DBusDirIter *iter)
00833 {
00834   closedir (iter->d);
00835   dbus_free (iter);
00836 }
00837 
00838 static dbus_bool_t
00839 fill_user_info_from_group (struct group  *g,
00840                            DBusGroupInfo *info,
00841                            DBusError     *error)
00842 {
00843   _dbus_assert (g->gr_name != NULL);
00844   
00845   info->gid = g->gr_gid;
00846   info->groupname = _dbus_strdup (g->gr_name);
00847 
00848   /* info->members = dbus_strdupv (g->gr_mem) */
00849   
00850   if (info->groupname == NULL)
00851     {
00852       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00853       return FALSE;
00854     }
00855 
00856   return TRUE;
00857 }
00858 
00859 static dbus_bool_t
00860 fill_group_info (DBusGroupInfo    *info,
00861                  dbus_gid_t        gid,
00862                  const DBusString *groupname,
00863                  DBusError        *error)
00864 {
00865   const char *group_c_str;
00866 
00867   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00868   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00869 
00870   if (groupname)
00871     group_c_str = _dbus_string_get_const_data (groupname);
00872   else
00873     group_c_str = NULL;
00874   
00875   /* For now assuming that the getgrnam() and getgrgid() flavors
00876    * always correspond to the pwnam flavors, if not we have
00877    * to add more configure checks.
00878    */
00879   
00880 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00881   {
00882     struct group *g;
00883     int result;
00884     size_t buflen;
00885     char *buf;
00886     struct group g_str;
00887     dbus_bool_t b;
00888 
00889     /* retrieve maximum needed size for buf */
00890     buflen = sysconf (_SC_GETGR_R_SIZE_MAX);
00891 
00892     /* sysconf actually returns a long, but everything else expects size_t,
00893      * so just recast here.
00894      * https://bugs.freedesktop.org/show_bug.cgi?id=17061
00895      */
00896     if ((long) buflen <= 0)
00897       buflen = 1024;
00898 
00899     result = -1;
00900     while (1)
00901       {
00902         buf = dbus_malloc (buflen);
00903         if (buf == NULL)
00904           {
00905             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00906             return FALSE;
00907           }
00908 
00909         g = NULL;
00910 #ifdef HAVE_POSIX_GETPWNAM_R
00911         if (group_c_str)
00912           result = getgrnam_r (group_c_str, &g_str, buf, buflen,
00913                                &g);
00914         else
00915           result = getgrgid_r (gid, &g_str, buf, buflen,
00916                                &g);
00917 #else
00918         g = getgrnam_r (group_c_str, &g_str, buf, buflen);
00919         result = 0;
00920 #endif /* !HAVE_POSIX_GETPWNAM_R */
00921         /* Try a bigger buffer if ERANGE was returned:
00922            https://bugs.freedesktop.org/show_bug.cgi?id=16727
00923         */
00924         if (result == ERANGE && buflen < 512 * 1024)
00925           {
00926             dbus_free (buf);
00927             buflen *= 2;
00928           }
00929         else
00930           {
00931             break;
00932           }
00933       }
00934 
00935     if (result == 0 && g == &g_str)
00936       {
00937         b = fill_user_info_from_group (g, info, error);
00938         dbus_free (buf);
00939         return b;
00940       }
00941     else
00942       {
00943         dbus_set_error (error, _dbus_error_from_errno (errno),
00944                         "Group %s unknown or failed to look it up\n",
00945                         group_c_str ? group_c_str : "???");
00946         dbus_free (buf);
00947         return FALSE;
00948       }
00949   }
00950 #else /* ! HAVE_GETPWNAM_R */
00951   {
00952     /* I guess we're screwed on thread safety here */
00953     struct group *g;
00954 
00955     g = getgrnam (group_c_str);
00956 
00957     if (g != NULL)
00958       {
00959         return fill_user_info_from_group (g, info, error);
00960       }
00961     else
00962       {
00963         dbus_set_error (error, _dbus_error_from_errno (errno),
00964                         "Group %s unknown or failed to look it up\n",
00965                         group_c_str ? group_c_str : "???");
00966         return FALSE;
00967       }
00968   }
00969 #endif  /* ! HAVE_GETPWNAM_R */
00970 }
00971 
00981 dbus_bool_t
00982 _dbus_group_info_fill (DBusGroupInfo    *info,
00983                        const DBusString *groupname,
00984                        DBusError        *error)
00985 {
00986   return fill_group_info (info, DBUS_GID_UNSET,
00987                           groupname, error);
00988 
00989 }
00990 
01000 dbus_bool_t
01001 _dbus_group_info_fill_gid (DBusGroupInfo *info,
01002                            dbus_gid_t     gid,
01003                            DBusError     *error)
01004 {
01005   return fill_group_info (info, gid, NULL, error);
01006 }
01007 
01016 dbus_bool_t
01017 _dbus_parse_unix_user_from_config (const DBusString  *username,
01018                                    dbus_uid_t        *uid_p)
01019 {
01020   return _dbus_get_user_id (username, uid_p);
01021 
01022 }
01023 
01032 dbus_bool_t
01033 _dbus_parse_unix_group_from_config (const DBusString  *groupname,
01034                                     dbus_gid_t        *gid_p)
01035 {
01036   return _dbus_get_group_id (groupname, gid_p);
01037 }
01038 
01049 dbus_bool_t
01050 _dbus_unix_groups_from_uid (dbus_uid_t            uid,
01051                             dbus_gid_t          **group_ids,
01052                             int                  *n_group_ids)
01053 {
01054   return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
01055 }
01056 
01066 dbus_bool_t
01067 _dbus_unix_user_is_at_console (dbus_uid_t         uid,
01068                                DBusError         *error)
01069 {
01070   return _dbus_is_console_user (uid, error);
01071 
01072 }
01073 
01081 dbus_bool_t
01082 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
01083 {
01084   return uid == _dbus_geteuid ();
01085 }
01086 
01094 dbus_bool_t
01095 _dbus_windows_user_is_process_owner (const char *windows_sid)
01096 {
01097   return FALSE;
01098 }
01099  /* End of DBusInternalsUtils functions */
01101 
01113 dbus_bool_t
01114 _dbus_string_get_dirname  (const DBusString *filename,
01115                            DBusString       *dirname)
01116 {
01117   int sep;
01118   
01119   _dbus_assert (filename != dirname);
01120   _dbus_assert (filename != NULL);
01121   _dbus_assert (dirname != NULL);
01122 
01123   /* Ignore any separators on the end */
01124   sep = _dbus_string_get_length (filename);
01125   if (sep == 0)
01126     return _dbus_string_append (dirname, "."); /* empty string passed in */
01127     
01128   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01129     --sep;
01130 
01131   _dbus_assert (sep >= 0);
01132   
01133   if (sep == 0)
01134     return _dbus_string_append (dirname, "/");
01135   
01136   /* Now find the previous separator */
01137   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
01138   if (sep < 0)
01139     return _dbus_string_append (dirname, ".");
01140   
01141   /* skip multiple separators */
01142   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01143     --sep;
01144 
01145   _dbus_assert (sep >= 0);
01146   
01147   if (sep == 0 &&
01148       _dbus_string_get_byte (filename, 0) == '/')
01149     return _dbus_string_append (dirname, "/");
01150   else
01151     return _dbus_string_copy_len (filename, 0, sep - 0,
01152                                   dirname, _dbus_string_get_length (dirname));
01153 } /* DBusString stuff */
01155 
01156 static void
01157 string_squash_nonprintable (DBusString *str)
01158 {
01159   unsigned char *buf;
01160   int i, len; 
01161   
01162   buf = _dbus_string_get_data (str);
01163   len = _dbus_string_get_length (str);
01164   
01165   for (i = 0; i < len; i++)
01166     {
01167       unsigned char c = (unsigned char) buf[i];
01168       if (c == '\0')
01169         buf[i] = ' ';
01170       else if (c < 0x20 || c > 127)
01171         buf[i] = '?';
01172     }
01173 }
01174 
01189 dbus_bool_t 
01190 _dbus_command_for_pid (unsigned long  pid,
01191                        DBusString    *str,
01192                        int            max_len,
01193                        DBusError     *error)
01194 {
01195   /* This is all Linux-specific for now */
01196   DBusString path;
01197   DBusString cmdline;
01198   int fd;
01199   
01200   if (!_dbus_string_init (&path)) 
01201     {
01202       _DBUS_SET_OOM (error);
01203       return FALSE;
01204     }
01205   
01206   if (!_dbus_string_init (&cmdline))
01207     {
01208       _DBUS_SET_OOM (error);
01209       _dbus_string_free (&path);
01210       return FALSE;
01211     }
01212   
01213   if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid))
01214     goto oom;
01215   
01216   fd = open (_dbus_string_get_const_data (&path), O_RDONLY);
01217   if (fd < 0) 
01218     {
01219       dbus_set_error (error,
01220                       _dbus_error_from_errno (errno),
01221                       "Failed to open \"%s\": %s",
01222                       _dbus_string_get_const_data (&path),
01223                       _dbus_strerror (errno));
01224       goto fail;
01225     }
01226   
01227   if (!_dbus_read (fd, &cmdline, max_len))
01228     {
01229       dbus_set_error (error,
01230                       _dbus_error_from_errno (errno),
01231                       "Failed to read from \"%s\": %s",
01232                       _dbus_string_get_const_data (&path),
01233                       _dbus_strerror (errno));      
01234       _dbus_close (fd, NULL);
01235       goto fail;
01236     }
01237   
01238   if (!_dbus_close (fd, error))
01239     goto fail;
01240   
01241   string_squash_nonprintable (&cmdline);  
01242 
01243   if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
01244     goto oom;
01245 
01246   _dbus_string_free (&cmdline);  
01247   _dbus_string_free (&path);
01248   return TRUE;
01249 oom:
01250   _DBUS_SET_OOM (error);
01251 fail:
01252   _dbus_string_free (&cmdline);
01253   _dbus_string_free (&path);
01254   return FALSE;
01255 }