2005-02-14 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-userdb-util.c
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   _dbus_user_database_lock_system ();
52
53   db = _dbus_user_database_get_system ();
54   if (db == NULL)
55     {
56       dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database.");
57       _dbus_user_database_unlock_system ();
58       return FALSE;
59     }
60
61   info = _dbus_user_database_lookup (db, uid, NULL, error);
62
63   if (info == NULL)
64     {
65       _dbus_user_database_unlock_system ();
66        return FALSE;
67     }
68
69   result = _dbus_user_at_console (info->username, error);
70
71   _dbus_user_database_unlock_system ();
72
73   return result;
74 }
75
76
77 /**
78  * Gets the credentials corresponding to the given UID.
79  *
80  * @param uid the UID
81  * @param credentials credentials to fill in
82  * @returns #TRUE if the UID existed and we got some credentials
83  */
84 dbus_bool_t
85 _dbus_credentials_from_uid (dbus_uid_t        uid,
86                             DBusCredentials  *credentials)
87 {
88   DBusUserDatabase *db;
89   const DBusUserInfo *info;
90   _dbus_user_database_lock_system ();
91
92   db = _dbus_user_database_get_system ();
93   if (db == NULL)
94     {
95       _dbus_user_database_unlock_system ();
96       return FALSE;
97     }
98
99   if (!_dbus_user_database_get_uid (db, uid,
100                                     &info, NULL))
101     {
102       _dbus_user_database_unlock_system ();
103       return FALSE;
104     }
105
106   _dbus_assert (info->uid == uid);
107   
108   credentials->pid = DBUS_PID_UNSET;
109   credentials->uid = info->uid;
110   credentials->gid = info->primary_gid;
111   
112   _dbus_user_database_unlock_system ();
113   return TRUE;
114 }
115
116
117 /**
118  * Gets user ID given username
119  *
120  * @param username the username
121  * @param uid return location for UID
122  * @returns #TRUE if username existed and we got the UID
123  */
124 dbus_bool_t
125 _dbus_get_user_id (const DBusString  *username,
126                    dbus_uid_t        *uid)
127 {
128   DBusCredentials creds;
129
130   if (!_dbus_credentials_from_username (username, &creds))
131     return FALSE;
132
133   if (creds.uid == DBUS_UID_UNSET)
134     return FALSE;
135
136   *uid = creds.uid;
137
138   return TRUE;
139 }
140
141 /**
142  * Gets group ID given groupname
143  *
144  * @param groupname the groupname
145  * @param gid return location for GID
146  * @returns #TRUE if group name existed and we got the GID
147  */
148 dbus_bool_t
149 _dbus_get_group_id (const DBusString  *groupname,
150                     dbus_gid_t        *gid)
151 {
152   DBusUserDatabase *db;
153   const DBusGroupInfo *info;
154   _dbus_user_database_lock_system ();
155
156   db = _dbus_user_database_get_system ();
157   if (db == NULL)
158     {
159       _dbus_user_database_unlock_system ();
160       return FALSE;
161     }
162
163   if (!_dbus_user_database_get_groupname (db, groupname,
164                                           &info, NULL))
165     {
166       _dbus_user_database_unlock_system ();
167       return FALSE;
168     }
169
170   *gid = info->gid;
171   
172   _dbus_user_database_unlock_system ();
173   return TRUE;
174 }
175
176 /**
177  * Looks up a gid or group name in the user database.  Only one of
178  * name or GID can be provided. There are wrapper functions for this
179  * that are better to use, this one does no locking or anything on the
180  * database and otherwise sort of sucks.
181  *
182  * @param db the database
183  * @param gid the group ID or #DBUS_GID_UNSET
184  * @param groupname group name or #NULL 
185  * @param error error to fill in
186  * @returns the entry in the database
187  */
188 DBusGroupInfo*
189 _dbus_user_database_lookup_group (DBusUserDatabase *db,
190                                   dbus_gid_t        gid,
191                                   const DBusString *groupname,
192                                   DBusError        *error)
193 {
194   DBusGroupInfo *info;
195
196   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
197
198   if (gid != DBUS_GID_UNSET)
199     info = _dbus_hash_table_lookup_ulong (db->groups, gid);
200   else
201     info = _dbus_hash_table_lookup_string (db->groups_by_name,
202                                            _dbus_string_get_const_data (groupname));
203   if (info)
204     {
205       _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n",
206                      gid);
207       return info;
208     }
209   else
210     {
211       _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
212                      gid);
213       
214       info = dbus_new0 (DBusGroupInfo, 1);
215       if (info == NULL)
216         {
217           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
218           return NULL;
219         }
220
221       if (gid != DBUS_GID_UNSET)
222         {
223           if (!_dbus_group_info_fill_gid (info, gid, error))
224             {
225               _DBUS_ASSERT_ERROR_IS_SET (error);
226               _dbus_group_info_free_allocated (info);
227               return NULL;
228             }
229         }
230       else
231         {
232           if (!_dbus_group_info_fill (info, groupname, error))
233             {
234               _DBUS_ASSERT_ERROR_IS_SET (error);
235               _dbus_group_info_free_allocated (info);
236               return NULL;
237             }
238         }
239
240       /* don't use these past here */
241       gid = DBUS_GID_UNSET;
242       groupname = NULL;
243
244       if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))
245         {
246           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
247           _dbus_group_info_free_allocated (info);
248           return NULL;
249         }
250
251
252       if (!_dbus_hash_table_insert_string (db->groups_by_name,
253                                            info->groupname,
254                                            info))
255         {
256           _dbus_hash_table_remove_ulong (db->groups, info->gid);
257           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
258           return NULL;
259         }
260       
261       return info;
262     }
263 }
264
265
266 /**
267  * Gets the user information for the given group name,
268  * returned group info should not be freed. 
269  *
270  * @param db user database
271  * @param groupname the group name
272  * @param info return location for const ref to group info
273  * @param error error location
274  * @returns #FALSE if error is set
275  */
276 dbus_bool_t
277 _dbus_user_database_get_groupname (DBusUserDatabase     *db,
278                                    const DBusString     *groupname,
279                                    const DBusGroupInfo **info,
280                                    DBusError            *error)
281 {
282   *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
283   return *info != NULL;
284 }
285
286 /**
287  * Gets the user information for the given GID,
288  * returned group info should not be freed. 
289  *
290  * @param db user database
291  * @param gid the group ID
292  * @param info return location for const ref to group info
293  * @param error error location
294  * @returns #FALSE if error is set
295  */
296 dbus_bool_t
297 _dbus_user_database_get_gid (DBusUserDatabase     *db,
298                              dbus_gid_t            gid,
299                              const DBusGroupInfo **info,
300                              DBusError            *error)
301 {
302   *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
303   return *info != NULL;
304 }
305
306
307 /**
308  * Gets all groups for a particular user. Returns #FALSE
309  * if no memory, or user isn't known, but always initializes
310  * group_ids to a NULL array. Sets error to the reason
311  * for returning #FALSE.
312  *
313  * @param db the user database object
314  * @param uid the user ID
315  * @param group_ids return location for array of group IDs
316  * @param n_group_ids return location for length of returned array
317  * @param error return location for error
318  * @returns #TRUE on success
319  */
320 dbus_bool_t
321 _dbus_user_database_get_groups (DBusUserDatabase  *db,
322                                 dbus_uid_t         uid,
323                                 dbus_gid_t       **group_ids,
324                                 int               *n_group_ids,
325                                 DBusError         *error)
326 {
327   DBusUserInfo *info;
328   
329   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
330
331   *group_ids = NULL;
332   *n_group_ids = 0;
333   
334   info = _dbus_user_database_lookup (db, uid, NULL, error);
335   if (info == NULL)
336     {
337       _DBUS_ASSERT_ERROR_IS_SET (error);
338       return FALSE;
339     }
340
341   if (info->n_group_ids > 0)
342     {
343       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
344       if (*group_ids == NULL)
345         {
346           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
347           return FALSE;
348         }
349
350       *n_group_ids = info->n_group_ids;
351
352       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
353     }
354
355   return TRUE;
356 }
357
358 /** @} */
359
360 #ifdef DBUS_BUILD_TESTS
361 #include <stdio.h>
362
363 /**
364  * Unit test for dbus-userdb.c.
365  * 
366  * @returns #TRUE on success.
367  */
368 dbus_bool_t
369 _dbus_userdb_test (const char *test_data_dir)
370 {
371   const DBusString *username;
372   const DBusString *homedir;
373
374   if (!_dbus_username_from_current_process (&username))
375     _dbus_assert_not_reached ("didn't get username");
376
377   if (!_dbus_homedir_from_current_process (&homedir))
378     _dbus_assert_not_reached ("didn't get homedir");  
379
380   printf ("    Current user: %s homedir: %s\n",
381           _dbus_string_get_const_data (username),
382           _dbus_string_get_const_data (homedir));
383   
384   return TRUE;
385 }
386 #endif /* DBUS_BUILD_TESTS */