source: proiecte/PPPP/gdm/daemon/gdm-chooser-server.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: 22.2 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
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 <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
35#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
36#include <sched.h>
37#endif
38
39#include <glib.h>
40#include <glib/gi18n.h>
41#include <glib-object.h>
42#define DBUS_API_SUBJECT_TO_CHANGE
43#include <dbus/dbus-glib.h>
44#include <dbus/dbus-glib-lowlevel.h>
45
46#include "gdm-chooser-server.h"
47
48#define GDM_CHOOSER_SERVER_DBUS_PATH      "/org/gnome/DisplayManager/ChooserServer"
49#define GDM_CHOOSER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.ChooserServer"
50
51#define GDM_CHOOSER_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_SERVER, GdmChooserServerPrivate))
52
53struct GdmChooserServerPrivate
54{
55        char           *user_name;
56        char           *group_name;
57        char           *display_id;
58
59        DBusServer     *server;
60        char           *server_address;
61        DBusConnection *chooser_connection;
62};
63
64enum {
65        PROP_0,
66        PROP_USER_NAME,
67        PROP_GROUP_NAME,
68        PROP_DISPLAY_ID,
69};
70
71enum {
72        HOSTNAME_SELECTED,
73        CONNECTED,
74        DISCONNECTED,
75        LAST_SIGNAL
76};
77
78static guint signals [LAST_SIGNAL] = { 0, };
79
80static void     gdm_chooser_server_class_init   (GdmChooserServerClass *klass);
81static void     gdm_chooser_server_init         (GdmChooserServer      *chooser_server);
82static void     gdm_chooser_server_finalize     (GObject               *object);
83
84G_DEFINE_TYPE (GdmChooserServer, gdm_chooser_server, G_TYPE_OBJECT)
85
86/* Note: Use abstract sockets like dbus does by default on Linux. Abstract
87 * sockets are only available on Linux.
88 */
89static char *
90generate_address (void)
91{
92        char *path;
93#if defined (__linux__)
94        int   i;
95        char  tmp[9];
96
97        for (i = 0; i < 8; i++) {
98                if (g_random_int_range (0, 2) == 0) {
99                        tmp[i] = g_random_int_range ('a', 'z' + 1);
100                } else {
101                        tmp[i] = g_random_int_range ('A', 'Z' + 1);
102                }
103        }
104        tmp[8] = '\0';
105
106        path = g_strdup_printf ("unix:abstract=/tmp/gdm-chooser-%s", tmp);
107#else
108        path = g_strdup ("unix:tmpdir=/tmp");
109#endif
110
111        return path;
112}
113
114static DBusHandlerResult
115handle_select_hostname (GdmChooserServer *chooser_server,
116                        DBusConnection   *connection,
117                        DBusMessage      *message)
118{
119        DBusMessage *reply;
120        DBusError    error;
121        const char  *text;
122
123        dbus_error_init (&error);
124        if (! dbus_message_get_args (message, &error,
125                                     DBUS_TYPE_STRING, &text,
126                                     DBUS_TYPE_INVALID)) {
127                g_warning ("ERROR: %s", error.message);
128        }
129
130        g_debug ("ChooserServer: SelectHostname: %s", text);
131
132        reply = dbus_message_new_method_return (message);
133        dbus_connection_send (connection, reply, NULL);
134        if (reply != NULL) {
135                dbus_message_unref (reply);
136        }
137
138        g_signal_emit (chooser_server, signals [HOSTNAME_SELECTED], 0, text);
139
140        return DBUS_HANDLER_RESULT_HANDLED;
141}
142
143static DBusHandlerResult
144handle_disconnect (GdmChooserServer *chooser_server,
145                   DBusConnection   *connection,
146                   DBusMessage      *message)
147{
148        DBusMessage *reply;
149
150        reply = dbus_message_new_method_return (message);
151        dbus_connection_send (connection, reply, NULL);
152        if (reply != NULL) {
153                dbus_message_unref (reply);
154        }
155
156        g_signal_emit (chooser_server, signals [DISCONNECTED], 0);
157
158        return DBUS_HANDLER_RESULT_HANDLED;
159}
160
161static DBusHandlerResult
162chooser_handle_child_message (DBusConnection *connection,
163                              DBusMessage    *message,
164                              void           *user_data)
165{
166        GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data);
167
168        if (dbus_message_is_method_call (message, GDM_CHOOSER_SERVER_DBUS_INTERFACE, "SelectHostname")) {
169                return handle_select_hostname (chooser_server, connection, message);
170        } else if (dbus_message_is_method_call (message, GDM_CHOOSER_SERVER_DBUS_INTERFACE, "Disconnect")) {
171                return handle_disconnect (chooser_server, connection, message);
172        }
173
174        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
175}
176
177static DBusHandlerResult
178do_introspect (DBusConnection *connection,
179               DBusMessage    *message)
180{
181        DBusMessage *reply;
182        GString     *xml;
183        char        *xml_string;
184
185        g_debug ("ChooserServer: Do introspect");
186
187        /* standard header */
188        xml = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
189                            "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
190                            "<node>\n"
191                            "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
192                            "    <method name=\"Introspect\">\n"
193                            "      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
194                            "    </method>\n"
195                            "  </interface>\n");
196
197        /* interface */
198        xml = g_string_append (xml,
199                               "  <interface name=\"org.gnome.DisplayManager.ChooserServer\">\n"
200                               "    <method name=\"SelectHostname\">\n"
201                               "      <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
202                               "    </method>\n"
203                               "    <method name=\"Disconnect\">\n"
204                               "    </method>\n"
205                               "  </interface>\n");
206
207        reply = dbus_message_new_method_return (message);
208
209        xml = g_string_append (xml, "</node>\n");
210        xml_string = g_string_free (xml, FALSE);
211
212        dbus_message_append_args (reply,
213                                  DBUS_TYPE_STRING, &xml_string,
214                                  DBUS_TYPE_INVALID);
215
216        g_free (xml_string);
217
218        if (reply == NULL) {
219                g_error ("No memory");
220        }
221
222        if (! dbus_connection_send (connection, reply, NULL)) {
223                g_error ("No memory");
224        }
225
226        if (reply != NULL) {
227                dbus_message_unref (reply);
228        }
229
230        return DBUS_HANDLER_RESULT_HANDLED;
231}
232
233static DBusHandlerResult
234chooser_server_message_handler (DBusConnection  *connection,
235                                DBusMessage     *message,
236                                void            *user_data)
237{
238        const char *dbus_destination = dbus_message_get_destination (message);
239        const char *dbus_path        = dbus_message_get_path (message);
240        const char *dbus_interface   = dbus_message_get_interface (message);
241        const char *dbus_member      = dbus_message_get_member (message);
242
243        g_debug ("chooser_server_message_handler: destination=%s obj_path=%s interface=%s method=%s",
244                 dbus_destination ? dbus_destination : "(null)",
245                 dbus_path        ? dbus_path        : "(null)",
246                 dbus_interface   ? dbus_interface   : "(null)",
247                 dbus_member      ? dbus_member      : "(null)");
248
249        if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
250                DBusMessage *reply;
251
252                reply = dbus_message_new_method_return (message);
253
254                if (reply == NULL) {
255                        g_error ("No memory");
256                }
257
258                if (! dbus_connection_send (connection, reply, NULL)) {
259                        g_error ("No memory");
260                }
261
262                dbus_message_unref (reply);
263
264                return DBUS_HANDLER_RESULT_HANDLED;
265        } else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
266                   strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
267
268                /*dbus_connection_unref (connection);*/
269
270                return DBUS_HANDLER_RESULT_HANDLED;
271        } else if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
272                return do_introspect (connection, message);
273        } else {
274                return chooser_handle_child_message (connection, message, user_data);
275        }
276
277        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
278}
279
280static void
281chooser_server_unregister_handler (DBusConnection  *connection,
282                                   void            *user_data)
283{
284        g_debug ("chooser_server_unregister_handler");
285}
286
287static DBusHandlerResult
288connection_filter_function (DBusConnection *connection,
289                            DBusMessage    *message,
290                            void           *user_data)
291{
292        GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data);
293        const char       *dbus_path      = dbus_message_get_path (message);
294        const char       *dbus_interface = dbus_message_get_interface (message);
295        const char       *dbus_message   = dbus_message_get_member (message);
296
297        g_debug ("ChooserServer: obj_path=%s interface=%s method=%s",
298                 dbus_path      ? dbus_path      : "(null)",
299                 dbus_interface ? dbus_interface : "(null)",
300                 dbus_message   ? dbus_message   : "(null)");
301
302        if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")
303            && strcmp (dbus_path, DBUS_PATH_LOCAL) == 0) {
304
305                g_debug ("ChooserServer: Disconnected");
306
307                dbus_connection_unref (connection);
308                chooser_server->priv->chooser_connection = NULL;
309
310                return DBUS_HANDLER_RESULT_HANDLED;
311        }
312
313        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
314}
315
316static dbus_bool_t
317allow_user_function (DBusConnection *connection,
318                     unsigned long   uid,
319                     void           *data)
320{
321        GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (data);
322        struct passwd    *pwent;
323
324        if (chooser_server->priv->user_name == NULL) {
325                return FALSE;
326        }
327
328        pwent = getpwnam (chooser_server->priv->user_name);
329        if (pwent == NULL) {
330                return FALSE;
331        }
332
333        if (pwent->pw_uid == uid) {
334                return TRUE;
335        }
336
337        return FALSE;
338}
339
340static void
341handle_connection (DBusServer      *server,
342                   DBusConnection  *new_connection,
343                   void            *user_data)
344{
345        GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data);
346
347        g_debug ("ChooserServer: Handing new connection");
348
349        if (chooser_server->priv->chooser_connection == NULL) {
350                DBusObjectPathVTable vtable = { &chooser_server_unregister_handler,
351                                                &chooser_server_message_handler,
352                                                NULL, NULL, NULL, NULL
353                };
354
355                chooser_server->priv->chooser_connection = new_connection;
356                dbus_connection_ref (new_connection);
357                dbus_connection_setup_with_g_main (new_connection, NULL);
358
359                g_debug ("ChooserServer: chooser connection is %p", new_connection);
360
361                dbus_connection_add_filter (new_connection,
362                                            connection_filter_function,
363                                            chooser_server,
364                                            NULL);
365
366                dbus_connection_set_unix_user_function (new_connection,
367                                                        allow_user_function,
368                                                        chooser_server,
369                                                        NULL);
370
371                dbus_connection_register_object_path (new_connection,
372                                                      GDM_CHOOSER_SERVER_DBUS_PATH,
373                                                      &vtable,
374                                                      chooser_server);
375
376                g_signal_emit (chooser_server, signals[CONNECTED], 0);
377
378        }
379}
380
381gboolean
382gdm_chooser_server_start (GdmChooserServer *chooser_server)
383{
384        DBusError   error;
385        gboolean    ret;
386        char       *address;
387        const char *auth_mechanisms[] = {"EXTERNAL", NULL};
388
389        ret = FALSE;
390
391        g_debug ("ChooserServer: Creating D-Bus server for chooser");
392
393        address = generate_address ();
394
395        dbus_error_init (&error);
396        chooser_server->priv->server = dbus_server_listen (address, &error);
397        g_free (address);
398
399        if (chooser_server->priv->server == NULL) {
400                g_warning ("Cannot create D-BUS server for the chooser: %s", error.message);
401                /* FIXME: should probably fail if we can't create the socket */
402                goto out;
403        }
404
405        dbus_server_setup_with_g_main (chooser_server->priv->server, NULL);
406        dbus_server_set_auth_mechanisms (chooser_server->priv->server, auth_mechanisms);
407        dbus_server_set_new_connection_function (chooser_server->priv->server,
408                                                 handle_connection,
409                                                 chooser_server,
410                                                 NULL);
411        ret = TRUE;
412
413        g_free (chooser_server->priv->server_address);
414        chooser_server->priv->server_address = dbus_server_get_address (chooser_server->priv->server);
415
416        g_debug ("ChooserServer: D-Bus server listening on %s", chooser_server->priv->server_address);
417
418 out:
419
420        return ret;
421}
422
423gboolean
424gdm_chooser_server_stop (GdmChooserServer *chooser_server)
425{
426        gboolean ret;
427
428        ret = FALSE;
429
430        g_debug ("ChooserServer: Stopping chooser server...");
431
432        return ret;
433}
434
435char *
436gdm_chooser_server_get_address (GdmChooserServer *chooser_server)
437{
438        return g_strdup (chooser_server->priv->server_address);
439}
440
441static void
442_gdm_chooser_server_set_display_id (GdmChooserServer *chooser_server,
443                                    const char       *display_id)
444{
445        g_free (chooser_server->priv->display_id);
446        chooser_server->priv->display_id = g_strdup (display_id);
447}
448
449static void
450_gdm_chooser_server_set_user_name (GdmChooserServer *chooser_server,
451                                  const char *name)
452{
453        g_free (chooser_server->priv->user_name);
454        chooser_server->priv->user_name = g_strdup (name);
455}
456
457static void
458_gdm_chooser_server_set_group_name (GdmChooserServer *chooser_server,
459                                    const char *name)
460{
461        g_free (chooser_server->priv->group_name);
462        chooser_server->priv->group_name = g_strdup (name);
463}
464
465static void
466gdm_chooser_server_set_property (GObject      *object,
467                                guint         prop_id,
468                                const GValue *value,
469                                GParamSpec   *pspec)
470{
471        GdmChooserServer *self;
472
473        self = GDM_CHOOSER_SERVER (object);
474
475        switch (prop_id) {
476        case PROP_DISPLAY_ID:
477                _gdm_chooser_server_set_display_id (self, g_value_get_string (value));
478                break;
479        case PROP_USER_NAME:
480                _gdm_chooser_server_set_user_name (self, g_value_get_string (value));
481                break;
482        case PROP_GROUP_NAME:
483                _gdm_chooser_server_set_group_name (self, g_value_get_string (value));
484                break;
485        default:
486                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
487                break;
488        }
489}
490
491static void
492gdm_chooser_server_get_property (GObject    *object,
493                                guint       prop_id,
494                                GValue     *value,
495                                GParamSpec *pspec)
496{
497        GdmChooserServer *self;
498
499        self = GDM_CHOOSER_SERVER (object);
500
501        switch (prop_id) {
502        case PROP_DISPLAY_ID:
503                g_value_set_string (value, self->priv->display_id);
504                break;
505        case PROP_USER_NAME:
506                g_value_set_string (value, self->priv->user_name);
507                break;
508        case PROP_GROUP_NAME:
509                g_value_set_string (value, self->priv->group_name);
510                break;
511        default:
512                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
513                break;
514        }
515}
516
517static GObject *
518gdm_chooser_server_constructor (GType                  type,
519                               guint                  n_construct_properties,
520                               GObjectConstructParam *construct_properties)
521{
522        GdmChooserServer      *chooser_server;
523
524        chooser_server = GDM_CHOOSER_SERVER (G_OBJECT_CLASS (gdm_chooser_server_parent_class)->constructor (type,
525                                                                                       n_construct_properties,
526                                                                                       construct_properties));
527
528        return G_OBJECT (chooser_server);
529}
530
531static void
532gdm_chooser_server_class_init (GdmChooserServerClass *klass)
533{
534        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
535
536        object_class->get_property = gdm_chooser_server_get_property;
537        object_class->set_property = gdm_chooser_server_set_property;
538        object_class->constructor = gdm_chooser_server_constructor;
539        object_class->finalize = gdm_chooser_server_finalize;
540
541        g_type_class_add_private (klass, sizeof (GdmChooserServerPrivate));
542
543        g_object_class_install_property (object_class,
544                                         PROP_DISPLAY_ID,
545                                         g_param_spec_string ("display-id",
546                                                              "display id",
547                                                              "display id",
548                                                              NULL,
549                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
550         g_object_class_install_property (object_class,
551                                         PROP_USER_NAME,
552                                         g_param_spec_string ("user-name",
553                                                              "user name",
554                                                              "user name",
555                                                              GDM_USERNAME,
556                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
557        g_object_class_install_property (object_class,
558                                         PROP_GROUP_NAME,
559                                         g_param_spec_string ("group-name",
560                                                              "group name",
561                                                              "group name",
562                                                              GDM_GROUPNAME,
563                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
564        signals [HOSTNAME_SELECTED] =
565                g_signal_new ("hostname-selected",
566                              G_OBJECT_CLASS_TYPE (object_class),
567                              G_SIGNAL_RUN_FIRST,
568                              G_STRUCT_OFFSET (GdmChooserServerClass, hostname_selected),
569                              NULL,
570                              NULL,
571                              g_cclosure_marshal_VOID__STRING,
572                              G_TYPE_NONE,
573                              1,
574                              G_TYPE_STRING);
575        signals [CONNECTED] =
576                g_signal_new ("connected",
577                              G_OBJECT_CLASS_TYPE (object_class),
578                              G_SIGNAL_RUN_FIRST,
579                              G_STRUCT_OFFSET (GdmChooserServerClass, connected),
580                              NULL,
581                              NULL,
582                              g_cclosure_marshal_VOID__VOID,
583                              G_TYPE_NONE,
584                              0);
585        signals [DISCONNECTED] =
586                g_signal_new ("disconnected",
587                              G_OBJECT_CLASS_TYPE (object_class),
588                              G_SIGNAL_RUN_FIRST,
589                              G_STRUCT_OFFSET (GdmChooserServerClass, disconnected),
590                              NULL,
591                              NULL,
592                              g_cclosure_marshal_VOID__VOID,
593                              G_TYPE_NONE,
594                              0);
595}
596
597static void
598gdm_chooser_server_init (GdmChooserServer *chooser_server)
599{
600
601        chooser_server->priv = GDM_CHOOSER_SERVER_GET_PRIVATE (chooser_server);
602}
603
604static void
605gdm_chooser_server_finalize (GObject *object)
606{
607        GdmChooserServer *chooser_server;
608
609        g_return_if_fail (object != NULL);
610        g_return_if_fail (GDM_IS_CHOOSER_SERVER (object));
611
612        chooser_server = GDM_CHOOSER_SERVER (object);
613
614        g_return_if_fail (chooser_server->priv != NULL);
615
616        gdm_chooser_server_stop (chooser_server);
617
618        G_OBJECT_CLASS (gdm_chooser_server_parent_class)->finalize (object);
619}
620
621GdmChooserServer *
622gdm_chooser_server_new (const char *display_id)
623{
624        GObject *object;
625
626        object = g_object_new (GDM_TYPE_CHOOSER_SERVER,
627                               "display-id", display_id,
628                               NULL);
629
630        return GDM_CHOOSER_SERVER (object);
631}
Note: See TracBrowser for help on using the repository browser.