tizen: release 0.0.4
[platform/core/system/tlm.git] / src / sessiond / tlm-session.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of tlm (Tizen Login Manager)
5  *
6  * Copyright (C) 2013-2014 Intel Corporation.
7  *
8  * Contact: Amarnath Valluri <amarnath.valluri@linux.intel.com>
9  *          Jussi Laako <jussi.laako@linux.intel.com>
10  *          Imran Zaman <imran.zaman@intel.com>
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25  * 02110-1301 USA
26  */
27
28 #include <string.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <grp.h>
34 #include <stdio.h>
35 #include <signal.h>
36 #include <termios.h>
37 #include <libintl.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/wait.h>
41 #include <sys/ioctl.h>
42 #include <ctype.h>
43 #include <sys/socket.h>
44 #include <netdb.h>
45
46 #include "tlm-session.h"
47 #include "tlm-auth-session.h"
48 #include "common/tlm-log.h"
49 #include "common/tlm-utils.h"
50 #include "common/tlm-error.h"
51 #include "common/tlm-config-general.h"
52
53 G_DEFINE_TYPE (TlmSession, tlm_session, G_TYPE_OBJECT);
54
55 #define TLM_SESSION_PRIV(obj) \
56     G_TYPE_INSTANCE_GET_PRIVATE ((obj), TLM_TYPE_SESSION, TlmSessionPrivate)
57
58 enum {
59     PROP_0,
60     PROP_CONFIG,
61     PROP_SEAT,
62     PROP_SERVICE,
63     PROP_USERNAME,
64     PROP_ENVIRONMENT,
65     N_PROPERTIES
66 };
67 static GParamSpec *pspecs[N_PROPERTIES];
68
69 enum {
70     SIG_SESSION_CREATED,
71     SIG_SESSION_TERMINATED,
72     SIG_AUTHENTICATED,
73     SIG_SESSION_ERROR,
74     SIG_MAX
75 };
76 static guint signals[SIG_MAX];
77
78 struct _TlmSessionPrivate
79 {
80     TlmConfig *config;
81     pid_t child_pid;
82     uid_t tty_uid;
83     gid_t tty_gid;
84     struct termios stdin_state, stdout_state, stderr_state;
85     gchar *seat_id;
86     gchar *service;
87     gchar *username;
88     GHashTable *env_hash;
89     TlmAuthSession *auth_session;
90     int last_sig;
91     guint timer_id;
92     guint child_watch_id;
93     gchar *sessionid;
94     gboolean can_emit_signal;
95     gboolean is_child_up;
96     gboolean session_pause;
97 };
98
99 static void
100 _clear_session (TlmSession *session)
101 {
102     tlm_session_reset_tty (session);
103
104     if (session->priv->timer_id) {
105         g_source_remove (session->priv->timer_id);
106         session->priv->timer_id = 0;
107     }
108
109     if (session->priv->child_watch_id) {
110         g_source_remove (session->priv->child_watch_id);
111         session->priv->child_watch_id = 0;
112     }
113
114     if (session->priv->auth_session)
115         g_clear_object (&session->priv->auth_session);
116
117     if (session->priv->env_hash) {
118         g_hash_table_unref (session->priv->env_hash);
119         session->priv->env_hash = NULL;
120     }
121     g_clear_string (&session->priv->seat_id);
122     g_clear_string (&session->priv->service);
123     g_clear_string (&session->priv->username);
124     g_clear_string (&session->priv->sessionid);
125 }
126
127 static void
128 tlm_session_dispose (GObject *self)
129 {
130     TlmSession *session = TLM_SESSION(self);
131     TlmSessionPrivate *priv = session->priv;
132     DBG("disposing session: %s", priv->service);
133     priv->can_emit_signal = FALSE;
134
135     tlm_session_terminate (session);
136     while (priv->is_child_up)
137         g_main_context_iteration(NULL, TRUE);
138
139     g_clear_object (&session->priv->config);
140
141     G_OBJECT_CLASS (tlm_session_parent_class)->dispose (self);
142 }
143
144 static void
145 tlm_session_finalize (GObject *self)
146 {
147     //TlmSession *session = TLM_SESSION(self);
148     G_OBJECT_CLASS (tlm_session_parent_class)->finalize (self);
149 }
150
151 static void
152 _session_set_property (GObject *obj,
153                        guint property_id,
154                        const GValue *value,
155                        GParamSpec *pspec)
156 {
157     TlmSession *session = TLM_SESSION(obj);
158     TlmSessionPrivate *priv = TLM_SESSION_PRIV (session);
159
160     switch (property_id) {
161         case PROP_CONFIG:
162             priv->config = g_value_dup_object (value);
163             break;
164         case PROP_SEAT:
165             g_free (priv->seat_id);
166             priv->seat_id = g_value_dup_string (value);
167             break;
168         case PROP_SERVICE:
169             priv->service = g_value_dup_string (value);
170             break;
171         case PROP_USERNAME:
172             priv->username = g_value_dup_string (value);
173             break;
174         case PROP_ENVIRONMENT:
175             priv->env_hash = (GHashTable *) g_value_get_pointer (value);
176             if (priv->env_hash)
177                 g_hash_table_ref (priv->env_hash);
178             break;
179         default:
180             G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
181     }
182 }
183
184 static void
185 _session_get_property (GObject *obj,
186                        guint property_id,
187                        GValue *value,
188                        GParamSpec *pspec)
189 {
190     TlmSession *session = TLM_SESSION(obj);
191     TlmSessionPrivate *priv = TLM_SESSION_PRIV (session);
192
193     switch (property_id) {
194         case PROP_CONFIG:
195             g_value_set_object (value, priv->config);
196             break;
197         case PROP_SEAT:
198             g_value_set_string (value, priv->seat_id);
199             break;
200         case PROP_SERVICE:
201             g_value_set_string (value, priv->service);
202             break;
203         case PROP_USERNAME:
204             g_value_set_string (value, priv->username);
205             break;
206         case PROP_ENVIRONMENT:
207             g_value_set_pointer (value, priv->env_hash);
208             break;
209         default:
210             G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
211     }
212 }
213
214 static void
215 tlm_session_class_init (TlmSessionClass *klass)
216 {
217     GObjectClass *g_klass = G_OBJECT_CLASS (klass);
218
219     g_type_class_add_private (klass, sizeof (TlmSessionPrivate));
220
221     g_klass->dispose = tlm_session_dispose ;
222     g_klass->finalize = tlm_session_finalize;
223     g_klass->set_property = _session_set_property;
224     g_klass->get_property = _session_get_property;
225
226     pspecs[PROP_CONFIG] =
227         g_param_spec_object ("config",
228                              "config object",
229                              "Configuration object",
230                              TLM_TYPE_CONFIG,
231                              G_PARAM_READWRITE|
232                              G_PARAM_STATIC_STRINGS);
233     pspecs[PROP_SEAT] =
234         g_param_spec_string ("seat",
235                              "seat id",
236                              "Seat id string",
237                              NULL,
238                              G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
239     pspecs[PROP_SERVICE] =
240         g_param_spec_string ("service",
241                              "authentication service",
242                              "PAM service",
243                              NULL,
244                              G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
245     pspecs[PROP_USERNAME] =
246         g_param_spec_string ("username",
247                              "user name",
248                              "Unix user name of user to login",
249                              NULL,
250                              G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
251     pspecs[PROP_ENVIRONMENT] =
252         g_param_spec_pointer ("environment",
253                               "environment variables",
254                               "Environment variables for the session",
255                               G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
256
257     g_object_class_install_properties (g_klass, N_PROPERTIES, pspecs);
258
259     signals[SIG_SESSION_CREATED] = g_signal_new ("session-created",
260                                 TLM_TYPE_SESSION, G_SIGNAL_RUN_LAST,
261                                 0, NULL, NULL, NULL, G_TYPE_NONE,
262                                 1, G_TYPE_STRING);
263
264     signals[SIG_SESSION_TERMINATED] = g_signal_new ("session-terminated",
265                                 TLM_TYPE_SESSION, G_SIGNAL_RUN_LAST,
266                                 0, NULL, NULL, NULL, G_TYPE_NONE,
267                                 0, G_TYPE_NONE);
268
269     signals[SIG_AUTHENTICATED] = g_signal_new ("authenticated",
270                                 TLM_TYPE_SESSION, G_SIGNAL_RUN_LAST,
271                                 0, NULL, NULL, NULL, G_TYPE_NONE,
272                                 0, G_TYPE_NONE);
273
274     signals[SIG_SESSION_ERROR] = g_signal_new ("session-error",
275                                 TLM_TYPE_SESSION, G_SIGNAL_RUN_LAST,
276                                 0, NULL, NULL, NULL, G_TYPE_NONE,
277                                 1, G_TYPE_ERROR);
278
279 }
280
281 static void
282 tlm_session_init (TlmSession *session)
283 {
284     TlmSessionPrivate *priv = TLM_SESSION_PRIV (session);
285
286     priv->service = NULL;
287     priv->env_hash = NULL;
288     priv->auth_session = NULL;
289     priv->sessionid = NULL;
290     priv->child_watch_id = 0;
291     priv->is_child_up = FALSE;
292     priv->can_emit_signal = TRUE;
293     priv->config = tlm_config_new ();
294
295     session->priv = priv;
296
297     struct stat tty_stat;
298
299     if (fstat (0, &tty_stat) == 0) {
300         priv->tty_uid = tty_stat.st_uid;
301         priv->tty_gid = tty_stat.st_gid;
302     } else {
303         priv->tty_uid = 0;
304         priv->tty_gid = 0;
305     }
306
307     if (tcgetattr (0, &priv->stdin_state) ||
308         tcgetattr (1, &priv->stdout_state) ||
309         tcgetattr (2, &priv->stderr_state))
310         WARN ("Failed to retrieve initial terminal state");
311 }
312
313 static void
314 _setenv_to_session (const gchar *key, const gchar *val,
315                     TlmSessionPrivate *user_data)
316 {
317     TlmSessionPrivate *priv = (TlmSessionPrivate *) user_data;
318     if (priv->session_pause)
319         tlm_auth_session_set_env (priv->auth_session,
320                                   (const gchar *) key,
321                                   (const gchar *) val);
322     else
323         setenv ((const char *) key, (const char *) val, 1);
324 }
325
326 static gboolean
327 _set_terminal (TlmSessionPrivate *priv)
328 {
329     int i;
330     int tty_fd;
331     pid_t tty_pgid;
332     const char *tty_dev;
333     struct stat tty_stat;
334
335     tty_dev = ttyname (0);
336     DBG ("trying to setup TTY '%s'", tty_dev);
337     if (!tty_dev) {
338         WARN ("No TTY");
339         return FALSE;
340     }
341     if (access (tty_dev, R_OK|W_OK)) {
342         WARN ("TTY not accessible: %s", strerror(errno));
343         return FALSE;
344     }
345     if (lstat (tty_dev, &tty_stat)) {
346         WARN ("lstat() failed: %s", strerror(errno));
347         return FALSE;
348     }
349     if (tty_stat.st_nlink > 1 ||
350         !S_ISCHR (tty_stat.st_mode) ||
351         strncmp (tty_dev, "/dev/", 5)) {
352         WARN ("Invalid TTY");
353         return FALSE;
354     }
355
356     tty_fd = open (tty_dev, O_RDWR | O_NONBLOCK);
357     if (tty_fd < 0) {
358         WARN ("open() failed: %s", strerror(errno));
359         return FALSE;
360     }
361     if (!isatty (tty_fd)) {
362         close (tty_fd);
363         WARN ("isatty() failed");
364         return FALSE;
365     }
366     if (ioctl (tty_fd, TIOCSCTTY, 1))
367         WARN ("ioctl(TIOCSCTTY) failed: %s", strerror(errno));
368     tty_pgid = getpgid (getpid ());
369     if (ioctl (tty_fd, TIOCSPGRP, &tty_pgid)) {
370         WARN ("ioctl(TIOCSPGRP) failed: %s", strerror(errno));
371     }
372     /*if (tcsetpgrp (tty_fd, getpgrp ()))
373         WARN ("tcsetpgrp() failed: %s", strerror(errno));*/
374
375     // close all old handles
376     for (i = 0; i < tty_fd; i++)
377         close (i);
378     dup2 (tty_fd, 0);
379     dup2 (tty_fd, 1);
380     dup2 (tty_fd, 2);
381     close (tty_fd);
382
383     return TRUE;
384 }
385
386 static gboolean
387 _set_environment (TlmSessionPrivate *priv)
388 {
389         gchar **envlist = tlm_auth_session_get_envlist(priv->auth_session);
390         const gchar *home_dir = NULL, *shell = NULL;
391
392     if (envlist) {
393         gchar **env = 0;
394         for (env = envlist; *env != NULL; ++env) {
395             DBG ("ENV : %s", *env);
396             putenv(*env);
397             g_free (*env);
398         }
399         g_free (envlist);
400     }
401
402     const gchar *path = tlm_config_get_string (priv->config,
403                                                TLM_CONFIG_GENERAL,
404                                                TLM_CONFIG_GENERAL_SESSION_PATH);
405     if (!path)
406         path = "/usr/local/bin:/usr/bin:/bin";
407     _setenv_to_session ("PATH", path, priv);
408
409     _setenv_to_session ("USER", priv->username, priv);
410     _setenv_to_session ("LOGNAME", priv->username, priv);
411     home_dir = tlm_user_get_home_dir (priv->username);
412     if (home_dir) _setenv_to_session ("HOME", home_dir, priv);
413     shell = tlm_user_get_shell (priv->username);
414     if (shell) _setenv_to_session ("SHELL", shell, priv);
415     _setenv_to_session ("XDG_SEAT", priv->seat_id, priv);
416
417     const gchar *xdg_data_dirs =
418         tlm_config_get_string (priv->config,
419                                TLM_CONFIG_GENERAL,
420                                TLM_CONFIG_GENERAL_DATA_DIRS);
421     if (!xdg_data_dirs)
422         xdg_data_dirs = "/usr/share:/usr/local/share";
423     _setenv_to_session ("XDG_DATA_DIRS", xdg_data_dirs, priv);
424
425     if (priv->env_hash)
426         g_hash_table_foreach (priv->env_hash,
427                               (GHFunc) _setenv_to_session,
428                               priv);
429
430     return TRUE;
431 }
432
433 static void
434 _on_child_down_cb (
435         GPid  pid,
436         gint  status,
437         gpointer data)
438 {
439     g_spawn_close_pid (pid);
440
441     TlmSession *session = TLM_SESSION (data);
442
443     DBG ("Sessiond(%p) with pid (%d) closed with status %d", session, pid,
444             status);
445
446     session->priv->child_pid = 0;
447     session->priv->is_child_up = FALSE;
448     _clear_session (session);
449     if (session->priv->can_emit_signal)
450         g_signal_emit (session, signals[SIG_SESSION_TERMINATED], 0);
451 }
452
453 static void
454 _exec_user_session (
455                 TlmSession *session)
456 {
457     gint i;
458     const gchar *pattern = "('.*?'|\".*?\"|\\S+)";
459     const char *home;
460     const char *shell = NULL;
461     const char *env_shell = NULL;
462     gchar **args = NULL;
463     gchar **args_iter = NULL;
464     TlmSessionPrivate *priv = session->priv;
465     gchar **temp_strv = NULL;
466
467     priv = session->priv;
468     if (!priv->username)
469         priv->username = g_strdup (tlm_auth_session_get_username (
470                 priv->auth_session));
471     DBG ("session ID : %s", priv->sessionid);
472
473     priv->child_pid = fork ();
474     if (priv->child_pid) {
475         DBG ("establish handler for the child pid %u", priv->child_pid);
476         session->priv->child_watch_id = g_child_watch_add (priv->child_pid,
477                     (GChildWatchFunc)_on_child_down_cb, session);
478         session->priv->is_child_up = TRUE;
479         return;
480     }
481
482     /* ==================================
483      * this is child process here onwards
484      * ================================== */
485     gint open_max;
486     gint fd;
487
488     //close all open descriptors other than stdin, stdout, stderr
489     open_max = sysconf (_SC_OPEN_MAX);
490     for (fd = 3; fd < open_max; fd++)
491         fcntl (fd, F_SETFD, FD_CLOEXEC);
492
493     uid_t target_uid = tlm_user_get_uid (priv->username);
494     gid_t target_gid = tlm_user_get_gid (priv->username);
495
496     if (fchown (0, target_uid, -1)) {
497         WARN ("Changing TTY access rights failed");
498     }
499
500     /*if (getppid() == 1) {
501         if (setsid () == (pid_t) -1)
502             WARN ("setsid() failed: %s", strerror (errno));
503     } else {
504         if (setpgrp ())
505             WARN ("setpgrp() failed: %s", strerror (errno));
506     }*/
507
508     DBG ("old pgid=%u", getpgrp ());
509     if (setsid () == (pid_t) -1)
510         WARN ("setsid() failed: %s", strerror (errno));
511     DBG ("new pgid=%u", getpgrp());
512
513     if (tlm_config_get_boolean (priv->config,
514                                 TLM_CONFIG_GENERAL,
515                                 TLM_CONFIG_GENERAL_SETUP_TERMINAL,
516                                 FALSE)) {
517         /* usually terminal settings are handled by PAM */
518         _set_terminal (priv);
519     }
520
521     if (initgroups (priv->username, target_gid))
522         WARN ("initgroups() failed: %s", strerror(errno));
523     if (setregid (target_gid, target_gid))
524         WARN ("setregid() failed: %s", strerror(errno));
525     if (setreuid (target_uid, target_uid))
526         WARN ("setreuid() failed: %s", strerror(errno));
527
528     int grouplist_len = NGROUPS_MAX;
529     gid_t grouplist[NGROUPS_MAX];
530     grouplist_len = getgroups (grouplist_len, grouplist);
531     DBG ("group membership:");
532     for (i = 0; i < grouplist_len; i++)
533         DBG ("\t%s", getgrgid (grouplist[i])->gr_name);
534
535     DBG (" state:\n\truid=%d, euid=%d, rgid=%d, egid=%d (%s)",
536          getuid(), geteuid(), getgid(), getegid(), priv->username);
537     _set_environment (priv);
538     umask(0700);
539
540     home = getenv("HOME");
541     if (home) {
542         DBG ("changing directory to : %s", home);
543         if (chdir (home) < 0)
544             WARN ("Failed to change directroy : %s", strerror (errno));
545     } else WARN ("Could not get home directory");
546
547     shell = tlm_config_get_string (priv->config,
548                                    TLM_CONFIG_GENERAL,
549                                    TLM_CONFIG_GENERAL_SESSION_CMD);
550     if (shell) {
551         DBG ("Session command : %s", shell);
552         temp_strv = g_regex_split_simple (pattern,
553                                           shell,
554                                           0,
555                                           G_REGEX_MATCH_NOTEMPTY);
556     }
557
558     if (temp_strv) {
559         gchar **temp_iter;
560
561         args = g_new0 (gchar *, g_strv_length (temp_strv));
562         for (temp_iter = temp_strv, args_iter = args;
563                 *temp_iter != NULL;
564                 temp_iter++) {
565             size_t item_len = 0;
566             gchar *item = g_strstrip (*temp_iter);
567
568             item_len = strlen (item);
569             if (item_len == 0) {
570                 continue;
571             }
572             if ((item[0] == '\"' && item[item_len - 1] == '\"') ||
573                     (item[0] == '\'' && item[item_len - 1] == '\'')) {
574                 item[item_len - 1] = '\0';
575                 memmove (item, item + 1, item_len - 1);
576             }
577             *args_iter = g_strcompress (item);
578             args_iter++;
579         }
580         g_strfreev (temp_strv);
581     } else if ((env_shell = getenv("SHELL"))){
582         /* use shell if no override configured */
583         args = g_new0 (gchar *, 2);
584         args[0] = g_strdup (env_shell);
585     } else {
586         /* in case shell is not defined, fall back to systemd --user */
587         args = g_new0 (gchar *, 3);
588         args[0] = g_strdup ("systemd");
589         args[1] = g_strdup ("--user");
590     }
591
592     DBG ("executing: ");
593     args_iter = args;
594     while (args_iter && *args_iter) {
595         DBG ("\targv[%d]: %s", i, *args_iter);
596         args_iter++; i++;
597     }
598     execvp (args[0], args);
599     /* we reach here only in case of error */
600     g_strfreev (args);
601     DBG ("execl(): %s", strerror(errno));
602     exit (0);
603 }
604
605 TlmSession *
606 tlm_session_new ()
607 {
608     DBG ("Session New");
609     return g_object_new (TLM_TYPE_SESSION, NULL);
610 }
611
612 gboolean
613 tlm_session_start (TlmSession *session,
614                    const gchar *seat_id, const gchar *service,
615                    const gchar *username, const gchar *password,
616                    GHashTable *environment)
617 {
618         GError *error = NULL;
619         g_return_val_if_fail (session && TLM_IS_SESSION(session), FALSE);
620     TlmSessionPrivate *priv = TLM_SESSION_PRIV(session);
621
622     if (!seat_id || !service || !username) {
623         error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SESSION_CREATION_FAILURE,
624                 "Unable to create PAM sesssion as input data is invalid "
625                 "seatid(%p) service(%p) username(%p)", seat_id, service,
626                 username);
627         g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
628         g_error_free (error);
629         return FALSE;
630     }
631
632     g_object_set (G_OBJECT (session), "seat", seat_id, "service", service,
633             "username", username, "environment", environment, NULL);
634
635     priv->auth_session = tlm_auth_session_new (priv->service, priv->username,
636             password);
637
638     if (!priv->auth_session) {
639         error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SESSION_CREATION_FAILURE,
640                 "Unable to create PAM sesssion");
641         g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
642         g_error_free (error);
643         return FALSE;
644     }
645
646     tlm_auth_session_putenv (priv->auth_session, "XDG_SEAT", priv->seat_id);
647
648     if (!tlm_auth_session_authenticate (priv->auth_session, &error)) {
649         if (error) {
650             //consistant error message flow
651             GError *err = TLM_GET_ERROR_FOR_ID (
652                     TLM_ERROR_SESSION_CREATION_FAILURE,
653                     "%d:%s", error->code, error->message);
654             g_error_free (error);
655             error = err;
656         } else {
657             error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SESSION_CREATION_FAILURE,
658                     "Unable to authenticate PAM sesssion");
659         }
660         g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
661         g_error_free (error);
662         return FALSE;
663     }
664     g_signal_emit (session, signals[SIG_AUTHENTICATED], 0);
665
666     priv->session_pause =  tlm_config_get_boolean (priv->config,
667                                              TLM_CONFIG_GENERAL,
668                                              TLM_CONFIG_GENERAL_PAUSE_SESSION,
669                                              FALSE);
670     if (priv->session_pause) {
671         _set_environment (priv);
672         umask(0700);
673     }
674
675     if (!tlm_auth_session_open (priv->auth_session, &error)) {
676         if (!error) {
677             error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SESSION_CREATION_FAILURE,
678                     "Unable to open PAM sesssion");
679         }
680         g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
681         g_error_free (error);
682         return FALSE;
683     }
684     priv->sessionid = g_strdup (tlm_auth_session_get_sessionid (
685             priv->auth_session));
686     tlm_utils_log_utmp_entry (priv->username);
687     if (!priv->session_pause)
688         _exec_user_session (session);
689     g_signal_emit (session, signals[SIG_SESSION_CREATED], 0, priv->sessionid);
690     return TRUE;
691 }
692
693 static gboolean
694 _terminate_timeout (gpointer user_data)
695 {
696     TlmSession *session = TLM_SESSION(user_data);
697     TlmSessionPrivate *priv = TLM_SESSION_PRIV(session);
698
699     switch (priv->last_sig)
700     {
701         case SIGHUP:
702             DBG ("child %u didn't respond to SIGHUP, sending SIGTERM",
703                  priv->child_pid);
704             if (killpg (getpgid (priv->child_pid), SIGTERM))
705                 WARN ("killpg(%u, SIGTERM): %s",
706                       getpgid (priv->child_pid),
707                       strerror(errno));
708             priv->last_sig = SIGTERM;
709             return G_SOURCE_CONTINUE;
710         case SIGTERM:
711             DBG ("child %u didn't respond to SIGTERM, sending SIGKILL",
712                  priv->child_pid);
713             if (killpg (getpgid (priv->child_pid), SIGKILL))
714                 WARN ("killpg(%u, SIGKILL): %s",
715                       getpgid (priv->child_pid),
716                       strerror(errno));
717             priv->last_sig = SIGKILL;
718             return G_SOURCE_CONTINUE;
719         case SIGKILL:
720             DBG ("child %u didn't respond to SIGKILL, process is stuck in kernel",
721                  priv->child_pid);
722             priv->timer_id = 0;
723             _clear_session (session);
724             if (session->priv->can_emit_signal) {
725                 GError *error = TLM_GET_ERROR_FOR_ID (
726                         TLM_ERROR_SESSION_TERMINATION_FAILURE,
727                         "Unable to terminate session - process is stuck"
728                         " in kernel");
729                 g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
730                 g_error_free (error);
731             }
732             return G_SOURCE_REMOVE;
733         default:
734             WARN ("%d has unknown signaling state %d",
735                   priv->child_pid,
736                   priv->last_sig);
737     }
738     return G_SOURCE_REMOVE;
739 }
740
741 void
742 tlm_session_terminate (TlmSession *session)
743 {
744     g_return_if_fail (session && TLM_IS_SESSION(session));
745     TlmSessionPrivate *priv = TLM_SESSION_PRIV(session);
746
747     DBG ("Session Terminate");
748
749     if (!priv->is_child_up) {
750         DBG ("no child process is running - closing pam session");
751         _clear_session (session);
752         if (session->priv->can_emit_signal)
753             g_signal_emit (session, signals[SIG_SESSION_TERMINATED], 0);
754         return;
755     }
756
757     if (killpg (getpgid (priv->child_pid), SIGHUP) < 0)
758         WARN ("kill(%u, SIGHUP): %s",
759               getpgid (priv->child_pid),
760               strerror(errno));
761     priv->last_sig = SIGHUP;
762     priv->timer_id = g_timeout_add_seconds (
763             tlm_config_get_uint (priv->config, TLM_CONFIG_GENERAL,
764                     TLM_CONFIG_GENERAL_TERMINATE_TIMEOUT, 3),
765             _terminate_timeout,
766             session);
767 }
768
769 void
770 tlm_session_reset_tty (TlmSession *session)
771 {
772     TlmSessionPrivate *priv = TLM_SESSION_PRIV(session);
773
774     if (fchown (0, priv->tty_uid, priv->tty_gid))
775         WARN ("Changing TTY access rights failed");
776     if (tcflush (0, TCIOFLUSH) ||
777         tcflush (1, TCIOFLUSH) ||
778         tcflush (2, TCIOFLUSH))
779         WARN ("Flushing stdio failed");
780     pid_t pgid = getpgid (getpid ());
781     if (tcsetpgrp (0, pgid) || tcsetpgrp (1, pgid) || tcsetpgrp (2, pgid))
782         WARN ("Change TTY controlling process failed");
783     if (tcsetattr (0, TCSANOW, &priv->stdin_state) ||
784         tcsetattr (1, TCSANOW, &priv->stdout_state) ||
785         tcsetattr (2, TCSANOW, &priv->stderr_state))
786         WARN ("Restoring TTY settings failed");
787 }
788