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