diff options
author | William Jon McCann <mccann@jhu.edu> | 2008-01-31 00:51:46 +0000 |
---|---|---|
committer | William Jon McCann <mccann@src.gnome.org> | 2008-01-31 00:51:46 +0000 |
commit | 98917b1ee7d15660bafd4ab8d2441f78afa974c1 (patch) | |
tree | 5aeff2f3cbabe5081e89b56cfcd13487fad3768e | |
parent | 17014d50d4e48c6145660df86c27324f566621b4 (diff) | |
download | gdm-98917b1ee7d15660bafd4ab8d2441f78afa974c1.tar.gz |
Initial support for XDMCP IndirectQuery choosers. Also fix broken
2008-01-30 William Jon McCann <mccann@jhu.edu>
* common/gdm-address.c: (add_local_siocgifconf),
(add_local_addrinfo), (gdm_address_peek_local_list):
* daemon/Makefile.am:
* daemon/gdm-chooser-server.c: (generate_address),
(handle_select_hostname), (handle_disconnect),
(chooser_handle_child_message), (do_introspect),
(chooser_server_message_handler),
(chooser_server_unregister_handler), (connection_filter_function),
(allow_user_function), (handle_connection),
(gdm_chooser_server_start), (gdm_chooser_server_stop),
(gdm_chooser_server_get_address),
(_gdm_chooser_server_set_display_id),
(_gdm_chooser_server_set_user_name),
(_gdm_chooser_server_set_group_name),
(gdm_chooser_server_set_property),
(gdm_chooser_server_get_property),
(gdm_chooser_server_constructor), (gdm_chooser_server_class_init),
(gdm_chooser_server_init), (gdm_chooser_server_finalize),
(gdm_chooser_server_new):
* daemon/gdm-chooser-server.h:
* daemon/gdm-chooser-session.c: (listify_hash),
(get_chooser_environment), (chooser_session_child_watch),
(spawn_child_setup), (spawn_command_line_sync_as_user),
(spawn_command_line_async_as_user), (parse_value_as_integer),
(parse_dbus_launch_output), (start_dbus_daemon),
(stop_dbus_daemon), (gdm_chooser_session_spawn),
(gdm_chooser_session_start), (wait_on_child),
(chooser_session_died), (gdm_chooser_session_stop),
(gdm_chooser_session_set_server_address),
(_gdm_chooser_session_set_x11_display_name),
(_gdm_chooser_session_set_x11_display_hostname),
(_gdm_chooser_session_set_x11_display_device),
(_gdm_chooser_session_set_x11_authority_file),
(_gdm_chooser_session_set_user_name),
(_gdm_chooser_session_set_group_name),
(gdm_chooser_session_set_property),
(gdm_chooser_session_get_property),
(gdm_chooser_session_constructor),
(gdm_chooser_session_class_init), (gdm_chooser_session_init),
(gdm_chooser_session_finalize), (gdm_chooser_session_new):
* daemon/gdm-chooser-session.h:
* daemon/gdm-display.c: (gdm_display_real_set_slave_bus_name),
(gdm_display_set_slave_bus_name), (gdm_display_class_init):
* daemon/gdm-display.h:
* daemon/gdm-display.xml:
* daemon/gdm-factory-slave.c:
* daemon/gdm-greeter-server.c:
* daemon/gdm-greeter-session.c: (gdm_greeter_session_init):
* daemon/gdm-product-slave.c:
* daemon/gdm-simple-slave.c:
* daemon/gdm-slave.c: (gdm_slave_set_slave_bus_name),
(gdm_slave_real_start), (register_slave), (gdm_slave_constructor):
* daemon/gdm-xdmcp-chooser-display.c: (on_hostname_selected),
(gdm_xdmcp_chooser_display_set_slave_bus_name),
(gdm_xdmcp_chooser_display_manage),
(gdm_xdmcp_chooser_display_class_init),
(gdm_xdmcp_chooser_display_init),
(gdm_xdmcp_chooser_display_finalize),
(gdm_xdmcp_chooser_display_new):
* daemon/gdm-xdmcp-chooser-display.h:
* daemon/gdm-xdmcp-chooser-display.xml:
* daemon/gdm-xdmcp-chooser-slave.c: (on_chooser_session_start),
(on_chooser_session_stop), (on_chooser_session_exited),
(on_chooser_session_died), (on_chooser_hostname_selected),
(on_chooser_disconnected), (on_chooser_connected), (setup_server),
(run_chooser), (idle_connect_to_display),
(gdm_xdmcp_chooser_slave_run), (gdm_xdmcp_chooser_slave_start),
(gdm_xdmcp_chooser_slave_stop),
(gdm_xdmcp_chooser_slave_set_property),
(gdm_xdmcp_chooser_slave_get_property),
(gdm_xdmcp_chooser_slave_constructor),
(gdm_xdmcp_chooser_slave_class_init),
(gdm_xdmcp_chooser_slave_init), (gdm_xdmcp_chooser_slave_finalize),
(gdm_xdmcp_chooser_slave_new):
* daemon/gdm-xdmcp-chooser-slave.h:
* daemon/gdm-xdmcp-display-factory.c: (set_port_for_request),
(gdm_xdmcp_send_forward_query), (indirect_client_create),
(indirect_client_destroy), (indirect_client_lookup_by_chosen),
(indirect_client_lookup), (gdm_xdmcp_handle_indirect_query),
(forward_query_destroy), (remove_oldest_forward),
(forward_query_create), (forward_query_lookup),
(gdm_xdmcp_handle_forward_query), (gdm_xdmcp_send_decline),
(on_hostname_selected), (gdm_xdmcp_display_create),
(gdm_xdmcp_handle_request), (gdm_xdmcp_send_refuse),
(gdm_xdmcp_handle_manage), (gdm_xdmcp_handle_managed_forward):
* daemon/gdm-xdmcp-display.c: (gdm_xdmcp_display_class_init),
(gdm_xdmcp_display_finalize):
* daemon/gdm-xdmcp-display.h:
* daemon/gdm-xdmcp-display.xml:
* daemon/gdm-xdmcp-greeter-display.c:
(gdm_xdmcp_greeter_display_class_init),
(gdm_xdmcp_greeter_display_init),
(gdm_xdmcp_greeter_display_finalize),
(gdm_xdmcp_greeter_display_new):
* daemon/gdm-xdmcp-greeter-display.h:
* daemon/xdmcp-chooser-slave-main.c: (get_system_bus), (signal_cb),
(on_slave_stopped), (main):
* data/gdm.conf:
* gui/simple-chooser/Makefile.am:
* gui/simple-chooser/chooser-main.c: (assistive_registry_launch),
(filter_watch), (filter_timeout), (assistive_registry_start),
(at_set_gtk_modules), (load_a11y), (main):
* gui/simple-chooser/gdm-chooser-client.c:
(gdm_chooser_client_error_quark), (send_dbus_string_method),
(send_dbus_void_method), (gdm_chooser_client_call_select_hostname),
(gdm_chooser_client_call_disconnect), (client_dbus_handle_message),
(client_dbus_filter_function), (gdm_chooser_client_start),
(gdm_chooser_client_stop), (gdm_chooser_client_set_property),
(gdm_chooser_client_get_property),
(gdm_chooser_client_constructor), (gdm_chooser_client_dispose),
(gdm_chooser_client_class_init), (gdm_chooser_client_init),
(gdm_chooser_client_finalize), (gdm_chooser_client_new):
* gui/simple-chooser/gdm-chooser-client.h:
* gui/simple-chooser/gdm-chooser-session.c: (launch_compiz),
(launch_metacity), (start_window_manager), (start_settings_daemon),
(on_dialog_response), (gdm_chooser_session_start),
(gdm_chooser_session_stop), (gdm_chooser_session_set_property),
(gdm_chooser_session_get_property),
(gdm_chooser_session_constructor), (gdm_chooser_session_dispose),
(gdm_chooser_session_class_init), (gdm_chooser_session_init),
(gdm_chooser_session_finalize), (gdm_chooser_session_new):
* gui/simple-chooser/gdm-chooser-session.h:
* gui/simple-chooser/test-host-chooser.c:
(assistive_registry_launch), (filter_watch), (filter_timeout),
(assistive_registry_start), (at_set_gtk_modules), (load_a11y),
(main):
* gui/simple-greeter/greeter-main.c: (load_a11y), (main):
Initial support for XDMCP IndirectQuery choosers.
Also fix broken gdm_address_is_local.
svn path=/trunk/; revision=5645
39 files changed, 4998 insertions, 227 deletions
@@ -1,3 +1,135 @@ +2008-01-30 William Jon McCann <mccann@jhu.edu> + + * common/gdm-address.c: (add_local_siocgifconf), + (add_local_addrinfo), (gdm_address_peek_local_list): + * daemon/Makefile.am: + * daemon/gdm-chooser-server.c: (generate_address), + (handle_select_hostname), (handle_disconnect), + (chooser_handle_child_message), (do_introspect), + (chooser_server_message_handler), + (chooser_server_unregister_handler), (connection_filter_function), + (allow_user_function), (handle_connection), + (gdm_chooser_server_start), (gdm_chooser_server_stop), + (gdm_chooser_server_get_address), + (_gdm_chooser_server_set_display_id), + (_gdm_chooser_server_set_user_name), + (_gdm_chooser_server_set_group_name), + (gdm_chooser_server_set_property), + (gdm_chooser_server_get_property), + (gdm_chooser_server_constructor), (gdm_chooser_server_class_init), + (gdm_chooser_server_init), (gdm_chooser_server_finalize), + (gdm_chooser_server_new): + * daemon/gdm-chooser-server.h: + * daemon/gdm-chooser-session.c: (listify_hash), + (get_chooser_environment), (chooser_session_child_watch), + (spawn_child_setup), (spawn_command_line_sync_as_user), + (spawn_command_line_async_as_user), (parse_value_as_integer), + (parse_dbus_launch_output), (start_dbus_daemon), + (stop_dbus_daemon), (gdm_chooser_session_spawn), + (gdm_chooser_session_start), (wait_on_child), + (chooser_session_died), (gdm_chooser_session_stop), + (gdm_chooser_session_set_server_address), + (_gdm_chooser_session_set_x11_display_name), + (_gdm_chooser_session_set_x11_display_hostname), + (_gdm_chooser_session_set_x11_display_device), + (_gdm_chooser_session_set_x11_authority_file), + (_gdm_chooser_session_set_user_name), + (_gdm_chooser_session_set_group_name), + (gdm_chooser_session_set_property), + (gdm_chooser_session_get_property), + (gdm_chooser_session_constructor), + (gdm_chooser_session_class_init), (gdm_chooser_session_init), + (gdm_chooser_session_finalize), (gdm_chooser_session_new): + * daemon/gdm-chooser-session.h: + * daemon/gdm-display.c: (gdm_display_real_set_slave_bus_name), + (gdm_display_set_slave_bus_name), (gdm_display_class_init): + * daemon/gdm-display.h: + * daemon/gdm-display.xml: + * daemon/gdm-factory-slave.c: + * daemon/gdm-greeter-server.c: + * daemon/gdm-greeter-session.c: (gdm_greeter_session_init): + * daemon/gdm-product-slave.c: + * daemon/gdm-simple-slave.c: + * daemon/gdm-slave.c: (gdm_slave_set_slave_bus_name), + (gdm_slave_real_start), (register_slave), (gdm_slave_constructor): + * daemon/gdm-xdmcp-chooser-display.c: (on_hostname_selected), + (gdm_xdmcp_chooser_display_set_slave_bus_name), + (gdm_xdmcp_chooser_display_manage), + (gdm_xdmcp_chooser_display_class_init), + (gdm_xdmcp_chooser_display_init), + (gdm_xdmcp_chooser_display_finalize), + (gdm_xdmcp_chooser_display_new): + * daemon/gdm-xdmcp-chooser-display.h: + * daemon/gdm-xdmcp-chooser-display.xml: + * daemon/gdm-xdmcp-chooser-slave.c: (on_chooser_session_start), + (on_chooser_session_stop), (on_chooser_session_exited), + (on_chooser_session_died), (on_chooser_hostname_selected), + (on_chooser_disconnected), (on_chooser_connected), (setup_server), + (run_chooser), (idle_connect_to_display), + (gdm_xdmcp_chooser_slave_run), (gdm_xdmcp_chooser_slave_start), + (gdm_xdmcp_chooser_slave_stop), + (gdm_xdmcp_chooser_slave_set_property), + (gdm_xdmcp_chooser_slave_get_property), + (gdm_xdmcp_chooser_slave_constructor), + (gdm_xdmcp_chooser_slave_class_init), + (gdm_xdmcp_chooser_slave_init), (gdm_xdmcp_chooser_slave_finalize), + (gdm_xdmcp_chooser_slave_new): + * daemon/gdm-xdmcp-chooser-slave.h: + * daemon/gdm-xdmcp-display-factory.c: (set_port_for_request), + (gdm_xdmcp_send_forward_query), (indirect_client_create), + (indirect_client_destroy), (indirect_client_lookup_by_chosen), + (indirect_client_lookup), (gdm_xdmcp_handle_indirect_query), + (forward_query_destroy), (remove_oldest_forward), + (forward_query_create), (forward_query_lookup), + (gdm_xdmcp_handle_forward_query), (gdm_xdmcp_send_decline), + (on_hostname_selected), (gdm_xdmcp_display_create), + (gdm_xdmcp_handle_request), (gdm_xdmcp_send_refuse), + (gdm_xdmcp_handle_manage), (gdm_xdmcp_handle_managed_forward): + * daemon/gdm-xdmcp-display.c: (gdm_xdmcp_display_class_init), + (gdm_xdmcp_display_finalize): + * daemon/gdm-xdmcp-display.h: + * daemon/gdm-xdmcp-display.xml: + * daemon/gdm-xdmcp-greeter-display.c: + (gdm_xdmcp_greeter_display_class_init), + (gdm_xdmcp_greeter_display_init), + (gdm_xdmcp_greeter_display_finalize), + (gdm_xdmcp_greeter_display_new): + * daemon/gdm-xdmcp-greeter-display.h: + * daemon/xdmcp-chooser-slave-main.c: (get_system_bus), (signal_cb), + (on_slave_stopped), (main): + * data/gdm.conf: + * gui/simple-chooser/Makefile.am: + * gui/simple-chooser/chooser-main.c: (assistive_registry_launch), + (filter_watch), (filter_timeout), (assistive_registry_start), + (at_set_gtk_modules), (load_a11y), (main): + * gui/simple-chooser/gdm-chooser-client.c: + (gdm_chooser_client_error_quark), (send_dbus_string_method), + (send_dbus_void_method), (gdm_chooser_client_call_select_hostname), + (gdm_chooser_client_call_disconnect), (client_dbus_handle_message), + (client_dbus_filter_function), (gdm_chooser_client_start), + (gdm_chooser_client_stop), (gdm_chooser_client_set_property), + (gdm_chooser_client_get_property), + (gdm_chooser_client_constructor), (gdm_chooser_client_dispose), + (gdm_chooser_client_class_init), (gdm_chooser_client_init), + (gdm_chooser_client_finalize), (gdm_chooser_client_new): + * gui/simple-chooser/gdm-chooser-client.h: + * gui/simple-chooser/gdm-chooser-session.c: (launch_compiz), + (launch_metacity), (start_window_manager), (start_settings_daemon), + (on_dialog_response), (gdm_chooser_session_start), + (gdm_chooser_session_stop), (gdm_chooser_session_set_property), + (gdm_chooser_session_get_property), + (gdm_chooser_session_constructor), (gdm_chooser_session_dispose), + (gdm_chooser_session_class_init), (gdm_chooser_session_init), + (gdm_chooser_session_finalize), (gdm_chooser_session_new): + * gui/simple-chooser/gdm-chooser-session.h: + * gui/simple-chooser/test-host-chooser.c: + (assistive_registry_launch), (filter_watch), (filter_timeout), + (assistive_registry_start), (at_set_gtk_modules), (load_a11y), + (main): + * gui/simple-greeter/greeter-main.c: (load_a11y), (main): + Initial support for XDMCP IndirectQuery choosers. + Also fix broken gdm_address_is_local. + 2008-01-29 William Jon McCann <mccann@jhu.edu> * configure.ac: diff --git a/common/gdm-address.c b/common/gdm-address.c index 490b7fcc..9e23f1a0 100644 --- a/common/gdm-address.c +++ b/common/gdm-address.c @@ -30,6 +30,8 @@ #include <sys/socket.h> #endif #include <netdb.h> +#include <sys/ioctl.h> +#include <net/if.h> #ifndef G_OS_WIN32 #include <sys/socket.h> @@ -280,25 +282,71 @@ gdm_address_is_loopback (GdmAddress *address) return FALSE; } -const GList * -gdm_address_peek_local_list (void) +static void +add_local_siocgifconf (GList **list) { - static GList *the_list = NULL; - static time_t last_time = 0; - char hostbuf[BUFSIZ]; - struct addrinfo *result; - struct addrinfo *res; + struct ifconf ifc; + struct ifreq ifreq; + struct ifreq *ifr; + struct ifreq *the_end; + int sock; + char buf[BUFSIZ]; + + if ((sock = socket (PF_INET, SOCK_DGRAM, 0)) < 0) { + perror ("socket"); + return; + } - /* Don't check more then every 5 seconds */ - if (last_time + 5 > time (NULL)) { - return the_list; + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0) { + perror ("SIOCGIFCONF"); + close (sock); + return; } - g_list_foreach (the_list, (GFunc)gdm_address_free, NULL); - g_list_free (the_list); - the_list = NULL; + /* Get IP address of each active IP network interface. */ + the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); + + for (ifr = ifc.ifc_req; ifr < the_end; ifr++) { + if (ifr->ifr_addr.sa_family == AF_INET) { + /* IP net interface */ + ifreq = *ifr; + + if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) { + perror("SIOCGIFFLAGS"); + } else if (ifreq.ifr_flags & IFF_UP) { /* active interface */ + if (ioctl (sock, SIOCGIFADDR, (char *) &ifreq) < 0) { + perror("SIOCGIFADDR"); + } else { + GdmAddress *address; + address = gdm_address_new_from_sockaddr ((struct sockaddr *)&ifreq.ifr_addr, + sizeof (struct sockaddr)); + + gdm_address_debug (address); + + *list = g_list_append (*list, address); + } + } + } + + /* Support for variable-length addresses. */ +#ifdef HAS_SA_LEN + ifr = (struct ifreq *) ((caddr_t) ifr + + ifr->ifr_addr.sa_len - sizeof(struct sockaddr)); +#endif + } - last_time = time (NULL); + close (sock); +} + +static void +add_local_addrinfo (GList **list) +{ + char hostbuf[BUFSIZ]; + struct addrinfo *result; + struct addrinfo *res; + struct addrinfo hints; hostbuf[BUFSIZ-1] = '\0'; if (gethostname (hostbuf, BUFSIZ-1) != 0) { @@ -306,26 +354,58 @@ gdm_address_peek_local_list (void) snprintf (hostbuf, BUFSIZ-1, "localhost"); } + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + + g_debug ("GdmAddress: looking up hostname: %s", hostbuf); result = NULL; - if (getaddrinfo (hostbuf, NULL, NULL, &result) != 0) { + if (getaddrinfo (hostbuf, NULL, &hints, &result) != 0) { g_debug ("%s: Could not get address from hostname!", "gdm_peek_local_address_list"); - return NULL; + return; } for (res = result; res != NULL; res = res->ai_next) { GdmAddress *address; + g_debug ("family=%d sock_type=%d protocol=%d flags=0x%x canonname=%s\n", + res->ai_family, + res->ai_socktype, + res->ai_protocol, + res->ai_flags, + res->ai_canonname); address = gdm_address_new_from_sockaddr (res->ai_addr, res->ai_addrlen); - the_list = g_list_append (the_list, address); + *list = g_list_append (*list, address); } if (result != NULL) { freeaddrinfo (result); result = NULL; } +} + +const GList * +gdm_address_peek_local_list (void) +{ + static GList *list = NULL; + static time_t last_time = 0; + + /* Don't check more then every 5 seconds */ + if (last_time + 5 > time (NULL)) { + return list; + } + + g_list_foreach (list, (GFunc)gdm_address_free, NULL); + g_list_free (list); + list = NULL; + + last_time = time (NULL); + + add_local_siocgifconf (&list); + add_local_addrinfo (&list); - return the_list; + return list; } gboolean diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 81b2b718..2e9c10bd 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -32,9 +32,11 @@ BUILT_SOURCES = \ gdm-simple-slave-glue.h \ gdm-factory-slave-glue.h \ gdm-product-slave-glue.h \ + gdm-xdmcp-chooser-slave-glue.h \ gdm-manager-glue.h \ gdm-display-glue.h \ - gdm-xdmcp-display-glue.h \ + gdm-xdmcp-greeter-display-glue.h \ + gdm-xdmcp-chooser-display-glue.h \ gdm-static-display-glue.h \ gdm-transient-display-glue.h \ gdm-local-display-factory-glue.h \ @@ -52,10 +54,14 @@ gdm-factory-slave-glue.h: gdm-factory-slave.xml Makefile.am dbus-binding-tool --prefix=gdm_factory_slave --mode=glib-server --output=gdm-factory-slave-glue.h $(srcdir)/gdm-factory-slave.xml gdm-product-slave-glue.h: gdm-product-slave.xml Makefile.am dbus-binding-tool --prefix=gdm_product_slave --mode=glib-server --output=gdm-product-slave-glue.h $(srcdir)/gdm-product-slave.xml +gdm-xdmcp-chooser-slave-glue.h: gdm-xdmcp-chooser-slave.xml Makefile.am + dbus-binding-tool --prefix=gdm_xdmcp_chooser_slave --mode=glib-server --output=gdm-xdmcp-chooser-slave-glue.h $(srcdir)/gdm-xdmcp-chooser-slave.xml gdm-display-glue.h: gdm-display.xml Makefile.am dbus-binding-tool --prefix=gdm_display --mode=glib-server --output=gdm-display-glue.h $(srcdir)/gdm-display.xml -gdm-xdmcp-display-glue.h: gdm-xdmcp-display.xml Makefile.am - dbus-binding-tool --prefix=gdm_xdmcp_display --mode=glib-server --output=gdm-xdmcp-display-glue.h $(srcdir)/gdm-xdmcp-display.xml +gdm-xdmcp-greeter-display-glue.h: gdm-xdmcp-greeter-display.xml Makefile.am + dbus-binding-tool --prefix=gdm_xdmcp_greeter_display --mode=glib-server --output=gdm-xdmcp-greeter-display-glue.h $(srcdir)/gdm-xdmcp-greeter-display.xml +gdm-xdmcp-chooser-display-glue.h: gdm-xdmcp-chooser-display.xml Makefile.am + dbus-binding-tool --prefix=gdm_xdmcp_chooser_display --mode=glib-server --output=gdm-xdmcp-chooser-display-glue.h $(srcdir)/gdm-xdmcp-chooser-display.xml gdm-static-display-glue.h: gdm-static-display.xml Makefile.am dbus-binding-tool --prefix=gdm_static_display --mode=glib-server --output=gdm-static-display-glue.h $(srcdir)/gdm-static-display.xml gdm-transient-display-glue.h: gdm-transient-display.xml Makefile.am @@ -106,6 +112,7 @@ libexec_PROGRAMS = \ gdm-simple-slave \ gdm-factory-slave \ gdm-product-slave \ + gdm-xdmcp-chooser-slave \ gdm-session-worker \ $(NULL) @@ -208,6 +215,25 @@ gdm_product_slave_LDADD = \ $(top_builddir)/common/libgdmcommon.la \ $(NULL) +gdm_xdmcp_chooser_slave_SOURCES = \ + xdmcp-chooser-slave-main.c \ + gdm-chooser-server.c \ + gdm-chooser-server.h \ + gdm-chooser-session.c \ + gdm-chooser-session.h \ + gdm-slave.c \ + gdm-slave.h \ + gdm-xdmcp-chooser-slave.c \ + gdm-xdmcp-chooser-slave.h \ + $(NULL) + +gdm_xdmcp_chooser_slave_LDADD = \ + $(XLIB_LIBS) \ + $(DAEMON_LIBS) \ + $(EXTRA_DAEMON_LIBS) \ + $(top_builddir)/common/libgdmcommon.la \ + $(NULL) + gdm_session_worker_SOURCES = \ session-worker-main.c \ gdm-session-worker.h \ @@ -241,6 +267,10 @@ gdm_binary_SOURCES = \ gdm-display.h \ gdm-xdmcp-display.c \ gdm-xdmcp-display.h \ + gdm-xdmcp-greeter-display.c \ + gdm-xdmcp-greeter-display.h \ + gdm-xdmcp-chooser-display.c \ + gdm-xdmcp-chooser-display.h \ gdm-static-display.c \ gdm-static-display.h \ gdm-transient-display.c \ @@ -309,9 +339,11 @@ EXTRA_DIST = \ gdm-simple-slave.xml \ gdm-factory-slave.xml \ gdm-product-slave.xml \ + gdm-xdmcp-chooser-slave.xml \ gdm-manager.xml \ gdm-display.xml \ - gdm-xdmcp-display.xml \ + gdm-xdmcp-greeter-display.xml \ + gdm-xdmcp-chooser-display.xml \ gdm-static-display.xml \ gdm-transient-display.xml \ gdm-local-display-factory.xml \ diff --git a/daemon/gdm-chooser-server.c b/daemon/gdm-chooser-server.c new file mode 100644 index 00000000..c53e7927 --- /dev/null +++ b/daemon/gdm-chooser-server.c @@ -0,0 +1,628 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <ctype.h> +#include <pwd.h> +#include <grp.h> + +#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD) +#include <sched.h> +#endif + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "gdm-chooser-server.h" + +#define GDM_CHOOSER_SERVER_DBUS_PATH "/org/gnome/DisplayManager/ChooserServer" +#define GDM_CHOOSER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.ChooserServer" + +#define GDM_CHOOSER_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_SERVER, GdmChooserServerPrivate)) + +struct GdmChooserServerPrivate +{ + char *user_name; + char *group_name; + char *display_id; + + DBusServer *server; + char *server_address; + DBusConnection *chooser_connection; +}; + +enum { + PROP_0, + PROP_USER_NAME, + PROP_GROUP_NAME, + PROP_DISPLAY_ID, +}; + +enum { + HOSTNAME_SELECTED, + CONNECTED, + DISCONNECTED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + +static void gdm_chooser_server_class_init (GdmChooserServerClass *klass); +static void gdm_chooser_server_init (GdmChooserServer *chooser_server); +static void gdm_chooser_server_finalize (GObject *object); + +G_DEFINE_TYPE (GdmChooserServer, gdm_chooser_server, G_TYPE_OBJECT) + +/* Note: Use abstract sockets like dbus does by default on Linux. Abstract + * sockets are only available on Linux. + */ +static char * +generate_address (void) +{ + char *path; +#if defined (__linux__) + int i; + char tmp[9]; + + for (i = 0; i < 8; i++) { + if (g_random_int_range (0, 2) == 0) { + tmp[i] = g_random_int_range ('a', 'z' + 1); + } else { + tmp[i] = g_random_int_range ('A', 'Z' + 1); + } + } + tmp[8] = '\0'; + + path = g_strdup_printf ("unix:abstract=/tmp/gdm-chooser-%s", tmp); +#else + path = g_strdup ("unix:tmpdir=/tmp"); +#endif + + return path; +} + +static DBusHandlerResult +handle_select_hostname (GdmChooserServer *chooser_server, + DBusConnection *connection, + DBusMessage *message) +{ + DBusMessage *reply; + DBusError error; + const char *text; + + dbus_error_init (&error); + if (! dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) { + g_warning ("ERROR: %s", error.message); + } + + g_debug ("ChooserServer: SelectHostname: %s", text); + + reply = dbus_message_new_method_return (message); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + g_signal_emit (chooser_server, signals [HOSTNAME_SELECTED], 0, text); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +handle_disconnect (GdmChooserServer *chooser_server, + DBusConnection *connection, + DBusMessage *message) +{ + DBusMessage *reply; + + reply = dbus_message_new_method_return (message); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + g_signal_emit (chooser_server, signals [DISCONNECTED], 0); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +chooser_handle_child_message (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data); + + if (dbus_message_is_method_call (message, GDM_CHOOSER_SERVER_DBUS_INTERFACE, "SelectHostname")) { + return handle_select_hostname (chooser_server, connection, message); + } else if (dbus_message_is_method_call (message, GDM_CHOOSER_SERVER_DBUS_INTERFACE, "Disconnect")) { + return handle_disconnect (chooser_server, connection, message); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusHandlerResult +do_introspect (DBusConnection *connection, + DBusMessage *message) +{ + DBusMessage *reply; + GString *xml; + char *xml_string; + + g_debug ("ChooserServer: Do introspect"); + + /* standard header */ + xml = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" + "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" + "<node>\n" + " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" + " <method name=\"Introspect\">\n" + " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n" + " </method>\n" + " </interface>\n"); + + /* interface */ + xml = g_string_append (xml, + " <interface name=\"org.gnome.DisplayManager.ChooserServer\">\n" + " <method name=\"SelectHostname\">\n" + " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n" + " </method>\n" + " <method name=\"Disconnect\">\n" + " </method>\n" + " </interface>\n"); + + reply = dbus_message_new_method_return (message); + + xml = g_string_append (xml, "</node>\n"); + xml_string = g_string_free (xml, FALSE); + + dbus_message_append_args (reply, + DBUS_TYPE_STRING, &xml_string, + DBUS_TYPE_INVALID); + + g_free (xml_string); + + if (reply == NULL) { + g_error ("No memory"); + } + + if (! dbus_connection_send (connection, reply, NULL)) { + g_error ("No memory"); + } + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +chooser_server_message_handler (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + const char *dbus_destination = dbus_message_get_destination (message); + const char *dbus_path = dbus_message_get_path (message); + const char *dbus_interface = dbus_message_get_interface (message); + const char *dbus_member = dbus_message_get_member (message); + + g_debug ("chooser_server_message_handler: destination=%s obj_path=%s interface=%s method=%s", + dbus_destination ? dbus_destination : "(null)", + dbus_path ? dbus_path : "(null)", + dbus_interface ? dbus_interface : "(null)", + dbus_member ? dbus_member : "(null)"); + + if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) { + DBusMessage *reply; + + reply = dbus_message_new_method_return (message); + + if (reply == NULL) { + g_error ("No memory"); + } + + if (! dbus_connection_send (connection, reply, NULL)) { + g_error ("No memory"); + } + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; + } else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") && + strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) { + + /*dbus_connection_unref (connection);*/ + + return DBUS_HANDLER_RESULT_HANDLED; + } else if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) { + return do_introspect (connection, message); + } else { + return chooser_handle_child_message (connection, message, user_data); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void +chooser_server_unregister_handler (DBusConnection *connection, + void *user_data) +{ + g_debug ("chooser_server_unregister_handler"); +} + +static DBusHandlerResult +connection_filter_function (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data); + const char *dbus_path = dbus_message_get_path (message); + const char *dbus_interface = dbus_message_get_interface (message); + const char *dbus_message = dbus_message_get_member (message); + + g_debug ("ChooserServer: obj_path=%s interface=%s method=%s", + dbus_path ? dbus_path : "(null)", + dbus_interface ? dbus_interface : "(null)", + dbus_message ? dbus_message : "(null)"); + + if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") + && strcmp (dbus_path, DBUS_PATH_LOCAL) == 0) { + + g_debug ("ChooserServer: Disconnected"); + + dbus_connection_unref (connection); + chooser_server->priv->chooser_connection = NULL; + + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static dbus_bool_t +allow_user_function (DBusConnection *connection, + unsigned long uid, + void *data) +{ + GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (data); + struct passwd *pwent; + + if (chooser_server->priv->user_name == NULL) { + return FALSE; + } + + pwent = getpwnam (chooser_server->priv->user_name); + if (pwent == NULL) { + return FALSE; + } + + if (pwent->pw_uid == uid) { + return TRUE; + } + + return FALSE; +} + +static void +handle_connection (DBusServer *server, + DBusConnection *new_connection, + void *user_data) +{ + GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data); + + g_debug ("ChooserServer: Handing new connection"); + + if (chooser_server->priv->chooser_connection == NULL) { + DBusObjectPathVTable vtable = { &chooser_server_unregister_handler, + &chooser_server_message_handler, + NULL, NULL, NULL, NULL + }; + + chooser_server->priv->chooser_connection = new_connection; + dbus_connection_ref (new_connection); + dbus_connection_setup_with_g_main (new_connection, NULL); + + g_debug ("ChooserServer: chooser connection is %p", new_connection); + + dbus_connection_add_filter (new_connection, + connection_filter_function, + chooser_server, + NULL); + + dbus_connection_set_unix_user_function (new_connection, + allow_user_function, + chooser_server, + NULL); + + dbus_connection_register_object_path (new_connection, + GDM_CHOOSER_SERVER_DBUS_PATH, + &vtable, + chooser_server); + + g_signal_emit (chooser_server, signals[CONNECTED], 0); + + } +} + +gboolean +gdm_chooser_server_start (GdmChooserServer *chooser_server) +{ + DBusError error; + gboolean ret; + char *address; + const char *auth_mechanisms[] = {"EXTERNAL", NULL}; + + ret = FALSE; + + g_debug ("ChooserServer: Creating D-Bus server for chooser"); + + address = generate_address (); + + dbus_error_init (&error); + chooser_server->priv->server = dbus_server_listen (address, &error); + g_free (address); + + if (chooser_server->priv->server == NULL) { + g_warning ("Cannot create D-BUS server for the chooser: %s", error.message); + /* FIXME: should probably fail if we can't create the socket */ + goto out; + } + + dbus_server_setup_with_g_main (chooser_server->priv->server, NULL); + dbus_server_set_auth_mechanisms (chooser_server->priv->server, auth_mechanisms); + dbus_server_set_new_connection_function (chooser_server->priv->server, + handle_connection, + chooser_server, + NULL); + ret = TRUE; + + g_free (chooser_server->priv->server_address); + chooser_server->priv->server_address = dbus_server_get_address (chooser_server->priv->server); + + g_debug ("ChooserServer: D-Bus server listening on %s", chooser_server->priv->server_address); + + out: + + return ret; +} + +gboolean +gdm_chooser_server_stop (GdmChooserServer *chooser_server) +{ + gboolean ret; + + ret = FALSE; + + g_debug ("ChooserServer: Stopping chooser server..."); + + return ret; +} + +char * +gdm_chooser_server_get_address (GdmChooserServer *chooser_server) +{ + return g_strdup (chooser_server->priv->server_address); +} + +static void +_gdm_chooser_server_set_display_id (GdmChooserServer *chooser_server, + const char *display_id) +{ + g_free (chooser_server->priv->display_id); + chooser_server->priv->display_id = g_strdup (display_id); +} + +static void +_gdm_chooser_server_set_user_name (GdmChooserServer *chooser_server, + const char *name) +{ + g_free (chooser_server->priv->user_name); + chooser_server->priv->user_name = g_strdup (name); +} + +static void +_gdm_chooser_server_set_group_name (GdmChooserServer *chooser_server, + const char *name) +{ + g_free (chooser_server->priv->group_name); + chooser_server->priv->group_name = g_strdup (name); +} + +static void +gdm_chooser_server_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdmChooserServer *self; + + self = GDM_CHOOSER_SERVER (object); + + switch (prop_id) { + case PROP_DISPLAY_ID: + _gdm_chooser_server_set_display_id (self, g_value_get_string (value)); + break; + case PROP_USER_NAME: + _gdm_chooser_server_set_user_name (self, g_value_get_string (value)); + break; + case PROP_GROUP_NAME: + _gdm_chooser_server_set_group_name (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gdm_chooser_server_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdmChooserServer *self; + + self = GDM_CHOOSER_SERVER (object); + + switch (prop_id) { + case PROP_DISPLAY_ID: + g_value_set_string (value, self->priv->display_id); + break; + case PROP_USER_NAME: + g_value_set_string (value, self->priv->user_name); + break; + case PROP_GROUP_NAME: + g_value_set_string (value, self->priv->group_name); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +gdm_chooser_server_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GdmChooserServer *chooser_server; + GdmChooserServerClass *klass; + + klass = GDM_CHOOSER_SERVER_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_SERVER)); + + chooser_server = GDM_CHOOSER_SERVER (G_OBJECT_CLASS (gdm_chooser_server_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + + return G_OBJECT (chooser_server); +} + +static void +gdm_chooser_server_class_init (GdmChooserServerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gdm_chooser_server_get_property; + object_class->set_property = gdm_chooser_server_set_property; + object_class->constructor = gdm_chooser_server_constructor; + object_class->finalize = gdm_chooser_server_finalize; + + g_type_class_add_private (klass, sizeof (GdmChooserServerPrivate)); + + g_object_class_install_property (object_class, + PROP_DISPLAY_ID, + g_param_spec_string ("display-id", + "display id", + "display id", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, + PROP_USER_NAME, + g_param_spec_string ("user-name", + "user name", + "user name", + "gdm", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, + PROP_GROUP_NAME, + g_param_spec_string ("group-name", + "group name", + "group name", + "gdm", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + signals [HOSTNAME_SELECTED] = + g_signal_new ("hostname-selected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmChooserServerClass, hostname_selected), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + signals [CONNECTED] = + g_signal_new ("connected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmChooserServerClass, connected), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals [DISCONNECTED] = + g_signal_new ("disconnected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmChooserServerClass, disconnected), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +static void +gdm_chooser_server_init (GdmChooserServer *chooser_server) +{ + + chooser_server->priv = GDM_CHOOSER_SERVER_GET_PRIVATE (chooser_server); +} + +static void +gdm_chooser_server_finalize (GObject *object) +{ + GdmChooserServer *chooser_server; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_CHOOSER_SERVER (object)); + + chooser_server = GDM_CHOOSER_SERVER (object); + + g_return_if_fail (chooser_server->priv != NULL); + + gdm_chooser_server_stop (chooser_server); + + G_OBJECT_CLASS (gdm_chooser_server_parent_class)->finalize (object); +} + +GdmChooserServer * +gdm_chooser_server_new (const char *display_id) +{ + GObject *object; + + object = g_object_new (GDM_TYPE_CHOOSER_SERVER, + "display-id", display_id, + NULL); + + return GDM_CHOOSER_SERVER (object); +} diff --git a/daemon/gdm-chooser-server.h b/daemon/gdm-chooser-server.h new file mode 100644 index 00000000..e5d4fee5 --- /dev/null +++ b/daemon/gdm-chooser-server.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __GDM_CHOOSER_SERVER_H +#define __GDM_CHOOSER_SERVER_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GDM_TYPE_CHOOSER_SERVER (gdm_chooser_server_get_type ()) +#define GDM_CHOOSER_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_SERVER, GdmChooserServer)) +#define GDM_CHOOSER_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_SERVER, GdmChooserServerClass)) +#define GDM_IS_CHOOSER_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_SERVER)) +#define GDM_IS_CHOOSER_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_SERVER)) +#define GDM_CHOOSER_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_SERVER, GdmChooserServerClass)) + +typedef struct GdmChooserServerPrivate GdmChooserServerPrivate; + +typedef struct +{ + GObject parent; + GdmChooserServerPrivate *priv; +} GdmChooserServer; + +typedef struct +{ + GObjectClass parent_class; + + void (* hostname_selected) (GdmChooserServer *chooser_server, + const char *hostname); + void (* connected) (GdmChooserServer *chooser_server); + void (* disconnected) (GdmChooserServer *chooser_server); +} GdmChooserServerClass; + +GType gdm_chooser_server_get_type (void); +GdmChooserServer * gdm_chooser_server_new (const char *display_id); + +gboolean gdm_chooser_server_start (GdmChooserServer *chooser_server); +gboolean gdm_chooser_server_stop (GdmChooserServer *chooser_server); +char * gdm_chooser_server_get_address (GdmChooserServer *chooser_server); + +G_END_DECLS + +#endif /* __GDM_CHOOSER_SERVER_H */ diff --git a/daemon/gdm-chooser-session.c b/daemon/gdm-chooser-session.c new file mode 100644 index 00000000..0c2c04e8 --- /dev/null +++ b/daemon/gdm-chooser-session.c @@ -0,0 +1,948 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <ctype.h> +#include <pwd.h> +#include <grp.h> +#include <signal.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "gdm-common.h" + +#include "gdm-chooser-session.h" + +#define DBUS_LAUNCH_COMMAND BINDIR "/dbus-launch --exit-with-session" + +#define GDM_CHOOSER_SERVER_DBUS_PATH "/org/gnome/DisplayManager/ChooserServer" +#define GDM_CHOOSER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.ChooserServer" + +extern char **environ; + +#define GDM_CHOOSER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionPrivate)) + +struct GdmChooserSessionPrivate +{ + char *command; + GPid pid; + + char *user_name; + char *group_name; + + char *x11_display_name; + char *x11_display_device; + char *x11_display_hostname; + char *x11_authority_file; + + guint child_watch_id; + + GPid dbus_pid; + char *dbus_bus_address; + + char *server_address; +}; + +enum { + PROP_0, + PROP_X11_DISPLAY_NAME, + PROP_X11_DISPLAY_DEVICE, + PROP_X11_DISPLAY_HOSTNAME, + PROP_X11_AUTHORITY_FILE, + PROP_USER_NAME, + PROP_GROUP_NAME, + PROP_SERVER_ADDRESS, +}; + +enum { + STARTED, + STOPPED, + EXITED, + DIED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + +static void gdm_chooser_session_class_init (GdmChooserSessionClass *klass); +static void gdm_chooser_session_init (GdmChooserSession *chooser_session); +static void gdm_chooser_session_finalize (GObject *object); + +G_DEFINE_TYPE (GdmChooserSession, gdm_chooser_session, G_TYPE_OBJECT) + +static void +listify_hash (const char *key, + const char *value, + GPtrArray *env) +{ + char *str; + str = g_strdup_printf ("%s=%s", key, value); + g_debug ("GdmChooserSession: chooser environment: %s", str); + g_ptr_array_add (env, str); +} + +static GPtrArray * +get_chooser_environment (GdmChooserSession *chooser_session) +{ + GPtrArray *env; + GHashTable *hash; + struct passwd *pwent; + + env = g_ptr_array_new (); + + /* create a hash table of current environment, then update keys has necessary */ + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + if (chooser_session->priv->dbus_bus_address != NULL) { + g_hash_table_insert (hash, g_strdup ("DBUS_SESSION_BUS_ADDRESS"), g_strdup (chooser_session->priv->dbus_bus_address)); + } + if (chooser_session->priv->server_address != NULL) { + g_hash_table_insert (hash, g_strdup ("GDM_CHOOSER_DBUS_ADDRESS"), g_strdup (chooser_session->priv->server_address)); + } + + g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (chooser_session->priv->x11_authority_file)); + g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (chooser_session->priv->x11_display_name)); + +#if 0 + /* hackish ain't it */ + set_xnest_parent_stuff (); +#endif + + g_hash_table_insert (hash, g_strdup ("LOGNAME"), g_strdup (chooser_session->priv->user_name)); + g_hash_table_insert (hash, g_strdup ("USER"), g_strdup (chooser_session->priv->user_name)); + g_hash_table_insert (hash, g_strdup ("USERNAME"), g_strdup (chooser_session->priv->user_name)); + + g_hash_table_insert (hash, g_strdup ("GDM_VERSION"), g_strdup (VERSION)); + g_hash_table_remove (hash, "MAIL"); + + g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/")); + g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup ("/")); + g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup ("/bin/sh")); + + pwent = getpwnam (chooser_session->priv->user_name); + if (pwent != NULL) { + if (pwent->pw_dir != NULL && pwent->pw_dir[0] != '\0') { + g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir)); + g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup (pwent->pw_dir)); + } + + g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell)); + } + + + g_hash_table_insert (hash, g_strdup ("PATH"), g_strdup (g_getenv ("PATH"))); + + g_hash_table_insert (hash, g_strdup ("RUNNING_UNDER_GDM"), g_strdup ("true")); + + g_hash_table_foreach (hash, (GHFunc)listify_hash, env); + g_hash_table_destroy (hash); + + g_ptr_array_add (env, NULL); + + return env; +} + +static void +chooser_session_child_watch (GPid pid, + int status, + GdmChooserSession *session) +{ + g_debug ("GdmChooserSession: child (pid:%d) done (%s:%d)", + (int) pid, + WIFEXITED (status) ? "status" + : WIFSIGNALED (status) ? "signal" + : "unknown", + WIFEXITED (status) ? WEXITSTATUS (status) + : WIFSIGNALED (status) ? WTERMSIG (status) + : -1); + + if (WIFEXITED (status)) { + int code = WEXITSTATUS (status); + g_signal_emit (session, signals [EXITED], 0, code); + } else if (WIFSIGNALED (status)) { + int num = WTERMSIG (status); + g_signal_emit (session, signals [DIED], 0, num); + } + + g_spawn_close_pid (session->priv->pid); + session->priv->pid = -1; +} + +typedef struct { + const char *user_name; + const char *group_name; +} SpawnChildData; + +static void +spawn_child_setup (SpawnChildData *data) +{ + struct passwd *pwent; + struct group *grent; + + if (data->user_name == NULL) { + return; + } + + pwent = getpwnam (data->user_name); + if (pwent == NULL) { + g_warning (_("User %s doesn't exist"), + data->user_name); + _exit (1); + } + + grent = getgrnam (data->group_name); + if (grent == NULL) { + g_warning (_("Group %s doesn't exist"), + data->group_name); + _exit (1); + } + + g_debug ("GdmChooserSession: Changing (uid:gid) for child process to (%d:%d)", + pwent->pw_uid, + grent->gr_gid); + + if (pwent->pw_uid != 0) { + if (setgid (grent->gr_gid) < 0) { + g_warning (_("Couldn't set groupid to %d"), + grent->gr_gid); + _exit (1); + } + + if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) { + g_warning (_("initgroups () failed for %s"), + pwent->pw_name); + _exit (1); + } + + if (setuid (pwent->pw_uid) < 0) { + g_warning (_("Couldn't set userid to %d"), + (int)pwent->pw_uid); + _exit (1); + } + } else { + gid_t groups[1] = { 0 }; + + if (setgid (0) < 0) { + g_warning (_("Couldn't set groupid to 0")); + /* Don't error out, it's not fatal, if it fails we'll + * just still be */ + } + + /* this will get rid of any suplementary groups etc... */ + setgroups (1, groups); + } + + if (setsid () < 0) { + g_debug ("GdmChooserSession: could not set pid '%u' as leader of new session and process group - %s", + (guint) getpid (), g_strerror (errno)); + _exit (2); + } +} + +static gboolean +spawn_command_line_sync_as_user (const char *command_line, + const char *user_name, + const char *group_name, + char **env, + char **std_output, + char **std_error, + int *exit_status, + GError **error) +{ + char **argv; + GError *local_error; + gboolean ret; + gboolean res; + SpawnChildData data; + + ret = FALSE; + + argv = NULL; + local_error = NULL; + if (! g_shell_parse_argv (command_line, NULL, &argv, &local_error)) { + g_warning ("Could not parse command: %s", local_error->message); + g_propagate_error (error, local_error); + goto out; + } + + data.user_name = user_name; + data.group_name = group_name; + + local_error = NULL; + res = g_spawn_sync (NULL, + argv, + env, + G_SPAWN_SEARCH_PATH, + (GSpawnChildSetupFunc)spawn_child_setup, + &data, + std_output, + std_error, + exit_status, + &local_error); + + if (! res) { + g_warning ("Could not spawn command: %s", local_error->message); + g_propagate_error (error, local_error); + goto out; + } + + ret = TRUE; + out: + g_strfreev (argv); + + return ret; +} + +static gboolean +spawn_command_line_async_as_user (const char *command_line, + const char *user_name, + const char *group_name, + char **env, + GPid *child_pid, + GError **error) +{ + char **argv; + GError *local_error; + gboolean ret; + gboolean res; + SpawnChildData data; + + ret = FALSE; + + argv = NULL; + local_error = NULL; + if (! g_shell_parse_argv (command_line, NULL, &argv, &local_error)) { + g_warning ("Could not parse command: %s", local_error->message); + g_propagate_error (error, local_error); + goto out; + } + + data.user_name = user_name; + data.group_name = group_name; + + local_error = NULL; + res = g_spawn_async (NULL, + argv, + env, + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, + (GSpawnChildSetupFunc)spawn_child_setup, + &data, + child_pid, + &local_error); + if (! res) { + g_warning ("Could not spawn command: %s", local_error->message); + g_propagate_error (error, local_error); + goto out; + } + + ret = TRUE; + out: + g_strfreev (argv); + + return ret; +} + +static gboolean +parse_value_as_integer (const char *value, + int *intval) +{ + char *end_of_valid_int; + glong long_value; + gint int_value; + + errno = 0; + long_value = strtol (value, &end_of_valid_int, 10); + + if (*value == '\0' || *end_of_valid_int != '\0') { + return FALSE; + } + + int_value = long_value; + if (int_value != long_value || errno == ERANGE) { + return FALSE; + } + + *intval = int_value; + + return TRUE; +} + +static gboolean +parse_dbus_launch_output (const char *output, + char **addressp, + GPid *pidp) +{ + GRegex *re; + GMatchInfo *match_info; + gboolean ret; + gboolean res; + GError *error; + + ret = FALSE; + + error = NULL; + re = g_regex_new ("DBUS_SESSION_BUS_ADDRESS=(.+)\nDBUS_SESSION_BUS_PID=([0-9]+)", 0, 0, &error); + if (re == NULL) { + g_critical (error->message); + } + + g_regex_match (re, output, 0, &match_info); + + res = g_match_info_matches (match_info); + if (! res) { + g_warning ("Unable to parse output: %s", output); + goto out; + } + + if (addressp != NULL) { + *addressp = g_strdup (g_match_info_fetch (match_info, 1)); + } + + if (pidp != NULL) { + int pid; + gboolean res; + res = parse_value_as_integer (g_match_info_fetch (match_info, 2), &pid); + if (res) { + *pidp = pid; + } else { + *pidp = 0; + } + } + + ret = TRUE; + + out: + g_match_info_free (match_info); + g_regex_unref (re); + + return ret; +} + +static gboolean +start_dbus_daemon (GdmChooserSession *chooser_session) +{ + gboolean res; + char *std_out; + char *std_err; + int exit_status; + GError *error; + GPtrArray *env; + + env = get_chooser_environment (chooser_session); + + error = NULL; + res = spawn_command_line_sync_as_user (DBUS_LAUNCH_COMMAND, + chooser_session->priv->user_name, + chooser_session->priv->group_name, + (char **)env->pdata, + &std_out, + &std_err, + &exit_status, + &error); + g_ptr_array_foreach (env, (GFunc)g_free, NULL); + g_ptr_array_free (env, TRUE); + + if (! res) { + g_warning ("Unable to launch D-Bus daemon: %s", error->message); + g_error_free (error); + goto out; + } + + /* pull the address and pid from the output */ + res = parse_dbus_launch_output (std_out, + &chooser_session->priv->dbus_bus_address, + &chooser_session->priv->dbus_pid); + if (! res) { + g_warning ("Unable to parse D-Bus launch output"); + } else { + g_debug ("GdmChooserSession: Started D-Bus daemon on pid %d", chooser_session->priv->dbus_pid); + } + out: + return res; +} + +static gboolean +stop_dbus_daemon (GdmChooserSession *chooser_session) +{ + if (chooser_session->priv->dbus_pid > 0) { + gdm_signal_pid (-1 * chooser_session->priv->dbus_pid, SIGTERM); + chooser_session->priv->dbus_pid = 0; + } + return TRUE; +} + +static gboolean +gdm_chooser_session_spawn (GdmChooserSession *chooser_session) +{ + GError *error; + GPtrArray *env; + gboolean ret; + gboolean res; + + ret = FALSE; + + g_debug ("GdmChooserSession: Running chooser_session process: %s", chooser_session->priv->command); + + res = start_dbus_daemon (chooser_session); + if (! res) { + /* FIXME: */ + } + + env = get_chooser_environment (chooser_session); + + error = NULL; + + ret = spawn_command_line_async_as_user (chooser_session->priv->command, + chooser_session->priv->user_name, + chooser_session->priv->group_name, + (char **)env->pdata, + &chooser_session->priv->pid, + &error); + + g_ptr_array_foreach (env, (GFunc)g_free, NULL); + g_ptr_array_free (env, TRUE); + + if (! ret) { + g_warning ("Could not start command '%s': %s", + chooser_session->priv->command, + error->message); + g_error_free (error); + goto out; + } else { + g_debug ("GdmChooserSession: ChooserSession on pid %d", (int)chooser_session->priv->pid); + } + + chooser_session->priv->child_watch_id = g_child_watch_add (chooser_session->priv->pid, + (GChildWatchFunc)chooser_session_child_watch, + chooser_session); + + out: + + return ret; +} + +/** + * gdm_chooser_session_start: + * @disp: Pointer to a GdmDisplay structure + * + * Starts a local X chooser_session. Handles retries and fatal errors properly. + */ +gboolean +gdm_chooser_session_start (GdmChooserSession *chooser_session) +{ + gboolean res; + + g_debug ("GdmChooserSession: Starting chooser..."); + + res = gdm_chooser_session_spawn (chooser_session); + + if (res) { + + } + + + return res; +} + +static int +wait_on_child (int pid) +{ + int status; + + wait_again: + if (waitpid (pid, &status, 0) < 0) { + if (errno == EINTR) { + goto wait_again; + } else if (errno == ECHILD) { + ; /* do nothing, child already reaped */ + } else { + g_debug ("GdmChooserSession: waitpid () should not fail"); + } + } + + return status; +} + +static void +chooser_session_died (GdmChooserSession *chooser_session) +{ + int exit_status; + + g_debug ("GdmChooserSession: Waiting on process %d", chooser_session->priv->pid); + exit_status = wait_on_child (chooser_session->priv->pid); + + if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) { + g_debug ("GdmChooserSession: Wait on child process failed"); + } else { + /* exited normally */ + } + + g_spawn_close_pid (chooser_session->priv->pid); + chooser_session->priv->pid = -1; + + g_debug ("GdmChooserSession: ChooserSession died"); +} + +gboolean +gdm_chooser_session_stop (GdmChooserSession *chooser_session) +{ + + if (chooser_session->priv->pid <= 1) { + return TRUE; + } + + /* remove watch source before we can wait on child */ + if (chooser_session->priv->child_watch_id > 0) { + g_source_remove (chooser_session->priv->child_watch_id); + chooser_session->priv->child_watch_id = 0; + } + + g_debug ("GdmChooserSession: Stopping chooser_session"); + + gdm_signal_pid (-1 * chooser_session->priv->pid, SIGTERM); + chooser_session_died (chooser_session); + + stop_dbus_daemon (chooser_session); + + return TRUE; +} + +void +gdm_chooser_session_set_server_address (GdmChooserSession *chooser_session, + const char *address) +{ + g_return_if_fail (GDM_IS_CHOOSER_SESSION (chooser_session)); + + g_free (chooser_session->priv->server_address); + chooser_session->priv->server_address = g_strdup (address); +} + +static void +_gdm_chooser_session_set_x11_display_name (GdmChooserSession *chooser_session, + const char *name) +{ + g_free (chooser_session->priv->x11_display_name); + chooser_session->priv->x11_display_name = g_strdup (name); +} + +static void +_gdm_chooser_session_set_x11_display_hostname (GdmChooserSession *chooser_session, + const char *name) +{ + g_free (chooser_session->priv->x11_display_hostname); + chooser_session->priv->x11_display_hostname = g_strdup (name); +} + +static void +_gdm_chooser_session_set_x11_display_device (GdmChooserSession *chooser_session, + const char *name) +{ + g_free (chooser_session->priv->x11_display_device); + chooser_session->priv->x11_display_device = g_strdup (name); +} + +static void +_gdm_chooser_session_set_x11_authority_file (GdmChooserSession *chooser_session, + const char *file) +{ + g_free (chooser_session->priv->x11_authority_file); + chooser_session->priv->x11_authority_file = g_strdup (file); +} + +static void +_gdm_chooser_session_set_user_name (GdmChooserSession *chooser_session, + const char *name) +{ + g_free (chooser_session->priv->user_name); + chooser_session->priv->user_name = g_strdup (name); +} + +static void +_gdm_chooser_session_set_group_name (GdmChooserSession *chooser_session, + const char *name) +{ + g_free (chooser_session->priv->group_name); + chooser_session->priv->group_name = g_strdup (name); +} + +static void +gdm_chooser_session_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdmChooserSession *self; + + self = GDM_CHOOSER_SESSION (object); + + switch (prop_id) { + case PROP_X11_DISPLAY_NAME: + _gdm_chooser_session_set_x11_display_name (self, g_value_get_string (value)); + break; + case PROP_X11_DISPLAY_HOSTNAME: + _gdm_chooser_session_set_x11_display_hostname (self, g_value_get_string (value)); + break; + case PROP_X11_DISPLAY_DEVICE: + _gdm_chooser_session_set_x11_display_device (self, g_value_get_string (value)); + break; + case PROP_X11_AUTHORITY_FILE: + _gdm_chooser_session_set_x11_authority_file (self, g_value_get_string (value)); + break; + case PROP_USER_NAME: + _gdm_chooser_session_set_user_name (self, g_value_get_string (value)); + break; + case PROP_GROUP_NAME: + _gdm_chooser_session_set_group_name (self, g_value_get_string (value)); + break; + case PROP_SERVER_ADDRESS: + gdm_chooser_session_set_server_address (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gdm_chooser_session_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdmChooserSession *self; + + self = GDM_CHOOSER_SESSION (object); + + switch (prop_id) { + case PROP_X11_DISPLAY_NAME: + g_value_set_string (value, self->priv->x11_display_name); + break; + case PROP_X11_DISPLAY_HOSTNAME: + g_value_set_string (value, self->priv->x11_display_hostname); + break; + case PROP_X11_DISPLAY_DEVICE: + g_value_set_string (value, self->priv->x11_display_device); + break; + case PROP_X11_AUTHORITY_FILE: + g_value_set_string (value, self->priv->x11_authority_file); + break; + case PROP_USER_NAME: + g_value_set_string (value, self->priv->user_name); + break; + case PROP_GROUP_NAME: + g_value_set_string (value, self->priv->group_name); + break; + case PROP_SERVER_ADDRESS: + g_value_set_string (value, self->priv->server_address); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +gdm_chooser_session_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GdmChooserSession *chooser_session; + GdmChooserSessionClass *klass; + + klass = GDM_CHOOSER_SESSION_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_SESSION)); + + chooser_session = GDM_CHOOSER_SESSION (G_OBJECT_CLASS (gdm_chooser_session_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + + return G_OBJECT (chooser_session); +} + +static void +gdm_chooser_session_class_init (GdmChooserSessionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gdm_chooser_session_get_property; + object_class->set_property = gdm_chooser_session_set_property; + object_class->constructor = gdm_chooser_session_constructor; + object_class->finalize = gdm_chooser_session_finalize; + + g_type_class_add_private (klass, sizeof (GdmChooserSessionPrivate)); + + g_object_class_install_property (object_class, + PROP_X11_DISPLAY_NAME, + g_param_spec_string ("x11-display-name", + "name", + "name", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_X11_DISPLAY_HOSTNAME, + g_param_spec_string ("x11-display-hostname", + "hostname", + "hostname", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_X11_DISPLAY_DEVICE, + g_param_spec_string ("x11-display-device", + "device", + "device", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_X11_AUTHORITY_FILE, + g_param_spec_string ("x11-authority-file", + "authority file", + "authority file", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, + PROP_USER_NAME, + g_param_spec_string ("user-name", + "user name", + "user name", + "gdm", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, + PROP_GROUP_NAME, + g_param_spec_string ("group-name", + "group name", + "group name", + "gdm", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, + PROP_SERVER_ADDRESS, + g_param_spec_string ("server-address", + "server address", + "server address", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + signals [STARTED] = + g_signal_new ("started", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmChooserSessionClass, started), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals [STOPPED] = + g_signal_new ("stopped", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmChooserSessionClass, stopped), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals [EXITED] = + g_signal_new ("exited", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmChooserSessionClass, exited), + NULL, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + signals [DIED] = + g_signal_new ("died", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmChooserSessionClass, died), + NULL, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); +} + +static void +gdm_chooser_session_init (GdmChooserSession *chooser_session) +{ + + chooser_session->priv = GDM_CHOOSER_SESSION_GET_PRIVATE (chooser_session); + + chooser_session->priv->pid = -1; + + chooser_session->priv->command = g_strdup (LIBEXECDIR "/gdm-simple-chooser"); +} + +static void +gdm_chooser_session_finalize (GObject *object) +{ + GdmChooserSession *chooser_session; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_CHOOSER_SESSION (object)); + + chooser_session = GDM_CHOOSER_SESSION (object); + + g_return_if_fail (chooser_session->priv != NULL); + + gdm_chooser_session_stop (chooser_session); + + g_free (chooser_session->priv->command); + g_free (chooser_session->priv->user_name); + g_free (chooser_session->priv->group_name); + g_free (chooser_session->priv->x11_display_name); + g_free (chooser_session->priv->x11_display_device); + g_free (chooser_session->priv->x11_display_hostname); + g_free (chooser_session->priv->x11_authority_file); + g_free (chooser_session->priv->server_address); + + G_OBJECT_CLASS (gdm_chooser_session_parent_class)->finalize (object); +} + +GdmChooserSession * +gdm_chooser_session_new (const char *display_name, + const char *display_device, + const char *display_hostname) +{ + GObject *object; + + object = g_object_new (GDM_TYPE_CHOOSER_SESSION, + "x11-display-name", display_name, + "x11-display-device", display_device, + "x11-display-hostname", display_hostname, + NULL); + + return GDM_CHOOSER_SESSION (object); +} diff --git a/daemon/gdm-chooser-session.h b/daemon/gdm-chooser-session.h new file mode 100644 index 00000000..c2999b2a --- /dev/null +++ b/daemon/gdm-chooser-session.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __GDM_CHOOSER_SESSION_H +#define __GDM_CHOOSER_SESSION_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GDM_TYPE_CHOOSER_SESSION (gdm_chooser_session_get_type ()) +#define GDM_CHOOSER_SESSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSession)) +#define GDM_CHOOSER_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionClass)) +#define GDM_IS_CHOOSER_SESSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_SESSION)) +#define GDM_IS_CHOOSER_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_SESSION)) +#define GDM_CHOOSER_SESSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionClass)) + +typedef struct GdmChooserSessionPrivate GdmChooserSessionPrivate; + +typedef struct +{ + GObject parent; + GdmChooserSessionPrivate *priv; +} GdmChooserSession; + +typedef struct +{ + GObjectClass parent_class; + + void (* started) (GdmChooserSession *chooser_session); + void (* stopped) (GdmChooserSession *chooser_session); + void (* exited) (GdmChooserSession *chooser_session, + int exit_code); + void (* died) (GdmChooserSession *chooser_session, + int signal_number); +} GdmChooserSessionClass; + +GType gdm_chooser_session_get_type (void); +GdmChooserSession * gdm_chooser_session_new (const char *display_name, + const char *display_device, + const char *display_hostname); +void gdm_chooser_session_set_server_address (GdmChooserSession *chooser_session, + const char *server_address); +gboolean gdm_chooser_session_start (GdmChooserSession *chooser_session); +gboolean gdm_chooser_session_stop (GdmChooserSession *chooser_session); + +G_END_DECLS + +#endif /* __GDM_CHOOSER_SESSION_H */ diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c index e952e36f..fbae90b9 100644 --- a/daemon/gdm-display.c +++ b/daemon/gdm-display.c @@ -47,25 +47,25 @@ static guint32 display_serial = 1; struct GdmDisplayPrivate { - char *id; - char *seat_id; + char *id; + char *seat_id; - char *remote_hostname; - int x11_display_number; - char *x11_display_name; - int status; - time_t creation_time; - char *slave_command; + char *remote_hostname; + int x11_display_number; + char *x11_display_name; + int status; + time_t creation_time; + char *slave_command; char *x11_cookie; gsize x11_cookie_size; GdmDisplayAccessFile *access_file; - gboolean is_local; - guint finish_idle_id; + gboolean is_local; + guint finish_idle_id; - GdmSlaveProxy *slave_proxy; - DBusGConnection *connection; + GdmSlaveProxy *slave_proxy; + DBusGConnection *connection; GdmDisplayAccessFile *user_access_file; }; @@ -263,6 +263,33 @@ gdm_display_add_user_authorization (GdmDisplay *display, } static gboolean +gdm_display_real_set_slave_bus_name (GdmDisplay *display, + const char *name, + GError **error) +{ + + return TRUE; +} + +gboolean +gdm_display_set_slave_bus_name (GdmDisplay *display, + const char *name, + GError **error) +{ + gboolean ret; + + g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE); + + g_debug ("Setting slave bus name:%s on display %s", name, display->priv->x11_display_name); + + g_object_ref (display); + ret = GDM_DISPLAY_GET_CLASS (display)->set_slave_bus_name (display, name, error); + g_object_unref (display); + + return ret; +} + +static gboolean gdm_display_real_remove_user_authorization (GdmDisplay *display, const char *username, GError **error) @@ -802,6 +829,7 @@ gdm_display_class_init (GdmDisplayClass *klass) klass->create_authority = gdm_display_real_create_authority; klass->add_user_authorization = gdm_display_real_add_user_authorization; klass->remove_user_authorization = gdm_display_real_remove_user_authorization; + klass->set_slave_bus_name = gdm_display_real_set_slave_bus_name; klass->manage = gdm_display_real_manage; klass->finish = gdm_display_real_finish; klass->unmanage = gdm_display_real_unmanage; diff --git a/daemon/gdm-display.h b/daemon/gdm-display.h index 4647ce07..87e274bc 100644 --- a/daemon/gdm-display.h +++ b/daemon/gdm-display.h @@ -61,10 +61,12 @@ typedef struct gboolean (*remove_user_authorization) (GdmDisplay *display, const char *username, GError **error); + gboolean (*set_slave_bus_name) (GdmDisplay *display, + const char *name, + GError **error); gboolean (*manage) (GdmDisplay *display); gboolean (*finish) (GdmDisplay *display); gboolean (*unmanage) (GdmDisplay *display); - } GdmDisplayClass; typedef enum @@ -123,6 +125,9 @@ gboolean gdm_display_add_user_authorization (GdmDisplay *disp gboolean gdm_display_remove_user_authorization (GdmDisplay *display, const char *username, GError **error); +gboolean gdm_display_set_slave_bus_name (GdmDisplay *display, + const char *name, + GError **error); G_END_DECLS diff --git a/daemon/gdm-display.xml b/daemon/gdm-display.xml index 239ad763..97d236b6 100644 --- a/daemon/gdm-display.xml +++ b/daemon/gdm-display.xml @@ -32,5 +32,8 @@ <method name="RemoveUserAuthorization"> <arg name="username" direction="in" type="s"/> </method> + <method name="SetSlaveBusName"> + <arg name="name" direction="in" type="s"/> + </method> </interface> </node> diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c index 971b2c39..ecda3225 100644 --- a/daemon/gdm-factory-slave.c +++ b/daemon/gdm-factory-slave.c @@ -67,8 +67,6 @@ struct GdmFactorySlavePrivate { char *id; GPid pid; - guint output_watch_id; - guint error_watch_id; guint greeter_reset_id; GPid server_pid; diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c index 68e9b349..612ded08 100644 --- a/daemon/gdm-greeter-server.c +++ b/daemon/gdm-greeter-server.c @@ -56,9 +56,6 @@ struct GdmGreeterServerPrivate char *group_name; char *display_id; - gboolean interrupted; - gboolean always_restart_greeter; - DBusServer *server; char *server_address; DBusConnection *greeter_connection; diff --git a/daemon/gdm-greeter-session.c b/daemon/gdm-greeter-session.c index a7a7d368..48891e7c 100644 --- a/daemon/gdm-greeter-session.c +++ b/daemon/gdm-greeter-session.c @@ -71,11 +71,6 @@ struct GdmGreeterSessionPrivate CkConnector *ckc; - int user_max_filesize; - - gboolean interrupted; - gboolean always_restart_greeter; - guint child_watch_id; GPid dbus_pid; @@ -1030,7 +1025,6 @@ gdm_greeter_session_init (GdmGreeterSession *greeter_session) greeter_session->priv->pid = -1; greeter_session->priv->command = g_strdup (LIBEXECDIR "/gdm-simple-greeter"); - greeter_session->priv->user_max_filesize = 65536; } static void diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c index 40e16bc6..3289fb3c 100644 --- a/daemon/gdm-product-slave.c +++ b/daemon/gdm-product-slave.c @@ -66,8 +66,6 @@ struct GdmProductSlavePrivate { char *id; GPid pid; - guint output_watch_id; - guint error_watch_id; char *relay_address; diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c index ce83180f..6f0564f2 100644 --- a/daemon/gdm-simple-slave.c +++ b/daemon/gdm-simple-slave.c @@ -62,8 +62,6 @@ struct GdmSimpleSlavePrivate { char *id; GPid pid; - guint output_watch_id; - guint error_watch_id; guint greeter_reset_id; guint start_session_id; diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c index b25cbff4..e8164f27 100644 --- a/daemon/gdm-slave.c +++ b/daemon/gdm-slave.c @@ -417,6 +417,35 @@ display_proxy_destroyed_cb (DBusGProxy *display_proxy, } static gboolean +gdm_slave_set_slave_bus_name (GdmSlave *slave) +{ + gboolean res; + GError *error; + const char *name; + + name = dbus_bus_get_unique_name (dbus_g_connection_get_connection (slave->priv->connection)); + + error = NULL; + res = dbus_g_proxy_call (slave->priv->display_proxy, + "SetSlaveBusName", + &error, + G_TYPE_STRING, name, + G_TYPE_INVALID, + G_TYPE_INVALID); + + if (! res) { + if (error != NULL) { + g_warning ("Failed to set slave bus name on parent: %s", error->message); + g_error_free (error); + } else { + g_warning ("Failed to set slave bus name on parent"); + } + } + + return res; +} + +static gboolean gdm_slave_real_start (GdmSlave *slave) { gboolean res; @@ -475,6 +504,8 @@ gdm_slave_real_start (GdmSlave *slave) exit (1); } + gdm_slave_set_slave_bus_name (slave); + /* cache some values up front */ error = NULL; res = dbus_g_proxy_call (slave->priv->display_proxy, @@ -1123,7 +1154,7 @@ gdm_slave_get_property (GObject *object, static gboolean register_slave (GdmSlave *slave) { - GError *error = NULL; + GError *error; error = NULL; slave->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); @@ -1155,6 +1186,7 @@ gdm_slave_constructor (GType type, slave = GDM_SLAVE (G_OBJECT_CLASS (gdm_slave_parent_class)->constructor (type, n_construct_properties, construct_properties)); + /* Always match the slave id with the master */ id = NULL; if (g_str_has_prefix (slave->priv->display_id, "/org/gnome/DisplayManager/Display")) { diff --git a/daemon/gdm-xdmcp-chooser-display.c b/daemon/gdm-xdmcp-chooser-display.c new file mode 100644 index 00000000..85bd3b71 --- /dev/null +++ b/daemon/gdm-xdmcp-chooser-display.c @@ -0,0 +1,234 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> + +#include "gdm-display.h" +#include "gdm-xdmcp-chooser-display.h" +#include "gdm-xdmcp-chooser-display-glue.h" + +#include "gdm-common.h" +#include "gdm-address.h" + +#define DEFAULT_SLAVE_COMMAND LIBEXECDIR"/gdm-xdmcp-chooser-slave" + +#define GDM_DBUS_NAME "/org/gnome/DisplayManager" +#define GDM_XDMCP_CHOOSER_SLAVE_DBUS_INTERFACE "org.gnome.DisplayManager.XdmcpChooserSlave" + +#define GDM_XDMCP_CHOOSER_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_CHOOSER_DISPLAY, GdmXdmcpChooserDisplayPrivate)) + +struct GdmXdmcpChooserDisplayPrivate +{ + DBusGProxy *slave_proxy; +}; + +enum { + PROP_0, +}; + +enum { + HOSTNAME_SELECTED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + +static void gdm_xdmcp_chooser_display_class_init (GdmXdmcpChooserDisplayClass *klass); +static void gdm_xdmcp_chooser_display_init (GdmXdmcpChooserDisplay *xdmcp_chooser_display); +static void gdm_xdmcp_chooser_display_finalize (GObject *object); + +G_DEFINE_TYPE (GdmXdmcpChooserDisplay, gdm_xdmcp_chooser_display, GDM_TYPE_XDMCP_DISPLAY) + +static void +on_hostname_selected (DBusGProxy *proxy, + const char *hostname, + GdmXdmcpChooserDisplay *display) +{ + g_debug ("GdmXdmcpChooserDisplay: hostname selected: %s", hostname); + g_signal_emit (display, signals [HOSTNAME_SELECTED], 0, hostname); +} + +static gboolean +gdm_xdmcp_chooser_display_set_slave_bus_name (GdmDisplay *display, + const char *name, + GError **error) +{ + char *display_id; + const char *slave_num; + char *slave_id; + DBusGConnection *connection; + GError *local_error; + GdmXdmcpChooserDisplay *chooser_display; + + display_id = NULL; + slave_id = NULL; + slave_num = NULL; + + chooser_display = GDM_XDMCP_CHOOSER_DISPLAY (display); + if (chooser_display->priv->slave_proxy != NULL) { + g_object_unref (chooser_display->priv->slave_proxy); + } + + g_object_get (display, "id", &display_id, NULL); + + if (g_str_has_prefix (display_id, "/org/gnome/DisplayManager/Display")) { + slave_num = display_id + strlen ("/org/gnome/DisplayManager/Display"); + } + + slave_id = g_strdup_printf ("/org/gnome/DisplayManager/Slave%s", slave_num); + + local_error = NULL; + connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &local_error); + if (connection == NULL) { + if (local_error != NULL) { + g_critical ("error getting system bus: %s", local_error->message); + g_error_free (local_error); + } + } + + g_debug ("GdmXdmcpChooserDisplay: creating proxy for %s on %s", slave_id, name); + + chooser_display->priv->slave_proxy = dbus_g_proxy_new_for_name (connection, + name, + slave_id, + GDM_XDMCP_CHOOSER_SLAVE_DBUS_INTERFACE); + if (chooser_display->priv->slave_proxy == NULL) { + g_warning ("Failed to connect to the slave object"); + goto out; + } + dbus_g_proxy_add_signal (chooser_display->priv->slave_proxy, + "HostnameSelected", + G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (chooser_display->priv->slave_proxy, + "HostnameSelected", + G_CALLBACK (on_hostname_selected), + display, + NULL); + out: + + g_free (display_id); + g_free (slave_id); + + return GDM_DISPLAY_CLASS (gdm_xdmcp_chooser_display_parent_class)->set_slave_bus_name (display, name, error); +} + +static gboolean +gdm_xdmcp_chooser_display_manage (GdmDisplay *display) +{ + g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE); + + GDM_DISPLAY_CLASS (gdm_xdmcp_chooser_display_parent_class)->manage (display); + + return TRUE; +} + +static void +gdm_xdmcp_chooser_display_class_init (GdmXdmcpChooserDisplayClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass); + + object_class->finalize = gdm_xdmcp_chooser_display_finalize; + + display_class->manage = gdm_xdmcp_chooser_display_manage; + display_class->set_slave_bus_name = gdm_xdmcp_chooser_display_set_slave_bus_name; + + signals [HOSTNAME_SELECTED] = + g_signal_new ("hostname-selected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmXdmcpChooserDisplayClass, hostname_selected), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + g_type_class_add_private (klass, sizeof (GdmXdmcpChooserDisplayPrivate)); + + dbus_g_object_type_install_info (GDM_TYPE_XDMCP_CHOOSER_DISPLAY, &dbus_glib_gdm_xdmcp_chooser_display_object_info); +} + +static void +gdm_xdmcp_chooser_display_init (GdmXdmcpChooserDisplay *xdmcp_chooser_display) +{ + + xdmcp_chooser_display->priv = GDM_XDMCP_CHOOSER_DISPLAY_GET_PRIVATE (xdmcp_chooser_display); +} + +static void +gdm_xdmcp_chooser_display_finalize (GObject *object) +{ + GdmXdmcpChooserDisplay *chooser_display; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_XDMCP_CHOOSER_DISPLAY (object)); + + chooser_display = GDM_XDMCP_CHOOSER_DISPLAY (object); + + g_return_if_fail (chooser_display->priv != NULL); + + if (chooser_display->priv->slave_proxy != NULL) { + g_object_unref (chooser_display->priv->slave_proxy); + } + + G_OBJECT_CLASS (gdm_xdmcp_chooser_display_parent_class)->finalize (object); +} + +GdmDisplay * +gdm_xdmcp_chooser_display_new (const char *hostname, + int number, + GdmAddress *address, + gint32 session_number) +{ + GObject *object; + char *x11_display; + + x11_display = g_strdup_printf ("%s:%d", hostname, number); + object = g_object_new (GDM_TYPE_XDMCP_CHOOSER_DISPLAY, + "slave-command", DEFAULT_SLAVE_COMMAND, + "remote-hostname", hostname, + "x11-display-number", number, + "x11-display-name", x11_display, + "is-local", FALSE, + "remote-address", address, + "session-number", session_number, + NULL); + g_free (x11_display); + + return GDM_DISPLAY (object); +} diff --git a/daemon/gdm-xdmcp-chooser-display.h b/daemon/gdm-xdmcp-chooser-display.h new file mode 100644 index 00000000..8ab17b8d --- /dev/null +++ b/daemon/gdm-xdmcp-chooser-display.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __GDM_XDMCP_CHOOSER_DISPLAY_H +#define __GDM_XDMCP_CHOOSER_DISPLAY_H + +#include <sys/types.h> +#include <sys/socket.h> +#include <glib-object.h> +#include <dbus/dbus-glib.h> + +#include "gdm-xdmcp-display.h" +#include "gdm-address.h" + +G_BEGIN_DECLS + +#define GDM_TYPE_XDMCP_CHOOSER_DISPLAY (gdm_xdmcp_chooser_display_get_type ()) +#define GDM_XDMCP_CHOOSER_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_XDMCP_CHOOSER_DISPLAY, GdmXdmcpChooserDisplay)) +#define GDM_XDMCP_CHOOSER_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_XDMCP_CHOOSER_DISPLAY, GdmXdmcpChooserDisplayClass)) +#define GDM_IS_XDMCP_CHOOSER_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_XDMCP_CHOOSER_DISPLAY)) +#define GDM_IS_XDMCP_CHOOSER_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_XDMCP_CHOOSER_DISPLAY)) +#define GDM_XDMCP_CHOOSER_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_XDMCP_CHOOSER_DISPLAY, GdmXdmcpChooserDisplayClass)) + +typedef struct GdmXdmcpChooserDisplayPrivate GdmXdmcpChooserDisplayPrivate; + +typedef struct +{ + GdmXdmcpDisplay parent; + GdmXdmcpChooserDisplayPrivate *priv; +} GdmXdmcpChooserDisplay; + +typedef struct +{ + GdmXdmcpDisplayClass parent_class; + + void (* hostname_selected) (GdmXdmcpChooserDisplay *display, + const char *hostname); +} GdmXdmcpChooserDisplayClass; + +GType gdm_xdmcp_chooser_display_get_type (void); + + +GdmDisplay * gdm_xdmcp_chooser_display_new (const char *hostname, + int number, + GdmAddress *addr, + gint32 serial_number); + +G_END_DECLS + +#endif /* __GDM_XDMCP_CHOOSER_DISPLAY_H */ diff --git a/daemon/gdm-xdmcp-chooser-display.xml b/daemon/gdm-xdmcp-chooser-display.xml new file mode 100644 index 00000000..194168f8 --- /dev/null +++ b/daemon/gdm-xdmcp-chooser-display.xml @@ -0,0 +1,5 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> +<node> + <interface name="org.gnome.DisplayManager.XdmcpChooserDisplay"> + </interface> +</node> diff --git a/daemon/gdm-xdmcp-chooser-slave.c b/daemon/gdm-xdmcp-chooser-slave.c new file mode 100644 index 00000000..39e62c83 --- /dev/null +++ b/daemon/gdm-xdmcp-chooser-slave.c @@ -0,0 +1,432 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib/gstdio.h> +#include <glib-object.h> + +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include <X11/Xlib.h> /* for Display */ + +#include "gdm-common.h" + +#include "gdm-xdmcp-chooser-slave.h" +#include "gdm-xdmcp-chooser-slave-glue.h" + +#include "gdm-server.h" +#include "gdm-chooser-server.h" +#include "gdm-chooser-session.h" + +#define GDM_XDMCP_CHOOSER_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlavePrivate)) + +#define GDM_DBUS_NAME "org.gnome.DisplayManager" +#define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display" + +#define MAX_CONNECT_ATTEMPTS 10 + +struct GdmXdmcpChooserSlavePrivate +{ + char *id; + GPid pid; + + int ping_interval; + + guint connection_attempts; + + GdmChooserServer *chooser_server; + GdmChooserSession *chooser; +}; + +enum { + PROP_0, +}; + +enum { + HOSTNAME_SELECTED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + +static void gdm_xdmcp_chooser_slave_class_init (GdmXdmcpChooserSlaveClass *klass); +static void gdm_xdmcp_chooser_slave_init (GdmXdmcpChooserSlave *xdmcp_chooser_slave); +static void gdm_xdmcp_chooser_slave_finalize (GObject *object); + +G_DEFINE_TYPE (GdmXdmcpChooserSlave, gdm_xdmcp_chooser_slave, GDM_TYPE_SLAVE) + + +static void +on_chooser_session_start (GdmChooserSession *chooser, + GdmXdmcpChooserSlave *slave) +{ + g_debug ("GdmXdmcpChooserSlave: Chooser started"); +} + +static void +on_chooser_session_stop (GdmChooserSession *chooser, + GdmXdmcpChooserSlave *slave) +{ + g_debug ("GdmXdmcpChooserSlave: Chooser stopped"); + gdm_slave_stopped (GDM_SLAVE (slave)); +} + +static void +on_chooser_session_exited (GdmChooserSession *chooser, + int code, + GdmXdmcpChooserSlave *slave) +{ + g_debug ("GdmXdmcpChooserSlave: Chooser exited: %d", code); + gdm_slave_stopped (GDM_SLAVE (slave)); +} + +static void +on_chooser_session_died (GdmChooserSession *chooser, + int signal, + GdmXdmcpChooserSlave *slave) +{ + g_debug ("GdmXdmcpChooserSlave: Chooser died: %d", signal); + gdm_slave_stopped (GDM_SLAVE (slave)); +} + +static void +on_chooser_hostname_selected (GdmChooserServer *chooser_server, + const char *name, + GdmXdmcpChooserSlave *slave) +{ + g_debug ("GdmXdmcpChooserSlave: emitting hostname selected: %s", name); + g_signal_emit (slave, signals [HOSTNAME_SELECTED], 0, name); +} + +static void +on_chooser_disconnected (GdmChooserServer *chooser_server, + GdmXdmcpChooserSlave *slave) +{ + g_debug ("GdmXdmcpChooserSlave: Chooser disconnected"); + + /* stop pinging */ + alarm (0); + + gdm_slave_stopped (GDM_SLAVE (slave)); +} + +static void +on_chooser_connected (GdmChooserServer *chooser_server, + GdmXdmcpChooserSlave *slave) +{ + g_debug ("GdmXdmcpChooserSlave: Chooser connected"); +} + +static void +setup_server (GdmXdmcpChooserSlave *slave) +{ + /* Set the busy cursor */ + gdm_slave_set_busy_cursor (GDM_SLAVE (slave)); +} + +static void +run_chooser (GdmXdmcpChooserSlave *slave) +{ + char *display_id; + char *display_name; + char *display_device; + char *display_hostname; + char *auth_file; + char *address; + + g_debug ("GdmXdmcpChooserSlave: Running chooser"); + + display_id = NULL; + display_name = NULL; + auth_file = NULL; + display_device = NULL; + display_hostname = NULL; + + g_object_get (slave, + "display-id", &display_id, + "display-name", &display_name, + "display-hostname", &display_hostname, + "display-x11-authority-file", &auth_file, + NULL); + + g_debug ("GdmXdmcpChooserSlave: Creating chooser for %s %s", display_name, display_hostname); + + /* FIXME: send a signal back to the master */ + + /* If XDMCP setup pinging */ + if (slave->priv->ping_interval > 0) { + alarm (slave->priv->ping_interval); + } + + /* Run the init script. gdmslave suspends until script has terminated */ + gdm_slave_run_script (GDM_SLAVE (slave), GDMCONFDIR "/Init", "gdm"); + + slave->priv->chooser_server = gdm_chooser_server_new (display_id); + g_signal_connect (slave->priv->chooser_server, + "hostname-selected", + G_CALLBACK (on_chooser_hostname_selected), + slave); + g_signal_connect (slave->priv->chooser_server, + "disconnected", + G_CALLBACK (on_chooser_disconnected), + slave); + g_signal_connect (slave->priv->chooser_server, + "connected", + G_CALLBACK (on_chooser_connected), + slave); + gdm_chooser_server_start (slave->priv->chooser_server); + + address = gdm_chooser_server_get_address (slave->priv->chooser_server); + + g_debug ("GdmXdmcpChooserSlave: Creating chooser on %s %s %s", display_name, display_device, display_hostname); + slave->priv->chooser = gdm_chooser_session_new (display_name, + display_device, + display_hostname); + g_signal_connect (slave->priv->chooser, + "started", + G_CALLBACK (on_chooser_session_start), + slave); + g_signal_connect (slave->priv->chooser, + "stopped", + G_CALLBACK (on_chooser_session_stop), + slave); + g_signal_connect (slave->priv->chooser, + "exited", + G_CALLBACK (on_chooser_session_exited), + slave); + g_signal_connect (slave->priv->chooser, + "died", + G_CALLBACK (on_chooser_session_died), + slave); + g_object_set (slave->priv->chooser, + "x11-authority-file", auth_file, + NULL); + gdm_chooser_session_set_server_address (slave->priv->chooser, address); + gdm_chooser_session_start (slave->priv->chooser); + + g_free (display_id); + g_free (display_name); + g_free (display_device); + g_free (display_hostname); + g_free (auth_file); +} + +static gboolean +idle_connect_to_display (GdmXdmcpChooserSlave *slave) +{ + gboolean res; + + slave->priv->connection_attempts++; + + res = gdm_slave_connect_to_x11_display (GDM_SLAVE (slave)); + if (res) { + /* FIXME: handle wait-for-go */ + + setup_server (slave); + run_chooser (slave); + } else { + if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) { + g_warning ("Unable to connect to display after %d tries - bailing out", slave->priv->connection_attempts); + exit (1); + } + } + + return FALSE; +} + +static gboolean +gdm_xdmcp_chooser_slave_run (GdmXdmcpChooserSlave *slave) +{ + char *display_name; + char *auth_file; + + g_object_get (slave, + "display-name", &display_name, + "display-x11-authority-file", &auth_file, + NULL); + + g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave); + + g_free (display_name); + g_free (auth_file); + + return TRUE; +} + +static gboolean +gdm_xdmcp_chooser_slave_start (GdmSlave *slave) +{ + gboolean res; + + res = GDM_SLAVE_CLASS (gdm_xdmcp_chooser_slave_parent_class)->start (slave); + + gdm_xdmcp_chooser_slave_run (GDM_XDMCP_CHOOSER_SLAVE (slave)); + + return TRUE; +} + +static gboolean +gdm_xdmcp_chooser_slave_stop (GdmSlave *slave) +{ + gboolean res; + + g_debug ("GdmXdmcpChooserSlave: Stopping xdmcp_chooser_slave"); + + res = GDM_SLAVE_CLASS (gdm_xdmcp_chooser_slave_parent_class)->stop (slave); + + if (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser != NULL) { + gdm_chooser_session_stop (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser); + g_object_unref (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser); + GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser = NULL; + } + + return TRUE; +} + +static void +gdm_xdmcp_chooser_slave_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdmXdmcpChooserSlave *self; + + self = GDM_XDMCP_CHOOSER_SLAVE (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gdm_xdmcp_chooser_slave_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdmXdmcpChooserSlave *self; + + self = GDM_XDMCP_CHOOSER_SLAVE (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +gdm_xdmcp_chooser_slave_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GdmXdmcpChooserSlave *xdmcp_chooser_slave; + GdmXdmcpChooserSlaveClass *klass; + + klass = GDM_XDMCP_CHOOSER_SLAVE_CLASS (g_type_class_peek (GDM_TYPE_XDMCP_CHOOSER_SLAVE)); + + xdmcp_chooser_slave = GDM_XDMCP_CHOOSER_SLAVE (G_OBJECT_CLASS (gdm_xdmcp_chooser_slave_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + + return G_OBJECT (xdmcp_chooser_slave); +} + +static void +gdm_xdmcp_chooser_slave_class_init (GdmXdmcpChooserSlaveClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdmSlaveClass *slave_class = GDM_SLAVE_CLASS (klass); + + object_class->get_property = gdm_xdmcp_chooser_slave_get_property; + object_class->set_property = gdm_xdmcp_chooser_slave_set_property; + object_class->constructor = gdm_xdmcp_chooser_slave_constructor; + object_class->finalize = gdm_xdmcp_chooser_slave_finalize; + + slave_class->start = gdm_xdmcp_chooser_slave_start; + slave_class->stop = gdm_xdmcp_chooser_slave_stop; + + signals [HOSTNAME_SELECTED] = + g_signal_new ("hostname-selected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmXdmcpChooserSlaveClass, hostname_selected), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + + g_type_class_add_private (klass, sizeof (GdmXdmcpChooserSlavePrivate)); + + dbus_g_object_type_install_info (GDM_TYPE_XDMCP_CHOOSER_SLAVE, &dbus_glib_gdm_xdmcp_chooser_slave_object_info); +} + +static void +gdm_xdmcp_chooser_slave_init (GdmXdmcpChooserSlave *slave) +{ + slave->priv = GDM_XDMCP_CHOOSER_SLAVE_GET_PRIVATE (slave); +} + +static void +gdm_xdmcp_chooser_slave_finalize (GObject *object) +{ + GdmXdmcpChooserSlave *xdmcp_chooser_slave; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_XDMCP_CHOOSER_SLAVE (object)); + + xdmcp_chooser_slave = GDM_XDMCP_CHOOSER_SLAVE (object); + + g_return_if_fail (xdmcp_chooser_slave->priv != NULL); + + gdm_xdmcp_chooser_slave_stop (GDM_SLAVE (xdmcp_chooser_slave)); + + G_OBJECT_CLASS (gdm_xdmcp_chooser_slave_parent_class)->finalize (object); +} + +GdmSlave * +gdm_xdmcp_chooser_slave_new (const char *id) +{ + GObject *object; + + object = g_object_new (GDM_TYPE_XDMCP_CHOOSER_SLAVE, + "display-id", id, + NULL); + + return GDM_SLAVE (object); +} diff --git a/daemon/gdm-xdmcp-chooser-slave.h b/daemon/gdm-xdmcp-chooser-slave.h new file mode 100644 index 00000000..61cdd137 --- /dev/null +++ b/daemon/gdm-xdmcp-chooser-slave.h @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __GDM_XDMCP_CHOOSER_SLAVE_H +#define __GDM_XDMCP_CHOOSER_SLAVE_H + +#include <glib-object.h> +#include "gdm-slave.h" + +G_BEGIN_DECLS + +#define GDM_TYPE_XDMCP_CHOOSER_SLAVE (gdm_xdmcp_chooser_slave_get_type ()) +#define GDM_XDMCP_CHOOSER_SLAVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlave)) +#define GDM_XDMCP_CHOOSER_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlaveClass)) +#define GDM_IS_XDMCP_CHOOSER_SLAVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE)) +#define GDM_IS_XDMCP_CHOOSER_SLAVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_XDMCP_CHOOSER_SLAVE)) +#define GDM_XDMCP_CHOOSER_SLAVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlaveClass)) + +typedef struct GdmXdmcpChooserSlavePrivate GdmXdmcpChooserSlavePrivate; + +typedef struct +{ + GdmSlave parent; + GdmXdmcpChooserSlavePrivate *priv; +} GdmXdmcpChooserSlave; + +typedef struct +{ + GdmSlaveClass parent_class; + + void (* hostname_selected) (GdmXdmcpChooserSlave *slave, + const char *hostname); +} GdmXdmcpChooserSlaveClass; + +GType gdm_xdmcp_chooser_slave_get_type (void); +GdmSlave * gdm_xdmcp_chooser_slave_new (const char *id); + +G_END_DECLS + +#endif /* __GDM_XDMCP_CHOOSER_SLAVE_H */ diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c index 4f6fe1f4..33ce282a 100644 --- a/daemon/gdm-xdmcp-display-factory.c +++ b/daemon/gdm-xdmcp-display-factory.c @@ -52,7 +52,8 @@ #include <X11/Xdmcp.h> #include "gdm-common.h" -#include "gdm-xdmcp-display.h" +#include "gdm-xdmcp-greeter-display.h" +#include "gdm-xdmcp-chooser-display.h" #include "gdm-display-factory.h" #include "gdm-xdmcp-display-factory.h" #include "gdm-display-store.h" @@ -136,17 +137,24 @@ static XdmAuthRec serv_authlist = { }; /* NOTE: Timeout and max are hardcoded */ -typedef struct _GdmForwardQuery { +typedef struct _ForwardQuery { time_t acctime; GdmAddress *dsp_address; GdmAddress *from_address; -} GdmForwardQuery; +} ForwardQuery; + +typedef struct _IndirectClient { + int id; + GdmAddress *dsp_address; + GdmAddress *chosen_address; + time_t acctime; +} IndirectClient; typedef struct { - int times; - guint handler; - GdmAddress *manager; - GdmAddress *origin; + int times; + guint handler; + GdmAddress *manager; + GdmAddress *origin; GdmXdmcpDisplayFactory *xdmcp_display_factory; } ManagedForward; @@ -154,6 +162,7 @@ struct GdmXdmcpDisplayFactoryPrivate { GSList *forward_queries; GSList *managed_forwards; + GSList *indirect_clients; int socket_fd; gint32 session_serial; @@ -873,8 +882,6 @@ gdm_xdmcp_send_unwilling (GdmXdmcpDisplayFactory *factory, #define SIN(__s) ((struct sockaddr_in *) __s) #define SIN6(__s) ((struct sockaddr_in6 *) __s) -#if 0 -/* FIXME: Add chooser support */ static void set_port_for_request (GdmAddress *address, ARRAY8 *port) @@ -898,7 +905,6 @@ set_port_for_request (GdmAddress *address, break; } } -#endif static void set_address_for_request (GdmAddress *address, @@ -925,11 +931,9 @@ set_address_for_request (GdmAddress *address, } -#if 0 -/* FIXME: Add chooser support */ static void gdm_xdmcp_send_forward_query (GdmXdmcpDisplayFactory *factory, - GdmIndirectDisplay *id, + IndirectClient *ic, GdmAddress *address, GdmAddress *display_address, ARRAYofARRAY8Ptr authlist) @@ -941,11 +945,11 @@ gdm_xdmcp_send_forward_query (GdmXdmcpDisplayFactory *factory, char *host; char *serv; - g_assert (id != NULL); - g_assert (id->chosen_host != NULL); + g_assert (ic != NULL); + g_assert (ic->chosen_address != NULL); host = NULL; - gdm_address_get_numeric_info (id->chosen_host, &host, NULL); + gdm_address_get_numeric_info (ic->chosen_address, &host, NULL); g_debug ("GdmXdmcpDisplayFactory: Sending forward query to %s", host); g_free (host); @@ -978,13 +982,12 @@ gdm_xdmcp_send_forward_query (GdmXdmcpDisplayFactory *factory, XdmcpFlush (factory->priv->socket_fd, &factory->priv->buf, - (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (id->chosen_host), + (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (ic->chosen_address), (int)sizeof (struct sockaddr_storage)); g_free (port.data); g_free (addr.data); } -#endif static void handle_any_query (GdmXdmcpDisplayFactory *factory, @@ -1051,15 +1054,167 @@ gdm_xdmcp_handle_query (GdmXdmcpDisplayFactory *factory, } } +static IndirectClient * +indirect_client_create (GdmXdmcpDisplayFactory *factory, + GdmAddress *dsp_address) +{ + IndirectClient *ic; + int count; + + count = g_slist_length (factory->priv->indirect_clients); + + ic = g_new0 (IndirectClient, 1); + ic->dsp_address = gdm_address_copy (dsp_address); + + factory->priv->indirect_clients = g_slist_prepend (factory->priv->indirect_clients, ic); + + return ic; +} + +static void +indirect_client_destroy (GdmXdmcpDisplayFactory *factory, + IndirectClient *ic) +{ + if (ic == NULL) { + return; + } + + factory->priv->indirect_clients = g_slist_remove (factory->priv->indirect_clients, ic); + + ic->acctime = 0; + + { + char *host; + + host = NULL; + gdm_address_get_numeric_info (ic->dsp_address, &host, NULL); + g_debug ("GdmXdmcpDisplayFactory: Disposing IndirectClient for %s", host); + g_free (host); + } + + g_free (ic->dsp_address); + ic->dsp_address = NULL; + g_free (ic->chosen_address); + ic->chosen_address = NULL; + + g_free (ic); +} + +static IndirectClient * +indirect_client_lookup_by_chosen (GdmXdmcpDisplayFactory *factory, + GdmAddress *chosen_address, + GdmAddress *origin_address) +{ + GSList *li; + char *host; + IndirectClient *ret; + + g_assert (chosen_address != NULL); + g_assert (origin_address != NULL); + + ret = NULL; + + for (li = factory->priv->indirect_clients; li != NULL; li = li->next) { + IndirectClient *ic = li->data; + + if (ic != NULL + && ic->chosen_address != NULL + && gdm_address_equal (ic->chosen_address, chosen_address)) { + if (gdm_address_equal (ic->dsp_address, origin_address)) { + ret = ic; + goto out; + } else if (gdm_address_is_loopback (ic->dsp_address) + && gdm_address_is_local (origin_address)) { + ret = ic; + goto out; + } + } + } + + gdm_address_get_numeric_info (chosen_address, &host, NULL); + + g_debug ("GdmXdmcpDisplayFactory: Chosen %s host not found", host); + g_free (host); + out: + return ret; +} + +/* lookup by origin */ +static IndirectClient * +indirect_client_lookup (GdmXdmcpDisplayFactory *factory, + GdmAddress *address) +{ + GSList *li; + GSList *qlist; + IndirectClient *ret; + time_t curtime; + + g_assert (address != NULL); + + curtime = time (NULL); + ret = NULL; + + qlist = g_slist_copy (factory->priv->indirect_clients); + + for (li = qlist; li != NULL; li = li->next) { + IndirectClient *ic; + char *host; + char *serv; + + ic = (IndirectClient *) li->data; + + if (ic == NULL) { + continue; + } + + host = NULL; + serv = NULL; + gdm_address_get_numeric_info (ic->dsp_address, &host, &serv); + + g_debug ("GdmXdmcpDisplayFactory: comparing %s:%s", host, serv); + if (gdm_address_equal (ic->dsp_address, address)) { + ret = ic; + g_free (host); + g_free (serv); + break; + } + + if (ic->acctime > 0 && curtime > ic->acctime + factory->priv->max_wait) { + g_debug ("GdmXdmcpDisplayFactory: Disposing stale forward query from %s:%s", + host, serv); + + indirect_client_destroy (factory, ic); + } + + g_free (host); + g_free (serv); + } + + g_slist_free (qlist); + + if (ret == NULL) { + char *host; + + host = NULL; + gdm_address_get_numeric_info (address, &host, NULL); + g_debug ("GdmXdmcpDisplayFactory: Host %s not found", + host); + g_free (host); + } + + return ret; +} + static void gdm_xdmcp_handle_indirect_query (GdmXdmcpDisplayFactory *factory, GdmAddress *address, int len) { - ARRAYofARRAY8 clnt_authlist; - int expected_len; - int i; - int res; + ARRAYofARRAY8 clnt_authlist; + int expected_len; + int i; + int res; + IndirectClient *ic; if (! gdm_xdmcp_host_allow (address)) { /* ignore the request */ @@ -1071,6 +1226,13 @@ gdm_xdmcp_handle_indirect_query (GdmXdmcpDisplayFactory *factory, return; } + if (factory->priv->num_sessions > factory->priv->max_displays || + (!gdm_address_is_local (address) && + gdm_xdmcp_num_displays_from_host (factory, address) > factory->priv->max_displays_per_host)) { + g_debug ("GdmXdmcpDisplayFactory: reached maximum number of clients - ignoring indirect query"); + return; + } + res = XdmcpReadARRAYofARRAY8 (&factory->priv->buf, &clnt_authlist); if G_UNLIKELY (! res) { g_warning (_("Could not extract authlist from packet")); @@ -1085,7 +1247,7 @@ gdm_xdmcp_handle_indirect_query (GdmXdmcpDisplayFactory *factory, /* Try to look up the display in * the pending list. If found send a FORWARD_QUERY to the - * chosen factory. Otherwise alloc a new indirect display. */ + * chosen manager. Otherwise alloc a new indirect display. */ if (len != expected_len) { g_warning (_("Error in checksum")); @@ -1093,18 +1255,16 @@ gdm_xdmcp_handle_indirect_query (GdmXdmcpDisplayFactory *factory, } -#if 0 - GdmIndirectDisplay *id; - /* FIXME: Add chooser support */ + ic = indirect_client_lookup (factory, address); - id = gdm_choose_indirect_lookup (address); - - if (id != NULL && id->chosen_host != NULL) { + if (ic != NULL && ic->chosen_address != NULL) { /* if user chose us, then just send willing */ - if (gdm_address_is_local (id->chosen_host)) { + if (gdm_address_is_local (ic->chosen_address)) { + g_debug ("GdmXdmcpDisplayFactory: the chosen address is local - dropping indirect"); + /* get rid of indirect, so that we don't get * the chooser */ - gdm_choose_indirect_dispose (id); + indirect_client_destroy (factory, ic); gdm_xdmcp_send_willing (factory, address); } else if (gdm_address_is_loopback (address)) { /* woohoo! fun, I have no clue how to get @@ -1112,13 +1272,15 @@ gdm_xdmcp_handle_indirect_query (GdmXdmcpDisplayFactory *factory, * queries with all the different IPs */ const GList *list = gdm_address_peek_local_list (); + g_debug ("GdmXdmcpDisplayFactory: the chosen address is a loopback"); + while (list != NULL) { GdmAddress *saddr = list->data; if (! gdm_address_is_loopback (saddr)) { /* forward query to * chosen host */ gdm_xdmcp_send_forward_query (factory, - id, + ic, address, saddr, &clnt_authlist); @@ -1129,28 +1291,27 @@ gdm_xdmcp_handle_indirect_query (GdmXdmcpDisplayFactory *factory, } else { /* or send forward query to chosen host */ gdm_xdmcp_send_forward_query (factory, - id, + ic, address, address, &clnt_authlist); } - } else if (id == NULL) { - id = gdm_choose_indirect_alloc (address); - if (id != NULL) { + } else if (ic == NULL) { + ic = indirect_client_create (factory, address); + if (ic != NULL) { gdm_xdmcp_send_willing (factory, address); } } else { gdm_xdmcp_send_willing (factory, address); } -#endif out: XdmcpDisposeARRAYofARRAY8 (&clnt_authlist); } static void -gdm_forward_query_dispose (GdmXdmcpDisplayFactory *factory, - GdmForwardQuery *q) +forward_query_destroy (GdmXdmcpDisplayFactory *factory, + ForwardQuery *q) { if (q == NULL) { return; @@ -1180,11 +1341,11 @@ gdm_forward_query_dispose (GdmXdmcpDisplayFactory *factory, static gboolean remove_oldest_forward (GdmXdmcpDisplayFactory *factory) { - GSList *li; - GdmForwardQuery *oldest = NULL; + GSList *li; + ForwardQuery *oldest = NULL; for (li = factory->priv->forward_queries; li != NULL; li = li->next) { - GdmForwardQuery *query = li->data; + ForwardQuery *query = li->data; if (oldest == NULL || query->acctime < oldest->acctime) { oldest = query; @@ -1192,20 +1353,20 @@ remove_oldest_forward (GdmXdmcpDisplayFactory *factory) } if (oldest != NULL) { - gdm_forward_query_dispose (factory, oldest); + forward_query_destroy (factory, oldest); return TRUE; } else { return FALSE; } } -static GdmForwardQuery * -gdm_forward_query_alloc (GdmXdmcpDisplayFactory *factory, +static ForwardQuery * +forward_query_create (GdmXdmcpDisplayFactory *factory, GdmAddress *mgr_address, GdmAddress *dsp_address) { - GdmForwardQuery *q; - int count; + ForwardQuery *q; + int count; count = g_slist_length (factory->priv->forward_queries); @@ -1213,7 +1374,7 @@ gdm_forward_query_alloc (GdmXdmcpDisplayFactory *factory, count--; } - q = g_new0 (GdmForwardQuery, 1); + q = g_new0 (ForwardQuery, 1); q->dsp_address = gdm_address_copy (dsp_address); q->from_address = gdm_address_copy (mgr_address); @@ -1222,14 +1383,14 @@ gdm_forward_query_alloc (GdmXdmcpDisplayFactory *factory, return q; } -static GdmForwardQuery * -gdm_forward_query_lookup (GdmXdmcpDisplayFactory *factory, +static ForwardQuery * +forward_query_lookup (GdmXdmcpDisplayFactory *factory, GdmAddress *address) { - GSList *li; - GSList *qlist; - GdmForwardQuery *ret; - time_t curtime; + GSList *li; + GSList *qlist; + ForwardQuery *ret; + time_t curtime; curtime = time (NULL); ret = NULL; @@ -1237,11 +1398,11 @@ gdm_forward_query_lookup (GdmXdmcpDisplayFactory *factory, qlist = g_slist_copy (factory->priv->forward_queries); for (li = qlist; li != NULL; li = li->next) { - GdmForwardQuery *q; - char *host; - char *serv; + ForwardQuery *q; + char *host; + char *serv; - q = (GdmForwardQuery *) li->data; + q = (ForwardQuery *) li->data; if (q == NULL) { continue; @@ -1263,7 +1424,7 @@ gdm_forward_query_lookup (GdmXdmcpDisplayFactory *factory, g_debug ("GdmXdmcpDisplayFactory: Disposing stale forward query from %s:%s", host, serv); - gdm_forward_query_dispose (factory, q); + forward_query_destroy (factory, q); } g_free (host); @@ -1482,14 +1643,14 @@ gdm_xdmcp_handle_forward_query (GdmXdmcpDisplayFactory *factory, /* Check with tcp_wrappers if display is allowed to access */ if (gdm_xdmcp_host_allow (disp_address)) { - GdmForwardQuery *q; + ForwardQuery *q; - q = gdm_forward_query_lookup (factory, disp_address); + q = forward_query_lookup (factory, disp_address); if (q != NULL) { - gdm_forward_query_dispose (factory, q); + forward_query_destroy (factory, q); } - gdm_forward_query_alloc (factory, address, disp_address); + forward_query_create (factory, address, disp_address); gdm_xdmcp_send_willing (factory, disp_address); } @@ -1751,7 +1912,7 @@ gdm_xdmcp_send_decline (GdmXdmcpDisplayFactory *factory, ARRAY8 authentype; ARRAY8 authendata; ARRAY8 status; - GdmForwardQuery *fq; + ForwardQuery *fq; char *host; host = NULL; @@ -1786,28 +1947,100 @@ gdm_xdmcp_send_decline (GdmXdmcpDisplayFactory *factory, /* Send MANAGED_FORWARD to indicate that the connection * reached some sort of resolution */ - fq = gdm_forward_query_lookup (factory, address); + fq = forward_query_lookup (factory, address); if (fq != NULL) { gdm_xdmcp_send_managed_forward (factory, fq->from_address, address); - gdm_forward_query_dispose (factory, fq); + forward_query_destroy (factory, fq); } } +static void +on_hostname_selected (GdmXdmcpChooserDisplay *display, + const char *hostname, + GdmXdmcpDisplayFactory *factory) +{ + struct addrinfo hints; + struct addrinfo *ai_list; + struct addrinfo *ai; + int gaierr; + GdmAddress *address; + IndirectClient *ic; + + g_debug ("GdmXdmcpDisplayFactory: hostname selected: %s", hostname); + + address = gdm_xdmcp_display_get_remote_address (GDM_XDMCP_DISPLAY (display)); + + g_assert (address != NULL); + + ic = indirect_client_lookup (factory, address); + + if (ic->chosen_address != NULL) { + gdm_address_free (ic->chosen_address); + ic->chosen_address = NULL; + } + + memset (&hints, 0, sizeof (hints)); + hints.ai_family = gdm_address_get_family_type (address); + hints.ai_flags = AI_V4MAPPED; /* this should convert IPv4 address to IPv6 if needed */ + if ((gaierr = getaddrinfo (hostname, NULL, &hints, &ai_list)) != 0) { + g_warning ("Unable get address: %s", gai_strerror (gaierr)); + return; + } + + /* just take the first one */ + ai = ai_list; + + if (ai != NULL) { + char *ip; + ic->chosen_address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen); + + ip = NULL; + gdm_address_get_numeric_info (ic->chosen_address, &ip, NULL); + g_debug ("GdmXdmcpDisplayFactory: hostname resolves to %s", ip); + g_free (ip); + } + + freeaddrinfo (ai_list); +} + static GdmDisplay * -gdm_xdmcp_display_alloc (GdmXdmcpDisplayFactory *factory, - const char *hostname, - GdmAddress *address, - int displaynum) +gdm_xdmcp_display_create (GdmXdmcpDisplayFactory *factory, + const char *hostname, + GdmAddress *address, + int displaynum) { GdmDisplay *display; GdmDisplayStore *store; + gboolean use_chooser; g_debug ("GdmXdmcpDisplayFactory: Creating xdmcp display for %s:%d", hostname, displaynum); - display = gdm_xdmcp_display_new (hostname, - displaynum, - address, - get_next_session_serial (factory)); + use_chooser = FALSE; + if (factory->priv->honor_indirect) { + IndirectClient *ic; + + ic = indirect_client_lookup (factory, address); + + /* This was an indirect thingie and nothing was yet chosen, + * use a chooser */ + if (ic != NULL && ic->chosen_address == NULL) { + use_chooser = TRUE; + } + } + + if (use_chooser) { + display = gdm_xdmcp_chooser_display_new (hostname, + displaynum, + address, + get_next_session_serial (factory)); + g_signal_connect (display, "hostname-selected", G_CALLBACK (on_hostname_selected), factory); + } else { + display = gdm_xdmcp_greeter_display_new (hostname, + displaynum, + address, + get_next_session_serial (factory)); + } + if (display == NULL) { goto out; } @@ -2036,10 +2269,10 @@ gdm_xdmcp_handle_request (GdmXdmcpDisplayFactory *factory, } else { GdmDisplay *display; - display = gdm_xdmcp_display_alloc (factory, - hostname, - address, - clnt_dspnum); + display = gdm_xdmcp_display_create (factory, + hostname, + address, + clnt_dspnum); if (display != NULL) { ARRAY8 authentication_name; @@ -2196,8 +2429,8 @@ gdm_xdmcp_send_refuse (GdmXdmcpDisplayFactory *factory, GdmAddress *address, CARD32 sessid) { - XdmcpHeader header; - GdmForwardQuery *fq; + XdmcpHeader header; + ForwardQuery *fq; g_debug ("GdmXdmcpDisplayFactory: Sending REFUSE to %ld", (long)sessid); @@ -2218,10 +2451,10 @@ gdm_xdmcp_send_refuse (GdmXdmcpDisplayFactory *factory, * This was from a forwarded query quite apparently so * send MANAGED_FORWARD */ - fq = gdm_forward_query_lookup (factory, address); + fq = forward_query_lookup (factory, address); if (fq != NULL) { gdm_xdmcp_send_managed_forward (factory, fq->from_address, address); - gdm_forward_query_dispose (factory, fq); + forward_query_destroy (factory, fq); } } @@ -2234,7 +2467,7 @@ gdm_xdmcp_handle_manage (GdmXdmcpDisplayFactory *factory, CARD16 clnt_dspnum; ARRAY8 clnt_dspclass; GdmDisplay *display; - GdmForwardQuery *fq; + ForwardQuery *fq; char *host; host = NULL; @@ -2292,36 +2525,34 @@ gdm_xdmcp_handle_manage (GdmXdmcpDisplayFactory *factory, g_debug ("GdmXdmcpDisplayFactory: Looked up %s", name); g_free (name); -#if 0 - /* FIXME: Add chooser support */ if (factory->priv->honor_indirect) { - GdmIndirectDisplay *id; + IndirectClient *ic; - id = gdm_choose_indirect_lookup (address); + ic = indirect_client_lookup (factory, address); /* This was an indirect thingie and nothing was yet chosen, * use a chooser */ - if (id != NULL && - id->chosen_host == NULL) { - d->use_chooser = TRUE; - d->indirect_id = id->id; + if (ic != NULL && ic->chosen_address == NULL) { + g_debug ("GdmXdmcpDisplayFactory: use chooser"); + /*d->use_chooser = TRUE; + d->indirect_id = ic->id;*/ } else { - d->indirect_id = 0; - d->use_chooser = FALSE; - if (id != NULL) { - gdm_choose_indirect_dispose (id); + /*d->indirect_id = 0; + d->use_chooser = FALSE;*/ + if (ic != NULL) { + indirect_client_destroy (factory, ic); } } } else { } -#endif + /* this was from a forwarded query quite apparently so * send MANAGED_FORWARD */ - fq = gdm_forward_query_lookup (factory, address); + fq = forward_query_lookup (factory, address); if (fq != NULL) { gdm_xdmcp_send_managed_forward (factory, fq->from_address, address); - gdm_forward_query_dispose (factory, fq); + forward_query_destroy (factory, fq); } factory->priv->num_sessions++; @@ -2355,6 +2586,7 @@ gdm_xdmcp_handle_managed_forward (GdmXdmcpDisplayFactory *factory, ARRAY8 clnt_address; char *host; GdmAddress *disp_address; + IndirectClient *ic; host = NULL; gdm_address_get_numeric_info (address, &host, NULL); @@ -2384,14 +2616,10 @@ gdm_xdmcp_handle_managed_forward (GdmXdmcpDisplayFactory *factory, return; } -#if 0 - GdmIndirectDisplay *id; - /* FIXME: Add chooser support */ - id = gdm_choose_indirect_lookup_by_chosen (address, disp_address); - if (id != NULL) { - gdm_choose_indirect_dispose (id); + ic = indirect_client_lookup_by_chosen (factory, address, disp_address); + if (ic != NULL) { + indirect_client_destroy (factory, ic); } -#endif /* Note: we send GOT even on not found, just in case our previous * didn't get through and this was a second managed forward */ diff --git a/daemon/gdm-xdmcp-display.c b/daemon/gdm-xdmcp-display.c index c6c44ace..2e40305f 100644 --- a/daemon/gdm-xdmcp-display.c +++ b/daemon/gdm-xdmcp-display.c @@ -37,7 +37,6 @@ #include "gdm-display.h" #include "gdm-xdmcp-display.h" -#include "gdm-xdmcp-display-glue.h" #include "gdm-common.h" #include "gdm-address.h" @@ -60,7 +59,7 @@ static void gdm_xdmcp_display_class_init (GdmXdmcpDisplayClass *klass); static void gdm_xdmcp_display_init (GdmXdmcpDisplay *xdmcp_display); static void gdm_xdmcp_display_finalize (GObject *object); -G_DEFINE_TYPE (GdmXdmcpDisplay, gdm_xdmcp_display, GDM_TYPE_DISPLAY) +G_DEFINE_ABSTRACT_TYPE (GdmXdmcpDisplay, gdm_xdmcp_display, GDM_TYPE_DISPLAY) gint32 gdm_xdmcp_display_get_session_number (GdmXdmcpDisplay *display) @@ -218,7 +217,6 @@ gdm_xdmcp_display_class_init (GdmXdmcpDisplayClass *klass) 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - dbus_g_object_type_install_info (GDM_TYPE_XDMCP_DISPLAY, &dbus_glib_gdm_xdmcp_display_object_info); } static void @@ -242,26 +240,3 @@ gdm_xdmcp_display_finalize (GObject *object) G_OBJECT_CLASS (gdm_xdmcp_display_parent_class)->finalize (object); } - -GdmDisplay * -gdm_xdmcp_display_new (const char *hostname, - int number, - GdmAddress *address, - gint32 session_number) -{ - GObject *object; - char *x11_display; - - x11_display = g_strdup_printf ("%s:%d", hostname, number); - object = g_object_new (GDM_TYPE_XDMCP_DISPLAY, - "remote-hostname", hostname, - "x11-display-number", number, - "x11-display-name", x11_display, - "is-local", FALSE, - "remote-address", address, - "session-number", session_number, - NULL); - g_free (x11_display); - - return GDM_DISPLAY (object); -} diff --git a/daemon/gdm-xdmcp-display.h b/daemon/gdm-xdmcp-display.h index 1748bc96..db9b4014 100644 --- a/daemon/gdm-xdmcp-display.h +++ b/daemon/gdm-xdmcp-display.h @@ -55,12 +55,6 @@ typedef struct GType gdm_xdmcp_display_get_type (void); - -GdmDisplay * gdm_xdmcp_display_new (const char *hostname, - int number, - GdmAddress *addr, - gint32 serial_number); - gint32 gdm_xdmcp_display_get_session_number (GdmXdmcpDisplay *display); GdmAddress * gdm_xdmcp_display_get_remote_address (GdmXdmcpDisplay *display); diff --git a/daemon/gdm-xdmcp-greeter-display.c b/daemon/gdm-xdmcp-greeter-display.c new file mode 100644 index 00000000..2273f4b3 --- /dev/null +++ b/daemon/gdm-xdmcp-greeter-display.c @@ -0,0 +1,120 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> + +#include "gdm-xdmcp-display.h" +#include "gdm-xdmcp-greeter-display.h" +#include "gdm-xdmcp-greeter-display-glue.h" + +#include "gdm-common.h" +#include "gdm-address.h" + +#define GDM_XDMCP_GREETER_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_GREETER_DISPLAY, GdmXdmcpGreeterDisplayPrivate)) + +struct GdmXdmcpGreeterDisplayPrivate +{ + GdmAddress *remote_address; + gint32 session_number; +}; + +enum { + PROP_0, + PROP_REMOTE_ADDRESS, + PROP_SESSION_NUMBER, +}; + +static void gdm_xdmcp_greeter_display_class_init (GdmXdmcpGreeterDisplayClass *klass); +static void gdm_xdmcp_greeter_display_init (GdmXdmcpGreeterDisplay *xdmcp_greeter_display); +static void gdm_xdmcp_greeter_display_finalize (GObject *object); + +G_DEFINE_TYPE (GdmXdmcpGreeterDisplay, gdm_xdmcp_greeter_display, GDM_TYPE_XDMCP_DISPLAY) + +static void +gdm_xdmcp_greeter_display_class_init (GdmXdmcpGreeterDisplayClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gdm_xdmcp_greeter_display_finalize; + + g_type_class_add_private (klass, sizeof (GdmXdmcpGreeterDisplayPrivate)); + + dbus_g_object_type_install_info (GDM_TYPE_XDMCP_GREETER_DISPLAY, &dbus_glib_gdm_xdmcp_greeter_display_object_info); +} + +static void +gdm_xdmcp_greeter_display_init (GdmXdmcpGreeterDisplay *xdmcp_greeter_display) +{ + + xdmcp_greeter_display->priv = GDM_XDMCP_GREETER_DISPLAY_GET_PRIVATE (xdmcp_greeter_display); +} + +static void +gdm_xdmcp_greeter_display_finalize (GObject *object) +{ + GdmXdmcpGreeterDisplay *xdmcp_greeter_display; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_XDMCP_GREETER_DISPLAY (object)); + + xdmcp_greeter_display = GDM_XDMCP_GREETER_DISPLAY (object); + + g_return_if_fail (xdmcp_greeter_display->priv != NULL); + + G_OBJECT_CLASS (gdm_xdmcp_greeter_display_parent_class)->finalize (object); +} + +GdmDisplay * +gdm_xdmcp_greeter_display_new (const char *hostname, + int number, + GdmAddress *address, + gint32 session_number) +{ + GObject *object; + char *x11_display; + + x11_display = g_strdup_printf ("%s:%d", hostname, number); + object = g_object_new (GDM_TYPE_XDMCP_GREETER_DISPLAY, + "remote-hostname", hostname, + "x11-display-number", number, + "x11-display-name", x11_display, + "is-local", FALSE, + "remote-address", address, + "session-number", session_number, + NULL); + g_free (x11_display); + + return GDM_DISPLAY (object); +} diff --git a/daemon/gdm-xdmcp-greeter-display.h b/daemon/gdm-xdmcp-greeter-display.h new file mode 100644 index 00000000..c4c82a50 --- /dev/null +++ b/daemon/gdm-xdmcp-greeter-display.h @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __GDM_XDMCP_GREETER_DISPLAY_H +#define __GDM_XDMCP_GREETER_DISPLAY_H + +#include <sys/types.h> +#include <sys/socket.h> +#include <glib-object.h> +#include <dbus/dbus-glib.h> + +#include "gdm-xdmcp-display.h" +#include "gdm-address.h" + +G_BEGIN_DECLS + +#define GDM_TYPE_XDMCP_GREETER_DISPLAY (gdm_xdmcp_greeter_display_get_type ()) +#define GDM_XDMCP_GREETER_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_XDMCP_GREETER_DISPLAY, GdmXdmcpGreeterDisplay)) +#define GDM_XDMCP_GREETER_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_XDMCP_GREETER_DISPLAY, GdmXdmcpGreeterDisplayClass)) +#define GDM_IS_XDMCP_GREETER_DISPLAY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_XDMCP_GREETER_DISPLAY)) +#define GDM_IS_XDMCP_GREETER_DISPLAY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_XDMCP_GREETER_DISPLAY)) +#define GDM_XDMCP_GREETER_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_XDMCP_GREETER_DISPLAY, GdmXdmcpGreeterDisplayClass)) + +typedef struct GdmXdmcpGreeterDisplayPrivate GdmXdmcpGreeterDisplayPrivate; + +typedef struct +{ + GdmXdmcpDisplay parent; + GdmXdmcpGreeterDisplayPrivate *priv; +} GdmXdmcpGreeterDisplay; + +typedef struct +{ + GdmXdmcpDisplayClass parent_class; + +} GdmXdmcpGreeterDisplayClass; + +GType gdm_xdmcp_greeter_display_get_type (void); + + +GdmDisplay * gdm_xdmcp_greeter_display_new (const char *hostname, + int number, + GdmAddress *addr, + gint32 serial_number); + +G_END_DECLS + +#endif /* __GDM_XDMCP_GREETER_DISPLAY_H */ diff --git a/daemon/gdm-xdmcp-display.xml b/daemon/gdm-xdmcp-greeter-display.xml index 512019ce..512019ce 100644 --- a/daemon/gdm-xdmcp-display.xml +++ b/daemon/gdm-xdmcp-greeter-display.xml diff --git a/daemon/xdmcp-chooser-slave-main.c b/daemon/xdmcp-chooser-slave-main.c new file mode 100644 index 00000000..2f7996d1 --- /dev/null +++ b/daemon/xdmcp-chooser-slave-main.c @@ -0,0 +1,229 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <signal.h> +#include <locale.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> + +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "gdm-signal-handler.h" +#include "gdm-log.h" +#include "gdm-common.h" +#include "gdm-xdmcp-chooser-slave.h" + +static int gdm_return_code = 0; + +static DBusGConnection * +get_system_bus (void) +{ + GError *error; + DBusGConnection *bus; + DBusConnection *connection; + + error = NULL; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_warning ("Couldn't connect to system bus: %s", + error->message); + g_error_free (error); + goto out; + } + + connection = dbus_g_connection_get_connection (bus); + dbus_connection_set_exit_on_disconnect (connection, FALSE); + + out: + return bus; +} + +static gboolean +signal_cb (int signo, + gpointer data) +{ + int ret; + + g_debug ("Got callback for signal %d", signo); + + ret = TRUE; + + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGILL: + case SIGABRT: + g_debug ("Caught signal %d.", signo); + + ret = FALSE; + break; + + case SIGFPE: + case SIGPIPE: + /* let the fatal signals interrupt us */ + g_debug ("Caught signal %d, shutting down abnormally.", signo); + ret = FALSE; + + break; + + case SIGINT: + case SIGTERM: + /* let the fatal signals interrupt us */ + g_debug ("Caught signal %d, shutting down normally.", signo); + ret = FALSE; + + break; + + case SIGHUP: + g_debug ("Got HUP signal"); + /* FIXME: + * Reread config stuff like system config files, VPN service files, etc + */ + ret = TRUE; + + break; + + case SIGUSR1: + g_debug ("Got USR1 signal"); + /* FIXME: + * Play with log levels or something + */ + ret = TRUE; + + break; + + default: + g_debug ("Caught unhandled signal %d", signo); + ret = TRUE; + + break; + } + + return ret; +} + +static void +on_slave_stopped (GdmSlave *slave, + GMainLoop *main_loop) +{ + g_debug ("slave finished"); + gdm_return_code = 0; + g_main_loop_quit (main_loop); +} + +int +main (int argc, + char **argv) +{ + GMainLoop *main_loop; + GOptionContext *context; + DBusGConnection *connection; + GdmSlave *slave; + static char *display_id = NULL; + GdmSignalHandler *signal_handler; + static GOptionEntry entries [] = { + { "display-id", 0, 0, G_OPTION_ARG_STRING, &display_id, N_("Display ID"), N_("id") }, + { NULL } + }; + + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + textdomain (GETTEXT_PACKAGE); + setlocale (LC_ALL, ""); + + gdm_set_fatal_warnings_if_unstable (); + + g_type_init (); + + context = g_option_context_new (_("GNOME Display Manager Slave")); + g_option_context_add_main_entries (context, entries, NULL); + + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free (context); + + connection = get_system_bus (); + if (connection == NULL) { + goto out; + } + + gdm_log_init (); + + gdm_log_set_debug (TRUE); + + if (display_id == NULL) { + g_critical ("No display ID set"); + exit (1); + } + + main_loop = g_main_loop_new (NULL, FALSE); + + signal_handler = gdm_signal_handler_new (); + gdm_signal_handler_set_main_loop (signal_handler, main_loop); + gdm_signal_handler_add (signal_handler, SIGTERM, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGINT, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGILL, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGBUS, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGFPE, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGHUP, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGSEGV, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGABRT, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGUSR1, signal_cb, NULL); + + slave = gdm_xdmcp_chooser_slave_new (display_id); + if (slave == NULL) { + goto out; + } + g_signal_connect (slave, + "stopped", + G_CALLBACK (on_slave_stopped), + main_loop); + gdm_slave_start (slave); + + g_main_loop_run (main_loop); + + if (slave != NULL) { + g_object_unref (slave); + } + + if (signal_handler != NULL) { + g_object_unref (signal_handler); + } + + g_main_loop_unref (main_loop); + + out: + + g_debug ("Slave finished"); + + return gdm_return_code; +} diff --git a/data/gdm.conf b/data/gdm.conf index 343ed88f..bdcdd6da 100644 --- a/data/gdm.conf +++ b/data/gdm.conf @@ -27,6 +27,8 @@ send_member="AddUserAuthoritization"/> <deny send_interface="org.gnome.DisplayManager.Display" send_member="RemoveUserAuthoritization"/> + <deny send_interface="org.gnome.DisplayManager.Display" + send_member="SetSlaveBusName"/> <deny send_interface="org.gnome.DisplayManager.Settings" send_member="SetValue"/> </policy> diff --git a/gui/simple-chooser/Makefile.am b/gui/simple-chooser/Makefile.am index 32543b07..8fabe53f 100644 --- a/gui/simple-chooser/Makefile.am +++ b/gui/simple-chooser/Makefile.am @@ -11,6 +11,10 @@ INCLUDES = \ -DLIBEXECDIR=\""$(libexecdir)"\" \ -DSBINDIR=\""$(sbindir)"\" \ -DPIXMAPDIR=\""$(pixmapdir)"\" \ + -DAT_SPI_REGISTRYD_DIR="\"$(AT_SPI_REGISTRYD_DIR)\"" \ + $(GTK_CFLAGS) \ + $(XDMCP_CFLAGS) \ + $(EXTRA_CHOOSER_CFLAGS) \ $(SIMPLE_CHOOSER_CFLAGS) \ $(NULL) @@ -18,15 +22,40 @@ libexec_PROGRAMS = \ gdm-simple-chooser \ $(NULL) +noinst_PROGRAMS = \ + test-host-chooser \ + $(NULL) + gdm_simple_chooser_SOURCES = \ chooser-main.c \ gdm-host-chooser-widget.c \ gdm-host-chooser-widget.h \ gdm-host-chooser-dialog.c \ gdm-host-chooser-dialog.h \ + gdm-chooser-client.c \ + gdm-chooser-client.h \ + gdm-chooser-session.c \ + gdm-chooser-session.h \ $(NULL) gdm_simple_chooser_LDADD = \ + $(GTK_LIBS) \ + $(EXTRA_CHOOSER_LIBS) \ + $(SIMPLE_CHOOSER_LIBS) \ + $(XDMCP_LIBS) \ + $(top_builddir)/common/libgdmcommon.la \ + $(NULL) + +test_host_chooser_SOURCES = \ + test-host-chooser.c \ + gdm-host-chooser-widget.c \ + gdm-host-chooser-widget.h \ + gdm-host-chooser-dialog.c \ + gdm-host-chooser-dialog.h \ + $(NULL) + +test_host_chooser_LDADD = \ + $(GTK_LIBS) \ $(EXTRA_CHOOSER_LIBS) \ $(SIMPLE_CHOOSER_LIBS) \ $(XDMCP_LIBS) \ diff --git a/gui/simple-chooser/chooser-main.c b/gui/simple-chooser/chooser-main.c index 459bc0d2..17d7765b 100644 --- a/gui/simple-chooser/chooser-main.c +++ b/gui/simple-chooser/chooser-main.c @@ -28,22 +28,204 @@ #include <errno.h> #include <glib/gi18n.h> +#include <gdk/gdkx.h> #include <gtk/gtk.h> -#define DBUS_API_SUBJECT_TO_CHANGE -#include <dbus/dbus-glib.h> -#include <dbus/dbus-glib-lowlevel.h> +#include <gconf/gconf-client.h> #include "gdm-common.h" #include "gdm-log.h" #include "gdm-settings-client.h" #include "gdm-settings-keys.h" -#include "gdm-host-chooser-dialog.h" +#include "gdm-chooser-session.h" + +#define ACCESSIBILITY_KEY "/desktop/gnome/interface/accessibility" + +static Atom AT_SPI_IOR; + + +static gboolean +assistive_registry_launch (void) +{ + GPid pid; + GError *error; + const char *command; + char **argv; + gboolean res; + + command = AT_SPI_REGISTRYD_DIR "/at-spi-registryd"; + + argv = NULL; + error = NULL; + res = g_shell_parse_argv (command, NULL, &argv, &error); + if (! res) { + g_warning ("Unable to parse command: %s", error->message); + return FALSE; + } + + error = NULL; + res = g_spawn_async (NULL, + argv, + NULL, + G_SPAWN_SEARCH_PATH + | G_SPAWN_STDOUT_TO_DEV_NULL + | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL, + &pid, + &error); + g_strfreev (argv); + + if (! res) { + g_warning ("Unable to run command %s: %s", command, error->message); + return FALSE; + } + + if (kill (pid, 0) < 0) { + g_warning ("at-spi-registryd not running"); + return FALSE; + } + + return TRUE; +} + +static GdkFilterReturn +filter_watch (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + XEvent *xev = (XEvent *)xevent; + + if (xev->xany.type == PropertyNotify + && xev->xproperty.atom == AT_SPI_IOR) { + gtk_main_quit (); + + return GDK_FILTER_REMOVE; + } + + return GDK_FILTER_CONTINUE; +} + +static gboolean +filter_timeout (gpointer data) +{ + g_warning ("The accessibility registry was not found."); + + gtk_main_quit (); + + return FALSE; +} + +static void +assistive_registry_start (void) +{ + GdkWindow *root; + guint tid; + + root = gdk_get_default_root_window (); + + if ( ! AT_SPI_IOR) { + AT_SPI_IOR = XInternAtom (GDK_DISPLAY (), "AT_SPI_IOR", False); + } + + gdk_window_set_events (root, GDK_PROPERTY_CHANGE_MASK); + + if ( ! assistive_registry_launch ()) { + g_warning ("The accessibility registry could not be started."); + return; + } + + gdk_window_add_filter (root, filter_watch, NULL); + tid = g_timeout_add_seconds (5, filter_timeout, NULL); + + gtk_main (); + + gdk_window_remove_filter (root, filter_watch, NULL); + g_source_remove (tid); +} + +static void +at_set_gtk_modules (void) +{ + GSList *modules_list; + GSList *l; + const char *old; + char **modules; + gboolean found_gail; + gboolean found_atk_bridge; + int n; + + n = 0; + modules_list = NULL; + found_gail = FALSE; + found_atk_bridge = FALSE; + + if ((old = g_getenv ("GTK_MODULES")) != NULL) { + modules = g_strsplit (old, ":", -1); + for (n = 0; modules[n]; n++) { + if (!strcmp (modules[n], "gail")) { + found_gail = TRUE; + } else if (!strcmp (modules[n], "atk-bridge")) { + found_atk_bridge = TRUE; + } + + modules_list = g_slist_prepend (modules_list, modules[n]); + modules[n] = NULL; + } + g_free (modules); + } + + if (!found_gail) { + modules_list = g_slist_prepend (modules_list, "gail"); + ++n; + } + + if (!found_atk_bridge) { + modules_list = g_slist_prepend (modules_list, "atk-bridge"); + ++n; + } + + modules = g_new (char *, n + 1); + modules[n--] = NULL; + for (l = modules_list; l; l = l->next) { + modules[n--] = g_strdup (l->data); + } + + g_setenv ("GTK_MODULES", g_strjoinv (":", modules), TRUE); + g_strfreev (modules); + g_slist_free (modules_list); +} + +static void +load_a11y (void) +{ + const char *env_a_t_support; + gboolean a_t_support; + GConfClient *gconf_client; + + gconf_client = gconf_client_get_default (); + + env_a_t_support = g_getenv ("GNOME_ACCESSIBILITY"); + if (env_a_t_support) { + a_t_support = atoi (env_a_t_support); + } else { + a_t_support = gconf_client_get_bool (gconf_client, ACCESSIBILITY_KEY, NULL); + } + + if (a_t_support) { + assistive_registry_start (); + at_set_gtk_modules (); + } + + g_object_unref (gconf_client); +} int main (int argc, char *argv[]) { - GtkWidget *chooser; + GdmChooserSession *session; + gboolean res; + GError *error; bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); @@ -51,29 +233,42 @@ main (int argc, char *argv[]) setlocale (LC_ALL, ""); + gdm_set_fatal_warnings_if_unstable (); + g_type_init (); - g_debug ("Chooser for display %s xauthority:%s", g_getenv ("DISPLAY"), g_getenv ("XAUTHORITY")); + gdm_log_init (); + gdm_log_set_debug (TRUE); + + g_debug ("Chooser for display %s xauthority:%s", + g_getenv ("DISPLAY"), + g_getenv ("XAUTHORITY")); - /* - * gdm_common_atspi_launch () needs gdk initialized. - * We cannot start gtk before the registry is running - * because the atk-bridge will crash. - */ gdk_init (&argc, &argv); - /*gdm_common_atspi_launch ();*/ + + load_a11y (); + gtk_init (&argc, &argv); - chooser = gdm_host_chooser_dialog_new (); - if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) { - char *hostname; + session = gdm_chooser_session_new (); + if (session == NULL) { + g_critical ("Unable to create chooser session"); + exit (1); + } - hostname = gdm_host_chooser_dialog_get_current_hostname (GDM_HOST_CHOOSER_DIALOG (chooser)); - g_print ("hostname: %s\n", hostname); - g_free (hostname); + error = NULL; + res = gdm_chooser_session_start (session, &error); + if (! res) { + g_warning ("Unable to start chooser session: %s", error->message); + g_error_free (error); + exit (1); } - gtk_widget_destroy (chooser); + gtk_main (); + + if (session != NULL) { + g_object_unref (session); + } return 0; } diff --git a/gui/simple-chooser/gdm-chooser-client.c b/gui/simple-chooser/gdm-chooser-client.c new file mode 100644 index 00000000..268fddf2 --- /dev/null +++ b/gui/simple-chooser/gdm-chooser-client.c @@ -0,0 +1,414 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> +#define DBUS_API_SUBJECT_TO_CHANGE +#include <dbus/dbus.h> +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "gdm-chooser-client.h" + +#define GDM_CHOOSER_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_CLIENT, GdmChooserClientPrivate)) + +#define CHOOSER_SERVER_DBUS_PATH "/org/gnome/DisplayManager/ChooserServer" +#define CHOOSER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.ChooserServer" + +#define GDM_DBUS_NAME "org.gnome.DisplayManager" +#define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display" + +struct GdmChooserClientPrivate +{ + DBusConnection *connection; + char *address; +}; + +enum { + PROP_0, +}; + +static void gdm_chooser_client_class_init (GdmChooserClientClass *klass); +static void gdm_chooser_client_init (GdmChooserClient *chooser_client); +static void gdm_chooser_client_finalize (GObject *object); + +G_DEFINE_TYPE (GdmChooserClient, gdm_chooser_client, G_TYPE_OBJECT) + +static gpointer client_object = NULL; + +GQuark +gdm_chooser_client_error_quark (void) +{ + static GQuark error_quark = 0; + + if (error_quark == 0) + error_quark = g_quark_from_static_string ("gdm-chooser-client"); + + return error_quark; +} + +static gboolean +send_dbus_string_method (DBusConnection *connection, + const char *method, + const char *payload) +{ + DBusError error; + DBusMessage *message; + DBusMessage *reply; + DBusMessageIter iter; + const char *str; + + if (payload != NULL) { + str = payload; + } else { + str = ""; + } + + g_debug ("GdmChooserClient: Calling %s", method); + message = dbus_message_new_method_call (NULL, + CHOOSER_SERVER_DBUS_PATH, + CHOOSER_SERVER_DBUS_INTERFACE, + method); + if (message == NULL) { + g_warning ("Couldn't allocate the D-Bus message"); + return FALSE; + } + + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_append_basic (&iter, + DBUS_TYPE_STRING, + &str); + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, + message, + -1, + &error); + + dbus_message_unref (message); + + if (dbus_error_is_set (&error)) { + g_warning ("%s %s raised: %s\n", + method, + error.name, + error.message); + return FALSE; + } + dbus_message_unref (reply); + dbus_connection_flush (connection); + + return TRUE; +} + + +static gboolean +send_dbus_void_method (DBusConnection *connection, + const char *method) +{ + DBusError error; + DBusMessage *message; + DBusMessage *reply; + + g_debug ("GdmChooserClient: Calling %s", method); + message = dbus_message_new_method_call (NULL, + CHOOSER_SERVER_DBUS_PATH, + CHOOSER_SERVER_DBUS_INTERFACE, + method); + if (message == NULL) { + g_warning ("Couldn't allocate the D-Bus message"); + return FALSE; + } + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, + message, + -1, + &error); + + dbus_message_unref (message); + + if (dbus_error_is_set (&error)) { + g_warning ("%s %s raised: %s\n", + method, + error.name, + error.message); + return FALSE; + } + dbus_message_unref (reply); + dbus_connection_flush (connection); + + return TRUE; +} + +void +gdm_chooser_client_call_select_hostname (GdmChooserClient *client, + const char *text) +{ + send_dbus_string_method (client->priv->connection, + "SelectHostname", + text); +} + +void +gdm_chooser_client_call_disconnect (GdmChooserClient *client) +{ + send_dbus_void_method (client->priv->connection, + "Disconnect"); +} + +static DBusHandlerResult +client_dbus_handle_message (DBusConnection *connection, + DBusMessage *message, + void *user_data, + dbus_bool_t local_interface) +{ + +#if 0 + g_message ("obj_path=%s interface=%s method=%s destination=%s", + dbus_message_get_path (message), + dbus_message_get_interface (message), + dbus_message_get_member (message), + dbus_message_get_destination (message)); +#endif + + g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); + + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +client_dbus_filter_function (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + GdmChooserClient *client = GDM_CHOOSER_CLIENT (user_data); + const char *path; + + path = dbus_message_get_path (message); + + g_debug ("GdmChooserClient: obj_path=%s interface=%s method=%s", + dbus_message_get_path (message), + dbus_message_get_interface (message), + dbus_message_get_member (message)); + + if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") + && strcmp (path, DBUS_PATH_LOCAL) == 0) { + + g_message ("Got disconnected from the session message bus"); + + dbus_connection_unref (connection); + client->priv->connection = NULL; + + } else if (dbus_message_is_signal (message, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) { + g_debug ("GdmChooserClient: Name owner changed?"); + } else { + return client_dbus_handle_message (connection, message, user_data, FALSE); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +gboolean +gdm_chooser_client_start (GdmChooserClient *client, + GError **error) +{ + gboolean ret; + DBusError local_error; + + g_return_val_if_fail (GDM_IS_CHOOSER_CLIENT (client), FALSE); + + ret = FALSE; + + if (client->priv->address == NULL) { + g_warning ("GDM_CHOOSER_DBUS_ADDRESS not set"); + g_set_error (error, + GDM_CHOOSER_CLIENT_ERROR, + GDM_CHOOSER_CLIENT_ERROR_GENERIC, + "GDM_CHOOSER_DBUS_ADDRESS not set"); + goto out; + } + + g_debug ("GdmChooserClient: connecting to address: %s", client->priv->address); + + dbus_error_init (&local_error); + client->priv->connection = dbus_connection_open (client->priv->address, &local_error); + if (client->priv->connection == NULL) { + if (dbus_error_is_set (&local_error)) { + g_warning ("error opening connection: %s", local_error.message); + g_set_error (error, + GDM_CHOOSER_CLIENT_ERROR, + GDM_CHOOSER_CLIENT_ERROR_GENERIC, + local_error.message); + dbus_error_free (&local_error); + } else { + g_warning ("Unable to open connection"); + } + goto out; + } + + dbus_connection_setup_with_g_main (client->priv->connection, NULL); + dbus_connection_set_exit_on_disconnect (client->priv->connection, TRUE); + + dbus_connection_add_filter (client->priv->connection, + client_dbus_filter_function, + client, + NULL); + + ret = TRUE; + + out: + return ret; +} + +void +gdm_chooser_client_stop (GdmChooserClient *client) +{ + g_return_if_fail (GDM_IS_CHOOSER_CLIENT (client)); + +} + +static void +gdm_chooser_client_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdmChooserClient *self; + + self = GDM_CHOOSER_CLIENT (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gdm_chooser_client_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdmChooserClient *self; + + self = GDM_CHOOSER_CLIENT (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +gdm_chooser_client_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GdmChooserClient *chooser_client; + GdmChooserClientClass *klass; + + klass = GDM_CHOOSER_CLIENT_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_CLIENT)); + + chooser_client = GDM_CHOOSER_CLIENT (G_OBJECT_CLASS (gdm_chooser_client_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + + return G_OBJECT (chooser_client); +} + +static void +gdm_chooser_client_dispose (GObject *object) +{ + GdmChooserClient *chooser_client; + + chooser_client = GDM_CHOOSER_CLIENT (object); + + g_debug ("GdmChooserClient: Disposing chooser_client"); + + G_OBJECT_CLASS (gdm_chooser_client_parent_class)->dispose (object); +} + +static void +gdm_chooser_client_class_init (GdmChooserClientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gdm_chooser_client_get_property; + object_class->set_property = gdm_chooser_client_set_property; + object_class->constructor = gdm_chooser_client_constructor; + object_class->dispose = gdm_chooser_client_dispose; + object_class->finalize = gdm_chooser_client_finalize; + + g_type_class_add_private (klass, sizeof (GdmChooserClientPrivate)); +} + +static void +gdm_chooser_client_init (GdmChooserClient *client) +{ + + client->priv = GDM_CHOOSER_CLIENT_GET_PRIVATE (client); + + client->priv->address = g_strdup (g_getenv ("GDM_CHOOSER_DBUS_ADDRESS")); +} + +static void +gdm_chooser_client_finalize (GObject *object) +{ + GdmChooserClient *client; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_CHOOSER_CLIENT (object)); + + client = GDM_CHOOSER_CLIENT (object); + + g_return_if_fail (client->priv != NULL); + + g_free (client->priv->address); + + G_OBJECT_CLASS (gdm_chooser_client_parent_class)->finalize (object); +} + +GdmChooserClient * +gdm_chooser_client_new (void) +{ + if (client_object != NULL) { + g_object_ref (client_object); + } else { + client_object = g_object_new (GDM_TYPE_CHOOSER_CLIENT, NULL); + g_object_add_weak_pointer (client_object, + (gpointer *) &client_object); + } + + return GDM_CHOOSER_CLIENT (client_object); +} diff --git a/gui/simple-chooser/gdm-chooser-client.h b/gui/simple-chooser/gdm-chooser-client.h new file mode 100644 index 00000000..540040d1 --- /dev/null +++ b/gui/simple-chooser/gdm-chooser-client.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __GDM_CHOOSER_CLIENT_H +#define __GDM_CHOOSER_CLIENT_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GDM_TYPE_CHOOSER_CLIENT (gdm_chooser_client_get_type ()) +#define GDM_CHOOSER_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_CLIENT, GdmChooserClient)) +#define GDM_CHOOSER_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_CLIENT, GdmChooserClientClass)) +#define GDM_IS_CHOOSER_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_CLIENT)) +#define GDM_IS_CHOOSER_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_CLIENT)) +#define GDM_CHOOSER_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_CLIENT, GdmChooserClientClass)) + +typedef struct GdmChooserClientPrivate GdmChooserClientPrivate; + +typedef struct +{ + GObject parent; + GdmChooserClientPrivate *priv; +} GdmChooserClient; + +typedef struct +{ + GObjectClass parent_class; +} GdmChooserClientClass; + +#define GDM_CHOOSER_CLIENT_ERROR (gdm_chooser_client_error_quark ()) + +typedef enum _GdmChooserClientError { + GDM_CHOOSER_CLIENT_ERROR_GENERIC = 0, +} GdmChooserClientError; + +GType gdm_chooser_client_get_type (void); +GQuark gdm_chooser_client_error_quark (void); + +GdmChooserClient * gdm_chooser_client_new (void); + +gboolean gdm_chooser_client_start (GdmChooserClient *client, + GError **error); +void gdm_chooser_client_stop (GdmChooserClient *client); + +void gdm_chooser_client_call_disconnect (GdmChooserClient *client); +void gdm_chooser_client_call_select_hostname (GdmChooserClient *client, + const char *text); + +G_END_DECLS + +#endif /* __GDM_CHOOSER_CLIENT_H */ diff --git a/gui/simple-chooser/gdm-chooser-session.c b/gui/simple-chooser/gdm-chooser-session.c new file mode 100644 index 00000000..47f35790 --- /dev/null +++ b/gui/simple-chooser/gdm-chooser-session.c @@ -0,0 +1,318 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> + +#include "gdm-chooser-session.h" +#include "gdm-chooser-client.h" + +#include "gdm-host-chooser-dialog.h" + +#define GDM_CHOOSER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionPrivate)) + +struct GdmChooserSessionPrivate +{ + GdmChooserClient *client; + GtkWidget *chooser_dialog; +}; + +enum { + PROP_0, +}; + +static void gdm_chooser_session_class_init (GdmChooserSessionClass *klass); +static void gdm_chooser_session_init (GdmChooserSession *chooser_session); +static void gdm_chooser_session_finalize (GObject *object); + +G_DEFINE_TYPE (GdmChooserSession, gdm_chooser_session, G_TYPE_OBJECT) + +static gpointer session_object = NULL; + +static gboolean +launch_compiz (GdmChooserSession *session) +{ + GError *error; + gboolean ret; + + g_debug ("GdmChooserSession: Launching compiz"); + + ret = FALSE; + + error = NULL; + g_spawn_command_line_async ("gtk-window-decorator --replace", &error); + if (error != NULL) { + g_warning ("Error starting WM: %s", error->message); + g_error_free (error); + goto out; + } + + error = NULL; + g_spawn_command_line_async ("compiz --replace", &error); + if (error != NULL) { + g_warning ("Error starting WM: %s", error->message); + g_error_free (error); + goto out; + } + + ret = TRUE; + + /* FIXME: should try to detect if it actually works */ + + out: + return ret; +} + +static gboolean +launch_metacity (GdmChooserSession *session) +{ + GError *error; + gboolean ret; + + g_debug ("GdmChooserSession: Launching metacity"); + + ret = FALSE; + + error = NULL; + g_spawn_command_line_async ("metacity --replace", &error); + if (error != NULL) { + g_warning ("Error starting WM: %s", error->message); + g_error_free (error); + goto out; + } + + ret = TRUE; + + out: + return ret; +} + +static void +start_window_manager (GdmChooserSession *session) +{ + if (! launch_metacity (session)) { + launch_compiz (session); + } +} + +static gboolean +start_settings_daemon (GdmChooserSession *session) +{ + GError *error; + gboolean ret; + + g_debug ("GdmChooserSession: Launching settings daemon"); + + ret = FALSE; + + error = NULL; + g_spawn_command_line_async (LIBEXECDIR "/gnome-settings-daemon --gconf-prefix=/apps/gdm/simple-chooser/settings-manager-plugins", &error); + if (error != NULL) { + g_warning ("Error starting settings daemon: %s", error->message); + g_error_free (error); + goto out; + } + + ret = TRUE; + + out: + return ret; +} + +static void +on_dialog_response (GtkDialog *dialog, + int response_id, + GdmChooserSession *session) +{ + char *hostname; + + hostname = NULL; + switch (response_id) { + case GTK_RESPONSE_OK: + hostname = gdm_host_chooser_dialog_get_current_hostname (GDM_HOST_CHOOSER_DIALOG (dialog)); + case GTK_RESPONSE_NONE: + /* delete event */ + default: + break; + } + + if (hostname != NULL) { + g_debug ("GdmChooserSession: Selected hostname '%s'", hostname); + gdm_chooser_client_call_select_hostname (session->priv->client, hostname); + g_free (hostname); + } + + gdm_chooser_client_call_disconnect (session->priv->client); +} + +gboolean +gdm_chooser_session_start (GdmChooserSession *session, + GError **error) +{ + gboolean res; + + g_return_val_if_fail (GDM_IS_CHOOSER_SESSION (session), FALSE); + + res = gdm_chooser_client_start (session->priv->client, error); + + if (res) { + start_settings_daemon (session); + start_window_manager (session); + + session->priv->chooser_dialog = gdm_host_chooser_dialog_new (); + g_signal_connect (session->priv->chooser_dialog, + "response", + G_CALLBACK (on_dialog_response), + session); + gtk_widget_show (session->priv->chooser_dialog); + } + + return res; +} + +void +gdm_chooser_session_stop (GdmChooserSession *session) +{ + g_return_if_fail (GDM_IS_CHOOSER_SESSION (session)); + +} + +static void +gdm_chooser_session_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GdmChooserSession *self; + + self = GDM_CHOOSER_SESSION (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gdm_chooser_session_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GdmChooserSession *self; + + self = GDM_CHOOSER_SESSION (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GObject * +gdm_chooser_session_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GdmChooserSession *chooser_session; + GdmChooserSessionClass *klass; + + klass = GDM_CHOOSER_SESSION_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_SESSION)); + + chooser_session = GDM_CHOOSER_SESSION (G_OBJECT_CLASS (gdm_chooser_session_parent_class)->constructor (type, + n_construct_properties, + construct_properties)); + + return G_OBJECT (chooser_session); +} + +static void +gdm_chooser_session_dispose (GObject *object) +{ + GdmChooserSession *chooser_session; + + chooser_session = GDM_CHOOSER_SESSION (object); + + g_debug ("GdmChooserSession: Disposing chooser_session"); + + G_OBJECT_CLASS (gdm_chooser_session_parent_class)->dispose (object); +} + +static void +gdm_chooser_session_class_init (GdmChooserSessionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = gdm_chooser_session_get_property; + object_class->set_property = gdm_chooser_session_set_property; + object_class->constructor = gdm_chooser_session_constructor; + object_class->dispose = gdm_chooser_session_dispose; + object_class->finalize = gdm_chooser_session_finalize; + + g_type_class_add_private (klass, sizeof (GdmChooserSessionPrivate)); +} + +static void +gdm_chooser_session_init (GdmChooserSession *session) +{ + + session->priv = GDM_CHOOSER_SESSION_GET_PRIVATE (session); + + session->priv->client = gdm_chooser_client_new (); +} + +static void +gdm_chooser_session_finalize (GObject *object) +{ + GdmChooserSession *chooser_session; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_CHOOSER_SESSION (object)); + + chooser_session = GDM_CHOOSER_SESSION (object); + + g_return_if_fail (chooser_session->priv != NULL); + + G_OBJECT_CLASS (gdm_chooser_session_parent_class)->finalize (object); +} + +GdmChooserSession * +gdm_chooser_session_new (void) +{ + if (session_object != NULL) { + g_object_ref (session_object); + } else { + session_object = g_object_new (GDM_TYPE_CHOOSER_SESSION, NULL); + g_object_add_weak_pointer (session_object, + (gpointer *) &session_object); + } + + return GDM_CHOOSER_SESSION (session_object); +} diff --git a/gui/simple-chooser/gdm-chooser-session.h b/gui/simple-chooser/gdm-chooser-session.h new file mode 100644 index 00000000..ebb12021 --- /dev/null +++ b/gui/simple-chooser/gdm-chooser-session.h @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __GDM_CHOOSER_SESSION_H +#define __GDM_CHOOSER_SESSION_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GDM_TYPE_CHOOSER_SESSION (gdm_chooser_session_get_type ()) +#define GDM_CHOOSER_SESSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSession)) +#define GDM_CHOOSER_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionClass)) +#define GDM_IS_CHOOSER_SESSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_SESSION)) +#define GDM_IS_CHOOSER_SESSION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_SESSION)) +#define GDM_CHOOSER_SESSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionClass)) + +typedef struct GdmChooserSessionPrivate GdmChooserSessionPrivate; + +typedef struct +{ + GObject parent; + GdmChooserSessionPrivate *priv; +} GdmChooserSession; + +typedef struct +{ + GObjectClass parent_class; +} GdmChooserSessionClass; + +GType gdm_chooser_session_get_type (void); + +GdmChooserSession * gdm_chooser_session_new (void); + +gboolean gdm_chooser_session_start (GdmChooserSession *session, + GError **error); +void gdm_chooser_session_stop (GdmChooserSession *session); + +G_END_DECLS + +#endif /* __GDM_CHOOSER_SESSION_H */ diff --git a/gui/simple-chooser/test-host-chooser.c b/gui/simple-chooser/test-host-chooser.c new file mode 100644 index 00000000..31e94005 --- /dev/null +++ b/gui/simple-chooser/test-host-chooser.c @@ -0,0 +1,263 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdlib.h> +#include <libintl.h> +#include <locale.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> + +#include <glib/gi18n.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> +#include <gconf/gconf-client.h> + +#include "gdm-common.h" +#include "gdm-log.h" +#include "gdm-settings-client.h" +#include "gdm-settings-keys.h" + +#include "gdm-host-chooser-dialog.h" + +#define ACCESSIBILITY_KEY "/desktop/gnome/interface/accessibility" + +static Atom AT_SPI_IOR; + + +static gboolean +assistive_registry_launch (void) +{ + GPid pid; + GError *error; + const char *command; + char **argv; + gboolean res; + + command = AT_SPI_REGISTRYD_DIR "/at-spi-registryd"; + + argv = NULL; + error = NULL; + res = g_shell_parse_argv (command, NULL, &argv, &error); + if (! res) { + g_warning ("Unable to parse command: %s", error->message); + return FALSE; + } + + error = NULL; + res = g_spawn_async (NULL, + argv, + NULL, + G_SPAWN_SEARCH_PATH + | G_SPAWN_STDOUT_TO_DEV_NULL + | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL, + &pid, + &error); + g_strfreev (argv); + + if (! res) { + g_warning ("Unable to run command %s: %s", command, error->message); + return FALSE; + } + + if (kill (pid, 0) < 0) { + g_warning ("at-spi-registryd not running"); + return FALSE; + } + + return TRUE; +} + +static GdkFilterReturn +filter_watch (GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + XEvent *xev = (XEvent *)xevent; + + if (xev->xany.type == PropertyNotify + && xev->xproperty.atom == AT_SPI_IOR) { + gtk_main_quit (); + + return GDK_FILTER_REMOVE; + } + + return GDK_FILTER_CONTINUE; +} + +static gboolean +filter_timeout (gpointer data) +{ + g_warning ("The accessibility registry was not found."); + + gtk_main_quit (); + + return FALSE; +} + +static void +assistive_registry_start (void) +{ + GdkWindow *root; + guint tid; + + root = gdk_get_default_root_window (); + + if ( ! AT_SPI_IOR) { + AT_SPI_IOR = XInternAtom (GDK_DISPLAY (), "AT_SPI_IOR", False); + } + + gdk_window_set_events (root, GDK_PROPERTY_CHANGE_MASK); + + if ( ! assistive_registry_launch ()) { + g_warning ("The accessibility registry could not be started."); + return; + } + + gdk_window_add_filter (root, filter_watch, NULL); + tid = g_timeout_add_seconds (5, filter_timeout, NULL); + + gtk_main (); + + gdk_window_remove_filter (root, filter_watch, NULL); + g_source_remove (tid); +} + +static void +at_set_gtk_modules (void) +{ + GSList *modules_list; + GSList *l; + const char *old; + char **modules; + gboolean found_gail; + gboolean found_atk_bridge; + int n; + + n = 0; + modules_list = NULL; + found_gail = FALSE; + found_atk_bridge = FALSE; + + if ((old = g_getenv ("GTK_MODULES")) != NULL) { + modules = g_strsplit (old, ":", -1); + for (n = 0; modules[n]; n++) { + if (!strcmp (modules[n], "gail")) { + found_gail = TRUE; + } else if (!strcmp (modules[n], "atk-bridge")) { + found_atk_bridge = TRUE; + } + + modules_list = g_slist_prepend (modules_list, modules[n]); + modules[n] = NULL; + } + g_free (modules); + } + + if (!found_gail) { + modules_list = g_slist_prepend (modules_list, "gail"); + ++n; + } + + if (!found_atk_bridge) { + modules_list = g_slist_prepend (modules_list, "atk-bridge"); + ++n; + } + + modules = g_new (char *, n + 1); + modules[n--] = NULL; + for (l = modules_list; l; l = l->next) { + modules[n--] = g_strdup (l->data); + } + + g_setenv ("GTK_MODULES", g_strjoinv (":", modules), TRUE); + g_strfreev (modules); + g_slist_free (modules_list); +} + +static void +load_a11y (void) +{ + const char *env_a_t_support; + gboolean a_t_support; + GConfClient *gconf_client; + + gconf_client = gconf_client_get_default (); + + env_a_t_support = g_getenv ("GNOME_ACCESSIBILITY"); + if (env_a_t_support) { + a_t_support = atoi (env_a_t_support); + } else { + a_t_support = gconf_client_get_bool (gconf_client, ACCESSIBILITY_KEY, NULL); + } + + if (a_t_support) { + assistive_registry_start (); + at_set_gtk_modules (); + } + + g_object_unref (gconf_client); +} + +int +main (int argc, char *argv[]) +{ + GtkWidget *chooser; + + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + setlocale (LC_ALL, ""); + + gdm_set_fatal_warnings_if_unstable (); + + g_type_init (); + + gdm_log_init (); + gdm_log_set_debug (TRUE); + + g_debug ("Chooser for display %s xauthority:%s", + g_getenv ("DISPLAY"), + g_getenv ("XAUTHORITY")); + + gdk_init (&argc, &argv); + + load_a11y (); + + gtk_init (&argc, &argv); + + chooser = gdm_host_chooser_dialog_new (); + if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) { + char *hostname; + + hostname = gdm_host_chooser_dialog_get_current_hostname (GDM_HOST_CHOOSER_DIALOG (chooser)); + g_print ("hostname: %s\n", hostname); + g_free (hostname); + } + + gtk_widget_destroy (chooser); + + return 0; +} diff --git a/gui/simple-greeter/greeter-main.c b/gui/simple-greeter/greeter-main.c index dc9891e9..d2ffbe56 100644 --- a/gui/simple-greeter/greeter-main.c +++ b/gui/simple-greeter/greeter-main.c @@ -194,15 +194,36 @@ at_set_gtk_modules (void) g_slist_free (modules_list); } +static void +load_a11y (void) +{ + const char *env_a_t_support; + gboolean a_t_support; + GConfClient *gconf_client; + + gconf_client = gconf_client_get_default (); + + env_a_t_support = g_getenv ("GNOME_ACCESSIBILITY"); + if (env_a_t_support) { + a_t_support = atoi (env_a_t_support); + } else { + a_t_support = gconf_client_get_bool (gconf_client, ACCESSIBILITY_KEY, NULL); + } + + if (a_t_support) { + assistive_registry_start (); + at_set_gtk_modules (); + } + + g_object_unref (gconf_client); +} + int main (int argc, char *argv[]) { GError *error; GdmGreeterSession *session; gboolean res; - const char *env_a_t_support; - gboolean a_t_support; - GConfClient *gconf_client; bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); @@ -231,19 +252,7 @@ main (int argc, char *argv[]) gdk_init (&argc, &argv); - gconf_client = gconf_client_get_default (); - - env_a_t_support = g_getenv ("GNOME_ACCESSIBILITY"); - if (env_a_t_support) { - a_t_support = atoi (env_a_t_support); - } else { - a_t_support = gconf_client_get_bool (gconf_client, ACCESSIBILITY_KEY, NULL); - } - - if (a_t_support) { - assistive_registry_start (); - at_set_gtk_modules (); - } + load_a11y (); gtk_init (&argc, &argv); @@ -253,6 +262,7 @@ main (int argc, char *argv[]) exit (1); } + error = NULL; res = gdm_greeter_session_start (session, &error); if (! res) { g_warning ("Unable to start greeter session: %s", error->message); diff --git a/po/ChangeLog b/po/ChangeLog index c1d2def7..d8f2e7ac 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,7 @@ +2008-01-30 William Jon McCann <mccann@jhu.edu> + + * POTFILES.in: Add missing files. + 2007-01-29 Yair Hershkovitz <yairhr@gmail.com> * he.po: Updated Hebrew translation by Mark Krapviner. @@ -73,8 +77,6 @@ 2007-12-21 William Jon McCann <mccann@jhu.edu> - reviewed by: <delete if not using a buddy> - * POTFILES.in: 2007-12-20 Kjartan Maraas <kmaraas@gnome.org> @@ -138,8 +140,6 @@ 2007-10-29 William Jon McCann <mccann@jhu.edu> - reviewed by: <delete if not using a buddy> - * POTFILES.in: 2007-10-29 Kjartan Maraas <kmaraas@gnome.org> diff --git a/po/POTFILES.in b/po/POTFILES.in index c2fa6c7b..297808cd 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -15,6 +15,7 @@ common/test-log.c common/test-settings-client.c common/test-settings-server.c daemon/factory-slave-main.c +daemon/gdm-chooser-session.c daemon/gdm-display.c daemon/gdm-display-access-file.c daemon/gdm-display-store.c @@ -43,6 +44,7 @@ daemon/product-slave-main.c daemon/session-worker-main.c daemon/simple-slave-main.c daemon/test-session.c +daemon/xdmcp-chooser-slave-main.c data/gdm.schemas.in.in gui/simple-chooser/gdm-host-chooser-widget.c gui/simple-greeter/gdm-chooser-widget.c |