]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/user-manager.c
Change language/layout/session when user selected in GTK+ greeter
[sojka/lightdm.git] / src / user-manager.c
1 /*
2  * Copyright (C) 2010 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
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
9  * license.
10  */
11
12 #include <string.h>
13 #include <pwd.h>
14 #include <errno.h>
15
16 #include "user-manager.h"
17 #include "user-manager-glue.h"
18
19 struct UserManagerPrivate
20 {
21     /* Configuration file */
22     GKeyFile *config;
23
24     /* TRUE if have scanned users */
25     gboolean have_users;
26
27     /* List of users */
28     GList *users;
29 };
30
31 G_DEFINE_TYPE (UserManager, user_manager, G_TYPE_OBJECT);
32
33 UserManager *
34 user_manager_new (GKeyFile *config_file)
35 {
36     UserManager *manager;
37
38     manager = g_object_new (USER_MANAGER_TYPE, NULL);
39     manager->priv->config = config_file;
40
41     return manager;
42 }
43
44 static gint
45 compare_user (gconstpointer a, gconstpointer b)
46 {
47     const UserInfo *user_a = a, *user_b = b;
48     const gchar *name_a, *name_b;
49     name_a = user_a->real_name ? user_a->real_name : user_a->name;
50     name_b = user_b->real_name ? user_b->real_name : user_b->name;
51     return strcmp (name_a, name_b);
52 }
53
54 static void
55 update_users (UserManager *manager)
56 {
57     gchar **hidden_users, **hidden_shells;
58     gchar *value;
59     gint minimum_uid;
60
61     if (manager->priv->have_users)
62         return;
63
64     /* User listing is disabled */
65     if (g_key_file_has_key (manager->priv->config, "UserManager", "load-users", NULL) &&
66         !g_key_file_get_boolean (manager->priv->config, "UserManager", "load-users", NULL))
67     {
68         manager->priv->have_users = TRUE;
69         return;
70     }
71
72     if (g_key_file_has_key (manager->priv->config, "UserManager", "minimum-uid", NULL))
73         minimum_uid = g_key_file_get_integer (manager->priv->config, "UserManager", "minimum-uid", NULL);
74     else
75         minimum_uid = 500;
76
77     value = g_key_file_get_string (manager->priv->config, "UserManager", "hidden-users", NULL);
78     if (!value)
79         value = g_strdup ("nobody nobody4 noaccess");
80     hidden_users = g_strsplit (value, " ", -1);
81     g_free (value);
82
83     value = g_key_file_get_string (manager->priv->config, "UserManager", "hidden-shells", NULL);
84     if (!value)
85         value = g_strdup ("/bin/false /usr/sbin/nologin");
86     hidden_shells = g_strsplit (value, " ", -1);
87     g_free (value);
88
89     setpwent ();
90
91     while (TRUE)
92     {
93         struct passwd *entry;
94         UserInfo *user;
95         char **tokens;
96         gchar *image_path;
97         int i;
98
99         errno = 0;
100         entry = getpwent ();
101         if (!entry)
102             break;
103
104         /* Ignore system users */
105         if (entry->pw_uid < minimum_uid)
106             continue;
107
108         /* Ignore users disabled by shell */
109         if (entry->pw_shell)
110         {
111             for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
112             if (hidden_shells[i])
113                 continue;
114         }
115
116         /* Ignore certain users */
117         for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
118         if (hidden_users[i])
119             continue;
120
121         user = g_malloc0 (sizeof (UserInfo));
122         user->name = g_strdup (entry->pw_name);
123
124         tokens = g_strsplit (entry->pw_gecos, ",", -1);
125         if (tokens[0] != NULL && tokens[0][0] != '\0')
126             user->real_name = g_strdup (tokens[0]);
127         else
128             user->real_name = NULL;
129         g_strfreev (tokens);
130       
131         user->home_dir = g_strdup (entry->pw_dir);
132
133         image_path = g_build_filename (user->home_dir, ".face", NULL);
134         if (g_file_test (image_path, G_FILE_TEST_EXISTS))
135             user->image = g_filename_to_uri (image_path, NULL, NULL);
136         else
137             user->image = g_strdup ("");
138         g_free (image_path);
139
140         manager->priv->users = g_list_insert_sorted (manager->priv->users, user, compare_user);
141     }
142
143     if (errno != 0)
144         g_warning ("Failed to read password database: %s", strerror (errno));
145
146     endpwent ();
147   
148     g_strfreev (hidden_users);
149     g_strfreev (hidden_shells);
150
151     manager->priv->have_users = TRUE;
152 }
153
154 gint
155 user_manager_get_num_users (UserManager *manager)
156 {
157     update_users (manager);
158     return g_list_length (manager->priv->users);
159 }
160
161 const UserInfo *
162 user_manager_get_user (UserManager *manager, const gchar *username)
163 {
164     GList *link;
165
166     update_users (manager);
167
168     for (link = manager->priv->users; link; link = link->next)
169     {
170         UserInfo *info = link->data;
171         if (strcmp (info->name, username) == 0)
172             return info;
173     }
174
175     return NULL;
176 }
177
178 #define TYPE_USER dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID)
179
180 gboolean
181 user_manager_get_users (UserManager *manager, GPtrArray **users, GError *error)
182 {
183     GList *link;
184
185     update_users (manager);
186
187     *users = g_ptr_array_sized_new (g_list_length (manager->priv->users));
188     for (link = manager->priv->users; link; link = link->next)
189     {
190         UserInfo *info = link->data;
191         GValue value = { 0 };
192
193         g_value_init (&value, TYPE_USER);
194         g_value_take_boxed (&value, dbus_g_type_specialized_construct (TYPE_USER));
195         dbus_g_type_struct_set (&value, 0, info->name, 1, info->real_name, 2, info->image, 3, info->logged_in, G_MAXUINT);
196         g_ptr_array_add (*users, g_value_get_boxed (&value));
197     }
198
199     return TRUE;
200 }
201
202 gboolean
203 user_manager_get_user_defaults (UserManager *manager, gchar *username, gchar **language, gchar **layout, gchar **session, GError *error)
204 {
205     const UserInfo *info;
206     GKeyFile *dmrc_file;
207     gboolean have_dmrc;
208     gchar *path;
209
210     info = user_manager_get_user (manager, username);
211     if (!info)
212         return FALSE;
213
214     dmrc_file = g_key_file_new ();
215     g_key_file_set_string (dmrc_file, "Desktop", "Language", "");
216     g_key_file_set_string (dmrc_file, "Desktop", "Layout", "");
217     g_key_file_set_string (dmrc_file, "Desktop", "Session", "");
218
219     /* Load the users login settings (~/.dmrc) */  
220     path = g_build_filename (info->home_dir, ".dmrc", NULL);
221     have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
222     g_free (path);
223
224     /* If no .dmrc, then load from the cache */
225     if (!have_dmrc)
226     {
227         gchar *filename;
228
229         filename = g_strdup_printf ("%s.dmrc", username);
230         path = g_build_filename (CACHE_DIR, "dmrc", filename, NULL);
231         g_free (filename);
232         have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
233         g_free (path);
234     }
235
236     *language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
237     *layout = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
238     *session = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
239
240     g_key_file_free (dmrc_file);
241
242     return TRUE;
243 }
244
245
246 static void
247 user_manager_init (UserManager *manager)
248 {
249     manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, USER_MANAGER_TYPE, UserManagerPrivate);
250 }
251
252 static void
253 user_manager_class_init (UserManagerClass *klass)
254 {
255     g_type_class_add_private (klass, sizeof (UserManagerPrivate));
256
257     dbus_g_object_type_install_info (USER_MANAGER_TYPE, &dbus_glib_user_manager_object_info);
258 }