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