1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of tlm (Tizen Login Manager)
6 * Copyright (C) 2013 Intel Corporation.
8 * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
9 * Jussi Laako <jussi.laako@linux.intel.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
27 #include "tlm-manager.h"
30 #include "tlm-account-plugin.h"
31 #include "tlm-auth-plugin.h"
32 #include "tlm-config.h"
33 #include "tlm-config-general.h"
34 #include "tlm-dbus-observer.h"
35 #include "tlm-utils.h"
43 G_DEFINE_TYPE (TlmManager, tlm_manager, G_TYPE_OBJECT);
45 #define TLM_MANAGER_PRIV(obj) \
46 G_TYPE_INSTANCE_GET_PRIVATE ((obj), TLM_TYPE_MANAGER, TlmManagerPrivate)
48 #define LOGIND_BUS_NAME "org.freedesktop.login1"
49 #define LOGIND_OBJECT_PATH "/org/freedesktop/login1"
50 #define LOGIND_MANAGER_IFACE LOGIND_BUS_NAME".Manager"
52 struct _TlmManagerPrivate
54 GDBusConnection *connection;
56 GHashTable *seats; /* { gchar*:TlmSeat* } */
57 TlmDbusObserver *dbus_observer; /* dbus observer accessed by root only */
58 TlmAccountPlugin *account_plugin;
64 guint seat_removed_id;
72 static GParamSpec *pspecs[N_PROPERTIES];
81 static guint signals[SIG_MAX];
84 _unref_auth_plugins (gpointer data)
86 GObject *plugin = G_OBJECT (data);
88 g_object_unref (plugin);
92 tlm_manager_dispose (GObject *self)
94 TlmManager *manager = TLM_MANAGER(self);
96 DBG("disposing manager");
98 if (manager->priv->dbus_observer) {
99 g_object_unref (manager->priv->dbus_observer);
100 manager->priv->dbus_observer = NULL;
103 if (manager->priv->is_started) {
104 tlm_manager_stop (manager);
107 if (manager->priv->seats) {
108 g_hash_table_unref (manager->priv->seats);
109 manager->priv->seats = NULL;
112 g_clear_object (&manager->priv->account_plugin);
113 g_clear_object (&manager->priv->config);
115 if (manager->priv->auth_plugins) {
116 g_list_free_full(manager->priv->auth_plugins, _unref_auth_plugins);
119 g_clear_string (&manager->priv->initial_user);
121 G_OBJECT_CLASS (tlm_manager_parent_class)->dispose (self);
125 tlm_manager_finalize (GObject *self)
127 G_OBJECT_CLASS (tlm_manager_parent_class)->finalize (self);
131 _manager_set_property (GObject *obj,
136 TlmManager *manager = TLM_MANAGER (obj);
138 switch (property_id) {
139 case PROP_INITIAL_USER:
140 manager->priv->initial_user = g_value_dup_string (value);
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
148 _manager_get_property (GObject *obj,
153 TlmManager *manager = TLM_MANAGER (obj);
155 switch (property_id) {
156 case PROP_INITIAL_USER:
157 g_value_set_string (value, manager->priv->initial_user);
160 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
165 tlm_manager_constructor (GType gtype, guint n_prop, GObjectConstructParam *prop)
167 static GObject *manager = NULL; /* Singleton */
169 if (manager != NULL) return g_object_ref (manager);
171 manager = G_OBJECT_CLASS (tlm_manager_parent_class)->
172 constructor (gtype, n_prop, prop);
173 g_object_add_weak_pointer (G_OBJECT(manager), (gpointer*)&manager);
179 tlm_manager_class_init (TlmManagerClass *klass)
181 GObjectClass *g_klass = G_OBJECT_CLASS (klass);
183 g_type_class_add_private (klass, sizeof(TlmManagerPrivate));
185 g_klass->constructor = tlm_manager_constructor;
186 g_klass->dispose = tlm_manager_dispose ;
187 g_klass->finalize = tlm_manager_finalize;
188 g_klass->set_property = _manager_set_property;
189 g_klass->get_property = _manager_get_property;
191 pspecs[PROP_INITIAL_USER] =
192 g_param_spec_string ("initial-user",
194 "User name for initial auto-login",
196 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_STATIC_STRINGS);
197 g_object_class_install_properties (g_klass, N_PROPERTIES, pspecs);
199 signals[SIG_SEAT_ADDED] = g_signal_new ("seat-added",
210 signals[SIG_SEAT_REMOVED] = g_signal_new ("seat-removed",
220 signals[SIG_MANAGER_STOPPED] = g_signal_new ("manager-stopped",
232 _manager_authenticate_cb (TlmAuthPlugin *plugin,
233 const gchar *seat_id,
234 const gchar *pam_service,
235 const gchar *username,
236 const gchar *password,
239 TlmManager *self = TLM_MANAGER (user_data);
240 TlmSeat *seat = NULL;
242 g_return_val_if_fail (self, FALSE);
244 DBG ("'%s' '%s' '%s' '%s'", seat_id, pam_service, username, password);
246 seat = g_hash_table_lookup (self->priv->seats, seat_id);
248 WARN ("Seat is not ready : %s", seat_id);
252 /* re login with new username */
253 return tlm_seat_switch_user (seat, pam_service, username, password, NULL);
257 _load_plugin_file (const gchar *file_path,
258 const gchar *plugin_name,
259 const gchar *plugin_type,
262 GObject *plugin = NULL;
264 DBG("Loading plugin %s", file_path);
265 GModule* plugin_module = g_module_open (file_path, G_MODULE_BIND_LAZY);
266 if (plugin_module == NULL) {
267 DBG("Plugin couldn't be opened: %s", g_module_error());
271 gchar* get_type_func = g_strdup_printf("tlm_%s_plugin_%s_get_type",
276 DBG("Resolving symbol %s", get_type_func);
277 gboolean symfound = g_module_symbol (plugin_module, get_type_func, &p);
278 g_free(get_type_func);
280 DBG("Symbol couldn't be resolved");
281 g_module_close (plugin_module);
285 DBG("Creating plugin object");
286 GType (*plugin_get_type_f)(void) = p;
287 plugin = g_object_new(plugin_get_type_f(), "config", config, NULL);
288 if (plugin == NULL) {
289 DBG("Plugin couldn't be created");
290 g_module_close (plugin_module);
293 g_module_make_resident (plugin_module);
301 const gchar *e_val = NULL;
303 e_val = g_getenv ("TLM_PLUGINS_DIR");
304 if (!e_val) return TLM_PLUGINS_DIR;
310 _load_accounts_plugin (TlmManager *self, const gchar *name)
312 const gchar *plugins_path = NULL;
313 gchar *plugin_file = NULL;
314 gchar *plugin_file_name = NULL;
315 GHashTable *accounts_config = NULL;
317 plugins_path = _get_plugins_path ();
319 accounts_config = tlm_config_get_group (self->priv->config, name);
321 plugin_file_name = g_strdup_printf ("libtlm-plugin-%s", name);
322 plugin_file = g_module_build_path(plugins_path, plugin_file_name);
323 g_free (plugin_file_name);
325 self->priv->account_plugin = TLM_ACCOUNT_PLUGIN(
326 _load_plugin_file (plugin_file, name, "account", accounts_config));
328 g_free (plugin_file);
332 _load_auth_plugins (TlmManager *self)
334 const gchar *plugins_path = NULL;
335 const gchar *plugin_file_name = NULL;
336 GDir *plugins_dir = NULL;
337 GError *error = NULL;
339 plugins_path = _get_plugins_path ();
341 DBG("plugins_path : %s", plugins_path);
342 plugins_dir = g_dir_open (plugins_path, 0, &error);
344 WARN ("Failed to open pluins folder '%s' : %s", plugins_path,
345 error ? error->message : "NULL");
346 g_error_free (error);
350 while ((plugin_file_name = g_dir_read_name (plugins_dir)) != NULL)
352 DBG("Plugin File : %s", plugin_file_name);
353 if (g_str_has_prefix (plugin_file_name, "libtlm-plugin-") &&
354 g_str_has_suffix (plugin_file_name, ".so"))
356 gchar *plugin_file_path = NULL;
357 gchar *plugin_name = NULL;
358 GHashTable *plugin_config = NULL;
359 GObject *plugin = NULL;
361 plugin_file_path = g_module_build_path(plugins_path,
364 if (!g_file_test (plugin_file_path,
365 G_FILE_TEST_IS_REGULAR && G_FILE_TEST_EXISTS)) {
366 WARN ("Ingnoring plugin : %s", plugin_file_path);
367 g_free (plugin_file_path);
371 DBG ("loading auth plugin '%s'", plugin_file_name);
373 plugin_name = g_strdup (plugin_file_name + 14); // truncate prefix
374 plugin_name[strlen(plugin_name) - 3] = '\0' ; // truncate suffix
376 plugin_config = tlm_config_get_group (self->priv->config,
379 plugin = _load_plugin_file (plugin_file_path,
384 g_signal_connect (plugin, "authenticate",
385 G_CALLBACK(_manager_authenticate_cb), self);
386 self->priv->auth_plugins = g_list_append (
387 self->priv->auth_plugins, plugin);
389 g_free (plugin_file_path);
390 g_free (plugin_name);
394 g_dir_close (plugins_dir);
399 tlm_manager_init (TlmManager *manager)
401 GError *error = NULL;
402 TlmManagerPrivate *priv = TLM_MANAGER_PRIV (manager);
404 priv->config = tlm_config_new ();
405 priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
406 if (!priv->connection) {
407 CRITICAL ("error getting system bus: %s", error->message);
408 g_error_free (error);
412 priv->seats = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
413 (GDestroyNotify)g_object_unref);
415 priv->account_plugin = NULL;
416 priv->auth_plugins = NULL;
418 manager->priv = priv;
420 _load_accounts_plugin (manager, tlm_config_get_string (priv->config,
421 TLM_CONFIG_GENERAL, TLM_CONFIG_GENERAL_ACCOUNTS_PLUGIN));
422 _load_auth_plugins (manager);
424 /* delete tlm runtime directory */
425 tlm_utils_delete_dir (TLM_DBUS_SOCKET_PATH);
426 priv->dbus_observer = TLM_DBUS_OBSERVER (tlm_dbus_observer_new (manager,
427 NULL, TLM_DBUS_ROOT_SOCKET_ADDRESS, getuid (),
428 DBUS_OBSERVER_ENABLE_ALL));
432 _prepare_user_cb (TlmSeat *seat, const gchar *user_name, gpointer user_data)
434 TlmManager *manager = TLM_MANAGER(user_data);
436 g_return_if_fail (user_data && TLM_IS_MANAGER(manager));
438 if (tlm_config_get_boolean (manager->priv->config,
440 TLM_CONFIG_GENERAL_PREPARE_DEFAULT,
442 DBG ("prepare for '%s'", user_name);
443 if (!tlm_manager_setup_guest_user (manager, user_name)) {
444 WARN ("failed to prepare for '%s'", user_name);
450 _add_seat (TlmManager *manager, const gchar *seat_id, const gchar *seat_path)
452 g_return_if_fail (manager && TLM_IS_MANAGER (manager));
454 TlmManagerPrivate *priv = TLM_MANAGER_PRIV (manager);
456 TlmSeat *seat = tlm_seat_new (priv->config,
459 g_signal_connect (seat,
461 G_CALLBACK (_prepare_user_cb),
464 g_hash_table_insert (priv->seats, g_strdup (seat_id), seat);
466 g_signal_emit (manager, signals[SIG_SEAT_ADDED], 0, seat, NULL);
468 if (tlm_config_get_boolean (priv->config,
470 TLM_CONFIG_GENERAL_AUTO_LOGIN,
472 priv->initial_user) {
473 DBG("intial auto-login for user '%s'", priv->initial_user);
474 if (!tlm_seat_create_session (seat,
479 WARN("Failed to create session for default user");
484 _manager_hashify_seats (TlmManager *manager, GVariant *hash_map)
487 gchar *id = 0, *path = 0;
489 g_return_if_fail (manager);
490 g_return_if_fail (hash_map);
492 g_variant_iter_init (&iter, hash_map);
493 while (g_variant_iter_next (&iter, "(so)", &id, &path)) {
494 DBG("found seat %s:%s", id, path);
495 _add_seat (manager, id, path);
502 _manager_sync_seats (TlmManager *manager)
504 GError *error = NULL;
505 GVariant *reply = NULL;
506 GVariant *hash_map = NULL;
508 g_return_if_fail (manager && manager->priv->connection);
510 reply = g_dbus_connection_call_sync (manager->priv->connection,
513 LOGIND_MANAGER_IFACE,
516 G_VARIANT_TYPE_TUPLE,
517 G_DBUS_CALL_FLAGS_NONE,
522 WARN ("failed to get attached seats: %s", error->message);
523 g_error_free (error);
527 g_variant_get (reply, "(@a(so))", &hash_map);
528 g_variant_unref (reply);
530 _manager_hashify_seats (manager, hash_map);
532 g_variant_unref (hash_map);
536 _manager_on_seat_added (GDBusConnection *connection,
538 const gchar *object_path,
540 const gchar *signal_name,
544 gchar *id = NULL, *path = NULL;
545 TlmManager *manager = TLM_MANAGER (userdata);
547 g_return_if_fail (manager);
548 g_return_if_fail (params);
550 g_variant_get (params, "(&s&o)", &id, &path);
551 g_variant_unref (params);
553 DBG("Seat added: %s:%s", id, path);
555 if (!g_hash_table_contains (manager->priv->seats, id)) {
556 _add_seat (manager, id, path);
563 _manager_on_seat_removed (GDBusConnection *connection,
565 const gchar *object_path,
567 const gchar *signal_name,
571 gchar *id = NULL, *path = NULL;
572 TlmManager *manager = TLM_MANAGER (userdata);
574 g_return_if_fail (manager);
575 g_return_if_fail (params);
577 g_variant_get (params, "(&s&o)", &id, path);
578 g_variant_unref (params);
580 DBG("Seat removed: %s:%s", id, path);
582 if (!g_hash_table_contains (manager->priv->seats, id)) {
583 g_hash_table_remove (manager->priv->seats, id);
584 g_signal_emit (manager, signals[SIG_SEAT_REMOVED], 0, id, NULL);
592 _manager_subscribe_seat_changes (TlmManager *manager)
594 TlmManagerPrivate *priv = manager->priv;
596 priv->seat_added_id = g_dbus_connection_signal_subscribe (
599 LOGIND_MANAGER_IFACE,
603 G_DBUS_SIGNAL_FLAGS_NONE,
604 _manager_on_seat_added,
607 priv->seat_removed_id = g_dbus_connection_signal_subscribe (
610 LOGIND_MANAGER_IFACE,
614 G_DBUS_SIGNAL_FLAGS_NONE,
615 _manager_on_seat_removed,
620 _manager_unsubsribe_seat_changes (TlmManager *manager)
622 if (manager->priv->seat_added_id) {
623 g_dbus_connection_signal_unsubscribe (manager->priv->connection,
624 manager->priv->seat_added_id);
625 manager->priv->seat_added_id = 0;
628 if (manager->priv->seat_removed_id) {
629 g_dbus_connection_signal_unsubscribe (manager->priv->connection,
630 manager->priv->seat_removed_id);
631 manager->priv->seat_removed_id = 0;
636 tlm_manager_start (TlmManager *manager)
638 g_return_val_if_fail (manager && TLM_IS_MANAGER (manager), FALSE);
640 _manager_sync_seats (manager);
641 _manager_subscribe_seat_changes (manager);
643 manager->priv->is_started = TRUE;
650 _session_terminated_cb (GObject *emitter, const gchar *seat_id,
653 g_return_val_if_fail (manager && TLM_IS_MANAGER (manager), TRUE);
654 DBG("seatid %s", seat_id);
656 g_hash_table_remove (manager->priv->seats, seat_id);
657 if (g_hash_table_size (manager->priv->seats) == 0) {
658 DBG ("signalling stopped");
659 g_signal_emit (manager, signals[SIG_MANAGER_STOPPED], 0);
666 tlm_manager_stop (TlmManager *manager)
668 g_return_val_if_fail (manager && TLM_IS_MANAGER (manager), FALSE);
670 _manager_unsubsribe_seat_changes (manager);
674 gboolean delayed = FALSE;
676 g_hash_table_iter_init (&iter, manager->priv->seats);
677 while (g_hash_table_iter_next (&iter, &key, &value)) {
678 DBG ("terminate seat '%s'", (const gchar *) key);
679 g_signal_connect_after ((TlmSeat *) value,
680 "session-terminated",
681 G_CALLBACK (_session_terminated_cb),
683 if (!tlm_seat_terminate_session ((TlmSeat *) value)) {
684 g_hash_table_remove (manager->priv->seats, key);
685 g_hash_table_iter_init (&iter, manager->priv->seats);
691 g_signal_emit (manager, signals[SIG_MANAGER_STOPPED], 0);
693 manager->priv->is_started = FALSE;
699 tlm_manager_setup_guest_user (TlmManager *manager, const gchar *user_name)
701 g_return_val_if_fail (manager && TLM_IS_MANAGER (manager), FALSE);
702 g_return_val_if_fail (manager->priv->account_plugin, FALSE);
704 if (tlm_account_plugin_is_valid_user (
705 manager->priv->account_plugin, user_name)) {
706 DBG("user account '%s' already existing, cleaning the home folder",
708 return tlm_account_plugin_cleanup_guest_user (
709 manager->priv->account_plugin, user_name, FALSE);
712 DBG("Asking plugin to setup guest user '%s'", user_name);
713 return tlm_account_plugin_setup_guest_user_account (
714 manager->priv->account_plugin, user_name);
719 tlm_manager_new (const gchar *initial_user)
721 return g_object_new (TLM_TYPE_MANAGER,
722 "initial-user", initial_user,
727 tlm_manager_get_seat (TlmManager *manager, const gchar *seat_id)
729 g_return_val_if_fail (manager && TLM_IS_MANAGER (manager), NULL);
731 return g_hash_table_lookup (manager->priv->seats, seat_id);
735 tlm_manager_sighup_received (TlmManager *manager)
737 g_return_if_fail (manager && TLM_IS_MANAGER (manager));
739 DBG ("sighup recvd. reload configuration and account plugin");
740 tlm_config_reload (manager->priv->config);
741 g_clear_object (&manager->priv->account_plugin);
742 _load_accounts_plugin (manager, tlm_config_get_string (
743 manager->priv->config, TLM_CONFIG_GENERAL,
744 TLM_CONFIG_GENERAL_ACCOUNTS_PLUGIN));