• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List

dbus-userdb.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-userdb.c User database abstraction
00003  * 
00004  * Copyright (C) 2003, 2004  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 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00024 #include "dbus-userdb.h"
00025 #include "dbus-hash.h"
00026 #include "dbus-test.h"
00027 #include "dbus-internals.h"
00028 #include "dbus-protocol.h"
00029 #include "dbus-credentials.h"
00030 #include <string.h>
00031 
00043 void
00044 _dbus_user_info_free_allocated (DBusUserInfo *info)
00045 {
00046   if (info == NULL) /* hash table will pass NULL */
00047     return;
00048 
00049   _dbus_user_info_free (info);
00050   dbus_free (info);
00051 }
00052 
00059 void
00060 _dbus_group_info_free_allocated (DBusGroupInfo *info)
00061 {
00062   if (info == NULL) /* hash table will pass NULL */
00063     return;
00064 
00065   _dbus_group_info_free (info);
00066   dbus_free (info);
00067 }
00068 
00074 void
00075 _dbus_user_info_free (DBusUserInfo *info)
00076 {
00077   dbus_free (info->group_ids);
00078   dbus_free (info->username);
00079   dbus_free (info->homedir);
00080 }
00081 
00087 void
00088 _dbus_group_info_free (DBusGroupInfo    *info)
00089 {
00090   dbus_free (info->groupname);
00091 }
00092 
00101 dbus_bool_t
00102 _dbus_is_a_number (const DBusString *str,
00103                    unsigned long    *num)
00104 {
00105   int end;
00106 
00107   if (_dbus_string_parse_uint (str, 0, num, &end) &&
00108       end == _dbus_string_get_length (str))
00109     return TRUE;
00110   else
00111     return FALSE;
00112 }
00113 
00126 DBusUserInfo*
00127 _dbus_user_database_lookup (DBusUserDatabase *db,
00128                             dbus_uid_t        uid,
00129                             const DBusString *username,
00130                             DBusError        *error)
00131 {
00132   DBusUserInfo *info;
00133 
00134   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00135   _dbus_assert (uid != DBUS_UID_UNSET || username != NULL);
00136 
00137   /* See if the username is really a number */
00138   if (uid == DBUS_UID_UNSET)
00139     {
00140       unsigned long n;
00141 
00142       if (_dbus_is_a_number (username, &n))
00143         uid = n;
00144     }
00145 
00146 #ifdef DBUS_ENABLE_USERDB_CACHE  
00147   if (uid != DBUS_UID_UNSET)
00148     info = _dbus_hash_table_lookup_ulong (db->users, uid);
00149   else
00150     info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username));
00151 
00152   if (info)
00153     {
00154       _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n",
00155                      info->uid);
00156       return info;
00157     }
00158   else
00159 #else 
00160   if (1)
00161 #endif
00162     {
00163       if (uid != DBUS_UID_UNSET)
00164         _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n",
00165                        uid);
00166       else
00167         _dbus_verbose ("No cache for user \"%s\"\n",
00168                        _dbus_string_get_const_data (username));
00169       
00170       info = dbus_new0 (DBusUserInfo, 1);
00171       if (info == NULL)
00172         {
00173           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00174           return NULL;
00175         }
00176 
00177       if (uid != DBUS_UID_UNSET)
00178         {
00179           if (!_dbus_user_info_fill_uid (info, uid, error))
00180             {
00181               _DBUS_ASSERT_ERROR_IS_SET (error);
00182               _dbus_user_info_free_allocated (info);
00183               return NULL;
00184             }
00185         }
00186       else
00187         {
00188           if (!_dbus_user_info_fill (info, username, error))
00189             {
00190               _DBUS_ASSERT_ERROR_IS_SET (error);
00191               _dbus_user_info_free_allocated (info);
00192               return NULL;
00193             }
00194         }
00195 
00196       /* be sure we don't use these after here */
00197       uid = DBUS_UID_UNSET;
00198       username = NULL;
00199 
00200       /* insert into hash */
00201       if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info))
00202         {
00203           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00204           _dbus_user_info_free_allocated (info);
00205           return NULL;
00206         }
00207 
00208       if (!_dbus_hash_table_insert_string (db->users_by_name,
00209                                            info->username,
00210                                            info))
00211         {
00212           _dbus_hash_table_remove_ulong (db->users, info->uid);
00213           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00214           return NULL;
00215         }
00216       
00217       return info;
00218     }
00219 }
00220 
00221 static dbus_bool_t database_locked = FALSE;
00222 static DBusUserDatabase *system_db = NULL;
00223 static DBusString process_username;
00224 static DBusString process_homedir;
00225       
00226 static void
00227 shutdown_system_db (void *data)
00228 {
00229   if (system_db != NULL)
00230     _dbus_user_database_unref (system_db);
00231   system_db = NULL;
00232   _dbus_string_free (&process_username);
00233   _dbus_string_free (&process_homedir);
00234 }
00235 
00236 static dbus_bool_t
00237 init_system_db (void)
00238 {
00239   _dbus_assert (database_locked);
00240     
00241   if (system_db == NULL)
00242     {
00243       DBusError error = DBUS_ERROR_INIT;
00244       const DBusUserInfo *info;
00245       
00246       system_db = _dbus_user_database_new ();
00247       if (system_db == NULL)
00248         return FALSE;
00249 
00250       if (!_dbus_user_database_get_uid (system_db,
00251                                         _dbus_getuid (),
00252                                         &info,
00253                                         &error))
00254         {
00255           _dbus_user_database_unref (system_db);
00256           system_db = NULL;
00257           
00258           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00259             {
00260               dbus_error_free (&error);
00261               return FALSE;
00262             }
00263           else
00264             {
00265               /* This really should not happen. */
00266               _dbus_warn ("Could not get password database information for UID of current process: %s\n",
00267                           error.message);
00268               dbus_error_free (&error);
00269               return FALSE;
00270             }
00271         }
00272 
00273       if (!_dbus_string_init (&process_username))
00274         {
00275           _dbus_user_database_unref (system_db);
00276           system_db = NULL;
00277           return FALSE;
00278         }
00279 
00280       if (!_dbus_string_init (&process_homedir))
00281         {
00282           _dbus_string_free (&process_username);
00283           _dbus_user_database_unref (system_db);
00284           system_db = NULL;
00285           return FALSE;
00286         }
00287 
00288       if (!_dbus_string_append (&process_username,
00289                                 info->username) ||
00290           !_dbus_string_append (&process_homedir,
00291                                 info->homedir) ||
00292           !_dbus_register_shutdown_func (shutdown_system_db, NULL))
00293         {
00294           _dbus_string_free (&process_username);
00295           _dbus_string_free (&process_homedir);
00296           _dbus_user_database_unref (system_db);
00297           system_db = NULL;
00298           return FALSE;
00299         }
00300     }
00301 
00302   return TRUE;
00303 }
00304 
00308 void
00309 _dbus_user_database_lock_system (void)
00310 {
00311   _DBUS_LOCK (system_users);
00312   database_locked = TRUE;
00313 }
00314 
00318 void
00319 _dbus_user_database_unlock_system (void)
00320 {
00321   database_locked = FALSE;
00322   _DBUS_UNLOCK (system_users);
00323 }
00324 
00331 DBusUserDatabase*
00332 _dbus_user_database_get_system (void)
00333 {
00334   _dbus_assert (database_locked);
00335 
00336   init_system_db ();
00337   
00338   return system_db;
00339 }
00340 
00344 void
00345 _dbus_user_database_flush_system (void)
00346 {
00347   _dbus_user_database_lock_system ();
00348    
00349    if (system_db != NULL)
00350     _dbus_user_database_flush (system_db);
00351 
00352   _dbus_user_database_unlock_system ();
00353 }
00354 
00362 dbus_bool_t
00363 _dbus_username_from_current_process (const DBusString **username)
00364 {
00365   _dbus_user_database_lock_system ();
00366   if (!init_system_db ())
00367     {
00368       _dbus_user_database_unlock_system ();
00369       return FALSE;
00370     }
00371   *username = &process_username;
00372   _dbus_user_database_unlock_system ();  
00373 
00374   return TRUE;
00375 }
00376 
00384 dbus_bool_t
00385 _dbus_homedir_from_current_process (const DBusString  **homedir)
00386 {
00387   _dbus_user_database_lock_system ();
00388   if (!init_system_db ())
00389     {
00390       _dbus_user_database_unlock_system ();
00391       return FALSE;
00392     }
00393   *homedir = &process_homedir;
00394   _dbus_user_database_unlock_system ();
00395 
00396   return TRUE;
00397 }
00398 
00406 dbus_bool_t
00407 _dbus_homedir_from_username (const DBusString *username,
00408                              DBusString       *homedir)
00409 {
00410   DBusUserDatabase *db;
00411   const DBusUserInfo *info;
00412   _dbus_user_database_lock_system ();
00413 
00414   db = _dbus_user_database_get_system ();
00415   if (db == NULL)
00416     {
00417       _dbus_user_database_unlock_system ();
00418       return FALSE;
00419     }
00420 
00421   if (!_dbus_user_database_get_username (db, username,
00422                                          &info, NULL))
00423     {
00424       _dbus_user_database_unlock_system ();
00425       return FALSE;
00426     }
00427 
00428   if (!_dbus_string_append (homedir, info->homedir))
00429     {
00430       _dbus_user_database_unlock_system ();
00431       return FALSE;
00432     }
00433   
00434   _dbus_user_database_unlock_system ();
00435   return TRUE;
00436 }
00437 
00445 dbus_bool_t
00446 _dbus_homedir_from_uid (dbus_uid_t         uid,
00447                         DBusString        *homedir)
00448 {
00449   DBusUserDatabase *db;
00450   const DBusUserInfo *info;
00451   _dbus_user_database_lock_system ();
00452 
00453   db = _dbus_user_database_get_system ();
00454   if (db == NULL)
00455     {
00456       _dbus_user_database_unlock_system ();
00457       return FALSE;
00458     }
00459 
00460   if (!_dbus_user_database_get_uid (db, uid,
00461                                     &info, NULL))
00462     {
00463       _dbus_user_database_unlock_system ();
00464       return FALSE;
00465     }
00466 
00467   if (!_dbus_string_append (homedir, info->homedir))
00468     {
00469       _dbus_user_database_unlock_system ();
00470       return FALSE;
00471     }
00472   
00473   _dbus_user_database_unlock_system ();
00474   return TRUE;
00475 }
00476 
00491 dbus_bool_t
00492 _dbus_credentials_add_from_user (DBusCredentials  *credentials,
00493                                  const DBusString *username)
00494 {
00495   DBusUserDatabase *db;
00496   const DBusUserInfo *info;
00497 
00498   _dbus_user_database_lock_system ();
00499 
00500   db = _dbus_user_database_get_system ();
00501   if (db == NULL)
00502     {
00503       _dbus_user_database_unlock_system ();
00504       return FALSE;
00505     }
00506 
00507   if (!_dbus_user_database_get_username (db, username,
00508                                          &info, NULL))
00509     {
00510       _dbus_user_database_unlock_system ();
00511       return FALSE;
00512     }
00513 
00514   if (!_dbus_credentials_add_unix_uid(credentials, info->uid))
00515     {
00516       _dbus_user_database_unlock_system ();
00517       return FALSE;
00518     }
00519   
00520   _dbus_user_database_unlock_system ();
00521   return TRUE;
00522 }
00523 
00529 DBusUserDatabase*
00530 _dbus_user_database_new (void)
00531 {
00532   DBusUserDatabase *db;
00533   
00534   db = dbus_new0 (DBusUserDatabase, 1);
00535   if (db == NULL)
00536     return NULL;
00537 
00538   db->refcount = 1;
00539 
00540   db->users = _dbus_hash_table_new (DBUS_HASH_ULONG,
00541                                     NULL, (DBusFreeFunction) _dbus_user_info_free_allocated);
00542   
00543   if (db->users == NULL)
00544     goto failed;
00545 
00546   db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG,
00547                                      NULL, (DBusFreeFunction) _dbus_group_info_free_allocated);
00548   
00549   if (db->groups == NULL)
00550     goto failed;
00551 
00552   db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00553                                             NULL, NULL);
00554   if (db->users_by_name == NULL)
00555     goto failed;
00556   
00557   db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING,
00558                                              NULL, NULL);
00559   if (db->groups_by_name == NULL)
00560     goto failed;
00561   
00562   return db;
00563   
00564  failed:
00565   _dbus_user_database_unref (db);
00566   return NULL;
00567 }
00568 
00572 void
00573 _dbus_user_database_flush (DBusUserDatabase *db) 
00574 {
00575   _dbus_hash_table_remove_all(db->users_by_name);
00576   _dbus_hash_table_remove_all(db->groups_by_name);
00577   _dbus_hash_table_remove_all(db->users);
00578   _dbus_hash_table_remove_all(db->groups);
00579 }
00580 
00581 #ifdef DBUS_BUILD_TESTS
00582 
00587 DBusUserDatabase *
00588 _dbus_user_database_ref (DBusUserDatabase  *db)
00589 {
00590   _dbus_assert (db->refcount > 0);
00591 
00592   db->refcount += 1;
00593 
00594   return db;
00595 }
00596 #endif /* DBUS_BUILD_TESTS */
00597 
00602 void
00603 _dbus_user_database_unref (DBusUserDatabase  *db)
00604 {
00605   _dbus_assert (db->refcount > 0);
00606 
00607   db->refcount -= 1;
00608   if (db->refcount == 0)
00609     {
00610       if (db->users)
00611         _dbus_hash_table_unref (db->users);
00612 
00613       if (db->groups)
00614         _dbus_hash_table_unref (db->groups);
00615 
00616       if (db->users_by_name)
00617         _dbus_hash_table_unref (db->users_by_name);
00618 
00619       if (db->groups_by_name)
00620         _dbus_hash_table_unref (db->groups_by_name);
00621       
00622       dbus_free (db);
00623     }
00624 }
00625 
00636 dbus_bool_t
00637 _dbus_user_database_get_uid (DBusUserDatabase    *db,
00638                              dbus_uid_t           uid,
00639                              const DBusUserInfo **info,
00640                              DBusError           *error)
00641 {
00642   *info = _dbus_user_database_lookup (db, uid, NULL, error);
00643   return *info != NULL;
00644 }
00645 
00655 dbus_bool_t
00656 _dbus_user_database_get_username  (DBusUserDatabase     *db,
00657                                    const DBusString     *username,
00658                                    const DBusUserInfo  **info,
00659                                    DBusError            *error)
00660 {
00661   *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error);
00662   return *info != NULL;
00663 }
00664 
00667 /* Tests in dbus-userdb-util.c */

Generated on Sun Feb 20 2011 22:49:19 for D-Bus by  doxygen 1.7.1