D-Bus  1.10.12
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 #include <unistd.h>
00025 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00026 #include "dbus-userdb.h"
00027 #include "dbus-test.h"
00028 #include "dbus-internals.h"
00029 #include "dbus-protocol.h"
00030 #include <string.h>
00031 
00032 #if HAVE_SYSTEMD
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   /* check if we have logind */
00059   if (access ("/run/systemd/seats/", F_OK) >= 0)
00060     {
00061       int r;
00062 
00063       /* Check whether this user is logged in on at least one physical
00064          seat */
00065       r = sd_uid_get_seats (uid, 0, NULL);
00066       if (r < 0)
00067         {
00068           dbus_set_error (error, _dbus_error_from_errno (-r),
00069                           "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
00070                           uid,
00071                           _dbus_strerror (-r));
00072           return FALSE;
00073         }
00074 
00075       return (r > 0);
00076     }
00077 #endif
00078 
00079 #ifdef HAVE_CONSOLE_OWNER_FILE
00080 
00081   DBusString f;
00082   DBusStat st;
00083 
00084   if (!_dbus_string_init (&f))
00085     {
00086       _DBUS_SET_OOM (error);
00087       return FALSE;
00088     }
00089 
00090   if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
00091     {
00092       _dbus_string_free(&f);
00093       _DBUS_SET_OOM (error);
00094       return FALSE;
00095     }
00096 
00097   if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
00098     {
00099       _dbus_string_free(&f);
00100       return TRUE;
00101     }
00102 
00103   _dbus_string_free(&f);
00104 
00105 #endif /* HAVE_CONSOLE_OWNER_FILE */
00106 
00107   if (!_dbus_user_database_lock_system ())
00108     {
00109       _DBUS_SET_OOM (error);
00110       return FALSE;
00111     }
00112 
00113   db = _dbus_user_database_get_system ();
00114   if (db == NULL)
00115     {
00116       dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
00117       _dbus_user_database_unlock_system ();
00118       return FALSE;
00119     }
00120 
00121   /* TPTD: this should be cache-safe, we've locked the DB and
00122     _dbus_user_at_console doesn't pass it on. */
00123   info = _dbus_user_database_lookup (db, uid, NULL, error);
00124 
00125   if (info == NULL)
00126     {
00127       _dbus_user_database_unlock_system ();
00128        return FALSE;
00129     }
00130 
00131   result = _dbus_user_at_console (info->username, error);
00132 
00133   _dbus_user_database_unlock_system ();
00134 
00135   return result;
00136 }
00137 
00145 dbus_bool_t
00146 _dbus_get_user_id (const DBusString  *username,
00147                    dbus_uid_t        *uid)
00148 {
00149   return _dbus_get_user_id_and_primary_group (username, uid, NULL);
00150 }
00151 
00159 dbus_bool_t
00160 _dbus_get_group_id (const DBusString  *groupname,
00161                     dbus_gid_t        *gid)
00162 {
00163   DBusUserDatabase *db;
00164   const DBusGroupInfo *info;
00165 
00166   /* FIXME: this can't distinguish ENOMEM from other errors */
00167   if (!_dbus_user_database_lock_system ())
00168     return FALSE;
00169 
00170   db = _dbus_user_database_get_system ();
00171   if (db == NULL)
00172     {
00173       _dbus_user_database_unlock_system ();
00174       return FALSE;
00175     }
00176 
00177   if (!_dbus_user_database_get_groupname (db, groupname,
00178                                           &info, NULL))
00179     {
00180       _dbus_user_database_unlock_system ();
00181       return FALSE;
00182     }
00183 
00184   *gid = info->gid;
00185   
00186   _dbus_user_database_unlock_system ();
00187   return TRUE;
00188 }
00189 
00198 dbus_bool_t
00199 _dbus_get_user_id_and_primary_group (const DBusString  *username,
00200                                      dbus_uid_t        *uid_p,
00201                                      dbus_gid_t        *gid_p)
00202 {
00203   DBusUserDatabase *db;
00204   const DBusUserInfo *info;
00205 
00206   /* FIXME: this can't distinguish ENOMEM from other errors */
00207   if (!_dbus_user_database_lock_system ())
00208     return FALSE;
00209 
00210   db = _dbus_user_database_get_system ();
00211   if (db == NULL)
00212     {
00213       _dbus_user_database_unlock_system ();
00214       return FALSE;
00215     }
00216 
00217   if (!_dbus_user_database_get_username (db, username,
00218                                          &info, NULL))
00219     {
00220       _dbus_user_database_unlock_system ();
00221       return FALSE;
00222     }
00223 
00224   if (uid_p)
00225     *uid_p = info->uid;
00226   if (gid_p)
00227     *gid_p = info->primary_gid;
00228   
00229   _dbus_user_database_unlock_system ();
00230   return TRUE;
00231 }
00232 
00245 DBusGroupInfo*
00246 _dbus_user_database_lookup_group (DBusUserDatabase *db,
00247                                   dbus_gid_t        gid,
00248                                   const DBusString *groupname,
00249                                   DBusError        *error)
00250 {
00251   DBusGroupInfo *info;
00252 
00253   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00254 
00255    /* See if the group is really a number */
00256    if (gid == DBUS_UID_UNSET)
00257     {
00258       unsigned long n;
00259 
00260       if (_dbus_is_a_number (groupname, &n))
00261         gid = n;
00262     }
00263 
00264   if (gid != DBUS_GID_UNSET)
00265     info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
00266   else
00267     info = _dbus_hash_table_lookup_string (db->groups_by_name,
00268                                            _dbus_string_get_const_data (groupname));
00269   if (info)
00270     {
00271       _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
00272                      info->gid);
00273       return info;
00274     }
00275   else
00276     {
00277       if (gid != DBUS_GID_UNSET)
00278         _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
00279                        gid);
00280       else
00281         _dbus_verbose ("No cache for groupname \"%s\"\n",
00282                        _dbus_string_get_const_data (groupname));
00283       
00284       info = dbus_new0 (DBusGroupInfo, 1);
00285       if (info == NULL)
00286         {
00287           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00288           return NULL;
00289         }
00290 
00291       if (gid != DBUS_GID_UNSET)
00292         {
00293           if (!_dbus_group_info_fill_gid (info, gid, error))
00294             {
00295               _DBUS_ASSERT_ERROR_IS_SET (error);
00296               _dbus_group_info_free_allocated (info);
00297               return NULL;
00298             }
00299         }
00300       else
00301         {
00302           if (!_dbus_group_info_fill (info, groupname, error))
00303             {
00304               _DBUS_ASSERT_ERROR_IS_SET (error);
00305               _dbus_group_info_free_allocated (info);
00306               return NULL;
00307             }
00308         }
00309 
00310       /* don't use these past here */
00311       gid = DBUS_GID_UNSET;
00312       groupname = NULL;
00313 
00314       if (!_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
00315         {
00316           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00317           _dbus_group_info_free_allocated (info);
00318           return NULL;
00319         }
00320 
00321 
00322       if (!_dbus_hash_table_insert_string (db->groups_by_name,
00323                                            info->groupname,
00324                                            info))
00325         {
00326           _dbus_hash_table_remove_uintptr (db->groups, info->gid);
00327           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00328           return NULL;
00329         }
00330       
00331       return info;
00332     }
00333 }
00334 
00335 
00346 dbus_bool_t
00347 _dbus_user_database_get_groupname (DBusUserDatabase     *db,
00348                                    const DBusString     *groupname,
00349                                    const DBusGroupInfo **info,
00350                                    DBusError            *error)
00351 {
00352   *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
00353   return *info != NULL;
00354 }
00355 
00366 dbus_bool_t
00367 _dbus_user_database_get_gid (DBusUserDatabase     *db,
00368                              dbus_gid_t            gid,
00369                              const DBusGroupInfo **info,
00370                              DBusError            *error)
00371 {
00372   *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
00373   return *info != NULL;
00374 }
00375 
00376 
00387 dbus_bool_t
00388 _dbus_groups_from_uid (dbus_uid_t         uid,
00389                        dbus_gid_t       **group_ids,
00390                        int               *n_group_ids)
00391 {
00392   DBusUserDatabase *db;
00393   const DBusUserInfo *info;
00394   *group_ids = NULL;
00395   *n_group_ids = 0;
00396 
00397   /* FIXME: this can't distinguish ENOMEM from other errors */
00398   if (!_dbus_user_database_lock_system ())
00399     return FALSE;
00400 
00401   db = _dbus_user_database_get_system ();
00402   if (db == NULL)
00403     {
00404       _dbus_user_database_unlock_system ();
00405       return FALSE;
00406     }
00407 
00408   if (!_dbus_user_database_get_uid (db, uid,
00409                                     &info, NULL))
00410     {
00411       _dbus_user_database_unlock_system ();
00412       return FALSE;
00413     }
00414 
00415   _dbus_assert (info->uid == uid);
00416   
00417   if (info->n_group_ids > 0)
00418     {
00419       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
00420       if (*group_ids == NULL)
00421         {
00422           _dbus_user_database_unlock_system ();
00423           return FALSE;
00424         }
00425 
00426       *n_group_ids = info->n_group_ids;
00427 
00428       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
00429     }
00430 
00431   _dbus_user_database_unlock_system ();
00432   return TRUE;
00433 }
00436 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00437 #include <stdio.h>
00438 
00444 dbus_bool_t
00445 _dbus_userdb_test (const char *test_data_dir)
00446 {
00447   const DBusString *username;
00448   const DBusString *homedir;
00449   dbus_uid_t uid;
00450   unsigned long *group_ids;
00451   int n_group_ids, i;
00452   DBusError error;
00453 
00454   if (!_dbus_username_from_current_process (&username))
00455     _dbus_assert_not_reached ("didn't get username");
00456 
00457   if (!_dbus_homedir_from_current_process (&homedir))
00458     _dbus_assert_not_reached ("didn't get homedir");  
00459 
00460   if (!_dbus_get_user_id (username, &uid))
00461     _dbus_assert_not_reached ("didn't get uid");
00462 
00463   if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids))
00464     _dbus_assert_not_reached ("didn't get groups");
00465 
00466   printf ("    Current user: %s homedir: %s gids:",
00467           _dbus_string_get_const_data (username),
00468           _dbus_string_get_const_data (homedir));
00469 
00470   for (i=0; i<n_group_ids; i++)
00471       printf(" %ld", group_ids[i]);
00472 
00473   printf ("\n");
00474 
00475   dbus_error_init (&error);
00476   printf ("Is Console user: %i\n",
00477           _dbus_is_console_user (uid, &error));
00478   printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
00479   dbus_error_free (&error);
00480   printf ("Is Console user 4711: %i\n",
00481           _dbus_is_console_user (4711, &error));
00482   printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
00483   dbus_error_free (&error);
00484 
00485   dbus_free (group_ids);
00486 
00487   return TRUE;
00488 }
00489 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */