source: proiecte/PPPP/gdm/daemon/main.c @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

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