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 #ifdef HAVE_LIBAUDIT
00047 #include <sys/prctl.h>
00048 #include <sys/capability.h>
00049 #include <libaudit.h>
00050 #endif /* HAVE_LIBAUDIT */
00051 
00052 #ifdef HAVE_SYS_SYSLIMITS_H
00053 #include <sys/syslimits.h>
00054 #endif
00055 
00056 #ifndef O_BINARY
00057 #define O_BINARY 0
00058 #endif
00059 
00074 dbus_bool_t
00075 _dbus_become_daemon (const DBusString *pidfile,
00076                      DBusPipe         *print_pid_pipe,
00077                      DBusError        *error)
00078 {
00079   const char *s;
00080   pid_t child_pid;
00081   int dev_null_fd;
00082 
00083   _dbus_verbose ("Becoming a daemon...\n");
00084 
00085   _dbus_verbose ("chdir to /\n");
00086   if (chdir ("/") < 0)
00087     {
00088       dbus_set_error (error, DBUS_ERROR_FAILED,
00089                       "Could not chdir() to root directory");
00090       return FALSE;
00091     }
00092 
00093   _dbus_verbose ("forking...\n");
00094   switch ((child_pid = fork ()))
00095     {
00096     case -1:
00097       _dbus_verbose ("fork failed\n");
00098       dbus_set_error (error, _dbus_error_from_errno (errno),
00099                       "Failed to fork daemon: %s", _dbus_strerror (errno));
00100       return FALSE;
00101       break;
00102 
00103     case 0:
00104       _dbus_verbose ("in child, closing std file descriptors\n");
00105 
00106       /* silently ignore failures here, if someone
00107        * doesn't have /dev/null we may as well try
00108        * to continue anyhow
00109        */
00110       
00111       dev_null_fd = open ("/dev/null", O_RDWR);
00112       if (dev_null_fd >= 0)
00113         {
00114           dup2 (dev_null_fd, 0);
00115           dup2 (dev_null_fd, 1);
00116           
00117           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00118           if (s == NULL || *s == '\0')
00119             dup2 (dev_null_fd, 2);
00120           else
00121             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00122         }
00123 
00124       /* Get a predictable umask */
00125       _dbus_verbose ("setting umask\n");
00126       umask (022);
00127 
00128       _dbus_verbose ("calling setsid()\n");
00129       if (setsid () == -1)
00130         _dbus_assert_not_reached ("setsid() failed");
00131       
00132       break;
00133 
00134     default:
00135       if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe,
00136                                              child_pid, error))
00137         {
00138           _dbus_verbose ("pid file or pipe write failed: %s\n",
00139                          error->message);
00140           kill (child_pid, SIGTERM);
00141           return FALSE;
00142         }
00143 
00144       _dbus_verbose ("parent exiting\n");
00145       _exit (0);
00146       break;
00147     }
00148   
00149   return TRUE;
00150 }
00151 
00152 
00161 static dbus_bool_t
00162 _dbus_write_pid_file (const DBusString *filename,
00163                       unsigned long     pid,
00164                       DBusError        *error)
00165 {
00166   const char *cfilename;
00167   int fd;
00168   FILE *f;
00169 
00170   cfilename = _dbus_string_get_const_data (filename);
00171   
00172   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00173   
00174   if (fd < 0)
00175     {
00176       dbus_set_error (error, _dbus_error_from_errno (errno),
00177                       "Failed to open \"%s\": %s", cfilename,
00178                       _dbus_strerror (errno));
00179       return FALSE;
00180     }
00181 
00182   if ((f = fdopen (fd, "w")) == NULL)
00183     {
00184       dbus_set_error (error, _dbus_error_from_errno (errno),
00185                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00186       _dbus_close (fd, NULL);
00187       return FALSE;
00188     }
00189   
00190   if (fprintf (f, "%lu\n", pid) < 0)
00191     {
00192       dbus_set_error (error, _dbus_error_from_errno (errno),
00193                       "Failed to write to \"%s\": %s", cfilename,
00194                       _dbus_strerror (errno));
00195       
00196       fclose (f);
00197       return FALSE;
00198     }
00199 
00200   if (fclose (f) == EOF)
00201     {
00202       dbus_set_error (error, _dbus_error_from_errno (errno),
00203                       "Failed to close \"%s\": %s", cfilename,
00204                       _dbus_strerror (errno));
00205       return FALSE;
00206     }
00207   
00208   return TRUE;
00209 }
00210 
00222 dbus_bool_t
00223 _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
00224                                   DBusPipe         *print_pid_pipe,
00225                                   dbus_pid_t        pid_to_write,
00226                                   DBusError        *error)
00227 {
00228   if (pidfile)
00229     {
00230       _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile));
00231       if (!_dbus_write_pid_file (pidfile,
00232                                  pid_to_write,
00233                                  error))
00234         {
00235           _dbus_verbose ("pid file write failed\n");
00236           _DBUS_ASSERT_ERROR_IS_SET(error);
00237           return FALSE;
00238         }
00239     }
00240   else
00241     {
00242       _dbus_verbose ("No pid file requested\n");
00243     }
00244 
00245   if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
00246     {
00247       DBusString pid;
00248       int bytes;
00249 
00250       _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd_or_handle);
00251       
00252       if (!_dbus_string_init (&pid))
00253         {
00254           _DBUS_SET_OOM (error);
00255           return FALSE;
00256         }
00257           
00258       if (!_dbus_string_append_int (&pid, pid_to_write) ||
00259           !_dbus_string_append (&pid, "\n"))
00260         {
00261           _dbus_string_free (&pid);
00262           _DBUS_SET_OOM (error);
00263           return FALSE;
00264         }
00265           
00266       bytes = _dbus_string_get_length (&pid);
00267       if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
00268         {
00269           /* _dbus_pipe_write sets error only on failure, not short write */
00270           if (error != NULL && !dbus_error_is_set(error))
00271             {
00272               dbus_set_error (error, DBUS_ERROR_FAILED,
00273                               "Printing message bus PID: did not write enough bytes\n");
00274             }
00275           _dbus_string_free (&pid);
00276           return FALSE;
00277         }
00278           
00279       _dbus_string_free (&pid);
00280     }
00281   else
00282     {
00283       _dbus_verbose ("No pid pipe to write to\n");
00284     }
00285 
00286   return TRUE;
00287 }
00288 
00295 dbus_bool_t
00296 _dbus_verify_daemon_user (const char *user)
00297 {
00298   DBusString u;
00299 
00300   _dbus_string_init_const (&u, user);
00301 
00302   return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
00303 }
00304 
00312 dbus_bool_t
00313 _dbus_change_to_daemon_user  (const char    *user,
00314                               DBusError     *error)
00315 {
00316   dbus_uid_t uid;
00317   dbus_gid_t gid;
00318   DBusString u;
00319 #ifdef HAVE_LIBAUDIT
00320   dbus_bool_t we_were_root;
00321   cap_t new_caps;
00322 #endif
00323   
00324   _dbus_string_init_const (&u, user);
00325   
00326   if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
00327     {
00328       dbus_set_error (error, DBUS_ERROR_FAILED,
00329                       "User '%s' does not appear to exist?",
00330                       user);
00331       return FALSE;
00332     }
00333   
00334 #ifdef HAVE_LIBAUDIT
00335   we_were_root = _dbus_geteuid () == 0;
00336   new_caps = NULL;
00337   /* have a tmp set of caps that we use to transition to the usr/grp dbus should
00338    * run as ... doesn't really help. But keeps people happy.
00339    */
00340     
00341   if (we_were_root)
00342     {
00343       cap_value_t new_cap_list[] = { CAP_AUDIT_WRITE };
00344       cap_value_t tmp_cap_list[] = { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
00345       cap_t tmp_caps = cap_init();
00346         
00347       if (!tmp_caps || !(new_caps = cap_init ()))
00348         {
00349           dbus_set_error (error, DBUS_ERROR_FAILED,
00350                           "Failed to initialize drop of capabilities: %s\n",
00351                           _dbus_strerror (errno));
00352 
00353           if (tmp_caps)
00354             cap_free (tmp_caps);
00355 
00356           return FALSE;
00357         }
00358 
00359       /* assume these work... */
00360       cap_set_flag (new_caps, CAP_PERMITTED, 1, new_cap_list, CAP_SET);
00361       cap_set_flag (new_caps, CAP_EFFECTIVE, 1, new_cap_list, CAP_SET);
00362       cap_set_flag (tmp_caps, CAP_PERMITTED, 3, tmp_cap_list, CAP_SET);
00363       cap_set_flag (tmp_caps, CAP_EFFECTIVE, 3, tmp_cap_list, CAP_SET);
00364       
00365       if (prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
00366         {
00367           dbus_set_error (error, _dbus_error_from_errno (errno),
00368                           "Failed to set keep-capabilities: %s\n",
00369                           _dbus_strerror (errno));
00370           cap_free (tmp_caps);
00371           goto fail;
00372         }
00373         
00374       if (cap_set_proc (tmp_caps) == -1)
00375         {
00376           dbus_set_error (error, DBUS_ERROR_FAILED,
00377                           "Failed to drop capabilities: %s\n",
00378                           _dbus_strerror (errno));
00379           cap_free (tmp_caps);
00380           goto fail;
00381         }
00382       cap_free (tmp_caps);
00383     }
00384 #endif /* HAVE_LIBAUDIT */
00385   
00386   /* setgroups() only works if we are a privileged process,
00387    * so we don't return error on failure; the only possible
00388    * failure is that we don't have perms to do it.
00389    *
00390    * not sure this is right, maybe if setuid()
00391    * is going to work then setgroups() should also work.
00392    */
00393   if (setgroups (0, NULL) < 0)
00394     _dbus_warn ("Failed to drop supplementary groups: %s\n",
00395                 _dbus_strerror (errno));
00396   
00397   /* Set GID first, or the setuid may remove our permission
00398    * to change the GID
00399    */
00400   if (setgid (gid) < 0)
00401     {
00402       dbus_set_error (error, _dbus_error_from_errno (errno),
00403                       "Failed to set GID to %lu: %s", gid,
00404                       _dbus_strerror (errno));
00405       goto fail;
00406     }
00407   
00408   if (setuid (uid) < 0)
00409     {
00410       dbus_set_error (error, _dbus_error_from_errno (errno),
00411                       "Failed to set UID to %lu: %s", uid,
00412                       _dbus_strerror (errno));
00413       goto fail;
00414     }
00415   
00416 #ifdef HAVE_LIBAUDIT
00417   if (we_were_root)
00418     {
00419       if (cap_set_proc (new_caps))
00420         {
00421           dbus_set_error (error, DBUS_ERROR_FAILED,
00422                           "Failed to drop capabilities: %s\n",
00423                           _dbus_strerror (errno));
00424           goto fail;
00425         }
00426       cap_free (new_caps);
00427 
00428       /* should always work, if it did above */      
00429       if (prctl (PR_SET_KEEPCAPS, 0, 0, 0, 0) == -1)
00430         {
00431           dbus_set_error (error, _dbus_error_from_errno (errno),
00432                           "Failed to unset keep-capabilities: %s\n",
00433                           _dbus_strerror (errno));
00434           return FALSE;
00435         }
00436     }
00437 #endif
00438 
00439  return TRUE;
00440 
00441  fail:
00442 #ifdef HAVE_LIBAUDIT
00443  if (!we_were_root)
00444    {
00445      /* should always work, if it did above */
00446      prctl (PR_SET_KEEPCAPS, 0, 0, 0, 0);
00447      cap_free (new_caps);
00448    }
00449 #endif
00450 
00451  return FALSE;
00452 }
00453 
00459 void
00460 _dbus_set_signal_handler (int               sig,
00461                           DBusSignalHandler handler)
00462 {
00463   struct sigaction act;
00464   sigset_t empty_mask;
00465   
00466   sigemptyset (&empty_mask);
00467   act.sa_handler = handler;
00468   act.sa_mask    = empty_mask;
00469   act.sa_flags   = 0;
00470   sigaction (sig,  &act, NULL);
00471 }
00472 
00473 
00481 dbus_bool_t
00482 _dbus_delete_directory (const DBusString *filename,
00483                         DBusError        *error)
00484 {
00485   const char *filename_c;
00486   
00487   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00488 
00489   filename_c = _dbus_string_get_const_data (filename);
00490 
00491   if (rmdir (filename_c) != 0)
00492     {
00493       dbus_set_error (error, DBUS_ERROR_FAILED,
00494                       "Failed to remove directory %s: %s\n",
00495                       filename_c, _dbus_strerror (errno));
00496       return FALSE;
00497     }
00498   
00499   return TRUE;
00500 }
00501 
00507 dbus_bool_t 
00508 _dbus_file_exists (const char *file)
00509 {
00510   return (access (file, F_OK) == 0);
00511 }
00512 
00519 dbus_bool_t 
00520 _dbus_user_at_console (const char *username,
00521                        DBusError  *error)
00522 {
00523 
00524   DBusString f;
00525   dbus_bool_t result;
00526 
00527   result = FALSE;
00528   if (!_dbus_string_init (&f))
00529     {
00530       _DBUS_SET_OOM (error);
00531       return FALSE;
00532     }
00533 
00534   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00535     {
00536       _DBUS_SET_OOM (error);
00537       goto out;
00538     }
00539 
00540 
00541   if (!_dbus_string_append (&f, username))
00542     {
00543       _DBUS_SET_OOM (error);
00544       goto out;
00545     }
00546 
00547   result = _dbus_file_exists (_dbus_string_get_const_data (&f));
00548 
00549  out:
00550   _dbus_string_free (&f);
00551 
00552   return result;
00553 }
00554 
00555 
00562 dbus_bool_t
00563 _dbus_path_is_absolute (const DBusString *filename)
00564 {
00565   if (_dbus_string_get_length (filename) > 0)
00566     return _dbus_string_get_byte (filename, 0) == '/';
00567   else
00568     return FALSE;
00569 }
00570 
00579 dbus_bool_t
00580 _dbus_stat (const DBusString *filename,
00581             DBusStat         *statbuf,
00582             DBusError        *error)
00583 {
00584   const char *filename_c;
00585   struct stat sb;
00586 
00587   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00588   
00589   filename_c = _dbus_string_get_const_data (filename);
00590 
00591   if (stat (filename_c, &sb) < 0)
00592     {
00593       dbus_set_error (error, _dbus_error_from_errno (errno),
00594                       "%s", _dbus_strerror (errno));
00595       return FALSE;
00596     }
00597 
00598   statbuf->mode = sb.st_mode;
00599   statbuf->nlink = sb.st_nlink;
00600   statbuf->uid = sb.st_uid;
00601   statbuf->gid = sb.st_gid;
00602   statbuf->size = sb.st_size;
00603   statbuf->atime = sb.st_atime;
00604   statbuf->mtime = sb.st_mtime;
00605   statbuf->ctime = sb.st_ctime;
00606 
00607   return TRUE;
00608 }
00609 
00610 
00614 struct DBusDirIter
00615 {
00616   DIR *d; 
00618 };
00619 
00627 DBusDirIter*
00628 _dbus_directory_open (const DBusString *filename,
00629                       DBusError        *error)
00630 {
00631   DIR *d;
00632   DBusDirIter *iter;
00633   const char *filename_c;
00634 
00635   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00636   
00637   filename_c = _dbus_string_get_const_data (filename);
00638 
00639   d = opendir (filename_c);
00640   if (d == NULL)
00641     {
00642       dbus_set_error (error, _dbus_error_from_errno (errno),
00643                       "Failed to read directory \"%s\": %s",
00644                       filename_c,
00645                       _dbus_strerror (errno));
00646       return NULL;
00647     }
00648   iter = dbus_new0 (DBusDirIter, 1);
00649   if (iter == NULL)
00650     {
00651       closedir (d);
00652       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00653                       "Could not allocate memory for directory iterator");
00654       return NULL;
00655     }
00656 
00657   iter->d = d;
00658 
00659   return iter;
00660 }
00661 
00662 /* Calculate the required buffer size (in bytes) for directory
00663  * entries read from the given directory handle.  Return -1 if this
00664  * this cannot be done. 
00665  *
00666  * If you use autoconf, include fpathconf and dirfd in your
00667  * AC_CHECK_FUNCS list.  Otherwise use some other method to detect
00668  * and use them where available.
00669  */
00670 static dbus_bool_t
00671 dirent_buf_size(DIR * dirp, size_t *size)
00672 {
00673  long name_max;
00674 #   if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
00675 #      if defined(HAVE_DIRFD)
00676           name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
00677 #      elif defined(HAVE_DDFD)
00678           name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
00679 #      else
00680           name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
00681 #      endif /* HAVE_DIRFD */
00682      if (name_max == -1)
00683 #           if defined(NAME_MAX)
00684              name_max = NAME_MAX;
00685 #           else
00686              return FALSE;
00687 #           endif
00688 #   elif defined(MAXNAMELEN)
00689      name_max = MAXNAMELEN;
00690 #   else
00691 #       if defined(NAME_MAX)
00692          name_max = NAME_MAX;
00693 #       else
00694 #           error "buffer size for readdir_r cannot be determined"
00695 #       endif
00696 #   endif
00697   if (size)
00698     *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
00699   else
00700     return FALSE;
00701 
00702   return TRUE;
00703 }
00704 
00715 dbus_bool_t
00716 _dbus_directory_get_next_file (DBusDirIter      *iter,
00717                                DBusString       *filename,
00718                                DBusError        *error)
00719 {
00720   struct dirent *d, *ent;
00721   size_t buf_size;
00722   int err;
00723 
00724   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00725  
00726   if (!dirent_buf_size (iter->d, &buf_size))
00727     {
00728       dbus_set_error (error, DBUS_ERROR_FAILED,
00729                       "Can't calculate buffer size when reading directory");
00730       return FALSE;
00731     }
00732 
00733   d = (struct dirent *)dbus_malloc (buf_size);
00734   if (!d)
00735     {
00736       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00737                       "No memory to read directory entry");
00738       return FALSE;
00739     }
00740 
00741  again:
00742   err = readdir_r (iter->d, d, &ent);
00743   if (err || !ent)
00744     {
00745       if (err != 0)
00746         dbus_set_error (error,
00747                         _dbus_error_from_errno (err),
00748                         "%s", _dbus_strerror (err));
00749 
00750       dbus_free (d);
00751       return FALSE;
00752     }
00753   else if (ent->d_name[0] == '.' &&
00754            (ent->d_name[1] == '\0' ||
00755             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00756     goto again;
00757   else
00758     {
00759       _dbus_string_set_length (filename, 0);
00760       if (!_dbus_string_append (filename, ent->d_name))
00761         {
00762           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00763                           "No memory to read directory entry");
00764           dbus_free (d);
00765           return FALSE;
00766         }
00767       else
00768         {
00769           dbus_free (d);
00770           return TRUE;
00771         }
00772     }
00773 }
00774 
00778 void
00779 _dbus_directory_close (DBusDirIter *iter)
00780 {
00781   closedir (iter->d);
00782   dbus_free (iter);
00783 }
00784 
00785 static dbus_bool_t
00786 fill_user_info_from_group (struct group  *g,
00787                            DBusGroupInfo *info,
00788                            DBusError     *error)
00789 {
00790   _dbus_assert (g->gr_name != NULL);
00791   
00792   info->gid = g->gr_gid;
00793   info->groupname = _dbus_strdup (g->gr_name);
00794 
00795   /* info->members = dbus_strdupv (g->gr_mem) */
00796   
00797   if (info->groupname == NULL)
00798     {
00799       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00800       return FALSE;
00801     }
00802 
00803   return TRUE;
00804 }
00805 
00806 static dbus_bool_t
00807 fill_group_info (DBusGroupInfo    *info,
00808                  dbus_gid_t        gid,
00809                  const DBusString *groupname,
00810                  DBusError        *error)
00811 {
00812   const char *group_c_str;
00813 
00814   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00815   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00816 
00817   if (groupname)
00818     group_c_str = _dbus_string_get_const_data (groupname);
00819   else
00820     group_c_str = NULL;
00821   
00822   /* For now assuming that the getgrnam() and getgrgid() flavors
00823    * always correspond to the pwnam flavors, if not we have
00824    * to add more configure checks.
00825    */
00826   
00827 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00828   {
00829     struct group *g;
00830     int result;
00831     size_t buflen;
00832     char *buf;
00833     struct group g_str;
00834     dbus_bool_t b;
00835 
00836     /* retrieve maximum needed size for buf */
00837     buflen = sysconf (_SC_GETGR_R_SIZE_MAX);
00838 
00839     /* sysconf actually returns a long, but everything else expects size_t,
00840      * so just recast here.
00841      * https://bugs.freedesktop.org/show_bug.cgi?id=17061
00842      */
00843     if ((long) buflen <= 0)
00844       buflen = 1024;
00845 
00846     result = -1;
00847     while (1)
00848       {
00849         buf = dbus_malloc (buflen);
00850         if (buf == NULL)
00851           {
00852             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00853             return FALSE;
00854           }
00855 
00856         g = NULL;
00857 #ifdef HAVE_POSIX_GETPWNAM_R
00858         if (group_c_str)
00859           result = getgrnam_r (group_c_str, &g_str, buf, buflen,
00860                                &g);
00861         else
00862           result = getgrgid_r (gid, &g_str, buf, buflen,
00863                                &g);
00864 #else
00865         g = getgrnam_r (group_c_str, &g_str, buf, buflen);
00866         result = 0;
00867 #endif /* !HAVE_POSIX_GETPWNAM_R */
00868         /* Try a bigger buffer if ERANGE was returned:
00869            https://bugs.freedesktop.org/show_bug.cgi?id=16727
00870         */
00871         if (result == ERANGE && buflen < 512 * 1024)
00872           {
00873             dbus_free (buf);
00874             buflen *= 2;
00875           }
00876         else
00877           {
00878             break;
00879           }
00880       }
00881 
00882     if (result == 0 && g == &g_str)
00883       {
00884         b = fill_user_info_from_group (g, info, error);
00885         dbus_free (buf);
00886         return b;
00887       }
00888     else
00889       {
00890         dbus_set_error (error, _dbus_error_from_errno (errno),
00891                         "Group %s unknown or failed to look it up\n",
00892                         group_c_str ? group_c_str : "???");
00893         dbus_free (buf);
00894         return FALSE;
00895       }
00896   }
00897 #else /* ! HAVE_GETPWNAM_R */
00898   {
00899     /* I guess we're screwed on thread safety here */
00900     struct group *g;
00901 
00902     g = getgrnam (group_c_str);
00903 
00904     if (g != NULL)
00905       {
00906         return fill_user_info_from_group (g, info, error);
00907       }
00908     else
00909       {
00910         dbus_set_error (error, _dbus_error_from_errno (errno),
00911                         "Group %s unknown or failed to look it up\n",
00912                         group_c_str ? group_c_str : "???");
00913         return FALSE;
00914       }
00915   }
00916 #endif  /* ! HAVE_GETPWNAM_R */
00917 }
00918 
00928 dbus_bool_t
00929 _dbus_group_info_fill (DBusGroupInfo    *info,
00930                        const DBusString *groupname,
00931                        DBusError        *error)
00932 {
00933   return fill_group_info (info, DBUS_GID_UNSET,
00934                           groupname, error);
00935 
00936 }
00937 
00947 dbus_bool_t
00948 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00949                            dbus_gid_t     gid,
00950                            DBusError     *error)
00951 {
00952   return fill_group_info (info, gid, NULL, error);
00953 }
00954 
00963 dbus_bool_t
00964 _dbus_parse_unix_user_from_config (const DBusString  *username,
00965                                    dbus_uid_t        *uid_p)
00966 {
00967   return _dbus_get_user_id (username, uid_p);
00968 
00969 }
00970 
00979 dbus_bool_t
00980 _dbus_parse_unix_group_from_config (const DBusString  *groupname,
00981                                     dbus_gid_t        *gid_p)
00982 {
00983   return _dbus_get_group_id (groupname, gid_p);
00984 }
00985 
00996 dbus_bool_t
00997 _dbus_unix_groups_from_uid (dbus_uid_t            uid,
00998                             dbus_gid_t          **group_ids,
00999                             int                  *n_group_ids)
01000 {
01001   return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
01002 }
01003 
01013 dbus_bool_t
01014 _dbus_unix_user_is_at_console (dbus_uid_t         uid,
01015                                DBusError         *error)
01016 {
01017   return _dbus_is_console_user (uid, error);
01018 
01019 }
01020 
01028 dbus_bool_t
01029 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
01030 {
01031   return uid == _dbus_geteuid ();
01032 }
01033 
01041 dbus_bool_t
01042 _dbus_windows_user_is_process_owner (const char *windows_sid)
01043 {
01044   return FALSE;
01045 }
01046  /* End of DBusInternalsUtils functions */
01048 
01060 dbus_bool_t
01061 _dbus_string_get_dirname  (const DBusString *filename,
01062                            DBusString       *dirname)
01063 {
01064   int sep;
01065   
01066   _dbus_assert (filename != dirname);
01067   _dbus_assert (filename != NULL);
01068   _dbus_assert (dirname != NULL);
01069 
01070   /* Ignore any separators on the end */
01071   sep = _dbus_string_get_length (filename);
01072   if (sep == 0)
01073     return _dbus_string_append (dirname, "."); /* empty string passed in */
01074     
01075   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01076     --sep;
01077 
01078   _dbus_assert (sep >= 0);
01079   
01080   if (sep == 0)
01081     return _dbus_string_append (dirname, "/");
01082   
01083   /* Now find the previous separator */
01084   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
01085   if (sep < 0)
01086     return _dbus_string_append (dirname, ".");
01087   
01088   /* skip multiple separators */
01089   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01090     --sep;
01091 
01092   _dbus_assert (sep >= 0);
01093   
01094   if (sep == 0 &&
01095       _dbus_string_get_byte (filename, 0) == '/')
01096     return _dbus_string_append (dirname, "/");
01097   else
01098     return _dbus_string_copy_len (filename, 0, sep - 0,
01099                                   dirname, _dbus_string_get_length (dirname));
01100 } /* DBusString stuff */
01102 

Generated on Thu Jan 22 16:37:06 2009 for D-Bus by  doxygen 1.5.1