~darkxst/ubuntu/trusty/gdm/nokill

1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 *
3
 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
1.4.52 by Jeremy Bicha
Import upstream version 3.5.92.1
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
18
 *
19
 */
20
21
#include "config.h"
22
23
#include <stdlib.h>
24
#include <stdio.h>
25
#include <fcntl.h>
26
#include <unistd.h>
27
#include <string.h>
28
#include <sys/types.h>
29
#include <sys/wait.h>
30
#include <errno.h>
31
#include <ctype.h>
32
#include <pwd.h>
33
#include <grp.h>
34
#include <signal.h>
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
35
#include <sys/ioctl.h>
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
36
#include <sys/resource.h>
37
1.4.45 by Kees Cook
Import upstream version 2.30.4
38
#ifdef HAVE_SYS_PRCTL_H
39
#include <sys/prctl.h>
40
#endif
41
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
42
#ifdef WITH_PLYMOUTH
215 by Robert Ancell
* debian/control:
43
#include <linux/vt.h>
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
44
#endif
45
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
46
#include <glib/gi18n.h>
47
#include <glib/gstdio.h>
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
48
#include <gio/gio.h>
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
49
50
#include <X11/Xlib.h> /* for Display */
51
52
#include "gdm-common.h"
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
53
#include "gdm-settings-direct.h"
54
#include "gdm-settings-keys.h"
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
55
56
#include "gdm-server.h"
57
58
extern char **environ;
59
60
#define GDM_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SERVER, GdmServerPrivate))
61
62
/* These are the servstat values, also used as server
63
 * process exit codes */
64
#define SERVER_TIMEOUT 2        /* Server didn't start */
65
#define SERVER_DEAD 250         /* Server stopped */
66
#define SERVER_PENDING 251      /* Server started but not ready for connections yet */
67
#define SERVER_RUNNING 252      /* Server running and ready for connections */
68
#define SERVER_ABORT 253        /* Server failed badly. Suspending display. */
69
70
#define MAX_LOGS 5
71
72
struct GdmServerPrivate
73
{
74
        char    *command;
75
        GPid     pid;
76
77
        gboolean disable_tcp;
78
        int      priority;
79
        char    *user_name;
80
        char    *session_args;
81
82
        char    *log_dir;
83
        char    *display_name;
84
        char    *display_device;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
85
        char    *display_seat_id;
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
86
        char    *auth_file;
87
88
        gboolean is_parented;
89
        char    *parent_display_name;
90
        char    *parent_auth_file;
91
        char    *chosen_hostname;
92
93
        guint    child_watch_id;
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
94
        guint    sigusr1_id;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
95
96
        gboolean is_initial;
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
97
};
98
99
enum {
100
        PROP_0,
101
        PROP_DISPLAY_NAME,
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
102
        PROP_DISPLAY_SEAT_ID,
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
103
        PROP_DISPLAY_DEVICE,
104
        PROP_AUTH_FILE,
105
        PROP_IS_PARENTED,
106
        PROP_PARENT_DISPLAY_NAME,
107
        PROP_PARENT_AUTH_FILE,
108
        PROP_CHOSEN_HOSTNAME,
109
        PROP_COMMAND,
110
        PROP_PRIORITY,
111
        PROP_USER_NAME,
112
        PROP_SESSION_ARGS,
113
        PROP_LOG_DIR,
114
        PROP_DISABLE_TCP,
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
115
        PROP_IS_INITIAL,
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
116
};
117
118
enum {
119
        READY,
120
        EXITED,
121
        DIED,
122
        LAST_SIGNAL
123
};
124
125
static guint signals [LAST_SIGNAL] = { 0, };
126
127
static void     gdm_server_class_init   (GdmServerClass *klass);
128
static void     gdm_server_init         (GdmServer      *server);
129
static void     gdm_server_finalize     (GObject        *object);
130
131
G_DEFINE_TYPE (GdmServer, gdm_server, G_TYPE_OBJECT)
132
133
static char *
134
_gdm_server_query_ck_for_display_device (GdmServer *server)
135
{
136
        char    *out;
137
        char    *command;
138
        int      status;
139
        gboolean res;
140
        GError  *error;
141
142
        g_return_val_if_fail (GDM_IS_SERVER (server), NULL);
143
144
        error = NULL;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
145
        command = g_strdup_printf (CONSOLEKIT_DIR "/ck-get-x11-display-device --display %s",
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
146
                                   server->priv->display_name);
147
148
        g_debug ("GdmServer: Running helper %s", command);
149
        out = NULL;
150
        res = g_spawn_command_line_sync (command,
151
                                         &out,
152
                                         NULL,
153
                                         &status,
154
                                         &error);
155
        if (! res) {
156
                g_warning ("Could not run helper: %s", error->message);
157
                g_error_free (error);
158
        } else {
159
                out = g_strstrip (out);
160
                g_debug ("GdmServer: Got tty: '%s'", out);
161
        }
162
163
        g_free (command);
164
165
        return out;
166
}
167
168
char *
169
gdm_server_get_display_device (GdmServer *server)
170
{
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
171
#ifdef WITH_SYSTEMD
274 by Martin Pitt
* Add debian/patches/00git_logind_check.patch: Fix checks for logind.
172
        if (LOGIND_RUNNING()) {
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
173
                /* systemd finds the display device out on its own based on the display */
174
                return NULL;
175
        }
176
#endif
177
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
178
        if (server->priv->display_device == NULL) {
179
                server->priv->display_device =
180
                    _gdm_server_query_ck_for_display_device (server);
181
182
                g_object_notify (G_OBJECT (server), "display-device");
183
        }
184
185
        return g_strdup (server->priv->display_device);
186
}
187
188
static gboolean
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
189
on_sigusr1 (gpointer user_data)
190
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
191
{
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
192
        GdmServer *server = user_data;
193
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
194
        g_debug ("GdmServer: Got USR1 from X server - emitting READY");
195
196
        g_signal_emit (server, signals[READY], 0);
197
        return FALSE;
198
}
199
200
/* We keep a connection (parent_dsp) open with the parent X server
201
 * before running a proxy on it to prevent the X server resetting
202
 * as we open and close other connections.
203
 * Note that XDMCP servers, by default, reset when the seed X
204
 * connection closes whereas usually the X server only quits when
205
 * all X connections have closed.
206
 */
207
#if 0
208
static gboolean
209
connect_to_parent (GdmServer *server)
210
{
211
        int maxtries;
212
        int openretries;
213
214
        g_debug ("GdmServer: Connecting to parent display \'%s\'",
215
                   d->parent_disp);
216
217
        d->parent_dsp = NULL;
218
219
        maxtries = SERVER_IS_XDMCP (d) ? 10 : 2;
220
221
        openretries = 0;
222
        while (openretries < maxtries &&
223
               d->parent_dsp == NULL) {
224
                d->parent_dsp = XOpenDisplay (d->parent_disp);
225
226
                if G_UNLIKELY (d->parent_dsp == NULL) {
227
                        g_debug ("GdmServer: Sleeping %d on a retry", 1+openretries*2);
228
                        gdm_sleep_no_signal (1+openretries*2);
229
                        openretries++;
230
                }
231
        }
232
233
        if (d->parent_dsp == NULL)
234
                gdm_error (_("%s: failed to connect to parent display \'%s\'"),
235
                           "gdm_server_start", d->parent_disp);
236
237
        return d->parent_dsp != NULL;
238
}
239
#endif
240
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
241
static void
242
gdm_server_init_command (GdmServer *server)
243
{
244
        gboolean debug = FALSE;
245
        const char *debug_options;
246
247
        if (server->priv->command != NULL) {
248
                return;
249
        }
250
251
        gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug);
252
        if (debug) {
253
                debug_options = " -logverbose 7 -core ";
254
        } else {
255
                debug_options = "";
256
        }
257
258
#ifdef WITH_SYSTEMD
259
260
        /* This is a temporary hack to work around the fact that XOrg
261
         * currently lacks support for multi-seat hotplugging for
262
         * display devices. This bit should be removed as soon as XOrg
263
         * gains native support for automatically enumerating usb
264
         * based graphics adapters at start-up via udev. */
265
266
        /* systemd ships an X server wrapper tool which simply invokes
267
         * the usual X but ensures it only uses the display devices of
268
         * the seat. */
269
270
        /* We do not rely on this wrapper server if, a) the machine
271
         * wasn't booted using systemd, or b) the wrapper tool is
272
         * missing, or c) we are running for the main seat 'seat0'. */
273
274 by Martin Pitt
* Add debian/patches/00git_logind_check.patch: Fix checks for logind.
274
        if (!LOGIND_RUNNING()) {
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
275
                goto fallback;
276
        }
277
278
        if (g_access (SYSTEMD_X_SERVER, X_OK) < 0) {
279
                goto fallback;
280
        }
281
282
        if (server->priv->display_seat_id == NULL ||
283
            strcmp (server->priv->display_seat_id, "seat0") == 0) {
284
                goto fallback;
285
        }
286
1.4.52 by Jeremy Bicha
Import upstream version 3.5.92.1
287
        server->priv->command = g_strdup_printf (SYSTEMD_X_SERVER " -background none -verbose%s", debug_options);
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
288
        return;
289
290
fallback:
291
#endif
292
1.4.52 by Jeremy Bicha
Import upstream version 3.5.92.1
293
        server->priv->command = g_strdup_printf (X_SERVER " -background none -verbose%s", debug_options);
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
294
}
295
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
296
static gboolean
297
gdm_server_resolve_command_line (GdmServer  *server,
298
                                 const char *vtarg,
299
                                 int        *argcp,
300
                                 char     ***argvp)
301
{
302
        int      argc;
303
        char   **argv;
304
        int      len;
305
        int      i;
306
        gboolean gotvtarg = FALSE;
307
        gboolean query_in_arglist = FALSE;
308
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
309
        gdm_server_init_command (server);
310
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
311
        g_shell_parse_argv (server->priv->command, &argc, &argv, NULL);
312
313
        for (len = 0; argv != NULL && argv[len] != NULL; len++) {
314
                char *arg = argv[len];
315
316
                /* HACK! Not to add vt argument to servers that already force
317
                 * allocation.  Mostly for backwards compat only */
318
                if (strncmp (arg, "vt", 2) == 0 &&
319
                    isdigit (arg[2]) &&
320
                    (arg[3] == '\0' ||
321
                     (isdigit (arg[3]) && arg[4] == '\0')))
322
                        gotvtarg = TRUE;
323
                if (strcmp (arg, "-query") == 0 ||
324
                    strcmp (arg, "-indirect") == 0)
325
                        query_in_arglist = TRUE;
326
        }
327
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
328
        argv = g_renew (char *, argv, len + 12);
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
329
        /* shift args down one */
330
        for (i = len - 1; i >= 1; i--) {
331
                argv[i+1] = argv[i];
332
        }
333
334
        /* server number is the FIRST argument, before any others */
335
        argv[1] = g_strdup (server->priv->display_name);
336
        len++;
337
338
        if (server->priv->auth_file != NULL) {
339
                argv[len++] = g_strdup ("-auth");
340
                argv[len++] = g_strdup (server->priv->auth_file);
341
        }
342
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
343
#ifdef WITH_SYSTEMD
274 by Martin Pitt
* Add debian/patches/00git_logind_check.patch: Fix checks for logind.
344
        if (LOGIND_RUNNING() && server->priv->display_seat_id != NULL) {
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
345
                argv[len++] = g_strdup ("-seat");
346
                argv[len++] = g_strdup (server->priv->display_seat_id);
347
        }
348
#endif
349
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
350
        if (server->priv->chosen_hostname) {
351
                /* run just one session */
352
                argv[len++] = g_strdup ("-terminate");
353
                argv[len++] = g_strdup ("-query");
354
                argv[len++] = g_strdup (server->priv->chosen_hostname);
355
                query_in_arglist = TRUE;
356
        }
357
358
        if (server->priv->disable_tcp && ! query_in_arglist) {
359
                argv[len++] = g_strdup ("-nolisten");
360
                argv[len++] = g_strdup ("tcp");
361
        }
362
363
        if (vtarg != NULL && ! gotvtarg) {
364
                argv[len++] = g_strdup (vtarg);
365
        }
366
367
        argv[len++] = NULL;
368
369
        *argvp = argv;
370
        *argcp = len;
371
372
        return TRUE;
373
}
374
375
static void
376
rotate_logs (const char *path,
377
             guint       n_copies)
378
{
379
        int i;
380
381
        for (i = n_copies - 1; i > 0; i--) {
382
                char *name_n;
383
                char *name_n1;
384
385
                name_n = g_strdup_printf ("%s.%d", path, i);
386
                if (i > 1) {
387
                        name_n1 = g_strdup_printf ("%s.%d", path, i - 1);
388
                } else {
389
                        name_n1 = g_strdup (path);
390
                }
391
392
                VE_IGNORE_EINTR (g_unlink (name_n));
393
                VE_IGNORE_EINTR (g_rename (name_n1, name_n));
394
395
                g_free (name_n1);
396
                g_free (name_n);
397
        }
398
399
        VE_IGNORE_EINTR (g_unlink (path));
400
}
401
402
static void
403
change_user (GdmServer *server)
404
{
405
        struct passwd *pwent;
406
407
        if (server->priv->user_name == NULL) {
408
                return;
409
        }
410
1.4.46 by Sebastien Bacher
Import upstream version 2.30.5
411
        gdm_get_pwent_for_name (server->priv->user_name, &pwent);
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
412
        if (pwent == NULL) {
413
                g_warning (_("Server was to be spawned by user %s but that user doesn't exist"),
414
                           server->priv->user_name);
415
                _exit (1);
416
        }
417
418
        g_debug ("GdmServer: Changing (uid:gid) for child process to (%d:%d)",
419
                 pwent->pw_uid,
420
                 pwent->pw_gid);
421
422
        if (pwent->pw_uid != 0) {
423
                if (setgid (pwent->pw_gid) < 0)  {
424
                        g_warning (_("Couldn't set groupid to %d"),
425
                                   pwent->pw_gid);
426
                        _exit (1);
427
                }
428
429
                if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) {
430
                        g_warning (_("initgroups () failed for %s"),
431
                                   pwent->pw_name);
432
                        _exit (1);
433
                }
434
435
                if (setuid (pwent->pw_uid) < 0)  {
436
                        g_warning (_("Couldn't set userid to %d"),
437
                                   (int)pwent->pw_uid);
438
                        _exit (1);
439
                }
440
        } else {
441
                gid_t groups[1] = { 0 };
442
443
                if (setgid (0) < 0)  {
1.4.43 by Martin Pitt
Import upstream version 2.30.2
444
                        g_warning (_("Couldn't set groupid to %d"), 0);
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
445
                        /* Don't error out, it's not fatal, if it fails we'll
446
                         * just still be */
447
                }
448
449
                /* this will get rid of any suplementary groups etc... */
450
                setgroups (1, groups);
451
        }
452
}
453
454
static void
455
server_child_setup (GdmServer *server)
456
{
457
        int              logfd;
458
        struct sigaction ign_signal;
459
        sigset_t         mask;
460
        char            *log_file;
461
        char            *log_path;
462
463
        log_file = g_strdup_printf ("%s.log", server->priv->display_name);
464
        log_path = g_build_filename (server->priv->log_dir, log_file, NULL);
465
        g_free (log_file);
466
467
        /* Rotate the X server logs */
468
        rotate_logs (log_path, MAX_LOGS);
469
470
        /* Log all output from spawned programs to a file */
471
        g_debug ("GdmServer: Opening logfile for server %s", log_path);
472
473
        VE_IGNORE_EINTR (g_unlink (log_path));
474
        VE_IGNORE_EINTR (logfd = open (log_path, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY|O_EXCL, 0644));
475
476
        g_free (log_path);
477
478
        if (logfd != -1) {
479
                VE_IGNORE_EINTR (dup2 (logfd, 1));
480
                VE_IGNORE_EINTR (dup2 (logfd, 2));
481
                close (logfd);
482
        } else {
1.4.47 by Martin Pitt
Import upstream version 2.32.0
483
                g_warning (_("%s: Could not open log file for display %s!"),
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
484
                           "gdm_server_spawn",
485
                           server->priv->display_name);
486
        }
487
488
        /* The X server expects USR1/TTIN/TTOU to be SIG_IGN */
489
        ign_signal.sa_handler = SIG_IGN;
490
        ign_signal.sa_flags = SA_RESTART;
491
        sigemptyset (&ign_signal.sa_mask);
492
493
        if (sigaction (SIGUSR1, &ign_signal, NULL) < 0) {
494
                g_warning (_("%s: Error setting %s to %s"),
495
                           "gdm_server_spawn", "USR1", "SIG_IGN");
496
                _exit (SERVER_ABORT);
497
        }
498
499
        if (sigaction (SIGTTIN, &ign_signal, NULL) < 0) {
500
                g_warning (_("%s: Error setting %s to %s"),
501
                           "gdm_server_spawn", "TTIN", "SIG_IGN");
502
                _exit (SERVER_ABORT);
503
        }
504
505
        if (sigaction (SIGTTOU, &ign_signal, NULL) < 0) {
506
                g_warning (_("%s: Error setting %s to %s"),
507
                           "gdm_server_spawn", "TTOU", "SIG_IGN");
508
                _exit (SERVER_ABORT);
509
        }
510
511
        /* And HUP and TERM are at SIG_DFL from gdm_unset_signals,
512
           we also have an empty mask and all that fun stuff */
513
514
        /* unblock signals (especially HUP/TERM/USR1) so that we
515
         * can control the X server */
516
        sigemptyset (&mask);
517
        sigprocmask (SIG_SETMASK, &mask, NULL);
518
1.4.45 by Kees Cook
Import upstream version 2.30.4
519
        /* Terminate the process when the parent dies */
520
#ifdef HAVE_SYS_PRCTL_H
521
        prctl (PR_SET_PDEATHSIG, SIGTERM);
522
#endif
523
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
524
        if (server->priv->priority != 0) {
525
                if (setpriority (PRIO_PROCESS, 0, server->priv->priority)) {
526
                        g_warning (_("%s: Server priority couldn't be set to %d: %s"),
527
                                   "gdm_server_spawn",
528
                                   server->priv->priority,
529
                                   g_strerror (errno));
530
                }
531
        }
532
533
        setpgid (0, 0);
534
535
        change_user (server);
536
}
537
538
static void
539
listify_hash (const char *key,
540
              const char *value,
541
              GPtrArray  *env)
542
{
543
        char *str;
544
        str = g_strdup_printf ("%s=%s", key, value);
545
        g_ptr_array_add (env, str);
546
}
547
548
static GPtrArray *
549
get_server_environment (GdmServer *server)
550
{
551
        GPtrArray  *env;
552
        char      **l;
553
        GHashTable *hash;
554
555
        env = g_ptr_array_new ();
556
557
        /* create a hash table of current environment, then update keys has necessary */
558
        hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
559
        for (l = environ; *l != NULL; l++) {
560
                char **str;
561
                str = g_strsplit (*l, "=", 2);
562
                g_hash_table_insert (hash, str[0], str[1]);
1.4.45 by Kees Cook
Import upstream version 2.30.4
563
                g_free (str);
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
564
        }
565
566
        /* modify environment here */
567
        if (server->priv->is_parented) {
568
                if (server->priv->parent_auth_file != NULL) {
569
                        g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (server->priv->parent_auth_file));
570
                }
571
572
                if (server->priv->parent_display_name != NULL) {
573
                        g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (server->priv->parent_display_name));
574
                }
575
        } else {
576
                g_hash_table_insert (hash, g_strdup ("DISPLAY="), g_strdup (server->priv->display_name));
577
        }
578
579
        if (server->priv->user_name != NULL) {
580
                struct passwd *pwent;
581
1.4.46 by Sebastien Bacher
Import upstream version 2.30.5
582
                gdm_get_pwent_for_name (server->priv->user_name, &pwent);
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
583
584
                if (pwent->pw_dir != NULL
585
                    && g_file_test (pwent->pw_dir, G_FILE_TEST_EXISTS)) {
586
                        g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir));
587
                } else {
588
                        /* Hack */
589
                        g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/"));
590
                }
591
                g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell));
592
                g_hash_table_remove (hash, "MAIL");
593
        }
594
595
        g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
596
        g_hash_table_destroy (hash);
597
598
        g_ptr_array_add (env, NULL);
599
600
        return env;
601
}
602
603
static void
604
server_add_xserver_args (GdmServer *server,
605
                         int       *argc,
606
                         char    ***argv)
607
{
608
        int    count;
609
        char **args;
610
        int    len;
611
        int    i;
612
613
        len = *argc;
614
        g_shell_parse_argv (server->priv->session_args, &count, &args, NULL);
615
        *argv = g_renew (char *, *argv, len + count + 1);
616
617
        for (i=0; i < count;i++) {
618
                *argv[len++] = g_strdup (args[i]);
619
        }
620
621
        *argc += count;
622
623
        argv[len] = NULL;
624
        g_strfreev (args);
625
}
626
627
static void
628
server_child_watch (GPid       pid,
629
                    int        status,
630
                    GdmServer *server)
631
{
632
        g_debug ("GdmServer: child (pid:%d) done (%s:%d)",
633
                 (int) pid,
634
                 WIFEXITED (status) ? "status"
635
                 : WIFSIGNALED (status) ? "signal"
636
                 : "unknown",
637
                 WIFEXITED (status) ? WEXITSTATUS (status)
638
                 : WIFSIGNALED (status) ? WTERMSIG (status)
639
                 : -1);
640
1.4.51 by Jeremy Bicha
Import upstream version 3.5.91
641
        g_object_ref (server);
642
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
643
        if (WIFEXITED (status)) {
644
                int code = WEXITSTATUS (status);
645
                g_signal_emit (server, signals [EXITED], 0, code);
646
        } else if (WIFSIGNALED (status)) {
647
                int num = WTERMSIG (status);
648
                g_signal_emit (server, signals [DIED], 0, num);
649
        }
650
651
        g_spawn_close_pid (server->priv->pid);
652
        server->priv->pid = -1;
1.4.51 by Jeremy Bicha
Import upstream version 3.5.91
653
654
        g_object_unref (server);
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
655
}
656
657
static gboolean
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
658
gdm_server_spawn (GdmServer    *server,
659
                  const char   *vtarg,
660
                  GError      **error)
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
661
{
662
        int              argc;
663
        gchar          **argv = NULL;
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
664
        GPtrArray       *env = NULL;
665
        gboolean         ret = FALSE;
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
666
        char            *freeme;
667
668
        /* Figure out the server command */
669
        argv = NULL;
670
        argc = 0;
671
        gdm_server_resolve_command_line (server,
672
                                         vtarg,
673
                                         &argc,
674
                                         &argv);
675
676
        if (server->priv->session_args) {
677
                server_add_xserver_args (server, &argc, &argv);
678
        }
679
680
        if (argv[0] == NULL) {
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
681
                g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
682
                             _("%s: Empty server command for display %s"),
683
                             "gdm_server_spawn",
684
                             server->priv->display_name);
1.4.52 by Jeremy Bicha
Import upstream version 3.5.92.1
685
                goto out;
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
686
        }
