CTRL-C caused the weston process to exit
[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 #include <linux/kd.h>
46
47 #include <glib.h>
48 #include <glib/gstdio.h>
49
50 #include "tlm-session.h"
51 #include "tlm-auth-session.h"
52 #include "common/tlm-log.h"
53 #include "common/tlm-utils.h"
54 #include "common/tlm-error.h"
55 #include "common/tlm-config-general.h"
56 #include "common/tlm-config-seat.h"
57
58 G_DEFINE_TYPE (TlmSession, tlm_session, G_TYPE_OBJECT);
59
60 #define TLM_SESSION_PRIV(obj) \
61     G_TYPE_INSTANCE_GET_PRIVATE ((obj), TLM_TYPE_SESSION, TlmSessionPrivate)
62
63 #ifndef KDSKBMUTE
64 #define KDSKBMUTE   0x4B51
65 #endif
66
67 enum {
68     PROP_0,
69     PROP_CONFIG,
70     PROP_SEAT,
71     PROP_SERVICE,
72     PROP_USERNAME,
73     PROP_ENVIRONMENT,
74     N_PROPERTIES
75 };
76 static GParamSpec *pspecs[N_PROPERTIES];
77
78 enum {
79     SIG_SESSION_CREATED,
80     SIG_SESSION_TERMINATED,
81     SIG_AUTHENTICATED,
82     SIG_SESSION_ERROR,
83     SIG_MAX
84 };
85 static guint signals[SIG_MAX];
86
87 struct _TlmSessionPrivate
88 {
89     TlmConfig *config;
90     pid_t child_pid;
91     uid_t tty_uid;
92     gid_t tty_gid;
93     unsigned vtnr;
94     struct termios stdin_state, stdout_state, stderr_state;
95     gchar *seat_id;
96     gchar *service;
97     gchar *username;
98     GHashTable *env_hash;
99     TlmAuthSession *auth_session;
100     int last_sig;
101     guint timer_id;
102     guint child_watch_id;
103     gchar *sessionid;
104     gchar *xdg_runtime_dir;
105     gboolean setup_runtime_dir;
106     gboolean can_emit_signal;
107     gboolean is_child_up;
108     gboolean session_pause;
109 };
110
111 static void
112 _clear_session (TlmSession *session)
113 {
114     tlm_session_reset_tty (session);
115     if (session->priv->setup_runtime_dir)
116         tlm_utils_delete_dir (session->priv->xdg_runtime_dir);
117
118     if (session->priv->timer_id) {
119         g_source_remove (session->priv->timer_id);
120         session->priv->timer_id = 0;
121     }
122
123     if (session->priv->child_watch_id) {
124         g_source_remove (session->priv->child_watch_id);
125         session->priv->child_watch_id = 0;
126     }
127
128     if (session->priv->auth_session)
129         g_clear_object (&session->priv->auth_session);
130
131     if (session->priv->env_hash) {
132         g_hash_table_unref (session->priv->env_hash);
133         session->priv->env_hash = NULL;
134     }
135     g_clear_string (&session->priv->seat_id);
136     g_clear_string (&session->priv->service);
137     g_clear_string (&session->priv->username);
138     g_clear_string (&session->priv->sessionid);
139     g_clear_string (&session->priv->xdg_runtime_dir);
140 }
141
142 static void
143 tlm_session_dispose (GObject *self)
144 {
145     TlmSession *session = TLM_SESSION(self);
146     TlmSessionPrivate *priv = session->priv;
147     DBG("disposing session: %s", priv->service);
148     priv->can_emit_signal = FALSE;
149
150     tlm_session_terminate (session);
151     while (priv->is_child_up)
152         g_main_context_iteration(NULL, TRUE);
153
154     g_clear_object (&session->priv->config);
155
156     G_OBJECT_CLASS (tlm_session_parent_class)->dispose (self);
157 }
158
159 static void
160 tlm_session_finalize (GObject *self)
161 {
162     //TlmSession *session = TLM_SESSION(self);
163     G_OBJECT_CLASS (tlm_session_parent_class)->finalize (self);
164 }
165
166 static void
167 _session_set_property (GObject *obj,
168                        guint property_id,
169                        const GValue *value,
170                        GParamSpec *pspec)
171 {
172     TlmSession *session = TLM_SESSION(obj);
173     TlmSessionPrivate *priv = TLM_SESSION_PRIV (session);
174
175     switch (property_id) {
176         case PROP_CONFIG:
177             priv->config = g_value_dup_object (value);
178             break;
179         case PROP_SEAT:
180             g_free (priv->seat_id);
181             priv->seat_id = g_value_dup_string (value);
182             break;
183         case PROP_SERVICE:
184             priv->service = g_value_dup_string (value);
185             break;
186         case PROP_USERNAME:
187             priv->username = g_value_dup_string (value);
188             break;
189         case PROP_ENVIRONMENT:
190             priv->env_hash = (GHashTable *) g_value_get_pointer (value);
191             if (priv->env_hash)
192                 g_hash_table_ref (priv->env_hash);
193             break;
194         default:
195             G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
196     }
197 }
198
199 static void
200 _session_get_property (GObject *obj,
201                        guint property_id,
202                        GValue *value,
203                        GParamSpec *pspec)
204 {
205     TlmSession *session = TLM_SESSION(obj);
206     TlmSessionPrivate *priv = TLM_SESSION_PRIV (session);
207
208     switch (property_id) {
209         case PROP_CONFIG:
210             g_value_set_object (value, priv->config);
211             break;
212         case PROP_SEAT:
213             g_value_set_string (value, priv->seat_id);
214             break;
215         case PROP_SERVICE:
216             g_value_set_string (value, priv->service);
217             break;
218         case PROP_USERNAME:
219             g_value_set_string (value, priv->username);
220             break;
221         case PROP_ENVIRONMENT:
222             g_value_set_pointer (value, priv->env_hash);
223             break;
224         default:
225             G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
226     }
227 }
228
229 static void
230 tlm_session_class_init (TlmSessionClass *klass)
231 {
232     GObjectClass *g_klass = G_OBJECT_CLASS (klass);
233
234     g_type_class_add_private (klass, sizeof (TlmSessionPrivate));
235
236     g_klass->dispose = tlm_session_dispose ;
237     g_klass->finalize = tlm_session_finalize;
238     g_klass->set_property = _session_set_property;
239     g_klass->get_property = _session_get_property;
240
241     pspecs[PROP_CONFIG] =
242         g_param_spec_object ("config",
243                              "config object",
244                              "Configuration object",
245                              TLM_TYPE_CONFIG,
246                              G_PARAM_READWRITE|
247                              G_PARAM_STATIC_STRINGS);
248     pspecs[PROP_SEAT] =
249         g_param_spec_string ("seat",
250                              "seat id",
251                              "Seat id string",
252                              NULL,
253                              G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
254     pspecs[PROP_SERVICE] =
255         g_param_spec_string ("service",
256                              "authentication service",
257                              "PAM service",
258                              NULL,
259                              G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
260     pspecs[PROP_USERNAME] =
261         g_param_spec_string ("username",
262                              "user name",
263                              "Unix user name of user to login",
264                              NULL,
265                              G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
266     pspecs[PROP_ENVIRONMENT] =
267         g_param_spec_pointer ("environment",
268                               "environment variables",
269                               "Environment variables for the session",
270                               G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
271
272     g_object_class_install_properties (g_klass, N_PROPERTIES, pspecs);
273
274     signals[SIG_SESSION_CREATED] = g_signal_new ("session-created",
275                                 TLM_TYPE_SESSION, G_SIGNAL_RUN_LAST,
276                                 0, NULL, NULL, NULL, G_TYPE_NONE,
277                                 1, G_TYPE_STRING);
278
279     signals[SIG_SESSION_TERMINATED] = g_signal_new ("session-terminated",
280                                 TLM_TYPE_SESSION, G_SIGNAL_RUN_LAST,
281                                 0, NULL, NULL, NULL, G_TYPE_NONE,
282                                 0, G_TYPE_NONE);
283
284     signals[SIG_AUTHENTICATED] = g_signal_new ("authenticated",
285                                 TLM_TYPE_SESSION, G_SIGNAL_RUN_LAST,
286                                 0, NULL, NULL, NULL, G_TYPE_NONE,
287                                 0, G_TYPE_NONE);
288
289     signals[SIG_SESSION_ERROR] = g_signal_new ("session-error",
290                                 TLM_TYPE_SESSION, G_SIGNAL_RUN_LAST,
291                                 0, NULL, NULL, NULL, G_TYPE_NONE,
292                                 1, G_TYPE_ERROR);
293
294 }
295
296 static void
297 tlm_session_init (TlmSession *session)
298 {
299     TlmSessionPrivate *priv = TLM_SESSION_PRIV (session);
300
301     priv->service = NULL;
302     priv->env_hash = NULL;
303     priv->auth_session = NULL;
304     priv->sessionid = NULL;
305     priv->child_watch_id = 0;
306     priv->is_child_up = FALSE;
307     priv->can_emit_signal = TRUE;
308     priv->config = tlm_config_new ();
309
310     session->priv = priv;
311
312     struct stat tty_stat;
313
314     if (fstat (0, &tty_stat) == 0) {
315         priv->tty_uid = tty_stat.st_uid;
316         priv->tty_gid = tty_stat.st_gid;
317     } else {
318         priv->tty_uid = 0;
319         priv->tty_gid = 0;
320     }
321
322     if (tcgetattr (0, &priv->stdin_state) ||
323         tcgetattr (1, &priv->stdout_state) ||
324         tcgetattr (2, &priv->stderr_state))
325         WARN ("Failed to retrieve initial terminal state");
326 }
327
328 static void
329 _setenv_to_session (const gchar *key, const gchar *val,
330                     TlmSessionPrivate *user_data)
331 {
332     TlmSessionPrivate *priv = (TlmSessionPrivate *) user_data;
333     if (priv->session_pause)
334         tlm_auth_session_set_env (priv->auth_session,
335                                   (const gchar *) key,
336                                   (const gchar *) val);
337     else
338         setenv ((const char *) key, (const char *) val, 1);
339 }
340
341 static gboolean
342 _set_terminal (TlmSessionPrivate *priv)
343 {
344     gboolean res = TRUE;
345     int i;
346     int tty_fd;
347     pid_t tty_pgid;
348     gchar *tty_dev = NULL;
349     struct stat tty_stat;
350
351     DBG ("VTNR is %u", priv->vtnr);
352     if (priv->vtnr > 0) {
353         tty_dev = g_strdup_printf ("/dev/tty%u", priv->vtnr);
354     } else {
355         tty_dev = g_strdup (ttyname (0));
356     }
357     DBG ("trying to setup TTY '%s'", tty_dev);
358     if (!tty_dev) {
359         WARN ("No TTY");
360         res = FALSE;
361         goto term_exit;
362     }
363     if (access (tty_dev, R_OK|W_OK)) {
364         WARN ("TTY not accessible: %s", strerror(errno));
365         res = FALSE;
366         goto term_exit;
367     }
368     if (lstat (tty_dev, &tty_stat)) {
369         WARN ("lstat() failed: %s", strerror(errno));
370         res = FALSE;
371         goto term_exit;
372     }
373     if (tty_stat.st_nlink > 1 ||
374         !S_ISCHR (tty_stat.st_mode) ||
375         strncmp (tty_dev, "/dev/", 5)) {
376         WARN ("Invalid TTY");
377         res = FALSE;
378         goto term_exit;
379     }
380
381     tty_fd = open (tty_dev, O_RDWR | O_NONBLOCK);
382     if (tty_fd < 0) {
383         WARN ("open() failed: %s", strerror(errno));
384         res = FALSE;
385         goto term_exit;
386     }
387     if (!isatty (tty_fd)) {
388         close (tty_fd);
389         WARN ("isatty() failed");
390         res = FALSE;
391         goto term_exit;
392     }
393     if (ioctl (tty_fd, TIOCSCTTY, 1))
394         WARN ("ioctl(TIOCSCTTY) failed: %s", strerror(errno));
395     tty_pgid = getpgid (getpid ());
396     if (ioctl (tty_fd, TIOCSPGRP, &tty_pgid)) {
397         WARN ("ioctl(TIOCSPGRP) failed: %s", strerror(errno));
398     }
399
400     /* TODO: unset the mode on session cleanup */
401     if (ioctl(tty_fd, KDSKBMUTE, 1) &&
402         ioctl(tty_fd, KDSKBMODE, K_OFF)) {
403         WARN ("ioctl(KDSKBMODE) failed: %s", strerror(errno));
404     }
405
406     /*if (tcsetpgrp (tty_fd, getpgrp ()))
407         WARN ("tcsetpgrp() failed: %s", strerror(errno));*/
408
409     // close all old handles
410     for (i = 0; i < tty_fd; i++)
411         close (i);
412     dup2 (tty_fd, 0);
413     dup2 (tty_fd, 1);
414     dup2 (tty_fd, 2);
415     close (tty_fd);
416
417 term_exit:
418     g_free (tty_dev);
419     return res;
420 }
421
422 static gboolean
423 _set_environment (TlmSessionPrivate *priv)
424 {
425         gchar **envlist = tlm_auth_session_get_envlist(priv->auth_session);
426         const gchar *home_dir = NULL, *shell = NULL;
427
428     if (envlist) {
429         gchar **env = 0;
430         for (env = envlist; *env != NULL; ++env) {
431             DBG ("ENV : %s", *env);
432             putenv(*env);
433             g_free (*env);
434         }
435         g_free (envlist);
436     }
437
438     const gchar *path = tlm_config_get_string (priv->config,
439                                                TLM_CONFIG_GENERAL,
440                                                TLM_CONFIG_GENERAL_SESSION_PATH);
441     if (!path)
442         path = "/usr/local/bin:/usr/bin:/bin";
443     _setenv_to_session ("PATH", path, priv);
444
445     _setenv_to_session ("USER", priv->username, priv);
446     _setenv_to_session ("LOGNAME", priv->username, priv);
447     home_dir = tlm_user_get_home_dir (priv->username);
448     if (home_dir) _setenv_to_session ("HOME", home_dir, priv);
449     shell = tlm_user_get_shell (priv->username);
450     if (shell) _setenv_to_session ("SHELL", shell, priv);
451
452     if (!tlm_config_has_key (priv->config,
453                              TLM_CONFIG_GENERAL,
454                              TLM_CONFIG_GENERAL_NSEATS))
455         _setenv_to_session ("XDG_SEAT", priv->seat_id, priv);
456
457     const gchar *xdg_data_dirs =
458         tlm_config_get_string (priv->config,
459                                TLM_CONFIG_GENERAL,
460                                TLM_CONFIG_GENERAL_DATA_DIRS);
461     if (!xdg_data_dirs)
462         xdg_data_dirs = "/usr/share:/usr/local/share";
463     _setenv_to_session ("XDG_DATA_DIRS", xdg_data_dirs, priv);
464
465     if (priv->xdg_runtime_dir)
466         _setenv_to_session ("XDG_RUNTIME_DIR", priv->xdg_runtime_dir, priv);
467
468     if (priv->env_hash)
469         g_hash_table_foreach (priv->env_hash,
470                               (GHFunc) _setenv_to_session,
471                               priv);
472
473     return TRUE;
474 }
475
476 static void
477 _on_child_down_cb (
478         GPid  pid,
479         gint  status,
480         gpointer data)
481 {
482     g_spawn_close_pid (pid);
483
484     TlmSession *session = TLM_SESSION (data);
485
486     DBG ("Sessiond(%p) with pid (%d) closed with status %d", session, pid,
487             status);
488
489     session->priv->child_pid = 0;
490     session->priv->is_child_up = FALSE;
491     _clear_session (session);
492     if (session->priv->can_emit_signal)
493         g_signal_emit (session, signals[SIG_SESSION_TERMINATED], 0);
494 }
495
496 static void
497 _exec_user_session (
498                 TlmSession *session)
499 {
500     gint i;
501     guint rtdir_perm = 0700;
502     const gchar *pattern = "('.*?'|\".*?\"|\\S+)";
503     const gchar *rtdir_perm_str;
504     const char *home;
505     const char *shell = NULL;
506     const char *env_shell = NULL;
507     gchar *uid_str;
508     gchar **args = NULL;
509     gchar **args_iter = NULL;
510     TlmSessionPrivate *priv = session->priv;
511     gchar **temp_strv = NULL;
512
513     priv = session->priv;
514     if (!priv->username)
515         priv->username = g_strdup (tlm_auth_session_get_username (
516                 priv->auth_session));
517     DBG ("session ID : %s", priv->sessionid);
518
519     if (tlm_config_has_key (priv->config,
520                             priv->seat_id,
521                             TLM_CONFIG_GENERAL_SETUP_RUNTIME_DIR)) {
522         priv->setup_runtime_dir = tlm_config_get_boolean (priv->config,
523                                            priv->seat_id,
524                                            TLM_CONFIG_GENERAL_SETUP_RUNTIME_DIR,
525                                            FALSE);
526     } else {
527         priv->setup_runtime_dir = tlm_config_get_boolean (priv->config,
528                                            TLM_CONFIG_GENERAL,
529                                            TLM_CONFIG_GENERAL_SETUP_RUNTIME_DIR,
530                                            FALSE);
531     }
532     rtdir_perm_str = tlm_config_get_string (priv->config,
533                                             priv->seat_id,
534                                             TLM_CONFIG_GENERAL_RUNTIME_MODE);
535     if (!rtdir_perm_str)
536         rtdir_perm_str = tlm_config_get_string (priv->config,
537                                                TLM_CONFIG_GENERAL,
538                                                TLM_CONFIG_GENERAL_RUNTIME_MODE);
539     uid_str = g_strdup_printf ("%u", tlm_user_get_uid (priv->username));
540     priv->xdg_runtime_dir = g_build_filename ("/run/user",
541                                               uid_str,
542                                               NULL);
543     g_free (uid_str);
544     if (priv->setup_runtime_dir) {
545         tlm_utils_delete_dir (priv->xdg_runtime_dir);
546         if (g_mkdir_with_parents ("/run/user", 0755))
547             WARN ("g_mkdir_with_parents(\"/run/user\") failed");
548         if (rtdir_perm_str)
549             sscanf(rtdir_perm_str, "%o", &rtdir_perm);
550         DBG ("setting up XDG_RUNTIME_DIR=%s mode=%o",
551              priv->xdg_runtime_dir, rtdir_perm);
552         if (g_mkdir (priv->xdg_runtime_dir, rtdir_perm))
553             WARN ("g_mkdir(\"%s\") failed", priv->xdg_runtime_dir);
554         if (chown (priv->xdg_runtime_dir,
555                tlm_user_get_uid (priv->username),
556                tlm_user_get_gid (priv->username)))
557             WARN ("chown(\"%s\"): %s", priv->xdg_runtime_dir, strerror(errno));
558         if (chmod (priv->xdg_runtime_dir, rtdir_perm))
559             WARN ("chmod(\"%s\"): %s", priv->xdg_runtime_dir, strerror(errno));
560     } else {
561         DBG ("not setting up XDG_RUNTIME_DIR");
562     }
563
564     priv->child_pid = fork ();
565     if (priv->child_pid) {
566         DBG ("establish handler for the child pid %u", priv->child_pid);
567         session->priv->child_watch_id = g_child_watch_add (priv->child_pid,
568                     (GChildWatchFunc)_on_child_down_cb, session);
569         session->priv->is_child_up = TRUE;
570         return;
571     }
572
573     /* ==================================
574      * this is child process here onwards
575      * ================================== */
576     gint open_max;
577     gint fd;
578
579     //close all open descriptors other than stdin, stdout, stderr
580     open_max = sysconf (_SC_OPEN_MAX);
581     for (fd = 3; fd < open_max; fd++) {
582         if (fcntl (fd, F_SETFD, FD_CLOEXEC) < -1) {
583             WARN ("Failed to close desriptor '%d', error: %s",
584                 fd, strerror(errno));
585         }
586     }
587
588     uid_t target_uid = tlm_user_get_uid (priv->username);
589     gid_t target_gid = tlm_user_get_gid (priv->username);
590
591     if (fchown (0, target_uid, -1)) {
592         WARN ("Changing TTY access rights failed");
593     }
594
595     /*if (getppid() == 1) {
596         if (setsid () == (pid_t) -1)
597             WARN ("setsid() failed: %s", strerror (errno));
598     } else {
599         if (setpgrp ())
600             WARN ("setpgrp() failed: %s", strerror (errno));
601     }*/
602
603     DBG ("old pgid=%u", getpgrp ());
604     if (setsid () == (pid_t) -1)
605         WARN ("setsid() failed: %s", strerror (errno));
606     DBG ("new pgid=%u", getpgrp());
607
608     gboolean setup_terminal;
609     if (tlm_config_has_key (priv->config,
610                             priv->seat_id,
611                             TLM_CONFIG_GENERAL_SETUP_TERMINAL)) {
612         setup_terminal = tlm_config_get_boolean (priv->config,
613                                                  priv->seat_id,
614                                                  TLM_CONFIG_GENERAL_SETUP_TERMINAL,
615                                                  FALSE);
616     } else {
617         setup_terminal = tlm_config_get_boolean (priv->config,
618                                                  TLM_CONFIG_GENERAL,
619                                                  TLM_CONFIG_GENERAL_SETUP_TERMINAL,
620                                                  FALSE);
621     }
622     if (setup_terminal) {
623         /* usually terminal settings are handled by PAM */
624         _set_terminal (priv);
625     }
626
627     if (initgroups (priv->username, target_gid))
628         WARN ("initgroups() failed: %s", strerror(errno));
629     if (setregid (target_gid, target_gid))
630         WARN ("setregid() failed: %s", strerror(errno));
631     if (setreuid (target_uid, target_uid))
632         WARN ("setreuid() failed: %s", strerror(errno));
633
634     int grouplist_len = NGROUPS_MAX;
635     gid_t grouplist[NGROUPS_MAX];
636     grouplist_len = getgroups (grouplist_len, grouplist);
637     DBG ("group membership:");
638     for (i = 0; i < grouplist_len; i++)
639         DBG ("\t%s", getgrgid (grouplist[i])->gr_name);
640
641     DBG (" state:\n\truid=%d, euid=%d, rgid=%d, egid=%d (%s)",
642          getuid(), geteuid(), getgid(), getegid(), priv->username);
643     _set_environment (priv);
644     umask(0077);
645
646     home = getenv("HOME");
647     if (home) {
648         DBG ("changing directory to : %s", home);
649         if (chdir (home) < 0)
650             WARN ("Failed to change directroy : %s", strerror (errno));
651     } else WARN ("Could not get home directory");
652
653     shell = tlm_config_get_string (priv->config,
654                                    priv->seat_id,
655                                    TLM_CONFIG_GENERAL_SESSION_CMD);
656     if (!shell)
657         shell = tlm_config_get_string (priv->config,
658                                        TLM_CONFIG_GENERAL,
659                                        TLM_CONFIG_GENERAL_SESSION_CMD);
660     if (shell) {
661         DBG ("Session command : %s", shell);
662         temp_strv = g_regex_split_simple (pattern,
663                                           shell,
664                                           0,
665                                           G_REGEX_MATCH_NOTEMPTY);
666     }
667
668     if (temp_strv) {
669         gchar **temp_iter;
670
671         args = g_new0 (gchar *, g_strv_length (temp_strv));
672         for (temp_iter = temp_strv, args_iter = args;
673                 *temp_iter != NULL;
674                 temp_iter++) {
675             size_t item_len = 0;
676             gchar *item = g_strstrip (*temp_iter);
677
678             item_len = strlen (item);
679             if (item_len == 0) {
680                 continue;
681             }
682             if ((item[0] == '\"' && item[item_len - 1] == '\"') ||
683                     (item[0] == '\'' && item[item_len - 1] == '\'')) {
684                 item[item_len - 1] = '\0';
685                 memmove (item, item + 1, item_len - 1);
686             }
687             *args_iter = g_strcompress (item);
688             args_iter++;
689         }
690         g_strfreev (temp_strv);
691     } else if ((env_shell = getenv("SHELL"))){
692         /* use shell if no override configured */
693         args = g_new0 (gchar *, 2);
694         args[0] = g_strdup (env_shell);
695     } else {
696         /* in case shell is not defined, fall back to systemd --user */
697         args = g_new0 (gchar *, 3);
698         args[0] = g_strdup ("systemd");
699         args[1] = g_strdup ("--user");
700     }
701
702     DBG ("executing: ");
703     args_iter = args;
704     while (args_iter && *args_iter) {
705         DBG ("\targv[%d]: %s", i, *args_iter);
706         args_iter++; i++;
707     }
708     execvp (args[0], args);
709     /* we reach here only in case of error */
710     g_strfreev (args);
711     DBG ("execl(): %s", strerror(errno));
712     exit (0);
713 }
714
715 TlmSession *
716 tlm_session_new ()
717 {
718     DBG ("Session New");
719     return g_object_new (TLM_TYPE_SESSION, NULL);
720 }
721
722 gboolean
723 tlm_session_start (TlmSession *session,
724                    const gchar *seat_id, const gchar *service,
725                    const gchar *username, const gchar *password,
726                    GHashTable *environment)
727 {
728         GError *error = NULL;
729         g_return_val_if_fail (session && TLM_IS_SESSION(session), FALSE);
730     TlmSessionPrivate *priv = TLM_SESSION_PRIV(session);
731     const gchar *session_type;
732
733     if (!seat_id || !service || !username) {
734         error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SESSION_CREATION_FAILURE,
735                 "Unable to create PAM sesssion as input data is invalid "
736                 "seatid(%p) service(%p) username(%p)", seat_id, service,
737                 username);
738         g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
739         g_error_free (error);
740         return FALSE;
741     }
742
743     g_object_set (G_OBJECT (session), "seat", seat_id, "service", service,
744             "username", username, "environment", environment, NULL);
745
746     priv->vtnr = tlm_config_get_uint (priv->config,
747                                       priv->seat_id,
748                                       TLM_CONFIG_SEAT_VTNR,
749                                       0);
750     gchar *tty_name = priv->vtnr > 0 ?
751         g_strdup_printf ("tty%u", priv->vtnr) : NULL;
752     priv->auth_session = tlm_auth_session_new (priv->service, priv->username,
753             password, tty_name);
754     g_free (tty_name);
755
756     if (!priv->auth_session) {
757         error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SESSION_CREATION_FAILURE,
758                 "Unable to create PAM sesssion");
759         g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
760         g_error_free (error);
761         return FALSE;
762     }
763
764     session_type = tlm_config_get_string (priv->config,
765                                           priv->seat_id,
766                                           TLM_CONFIG_GENERAL_SESSION_TYPE);
767     if (!session_type)
768         session_type = tlm_config_get_string (priv->config,
769                                               TLM_CONFIG_GENERAL,
770                                               TLM_CONFIG_GENERAL_SESSION_TYPE);
771     if (!tlm_config_has_key (priv->config,
772                              TLM_CONFIG_GENERAL,
773                              TLM_CONFIG_GENERAL_NSEATS))
774         tlm_auth_session_putenv (priv->auth_session,
775                                  "XDG_SEAT",
776                                  priv->seat_id);
777     if (session_type) {
778         tlm_auth_session_putenv (priv->auth_session,
779                                  "XDG_SESSION_CLASS",
780                                  "user");
781         tlm_auth_session_putenv (priv->auth_session,
782                                  "XDG_SESSION_TYPE",
783                                  session_type);
784     }
785     if (priv->vtnr > 0) {
786         gchar *vtnr_str = g_strdup_printf("%u", priv->vtnr);
787         tlm_auth_session_putenv (priv->auth_session,
788                                  "XDG_VTNR",
789                                  vtnr_str);
790         g_free (vtnr_str);
791     }
792
793     if (!tlm_auth_session_authenticate (priv->auth_session, &error)) {
794         if (error) {
795             //consistant error message flow
796             GError *err = TLM_GET_ERROR_FOR_ID (
797                     TLM_ERROR_SESSION_CREATION_FAILURE,
798                     "%d:%s", error->code, error->message);
799             g_error_free (error);
800             error = err;
801         } else {
802             error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SESSION_CREATION_FAILURE,
803                     "Unable to authenticate PAM sesssion");
804         }
805         g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
806         g_error_free (error);
807         return FALSE;
808     }
809     g_signal_emit (session, signals[SIG_AUTHENTICATED], 0);
810
811     priv->session_pause =  tlm_config_get_boolean (priv->config,
812                                              TLM_CONFIG_GENERAL,
813                                              TLM_CONFIG_GENERAL_PAUSE_SESSION,
814                                              FALSE);
815     if (priv->session_pause) {
816         _set_environment (priv);
817         umask(0077);
818     }
819
820     if (!tlm_auth_session_open (priv->auth_session, &error)) {
821         if (!error) {
822             error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SESSION_CREATION_FAILURE,
823                     "Unable to open PAM sesssion");
824         }
825         g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
826         g_error_free (error);
827         return FALSE;
828     }
829     priv->sessionid = g_strdup (tlm_auth_session_get_sessionid (
830             priv->auth_session));
831     tlm_utils_log_utmp_entry (priv->username);
832     if (!priv->session_pause)
833         _exec_user_session (session);
834     g_signal_emit (session, signals[SIG_SESSION_CREATED], 0,
835                    priv->sessionid ? priv->sessionid : "");
836     return TRUE;
837 }
838
839 static gboolean
840 _terminate_timeout (gpointer user_data)
841 {
842     TlmSession *session = TLM_SESSION(user_data);
843     TlmSessionPrivate *priv = TLM_SESSION_PRIV(session);
844
845     switch (priv->last_sig)
846     {
847         case SIGHUP:
848             DBG ("child %u didn't respond to SIGHUP, sending SIGTERM",
849                  priv->child_pid);
850             if (killpg (getpgid (priv->child_pid), SIGTERM))
851                 WARN ("killpg(%u, SIGTERM): %s",
852                       getpgid (priv->child_pid),
853                       strerror(errno));
854             priv->last_sig = SIGTERM;
855             return G_SOURCE_CONTINUE;
856         case SIGTERM:
857             DBG ("child %u didn't respond to SIGTERM, sending SIGKILL",
858                  priv->child_pid);
859             if (killpg (getpgid (priv->child_pid), SIGKILL))
860                 WARN ("killpg(%u, SIGKILL): %s",
861                       getpgid (priv->child_pid),
862                       strerror(errno));
863             priv->last_sig = SIGKILL;
864             return G_SOURCE_CONTINUE;
865         case SIGKILL:
866             DBG ("child %u didn't respond to SIGKILL, process is stuck in kernel",
867                  priv->child_pid);
868             priv->timer_id = 0;
869             _clear_session (session);
870             if (session->priv->can_emit_signal) {
871                 GError *error = TLM_GET_ERROR_FOR_ID (
872                         TLM_ERROR_SESSION_TERMINATION_FAILURE,
873                         "Unable to terminate session - process is stuck"
874                         " in kernel");
875                 g_signal_emit (session, signals[SIG_SESSION_ERROR], 0, error);
876                 g_error_free (error);
877             }
878             return G_SOURCE_REMOVE;
879         default:
880             WARN ("%d has unknown signaling state %d",
881                   priv->child_pid,
882                   priv->last_sig);
883     }
884     return G_SOURCE_REMOVE;
885 }
886
887 void
888 tlm_session_terminate (TlmSession *session)
889 {
890     g_return_if_fail (session && TLM_IS_SESSION(session));
891     TlmSessionPrivate *priv = TLM_SESSION_PRIV(session);
892
893     DBG ("Session Terminate");
894
895     if (!priv->is_child_up) {
896         DBG ("no child process is running - closing pam session");
897         _clear_session (session);
898         if (session->priv->can_emit_signal)
899             g_signal_emit (session, signals[SIG_SESSION_TERMINATED], 0);
900         return;
901     }
902
903     if (killpg (getpgid (priv->child_pid), SIGHUP) < 0)
904         WARN ("kill(%u, SIGHUP): %s",
905               getpgid (priv->child_pid),
906               strerror(errno));
907     priv->last_sig = SIGHUP;
908     priv->timer_id = g_timeout_add_seconds (
909             tlm_config_get_uint (priv->config, TLM_CONFIG_GENERAL,
910                     TLM_CONFIG_GENERAL_TERMINATE_TIMEOUT, 3),
911             _terminate_timeout,
912             session);
913 }
914
915 void
916 tlm_session_reset_tty (TlmSession *session)
917 {
918     TlmSessionPrivate *priv = TLM_SESSION_PRIV(session);
919
920     if (fchown (0, priv->tty_uid, priv->tty_gid))
921         WARN ("Changing TTY access rights failed");
922     if (tcflush (0, TCIOFLUSH) ||
923         tcflush (1, TCIOFLUSH) ||
924         tcflush (2, TCIOFLUSH))
925         WARN ("Flushing stdio failed");
926     pid_t pgid = getpgid (getpid ());
927     if (tcsetpgrp (0, pgid) || tcsetpgrp (1, pgid) || tcsetpgrp (2, pgid))
928         WARN ("Change TTY controlling process failed");
929     if (tcsetattr (0, TCSANOW, &priv->stdin_state) ||
930         tcsetattr (1, TCSANOW, &priv->stdout_state) ||
931         tcsetattr (2, TCSANOW, &priv->stderr_state))
932         WARN ("Restoring TTY settings failed");
933 }
934