2
* Copyright (C) 2010 Robert Ancell.
3
* Author: Robert Ancell <robert.ancell@canonical.com>
5
* This program is free software: you can redistribute it and/or modify it under
6
* the terms of the GNU General Public License as published by the Free Software
7
* Foundation, either version 3 of the License, or (at your option) any later
8
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
17
#include "user-manager.h"
25
static guint signals[LAST_SIGNAL] = { 0 };
27
struct UserManagerPrivate
29
/* Configuration file */
32
/* File monitor for password file */
33
GFileMonitor *passwd_monitor;
35
/* TRUE if have scanned users */
42
G_DEFINE_TYPE (UserManager, user_manager, G_TYPE_OBJECT);
45
user_manager_new (GKeyFile *config_file)
49
manager = g_object_new (USER_MANAGER_TYPE, NULL);
50
manager->priv->config = config_file;
56
compare_user (gconstpointer a, gconstpointer b)
58
const UserInfo *user_a = a, *user_b = b;
59
const gchar *name_a, *name_b;
60
name_a = user_a->real_name ? user_a->real_name : user_a->name;
61
name_b = user_b->real_name ? user_b->real_name : user_b->name;
62
return strcmp (name_a, name_b);
66
load_users (UserManager *manager)
68
gchar **hidden_users, **hidden_shells;
71
GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
73
if (g_key_file_has_key (manager->priv->config, "UserManager", "minimum-uid", NULL))
74
minimum_uid = g_key_file_get_integer (manager->priv->config, "UserManager", "minimum-uid", NULL);
78
value = g_key_file_get_string (manager->priv->config, "UserManager", "hidden-users", NULL);
80
value = g_strdup ("nobody nobody4 noaccess");
81
hidden_users = g_strsplit (value, " ", -1);
84
value = g_key_file_get_string (manager->priv->config, "UserManager", "hidden-shells", NULL);
86
value = g_strdup ("/bin/false /usr/sbin/nologin");
87
hidden_shells = g_strsplit (value, " ", -1);
105
/* Ignore system users */
106
if (entry->pw_uid < minimum_uid)
109
/* Ignore users disabled by shell */
112
for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
113
if (hidden_shells[i])
117
/* Ignore certain users */
118
for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
122
user = g_malloc0 (sizeof (UserInfo));
123
user->name = g_strdup (entry->pw_name);
125
tokens = g_strsplit (entry->pw_gecos, ",", -1);
126
if (tokens[0] != NULL && tokens[0][0] != '\0')
127
user->real_name = g_strdup (tokens[0]);
129
user->real_name = NULL;
132
user->home_dir = g_strdup (entry->pw_dir);
134
image_path = g_build_filename (user->home_dir, ".face", NULL);
135
if (!g_file_test (image_path, G_FILE_TEST_EXISTS))
138
image_path = g_build_filename (user->home_dir, ".face.icon", NULL);
139
if (!g_file_test (image_path, G_FILE_TEST_EXISTS))
146
user->image = g_filename_to_uri (image_path, NULL, NULL);
148
user->image = g_strdup ("");
151
/* Update existing users if have them */
152
for (link = manager->priv->users; link; link = link->next)
154
UserInfo *info = link->data;
155
if (strcmp (info->name, user->name) == 0)
157
if (strcmp (info->real_name, user->real_name) != 0 ||
158
strcmp (info->image, user->image) != 0 ||
159
strcmp (info->home_dir, user->home_dir) != 0 ||
160
info->logged_in != user->logged_in)
162
g_free (info->real_name);
163
g_free (info->image);
164
g_free (info->home_dir);
165
info->real_name = user->real_name;
166
info->image = user->image;
167
info->home_dir = user->home_dir;
168
info->logged_in = user->logged_in;
171
changed_users = g_list_insert_sorted (changed_users, user, compare_user);
175
g_free (user->real_name);
176
g_free (user->image);
177
g_free (user->home_dir);
186
/* Only notify once we have loaded the user list */
187
if (manager->priv->have_users)
188
new_users = g_list_insert_sorted (new_users, user, compare_user);
190
users = g_list_insert_sorted (users, user, compare_user);
192
g_strfreev (hidden_users);
193
g_strfreev (hidden_shells);
196
g_warning ("Failed to read password database: %s", strerror (errno));
200
/* Use new user list */
201
old_users = manager->priv->users;
202
manager->priv->users = users;
204
/* Notify of changes */
205
for (link = new_users; link; link = link->next)
207
UserInfo *info = link->data;
208
g_debug ("User %s added", info->name);
209
g_signal_emit (manager, signals[USER_ADDED], 0, info);
211
g_list_free (new_users);
212
for (link = changed_users; link; link = link->next)
214
UserInfo *info = link->data;
215
g_debug ("User %s changed", info->name);
216
g_signal_emit (manager, signals[USER_CHANGED], 0, info);
218
g_list_free (changed_users);
219
for (link = old_users; link; link = link->next)
223
/* See if this user is in the current list */
224
for (new_link = manager->priv->users; new_link; new_link = new_link->next)
226
if (new_link->data == link->data)
232
UserInfo *info = link->data;
233
g_debug ("User %s removed", info->name);
234
g_signal_emit (manager, signals[USER_REMOVED], 0, info);
236
g_free (info->real_name);
237
g_free (info->image);
238
g_free (info->home_dir);
242
g_list_free (old_users);
246
passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, UserManager *manager)
248
if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
250
g_debug ("%s changed, reloading user list", g_file_get_path (file));
251
load_users (manager);
256
update_users (UserManager *manager)
259
GError *error = NULL;
261
if (manager->priv->have_users)
264
/* User listing is disabled */
265
if (g_key_file_has_key (manager->priv->config, "UserManager", "load-users", NULL) &&
266
!g_key_file_get_boolean (manager->priv->config, "UserManager", "load-users", NULL))
268
manager->priv->have_users = TRUE;
272
load_users (manager);
274
/* Watch for changes to user list */
275
passwd_file = g_file_new_for_path ("/etc/passwd");
276
manager->priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
277
g_object_unref (passwd_file);
278
if (!manager->priv->passwd_monitor)
279
g_warning ("Error monitoring /etc/passwd: %s", error->message);
281
g_signal_connect (manager->priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), manager);
282
g_clear_error (&error);
284
manager->priv->have_users = TRUE;
288
user_manager_get_num_users (UserManager *manager)
290
update_users (manager);
291
return g_list_length (manager->priv->users);
295
user_manager_get_user (UserManager *manager, const gchar *username)
299
update_users (manager);
301
for (link = manager->priv->users; link; link = link->next)
303
UserInfo *info = link->data;
304
if (strcmp (info->name, username) == 0)
312
user_manager_get_users (UserManager *manager)
314
update_users (manager);
315
return manager->priv->users;
319
user_manager_get_user_defaults (UserManager *manager, gchar *username, gchar **language, gchar **layout, gchar **session)
321
const UserInfo *info;
326
info = user_manager_get_user (manager, username);
329
g_debug ("Unable to get user defaults, user %s does not exist", username);
333
dmrc_file = g_key_file_new ();
334
g_key_file_set_string (dmrc_file, "Desktop", "Language", "");
335
g_key_file_set_string (dmrc_file, "Desktop", "Layout", "");
336
g_key_file_set_string (dmrc_file, "Desktop", "Session", "");
338
/* Load the users login settings (~/.dmrc) */
339
path = g_build_filename (info->home_dir, ".dmrc", NULL);
340
have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
343
/* If no .dmrc, then load from the cache */
348
filename = g_strdup_printf ("%s.dmrc", username);
349
path = g_build_filename (CACHE_DIR, "dmrc", filename, NULL);
351
have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
355
*language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
356
*layout = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
357
*session = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
359
g_key_file_free (dmrc_file);
366
user_manager_init (UserManager *manager)
368
manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, USER_MANAGER_TYPE, UserManagerPrivate);
372
user_manager_class_init (UserManagerClass *klass)
374
g_type_class_add_private (klass, sizeof (UserManagerPrivate));
376
signals[USER_ADDED] =
377
g_signal_new ("user-added",
378
G_TYPE_FROM_CLASS (klass),
380
G_STRUCT_OFFSET (UserManagerClass, user_added),
382
g_cclosure_marshal_VOID__POINTER,
383
G_TYPE_NONE, 1, G_TYPE_POINTER);
384
signals[USER_CHANGED] =
385
g_signal_new ("user-changed",
386
G_TYPE_FROM_CLASS (klass),
388
G_STRUCT_OFFSET (UserManagerClass, user_changed),
390
g_cclosure_marshal_VOID__POINTER,
391
G_TYPE_NONE, 1, G_TYPE_POINTER);
392
signals[USER_REMOVED] =
393
g_signal_new ("user-removed",
394
G_TYPE_FROM_CLASS (klass),
396
G_STRUCT_OFFSET (UserManagerClass, user_removed),
398
g_cclosure_marshal_VOID__POINTER,
399
G_TYPE_NONE, 1, G_TYPE_POINTER);