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-2014 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
35 #include "tlm-session-remote.h"
37 #include "tlm-error.h"
38 #include "tlm-utils.h"
39 #include "tlm-config-general.h"
40 #include "tlm-dbus-observer.h"
42 G_DEFINE_TYPE (TlmSeat, tlm_seat, G_TYPE_OBJECT);
44 #define TLM_SEAT_PRIV(obj) \
45 G_TYPE_INSTANCE_GET_PRIVATE ((obj), TLM_TYPE_SEAT, TlmSeatPrivate)
54 static GParamSpec *pspecs[N_PROPERTIES];
59 SIG_SESSION_TERMINATED,
63 static guint signals[SIG_MAX];
65 struct _TlmSeatPrivate
73 GHashTable *next_environment;
76 TlmSessionRemote *session;
77 TlmDbusObserver *dbus_observer; /* dbus server accessed only by user who has
79 TlmDbusObserver *prev_dbus_observer;
82 typedef struct _DelayClosure
88 GHashTable *environment;
92 _disconnect_session_signals (
96 _reset_next (TlmSeatPrivate *priv)
98 g_clear_string (&priv->next_service);
99 g_clear_string (&priv->next_user);
100 g_clear_string (&priv->next_password);
101 if (priv->next_environment) {
102 g_hash_table_unref (priv->next_environment);
103 priv->next_environment = NULL;
108 _handle_session_created (
110 const gchar *sessionid,
113 g_return_if_fail (self && TLM_IS_SEAT (self));
115 DBG ("sessionid: %s", sessionid);
117 g_signal_emit (self, signals[SIG_SESSION_CREATED], 0, self->priv->id);
119 g_clear_object (&self->priv->prev_dbus_observer);
123 _close_active_session (TlmSeat *self)
125 TlmSeatPrivate *priv = TLM_SEAT_PRIV (self);
126 _disconnect_session_signals (self);
128 g_clear_object (&priv->session);
132 _handle_session_terminated (
136 g_return_if_fail (self && TLM_IS_SEAT (self));
138 TlmSeat *seat = TLM_SEAT(self);
139 TlmSeatPrivate *priv = TLM_SEAT_PRIV(seat);
140 gboolean stop = FALSE;
142 DBG ("seat %p session %p", self, priv->session);
143 _close_active_session (seat);
146 signals[SIG_SESSION_TERMINATED],
151 DBG ("no relogin or switch user");
154 g_clear_object (&priv->dbus_observer);
156 if (tlm_config_get_boolean (priv->config,
158 TLM_CONFIG_GENERAL_X11_SESSION,
160 DBG ("X11 session termination");
161 if (kill (0, SIGTERM))
162 WARN ("Failed to send TERM signal to process tree");
166 if (tlm_config_get_boolean (priv->config,
168 TLM_CONFIG_GENERAL_AUTO_LOGIN,
170 seat->priv->next_user) {
171 DBG ("auto re-login with '%s'", seat->priv->next_user);
172 tlm_seat_create_session (seat,
173 seat->priv->next_service,
174 seat->priv->next_user,
175 seat->priv->next_password,
176 seat->priv->next_environment);
187 g_return_if_fail (self && TLM_IS_SEAT (self));
189 DBG ("Error : %d:%s", error->code, error->message);
190 g_signal_emit (self, signals[SIG_SESSION_ERROR], 0, error->code);
192 if (error->code == TLM_ERROR_PAM_AUTH_FAILURE ||
193 error->code == TLM_ERROR_SESSION_CREATION_FAILURE ||
194 error->code == TLM_ERROR_SESSION_TERMINATION_FAILURE) {
195 DBG ("Destroy the session in case of creation/termination failure");
196 _close_active_session (self);
197 g_clear_object (&self->priv->dbus_observer);
202 _disconnect_session_signals (
205 TlmSeatPrivate *priv = TLM_SEAT_PRIV (seat);
206 if (!priv->session) return;
207 DBG ("seat %p session %p", seat, priv->session);
209 g_signal_handlers_disconnect_by_func (G_OBJECT (priv->session),
210 _handle_session_created, seat);
211 g_signal_handlers_disconnect_by_func (G_OBJECT (priv->session),
212 _handle_session_terminated, seat);
213 g_signal_handlers_disconnect_by_func (G_OBJECT (priv->session),
214 _handle_error, seat);
218 _connect_session_signals (
221 TlmSeatPrivate *priv = TLM_SEAT_PRIV (seat);
222 DBG ("seat %p", seat);
223 /* Connect session signals to handlers */
224 g_signal_connect_swapped (priv->session, "session-created",
225 G_CALLBACK (_handle_session_created), seat);
226 g_signal_connect_swapped (priv->session, "session-terminated",
227 G_CALLBACK(_handle_session_terminated), seat);
228 g_signal_connect_swapped (priv->session, "session-error",
229 G_CALLBACK(_handle_error), seat);
233 _create_dbus_observer (
235 const gchar *username)
237 gchar *address = NULL;
240 if (!username) return FALSE;
242 uid = tlm_user_get_uid (username);
243 if (uid == -1) return FALSE;
245 address = g_strdup_printf ("unix:path=%s/%s-%d", TLM_DBUS_SOCKET_PATH,
246 seat->priv->id, uid);
247 seat->priv->dbus_observer = TLM_DBUS_OBSERVER (tlm_dbus_observer_new (
248 NULL, seat, address, uid,
249 DBUS_OBSERVER_ENABLE_LOGOUT_USER |
250 DBUS_OBSERVER_ENABLE_SWITCH_USER));
252 DBG ("created dbus obs: %p", seat->priv->dbus_observer);
253 return (seat->priv->dbus_observer != NULL);
257 tlm_seat_dispose (GObject *self)
259 TlmSeat *seat = TLM_SEAT(self);
261 DBG("disposing seat: %s", seat->priv->id);
263 g_clear_object (&seat->priv->dbus_observer);
264 g_clear_object (&seat->priv->prev_dbus_observer);
266 _disconnect_session_signals (seat);
267 if (seat->priv->session)
268 g_clear_object (&seat->priv->session);
269 if (seat->priv->config) {
270 g_object_unref (seat->priv->config);
271 seat->priv->config = NULL;
274 G_OBJECT_CLASS (tlm_seat_parent_class)->dispose (self);
278 tlm_seat_finalize (GObject *self)
280 TlmSeat *seat = TLM_SEAT(self);
281 TlmSeatPrivate *priv = TLM_SEAT_PRIV(seat);
283 g_clear_string (&priv->id);
284 g_clear_string (&priv->path);
288 G_OBJECT_CLASS (tlm_seat_parent_class)->finalize (self);
292 _seat_set_property (GObject *obj,
297 TlmSeat *seat = TLM_SEAT(obj);
298 TlmSeatPrivate *priv = TLM_SEAT_PRIV(seat);
300 switch (property_id) {
302 priv->config = g_value_dup_object (value);
305 priv->id = g_value_dup_string (value);
308 priv->path = g_value_dup_string (value);
311 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
316 _seat_get_property (GObject *obj,
321 TlmSeat *seat = TLM_SEAT(obj);
322 TlmSeatPrivate *priv = TLM_SEAT_PRIV(seat);
324 switch (property_id) {
326 g_value_set_object (value, priv->config);
329 g_value_set_string (value, priv->id);
332 g_value_set_string (value, priv->path);
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
340 tlm_seat_class_init (TlmSeatClass *klass)
342 GObjectClass *g_klass = G_OBJECT_CLASS (klass);
344 g_type_class_add_private (klass, sizeof (TlmSeatPrivate));
346 g_klass->dispose = tlm_seat_dispose ;
347 g_klass->finalize = tlm_seat_finalize;
348 g_klass->set_property = _seat_set_property;
349 g_klass->get_property = _seat_get_property;
351 pspecs[PROP_CONFIG] =
352 g_param_spec_object ("config",
354 "Configuration object",
356 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|
357 G_PARAM_STATIC_STRINGS);
359 g_param_spec_string ("id",
363 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|
364 G_PARAM_STATIC_STRINGS);
366 g_param_spec_string ("path",
368 "Seat Object path at logind",
370 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|
371 G_PARAM_STATIC_STRINGS);
372 g_object_class_install_properties (g_klass, N_PROPERTIES, pspecs);
374 signals[SIG_PREPARE_USER] = g_signal_new ("prepare-user",
384 signals[SIG_SESSION_CREATED] = g_signal_new ("session-created",
394 signals[SIG_SESSION_TERMINATED] = g_signal_new ("session-terminated",
404 signals[SIG_SESSION_ERROR] = g_signal_new ("session-error",
417 tlm_seat_init (TlmSeat *seat)
419 TlmSeatPrivate *priv = TLM_SEAT_PRIV (seat);
421 priv->id = priv->path = NULL;
422 priv->dbus_observer = priv->prev_dbus_observer = NULL;
427 tlm_seat_get_id (TlmSeat *seat)
429 g_return_val_if_fail (seat && TLM_IS_SEAT (seat), NULL);
431 return (const gchar*) seat->priv->id;
435 tlm_seat_switch_user (TlmSeat *seat,
436 const gchar *service,
437 const gchar *username,
438 const gchar *password,
439 GHashTable *environment)
441 g_return_val_if_fail (seat && TLM_IS_SEAT(seat), FALSE);
443 TlmSeatPrivate *priv = TLM_SEAT_PRIV (seat);
445 if (!priv->session) {
446 return tlm_seat_create_session (seat, service, username, password,
451 priv->next_service = g_strdup (service);
452 priv->next_user = g_strdup (username);
453 priv->next_password = g_strdup (password);
454 priv->next_environment = g_hash_table_ref (environment);
456 return tlm_seat_terminate_session (seat);
460 _build_user_name (const gchar *template, const gchar *seat_id)
467 if (strncmp (seat_id, "seat", 4) == 0)
468 seat_num = atoi (seat_id + 4);
470 WARN ("Unrecognized seat id format");
472 str = g_string_sized_new (16);
473 while (*pptr != '\0') {
478 g_string_append_printf (str, "%d", seat_num);
481 g_string_append (str, seat_id);
487 g_string_append_c (str, *pptr);
491 out = g_string_free (str, FALSE);
496 _delayed_session (gpointer user_data)
498 DelayClosure *delay_closure = (DelayClosure *) user_data;
500 g_return_val_if_fail (user_data, FALSE);
502 tlm_seat_create_session (delay_closure->seat,
503 delay_closure->service,
504 delay_closure->username,
505 delay_closure->password,
506 delay_closure->environment);
507 g_object_unref (delay_closure->seat);
508 g_free (delay_closure->service);
509 g_free (delay_closure->username);
510 g_free (delay_closure->password);
511 if (delay_closure->environment)
512 g_hash_table_unref (delay_closure->environment);
513 g_slice_free (DelayClosure, delay_closure);
518 tlm_seat_create_session (TlmSeat *seat,
519 const gchar *service,
520 const gchar *username,
521 const gchar *password,
522 GHashTable *environment)
524 g_return_val_if_fail (seat && TLM_IS_SEAT(seat), FALSE);
525 TlmSeatPrivate *priv = TLM_SEAT_PRIV (seat);
527 if (priv->session != NULL) {
528 g_signal_emit (seat, signals[SIG_SESSION_ERROR], 0,
529 TLM_ERROR_SESSION_ALREADY_EXISTS);
533 if (g_get_monotonic_time () - priv->prev_time < 1000000) {
534 DBG ("short time relogin");
535 priv->prev_time = g_get_monotonic_time ();
537 if (priv->prev_count > 3) {
538 WARN ("relogins spinning too fast, delay...");
539 DelayClosure *delay_closure = g_slice_new0 (DelayClosure);
540 delay_closure->seat = g_object_ref (seat);
541 delay_closure->service = g_strdup (service);
542 delay_closure->username = g_strdup (username);
543 delay_closure->password = g_strdup (password);
545 delay_closure->environment = g_hash_table_ref (environment);
546 g_timeout_add_seconds (10, _delayed_session, delay_closure);
550 priv->prev_time = g_get_monotonic_time ();
551 priv->prev_count = 1;
554 gchar *default_user = NULL;
557 service = tlm_config_get_string (priv->config,
559 username ? TLM_CONFIG_GENERAL_PAM_SERVICE : TLM_CONFIG_GENERAL_DEFAULT_PAM_SERVICE);
561 service = tlm_config_get_string (priv->config,
563 username ? TLM_CONFIG_GENERAL_PAM_SERVICE : TLM_CONFIG_GENERAL_DEFAULT_PAM_SERVICE);
566 const gchar *name_tmpl =
567 tlm_config_get_string (priv->config,
569 TLM_CONFIG_GENERAL_DEFAULT_USER);
571 name_tmpl = tlm_config_get_string (priv->config,
573 TLM_CONFIG_GENERAL_DEFAULT_USER);
574 if (name_tmpl) default_user = _build_user_name (name_tmpl, priv->id);
577 signals[SIG_PREPARE_USER],
582 priv->session = tlm_session_remote_new (priv->config,
585 default_user ? default_user : username);
586 if (!priv->session) {
587 g_signal_emit (seat, signals[SIG_SESSION_ERROR], 0,
588 TLM_ERROR_SESSION_CREATION_FAILURE);
592 /*It is needed to handle switch user case which completes after new session
594 seat->priv->prev_dbus_observer = seat->priv->dbus_observer;
595 seat->priv->dbus_observer = NULL;
596 if (!_create_dbus_observer (seat, default_user ? default_user : username)) {
597 g_object_unref (priv->session);
598 g_signal_emit (seat, signals[SIG_SESSION_ERROR], 0,
599 TLM_ERROR_DBUS_SERVER_START_FAILURE);
603 _connect_session_signals (seat);
604 tlm_session_remote_create (priv->session, password, environment);
609 tlm_seat_terminate_session (TlmSeat *seat)
611 g_return_val_if_fail (seat && TLM_IS_SEAT(seat), FALSE);
612 g_return_val_if_fail (seat->priv, FALSE);
614 if (!seat->priv->session ||
615 !tlm_session_remote_terminate (seat->priv->session)) {
616 WARN ("No active session to terminate");
617 g_signal_emit (seat, signals[SIG_SESSION_ERROR], 0,
618 TLM_ERROR_SESSION_NOT_VALID);
626 tlm_seat_new (TlmConfig *config,
630 TlmSeat *seat = g_object_new (TLM_TYPE_SEAT,