687
688
        env = get_server_environment (server);
689
690
        freeme = g_strjoinv (" ", argv);
691
        g_debug ("GdmServer: Starting X server process: %s", freeme);
692
        g_free (freeme);
693
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
694
        if (!g_spawn_async_with_pipes (NULL,
695
                                       argv,
696
                                       (char **)env->pdata,
697
                                       G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
698
                                       (GSpawnChildSetupFunc)server_child_setup,
699
                                       server,
700
                                       &server->priv->pid,
701
                                       NULL,
702
                                       NULL,
703
                                       NULL,
704
                                       error))
705
                goto out;
706
707
        g_debug ("GdmServer: Started X server process %d - waiting for READY", (int)server->priv->pid);
708
709
        server->priv->child_watch_id = g_child_watch_add (server->priv->pid,
710
                                                          (GChildWatchFunc)server_child_watch,
711
                                                          server);
712
713
        ret = TRUE;
714
 out:
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
715
        g_strfreev (argv);
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
716
        if (env) {
717
                g_ptr_array_foreach (env, (GFunc)g_free, NULL);
718
                g_ptr_array_free (env, TRUE);
1.4.52 by Jeremy Bicha
Import upstream version 3.5.92.1
719
        }
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
720
        return ret;
721
}
722
723
/**
724
 * gdm_server_start:
725
 * @disp: Pointer to a GdmDisplay structure
726
 *
727
 * Starts a local X server. Handles retries and fatal errors properly.
728
 */
729
730
gboolean
731
gdm_server_start (GdmServer *server)
732
{
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
733
        gboolean res = FALSE;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
734
        const char *vtarg = NULL;
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
735
        GError *local_error = NULL;
736
        GError **error = &local_error;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
737
738
        /* Hardcode the VT for the initial X server, but nothing else */
739
        if (server->priv->is_initial) {
740
                vtarg = "vt" GDM_INITIAL_VT;
741
742
#ifdef WITH_SYSTEMD
743
                /* undo the hardcoding if we are an auxillary seat */
274 by Martin Pitt
* Add debian/patches/00git_logind_check.patch: Fix checks for logind.
744
                if (LOGIND_RUNNING()) {
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
745
                     if (strcmp (server->priv->display_seat_id, "seat0") != 0) {
746
                         vtarg = NULL;
747
                     }
748
                }
749
#endif
750
        }
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
751
752
        /* fork X server process */
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
753
        if (!gdm_server_spawn (server, vtarg, error)) {
754
                goto out;
755
        }
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
756
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
757
        res = TRUE;
758
 out:
759
        if (local_error) {
760
                g_printerr ("%s\n", local_error->message);
761
                g_clear_error (&local_error);
762
        }
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
763
        return res;
764
}
765
766
static void
767
server_died (GdmServer *server)
768
{
769
        int exit_status;
770
771
        g_debug ("GdmServer: Waiting on process %d", server->priv->pid);
772
        exit_status = gdm_wait_on_pid (server->priv->pid);
773
774
        if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
775
                g_debug ("GdmServer: Wait on child process failed");
776
        } else {
777
                /* exited normally */
778
        }
779
780
        g_spawn_close_pid (server->priv->pid);
781
        server->priv->pid = -1;
782
783
        if (server->priv->display_device != NULL) {
784
                g_free (server->priv->display_device);
785
                server->priv->display_device = NULL;
786
                g_object_notify (G_OBJECT (server), "display-device");
787
        }
788
789
        g_debug ("GdmServer: Server died");
790
}
791
792
gboolean
793
gdm_server_stop (GdmServer *server)
794
{
795
        int res;
796
797
        if (server->priv->pid <= 1) {
798
                return TRUE;
799
        }
800
801
        /* remove watch source before we can wait on child */
802
        if (server->priv->child_watch_id > 0) {
803
                g_source_remove (server->priv->child_watch_id);
804
                server->priv->child_watch_id = 0;
805
        }
806
807
        g_debug ("GdmServer: Stopping server");
808
809
        res = gdm_signal_pid (server->priv->pid, SIGTERM);
810
        if (res < 0) {
811
        } else {
812
                server_died (server);
813
        }
814
815
        return TRUE;
816
}
817
818
819
static void
820
_gdm_server_set_display_name (GdmServer  *server,
821
                              const char *name)
822
{
823
        g_free (server->priv->display_name);
824
        server->priv->display_name = g_strdup (name);
825
}
826
827
static void
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
828
_gdm_server_set_display_seat_id (GdmServer  *server,
829
                                 const char *name)
830
{
831
        g_free (server->priv->display_seat_id);
832
        server->priv->display_seat_id = g_strdup (name);
833
}
834
835
static void
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
836
_gdm_server_set_auth_file (GdmServer  *server,
837
                           const char *auth_file)
838
{
839
        g_free (server->priv->auth_file);
840
        server->priv->auth_file = g_strdup (auth_file);
841
}
842
843
static void
844
_gdm_server_set_user_name (GdmServer  *server,
845
                           const char *name)
846
{
847
        g_free (server->priv->user_name);
848
        server->priv->user_name = g_strdup (name);
849
}
850
851
static void
852
_gdm_server_set_disable_tcp (GdmServer  *server,
853
                             gboolean    disabled)
854
{
855
        server->priv->disable_tcp = disabled;
856
}
857
858
static void
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
859
_gdm_server_set_is_initial (GdmServer  *server,
860
                            gboolean    initial)
861
{
862
        server->priv->is_initial = initial;
863
}
864
865
static void
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
866
gdm_server_set_property (GObject      *object,
867
                         guint         prop_id,
868
                         const GValue *value,
869
                         GParamSpec   *pspec)
870
{
871
        GdmServer *self;
872
873
        self = GDM_SERVER (object);
874
875
        switch (prop_id) {
876
        case PROP_DISPLAY_NAME:
877
                _gdm_server_set_display_name (self, g_value_get_string (value));
878
                break;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
879
        case PROP_DISPLAY_SEAT_ID:
880
                _gdm_server_set_display_seat_id (self, g_value_get_string (value));
881
                break;
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
882
        case PROP_AUTH_FILE:
883
                _gdm_server_set_auth_file (self, g_value_get_string (value));
884
                break;
885
        case PROP_USER_NAME:
886
                _gdm_server_set_user_name (self, g_value_get_string (value));
887
                break;
888
        case PROP_DISABLE_TCP:
889
                _gdm_server_set_disable_tcp (self, g_value_get_boolean (value));
890
                break;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
891
        case PROP_IS_INITIAL:
892
                _gdm_server_set_is_initial (self, g_value_get_boolean (value));
893
                break;
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
894
        default:
895
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
896
                break;
897
        }
898
}
899
900
static void
901
gdm_server_get_property (GObject    *object,
902
                         guint       prop_id,
903
                         GValue     *value,
904
                         GParamSpec *pspec)
