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