"Fossies" - the Fresh Open Source Software Archive

Member "dbus-1.12.20/dbus/dbus-userdb-util.c" (2 Jul 2020, 13633 Bytes) of package /linux/misc/dbus-1.12.20.tar.gz:


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.12.18_vs_1.12.20.

    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 <string.h>
   31 
   32 #ifdef HAVE_SYSTEMD
   33 #include <systemd/sd-login.h>
   34 #endif
   35 
   36 /**
   37  * @addtogroup DBusInternalsUtils
   38  * @{
   39  */
   40 
   41 static DBusGroupInfo *
   42 _dbus_group_info_ref (DBusGroupInfo *info)
   43 {
   44   _dbus_assert (info->refcount > 0);
   45   _dbus_assert (info->refcount < SIZE_MAX);
   46   info->refcount++;
   47   return info;
   48 }
   49 
   50 /**
   51  * Checks to see if the UID sent in is the console user
   52  *
   53  * @param uid UID of person to check 
   54  * @param error return location for errors
   55  * @returns #TRUE if the UID is the same as the console user and there are no errors
   56  */
   57 dbus_bool_t
   58 _dbus_is_console_user (dbus_uid_t uid,
   59                DBusError *error)
   60 {
   61 
   62   DBusUserDatabase *db;
   63   const DBusUserInfo *info;
   64   dbus_bool_t result = FALSE;
   65 
   66 #ifdef HAVE_SYSTEMD
   67   /* check if we have logind */
   68   if (access ("/run/systemd/seats/", F_OK) >= 0)
   69     {
   70       int r;
   71 
   72       /* Check whether this user is logged in on at least one physical
   73          seat */
   74       r = sd_uid_get_seats (uid, 0, NULL);
   75       if (r < 0)
   76         {
   77           dbus_set_error (error, _dbus_error_from_errno (-r),
   78                           "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
   79                           uid,
   80                           _dbus_strerror (-r));
   81           return FALSE;
   82         }
   83 
   84       return (r > 0);
   85     }
   86 #endif
   87 
   88 #ifdef HAVE_CONSOLE_OWNER_FILE
   89 
   90   DBusString f;
   91   DBusStat st;
   92 
   93   if (!_dbus_string_init (&f))
   94     {
   95       _DBUS_SET_OOM (error);
   96       return FALSE;
   97     }
   98 
   99   if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE))
  100     {
  101       _dbus_string_free(&f);
  102       _DBUS_SET_OOM (error);
  103       return FALSE;
  104     }
  105 
  106   if (_dbus_stat(&f, &st, NULL) && (st.uid == uid))
  107     {
  108       _dbus_string_free(&f);
  109       return TRUE;
  110     }
  111 
  112   _dbus_string_free(&f);
  113 
  114 #endif /* HAVE_CONSOLE_OWNER_FILE */
  115 
  116   if (!_dbus_user_database_lock_system ())
  117     {
  118       _DBUS_SET_OOM (error);
  119       return FALSE;
  120     }
  121 
  122   db = _dbus_user_database_get_system ();
  123   if (db == NULL)
  124     {
  125       dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
  126       _dbus_user_database_unlock_system ();
  127       return FALSE;
  128     }
  129 
  130   /* TPTD: this should be cache-safe, we've locked the DB and
  131     _dbus_user_at_console doesn't pass it on. */
  132   info = _dbus_user_database_lookup (db, uid, NULL, error);
  133 
  134   if (info == NULL)
  135     {
  136       _dbus_user_database_unlock_system ();
  137        return FALSE;
  138     }
  139 
  140   result = _dbus_user_at_console (info->username, error);
  141 
  142   _dbus_user_database_unlock_system ();
  143 
  144   return result;
  145 }
  146 
  147 /**
  148  * Gets user ID given username
  149  *
  150  * @param username the username
  151  * @param uid return location for UID
  152  * @returns #TRUE if username existed and we got the UID
  153  */
  154 dbus_bool_t
  155 _dbus_get_user_id (const DBusString  *username,
  156                    dbus_uid_t        *uid)
  157 {
  158   return _dbus_get_user_id_and_primary_group (username, uid, NULL);
  159 }
  160 
  161 /**
  162  * Gets group ID given groupname
  163  *
  164  * @param groupname the groupname
  165  * @param gid return location for GID
  166  * @returns #TRUE if group name existed and we got the GID
  167  */
  168 dbus_bool_t
  169 _dbus_get_group_id (const DBusString  *groupname,
  170                     dbus_gid_t        *gid)
  171 {
  172   DBusUserDatabase *db;
  173   const DBusGroupInfo *info;
  174 
  175   /* FIXME: this can't distinguish ENOMEM from other errors */
  176   if (!_dbus_user_database_lock_system ())
  177     return FALSE;
  178 
  179   db = _dbus_user_database_get_system ();
  180   if (db == NULL)
  181     {
  182       _dbus_user_database_unlock_system ();
  183       return FALSE;
  184     }
  185 
  186   if (!_dbus_user_database_get_groupname (db, groupname,
  187                                           &info, NULL))
  188     {
  189       _dbus_user_database_unlock_system ();
  190       return FALSE;
  191     }
  192 
  193   *gid = info->gid;
  194   
  195   _dbus_user_database_unlock_system ();
  196   return TRUE;
  197 }
  198 
  199 /**
  200  * Gets user ID and primary group given username
  201  *
  202  * @param username the username
  203  * @param uid_p return location for UID
  204  * @param gid_p return location for GID
  205  * @returns #TRUE if username existed and we got the UID and GID
  206  */
  207 dbus_bool_t
  208 _dbus_get_user_id_and_primary_group (const DBusString  *username,
  209                                      dbus_uid_t        *uid_p,
  210                                      dbus_gid_t        *gid_p)
  211 {
  212   DBusUserDatabase *db;
  213   const DBusUserInfo *info;
  214 
  215   /* FIXME: this can't distinguish ENOMEM from other errors */
  216   if (!_dbus_user_database_lock_system ())
  217     return FALSE;
  218 
  219   db = _dbus_user_database_get_system ();
  220   if (db == NULL)
  221     {
  222       _dbus_user_database_unlock_system ();
  223       return FALSE;
  224     }
  225 
  226   if (!_dbus_user_database_get_username (db, username,
  227                                          &info, NULL))
  228     {
  229       _dbus_user_database_unlock_system ();
  230       return FALSE;
  231     }
  232 
  233   if (uid_p)
  234     *uid_p = info->uid;
  235   if (gid_p)
  236     *gid_p = info->primary_gid;
  237   
  238   _dbus_user_database_unlock_system ();
  239   return TRUE;
  240 }
  241 
  242 /**
  243  * Looks up a gid or group name in the user database.  Only one of
  244  * name or GID can be provided. There are wrapper functions for this
  245  * that are better to use, this one does no locking or anything on the
  246  * database and otherwise sort of sucks.
  247  *
  248  * @param db the database
  249  * @param gid the group ID or #DBUS_GID_UNSET
  250  * @param groupname group name or #NULL 
  251  * @param error error to fill in
  252  * @returns the entry in the database (borrowed, do not free)
  253  */
  254 const DBusGroupInfo *
  255 _dbus_user_database_lookup_group (DBusUserDatabase *db,
  256                                   dbus_gid_t        gid,
  257                                   const DBusString *groupname,
  258                                   DBusError        *error)
  259 {
  260   DBusGroupInfo *info;
  261 
  262   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  263 
  264    /* See if the group is really a number */
  265    if (gid == DBUS_UID_UNSET)
  266     {
  267       unsigned long n;
  268 
  269       if (_dbus_is_a_number (groupname, &n))
  270         gid = n;
  271     }
  272 
  273   if (gid != DBUS_GID_UNSET)
  274     info = _dbus_hash_table_lookup_uintptr (db->groups, gid);
  275   else
  276     info = _dbus_hash_table_lookup_string (db->groups_by_name,
  277                                            _dbus_string_get_const_data (groupname));
  278   if (info)
  279     {
  280       _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
  281                      info->gid);
  282       return info;
  283     }
  284   else
  285     {
  286       if (gid != DBUS_GID_UNSET)
  287     _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
  288                gid);
  289       else
  290     _dbus_verbose ("No cache for groupname \"%s\"\n",
  291                _dbus_string_get_const_data (groupname));
  292       
  293       info = dbus_new0 (DBusGroupInfo, 1);
  294       if (info == NULL)
  295         {
  296           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  297           return NULL;
  298         }
  299       info->refcount = 1;
  300 
  301       if (gid != DBUS_GID_UNSET)
  302         {
  303           if (!_dbus_group_info_fill_gid (info, gid, error))
  304             {
  305               _DBUS_ASSERT_ERROR_IS_SET (error);
  306               _dbus_group_info_unref (info);
  307               return NULL;
  308             }
  309         }
  310       else
  311         {
  312           if (!_dbus_group_info_fill (info, groupname, error))
  313             {
  314               _DBUS_ASSERT_ERROR_IS_SET (error);
  315               _dbus_group_info_unref (info);
  316               return NULL;
  317             }
  318         }
  319 
  320       /* don't use these past here */
  321       gid = DBUS_GID_UNSET;
  322       groupname = NULL;
  323 
  324       if (_dbus_hash_table_insert_uintptr (db->groups, info->gid, info))
  325         {
  326           _dbus_group_info_ref (info);
  327         }
  328       else
  329         {
  330           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  331           _dbus_group_info_unref (info);
  332           return NULL;
  333         }
  334 
  335 
  336       if (_dbus_hash_table_insert_string (db->groups_by_name,
  337                                           info->groupname,
  338                                           info))
  339         {
  340           _dbus_group_info_ref (info);
  341         }
  342       else
  343         {
  344           _dbus_hash_table_remove_uintptr (db->groups, info->gid);
  345           _dbus_group_info_unref (info);
  346           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
  347           return NULL;
  348         }
  349 
  350       /* Release the original reference */
  351       _dbus_group_info_unref (info);
  352 
  353       /* Return a borrowed reference to the DBusGroupInfo owned by the
  354        * two hash tables */
  355       return info;
  356     }
  357 }
  358 
  359 
  360 /**
  361  * Gets the user information for the given group name,
  362  * returned group info should not be freed. 
  363  *
  364  * @param db user database
  365  * @param groupname the group name
  366  * @param info return location for const ref to group info
  367  * @param error error location
  368  * @returns #FALSE if error is set
  369  */
  370 dbus_bool_t
  371 _dbus_user_database_get_groupname (DBusUserDatabase     *db,
  372                                    const DBusString     *groupname,
  373                                    const DBusGroupInfo **info,
  374                                    DBusError            *error)
  375 {
  376   *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
  377   return *info != NULL;
  378 }
  379 
  380 /**
  381  * Gets the user information for the given GID,
  382  * returned group info should not be freed. 
  383  *
  384  * @param db user database
  385  * @param gid the group ID
  386  * @param info return location for const ref to group info
  387  * @param error error location
  388  * @returns #FALSE if error is set
  389  */
  390 dbus_bool_t
  391 _dbus_user_database_get_gid (DBusUserDatabase     *db,
  392                              dbus_gid_t            gid,
  393                              const DBusGroupInfo **info,
  394                              DBusError            *error)
  395 {
  396   *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
  397   return *info != NULL;
  398 }
  399 
  400 
  401 /**
  402  * Gets all groups  corresponding to the given UID. Returns #FALSE
  403  * if no memory, or user isn't known, but always initializes
  404  * group_ids to a NULL array. 
  405  *
  406  * @param uid the UID
  407  * @param group_ids return location for array of group IDs
  408  * @param n_group_ids return location for length of returned array
  409  * @returns #TRUE if the UID existed and we got some credentials
  410  */
  411 dbus_bool_t
  412 _dbus_groups_from_uid (dbus_uid_t         uid,
  413                        dbus_gid_t       **group_ids,
  414                        int               *n_group_ids)
  415 {
  416   DBusUserDatabase *db;
  417   const DBusUserInfo *info;
  418   *group_ids = NULL;
  419   *n_group_ids = 0;
  420 
  421   /* FIXME: this can't distinguish ENOMEM from other errors */
  422   if (!_dbus_user_database_lock_system ())
  423     return FALSE;
  424 
  425   db = _dbus_user_database_get_system ();
  426   if (db == NULL)
  427     {
  428       _dbus_user_database_unlock_system ();
  429       return FALSE;
  430     }
  431 
  432   if (!_dbus_user_database_get_uid (db, uid,
  433                                     &info, NULL))
  434     {
  435       _dbus_user_database_unlock_system ();
  436       return FALSE;
  437     }
  438 
  439   _dbus_assert (info->uid == uid);
  440   
  441   if (info->n_group_ids > 0)
  442     {
  443       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
  444       if (*group_ids == NULL)
  445         {
  446       _dbus_user_database_unlock_system ();
  447           return FALSE;
  448         }
  449 
  450       *n_group_ids = info->n_group_ids;
  451 
  452       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
  453     }
  454 
  455   _dbus_user_database_unlock_system ();
  456   return TRUE;
  457 }
  458 /** @} */
  459 
  460 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
  461 #include <stdio.h>
  462 
  463 /**
  464  * Unit test for dbus-userdb.c.
  465  * 
  466  * @returns #TRUE on success.
  467  */
  468 dbus_bool_t
  469 _dbus_userdb_test (const char *test_data_dir)
  470 {
  471   const DBusString *username;
  472   const DBusString *homedir;
  473   dbus_uid_t uid;
  474   unsigned long *group_ids;
  475   int n_group_ids, i;
  476   DBusError error;
  477 
  478   if (!_dbus_username_from_current_process (&username))
  479     _dbus_assert_not_reached ("didn't get username");
  480 
  481   if (!_dbus_homedir_from_current_process (&homedir))
  482     _dbus_assert_not_reached ("didn't get homedir");  
  483 
  484   if (!_dbus_get_user_id (username, &uid))
  485     _dbus_assert_not_reached ("didn't get uid");
  486 
  487   if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids))
  488     _dbus_assert_not_reached ("didn't get groups");
  489 
  490   printf ("    Current user: %s homedir: %s gids:",
  491           _dbus_string_get_const_data (username),
  492           _dbus_string_get_const_data (homedir));
  493 
  494   for (i=0; i<n_group_ids; i++)
  495       printf(" %ld", group_ids[i]);
  496 
  497   printf ("\n");
  498 
  499   dbus_error_init (&error);
  500   printf ("Is Console user: %i\n",
  501           _dbus_is_console_user (uid, &error));
  502   printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
  503   dbus_error_free (&error);
  504   printf ("Is Console user 4711: %i\n",
  505           _dbus_is_console_user (4711, &error));
  506   printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
  507   dbus_error_free (&error);
  508 
  509   dbus_free (group_ids);
  510 
  511   return TRUE;
  512 }
  513 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */