D-Bus  1.4.10
dbus-userdb-util.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-userdb-util.c Would be in dbus-userdb.c, but not used in libdbus
00003  * 
00004  * Copyright (C) 2003, 2004, 2005  Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */
00023 #include <config.h>
00024 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00025 #include "dbus-userdb.h"
00026 #include "dbus-test.h"
00027 #include "dbus-internals.h"
00028 #include "dbus-protocol.h"
00029 #include <string.h>
00030 
00043 dbus_bool_t
00044 _dbus_is_console_user (dbus_uid_t uid,
00045                        DBusError *error)
00046 {
00047 
00048   DBusUserDatabase *db;
00049   const DBusUserInfo *info;
00050   dbus_bool_t result = FALSE; 
00051 
00052 #ifdef HAVE_CONSOLE_OWNER_FILE
00053 
00054   DBusString f;
00055   DBusStat st;
00056 
00057   if (!_dbus_string_init (&f))
00058     {
00059       _DBUS_SET_OOM (error);
00060       return FALSE;
00061     }
00062 
00063   if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
00064     {
00065       _dbus_string_free(&f);
00066       _DBUS_SET_OOM (error);
00067       return FALSE;
00068     }
00069 
00070   if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
00071     {
00072       _dbus_string_free(&f);
00073       return TRUE;
00074     }
00075 
00076   _dbus_string_free(&f);
00077 
00078 #endif /* HAVE_CONSOLE_OWNER_FILE */
00079 
00080   _dbus_user_database_lock_system ();
00081 
00082   db = _dbus_user_database_get_system ();
00083   if (db == NULL)
00084     {
00085       dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
00086       _dbus_user_database_unlock_system ();
00087       return FALSE;
00088     }
00089 
00090   /* TPTD: this should be cache-safe, we've locked the DB and
00091     _dbus_user_at_console doesn't pass it on. */
00092   info = _dbus_user_database_lookup (db, uid, NULL, error);
00093 
00094   if (info == NULL)
00095     {
00096       _dbus_user_database_unlock_system ();
00097        return FALSE;
00098     }
00099 
00100   result = _dbus_user_at_console (info->username, error);
00101 
00102   _dbus_user_database_unlock_system ();
00103 
00104   return result;
00105 }
00106 
00114 dbus_bool_t
00115 _dbus_get_user_id (const DBusString  *username,
00116                    dbus_uid_t        *uid)
00117 {
00118   return _dbus_get_user_id_and_primary_group (username, uid, NULL);
00119 }
00120 
00128 dbus_bool_t
00129 _dbus_get_group_id (const DBusString  *groupname,
00130                     dbus_gid_t        *gid)
00131 {
00132   DBusUserDatabase *db;
00133   const DBusGroupInfo *info;
00134   _dbus_user_database_lock_system ();
00135 
00136   db = _dbus_user_database_get_system ();
00137   if (db == NULL)
00138     {
00139       _dbus_user_database_unlock_system ();
00140       return FALSE;
00141     }
00142 
00143   if (!_dbus_user_database_get_groupname (db, groupname,
00144                                           &info, NULL))
00145     {
00146       _dbus_user_database_unlock_system ();
00147       return FALSE;
00148     }
00149 
00150   *gid = info->gid;
00151   
00152   _dbus_user_database_unlock_system ();
00153   return TRUE;
00154 }
00155 
00164 dbus_bool_t
00165 _dbus_get_user_id_and_primary_group (const DBusString  *username,
00166                                      dbus_uid_t        *uid_p,
00167                                      dbus_gid_t        *gid_p)
00168 {
00169   DBusUserDatabase *db;
00170   const DBusUserInfo *info;
00171   _dbus_user_database_lock_system ();
00172 
00173   db = _dbus_user_database_get_system ();
00174   if (db == NULL)
00175     {
00176       _dbus_user_database_unlock_system ();
00177       return FALSE;
00178     }
00179 
00180   if (!_dbus_user_database_get_username (db, username,
00181                                          &info, NULL))
00182     {
00183       _dbus_user_database_unlock_system ();
00184       return FALSE;
00185     }
00186 
00187   if (uid_p)
00188     *uid_p = info->uid;
00189   if (gid_p)
00190     *gid_p = info->primary_gid;
00191   
00192   _dbus_user_database_unlock_system ();
00193   return TRUE;
00194 }
00195 
00208 DBusGroupInfo*
00209 _dbus_user_database_lookup_group (DBusUserDatabase *db,
00210                                   dbus_gid_t        gid,
00211                                   const DBusString *groupname,
00212                                   DBusError        *error)
00213 {
00214   DBusGroupInfo *info;
00215 
00216   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00217 
00218    /* See if the group is really a number */
00219    if (gid == DBUS_UID_UNSET)
00220     {
00221       unsigned long n;
00222 
00223       if (_dbus_is_a_number (groupname, &n))
00224         gid = n;
00225     }
00226 
00227 #ifdef DBUS_ENABLE_USERDB_CACHE
00228   if (gid != DBUS_GID_UNSET)
00229     info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
00230   else
00231     info = _dbus_hash_table_lookup_string (db->groups_by_name,
00232                                            _dbus_string_get_const_data (groupname));
00233   if (info)
00234     {
00235       _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
00236                      info->gid);
00237       return info;
00238     }
00239   else
00240 #else
00241   if (1)
00242 #endif
00243     {
00244       if (gid != DBUS_GID_UNSET)
00245         _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
00246                        gid);
00247       else
00248         _dbus_verbose ("No cache for groupname \"%s\"\n",
00249                        _dbus_string_get_const_data (groupname));
00250       
00251       info = dbus_new0 (DBusGroupInfo, 1);
00252       if (info == NULL)
00253         {
00254           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00255           return NULL;
00256         }
00257 
00258       if (gid != DBUS_GID_UNSET)
00259         {
00260           if (!_dbus_group_info_fill_gid (info, gid, error))
00261             {
00262               _DBUS_ASSERT_ERROR_IS_SET (error);
00263               _dbus_group_info_free_allocated (info);
00264               return NULL;
00265             }
00266         }
00267       else
00268         {
00269           if (!_dbus_group_info_fill (info, groupname, error))
00270             {
00271               _DBUS_ASSERT_ERROR_IS_SET (error);
00272               _dbus_group_info_free_allocated (info);
00273               return NULL;
00274             }
00275         }
00276 
00277       /* don't use these past here */
00278       gid = DBUS_GID_UNSET;
00279       groupname = NULL;
00280 
00281       if (!_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
00282         {
00283           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00284           _dbus_group_info_free_allocated (info);
00285           return NULL;
00286         }
00287 
00288 
00289       if (!_dbus_hash_table_insert_string (db->groups_by_name,
00290                                            info->groupname,
00291                                            info))
00292         {
00293           _dbus_hash_table_remove_uintptr (db->groups, info->gid);
00294           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00295           return NULL;
00296         }
00297       
00298       return info;
00299     }
00300 }
00301 
00302 
00313 dbus_bool_t
00314 _dbus_user_database_get_groupname (DBusUserDatabase     *db,
00315                                    const DBusString     *groupname,
00316                                    const DBusGroupInfo **info,
00317                                    DBusError            *error)
00318 {
00319   *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
00320   return *info != NULL;
00321 }
00322 
00333 dbus_bool_t
00334 _dbus_user_database_get_gid (DBusUserDatabase     *db,
00335                              dbus_gid_t            gid,
00336                              const DBusGroupInfo **info,
00337                              DBusError            *error)
00338 {
00339   *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
00340   return *info != NULL;
00341 }
00342 
00343 
00354 dbus_bool_t
00355 _dbus_groups_from_uid (dbus_uid_t         uid,
00356                        dbus_gid_t       **group_ids,
00357                        int               *n_group_ids)
00358 {
00359   DBusUserDatabase *db;
00360   const DBusUserInfo *info;
00361   *group_ids = NULL;
00362   *n_group_ids = 0;
00363 
00364   _dbus_user_database_lock_system ();
00365 
00366   db = _dbus_user_database_get_system ();
00367   if (db == NULL)
00368     {
00369       _dbus_user_database_unlock_system ();
00370       return FALSE;
00371     }
00372 
00373   if (!_dbus_user_database_get_uid (db, uid,
00374                                     &info, NULL))
00375     {
00376       _dbus_user_database_unlock_system ();
00377       return FALSE;
00378     }
00379 
00380   _dbus_assert (info->uid == uid);
00381   
00382   if (info->n_group_ids > 0)
00383     {
00384       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
00385       if (*group_ids == NULL)
00386         {
00387           _dbus_user_database_unlock_system ();
00388           return FALSE;
00389         }
00390 
00391       *n_group_ids = info->n_group_ids;
00392 
00393       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
00394     }
00395 
00396   _dbus_user_database_unlock_system ();
00397   return TRUE;
00398 }
00401 #ifdef DBUS_BUILD_TESTS
00402 #include <stdio.h>
00403 
00409 dbus_bool_t
00410 _dbus_userdb_test (const char *test_data_dir)
00411 {
00412   const DBusString *username;
00413   const DBusString *homedir;
00414   dbus_uid_t uid;
00415   unsigned long *group_ids;
00416   int n_group_ids, i;
00417 
00418   if (!_dbus_username_from_current_process (&username))
00419     _dbus_assert_not_reached ("didn't get username");
00420 
00421   if (!_dbus_homedir_from_current_process (&homedir))
00422     _dbus_assert_not_reached ("didn't get homedir");  
00423 
00424   if (!_dbus_get_user_id (username, &uid))
00425     _dbus_assert_not_reached ("didn't get uid");
00426 
00427   if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids))
00428     _dbus_assert_not_reached ("didn't get groups");
00429 
00430   printf ("    Current user: %s homedir: %s gids:",
00431           _dbus_string_get_const_data (username),
00432           _dbus_string_get_const_data (homedir));
00433 
00434   for (i=0; i<n_group_ids; i++)
00435       printf(" %ld", group_ids[i]);
00436 
00437   printf ("\n");
00438  
00439   dbus_free (group_ids);
00440 
00441   return TRUE;
00442 }
00443 #endif /* DBUS_BUILD_TESTS */