905
{
906
        GdmServer *self;
907
908
        self = GDM_SERVER (object);
909
910
        switch (prop_id) {
911
        case PROP_DISPLAY_NAME:
912
                g_value_set_string (value, self->priv->display_name);
913
                break;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
914
        case PROP_DISPLAY_SEAT_ID:
915
                g_value_set_string (value, self->priv->display_seat_id);
916
                break;
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
917
        case PROP_DISPLAY_DEVICE:
918
                g_value_take_string (value,
919
                                     gdm_server_get_display_device (self));
920
                break;
921
        case PROP_AUTH_FILE:
922
                g_value_set_string (value, self->priv->auth_file);
923
                break;
924
        case PROP_USER_NAME:
925
                g_value_set_string (value, self->priv->user_name);
926
                break;
927
        case PROP_DISABLE_TCP:
928
                g_value_set_boolean (value, self->priv->disable_tcp);
929
                break;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
930
        case PROP_IS_INITIAL:
931
                g_value_set_boolean (value, self->priv->is_initial);
932
                break;
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
933
        default:
934
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
935
                break;
936
        }
937
}
938
939
static void
940
gdm_server_class_init (GdmServerClass *klass)
941
{
942
        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
943
944
        object_class->get_property = gdm_server_get_property;
945
        object_class->set_property = gdm_server_set_property;
946
        object_class->finalize = gdm_server_finalize;
947
948
        g_type_class_add_private (klass, sizeof (GdmServerPrivate));
949
950
        signals [READY] =
951
                g_signal_new ("ready",
952
                              G_TYPE_FROM_CLASS (object_class),
953
                              G_SIGNAL_RUN_LAST,
954
                              G_STRUCT_OFFSET (GdmServerClass, ready),
955
                              NULL,
956
                              NULL,
957
                              g_cclosure_marshal_VOID__VOID,
958
                              G_TYPE_NONE,
959
                              0);
960
        signals [EXITED] =
961
                g_signal_new ("exited",
962
                              G_OBJECT_CLASS_TYPE (object_class),
963
                              G_SIGNAL_RUN_FIRST,
964
                              G_STRUCT_OFFSET (GdmServerClass, exited),
965
                              NULL,
966
                              NULL,
967
                              g_cclosure_marshal_VOID__INT,
968
                              G_TYPE_NONE,
969
                              1,
970
                              G_TYPE_INT);
971
        signals [DIED] =
972
                g_signal_new ("died",
973
                              G_OBJECT_CLASS_TYPE (object_class),
974
                              G_SIGNAL_RUN_FIRST,
975
                              G_STRUCT_OFFSET (GdmServerClass, died),
976
                              NULL,
977
                              NULL,
978
                              g_cclosure_marshal_VOID__INT,
979
                              G_TYPE_NONE,
980
                              1,
981
                              G_TYPE_INT);
982
983
        g_object_class_install_property (object_class,
984
                                         PROP_DISPLAY_NAME,
985
                                         g_param_spec_string ("display-name",
986
                                                              "name",
987
                                                              "name",
988
                                                              NULL,
989
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
990
        g_object_class_install_property (object_class,
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
991
                                         PROP_DISPLAY_SEAT_ID,
992
                                         g_param_spec_string ("display-seat-id",
993
                                                              "Seat ID",
994
                                                              "ID of the seat this display is running on",
995
                                                              NULL,
996
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
997
        g_object_class_install_property (object_class,
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
998
                                         PROP_DISPLAY_DEVICE,
999
                                         g_param_spec_string ("display-device",
1000
                                                              "Display Device",
1001
                                                              "Path to terminal display is running on",
1002
                                                              NULL,
1003
                                                              G_PARAM_READABLE));
1004
        g_object_class_install_property (object_class,
1005
                                         PROP_AUTH_FILE,
1006
                                         g_param_spec_string ("auth-file",
1007
                                                              "Authorization File",
1008
                                                              "Path to X authorization file",
1009
                                                              NULL,
1010
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1011
1012
        g_object_class_install_property (object_class,
1013
                                         PROP_USER_NAME,
1014
                                         g_param_spec_string ("user-name",
1015
                                                              "user name",
1016
                                                              "user name",
1017
                                                              NULL,
1018
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
1019
        g_object_class_install_property (object_class,
1020
                                         PROP_DISABLE_TCP,
1021
                                         g_param_spec_boolean ("disable-tcp",
1022
                                                               NULL,
1023
                                                               NULL,
1024
                                                               TRUE,
1025
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
1026
        g_object_class_install_property (object_class,
1027
                                         PROP_IS_INITIAL,
1028
                                         g_param_spec_boolean ("is-initial",
1029
                                                               NULL,
1030
                                                               NULL,
1031
                                                               FALSE,
1032
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1033
}
1034
1035
static void
1036
gdm_server_init (GdmServer *server)
1037
{
1038
1039
        server->priv = GDM_SERVER_GET_PRIVATE (server);
1040
1041
        server->priv->pid = -1;
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
1042
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1043
        server->priv->log_dir = g_strdup (LOGDIR);
1044
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
1045
        server->priv->sigusr1_id = g_unix_signal_add (SIGUSR1,
1046
                                                      on_sigusr1,
1047
                                                      server);
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1048
}
1049
1050
static void
1051
gdm_server_finalize (GObject *object)
1052
{
1053
        GdmServer *server;
1054
1055
        g_return_if_fail (object != NULL);
1056
        g_return_if_fail (GDM_IS_SERVER (object));
1057
1058
        server = GDM_SERVER (object);
1059
1060
        g_return_if_fail (server->priv != NULL);
1061
1.4.55 by Jeremy Bicha
Import upstream version 3.8.1.1
1062
        if (server->priv->sigusr1_id > 0)
1063
                g_source_remove (server->priv->sigusr1_id);
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1064
1065
        gdm_server_stop (server);
1066
1.4.45 by Kees Cook
Import upstream version 2.30.4
1067
        g_free (server->priv->command);
1068
        g_free (server->priv->user_name);
1069
        g_free (server->priv->session_args);
1070
        g_free (server->priv->log_dir);
1071
        g_free (server->priv->display_name);
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
1072
        g_free (server->priv->display_seat_id);
1.4.45 by Kees Cook
Import upstream version 2.30.4
1073
        g_free (server->priv->display_device);
1074
        g_free (server->priv->auth_file);
1075
        g_free (server->priv->parent_display_name);
1076
        g_free (server->priv->parent_auth_file);
1077
        g_free (server->priv->chosen_hostname);
1078
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1079
        G_OBJECT_CLASS (gdm_server_parent_class)->finalize (object);
1080
}
1081
1082
GdmServer *
1083
gdm_server_new (const char *display_name,
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
1084
                const char *seat_id,
1085
                const char *auth_file,
1086
                gboolean    initial)
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1087
{
1088
        GObject *object;
1089
1090
        object = g_object_new (GDM_TYPE_SERVER,
1091
                               "display-name", display_name,
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
1092
                               "display-seat-id", seat_id,
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1093
                               "auth-file", auth_file,
1.4.50 by Fabien Tassin
Import upstream version 3.5.90+git20120827.b558e179
1094
                               "is-initial", initial,
1.4.31 by Sebastien Bacher
Import upstream version 2.26.1
1095
                               NULL);
1096
1097
        return GDM_SERVER (object);
1098
}