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