"Fossies" - the Fresh Open Source Software Archive

Member "dbus-1.13.18/dbus/dbus-userdb-util.c" (1 Jul 2020, 11108 Bytes) of package /linux/misc/dbus-1.13.18.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dbus-userdb-util.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.13.16_vs_1.13.18.

    1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
   21  *
   22  */
   23 #include <config.h>
   24 #include <unistd.h>
   25 #define DBUS_USERDB_INCLUDES_PRIVATE 1
   26 #include "dbus-userdb.h"
   27 #include "dbus-test.h"
   28 #include "dbus-internals.h"
   29 #include "dbus-protocol.h"
   30 #include <dbus/dbus-test-tap.h>
   31 #include <string.h>
   32 
   33 /* It isn't obvious from its name, but this file is part of the Unix
   34  * system-dependent part of libdbus. */
   35 #if defined(DBUS_WIN) || !defined(DBUS_UNIX)
   36 #error "This file only makes sense on Unix OSs"
   37 #endif
   38 
   39 #ifdef HAVE_SYSTEMD
   40 #include <systemd/sd-login.h>
   41 #endif
   42 
   43 /**
   44  * @addtogroup DBusInternalsUtils
   45  * @{
   46  */
   47 
   48 static DBusGroupInfo *
   49 _dbus_group_info_ref (DBusGroupInfo *info)
   50 {
   51   _dbus_assert (info->refcount > 0);
   52   _dbus_assert (info->refcount < SIZE_MAX);
   53   info->refcount++;
   54   return info;
   55 }
   56 
   57 /**
   58  * Checks to see if the UID sent in is the console user
   59  *
   60  * @param uid UID of person to check 
   61  * @param error return location for errors
   62  * @returns #TRUE if the UID is the same as the console user and there are no errors
   63  */
   64 dbus_bool_t
   65 _dbus_is_console_user (dbus_uid_t uid,
   66                DBusError *error)
   67 {
   68 
   69   DBusUserDatabase *db;
   70   const DBusUserInfo *info;
   71   dbus_bool_t result = FALSE;
   72 
   73 #ifdef HAVE_SYSTEMD
   74   /* check if we have logind */
   75   if (access ("/run/systemd/seats/", F_OK) >= 0)
   76     {
   77       int r;
   78 
   79       /* Check whether this user is logged in on at least one physical
   80          seat */
   81       r = sd_uid_get_seats (uid, 0, NULL);
   82       if (r < 0)
   83         {
   84           dbus_set_error (error, _dbus_error_from_errno (-r),
   85                           "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
   86                           uid,
   87                           _dbus_strerror (-r));
   88           return FALSE;
   89         }
   90 
   91       return (r > 0);
   92     }
   93 #endif
   94 
   95 #ifdef HAVE_CONSOLE_OWNER_FILE
   96 
   97   DBusString f;
   98   DBusStat st;
   99 
  100   if (!_dbus_string_init (&f))
  101     {
  102       _DBUS_SET_OOM (error);
  103       return FALSE;
  104     }
  105 
  106   if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
  107     {
  108       _dbus_string_free(&f);
  109       _DBUS_SET_OOM (error);
  110       return FALSE;
  111     }
  112 
  113   if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
  114     {
  115       _dbus_string_free(&f);
  116       return TRUE;
  117     }
  118 
  119   _dbus_string_free(&f);
  120 
  121 #endif /* HAVE_CONSOLE_OWNER_FILE */
  122 
  123   if (!_dbus_user_database_lock_system ())
  124     {
  125       _DBUS_SET_OOM (error);
  126       return FALSE;
  127     }
  128 
  129   db = _dbus_user_database_get_system ();
  130   if (db == NULL)
  131     {
  132       dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
  133       _dbus_user_database_unlock_system ();
  134       return FALSE;
  135     }
  136 
  137   /* TPTD: this should be cache-safe, we've locked the DB and
  138     _dbus_user_at_console doesn't pass it on. */
  139   info = _dbus_user_database_lookup (db, uid, NULL, error);
  140 
  141   if (info == NULL)
  142     {
  143       _dbus_user_database_unlock_system ();
  144        return FALSE;
  145     }
  146 
  147   result = _dbus_user_at_console (info->username, error);
  148 
  149   _dbus_user_database_unlock_system ();
  150 
  151   return result;
  152 }
  153 
  154 /**
  155  * Gets user ID given username
  156  *
  157  * @param username the username
  158  * @param uid return location for UID
  159  * @returns #TRUE if username existed and we got the UID
  160  */
  161 dbus_bool_t
  162 _dbus_get_user_id (const DBusString  *username,
  163                    dbus_uid_t        *uid)
  164 {
  165   return _dbus_get_user_id_and_primary_group (username, uid, NULL);
  166 }
  167 
  168 /**
  169  * Gets group ID given groupname
  170  *
  171  * @param groupname the groupname
  172  * @param gid return location for GID
  173  * @returns #TRUE if group name existed and we got the GID
  174  */
  175 dbus_bool_t
  176 _dbus_get_group_id (const DBusString  *groupname,
  177                     dbus_gid_t        *gid)
  178 {
  179   DBusUserDatabase *db;
  180   const DBusGroupInfo *info;
  181 
  182   /* FIXME: this can't distinguish ENOMEM from other errors */
  183   if (!_dbus_user_database_lock_system ())
  184     return FALSE;
  185 
  186   db = _dbus_user_database_get_system ();
  187   if (db == NULL)
  188     {
  189       _dbus_user_database_unlock_system ();
  190       return FALSE;
  191     }
  192 
  193   info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname,
  194                                            NULL);
  195 
  196   if (info == NULL)
  197     {
  198       _dbus_user_database_unlock_system ();
  199       return FALSE;
  200     }
  201 
  202   *gid = info->gid;
  203   
  204   _dbus_user_database_unlock_system ();
  205   return TRUE;
  206 }
  207 
  208 /**
  209  * Gets user ID and primary group given username
  210  *
  211  * @param username the username
  212  * @param uid_p return location for UID
  213  * @param gid_p return location for GID
  214  * @returns #TRUE if username existed and we got the UID and GID
  215  */
  216 dbus_bool_t
  217 _dbus_get_user_id_and_primary_group (const DBusString  *username,
  218                                      dbus_uid_t        *uid_p,
  219                                      dbus_gid_t        *gid_p)
  220 {
  221   DBusUserDatabase *db;
  222   const DBusUserInfo *info;
  223 
  224   /* FIXME: this can't distinguish ENOMEM from other errors */
  225   if (!_dbus_user_database_lock_system ())
  226     return FALSE;
  227 
  228   db = _dbus_user_database_get_system ();
  229   if (db == NULL)
  230     {
  231       _dbus_user_database_unlock_system ();
  232       return FALSE;
  233     }
  234 
  235   if (!_dbus_user_database_get_username (db, username,
  236                                          &info, NULL))
  237     {
  238       _dbus_user_database_unlock_system ();
  239       return FALSE;
  240     }
  241 
  242   if (uid_p)
  243     *uid_p = info->uid;
  244   if (gid_p)
  245     *gid_p = info->primary_gid;
  246   
  247   _dbus_user_database_unlock_system ();
  248   return TRUE;
  249 }
  250 
  251 /**
  252  * Looks up a gid or group name in the user database.  Only one of
  253  * name or GID can be provided. There are wrapper functions for this
  254  * that are better to use, this one does no locking or anything on the
  255  * database and otherwise sort of sucks.
  256  *
  257  * @param db the database
  258  * @param gid the group ID or #DBUS_GID_UNSET
  259  * @param groupname group name or #NULL 
  260  * @param error error to fill in
  261  * @returns the entry in the database (borrowed, do not free)
  262  */
  263 const DBusGroupInfo *
  264 _dbus_user_database_lookup_group (DBusUserDatabase *db,
  265                                   dbus_gid_t        gid,
  266                                   const DBusString *groupname,
  267                                   DBusError        *error)
  268 {
  269   DBusGroupInfo *info;
  270 
  271   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  272 
  273    /* See if the group is really a number */
  274    if (gid == DBUS_UID_UNSET)
  275     {
  276       unsigned long n;
  277 
  278       if (_dbus_is_a_number (groupname, &n))
  279         gid = n;
  280     }
  281 
  282   if (gid != DBUS_GID_UNSET)
  283     info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
  284   else
  285     info = _dbus_hash_table_lookup_string (db->groups_by_name,
  286                                            _dbus_string_get_const_data (groupname));
  287   if (info)
  288     {
  289       _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
  290                      info->gid);
  291       return info;
  292     }
  293   else
  294     {
  295       if (gid != DBUS_GID_UNSET)
  296     _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
  297                gid);
  298       else
  299     _dbus_verbose ("No cache for groupname \"%s\"\n",
  300                _dbus_string_get_const_data (groupname));
  301       
  302       info = dbus_new0 (DBusGroupInfo, 1);
  303       if (info == NULL)
  304         {
  305           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  306           return NULL;
  307         }
  308       info->refcount = 1;
  309 
  310       if (gid != DBUS_GID_UNSET)
  311         {
  312           if (!_dbus_group_info_fill_gid (info, gid, error))
  313             {
  314               _DBUS_ASSERT_ERROR_IS_SET (error);
  315               _dbus_group_info_unref (info);
  316               return NULL;
  317             }
  318         }
  319       else
  320         {
  321           if (!_dbus_group_info_fill (info, groupname, error))
  322             {
  323               _DBUS_ASSERT_ERROR_IS_SET (error);
  324               _dbus_group_info_unref (info);
  325               return NULL;
  326             }
  327         }
  328 
  329       /* don't use these past here */
  330       gid = DBUS_GID_UNSET;
  331       groupname = NULL;
  332 
  333       if (_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
  334         {
  335           _dbus_group_info_ref (info);
  336         }
  337       else
  338         {
  339           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  340           _dbus_group_info_unref (info);
  341           return NULL;
  342         }
  343 
  344 
  345       if (_dbus_hash_table_insert_string (db->groups_by_name,
  346                                           info->groupname,
  347                                           info))
  348         {
  349           _dbus_group_info_ref (info);
  350         }
  351       else
  352         {
  353           _dbus_hash_table_remove_uintptr (db->groups, info->gid);
  354           _dbus_group_info_unref (info);
  355           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  356           return NULL;
  357         }
  358 
  359       /* Release the original reference */
  360       _dbus_group_info_unref (info);
  361 
  362       /* Return a borrowed reference to the DBusGroupInfo owned by the
  363        * two hash tables */
  364       return info;
  365     }
  366 }
  367 
  368 /**
  369  * Gets all groups  corresponding to the given UID. Returns #FALSE
  370  * if no memory, or user isn't known, but always initializes
  371  * group_ids to a NULL array. 
  372  *
  373  * @param uid the UID
  374  * @param group_ids return location for array of group IDs
  375  * @param n_group_ids return location for length of returned array
  376  * @returns #TRUE if the UID existed and we got some credentials
  377  */
  378 dbus_bool_t
  379 _dbus_groups_from_uid (dbus_uid_t         uid,
  380                        dbus_gid_t       **group_ids,
  381                        int               *n_group_ids)
  382 {
  383   DBusUserDatabase *db;
  384   const DBusUserInfo *info;
  385   *group_ids = NULL;
  386   *n_group_ids = 0;
  387 
  388   /* FIXME: this can't distinguish ENOMEM from other errors */
  389   if (!_dbus_user_database_lock_system ())
  390     return FALSE;
  391 
  392   db = _dbus_user_database_get_system ();
  393   if (db == NULL)
  394     {
  395       _dbus_user_database_unlock_system ();
  396       return FALSE;
  397     }
  398 
  399   if (!_dbus_user_database_get_uid (db, uid,
  400                                     &info, NULL))
  401     {
  402       _dbus_user_database_unlock_system ();
  403       return FALSE;
  404     }
  405 
  406   _dbus_assert (info->uid == uid);
  407   
  408   if (info->n_group_ids > 0)
  409     {
  410       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
  411       if (*group_ids == NULL)
  412         {
  413       _dbus_user_database_unlock_system ();
  414           return FALSE;
  415         }
  416 
  417       *n_group_ids = info->n_group_ids;
  418 
  419       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
  420     }
  421 
  422   _dbus_user_database_unlock_system ();
  423   return TRUE;
  424 }
  425 /** @} */