2005-03-17 Tom Parker <palfrey@tevp.net>
[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                      info->gid);
207       return info;
208     }
209   else
210     {
211       if (gid != DBUS_GID_UNSET)
212         _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n",
213                        gid);
214       else
215         _dbus_verbose ("No cache for groupname \"%s\"\n",
216                        _dbus_string_get_const_data (groupname));
217       
218       info = dbus_new0 (DBusGroupInfo, 1);
219       if (info == NULL)
220         {
221           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
222           return NULL;
223         }
224
225       if (gid != DBUS_GID_UNSET)
226         {
227           if (!_dbus_group_info_fill_gid (info, gid, error))
228             {
229               _DBUS_ASSERT_ERROR_IS_SET (error);
230               _dbus_group_info_free_allocated (info);
231               return NULL;
232             }
233         }
234       else
235         {
236           if (!_dbus_group_info_fill (info, groupname, error))
237             {
238               _DBUS_ASSERT_ERROR_IS_SET (error);
239               _dbus_group_info_free_allocated (info);
240               return NULL;
241             }
242         }
243
244       /* don't use these past here */
245       gid = DBUS_GID_UNSET;
246       groupname = NULL;
247
248       if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info))
249         {
250           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
251           _dbus_group_info_free_allocated (info);
252           return NULL;
253         }
254
255
256       if (!_dbus_hash_table_insert_string (db->groups_by_name,
257                                            info->groupname,
258                                            info))
259         {
260           _dbus_hash_table_remove_ulong (db->groups, info->gid);
261           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
262           return NULL;
263         }
264       
265       return info;
266     }
267 }
268
269
270 /**
271  * Gets the user information for the given group name,
272  * returned group info should not be freed. 
273  *
274  * @param db user database
275  * @param groupname the group name
276  * @param info return location for const ref to group info
277  * @param error error location
278  * @returns #FALSE if error is set
279  */
280 dbus_bool_t
281 _dbus_user_database_get_groupname (DBusUserDatabase     *db,
282                                    const DBusString     *groupname,
283                                    const DBusGroupInfo **info,
284                                    DBusError            *error)
285 {
286   *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error);
287   return *info != NULL;
288 }
289
290 /**
291  * Gets the user information for the given GID,
292  * returned group info should not be freed. 
293  *
294  * @param db user database
295  * @param gid the group ID
296  * @param info return location for const ref to group info
297  * @param error error location
298  * @returns #FALSE if error is set
299  */
300 dbus_bool_t
301 _dbus_user_database_get_gid (DBusUserDatabase     *db,
302                              dbus_gid_t            gid,
303                              const DBusGroupInfo **info,
304                              DBusError            *error)
305 {
306   *info = _dbus_user_database_lookup_group (db, gid, NULL, error);
307   return *info != NULL;
308 }
309
310
311 /**
312  * Gets all groups for a particular user. Returns #FALSE
313  * if no memory, or user isn't known, but always initializes
314  * group_ids to a NULL array. Sets error to the reason
315  * for returning #FALSE.
316  *
317  * @param db the user database object
318  * @param uid the user ID
319  * @param group_ids return location for array of group IDs
320  * @param n_group_ids return location for length of returned array
321  * @param error return location for error
322  * @returns #TRUE on success
323  */
324 dbus_bool_t
325 _dbus_user_database_get_groups (DBusUserDatabase  *db,
326                                 dbus_uid_t         uid,
327                                 dbus_gid_t       **group_ids,
328                                 int               *n_group_ids,
329                                 DBusError         *error)
330 {
331   DBusUserInfo *info;
332   
333   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
334
335   *group_ids = NULL;
336   *n_group_ids = 0;
337   
338   info = _dbus_user_database_lookup (db, uid, NULL, error);
339   if (info == NULL)
340     {
341       _DBUS_ASSERT_ERROR_IS_SET (error);
342       return FALSE;
343     }
344
345   if (info->n_group_ids > 0)
346     {
347       *group_ids = dbus_new (dbus_gid_t, info->n_group_ids);
348       if (*group_ids == NULL)
349         {
350           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
351           return FALSE;
352         }
353
354       *n_group_ids = info->n_group_ids;
355
356       memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t));
357     }
358
359   return TRUE;
360 }
361
362 /** @} */
363
364 #ifdef DBUS_BUILD_TESTS
365 #include <stdio.h>
366
367 /**
368  * Unit test for dbus-userdb.c.
369  * 
370  * @returns #TRUE on success.
371  */
372 dbus_bool_t
373 _dbus_userdb_test (const char *test_data_dir)
374 {
375   const DBusString *username;
376   const DBusString *homedir;
377
378   if (!_dbus_username_from_current_process (&username))
379     _dbus_assert_not_reached ("didn't get username");
380
381   if (!_dbus_homedir_from_current_process (&homedir))
382     _dbus_assert_not_reached ("didn't get homedir");  
383
384   printf ("    Current user: %s homedir: %s\n",
385           _dbus_string_get_const_data (username),
386           _dbus_string_get_const_data (homedir));
387   
388   return TRUE;
389 }
390 #endif /* DBUS_BUILD_TESTS */