[134] | 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 | |
---|
| 32 | #include <glib.h> |
---|
| 33 | #include <glib/gi18n.h> |
---|
| 34 | #include <glib/gstdio.h> |
---|
| 35 | #include <glib-object.h> |
---|
| 36 | |
---|
| 37 | #define DBUS_API_SUBJECT_TO_CHANGE |
---|
| 38 | #include <dbus/dbus-glib.h> |
---|
| 39 | #include <dbus/dbus-glib-lowlevel.h> |
---|
| 40 | |
---|
| 41 | #include <X11/Xlib.h> /* for Display */ |
---|
| 42 | |
---|
| 43 | #include "gdm-common.h" |
---|
| 44 | |
---|
| 45 | #include "gdm-xdmcp-chooser-slave.h" |
---|
| 46 | #include "gdm-xdmcp-chooser-slave-glue.h" |
---|
| 47 | |
---|
| 48 | #include "gdm-server.h" |
---|
| 49 | #include "gdm-chooser-server.h" |
---|
| 50 | #include "gdm-chooser-session.h" |
---|
| 51 | #include "gdm-settings-direct.h" |
---|
| 52 | #include "gdm-settings-keys.h" |
---|
| 53 | |
---|
| 54 | #define GDM_XDMCP_CHOOSER_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlavePrivate)) |
---|
| 55 | |
---|
| 56 | #define GDM_DBUS_NAME "org.gnome.DisplayManager" |
---|
| 57 | #define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display" |
---|
| 58 | |
---|
| 59 | #define MAX_CONNECT_ATTEMPTS 10 |
---|
| 60 | #define DEFAULT_PING_INTERVAL 15 |
---|
| 61 | |
---|
| 62 | struct GdmXdmcpChooserSlavePrivate |
---|
| 63 | { |
---|
| 64 | char *id; |
---|
| 65 | GPid pid; |
---|
| 66 | |
---|
| 67 | int ping_interval; |
---|
| 68 | |
---|
| 69 | guint connection_attempts; |
---|
| 70 | |
---|
| 71 | GdmChooserServer *chooser_server; |
---|
| 72 | GdmChooserSession *chooser; |
---|
| 73 | }; |
---|
| 74 | |
---|
| 75 | enum { |
---|
| 76 | PROP_0, |
---|
| 77 | }; |
---|
| 78 | |
---|
| 79 | enum { |
---|
| 80 | HOSTNAME_SELECTED, |
---|
| 81 | LAST_SIGNAL |
---|
| 82 | }; |
---|
| 83 | |
---|
| 84 | static guint signals [LAST_SIGNAL] = { 0, }; |
---|
| 85 | |
---|
| 86 | static void gdm_xdmcp_chooser_slave_class_init (GdmXdmcpChooserSlaveClass *klass); |
---|
| 87 | static void gdm_xdmcp_chooser_slave_init (GdmXdmcpChooserSlave *xdmcp_chooser_slave); |
---|
| 88 | static void gdm_xdmcp_chooser_slave_finalize (GObject *object); |
---|
| 89 | |
---|
| 90 | G_DEFINE_TYPE (GdmXdmcpChooserSlave, gdm_xdmcp_chooser_slave, GDM_TYPE_SLAVE) |
---|
| 91 | |
---|
| 92 | |
---|
| 93 | static void |
---|
| 94 | on_chooser_session_start (GdmChooserSession *chooser, |
---|
| 95 | GdmXdmcpChooserSlave *slave) |
---|
| 96 | { |
---|
| 97 | g_debug ("GdmXdmcpChooserSlave: Chooser started"); |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | static void |
---|
| 101 | on_chooser_session_stop (GdmChooserSession *chooser, |
---|
| 102 | GdmXdmcpChooserSlave *slave) |
---|
| 103 | { |
---|
| 104 | g_debug ("GdmXdmcpChooserSlave: Chooser stopped"); |
---|
| 105 | gdm_slave_stopped (GDM_SLAVE (slave)); |
---|
| 106 | } |
---|
| 107 | |
---|
| 108 | static void |
---|
| 109 | on_chooser_session_exited (GdmChooserSession *chooser, |
---|
| 110 | int code, |
---|
| 111 | GdmXdmcpChooserSlave *slave) |
---|
| 112 | { |
---|
| 113 | g_debug ("GdmXdmcpChooserSlave: Chooser exited: %d", code); |
---|
| 114 | gdm_slave_stopped (GDM_SLAVE (slave)); |
---|
| 115 | } |
---|
| 116 | |
---|
| 117 | static void |
---|
| 118 | on_chooser_session_died (GdmChooserSession *chooser, |
---|
| 119 | int signal, |
---|
| 120 | GdmXdmcpChooserSlave *slave) |
---|
| 121 | { |
---|
| 122 | g_debug ("GdmXdmcpChooserSlave: Chooser died: %d", signal); |
---|
| 123 | gdm_slave_stopped (GDM_SLAVE (slave)); |
---|
| 124 | } |
---|
| 125 | |
---|
| 126 | static void |
---|
| 127 | on_chooser_hostname_selected (GdmChooserServer *chooser_server, |
---|
| 128 | const char *name, |
---|
| 129 | GdmXdmcpChooserSlave *slave) |
---|
| 130 | { |
---|
| 131 | g_debug ("GdmXdmcpChooserSlave: emitting hostname selected: %s", name); |
---|
| 132 | g_signal_emit (slave, signals [HOSTNAME_SELECTED], 0, name); |
---|
| 133 | } |
---|
| 134 | |
---|
| 135 | static void |
---|
| 136 | on_chooser_disconnected (GdmChooserServer *chooser_server, |
---|
| 137 | GdmXdmcpChooserSlave *slave) |
---|
| 138 | { |
---|
| 139 | g_debug ("GdmXdmcpChooserSlave: Chooser disconnected"); |
---|
| 140 | |
---|
| 141 | /* stop pinging */ |
---|
| 142 | alarm (0); |
---|
| 143 | |
---|
| 144 | gdm_slave_stopped (GDM_SLAVE (slave)); |
---|
| 145 | } |
---|
| 146 | |
---|
| 147 | static void |
---|
| 148 | on_chooser_connected (GdmChooserServer *chooser_server, |
---|
| 149 | GdmXdmcpChooserSlave *slave) |
---|
| 150 | { |
---|
| 151 | g_debug ("GdmXdmcpChooserSlave: Chooser connected"); |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | static void |
---|
| 155 | setup_server (GdmXdmcpChooserSlave *slave) |
---|
| 156 | { |
---|
| 157 | /* Set the busy cursor */ |
---|
| 158 | gdm_slave_set_busy_cursor (GDM_SLAVE (slave)); |
---|
| 159 | } |
---|
| 160 | |
---|
| 161 | static void |
---|
| 162 | run_chooser (GdmXdmcpChooserSlave *slave) |
---|
| 163 | { |
---|
| 164 | char *display_id; |
---|
| 165 | char *display_name; |
---|
| 166 | char *display_device; |
---|
| 167 | char *display_hostname; |
---|
| 168 | char *auth_file; |
---|
| 169 | char *address; |
---|
| 170 | gboolean res; |
---|
| 171 | |
---|
| 172 | g_debug ("GdmXdmcpChooserSlave: Running chooser"); |
---|
| 173 | |
---|
| 174 | display_id = NULL; |
---|
| 175 | display_name = NULL; |
---|
| 176 | auth_file = NULL; |
---|
| 177 | display_device = NULL; |
---|
| 178 | display_hostname = NULL; |
---|
| 179 | |
---|
| 180 | g_object_get (slave, |
---|
| 181 | "display-id", &display_id, |
---|
| 182 | "display-name", &display_name, |
---|
| 183 | "display-hostname", &display_hostname, |
---|
| 184 | "display-x11-authority-file", &auth_file, |
---|
| 185 | NULL); |
---|
| 186 | |
---|
| 187 | g_debug ("GdmXdmcpChooserSlave: Creating chooser for %s %s", display_name, display_hostname); |
---|
| 188 | |
---|
| 189 | /* FIXME: send a signal back to the master */ |
---|
| 190 | |
---|
| 191 | /* If XDMCP setup pinging */ |
---|
| 192 | slave->priv->ping_interval = DEFAULT_PING_INTERVAL; |
---|
| 193 | res = gdm_settings_direct_get_int (GDM_KEY_PING_INTERVAL, |
---|
| 194 | &(slave->priv->ping_interval)); |
---|
| 195 | |
---|
| 196 | if (slave->priv->ping_interval > 0) { |
---|
| 197 | alarm (slave->priv->ping_interval); |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | /* Run the init script. gdmslave suspends until script has terminated */ |
---|
| 201 | gdm_slave_run_script (GDM_SLAVE (slave), GDMCONFDIR "/Init", GDM_USERNAME); |
---|
| 202 | |
---|
| 203 | slave->priv->chooser_server = gdm_chooser_server_new (display_id); |
---|
| 204 | g_signal_connect (slave->priv->chooser_server, |
---|
| 205 | "hostname-selected", |
---|
| 206 | G_CALLBACK (on_chooser_hostname_selected), |
---|
| 207 | slave); |
---|
| 208 | g_signal_connect (slave->priv->chooser_server, |
---|
| 209 | "disconnected", |
---|
| 210 | G_CALLBACK (on_chooser_disconnected), |
---|
| 211 | slave); |
---|
| 212 | g_signal_connect (slave->priv->chooser_server, |
---|
| 213 | "connected", |
---|
| 214 | G_CALLBACK (on_chooser_connected), |
---|
| 215 | slave); |
---|
| 216 | gdm_chooser_server_start (slave->priv->chooser_server); |
---|
| 217 | |
---|
| 218 | address = gdm_chooser_server_get_address (slave->priv->chooser_server); |
---|
| 219 | |
---|
| 220 | g_debug ("GdmXdmcpChooserSlave: Creating chooser on %s %s %s", display_name, display_device, display_hostname); |
---|
| 221 | slave->priv->chooser = gdm_chooser_session_new (display_name, |
---|
| 222 | display_device, |
---|
| 223 | display_hostname); |
---|
| 224 | g_signal_connect (slave->priv->chooser, |
---|
| 225 | "started", |
---|
| 226 | G_CALLBACK (on_chooser_session_start), |
---|
| 227 | slave); |
---|
| 228 | g_signal_connect (slave->priv->chooser, |
---|
| 229 | "stopped", |
---|
| 230 | G_CALLBACK (on_chooser_session_stop), |
---|
| 231 | slave); |
---|
| 232 | g_signal_connect (slave->priv->chooser, |
---|
| 233 | "exited", |
---|
| 234 | G_CALLBACK (on_chooser_session_exited), |
---|
| 235 | slave); |
---|
| 236 | g_signal_connect (slave->priv->chooser, |
---|
| 237 | "died", |
---|
| 238 | G_CALLBACK (on_chooser_session_died), |
---|
| 239 | slave); |
---|
| 240 | g_object_set (slave->priv->chooser, |
---|
| 241 | "x11-authority-file", auth_file, |
---|
| 242 | NULL); |
---|
| 243 | gdm_welcome_session_set_server_address (GDM_WELCOME_SESSION (slave->priv->chooser), address); |
---|
| 244 | gdm_welcome_session_start (GDM_WELCOME_SESSION (slave->priv->chooser)); |
---|
| 245 | |
---|
| 246 | g_free (display_id); |
---|
| 247 | g_free (display_name); |
---|
| 248 | g_free (display_device); |
---|
| 249 | g_free (display_hostname); |
---|
| 250 | g_free (auth_file); |
---|
| 251 | } |
---|
| 252 | |
---|
| 253 | static gboolean |
---|
| 254 | idle_connect_to_display (GdmXdmcpChooserSlave *slave) |
---|
| 255 | { |
---|
| 256 | gboolean res; |
---|
| 257 | |
---|
| 258 | slave->priv->connection_attempts++; |
---|
| 259 | |
---|
| 260 | res = gdm_slave_connect_to_x11_display (GDM_SLAVE (slave)); |
---|
| 261 | if (res) { |
---|
| 262 | /* FIXME: handle wait-for-go */ |
---|
| 263 | |
---|
| 264 | setup_server (slave); |
---|
| 265 | run_chooser (slave); |
---|
| 266 | } else { |
---|
| 267 | if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) { |
---|
| 268 | g_warning ("Unable to connect to display after %d tries - bailing out", slave->priv->connection_attempts); |
---|
| 269 | exit (1); |
---|
| 270 | } |
---|
| 271 | return TRUE; |
---|
| 272 | } |
---|
| 273 | |
---|
| 274 | return FALSE; |
---|
| 275 | } |
---|
| 276 | |
---|
| 277 | static gboolean |
---|
| 278 | gdm_xdmcp_chooser_slave_run (GdmXdmcpChooserSlave *slave) |
---|
| 279 | { |
---|
| 280 | char *display_name; |
---|
| 281 | char *auth_file; |
---|
| 282 | |
---|
| 283 | g_object_get (slave, |
---|
| 284 | "display-name", &display_name, |
---|
| 285 | "display-x11-authority-file", &auth_file, |
---|
| 286 | NULL); |
---|
| 287 | |
---|
| 288 | g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave); |
---|
| 289 | |
---|
| 290 | g_free (display_name); |
---|
| 291 | g_free (auth_file); |
---|
| 292 | |
---|
| 293 | return TRUE; |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | static gboolean |
---|
| 297 | gdm_xdmcp_chooser_slave_start (GdmSlave *slave) |
---|
| 298 | { |
---|
| 299 | GDM_SLAVE_CLASS (gdm_xdmcp_chooser_slave_parent_class)->start (slave); |
---|
| 300 | |
---|
| 301 | gdm_xdmcp_chooser_slave_run (GDM_XDMCP_CHOOSER_SLAVE (slave)); |
---|
| 302 | |
---|
| 303 | return TRUE; |
---|
| 304 | } |
---|
| 305 | |
---|
| 306 | static gboolean |
---|
| 307 | gdm_xdmcp_chooser_slave_stop (GdmSlave *slave) |
---|
| 308 | { |
---|
| 309 | g_debug ("GdmXdmcpChooserSlave: Stopping xdmcp_chooser_slave"); |
---|
| 310 | |
---|
| 311 | GDM_SLAVE_CLASS (gdm_xdmcp_chooser_slave_parent_class)->stop (slave); |
---|
| 312 | |
---|
| 313 | if (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser != NULL) { |
---|
| 314 | gdm_welcome_session_stop (GDM_WELCOME_SESSION (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser)); |
---|
| 315 | g_object_unref (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser); |
---|
| 316 | GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser = NULL; |
---|
| 317 | } |
---|
| 318 | |
---|
| 319 | return TRUE; |
---|
| 320 | } |
---|
| 321 | |
---|
| 322 | static void |
---|
| 323 | gdm_xdmcp_chooser_slave_set_property (GObject *object, |
---|
| 324 | guint prop_id, |
---|
| 325 | const GValue *value, |
---|
| 326 | GParamSpec *pspec) |
---|
| 327 | { |
---|
| 328 | switch (prop_id) { |
---|
| 329 | default: |
---|
| 330 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
---|
| 331 | break; |
---|
| 332 | } |
---|
| 333 | } |
---|
| 334 | |
---|
| 335 | static void |
---|
| 336 | gdm_xdmcp_chooser_slave_get_property (GObject *object, |
---|
| 337 | guint prop_id, |
---|
| 338 | GValue *value, |
---|
| 339 | GParamSpec *pspec) |
---|
| 340 | { |
---|
| 341 | switch (prop_id) { |
---|
| 342 | default: |
---|
| 343 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
---|
| 344 | break; |
---|
| 345 | } |
---|
| 346 | } |
---|
| 347 | |
---|
| 348 | static GObject * |
---|
| 349 | gdm_xdmcp_chooser_slave_constructor (GType type, |
---|
| 350 | guint n_construct_properties, |
---|
| 351 | GObjectConstructParam *construct_properties) |
---|
| 352 | { |
---|
| 353 | GdmXdmcpChooserSlave *xdmcp_chooser_slave; |
---|
| 354 | |
---|
| 355 | xdmcp_chooser_slave = GDM_XDMCP_CHOOSER_SLAVE (G_OBJECT_CLASS (gdm_xdmcp_chooser_slave_parent_class)->constructor (type, |
---|
| 356 | n_construct_properties, |
---|
| 357 | construct_properties)); |
---|
| 358 | |
---|
| 359 | return G_OBJECT (xdmcp_chooser_slave); |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | static void |
---|
| 363 | gdm_xdmcp_chooser_slave_class_init (GdmXdmcpChooserSlaveClass *klass) |
---|
| 364 | { |
---|
| 365 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
---|
| 366 | GdmSlaveClass *slave_class = GDM_SLAVE_CLASS (klass); |
---|
| 367 | |
---|
| 368 | object_class->get_property = gdm_xdmcp_chooser_slave_get_property; |
---|
| 369 | object_class->set_property = gdm_xdmcp_chooser_slave_set_property; |
---|
| 370 | object_class->constructor = gdm_xdmcp_chooser_slave_constructor; |
---|
| 371 | object_class->finalize = gdm_xdmcp_chooser_slave_finalize; |
---|
| 372 | |
---|
| 373 | slave_class->start = gdm_xdmcp_chooser_slave_start; |
---|
| 374 | slave_class->stop = gdm_xdmcp_chooser_slave_stop; |
---|
| 375 | |
---|
| 376 | signals [HOSTNAME_SELECTED] = |
---|
| 377 | g_signal_new ("hostname-selected", |
---|
| 378 | G_OBJECT_CLASS_TYPE (object_class), |
---|
| 379 | G_SIGNAL_RUN_FIRST, |
---|
| 380 | G_STRUCT_OFFSET (GdmXdmcpChooserSlaveClass, hostname_selected), |
---|
| 381 | NULL, |
---|
| 382 | NULL, |
---|
| 383 | g_cclosure_marshal_VOID__STRING, |
---|
| 384 | G_TYPE_NONE, |
---|
| 385 | 1, |
---|
| 386 | G_TYPE_STRING); |
---|
| 387 | |
---|
| 388 | g_type_class_add_private (klass, sizeof (GdmXdmcpChooserSlavePrivate)); |
---|
| 389 | |
---|
| 390 | dbus_g_object_type_install_info (GDM_TYPE_XDMCP_CHOOSER_SLAVE, &dbus_glib_gdm_xdmcp_chooser_slave_object_info); |
---|
| 391 | } |
---|
| 392 | |
---|
| 393 | static void |
---|
| 394 | gdm_xdmcp_chooser_slave_init (GdmXdmcpChooserSlave *slave) |
---|
| 395 | { |
---|
| 396 | slave->priv = GDM_XDMCP_CHOOSER_SLAVE_GET_PRIVATE (slave); |
---|
| 397 | } |
---|
| 398 | |
---|
| 399 | static void |
---|
| 400 | gdm_xdmcp_chooser_slave_finalize (GObject *object) |
---|
| 401 | { |
---|
| 402 | GdmXdmcpChooserSlave *xdmcp_chooser_slave; |
---|
| 403 | |
---|
| 404 | g_return_if_fail (object != NULL); |
---|
| 405 | g_return_if_fail (GDM_IS_XDMCP_CHOOSER_SLAVE (object)); |
---|
| 406 | |
---|
| 407 | xdmcp_chooser_slave = GDM_XDMCP_CHOOSER_SLAVE (object); |
---|
| 408 | |
---|
| 409 | g_return_if_fail (xdmcp_chooser_slave->priv != NULL); |
---|
| 410 | |
---|
| 411 | gdm_xdmcp_chooser_slave_stop (GDM_SLAVE (xdmcp_chooser_slave)); |
---|
| 412 | |
---|
| 413 | G_OBJECT_CLASS (gdm_xdmcp_chooser_slave_parent_class)->finalize (object); |
---|
| 414 | } |
---|
| 415 | |
---|
| 416 | GdmSlave * |
---|
| 417 | gdm_xdmcp_chooser_slave_new (const char *id) |
---|
| 418 | { |
---|
| 419 | GObject *object; |
---|
| 420 | |
---|
| 421 | object = g_object_new (GDM_TYPE_XDMCP_CHOOSER_SLAVE, |
---|
| 422 | "display-id", id, |
---|
| 423 | NULL); |
---|
| 424 | |
---|
| 425 | return GDM_SLAVE (object); |
---|
| 426 | } |
---|