D-Bus  1.6.8
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 
00031 #if HAVE_SYSTEMD
00032 #include <systemd/sd-daemon.h>
00033 #include <systemd/sd-login.h>
00034 #endif
00035 
00048 dbus_bool_t
00049 _dbus_is_console_user (dbus_uid_t uid,
00050                        DBusError *error)
00051 {
00052 
00053   DBusUserDatabase *db;
00054   const DBusUserInfo *info;
00055   dbus_bool_t result = FALSE;
00056 
00057 #ifdef HAVE_SYSTEMD
00058   if (sd_booted () > 0)
00059     {
00060       int r;
00061 
00062       /* Check whether this user is logged in on at least one physical
00063          seat */
00064       r = sd_uid_get_seats (uid, 0, NULL);
00065       if (r < 0)
00066         {
00067           dbus_set_error (error, _dbus_error_from_errno (-r),
00068                           "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
00069                           uid,
00070                           _dbus_strerror (-r));
00071           return FALSE;
00072         }
00073 
00074       return (r > 0);
00075     }
00076 #endif
00077 
00078 #ifdef HAVE_CONSOLE_OWNER_FILE
00079 
00080   DBusString f;
00081   DBusStat st;
00082 
00083   if (!_dbus_string_init (&f))
00084     {
00085       _DBUS_SET_OOM (error);
00086       return FALSE;
00087     }
00088 
00089   if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
00090     {
00091       _dbus_string_free(&f);
00092       _DBUS_SET_OOM (error);
00093       return FALSE;
00094     }
00095 
00096   if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
00097     {
00098       _dbus_string_free(&f);
00099       return TRUE;
00100     }
00101 
00102   _dbus_string_free(&f);
00103 
00104 #endif /* HAVE_CONSOLE_OWNER_FILE */
00105 
00106   _dbus_user_database_lock_system ();
00107 
00108   db = _dbus_user_database_get_system ();
00109   if (db == NULL)
00110     {
00111       dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
00112       _dbus_user_database_unlock_system ();
00113       return FALSE;
00114     }
00115 
00116   /* TPTD: this should be cache-safe, we've locked the DB and
00117     _dbus_user_at_console doesn't pass it on. */
00118   info = _dbus_user_database_lookup (db, uid, NULL, error);
00119 
00120   if (info == NULL)
00121     {
00122       _dbus_user_database_unlock_system ();
00123        return FALSE;
00124     }
00125 
00126   result = _dbus_user_at_console (info->username, error);
00127 
00128   _dbus_user_database_unlock_system ();
00129 
00130   return result;
00131 }
00132 
00140 dbus_bool_t
00141 _dbus_get_user_id (const DBusString  *username,
00142                    dbus_uid_t        *uid)
00143 {
00144   return _dbus_get_user_id_and_primary_group (username, uid, NULL);
00145 }
00146 
00154 dbus_bool_t
00155 _dbus_get_group_id (const DBusString  *groupname,
00156                     dbus_gid_t        *gid)
00157 {
00158   DBusUserDatabase *db;
00159   const DBusGroupInfo *info;
00160   _dbus_user_database_lock_system ();
00161 
00162   db = _dbus_user_database_get_system ();
00163   if (db == NULL)
00164     {
00165       _dbus_user_database_unlock_system ();
00166       return FALSE;
00167     }
00168 
00169   if (!_dbus_user_database_get_groupname (db, groupname,
00170                                           &info, NULL))
00171     {
00172       _dbus_user_database_unlock_system ();
00173       return FALSE;
00174     }
00175 
00176   *gid = info->gid;
00177   
00178   _dbus_user_database_unlock_system ();
00179   return TRUE;
00180 }
00181 
00190 dbus_bool_t
00191 _dbus_get_user_id_and_primary_group (const DBusString  *username,
00192                                      dbus_uid_t        *uid_p,
00193                                      dbus_gid_t        *gid_p)
00194 {
00195   DBusUserDatabase *db;
00196   const DBusUserInfo *info;
00197   _dbus_user_database_lock_system ();
00198 
00199   db = _dbus_user_database_get_system ();
00200   if (db == NULL)
00201     {
00202       _dbus_user_database_unlock_system ();
00203       return FALSE;
00204     }
00205 
00206   if (!_dbus_user_database_get_username (db, username,
00207                                          &info, NULL))
00208     {
00209       _dbus_user_database_unlock_system ();
00210       return FALSE;
00211     }
00212 
00213   if (uid_p)
00214     *uid_p = info->uid;
00215   if (gid_p)
00216     *gid_p = info->primary_gid;
00217   
00218   _dbus_user_database_unlock_system ();
00219   return TRUE;
00220 }
00221 
00234 DBusGroupInfo*
00235 _dbus_user_database_lookup_group (DBusUserDatabase *db,
00236                                   dbus_gid_t        gid,
00237                                   const DBusString *groupname,
00238                                   DBusError        *error)
00239 {
00240   DBusGroupInfo *info;
00241 
00242   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00243 
00244    /* See if the group is really a number */
00245    if (gid == DBUS_UID_UNSET)
00246     {
00247       unsigned long n;
00248 
00249       if (_dbus_is_a_number (groupname, &n))
00250         gid = n;
00251     }
00252 
00253 #ifdef DBUS_ENABLE_USERDB_CACHE
00254   if (gid != DBUS_GID_UNSET)
00255     info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
00256   else
00257     info = _dbus_hash_table_lookup_string (db->groups_by_name,
00258                                            _dbus_string_get_const_data (groupname));
00259   if (info)
00260     {
00261       _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
00262                      info->gid);
00263       return info;
00264     }
00265   else
00266 #else
00267   if (1)
00268 #endif
00269     {
00270       if (gid != DBUS_GID_UNSET)
00271         _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
00272                        gid);
00273       else
00274         _dbus_verbose ("No cache for groupname \"%s\"\n",
00275                        _dbus_string_get_const_data (groupname));
00276       
00277       info = dbus_new0 (DBusGroupInfo, 1);
00278       if (info == NULL)
00279         {
00280           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00281           return NULL;
00282         }
00283 
00284       if (gid != DBUS_GID_UNSET)
00285         {
00286           if (!_dbus_group_info_fill_gid (info, gid, error))
00287             {
00288               _DBUS_ASSERT_ERROR_IS_SET (error);
00289               _dbus_group_info_free_allocated (info);
00290               return NULL;
00291             }
00292         }
00293       else
00294         {
00295           if (!_dbus_group_info_fill (info, groupname, error))
00296             {
00297               _DBUS_ASSERT_ERROR_IS_SET (error);
00298               _dbus_group_info_free_allocated (info);
00299               return NULL;
00300             }
00301         }
00302 
00303       /* don't use these past here */
00304       gid = DBUS_GID_UNSET;
00305       groupname = NULL;
00306 
00307       if (!_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
00308         {
00309           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00310           _dbus_group_info_free_allocated (info);
00311           return NULL;
00312         }
00313 
00314 
00315       if (!_dbus_hash_table_insert_string (db->groups_by_name,
00316                                            info->groupname,
00317                                            info))
00318         {
00319           _dbus_hash_table_remove_uintptr (db->groups, info->gid);
00320           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00321           return NULL;
00322         }
00323       
00324       return info;
00325     }
00326 }
00327 
00328 
00339 dbus_bool_t
00340 _dbus_user_database_get_groupname (DBusUserDatabase     *db,
00341                                    const DBusString     *groupname,
00342                                    const DBusGroupInfo **info,
00343                                    DBusError            *error)
00344 {
00345   *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
00346   return *info != NULL;
00347 }
00348 
00359 dbus_bool_t
00360 _dbus_user_database_get_gid (DBusUserDatabase     *db,
00361                              dbus_gid_t            gid,
00362                              const DBusGroupInfo **info,
00363                              DBusError            *error)
00364 {
00365   *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
00366   return *info != NULL;
00367 }
00368 
00369 
00380 dbus_bool_t
00381 _dbus_groups_from_uid (dbus_uid_t         uid,
00382                        dbus_gid_t       **group_ids,
00383                        int               *n_group_ids)
00384 {
00385   DBusUserDatabase *db;
00386   const DBusUserInfo *info;
00387   *group_ids = NULL;
00388   *n_group_ids = 0;
00389 
00390   _dbus_user_database_lock_system ();
00391 
00392   db = _dbus_user_database_get_system ();
00393   if (db == NULL)
00394     {
00395       _dbus_user_database_unlock_system ();
00396       return FALSE;
00397     }
00398 
00399   if (!_dbus_user_database_get_uid (db, uid,
00400                                     &info, NULL))
00401     {
00402       _dbus_user_database_unlock_system ();
00403       return FALSE;
00404     }
00405 
00406   _dbus_assert (info->uid == uid);
00407   
00408   if (info->n_group_ids > 0)
00409     {
00410       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
00411       if (*group_ids == NULL)
00412         {
00413           _dbus_user_database_unlock_system ();
00414           return FALSE;
00415         }
00416 
00417       *n_group_ids = info->n_group_ids;
00418 
00419       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
00420     }
00421 
00422   _dbus_user_database_unlock_system ();
00423   return TRUE;
00424 }
00427 #ifdef DBUS_BUILD_TESTS
00428 #include <stdio.h>
00429 
00435 dbus_bool_t
00436 _dbus_userdb_test (const char *test_data_dir)
00437 {
00438   const DBusString *username;
00439   const DBusString *homedir;
00440   dbus_uid_t uid;
00441   unsigned long *group_ids;
00442   int n_group_ids, i;
00443   DBusError error;
00444 
00445   if (!_dbus_username_from_current_process (&username))
00446     _dbus_assert_not_reached ("didn't get username");
00447 
00448   if (!_dbus_homedir_from_current_process (&homedir))
00449     _dbus_assert_not_reached ("didn't get homedir");  
00450 
00451   if (!_dbus_get_user_id (username, &uid))
00452     _dbus_assert_not_reached ("didn't get uid");
00453 
00454   if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids))
00455     _dbus_assert_not_reached ("didn't get groups");
00456 
00457   printf ("    Current user: %s homedir: %s gids:",
00458           _dbus_string_get_const_data (username),
00459           _dbus_string_get_const_data (homedir));
00460 
00461   for (i=0; i<n_group_ids; i++)
00462       printf(" %ld", group_ids[i]);
00463 
00464   printf ("\n");
00465 
00466   dbus_error_init (&error);
00467   printf ("Is Console user: %i\n",
00468           _dbus_is_console_user (uid, &error));
00469   printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
00470   dbus_error_free (&error);
00471   printf ("Is Console user 4711: %i\n",
00472           _dbus_is_console_user (4711, &error));
00473   printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
00474   dbus_error_free (&error);
00475 
00476   dbus_free (group_ids);
00477 
00478   return TRUE;
00479 }
00480 #endif /* DBUS_BUILD_TESTS */