~darkxst/ubuntu/saucy/gdm/lp1212408

« back to all changes in this revision

Viewing changes to .pc/ubuntu_ensure_dirs.patch/daemon/main.c

  • Committer: Package Import Robot
  • Author(s): Tim Lunn
  • Date: 2012-10-07 07:40:28 UTC
  • Revision ID: package-import@ubuntu.com-20121007074028-f2c3v19u9oqxqf9r
Tags: 3.6.0-0ubuntu4
* debian/patches
  - add 3 upstream patches to fix logout when autologin enabled.
    (LP: #1061993)
    - ubuntu_ensure_dirs.patch
    - ubuntu_slave-only-set-up-autologin.patch
    - ubuntu_daemon_autologin_tracking.patch
 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
18
 *
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <stdlib.h>
 
24
#include <stdio.h>
 
25
#include <unistd.h>
 
26
#include <errno.h>
 
27
#include <string.h>
 
28
#include <sys/types.h>
 
29
#include <sys/stat.h>
 
30
#include <fcntl.h>
 
31
#include <pwd.h>
 
32
#include <grp.h>
 
33
#include <sys/wait.h>
 
34
#include <locale.h>
 
35
#include <signal.h>
 
36
 
 
37
#include <glib.h>
 
38
#include <glib/gi18n.h>
 
39
#include <glib/gstdio.h>
 
40
#include <glib-object.h>
 
41
#include <gio/gio.h>
 
42
 
 
43
#include "gdm-manager.h"
 
44
#include "gdm-log.h"
 
45
#include "gdm-common.h"
 
46
#include "gdm-signal-handler.h"
 
47
 
 
48
#include "gdm-settings.h"
 
49
#include "gdm-settings-direct.h"
 
50
#include "gdm-settings-keys.h"
 
51
 
 
52
#define GDM_DBUS_NAME "org.gnome.DisplayManager"
 
53
 
 
54
static GDBusConnection *get_system_bus (void);
 
55
static gboolean         bus_reconnect (void);
 
56
 
 
57
extern char **environ;
 
58
 
 
59
static GdmManager      *manager       = NULL;
 
60
static int              name_id       = -1;
 
61
static GdmSettings     *settings      = NULL;
 
62
static uid_t            gdm_uid       = -1;
 
63
static gid_t            gdm_gid       = -1;
 
64
 
 
65
static gboolean
 
66
timed_exit_cb (GMainLoop *loop)
 
67
{
 
68
        g_main_loop_quit (loop);
 
69
        return FALSE;
 
70
}
 
71
 
 
72
static void
 
73
bus_connection_closed (void)
 
74
{
 
75
        g_debug ("Disconnected from D-Bus");
 
76
 
 
77
        if (manager == NULL) {
 
78
                /* probably shutting down or something */
 
79
                return;
 
80
        }
 
81
 
 
82
        g_clear_object (&manager);
 
83
 
 
84
        g_timeout_add_seconds (3, (GSourceFunc)bus_reconnect, NULL);
 
85
}
 
86
 
 
87
static GDBusConnection *
 
88
get_system_bus (void)
 
89
{
 
90
        GError          *error;
 
91
        GDBusConnection *bus;
 
92
 
 
93
        error = NULL;
 
94
        bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
 
95
        if (bus == NULL) {
 
96
                g_warning ("Couldn't connect to system bus: %s",
 
97
                           error->message);
 
98
                g_error_free (error);
 
99
                goto out;
 
100
        }
 
101
 
 
102
        g_signal_connect (bus, "closed",
 
103
                          G_CALLBACK (bus_connection_closed), NULL);
 
104
        g_dbus_connection_set_exit_on_close (bus, FALSE);
 
105
 
 
106
 out:
 
107
        return bus;
 
108
}
 
109
 
 
110
static void
 
111
delete_pid (void)
 
112
{
 
113
        g_unlink (GDM_PID_FILE);
 
114
}
 
115
 
 
116
static void
 
117
write_pid (void)
 
118
{
 
119
        int     pf;
 
120
        ssize_t written;
 
121
        char    pid[9];
 
122
 
 
123
        errno = 0;
 
124
        pf = open (GDM_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
 
125
        if (pf < 0) {
 
126
                g_warning (_("Cannot write PID file %s: possibly out of disk space: %s"),
 
127
                           GDM_PID_FILE,
 
128
                           g_strerror (errno));
 
129
 
 
130
                return;
 
131
        }
 
132
 
 
133
        snprintf (pid, sizeof (pid), "%lu\n", (long unsigned) getpid ());
 
134
        errno = 0;
 
135
        written = write (pf, pid, strlen (pid));
 
136
        close (pf);
 
137
 
 
138
        if (written < 0) {
 
139
                g_warning (_("Cannot write PID file %s: possibly out of disk space: %s"),
 
140
                           GDM_PID_FILE,
 
141
                           g_strerror (errno));
 
142
                return;
 
143
        }
 
144
 
 
145
        atexit (delete_pid);
 
146
}
 
147
 
 
148
static void
 
149
check_logdir (void)
 
150
{
 
151
        struct stat     statbuf;
 
152
        int             r;
 
153
        const char     *log_path;
 
154
 
 
155
        log_path = LOGDIR;
 
156
 
 
157
        r = g_stat (log_path, &statbuf);
 
158
        if (r < 0 || ! S_ISDIR (statbuf.st_mode))  {
 
159
                if (g_mkdir (log_path, 0755) < 0) {
 
160
                        gdm_fail (_("Logdir %s does not exist or isn't a directory."),
 
161
                                  log_path);
 
162
                }
 
163
                g_chmod (log_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
 
164
        }
 
165
}
 
166
 
 
167
static void
 
168
check_servauthdir (const char  *auth_path,
 
169
                   struct stat *statbuf)
 
170
{
 
171
        int r;
 
172
 
 
173
        /* Enter paranoia mode */
 
174
        r = g_stat (auth_path, statbuf);
 
175
        if (r < 0) {
 
176
                gdm_fail (_("Authdir %s does not exist. Aborting."), auth_path);
 
177
        }
 
178
 
 
179
        if (! S_ISDIR (statbuf->st_mode)) {
 
180
                gdm_fail (_("Authdir %s is not a directory. Aborting."), auth_path);
 
181
        }
 
182
}
 
183
 
 
184
static void
 
185
set_effective_user (uid_t uid)
 
186
{
 
187
        int res;
 
188
 
 
189
        res = 0;
 
190
 
 
191
        if (geteuid () != uid) {
 
192
                res = seteuid (uid);
 
193
        }
 
194
 
 
195
        if (res != 0) {
 
196
                g_error ("Cannot set uid to %d: %s",
 
197
                         (int)uid,
 
198
                         g_strerror (errno));
 
199
        }
 
200
}
 
201
 
 
202
static void
 
203
set_effective_group (gid_t gid)
 
204
{
 
205
        int res;
 
206
 
 
207
        res = 0;
 
208
        if (getegid () != gid) {
 
209
                res = setegid (gid);
 
210
        }
 
211
 
 
212
        if (res != 0) {
 
213
                g_error ("Cannot set gid to %d: %s",
 
214
                         (int)gid,
 
215
                         g_strerror (errno));
 
216
        }
 
217
}
 
218
 
 
219
static void
 
220
set_effective_user_group (uid_t uid,
 
221
                          gid_t gid)
 
222
{
 
223
        set_effective_user (0);
 
224
        set_effective_group (gid);
 
225
        if (uid != 0) {
 
226
                set_effective_user (0);
 
227
        }
 
228
}
 
229
 
 
230
static void
 
231
gdm_daemon_check_permissions (uid_t uid,
 
232
                              gid_t gid)
 
233
{
 
234
        struct stat statbuf;
 
235
        const char *auth_path;
 
236
 
 
237
        auth_path = LOGDIR;
 
238
 
 
239
        /* Enter paranoia mode */
 
240
        check_servauthdir (auth_path, &statbuf);
 
241
 
 
242
        set_effective_user_group (0, 0);
 
243
 
 
244
        /* Now set things up for us as  */
 
245
        chown (auth_path, 0, gid);
 
246
        g_chmod (auth_path, (S_IRWXU|S_IRWXG|S_ISVTX));
 
247
 
 
248
        set_effective_user_group (uid, gid);
 
249
 
 
250
        /* Again paranoid */
 
251
        check_servauthdir (auth_path, &statbuf);
 
252
 
 
253
        if G_UNLIKELY (statbuf.st_uid != 0 || statbuf.st_gid != gid)  {
 
254
                gdm_fail (_("Authdir %s is not owned by user %d, group %d. Aborting."),
 
255
                          auth_path,
 
256
                          (int)uid,
 
257
                          (int)gid);
 
258
        }
 
259
 
 
260
        if G_UNLIKELY (statbuf.st_mode != (S_IFDIR|S_IRWXU|S_IRWXG|S_ISVTX))  {
 
261
                gdm_fail (_("Authdir %s has wrong permissions %o. Should be %o. Aborting."),
 
262
                          auth_path,
 
263
                          statbuf.st_mode,
 
264
                          (S_IRWXU|S_IRWXG|S_ISVTX));
 
265
        }
 
266
}
 
267
 
 
268
static void
 
269
gdm_daemon_change_user (uid_t *uidp,
 
270
                        gid_t *gidp)
 
271
{
 
272
        char          *username;
 
273
        char          *groupname;
 
274
        uid_t          uid;
 
275
        gid_t          gid;
 
276
        struct passwd *pwent;
 
277
        struct group  *grent;
 
278
 
 
279
        username = NULL;
 
280
        groupname = NULL;
 
281
        uid = 0;
 
282
        gid = 0;
 
283
 
 
284
        gdm_settings_direct_get_string (GDM_KEY_USER, &username);
 
285
        gdm_settings_direct_get_string (GDM_KEY_GROUP, &groupname);
 
286
 
 
287
        if (username == NULL || groupname == NULL) {
 
288
                return;
 
289
        }
 
290
 
 
291
        g_debug ("Changing user:group to %s:%s", username, groupname);
 
292
 
 
293
        /* Lookup user and groupid for the GDM user */
 
294
        gdm_get_pwent_for_name (username, &pwent);
 
295
 
 
296
        /* Set uid and gid */
 
297
        if G_UNLIKELY (pwent == NULL) {
 
298
                gdm_fail (_("Can't find the GDM user '%s'. Aborting!"), username);
 
299
        } else {
 
300
                uid = pwent->pw_uid;
 
301
        }
 
302
 
 
303
        if G_UNLIKELY (uid == 0) {
 
304
                gdm_fail (_("The GDM user should not be root. Aborting!"));
 
305
        }
 
306
 
 
307
        grent = getgrnam (groupname);
 
308
 
 
309
        if G_UNLIKELY (grent == NULL) {
 
310
                gdm_fail (_("Can't find the GDM group '%s'. Aborting!"), groupname);
 
311
        } else  {
 
312
                gid = grent->gr_gid;
 
313
        }
 
314
 
 
315
        if G_UNLIKELY (gid == 0) {
 
316
                gdm_fail (_("The GDM group should not be root. Aborting!"));
 
317
        }
 
318
 
 
319
        /* gid remains 'gdm' */
 
320
        set_effective_user_group (uid, gid);
 
321
 
 
322
        if (uidp != NULL) {
 
323
                *uidp = uid;
 
324
        }
 
325
 
 
326
        if (gidp != NULL) {
 
327
                *gidp = gid;
 
328
        }
 
329
 
 
330
        g_free (username);
 
331
        g_free (groupname);
 
332
}
 
333
 
 
334
static gboolean
 
335
signal_cb (int      signo,
 
336
           gpointer data)
 
337
{
 
338
        int ret;
 
339
 
 
340
        g_debug ("Got callback for signal %d", signo);
 
341
 
 
342
        ret = TRUE;
 
343
 
 
344
        switch (signo) {
 
345
        case SIGFPE:
 
346
        case SIGPIPE:
 
347
                /* let the fatal signals interrupt us */
 
348
                g_debug ("Caught signal %d, shutting down abnormally.", signo);
 
349
                ret = FALSE;
 
350
 
 
351
                break;
 
352
 
 
353
        case SIGINT:
 
354
        case SIGTERM:
 
355
                /* let the fatal signals interrupt us */
 
356
                g_debug ("Caught signal %d, shutting down normally.", signo);
 
357
                ret = FALSE;
 
358
 
 
359
                break;
 
360
 
 
361
        case SIGHUP:
 
362
                g_debug ("Got HUP signal");
 
363
                /* Reread config stuff like system config files, VPN service
 
364
                 * files, etc
 
365
                 */
 
366
                g_object_unref (settings);
 
367
                settings = gdm_settings_new ();
 
368
                if (settings != NULL) {
 
369
                        if (! gdm_settings_direct_init (settings, GDMCONFDIR "/gdm.schemas", "/")) {
 
370
                                g_warning ("Unable to initialize settings");
 
371
                        }
 
372
                }
 
373
 
 
374
                ret = TRUE;
 
375
 
 
376
                break;
 
377
 
 
378
        case SIGUSR1:
 
379
                g_debug ("Got USR1 signal");
 
380
                /* FIXME:
 
381
                 * Play with log levels or something
 
382
                 */
 
383
                ret = TRUE;
 
384
 
 
385
                gdm_log_toggle_debug ();
 
386
 
 
387
                break;
 
388
 
 
389
        default:
 
390
                g_debug ("Caught unhandled signal %d", signo);
 
391
                ret = TRUE;
 
392
 
 
393
                break;
 
394
        }
 
395
 
 
396
        return ret;
 
397
}
 
398
 
 
399
static gboolean
 
400
is_debug_set (void)
 
401
{
 
402
        gboolean debug = FALSE;
 
403
 
 
404
        /* enable debugging for unstable builds */
 
405
        if (gdm_is_version_unstable ()) {
 
406
                return TRUE;
 
407
        }
 
408
 
 
409
        gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug);
 
410
        return debug;
 
411
}
 
412
 
 
413
int
 
414
main (int    argc,
 
415
      char **argv)
 
416
{
 
417
        GMainLoop          *main_loop;
 
418
        GOptionContext     *context;
 
419
        GError             *error;
 
420
        int                 ret;
 
421
        gboolean            res;
 
422
        GdmSignalHandler   *signal_handler;
 
423
        static gboolean     do_timed_exit    = FALSE;
 
424
        static gboolean     print_version    = FALSE;
 
425
        static gboolean     fatal_warnings   = FALSE;
 
426
        static GOptionEntry entries []   = {
 
427
                { "fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &fatal_warnings, N_("Make all warnings fatal"), NULL },
 
428
                { "timed-exit", 0, 0, G_OPTION_ARG_NONE, &do_timed_exit, N_("Exit after a time (for debugging)"), NULL },
 
429
                { "version", 0, 0, G_OPTION_ARG_NONE, &print_version, N_("Print GDM version"), NULL },
 
430
 
 
431
                { NULL }
 
432
        };
 
433
 
 
434
        bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
 
435
        textdomain (GETTEXT_PACKAGE);
 
436
        setlocale (LC_ALL, "");
 
437
 
 
438
        ret = 1;
 
439
 
 
440
        g_type_init ();
 
441
 
 
442
        context = g_option_context_new (_("GNOME Display Manager"));
 
443
        g_option_context_add_main_entries (context, entries, NULL);
 
444
        g_option_context_set_ignore_unknown_options (context, TRUE);
 
445
 
 
446
        error = NULL;
 
447
        res = g_option_context_parse (context, &argc, &argv, &error);
 
448
        g_option_context_free (context);
 
449
        if (! res) {
 
450
                g_warning ("%s", error->message);
 
451
                g_error_free (error);
 
452
                goto out;
 
453
        }
 
454
 
 
455
        if (print_version) {
 
456
                g_print ("GDM %s\n", VERSION);
 
457
                exit (1);
 
458
        }
 
459
 
 
460
        if (fatal_warnings) {
 
461
                GLogLevelFlags fatal_mask;
 
462
 
 
463
                fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
 
464
                fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
 
465
                g_log_set_always_fatal (fatal_mask);
 
466
        }
 
467
 
 
468
        gdm_log_init ();
 
469
 
 
470
        settings = gdm_settings_new ();
 
471
        if (settings == NULL) {
 
472
                g_warning ("Unable to initialize settings");
 
473
                goto out;
 
474
        }
 
475
 
 
476
        if (! gdm_settings_direct_init (settings, DATADIR "/gdm/gdm.schemas", "/")) {
 
477
                g_warning ("Unable to initialize settings");
 
478
                goto out;
 
479
        }
 
480
 
 
481
        gdm_log_set_debug (is_debug_set ());
 
482
 
 
483
        gdm_daemon_change_user (&gdm_uid, &gdm_gid);
 
484
        gdm_daemon_check_permissions (gdm_uid, gdm_gid);
 
485
 
 
486
        set_effective_user_group (0, 0);
 
487
        check_logdir ();
 
488
 
 
489
        /* XDM compliant error message */
 
490
        if (getuid () != 0) {
 
491
                /* make sure the pid file doesn't get wiped */
 
492
                g_warning (_("Only the root user can run GDM"));
 
493
                exit (-1);
 
494
        }
 
495
 
 
496
        /* Connect to the bus, own the name and start the manager */
 
497
        bus_reconnect ();
 
498
 
 
499
        /* pid file */
 
500
        delete_pid ();
 
501
        write_pid ();
 
502
 
 
503
        g_chdir (AUTHDIR);
 
504
 
 
505
        main_loop = g_main_loop_new (NULL, FALSE);
 
506
 
 
507
        signal_handler = gdm_signal_handler_new ();
 
508
        gdm_signal_handler_set_fatal_func (signal_handler,
 
509
                                           (GDestroyNotify)g_main_loop_quit,
 
510
                                           main_loop);
 
511
        gdm_signal_handler_add_fatal (signal_handler);
 
512
        gdm_signal_handler_add (signal_handler, SIGTERM, signal_cb, NULL);
 
513
        gdm_signal_handler_add (signal_handler, SIGINT, signal_cb, NULL);
 
514
        gdm_signal_handler_add (signal_handler, SIGFPE, signal_cb, NULL);
 
515
        gdm_signal_handler_add (signal_handler, SIGHUP, signal_cb, NULL);
 
516
        gdm_signal_handler_add (signal_handler, SIGUSR1, signal_cb, NULL);
 
517
 
 
518
        if (do_timed_exit) {
 
519
                g_timeout_add_seconds (30, (GSourceFunc) timed_exit_cb, main_loop);
 
520
        }
 
521
 
 
522
        g_main_loop_run (main_loop);
 
523
 
 
524
        g_debug ("GDM finished, cleaning up...");
 
525
 
 
526
        g_clear_object (&manager);
 
527
        g_clear_object (&settings);
 
528
        g_clear_object (&signal_handler);
 
529
 
 
530
        gdm_settings_direct_shutdown ();
 
531
        gdm_log_shutdown ();
 
532
 
 
533
        g_main_loop_unref (main_loop);
 
534
 
 
535
        ret = 0;
 
536
 
 
537
 out:
 
538
 
 
539
        return ret;
 
540
}
 
541
 
 
542
static void
 
543
on_name_acquired (GDBusConnection *bus,
 
544
                  const char      *name,
 
545
                  gpointer         user_data)
 
546
{
 
547
        gboolean xdmcp_enabled;
 
548
        gboolean show_local_greeter;
 
549
 
 
550
        manager = gdm_manager_new ();
 
551
        if (manager == NULL) {
 
552
                g_warning ("Could not construct manager object");
 
553
                exit (1);
 
554
        }
 
555
 
 
556
        g_debug ("Successfully connected to D-Bus");
 
557
 
 
558
        gdm_manager_start (manager);
 
559
 
 
560
        show_local_greeter = TRUE;
 
561
        gdm_settings_direct_get_boolean (GDM_KEY_SHOW_LOCAL_GREETER, &show_local_greeter);
 
562
        gdm_manager_set_show_local_greeter (manager, show_local_greeter);
 
563
 
 
564
        xdmcp_enabled = FALSE;
 
565
        gdm_settings_direct_get_boolean (GDM_KEY_XDMCP_ENABLE, &xdmcp_enabled);
 
566
        gdm_manager_set_xdmcp_enabled (manager, xdmcp_enabled);
 
567
}
 
568
 
 
569
static void
 
570
on_name_lost (GDBusConnection *bus,
 
571
              const char      *name,
 
572
              gpointer         user_data)
 
573
{
 
574
        g_debug ("Lost GDM name on bus");
 
575
 
 
576
        bus_connection_closed ();
 
577
}
 
578
 
 
579
static gboolean
 
580
bus_reconnect ()
 
581
{
 
582
        GDBusConnection *bus;
 
583
        gboolean         ret;
 
584
 
 
585
        ret = TRUE;
 
586
 
 
587
        bus = get_system_bus ();
 
588
        if (bus == NULL) {
 
589
                goto out;
 
590
        }
 
591
 
 
592
        name_id = g_bus_own_name_on_connection (bus,
 
593
                                                GDM_DBUS_NAME,
 
594
                                                G_BUS_NAME_OWNER_FLAGS_NONE,
 
595
                                                on_name_acquired,
 
596
                                                on_name_lost,
 
597
                                                NULL,
 
598
                                                NULL);
 
599
 
 
600
        ret = FALSE;
 
601
 out:
 
602
        return ret;
 
603
}