Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu" -*- */
      2 /* dbus-userdb-util.c Would be in dbus-userdb.c, but not used in libdbus
      3  *
      4  * Copyright (C) 2003, 2004, 2005  Red Hat, Inc.
      5  *
      6  * Licensed under the Academic Free License version 2.1
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License as published by
     10  * the Free Software Foundation; either version 2 of the License, or
     11  * (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     21  *
     22  */
     23 #define DBUS_USERDB_INCLUDES_PRIVATE 1
     24 #include "dbus-userdb.h"
     25 #include "dbus-test.h"
     26 #include "dbus-internals.h"
     27 #include "dbus-protocol.h"
     28 #include <string.h>
     29 
     30 /**
     31  * @addtogroup DBusInternalsUtils
     32  * @{
     33  */
     34 
     35 /**
     36  * Checks to see if the UID sent in is the console user
     37  *
     38  * @param uid UID of person to check
     39  * @param error return location for errors
     40  * @returns #TRUE if the UID is the same as the console user and there are no errors
     41  */
     42 dbus_bool_t
     43 _dbus_is_console_user (dbus_uid_t uid,
     44 		       DBusError *error)
     45 {
     46 
     47   DBusUserDatabase *db;
     48   const DBusUserInfo *info;
     49   dbus_bool_t result = FALSE;
     50 
     51 #ifdef HAVE_CONSOLE_OWNER_FILE
     52 
     53   DBusString f;
     54   DBusStat st;
     55 
     56   if (!_dbus_string_init (&f))
     57     {
     58       _DBUS_SET_OOM (error);
     59       return FALSE;
     60     }
     61 
     62   if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
     63     {
     64       _dbus_string_free(&f);
     65       _DBUS_SET_OOM (error);
     66       return FALSE;
     67     }
     68 
     69   if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
     70     {
     71       _dbus_string_free(&f);
     72       return TRUE;
     73     }
     74 
     75   _dbus_string_free(&f);
     76 
     77 #endif /* HAVE_CONSOLE_OWNER_FILE */
     78 
     79   _dbus_user_database_lock_system ();
     80 
     81   db = _dbus_user_database_get_system ();
     82   if (db == NULL)
     83     {
     84       dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
     85       _dbus_user_database_unlock_system ();
     86       return FALSE;
     87     }
     88 
     89   info = _dbus_user_database_lookup (db, uid, NULL, error);
     90 
     91   if (info == NULL)
     92     {
     93       _dbus_user_database_unlock_system ();
     94        return FALSE;
     95     }
     96 
     97   result = _dbus_user_at_console (info->username, error);
     98 
     99   _dbus_user_database_unlock_system ();
    100 
    101   return result;
    102 }
    103 
    104 
    105 /**
    106  * Gets the credentials corresponding to the given UID.
    107  *
    108  * @param uid the UID
    109  * @param credentials credentials to fill in
    110  * @returns #TRUE if the UID existed and we got some credentials
    111  */
    112 dbus_bool_t
    113 _dbus_credentials_from_uid (dbus_uid_t        uid,
    114                             DBusCredentials  *credentials)
    115 {
    116   DBusUserDatabase *db;
    117   const DBusUserInfo *info;
    118   _dbus_user_database_lock_system ();
    119 
    120   db = _dbus_user_database_get_system ();
    121   if (db == NULL)
    122     {
    123       _dbus_user_database_unlock_system ();
    124       return FALSE;
    125     }
    126 
    127   if (!_dbus_user_database_get_uid (db, uid,
    128                                     &info, NULL))
    129     {
    130       _dbus_user_database_unlock_system ();
    131       return FALSE;
    132     }
    133 
    134   _dbus_assert (info->uid == uid);
    135 
    136   credentials->pid = DBUS_PID_UNSET;
    137   credentials->uid = info->uid;
    138   credentials->gid = info->primary_gid;
    139 
    140   _dbus_user_database_unlock_system ();
    141   return TRUE;
    142 }
    143 
    144 
    145 /**
    146  * Gets user ID given username
    147  *
    148  * @param username the username
    149  * @param uid return location for UID
    150  * @returns #TRUE if username existed and we got the UID
    151  */
    152 dbus_bool_t
    153 _dbus_get_user_id (const DBusString  *username,
    154                    dbus_uid_t        *uid)
    155 {
    156   DBusCredentials creds;
    157 
    158   if (!_dbus_credentials_from_username (username, &creds))
    159     return FALSE;
    160 
    161   if (creds.uid == DBUS_UID_UNSET)
    162     return FALSE;
    163 
    164   *uid = creds.uid;
    165 
    166   return TRUE;
    167 }
    168 
    169 /**
    170  * Gets group ID given groupname
    171  *
    172  * @param groupname the groupname
    173  * @param gid return location for GID
    174  * @returns #TRUE if group name existed and we got the GID
    175  */
    176 dbus_bool_t
    177 _dbus_get_group_id (const DBusString  *groupname,
    178                     dbus_gid_t        *gid)
    179 {
    180   DBusUserDatabase *db;
    181   const DBusGroupInfo *info;
    182   _dbus_user_database_lock_system ();
    183 
    184   db = _dbus_user_database_get_system ();
    185   if (db == NULL)
    186     {
    187       _dbus_user_database_unlock_system ();
    188       return FALSE;
    189     }
    190 
    191   if (!_dbus_user_database_get_groupname (db, groupname,
    192                                           &info, NULL))
    193     {
    194       _dbus_user_database_unlock_system ();
    195       return FALSE;
    196     }
    197 
    198   *gid = info->gid;
    199 
    200   _dbus_user_database_unlock_system ();
    201   return TRUE;
    202 }
    203 
    204 /**
    205  * Looks up a gid or group name in the user database.  Only one of
    206  * name or GID can be provided. There are wrapper functions for this
    207  * that are better to use, this one does no locking or anything on the
    208  * database and otherwise sort of sucks.
    209  *
    210  * @param db the database
    211  * @param gid the group ID or #DBUS_GID_UNSET
    212  * @param groupname group name or #NULL
    213  * @param error error to fill in
    214  * @returns the entry in the database
    215  */
    216 DBusGroupInfo*
    217 _dbus_user_database_lookup_group (DBusUserDatabase *db,
    218                                   dbus_gid_t        gid,
    219                                   const DBusString *groupname,
    220                                   DBusError        *error)
    221 {
    222   DBusGroupInfo *info;
    223 
    224   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    225 
    226    /* See if the group is really a number */
    227    if (gid == DBUS_UID_UNSET)
    228     {
    229       unsigned long n;
    230 
    231       if (_dbus_is_a_number (groupname, &n))
    232         gid = n;
    233     }
    234 
    235 
    236   if (gid != DBUS_GID_UNSET)
    237     info = _dbus_hash_table_lookup_ulong (db->groups, gid);
    238   else
    239     info = _dbus_hash_table_lookup_string (db->groups_by_name,
    240                                            _dbus_string_get_const_data (groupname));
    241   if (info)
    242     {
    243       _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
    244                      info->gid);
    245       return info;
    246     }
    247   else
    248     {
    249       if (gid != DBUS_GID_UNSET)
    250 	_dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
    251 		       gid);
    252       else
    253 	_dbus_verbose ("No cache for groupname \"%s\"\n",
    254 		       _dbus_string_get_const_data (groupname));
    255 
    256       info = dbus_new0 (DBusGroupInfo, 1);
    257       if (info == NULL)
    258         {
    259           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    260           return NULL;
    261         }
    262 
    263       if (gid != DBUS_GID_UNSET)
    264         {
    265           if (!_dbus_group_info_fill_gid (info, gid, error))
    266             {
    267               _DBUS_ASSERT_ERROR_IS_SET (error);
    268               _dbus_group_info_free_allocated (info);
    269               return NULL;
    270             }
    271         }
    272       else
    273         {
    274           if (!_dbus_group_info_fill (info, groupname, error))
    275             {
    276               _DBUS_ASSERT_ERROR_IS_SET (error);
    277               _dbus_group_info_free_allocated (info);
    278               return NULL;
    279             }
    280         }
    281 
    282       /* don't use these past here */
    283       gid = DBUS_GID_UNSET;
    284       groupname = NULL;
    285 
    286       if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))
    287         {
    288           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    289           _dbus_group_info_free_allocated (info);
    290           return NULL;
    291         }
    292 
    293 
    294       if (!_dbus_hash_table_insert_string (db->groups_by_name,
    295                                            info->groupname,
    296                                            info))
    297         {
    298           _dbus_hash_table_remove_ulong (db->groups, info->gid);
    299           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    300           return NULL;
    301         }
    302 
    303       return info;
    304     }
    305 }
    306 
    307 
    308 /**
    309  * Gets the user information for the given group name,
    310  * returned group info should not be freed.
    311  *
    312  * @param db user database
    313  * @param groupname the group name
    314  * @param info return location for const ref to group info
    315  * @param error error location
    316  * @returns #FALSE if error is set
    317  */
    318 dbus_bool_t
    319 _dbus_user_database_get_groupname (DBusUserDatabase     *db,
    320                                    const DBusString     *groupname,
    321                                    const DBusGroupInfo **info,
    322                                    DBusError            *error)
    323 {
    324   *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
    325   return *info != NULL;
    326 }
    327 
    328 /**
    329  * Gets the user information for the given GID,
    330  * returned group info should not be freed.
    331  *
    332  * @param db user database
    333  * @param gid the group ID
    334  * @param info return location for const ref to group info
    335  * @param error error location
    336  * @returns #FALSE if error is set
    337  */
    338 dbus_bool_t
    339 _dbus_user_database_get_gid (DBusUserDatabase     *db,
    340                              dbus_gid_t            gid,
    341                              const DBusGroupInfo **info,
    342                              DBusError            *error)
    343 {
    344   *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
    345   return *info != NULL;
    346 }
    347 
    348 
    349 /**
    350  * Gets all groups for a particular user. Returns #FALSE
    351  * if no memory, or user isn't known, but always initializes
    352  * group_ids to a NULL array. Sets error to the reason
    353  * for returning #FALSE.
    354  *
    355  * @param db the user database object
    356  * @param uid the user ID
    357  * @param group_ids return location for array of group IDs
    358  * @param n_group_ids return location for length of returned array
    359  * @param error return location for error
    360  * @returns #TRUE on success
    361  */
    362 dbus_bool_t
    363 _dbus_user_database_get_groups (DBusUserDatabase  *db,
    364                                 dbus_uid_t         uid,
    365                                 dbus_gid_t       **group_ids,
    366                                 int               *n_group_ids,
    367                                 DBusError         *error)
    368 {
    369   DBusUserInfo *info;
    370 
    371   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    372 
    373   *group_ids = NULL;
    374   *n_group_ids = 0;
    375 
    376   info = _dbus_user_database_lookup (db, uid, NULL, error);
    377   if (info == NULL)
    378     {
    379       _DBUS_ASSERT_ERROR_IS_SET (error);
    380       return FALSE;
    381     }
    382 
    383   if (info->n_group_ids > 0)
    384     {
    385       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
    386       if (*group_ids == NULL)
    387         {
    388           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    389           return FALSE;
    390         }
    391 
    392       *n_group_ids = info->n_group_ids;
    393 
    394       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
    395     }
    396 
    397   return TRUE;
    398 }
    399 
    400 /** @} */
    401 
    402 #ifdef DBUS_BUILD_TESTS
    403 #include <stdio.h>
    404 
    405 /**
    406  * Unit test for dbus-userdb.c.
    407  *
    408  * @returns #TRUE on success.
    409  */
    410 dbus_bool_t
    411 _dbus_userdb_test (const char *test_data_dir)
    412 {
    413   const DBusString *username;
    414   const DBusString *homedir;
    415 
    416   if (!_dbus_username_from_current_process (&username))
    417     _dbus_assert_not_reached ("didn't get username");
    418 
    419   if (!_dbus_homedir_from_current_process (&homedir))
    420     _dbus_assert_not_reached ("didn't get homedir");
    421 
    422   printf ("    Current user: %s homedir: %s\n",
    423           _dbus_string_get_const_data (username),
    424           _dbus_string_get_const_data (homedir));
    425 
    426   return TRUE;
    427 }
    428 #endif /* DBUS_BUILD_TESTS */
    429