diff options
Diffstat (limited to 'daemon/gdm-xdmcp-manager.c')
-rw-r--r-- | daemon/gdm-xdmcp-manager.c | 2943 |
1 files changed, 0 insertions, 2943 deletions
diff --git a/daemon/gdm-xdmcp-manager.c b/daemon/gdm-xdmcp-manager.c deleted file mode 100644 index b11fcff5..00000000 --- a/daemon/gdm-xdmcp-manager.c +++ /dev/null @@ -1,2943 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net> - * 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/utsname.h> - -#include <sys/socket.h> -#include <netdb.h> -#include <arpa/inet.h> -#include <net/if.h> -#ifdef HAVE_SYS_SOCKIO_H -#include <sys/sockio.h> -#endif -#include <sys/ioctl.h> - -#include <errno.h> - -#include <glib.h> -#include <glib/gi18n.h> -#include <glib-object.h> - -#include <X11/Xlib.h> -#include <X11/Xmd.h> -#include <X11/Xdmcp.h> - -#include "gdm-common.h" -#include "gdm-xdmcp-manager.h" - -#include "misc.h" -#include "auth.h" -#include "cookie.h" -#include "choose.h" -#include "gdm-daemon-config.h" - -/* - * On Sun, we need to define allow_severity and deny_severity to link - * against libwrap. - */ -#ifdef __sun -#include <syslog.h> -int allow_severity = LOG_INFO; -int deny_severity = LOG_WARNING; -#endif - -#define GDM_XDMCP_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_MANAGER, GdmXdmcpManagerPrivate)) - -#define DEFAULT_PORT 177 -#define DEFAULT_USE_MULTICAST FALSE -#define DEFAULT_MULTICAST_ADDRESS "ff02::1" -#define DEFAULT_HONOR_INDIRECT TRUE -#define DEFAULT_MAX_DISPLAYS_PER_HOST 2 -#define DEFAULT_MAX_DISPLAYS 16 -#define DEFAULT_MAX_PENDING_DISPLAYS 4 -#define DEFAULT_MAX_WAIT 15 - -#define GDM_MAX_FORWARD_QUERIES 10 -#define GDM_FORWARD_QUERY_TIMEOUT 30 -#define MANAGED_FORWARD_INTERVAL 1500 /* 1.5 seconds */ - -/* some extra XDMCP opcodes that xdm will happily ignore since they'll be - * the wrong XDMCP version anyway */ -#define GDM_XDMCP_PROTOCOL_VERSION 1001 -enum { - GDM_XDMCP_FIRST_OPCODE = 1000, /*just a marker, not an opcode */ - - GDM_XDMCP_MANAGED_FORWARD = 1000, - /* manager (master) -> manager - * A packet with MANAGED_FORWARD is sent to the - * manager that sent the forward query from the manager to - * which forward query was sent. It indicates that the forward - * was fully processed and that the client now has either - * a managed session, or has been sent denial, refuse or failed. - * (if the denial gets lost then client gets dumped into the - * chooser again). This should be resent a few times - * until some (short) timeout or until GOT_MANAGED_FORWARD - * is sent. GDM sends at most 3 packates with 1.5 seconds - * between each. - * - * Argument is ARRAY8 with the address of the originating host */ - GDM_XDMCP_GOT_MANAGED_FORWARD, - /* manager -> manager (master) - * A single packet with GOT_MANAGED_FORWARD is sent to indicate - * that we did receive the MANAGED_FORWARD packet. The argument - * must match the MANAGED_FORWARD one or it will just be ignored. - * - * Argument is ARRAY8 with the address of the originating host */ - GDM_XDMCP_LAST_OPCODE /*just a marker, not an opcode */ -}; - -/* - * We don't support XDM-AUTHENTICATION-1 and XDM-AUTHORIZATION-1. - * - * The latter would be quite useful to avoid sending unencrypted - * cookies over the wire. Unfortunately it isn't supported without - * XDM-AUTHENTICATION-1 which requires a key database with private - * keys from all X terminals on your LAN. Fun, fun, fun. - * - * Furthermore user passwords go over the wire in cleartext anyway, - * so protecting cookies is not that important. - */ - -typedef struct _XdmAuth { - ARRAY8 authentication; - ARRAY8 authorization; -} XdmAuthRec, *XdmAuthPtr; - -static XdmAuthRec serv_authlist = { - { (CARD16) 0, (CARD8 *) 0 }, - { (CARD16) 0, (CARD8 *) 0 } -}; - -/* NOTE: Timeout and max are hardcoded */ -typedef struct _GdmForwardQuery { - time_t acctime; - struct sockaddr_storage *dsp_sa; - struct sockaddr_storage *from_sa; -} GdmForwardQuery; - -typedef struct { - int times; - guint handler; - struct sockaddr_storage manager; - struct sockaddr_storage origin; - GdmXdmcpManager *xdmcp_manager; -} ManagedForward; - -struct GdmXdmcpManagerPrivate -{ - GSList *forward_queries; - GSList *managed_forwards; - - int socket_fd; - gint32 session_serial; - guint socket_watch_id; - XdmcpBuffer buf; - - guint num_sessions; - guint num_pending_sessions; - - char *sysid; - char *hostname; - ARRAY8 servhost; - - /* configuration */ - guint port; - gboolean use_multicast; - char *multicast_address; - gboolean honor_indirect; - char *willing_script; - guint max_displays_per_host; - guint max_displays; - guint max_pending_displays; - guint max_wait; -}; - -enum { - DISPLAY_ADDED, - DISPLAY_REMOVED, - LAST_SIGNAL -}; - -enum { - PROP_0, - PROP_PORT, - PROP_USE_MULTICAST, - PROP_MULTICAST_ADDRESS, - PROP_HONOR_INDIRECT, - PROP_WILLING_SCRIPT, - PROP_MAX_DISPLAYS_PER_HOST, - PROP_MAX_DISPLAYS, - PROP_MAX_PENDING_DISPLAYS, - PROP_MAX_WAIT, -}; - -static void gdm_xdmcp_manager_class_init (GdmXdmcpManagerClass *klass); -static void gdm_xdmcp_manager_init (GdmXdmcpManager *manager); -static void gdm_xdmcp_manager_finalize (GObject *object); - -static gpointer xdmcp_manager_object = NULL; - -G_DEFINE_TYPE (GdmXdmcpManager, gdm_xdmcp_manager, G_TYPE_OBJECT) - -/* Theory of operation: - * - * Process idles waiting for UDP packets on port 177. - * Incoming packets are decoded and checked against tcp_wrapper. - * - * A typical session looks like this: - * - * Display sends Query/BroadcastQuery to Manager. - * - * Manager selects an appropriate authentication scheme from the - * display's list of supported ones and sends Willing/Unwilling. - * - * Assuming the display accepts the auth. scheme it sends back a - * Request. - * - * If the manager accepts to service the display (i.e. loadavg is low) - * it sends back an Accept containing a unique SessionID. The - * SessionID is stored in an accept queue by the Manager. Should the - * manager refuse to start a session a Decline is sent to the display. - * - * The display returns a Manage request containing the supplied - * SessionID. The manager will then start a session on the display. In - * case the SessionID is not on the accept queue the manager returns - * Refuse. If the manager fails to open the display for connections - * Failed is returned. - * - * During the session the display periodically sends KeepAlive packets - * to the manager. The manager responds with Alive. - * - * Similarly the manager xpings the display once in a while and shuts - * down the connection on failure. - * - */ - -GQuark -gdm_xdmcp_manager_error_quark (void) -{ - static GQuark ret = 0; - if (ret == 0) { - ret = g_quark_from_static_string ("gdm_xdmcp_manager_error"); - } - - return ret; -} - -static gint32 -get_next_session_serial (GdmXdmcpManager *manager) -{ - gint32 serial; - - again: - if (manager->priv->session_serial != G_MAXINT32) { - serial = manager->priv->session_serial++; - } else { - serial = g_random_int (); - } - - if (serial == 0) { - goto again; - } - - return serial; -} - -/* for debugging */ -static const char * -ai_family_str (struct addrinfo *ai) -{ - const char *str; - switch (ai->ai_family) { - case AF_INET: - str = "inet"; - break; - case AF_INET6: - str = "inet6"; - break; - case AF_UNIX: - str = "unix"; - break; - case AF_UNSPEC: - str = "unspecified"; - break; - default: - str = "unknown"; - break; - } - return str; -} - -/* for debugging */ -static const char * -ai_type_str (struct addrinfo *ai) -{ - const char *str; - switch (ai->ai_socktype) { - case SOCK_STREAM: - str = "stream"; - break; - case SOCK_DGRAM: - str = "datagram"; - break; - case SOCK_SEQPACKET: - str = "seqpacket"; - break; - case SOCK_RAW: - str = "raw"; - break; - default: - str = "unknown"; - break; - } - return str; -} - -/* for debugging */ -static const char * -ai_protocol_str (struct addrinfo *ai) -{ - const char *str; - switch (ai->ai_protocol) { - case 0: - str = "default"; - break; - case IPPROTO_TCP: - str = "TCP"; - break; - case IPPROTO_UDP: - str = "UDP"; - break; - case IPPROTO_RAW: - str = "raw"; - break; - default: - str = "unknown"; - break; - } - - return str; -} - -/* for debugging */ -static char * -ai_flags_str (struct addrinfo *ai) -{ - GString *str; - - str = g_string_new (""); - if (ai->ai_flags == 0) { - g_string_append (str, "none"); - } else { - if (ai->ai_flags & AI_PASSIVE) { - g_string_append (str, "passive "); - } - if (ai->ai_flags & AI_CANONNAME) { - g_string_append (str, "canon "); - } - if (ai->ai_flags & AI_NUMERICHOST) { - g_string_append (str, "numhost "); - } - if (ai->ai_flags & AI_NUMERICSERV) { - g_string_append (str, "numserv "); - } - if (ai->ai_flags & AI_V4MAPPED) { - g_string_append (str, "v4mapped "); - } - if (ai->ai_flags & AI_ALL) { - g_string_append (str, "all "); - } - } - return g_string_free (str, FALSE); -} - -/* for debugging */ -static void -debug_addrinfo (struct addrinfo *ai) -{ - char *str; - str = ai_flags_str (ai); - g_debug ("XDMCP: addrinfo family=%s type=%s proto=%s flags=%s", - ai_family_str (ai), - ai_type_str (ai), - ai_protocol_str (ai), - str); - g_free (str); -} - -static int -create_socket (struct addrinfo *ai) -{ - int sock; - - sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock < 0) { - g_warning ("socket: %s", g_strerror (errno)); - return sock; - } - - if (bind (sock, ai->ai_addr, ai->ai_addrlen) < 0) { - g_warning ("bind: %s", g_strerror (errno)); - close (sock); - return -1; - } - - return sock; -} - -static int -do_bind (guint port, - int family, - struct sockaddr_storage * hostaddr) -{ - struct addrinfo hints; - struct addrinfo *ai_list; - struct addrinfo *ai; - char strport[NI_MAXSERV]; - int gaierr; - int sock; - - sock = -1; - - memset (&hints, 0, sizeof (hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; - - snprintf (strport, sizeof (strport), "%u", port); - if ((gaierr = getaddrinfo (NULL, strport, &hints, &ai_list)) != 0) { - g_error ("Unable to connect to socket: %s", gai_strerror (gaierr)); - return -1; - } - - /* should only be one but.. */ - for (ai = ai_list; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { - continue; - } - - debug_addrinfo (ai); - - if (sock < 0) { - char *host; - char *serv; - - gdm_address_get_info ((struct sockaddr_storage *)ai->ai_addr, &host, &serv); - g_debug ("XDMCP: Attempting to bind to host %s port %s", host, serv); - g_free (host); - g_free (serv); - sock = create_socket (ai); - if (sock >= 0) { - if (hostaddr != NULL) { - memcpy (hostaddr, ai->ai_addr, ai->ai_addrlen); - } - } - } - } - - freeaddrinfo (ai_list); - - return sock; -} - -static void -setup_multicast (GdmXdmcpManager *manager) -{ -#ifdef ENABLE_IPV6 - /* Checking and Setting Multicast options */ - { - /* - * socktemp is a temporary socket for getting info about - * available interfaces - */ - int socktemp; - int i; - int num; - char *buf; - struct ipv6_mreq mreq; - - /* For interfaces' list */ - struct ifconf ifc; - struct ifreq *ifr; - - socktemp = socket (AF_INET, SOCK_DGRAM, 0); -#ifdef SIOCGIFNUM - if (ioctl (socktemp, SIOCGIFNUM, &num) < 0) { - num = 64; - } -#else - num = 64; -#endif /* SIOCGIFNUM */ - ifc.ifc_len = sizeof (struct ifreq) * num; - ifc.ifc_buf = buf = malloc (ifc.ifc_len); - - if (ioctl (socktemp, SIOCGIFCONF, &ifc) >= 0) { - ifr = ifc.ifc_req; - num = ifc.ifc_len / sizeof (struct ifreq); /* No of interfaces */ - - /* Joining multicast group with all interfaces */ - for (i = 0 ; i < num ; i++) { - struct ifreq ifreq; - int ifindex; - - memset (&ifreq, 0, sizeof (ifreq)); - strncpy (ifreq.ifr_name, ifr[i].ifr_name, sizeof (ifreq.ifr_name)); - /* paranoia */ - ifreq.ifr_name[sizeof (ifreq.ifr_name) - 1] = '\0'; - - if (ioctl (socktemp, SIOCGIFFLAGS, &ifreq) < 0) { - g_debug ("XDMCP: Could not get SIOCGIFFLAGS for %s", - ifr[i].ifr_name); - } - - ifindex = if_nametoindex (ifr[i].ifr_name); - - if ((!(ifreq.ifr_flags & IFF_UP) || - (ifreq.ifr_flags & IFF_LOOPBACK)) || - ((ifindex == 0 ) && (errno == ENXIO))) { - /* Not a valid interface or loopback interface*/ - continue; - } - - mreq.ipv6mr_interface = ifindex; - inet_pton (AF_INET6, - manager->priv->multicast_address, - &mreq.ipv6mr_multiaddr); - - setsockopt (manager->priv->socket_fd, - IPPROTO_IPV6, - IPV6_JOIN_GROUP, - &mreq, - sizeof (mreq)); - } - } - g_free (buf); - close (socktemp); - } -#endif /* ENABLE_IPV6 */ -} - -static gboolean -open_port (GdmXdmcpManager *manager) -{ - struct sockaddr_storage serv_sa = { 0 }; - - g_debug ("XDMCP: Start up on host %s, port %d", - manager->priv->hostname, - manager->priv->port); - - /* Open socket for communications */ -#ifdef ENABLE_IPV6 - manager->priv->socket_fd = do_bind (manager->priv->port, AF_INET6, &serv_sa); - if (manager->priv->socket_fd < 0) -#endif - manager->priv->socket_fd = do_bind (manager->priv->port, AF_INET, &serv_sa); - - if G_UNLIKELY (manager->priv->socket_fd < 0) { - g_warning (_("Could not create socket!")); - return FALSE; - } - - if (manager->priv->use_multicast) { - setup_multicast (manager); - } - - return TRUE; -} - -static gboolean -gdm_xdmcp_host_allow (struct sockaddr_storage *clnt_sa) -{ -#ifdef HAVE_TCPWRAPPERS - - /* - * Avoids a warning, my tcpd.h file doesn't include this prototype, even - * though the library does include the function and the manpage mentions it - */ - extern int hosts_ctl (char *daemon, - char *client_name, - char *client_addr, - char *client_user); - - GdmHostent *client_he; - char *client; - gboolean ret; - char *host; - - /* Find client hostname */ - client_he = gdm_gethostbyaddr (clnt_sa); - - if (client_he->not_found) { - client = "unknown"; - } else { - g_debug ("gdm_xdmcp_host_allow: client->hostname is %s\n", - client_he->hostname); - client = client_he->hostname; - } - - /* Check with tcp_wrappers if client is allowed to access */ - host = NULL; - gdm_address_get_info (clnt_sa, &host, NULL); - ret = hosts_ctl ("gdm", client, host, ""); - g_free (host); - - gdm_hostent_free (client_he); - - return ret; -#else /* HAVE_TCPWRAPPERS */ - return (TRUE); -#endif /* HAVE_TCPWRAPPERS */ -} - -static int -gdm_xdmcp_num_displays_from_host (GdmXdmcpManager *manager, - struct sockaddr_storage *addr) -{ - GSList *li; - int count = 0; - GSList *displays; - - displays = gdm_daemon_config_get_display_list (); - - for (li = displays; li != NULL; li = li->next) { - GdmDisplay *disp = li->data; - if (SERVER_IS_XDMCP (disp)) { - if (gdm_address_equal (&disp->addr, addr)) { - count++; - } - } - } - return count; -} - -static GdmDisplay * -gdm_xdmcp_display_lookup_by_host (GdmXdmcpManager *manager, - struct sockaddr_storage *addr, - int dspnum) -{ - GSList *li; - GSList *displays; - - displays = gdm_daemon_config_get_display_list (); - - for (li = displays; li != NULL; li = li->next) { - GdmDisplay *disp = li->data; - if (SERVER_IS_XDMCP (disp)) { - - if (gdm_address_equal (&disp->addr, addr) - && disp->xdmcp_dispnum == dspnum) { - return disp; - } - } - } - - return NULL; -} - -static char * -get_willing_output (GdmXdmcpManager *manager) -{ - char *output; - char **argv; - FILE *fd; - char buf[256]; - - output = NULL; - buf[0] = '\0'; - - if (manager->priv->willing_script == NULL) { - goto out; - } - - argv = NULL; - if (! g_shell_parse_argv (manager->priv->willing_script, NULL, &argv, NULL)) { - goto out; - } - - if (argv == NULL || - argv[0] == NULL || - g_access (argv[0], X_OK) != 0) { - goto out; - } - - fd = popen (manager->priv->willing_script, "r"); - if (fd == NULL) { - goto out; - } - - if (fgets (buf, sizeof (buf), fd) == NULL) { - pclose (fd); - goto out; - } - - pclose (fd); - - output = g_strdup (buf); - - out: - return output; -} - -static void -gdm_xdmcp_send_willing (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa) -{ - ARRAY8 status; - XdmcpHeader header; - static char *last_status = NULL; - static time_t last_willing = 0; - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("XDMCP: Sending WILLING to %s", host); - g_free (host); - - if (last_willing == 0 || time (NULL) - 3 > last_willing) { - char *s; - - g_free (last_status); - - s = get_willing_output (manager); - if (s != NULL) { - g_free (last_status); - last_status = s; - } else { - last_status = g_strdup (manager->priv->sysid); - } - } - - if (! gdm_address_is_local (clnt_sa) && - gdm_xdmcp_num_displays_from_host (manager, clnt_sa) >= manager->priv->max_displays_per_host) { - /* - * Don't translate, this goes over the wire to servers where we - * don't know the charset or language, so it must be ascii - */ - status.data = (CARD8 *) g_strdup_printf ("%s (Server is busy)", - last_status); - } else { - status.data = (CARD8 *) g_strdup (last_status); - } - - status.length = strlen ((char *) status.data); - - header.opcode = (CARD16) WILLING; - header.length = 6 + serv_authlist.authentication.length; - header.length += manager->priv->servhost.length + status.length; - header.version = XDM_PROTOCOL_VERSION; - XdmcpWriteHeader (&manager->priv->buf, &header); - - /* Hardcoded authentication */ - XdmcpWriteARRAY8 (&manager->priv->buf, &serv_authlist.authentication); - XdmcpWriteARRAY8 (&manager->priv->buf, &manager->priv->servhost); - XdmcpWriteARRAY8 (&manager->priv->buf, &status); - - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); - - g_free (status.data); -} - -static void -gdm_xdmcp_send_unwilling (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int type) -{ - ARRAY8 status; - XdmcpHeader header; - static time_t last_time = 0; - char *host; - - /* only send at most one packet per second, - no harm done if we don't send it at all */ - if (last_time + 1 >= time (NULL)) { - return; - } - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("XDMCP: Sending UNWILLING to %s", host); - g_warning (_("Denied XDMCP query from host %s"), host); - g_free (host); - - /* - * Don't translate, this goes over the wire to servers where we - * don't know the charset or language, so it must be ascii - */ - status.data = (CARD8 *) "Display not authorized to connect"; - status.length = strlen ((char *) status.data); - - header.opcode = (CARD16) UNWILLING; - header.length = 4 + manager->priv->servhost.length + status.length; - header.version = XDM_PROTOCOL_VERSION; - XdmcpWriteHeader (&manager->priv->buf, &header); - - XdmcpWriteARRAY8 (&manager->priv->buf, &manager->priv->servhost); - XdmcpWriteARRAY8 (&manager->priv->buf, &status); - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); - - last_time = time (NULL); -} - -#define SIN(__s) ((struct sockaddr_in *) __s) -#define SIN6(__s) ((struct sockaddr_in6 *) __s) - -static void -set_port_for_request (struct sockaddr_storage *ss, - ARRAY8 *port) -{ - /* we depend on this being 2 elsewhere as well */ - port->length = 2; - - switch (ss->ss_family) { - case AF_INET: - port->data = (CARD8 *)g_memdup (&(SIN (ss)->sin_port), port->length); - break; - case AF_INET6: - port->data = (CARD8 *)g_memdup (&(SIN6 (ss)->sin6_port), port->length); - break; - default: - port->data = NULL; - break; - } -} - -static void -set_address_for_request (struct sockaddr_storage *ss, - ARRAY8 *address) -{ - - switch (ss->ss_family) { - case AF_INET: - address->length = sizeof (struct in_addr); - address->data = g_memdup (&SIN (ss)->sin_addr, address->length); - break; - case AF_INET6: - address->length = sizeof (struct in6_addr); - address->data = g_memdup (&SIN6 (ss)->sin6_addr, address->length); - break; - default: - address->length = 0; - address->data = NULL; - break; - } - -} - -static void -gdm_xdmcp_send_forward_query (GdmXdmcpManager *manager, - GdmIndirectDisplay *id, - struct sockaddr_storage *clnt_sa, - struct sockaddr_storage *display_addr, - ARRAYofARRAY8Ptr authlist) -{ - struct sockaddr_storage *sa; - XdmcpHeader header; - int i; - ARRAY8 address; - ARRAY8 port; - char *host; - char *serv; - - g_assert (id != NULL); - g_assert (id->chosen_host != NULL); - - gdm_address_get_info (id->chosen_host, &host, NULL); - g_debug ("XDMCP: Sending forward query to %s", - host); - g_free (host); - - gdm_address_get_info (display_addr, &host, &serv); - g_debug ("gdm_xdmcp_send_forward_query: Query contains %s:%s", - host, serv); - g_free (host); - g_free (serv); - - set_port_for_request (clnt_sa, &port); - set_address_for_request (display_addr, &address); - - sa = g_memdup (id->chosen_host, sizeof (id->chosen_host)); - - header.version = XDM_PROTOCOL_VERSION; - header.opcode = (CARD16) FORWARD_QUERY; - header.length = 0; - header.length += 2 + address.length; - header.length += 2 + port.length; - header.length += 1; - for (i = 0; i < authlist->length; i++) { - header.length += 2 + authlist->data[i].length; - } - - XdmcpWriteHeader (&manager->priv->buf, &header); - XdmcpWriteARRAY8 (&manager->priv->buf, &address); - XdmcpWriteARRAY8 (&manager->priv->buf, &port); - XdmcpWriteARRAYofARRAY8 (&manager->priv->buf, authlist); - - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr) sa, - (int)sizeof (struct sockaddr_storage)); - - g_free (port.data); - g_free (address.data); - g_free (sa); -} - -static void -handle_any_query (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - ARRAYofARRAY8Ptr authentication_names, - int type) -{ - gdm_xdmcp_send_willing (manager, clnt_sa); -} - -static void -handle_direct_query (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len, - int type) -{ - ARRAYofARRAY8 clnt_authlist; - int expected_len; - int i; - int res; - - res = XdmcpReadARRAYofARRAY8 (&manager->priv->buf, &clnt_authlist); - if G_UNLIKELY (! res) { - g_warning (_("Could not extract authlist from packet")); - return; - } - - expected_len = 1; - - for (i = 0 ; i < clnt_authlist.length ; i++) { - expected_len += 2 + clnt_authlist.data[i].length; - } - - if (len == expected_len) { - handle_any_query (manager, clnt_sa, &clnt_authlist, type); - } else { - g_warning (_("Error in checksum")); - } - - XdmcpDisposeARRAYofARRAY8 (&clnt_authlist); -} - -static void -gdm_xdmcp_handle_broadcast_query (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - if (gdm_xdmcp_host_allow (clnt_sa)) { - handle_direct_query (manager, clnt_sa, len, BROADCAST_QUERY); - } else { - /* just ignore it */ - } -} - -static void -gdm_xdmcp_handle_query (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - if (gdm_xdmcp_host_allow (clnt_sa)) { - handle_direct_query (manager, clnt_sa, len, QUERY); - } else { - gdm_xdmcp_send_unwilling (manager, clnt_sa, QUERY); - } -} - -static void -gdm_xdmcp_handle_indirect_query (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - ARRAYofARRAY8 clnt_authlist; - int expected_len; - int i; - int res; - - if (! gdm_xdmcp_host_allow (clnt_sa)) { - /* ignore the request */ - return; - } - - if (! manager->priv->honor_indirect) { - /* ignore it */ - return; - } - - res = XdmcpReadARRAYofARRAY8 (&manager->priv->buf, &clnt_authlist); - if G_UNLIKELY (! res) { - g_warning (_("Could not extract authlist from packet")); - return; - } - - expected_len = 1; - - for (i = 0 ; i < clnt_authlist.length ; i++) { - expected_len += 2 + clnt_authlist.data[i].length; - } - - /* Try to look up the display in - * the pending list. If found send a FORWARD_QUERY to the - * chosen manager. Otherwise alloc a new indirect display. */ - - if (len == expected_len) { - GdmIndirectDisplay *id; - - id = gdm_choose_indirect_lookup (clnt_sa); - - if (id != NULL && id->chosen_host != NULL) { - /* if user chose us, then just send willing */ - if (gdm_address_is_local (id->chosen_host)) { - /* get rid of indirect, so that we don't get - * the chooser */ - gdm_choose_indirect_dispose (id); - gdm_xdmcp_send_willing (manager, clnt_sa); - } else if (gdm_address_is_loopback (clnt_sa)) { - /* woohoo! fun, I have no clue how to get - * the correct ip, SO I just send forward - * queries with all the different IPs */ - const GList *list = gdm_address_peek_local_list (); - - while (list != NULL) { - struct sockaddr_storage *saddr = list->data; - - if (! gdm_address_is_loopback (saddr)) { - /* forward query to * chosen host */ - gdm_xdmcp_send_forward_query (manager, - id, - clnt_sa, - saddr, - &clnt_authlist); - } - - list = list->next; - } - } else { - /* or send forward query to chosen host */ - gdm_xdmcp_send_forward_query (manager, - id, - clnt_sa, - clnt_sa, - &clnt_authlist); - } - } else if (id == NULL) { - id = gdm_choose_indirect_alloc (clnt_sa); - if (id != NULL) { - gdm_xdmcp_send_willing (manager, clnt_sa); - } - } else { - gdm_xdmcp_send_willing (manager, clnt_sa); - } - - } else { - g_warning (_("Error in checksum")); - } - - XdmcpDisposeARRAYofARRAY8 (&clnt_authlist); -} - -static void -gdm_forward_query_dispose (GdmXdmcpManager *manager, - GdmForwardQuery *q) -{ - if (q == NULL) { - return; - } - - manager->priv->forward_queries = g_slist_remove (manager->priv->forward_queries, q); - - q->acctime = 0; - - { - char *host; - - gdm_address_get_info (q->dsp_sa, &host, NULL); - g_debug ("gdm_forward_query_dispose: Disposing %s", host); - g_free (host); - } - - g_free (q->dsp_sa); - q->dsp_sa = NULL; - g_free (q->from_sa); - q->from_sa = NULL; - - g_free (q); -} - -static gboolean -remove_oldest_forward (GdmXdmcpManager *manager) -{ - GSList *li; - GdmForwardQuery *oldest = NULL; - - for (li = manager->priv->forward_queries; li != NULL; li = li->next) { - GdmForwardQuery *query = li->data; - - if (oldest == NULL || query->acctime < oldest->acctime) { - oldest = query; - } - } - - if (oldest != NULL) { - gdm_forward_query_dispose (manager, oldest); - return TRUE; - } else { - return FALSE; - } -} - -static GdmForwardQuery * -gdm_forward_query_alloc (GdmXdmcpManager *manager, - struct sockaddr_storage *mgr_sa, - struct sockaddr_storage *dsp_sa) -{ - GdmForwardQuery *q; - int count; - - count = g_slist_length (manager->priv->forward_queries); - - while (count > GDM_MAX_FORWARD_QUERIES && remove_oldest_forward (manager)) { - count--; - } - - q = g_new0 (GdmForwardQuery, 1); - q->dsp_sa = g_memdup (dsp_sa, sizeof (struct sockaddr_storage)); - q->from_sa = g_memdup (mgr_sa, sizeof (struct sockaddr_storage)); - - manager->priv->forward_queries = g_slist_prepend (manager->priv->forward_queries, q); - - return q; -} - -static GdmForwardQuery * -gdm_forward_query_lookup (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa) -{ - GSList *li; - GSList *qlist; - GdmForwardQuery *q; - time_t curtime; - - curtime = time (NULL); - - qlist = g_slist_copy (manager->priv->forward_queries); - - for (li = qlist; li != NULL; li = li->next) { - q = (GdmForwardQuery *) li->data; - - if (q == NULL) - continue; - - if (gdm_address_equal (q->dsp_sa, clnt_sa)) { - g_slist_free (qlist); - return q; - } - - if (q->acctime > 0 && curtime > q->acctime + GDM_FORWARD_QUERY_TIMEOUT) { - char *host; - char *serv; - - gdm_address_get_info (q->dsp_sa, &host, &serv); - - g_debug ("gdm_forward_query_lookup: Disposing stale forward query from %s:%s", - host, serv); - g_free (host); - g_free (serv); - - gdm_forward_query_dispose (manager, q); - continue; - } - } - - g_slist_free (qlist); - - { - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("gdm_forward_query_lookup: Host %s not found", - host); - g_free (host); - } - - return NULL; -} - -static gboolean -create_sa_from_request (ARRAY8 *req_addr, - ARRAY8 *req_port, - int family, - struct sockaddr_storage **sap) -{ - uint16_t port; - char host_buf [NI_MAXHOST]; - char serv_buf [NI_MAXSERV]; - char *serv; - const char *host; - struct addrinfo hints; - struct addrinfo *ai_list; - struct addrinfo *ai; - int gaierr; - gboolean found; - - if (sap != NULL) { - *sap = NULL; - } - - if (req_addr == NULL) { - return FALSE; - } - - serv = NULL; - if (req_port != NULL) { - /* port must always be length 2 */ - if (req_port->length != 2) { - return FALSE; - } - - memcpy (&port, req_port->data, 2); - snprintf (serv_buf, sizeof (serv_buf), "%d", ntohs (port)); - serv = serv_buf; - } else { - /* assume XDM_UDP_PORT */ - snprintf (serv_buf, sizeof (serv_buf), "%d", XDM_UDP_PORT); - serv = serv_buf; - } - - host = NULL; - if (req_addr->length == 4) { - host = inet_ntop (AF_INET, - (const void *)req_addr->data, - host_buf, - sizeof (host_buf)); - } else if (req_addr->length == 16) { - host = inet_ntop (AF_INET6, - (const void *)req_addr->data, - host_buf, - sizeof (host_buf)); - } - - if (host == NULL) { - g_warning (_("Bad address")); - return FALSE; - } - - memset (&hints, 0, sizeof (hints)); - hints.ai_family = family; - hints.ai_flags = AI_V4MAPPED; /* this should convert IPv4 address to IPv6 if needed */ - if ((gaierr = getaddrinfo (host, serv, &hints, &ai_list)) != 0) { - g_warning ("Unable get address: %s", gai_strerror (gaierr)); - return FALSE; - } - - /* just take the first one */ - ai = ai_list; - - found = FALSE; - if (ai != NULL) { - found = TRUE; - if (sap != NULL) { - *sap = g_memdup (ai->ai_addr, ai->ai_addrlen); - } - } - - freeaddrinfo (ai_list); - - return found; -} - -static void -gdm_xdmcp_whack_queued_managed_forwards (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - struct sockaddr_storage *origin) -{ - GSList *li; - - for (li = manager->priv->managed_forwards; li != NULL; li = li->next) { - ManagedForward *mf = li->data; - - if (gdm_address_equal (&mf->manager, clnt_sa) && - gdm_address_equal (&mf->origin, origin)) { - manager->priv->managed_forwards = g_slist_remove_link (manager->priv->managed_forwards, li); - g_slist_free_1 (li); - g_source_remove (mf->handler); - /* mf freed by glib */ - return; - } - } -} - -static void -gdm_xdmcp_handle_forward_query (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - ARRAY8 clnt_addr; - ARRAY8 clnt_port; - ARRAYofARRAY8 clnt_authlist; - int i; - int explen; - struct sockaddr_storage *disp_sa; - char *host; - char *serv; - - disp_sa = NULL; - - /* Check with tcp_wrappers if client is allowed to access */ - if (! gdm_xdmcp_host_allow (clnt_sa)) { - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - - g_warning ("%s: Got FORWARD_QUERY from banned host %s", - "gdm_xdmcp_handle_forward query", - host); - g_free (host); - return; - } - - /* Read display address */ - if G_UNLIKELY (! XdmcpReadARRAY8 (&manager->priv->buf, &clnt_addr)) { - g_warning (_("%s: Could not read display address"), - "gdm_xdmcp_handle_forward_query"); - return; - } - - /* Read display port */ - if G_UNLIKELY (! XdmcpReadARRAY8 (&manager->priv->buf, &clnt_port)) { - XdmcpDisposeARRAY8 (&clnt_addr); - g_warning (_("%s: Could not read display port number"), - "gdm_xdmcp_handle_forward_query"); - return; - } - - /* Extract array of authentication names from Xdmcp packet */ - if G_UNLIKELY (! XdmcpReadARRAYofARRAY8 (&manager->priv->buf, &clnt_authlist)) { - XdmcpDisposeARRAY8 (&clnt_addr); - XdmcpDisposeARRAY8 (&clnt_port); - g_warning (_("%s: Could not extract authlist from packet"), - "gdm_xdmcp_handle_forward_query"); - return; - } - - /* Crude checksumming */ - explen = 1; - explen += 2 + clnt_addr.length; - explen += 2 + clnt_port.length; - - for (i = 0 ; i < clnt_authlist.length ; i++) { - char *s = g_strndup ((char *) clnt_authlist.data[i].data, - clnt_authlist.length); - g_debug ("gdm_xdmcp_handle_forward_query: authlist: %s", s); - g_free (s); - - explen += 2 + clnt_authlist.data[i].length; - } - - if G_UNLIKELY (len != explen) { - g_warning (_("%s: Error in checksum"), - "gdm_xdmcp_handle_forward_query"); - goto out; - } - - if (! create_sa_from_request (&clnt_addr, &clnt_port, clnt_sa->ss_family, &disp_sa)) { - g_warning ("Unable to parse address for request"); - goto out; - } - - gdm_xdmcp_whack_queued_managed_forwards (manager, - clnt_sa, - disp_sa); - - gdm_address_get_info (disp_sa, &host, &serv); - g_debug ("gdm_xdmcp_handle_forward_query: Got FORWARD_QUERY for display: %s, port %s", - host, serv); - g_free (host); - g_free (serv); - - /* Check with tcp_wrappers if display is allowed to access */ - if (gdm_xdmcp_host_allow (disp_sa)) { - GdmForwardQuery *q; - - q = gdm_forward_query_lookup (manager, disp_sa); - if (q != NULL) - gdm_forward_query_dispose (manager, q); - - gdm_forward_query_alloc (manager, clnt_sa, disp_sa); - - gdm_xdmcp_send_willing (manager, disp_sa); - } - - out: - - g_free (disp_sa); - XdmcpDisposeARRAYofARRAY8 (&clnt_authlist); - XdmcpDisposeARRAY8 (&clnt_port); - XdmcpDisposeARRAY8 (&clnt_addr); -} - -static void -gdm_xdmcp_really_send_managed_forward (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - struct sockaddr_storage *origin) -{ - ARRAY8 address; - XdmcpHeader header; - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("XDMCP: Sending MANAGED_FORWARD to %s", host); - g_free (host); - - set_address_for_request (origin, &address); - - header.opcode = (CARD16) GDM_XDMCP_MANAGED_FORWARD; - header.length = 4 + address.length; - header.version = GDM_XDMCP_PROTOCOL_VERSION; - XdmcpWriteHeader (&manager->priv->buf, &header); - - XdmcpWriteARRAY8 (&manager->priv->buf, &address); - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); - - g_free (address.data); -} - -static gboolean -managed_forward_handler (ManagedForward *mf) -{ - if (mf->xdmcp_manager->priv->socket_fd > 0) { - gdm_xdmcp_really_send_managed_forward (mf->xdmcp_manager, - &(mf->manager), - &(mf->origin)); - } - - mf->times++; - if (mf->xdmcp_manager->priv->socket_fd <= 0 || mf->times >= 2) { - mf->xdmcp_manager->priv->managed_forwards = g_slist_remove (mf->xdmcp_manager->priv->managed_forwards, mf); - mf->handler = 0; - /* mf freed by glib */ - return FALSE; - } - return TRUE; -} - -static void -gdm_xdmcp_send_managed_forward (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - struct sockaddr_storage *origin) -{ - ManagedForward *mf; - - gdm_xdmcp_really_send_managed_forward (manager, clnt_sa, origin); - - mf = g_new0 (ManagedForward, 1); - mf->times = 0; - mf->xdmcp_manager = manager; - - memcpy (&(mf->manager), clnt_sa, sizeof (struct sockaddr_storage)); - memcpy (&(mf->origin), origin, sizeof (struct sockaddr_storage)); - - mf->handler = g_timeout_add_full (G_PRIORITY_DEFAULT, - MANAGED_FORWARD_INTERVAL, - (GSourceFunc)managed_forward_handler, - mf, - (GDestroyNotify) g_free); - manager->priv->managed_forwards = g_slist_prepend (manager->priv->managed_forwards, mf); -} - -static void -gdm_xdmcp_send_got_managed_forward (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - struct sockaddr_storage *origin) -{ - ARRAY8 address; - XdmcpHeader header; - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("XDMCP: Sending GOT_MANAGED_FORWARD to %s", host); - g_free (host); - - set_address_for_request (origin, &address); - - header.opcode = (CARD16) GDM_XDMCP_GOT_MANAGED_FORWARD; - header.length = 4 + address.length; - header.version = GDM_XDMCP_PROTOCOL_VERSION; - XdmcpWriteHeader (&manager->priv->buf, &header); - - XdmcpWriteARRAY8 (&manager->priv->buf, &address); - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); -} - -static void -gdm_xdmcp_recount_sessions (GdmXdmcpManager *manager) -{ - GSList *li; - GSList *displays; - - displays = gdm_daemon_config_get_display_list (); - - manager->priv->num_sessions = 0; - manager->priv->num_pending_sessions = 0; - - for (li = displays; li != NULL; li = li->next) { - GdmDisplay *d = li->data; - if (SERVER_IS_XDMCP (d)) { - if (d->dispstat == XDMCP_MANAGED) - manager->priv->num_sessions++; - else if (d->dispstat == XDMCP_PENDING) - manager->priv->num_pending_sessions++; - } - } -} - -static void -gdm_xdmcp_displays_purge (GdmXdmcpManager *manager) -{ - GSList *dlist; - time_t curtime = time (NULL); - GSList *displays; - gboolean sess_dirty = FALSE; - - displays = gdm_daemon_config_get_display_list (); - - dlist = displays; - while (dlist != NULL) { - GdmDisplay *d = dlist->data; - - if (d != NULL && - SERVER_IS_XDMCP (d) && - d->dispstat == XDMCP_PENDING && - curtime > d->acctime + manager->priv->max_wait) { - g_debug ("gdm_xdmcp_displays_purge: Disposing session id %ld", - (long)d->sessionid); - gdm_display_dispose (d); - sess_dirty = TRUE; - - /* restart as the list is now broken */ - dlist = displays; - } else { - /* just go on */ - dlist = dlist->next; - } - } - - /* Recount sessions only if dirty */ - if (sess_dirty) { - gdm_xdmcp_recount_sessions (manager); - } -} - -static void -gdm_xdmcp_display_dispose_check (GdmXdmcpManager *manager, - const char *hostname, - int dspnum) -{ - GSList *dlist; - GSList *displays; - gboolean sess_dirty = FALSE; - - if (hostname == NULL) { - return; - } - - g_debug ("gdm_xdmcp_display_dispose_check (%s:%d)", hostname, dspnum); - - displays = gdm_daemon_config_get_display_list (); - - dlist = displays; - while (dlist != NULL) { - GdmDisplay *d = dlist->data; - - if (d != NULL && - SERVER_IS_XDMCP (d) && - d->xdmcp_dispnum == dspnum && - strcmp (d->hostname, hostname) == 0) { - - if (d->dispstat == XDMCP_MANAGED) { - gdm_display_unmanage (d); - } else { - gdm_display_dispose (d); - sess_dirty = TRUE; - } - - /* restart as the list is now broken */ - dlist = displays; - } else { - /* just go on */ - dlist = dlist->next; - } - } - - /* Recount sessions only if dirty */ - if (sess_dirty) { - gdm_xdmcp_recount_sessions (manager); - } -} - -static void -gdm_xdmcp_send_decline (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - const char *reason) -{ - XdmcpHeader header; - ARRAY8 authentype; - ARRAY8 authendata; - ARRAY8 status; - GdmForwardQuery *fq; - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("XDMCP: Sending DECLINE to %s", host); - g_free (host); - - authentype.data = (CARD8 *) 0; - authentype.length = (CARD16) 0; - - authendata.data = (CARD8 *) 0; - authendata.length = (CARD16) 0; - - status.data = (CARD8 *) reason; - status.length = strlen ((char *) status.data); - - header.version = XDM_PROTOCOL_VERSION; - header.opcode = (CARD16) DECLINE; - header.length = 2 + status.length; - header.length += 2 + authentype.length; - header.length += 2 + authendata.length; - - XdmcpWriteHeader (&manager->priv->buf, &header); - XdmcpWriteARRAY8 (&manager->priv->buf, &status); - XdmcpWriteARRAY8 (&manager->priv->buf, &authentype); - XdmcpWriteARRAY8 (&manager->priv->buf, &authendata); - - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); - - /* Send MANAGED_FORWARD to indicate that the connection - * reached some sort of resolution */ - fq = gdm_forward_query_lookup (manager, clnt_sa); - if (fq != NULL) { - gdm_xdmcp_send_managed_forward (manager, fq->from_sa, clnt_sa); - gdm_forward_query_dispose (manager, fq); - } -} - -static GdmDisplay * -gdm_xdmcp_display_alloc (GdmXdmcpManager *manager, - struct sockaddr_storage *addr, - GdmHostent *he /* eaten and freed */, - int displaynum) -{ - GdmDisplay *d = NULL; - const char *proxycmd; - gboolean use_proxy = FALSE; - - proxycmd = NULL; - use_proxy = FALSE; -#if 0 - proxycmd = gdm_daemon_config_get_value_string (GDM_KEY_XDMCP_PROXY_XSERVER); - use_proxy = FALSE; -#endif - d = g_new0 (GdmDisplay, 1); - - if (use_proxy && proxycmd != NULL) { - d->type = TYPE_XDMCP_PROXY; - d->command = g_strdup (proxycmd); - g_debug ("Using proxy server for XDMCP: %s\n", d->command); - } else { - d->type = TYPE_XDMCP; - } - - d->logout_action = GDM_LOGOUT_ACTION_NONE; - d->authfile = NULL; - d->auths = NULL; - d->userauth = NULL; - d->greetpid = 0; - d->servpid = 0; - d->servstat = 0; - d->sesspid = 0; - d->slavepid = 0; - d->attached = FALSE; - d->dispstat = XDMCP_PENDING; - d->sessionid = get_next_session_serial (manager); - - d->acctime = time (NULL); - d->dispnum = displaynum; - d->xdmcp_dispnum = displaynum; - - d->handled = TRUE; - d->tcp_disallowed = FALSE; - d->vt = -1; - d->vtnum = -1; - d->x_servers_order = -1; - d->logged_in = FALSE; - d->login = NULL; - d->sleep_before_run = 0; - - if (gdm_daemon_config_get_value_bool (GDM_KEY_ALLOW_REMOTE_AUTOLOGIN) && - ! ve_string_empty (gdm_daemon_config_get_value_string (GDM_KEY_TIMED_LOGIN))) { - d->timed_login_ok = TRUE; - } else { - d->timed_login_ok = FALSE; - } - - d->name = g_strdup_printf ("%s:%d", - he->hostname, - displaynum); - - memcpy (&d->addr, addr, sizeof (struct sockaddr_storage)); - - d->hostname = he->hostname; - he->hostname = NULL; - d->addrs = he->addrs; - he->addrs = NULL; - d->addr_count = he->addr_count; - he->addr_count = 0; - - gdm_hostent_free (he); - - d->windowpath = NULL; - d->slave_notify_fd = -1; - d->master_notify_fd = -1; - d->xsession_errors_bytes = 0; - d->xsession_errors_fd = -1; - d->session_output_fd = -1; - d->chooser_output_fd = -1; - d->chooser_last_line = NULL; - d->theme_name = NULL; - - /* Secure display with cookie */ - if G_UNLIKELY (! gdm_auth_secure_display (d)) { - g_warning ("gdm_xdmcp_display_alloc: Error setting up cookies for %s", - d->name); - } - - if (d->type == TYPE_XDMCP_PROXY) { - d->parent_disp = d->name; - d->name = g_strdup (":-1"); - d->dispnum = -1; - d->server_uid = gdm_daemon_config_get_gdmuid (); - d->parent_auth_file = d->authfile; - d->authfile = NULL; - } - - gdm_daemon_config_display_list_append (d); - - manager->priv->num_pending_sessions++; - - g_debug ("gdm_xdmcp_display_alloc: display=%s, session id=%ld, xdmcp_pending=%d", - d->name, (long)d->sessionid, manager->priv->num_pending_sessions); - - return d; -} - -static void -gdm_xdmcp_send_accept (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - CARD32 session_id, - ARRAY8Ptr authentication_name, - ARRAY8Ptr authentication_data, - ARRAY8Ptr authorization_name, - ARRAY8Ptr authorization_data) -{ - XdmcpHeader header; - char *host; - - header.version = XDM_PROTOCOL_VERSION; - header.opcode = (CARD16) ACCEPT; - header.length = 4; - header.length += 2 + authentication_name->length; - header.length += 2 + authentication_data->length; - header.length += 2 + authorization_name->length; - header.length += 2 + authorization_data->length; - - XdmcpWriteHeader (&manager->priv->buf, &header); - XdmcpWriteCARD32 (&manager->priv->buf, session_id); - XdmcpWriteARRAY8 (&manager->priv->buf, authentication_name); - XdmcpWriteARRAY8 (&manager->priv->buf, authentication_data); - XdmcpWriteARRAY8 (&manager->priv->buf, authorization_name); - XdmcpWriteARRAY8 (&manager->priv->buf, authorization_data); - - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("XDMCP: Sending ACCEPT to %s with SessionID=%ld", - host, - (long)session_id); - g_free (host); -} - -static void -gdm_xdmcp_handle_request (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - CARD16 clnt_dspnum; - ARRAY16 clnt_conntyp; - ARRAYofARRAY8 clnt_addr; - ARRAY8 clnt_authname; - ARRAY8 clnt_authdata; - ARRAYofARRAY8 clnt_authorization; - ARRAY8 clnt_manufacturer; - int explen; - int i; - gboolean mitauth; - gboolean entered; - char *host; - - mitauth = FALSE; - entered = FALSE; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("gdm_xdmcp_handle_request: Got REQUEST from %s", host); - - /* Check with tcp_wrappers if client is allowed to access */ - if (! gdm_xdmcp_host_allow (clnt_sa)) { - g_warning (_("%s: Got REQUEST from banned host %s"), - "gdm_xdmcp_handle_request", - host); - g_free (host); - return; - } - g_free (host); - - gdm_xdmcp_displays_purge (manager); /* Purge pending displays */ - - /* Update num_sessions only if the length of the list that contain - * them is smaller */ - if (g_list_length (gdm_daemon_config_get_display_list()) < manager->priv->num_sessions ){ - gdm_xdmcp_recount_sessions (manager); - } - - /* Remote display number */ - if G_UNLIKELY (! XdmcpReadCARD16 (&manager->priv->buf, &clnt_dspnum)) { - g_warning (_("%s: Could not read Display Number"), - "gdm_xdmcp_handle_request"); - return; - } - - /* We don't care about connection type. Address says it all */ - if G_UNLIKELY (! XdmcpReadARRAY16 (&manager->priv->buf, &clnt_conntyp)) { - g_warning (_("%s: Could not read Connection Type"), - "gdm_xdmcp_handle_request"); - return; - } - - /* This is TCP/IP - we don't care */ - if G_UNLIKELY (! XdmcpReadARRAYofARRAY8 (&manager->priv->buf, &clnt_addr)) { - g_warning (_("%s: Could not read Client Address"), - "gdm_xdmcp_handle_request"); - XdmcpDisposeARRAY16 (&clnt_conntyp); - return; - } - - /* Read authentication type */ - if G_UNLIKELY (! XdmcpReadARRAY8 (&manager->priv->buf, &clnt_authname)) { - g_warning (_("%s: Could not read Authentication Names"), - "gdm_xdmcp_handle_request"); - XdmcpDisposeARRAYofARRAY8 (&clnt_addr); - XdmcpDisposeARRAY16 (&clnt_conntyp); - return; - } - - /* Read authentication data */ - if G_UNLIKELY (! XdmcpReadARRAY8 (&manager->priv->buf, &clnt_authdata)) { - g_warning (_("%s: Could not read Authentication Data"), - "gdm_xdmcp_handle_request"); - XdmcpDisposeARRAYofARRAY8 (&clnt_addr); - XdmcpDisposeARRAY16 (&clnt_conntyp); - XdmcpDisposeARRAY8 (&clnt_authname); - return; - } - - /* Read and select from supported authorization list */ - if G_UNLIKELY (! XdmcpReadARRAYofARRAY8 (&manager->priv->buf, &clnt_authorization)) { - g_warning (_("%s: Could not read Authorization List"), - "gdm_xdmcp_handle_request"); - XdmcpDisposeARRAY8 (&clnt_authdata); - XdmcpDisposeARRAYofARRAY8 (&clnt_addr); - XdmcpDisposeARRAY16 (&clnt_conntyp); - XdmcpDisposeARRAY8 (&clnt_authname); - return; - } - - /* libXdmcp doesn't terminate strings properly so we cheat and use strncmp () */ - for (i = 0 ; i < clnt_authorization.length ; i++) - if (clnt_authorization.data[i].length == 18 && - strncmp ((char *) clnt_authorization.data[i].data, - "MIT-MAGIC-COOKIE-1", 18) == 0) - mitauth = TRUE; - - /* Manufacturer ID */ - if G_UNLIKELY (! XdmcpReadARRAY8 (&manager->priv->buf, &clnt_manufacturer)) { - g_warning (_("%s: Could not read Manufacturer ID"), - "gdm_xdmcp_handle_request"); - XdmcpDisposeARRAY8 (&clnt_authname); - XdmcpDisposeARRAY8 (&clnt_authdata); - XdmcpDisposeARRAYofARRAY8 (&clnt_addr); - XdmcpDisposeARRAYofARRAY8 (&clnt_authorization); - XdmcpDisposeARRAY16 (&clnt_conntyp); - return; - } - - /* Crude checksumming */ - explen = 2; /* Display Number */ - explen += 1 + 2 * clnt_conntyp.length; /* Connection Type */ - explen += 1; /* Connection Address */ - for (i = 0 ; i < clnt_addr.length ; i++) - explen += 2 + clnt_addr.data[i].length; - explen += 2 + clnt_authname.length; /* Authentication Name */ - explen += 2 + clnt_authdata.length; /* Authentication Data */ - explen += 1; /* Authorization Names */ - for (i = 0 ; i < clnt_authorization.length ; i++) - explen += 2 + clnt_authorization.data[i].length; - explen += 2 + clnt_manufacturer.length; - - if G_UNLIKELY (explen != len) { - gdm_address_get_info (clnt_sa, &host, NULL); - g_warning (_("%s: Failed checksum from %s"), - "gdm_xdmcp_handle_request", - host); - g_free (host); - - XdmcpDisposeARRAY8 (&clnt_authname); - XdmcpDisposeARRAY8 (&clnt_authdata); - XdmcpDisposeARRAY8 (&clnt_manufacturer); - XdmcpDisposeARRAYofARRAY8 (&clnt_addr); - XdmcpDisposeARRAYofARRAY8 (&clnt_authorization); - XdmcpDisposeARRAY16 (&clnt_conntyp); - return; - } - - { - char *s = g_strndup ((char *) clnt_manufacturer.data, clnt_manufacturer.length); - g_debug ("gdm_xdmcp_handle_request: xdmcp_pending=%d, MaxPending=%d, xdmcp_sessions=%d, MaxSessions=%d, ManufacturerID=%s", - manager->priv->num_pending_sessions, - manager->priv->max_pending_displays, - manager->priv->num_sessions, - manager->priv->max_displays, - ve_sure_string (s)); - g_free (s); - } - - /* Check if ok to manage display */ - if (mitauth && - manager->priv->num_sessions < manager->priv->max_displays && - (gdm_address_is_local (clnt_sa) || - gdm_xdmcp_num_displays_from_host (manager, clnt_sa) < manager->priv->max_displays_per_host)) { - entered = TRUE; - } - - if (entered) { - GdmHostent *he; - he = gdm_gethostbyaddr (clnt_sa); - - /* Check if we are already talking to this host */ - gdm_xdmcp_display_dispose_check (manager, he->hostname, clnt_dspnum); - - if (manager->priv->num_pending_sessions >= manager->priv->max_pending_displays) { - g_debug ("gdm_xdmcp_handle_request: maximum pending"); - /* Don't translate, this goes over the wire to servers where we - * don't know the charset or language, so it must be ascii */ - gdm_xdmcp_send_decline (manager, clnt_sa, "Maximum pending servers"); - gdm_hostent_free (he); - } else { - GdmDisplay *d; - - d = gdm_xdmcp_display_alloc (manager, - clnt_sa, - he /* eaten and freed */, - clnt_dspnum); - if (d != NULL) { - ARRAY8 authentication_name; - ARRAY8 authentication_data; - ARRAY8 authorization_name; - ARRAY8 authorization_data; - - authentication_name.data = NULL; - authentication_name.length = 0; - authentication_data.data = NULL; - authentication_data.length = 0; - - authorization_name.data = (CARD8 *) "MIT-MAGIC-COOKIE-1"; - authorization_name.length = strlen ((char *) authorization_name.data); - - authorization_data.data = (CARD8 *) d->bcookie; - authorization_data.length = 16; - - /* the addrs are NOT copied */ - gdm_xdmcp_send_accept (manager, - clnt_sa, - d->sessionid, - &authentication_name, - &authentication_data, - &authorization_name, - &authorization_data); - } - } - } else { - /* Don't translate, this goes over the wire to servers where we - * don't know the charset or language, so it must be ascii */ - if ( ! mitauth) { - gdm_xdmcp_send_decline (manager, - clnt_sa, - "Only MIT-MAGIC-COOKIE-1 supported"); - } else if (manager->priv->num_sessions >= manager->priv->max_displays) { - g_warning ("Maximum number of open XDMCP sessions reached"); - gdm_xdmcp_send_decline (manager, - clnt_sa, - "Maximum number of open sessions reached"); - } else { - g_debug ("Maximum number of open XDMCP sessions from host %s reached", - host); - gdm_xdmcp_send_decline (manager, - clnt_sa, - "Maximum number of open sessions from your host reached"); - } - } - - XdmcpDisposeARRAY8 (&clnt_authname); - XdmcpDisposeARRAY8 (&clnt_authdata); - XdmcpDisposeARRAY8 (&clnt_manufacturer); - XdmcpDisposeARRAYofARRAY8 (&clnt_addr); - XdmcpDisposeARRAYofARRAY8 (&clnt_authorization); - XdmcpDisposeARRAY16 (&clnt_conntyp); -} - -static GdmDisplay * -gdm_xdmcp_display_lookup (GdmXdmcpManager *manager, - CARD32 sessid) -{ - GSList *l; - GdmDisplay *d; - GSList *displays; - - if (sessid == 0) { - return (NULL); - } - - displays = gdm_daemon_config_get_display_list (); - - l = displays; - while (l != NULL) { - d = (GdmDisplay *) l->data; - - if (d && d->sessionid == sessid) { - return (d); - } - - l = l->next; - } - - return (NULL); -} - -static void -gdm_xdmcp_send_failed (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - CARD32 sessid) -{ - XdmcpHeader header; - ARRAY8 status; - - g_debug ("XDMCP: Sending FAILED to %ld", (long)sessid); - - /* - * Don't translate, this goes over the wire to servers where we - * don't know the charset or language, so it must be ascii - */ - status.data = (CARD8 *) "Failed to start session"; - status.length = strlen ((char *) status.data); - - header.version = XDM_PROTOCOL_VERSION; - header.opcode = (CARD16) FAILED; - header.length = 6+status.length; - - XdmcpWriteHeader (&manager->priv->buf, &header); - XdmcpWriteCARD32 (&manager->priv->buf, sessid); - XdmcpWriteARRAY8 (&manager->priv->buf, &status); - - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); -} - -static void -gdm_xdmcp_send_refuse (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - CARD32 sessid) -{ - XdmcpHeader header; - GdmForwardQuery *fq; - - g_debug ("XDMCP: Sending REFUSE to %ld", - (long)sessid); - - header.version = XDM_PROTOCOL_VERSION; - header.opcode = (CARD16) REFUSE; - header.length = 4; - - XdmcpWriteHeader (&manager->priv->buf, &header); - XdmcpWriteCARD32 (&manager->priv->buf, sessid); - - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); - - /* - * This was from a forwarded query quite apparently so - * send MANAGED_FORWARD - */ - fq = gdm_forward_query_lookup (manager, clnt_sa); - if (fq != NULL) { - gdm_xdmcp_send_managed_forward (manager, fq->from_sa, clnt_sa); - gdm_forward_query_dispose (manager, fq); - } -} - -static void -gdm_xdmcp_handle_manage (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - CARD32 clnt_sessid; - CARD16 clnt_dspnum; - ARRAY8 clnt_dspclass; - GdmDisplay *d; - GdmIndirectDisplay *id; - GdmForwardQuery *fq; - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("gdm_xdmcp_handle_manage: Got MANAGE from %s", host); - - /* Check with tcp_wrappers if client is allowed to access */ - if (! gdm_xdmcp_host_allow (clnt_sa)) { - g_warning (_("%s: Got Manage from banned host %s"), - "gdm_xdmcp_handle_manage", - host); - g_free (host); - return; - } - g_free (host); - - /* SessionID */ - if G_UNLIKELY (! XdmcpReadCARD32 (&manager->priv->buf, &clnt_sessid)) { - g_warning (_("%s: Could not read Session ID"), - "gdm_xdmcp_handle_manage"); - return; - } - - /* Remote display number */ - if G_UNLIKELY (! XdmcpReadCARD16 (&manager->priv->buf, &clnt_dspnum)) { - g_warning (_("%s: Could not read Display Number"), - "gdm_xdmcp_handle_manage"); - return; - } - - /* Display Class */ - if G_UNLIKELY (! XdmcpReadARRAY8 (&manager->priv->buf, &clnt_dspclass)) { - g_warning (_("%s: Could not read Display Class"), - "gdm_xdmcp_handle_manage"); - return; - } - - if G_UNLIKELY (gdm_daemon_config_get_value_bool (GDM_KEY_DEBUG)) { - char *s = g_strndup ((char *) clnt_dspclass.data, clnt_dspclass.length); - g_debug ("gdm_xdmcp-handle_manage: Got display=%d, SessionID=%ld Class=%s from %s", - (int)clnt_dspnum, (long)clnt_sessid, ve_sure_string (s), host); - - g_free (s); - } - - d = gdm_xdmcp_display_lookup (manager, clnt_sessid); - if (d != NULL && - d->dispstat == XDMCP_PENDING) { - - g_debug ("gdm_xdmcp_handle_manage: Looked up %s", d->name); - - if (gdm_daemon_config_get_value_bool (GDM_KEY_INDIRECT)) { - id = gdm_choose_indirect_lookup (clnt_sa); - - /* This was an indirect thingie and nothing was yet chosen, - * use a chooser */ - if (d->dispstat == XDMCP_PENDING && - id != NULL && - id->chosen_host == NULL) { - d->use_chooser = TRUE; - d->indirect_id = id->id; - } else { - d->indirect_id = 0; - d->use_chooser = FALSE; - if (id != NULL) - gdm_choose_indirect_dispose (id); - } - } else { - d->indirect_id = 0; - d->use_chooser = FALSE; - } - - /* this was from a forwarded query quite apparently so - * send MANAGED_FORWARD */ - fq = gdm_forward_query_lookup (manager, clnt_sa); - if (fq != NULL) { - gdm_xdmcp_send_managed_forward (manager, fq->from_sa, clnt_sa); - gdm_forward_query_dispose (manager, fq); - } - - d->dispstat = XDMCP_MANAGED; - manager->priv->num_sessions++; - manager->priv->num_pending_sessions--; - - /* Start greeter/session */ - if G_UNLIKELY (!gdm_display_manage (d)) { - gdm_xdmcp_send_failed (manager, clnt_sa, clnt_sessid); - XdmcpDisposeARRAY8 (&clnt_dspclass); - return; - } - } else if G_UNLIKELY (d != NULL && d->dispstat == XDMCP_MANAGED) { - g_debug ("gdm_xdmcp_handle_manage: Session id %ld already managed", - (long)clnt_sessid); - } else { - g_warning ("gdm_xdmcp_handle_manage: Failed to look up session id %ld", - (long)clnt_sessid); - gdm_xdmcp_send_refuse (manager, clnt_sa, clnt_sessid); - } - - XdmcpDisposeARRAY8 (&clnt_dspclass); -} - -static void -gdm_xdmcp_handle_managed_forward (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - ARRAY8 clnt_address; - GdmIndirectDisplay *id; - char *host; - struct sockaddr_storage *disp_sa; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("gdm_xdmcp_handle_managed_forward: Got MANAGED_FORWARD from %s", - host); - - /* Check with tcp_wrappers if client is allowed to access */ - if (! gdm_xdmcp_host_allow (clnt_sa)) { - g_warning ("%s: Got MANAGED_FORWARD from banned host %s", - "gdm_xdmcp_handle_request", host); - g_free (host); - return; - } - g_free (host); - - /* Hostname */ - if G_UNLIKELY ( ! XdmcpReadARRAY8 (&manager->priv->buf, &clnt_address)) { - g_warning (_("%s: Could not read address"), - "gdm_xdmcp_handle_managed_forward"); - return; - } - - disp_sa = NULL; - if (! create_sa_from_request (&clnt_address, NULL, clnt_sa->ss_family, &disp_sa)) { - g_warning ("Unable to parse address for request"); - XdmcpDisposeARRAY8 (&clnt_address); - return; - } - - id = gdm_choose_indirect_lookup_by_chosen (clnt_sa, disp_sa); - if (id != NULL) { - gdm_choose_indirect_dispose (id); - } - - /* Note: we send GOT even on not found, just in case our previous - * didn't get through and this was a second managed forward */ - gdm_xdmcp_send_got_managed_forward (manager, clnt_sa, disp_sa); - - XdmcpDisposeARRAY8 (&clnt_address); -} - -static void -gdm_xdmcp_handle_got_managed_forward (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - struct sockaddr_storage *disp_sa; - ARRAY8 clnt_address; - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("gdm_xdmcp_handle_got_managed_forward: Got MANAGED_FORWARD from %s", - host); - - if (! gdm_xdmcp_host_allow (clnt_sa)) { - g_warning ("%s: Got GOT_MANAGED_FORWARD from banned host %s", - "gdm_xdmcp_handle_request", host); - g_free (host); - return; - } - g_free (host); - - /* Hostname */ - if G_UNLIKELY ( ! XdmcpReadARRAY8 (&manager->priv->buf, &clnt_address)) { - g_warning (_("%s: Could not read address"), - "gdm_xdmcp_handle_got_managed_forward"); - return; - } - - if (! create_sa_from_request (&clnt_address, NULL, clnt_sa->ss_family, &disp_sa)) { - g_warning (_("%s: Could not read address"), - "gdm_xdmcp_handle_got_managed_forward"); - XdmcpDisposeARRAY8 (&clnt_address); - return; - } - - gdm_xdmcp_whack_queued_managed_forwards (manager, clnt_sa, disp_sa); - - XdmcpDisposeARRAY8 (&clnt_address); -} - -static void -gdm_xdmcp_send_alive (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - CARD16 dspnum, - CARD32 sessid) -{ - XdmcpHeader header; - GdmDisplay *d; - int send_running = 0; - CARD32 send_sessid = 0; - - d = gdm_xdmcp_display_lookup (manager, sessid); - if (d == NULL) { - d = gdm_xdmcp_display_lookup_by_host (manager, clnt_sa, dspnum); - } - - if (d != NULL) { - send_sessid = d->sessionid; - if (d->dispstat == XDMCP_MANAGED) { - send_running = 1; - } - } - - g_debug ("XDMCP: Sending ALIVE to %ld (running %d, sessid %ld)", - (long)sessid, - send_running, - (long)send_sessid); - - header.version = XDM_PROTOCOL_VERSION; - header.opcode = (CARD16) ALIVE; - header.length = 5; - - XdmcpWriteHeader (&manager->priv->buf, &header); - XdmcpWriteCARD8 (&manager->priv->buf, send_running); - XdmcpWriteCARD32 (&manager->priv->buf, send_sessid); - - XdmcpFlush (manager->priv->socket_fd, - &manager->priv->buf, - (XdmcpNetaddr)clnt_sa, - (int)sizeof (struct sockaddr_storage)); -} - -static void -gdm_xdmcp_handle_keepalive (GdmXdmcpManager *manager, - struct sockaddr_storage *clnt_sa, - int len) -{ - CARD16 clnt_dspnum; - CARD32 clnt_sessid; - char *host; - - gdm_address_get_info (clnt_sa, &host, NULL); - g_debug ("XDMCP: Got KEEPALIVE from %s", host); - - /* Check with tcp_wrappers if client is allowed to access */ - if (! gdm_xdmcp_host_allow (clnt_sa)) { - g_warning (_("%s: Got KEEPALIVE from banned host %s"), - "gdm_xdmcp_handle_keepalive", - host); - g_free (host); - return; - } - g_free (host); - - /* Remote display number */ - if G_UNLIKELY (! XdmcpReadCARD16 (&manager->priv->buf, &clnt_dspnum)) { - g_warning (_("%s: Could not read Display Number"), - "gdm_xdmcp_handle_keepalive"); - return; - } - - /* SessionID */ - if G_UNLIKELY (! XdmcpReadCARD32 (&manager->priv->buf, &clnt_sessid)) { - g_warning (_("%s: Could not read Session ID"), - "gdm_xdmcp_handle_keepalive"); - return; - } - - gdm_xdmcp_send_alive (manager, clnt_sa, clnt_dspnum, clnt_sessid); -} - -static const char * -opcode_string (int opcode) -{ - static const char * const opcode_names[] = { - NULL, - "BROADCAST_QUERY", - "QUERY", - "INDIRECT_QUERY", - "FORWARD_QUERY", - "WILLING", - "UNWILLING", - "REQUEST", - "ACCEPT", - "DECLINE", - "MANAGE", - "REFUSE", - "FAILED", - "KEEPALIVE", - "ALIVE" - }; - static const char * const gdm_opcode_names[] = { - "MANAGED_FORWARD", - "GOT_MANAGED_FORWARD" - }; - - - if (opcode < G_N_ELEMENTS (opcode_names)) { - return opcode_names [opcode]; - } else if (opcode >= GDM_XDMCP_FIRST_OPCODE && - opcode < GDM_XDMCP_LAST_OPCODE) { - return gdm_opcode_names [opcode - GDM_XDMCP_FIRST_OPCODE]; - } else { - return "UNKNOWN"; - } -} - -static gboolean -decode_packet (GIOChannel *source, - GIOCondition cond, - GdmXdmcpManager *manager) -{ - struct sockaddr_storage clnt_sa; - gint sa_len; - XdmcpHeader header; - char *host; - char *port; - int res; - - sa_len = sizeof (clnt_sa); - - g_debug ("decode_packet: GIOCondition %d", (int)cond); - - if ( ! (cond & G_IO_IN)) { - return TRUE; - } - - res = XdmcpFill (manager->priv->socket_fd, &manager->priv->buf, (XdmcpNetaddr)&clnt_sa, &sa_len); - if G_UNLIKELY (! res) { - g_debug (_("XDMCP: Could not create XDMCP buffer!")); - return TRUE; - } - - res = XdmcpReadHeader (&manager->priv->buf, &header); - if G_UNLIKELY (! res) { - g_warning (_("XDMCP: Could not read XDMCP header!")); - return TRUE; - } - - if G_UNLIKELY (header.version != XDM_PROTOCOL_VERSION && - header.version != GDM_XDMCP_PROTOCOL_VERSION) { - g_warning (_("XDMCP: Incorrect XDMCP version!")); - return TRUE; - } - - gdm_address_get_info (&clnt_sa, &host, &port); - - g_debug ("XDMCP: Received opcode %s from client %s : %s", - opcode_string (header.opcode), - host, - port); - - switch (header.opcode) { - case BROADCAST_QUERY: - gdm_xdmcp_handle_broadcast_query (manager, &clnt_sa, header.length); - break; - - case QUERY: - gdm_xdmcp_handle_query (manager, &clnt_sa, header.length); - break; - - case INDIRECT_QUERY: - gdm_xdmcp_handle_indirect_query (manager, &clnt_sa, header.length); - break; - - case FORWARD_QUERY: - gdm_xdmcp_handle_forward_query (manager, &clnt_sa, header.length); - break; - - case REQUEST: - gdm_xdmcp_handle_request (manager, &clnt_sa, header.length); - break; - - case MANAGE: - gdm_xdmcp_handle_manage (manager, &clnt_sa, header.length); - break; - - case KEEPALIVE: - gdm_xdmcp_handle_keepalive (manager, &clnt_sa, header.length); - break; - - case GDM_XDMCP_MANAGED_FORWARD: - gdm_xdmcp_handle_managed_forward (manager, &clnt_sa, header.length); - break; - - case GDM_XDMCP_GOT_MANAGED_FORWARD: - gdm_xdmcp_handle_got_managed_forward (manager, &clnt_sa, header.length); - break; - - default: - g_debug ("XDMCP: Unknown opcode from client %s : %s", - host, - port); - - break; - } - - g_free (host); - g_free (port); - - return TRUE; -} - -gboolean -gdm_xdmcp_manager_start (GdmXdmcpManager *manager, - GError **error) -{ - gboolean ret; - GIOChannel *ioc; - - g_return_val_if_fail (GDM_IS_XDMCP_MANAGER (manager), FALSE); - g_return_val_if_fail (manager->priv->socket_fd == -1, FALSE); - - ret = open_port (manager); - if (! ret) { - return ret; - } - - g_debug ("XDMCP: Starting to listen on XDMCP port"); - - ioc = g_io_channel_unix_new (manager->priv->socket_fd); - - g_io_channel_set_encoding (ioc, NULL, NULL); - g_io_channel_set_buffered (ioc, FALSE); - - manager->priv->socket_watch_id = g_io_add_watch_full (ioc, - G_PRIORITY_DEFAULT, - G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc)decode_packet, - manager, - NULL); - g_io_channel_unref (ioc); - - return ret; -} - -gboolean -gdm_xdmcp_manager_stop (GdmXdmcpManager *manager, - GError **error) -{ - g_return_val_if_fail (GDM_IS_XDMCP_MANAGER (manager), FALSE); - g_return_val_if_fail (manager->priv->socket_fd != -1, FALSE); - - if (manager->priv->socket_watch_id > 0) { - g_source_remove (manager->priv->socket_watch_id); - manager->priv->socket_watch_id = 0; - } - - if (manager->priv->socket_fd > 0) { - VE_IGNORE_EINTR (close (manager->priv->socket_fd)); - manager->priv->socket_fd = -1; - } - - return TRUE; -} - -void -gdm_xdmcp_manager_set_port (GdmXdmcpManager *manager, - guint port) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - manager->priv->port = port; -} - -static void -gdm_xdmcp_manager_set_use_multicast (GdmXdmcpManager *manager, - gboolean use_multicast) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - manager->priv->use_multicast = use_multicast; -} - -static void -gdm_xdmcp_manager_set_multicast_address (GdmXdmcpManager *manager, - const char *address) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - g_free (manager->priv->multicast_address); - manager->priv->multicast_address = g_strdup (address); -} - -static void -gdm_xdmcp_manager_set_honor_indirect (GdmXdmcpManager *manager, - gboolean honor_indirect) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - manager->priv->honor_indirect = honor_indirect; -} - -static void -gdm_xdmcp_manager_set_max_displays_per_host (GdmXdmcpManager *manager, - guint num) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - manager->priv->max_displays_per_host = num; -} - -static void -gdm_xdmcp_manager_set_max_displays (GdmXdmcpManager *manager, - guint num) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - manager->priv->max_displays = num; -} - -static void -gdm_xdmcp_manager_set_max_pending_displays (GdmXdmcpManager *manager, - guint num) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - manager->priv->max_pending_displays = num; -} - -static void -gdm_xdmcp_manager_set_max_wait (GdmXdmcpManager *manager, - guint num) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - manager->priv->max_wait = num; -} - -static void -gdm_xdmcp_manager_set_willing_script (GdmXdmcpManager *manager, - const char *script) -{ - g_return_if_fail (GDM_IS_XDMCP_MANAGER (manager)); - - g_free (manager->priv->willing_script); - manager->priv->willing_script = g_strdup (script); -} - -static void -gdm_xdmcp_manager_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GdmXdmcpManager *self; - - self = GDM_XDMCP_MANAGER (object); - - switch (prop_id) { - case PROP_PORT: - gdm_xdmcp_manager_set_port (self, g_value_get_uint (value)); - break; - case PROP_USE_MULTICAST: - gdm_xdmcp_manager_set_use_multicast (self, g_value_get_boolean (value)); - break; - case PROP_MULTICAST_ADDRESS: - gdm_xdmcp_manager_set_multicast_address (self, g_value_get_string (value)); - break; - case PROP_HONOR_INDIRECT: - gdm_xdmcp_manager_set_honor_indirect (self, g_value_get_boolean (value)); - break; - case PROP_MAX_DISPLAYS_PER_HOST: - gdm_xdmcp_manager_set_max_displays_per_host (self, g_value_get_uint (value)); - break; - case PROP_MAX_DISPLAYS: - gdm_xdmcp_manager_set_max_displays (self, g_value_get_uint (value)); - break; - case PROP_MAX_PENDING_DISPLAYS: - gdm_xdmcp_manager_set_max_pending_displays (self, g_value_get_uint (value)); - break; - case PROP_MAX_WAIT: - gdm_xdmcp_manager_set_max_wait (self, g_value_get_uint (value)); - break; - case PROP_WILLING_SCRIPT: - gdm_xdmcp_manager_set_willing_script (self, g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gdm_xdmcp_manager_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GdmXdmcpManager *self; - - self = GDM_XDMCP_MANAGER (object); - - switch (prop_id) { - case PROP_PORT: - g_value_set_uint (value, self->priv->port); - break; - case PROP_USE_MULTICAST: - g_value_set_boolean (value, self->priv->use_multicast); - break; - case PROP_MULTICAST_ADDRESS: - g_value_set_string (value, self->priv->multicast_address); - break; - case PROP_HONOR_INDIRECT: - g_value_set_boolean (value, self->priv->honor_indirect); - break; - case PROP_MAX_DISPLAYS_PER_HOST: - g_value_set_uint (value, self->priv->max_displays_per_host); - break; - case PROP_MAX_DISPLAYS: - g_value_set_uint (value, self->priv->max_displays); - break; - case PROP_MAX_PENDING_DISPLAYS: - g_value_set_uint (value, self->priv->max_pending_displays); - break; - case PROP_MAX_WAIT: - g_value_set_uint (value, self->priv->max_wait); - break; - case PROP_WILLING_SCRIPT: - g_value_set_string (value, self->priv->willing_script); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gdm_xdmcp_manager_class_init (GdmXdmcpManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->get_property = gdm_xdmcp_manager_get_property; - object_class->set_property = gdm_xdmcp_manager_set_property; - object_class->finalize = gdm_xdmcp_manager_finalize; - - g_object_class_install_property (object_class, - PROP_PORT, - g_param_spec_uint ("port", - "UDP port", - "UDP port", - 0, - G_MAXINT, - DEFAULT_PORT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, - PROP_USE_MULTICAST, - g_param_spec_boolean ("use-multicast", - NULL, - NULL, - DEFAULT_USE_MULTICAST, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, - PROP_MULTICAST_ADDRESS, - g_param_spec_string ("multicast-address", - "multicast-address", - "multicast-address", - DEFAULT_MULTICAST_ADDRESS, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, - PROP_HONOR_INDIRECT, - g_param_spec_boolean ("honor-indirect", - NULL, - NULL, - DEFAULT_HONOR_INDIRECT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, - PROP_WILLING_SCRIPT, - g_param_spec_string ("willing-script", - "willing-script", - "willing-script", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, - PROP_MAX_DISPLAYS_PER_HOST, - g_param_spec_uint ("max-displays-per-host", - "max-displays-per-host", - "max-displays-per-host", - 0, - G_MAXINT, - DEFAULT_MAX_DISPLAYS_PER_HOST, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, - PROP_MAX_DISPLAYS, - g_param_spec_uint ("max-displays", - "max-displays", - "max-displays", - 0, - G_MAXINT, - DEFAULT_MAX_DISPLAYS, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, - PROP_MAX_PENDING_DISPLAYS, - g_param_spec_uint ("max-pending-displays", - "max-pending-displays", - "max-pending-displays", - 0, - G_MAXINT, - DEFAULT_MAX_PENDING_DISPLAYS, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, - PROP_MAX_WAIT, - g_param_spec_uint ("max-wait", - "max-wait", - "max-wait", - 0, - G_MAXINT, - DEFAULT_MAX_WAIT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_type_class_add_private (klass, sizeof (GdmXdmcpManagerPrivate)); -} - -static void -gdm_xdmcp_manager_init (GdmXdmcpManager *manager) -{ - char hostbuf[1024]; - struct utsname name; - - manager->priv = GDM_XDMCP_MANAGER_GET_PRIVATE (manager); - - manager->priv->socket_fd = -1; - - manager->priv->session_serial = g_random_int (); - - /* Fetch and store local hostname in XDMCP friendly format */ - hostbuf[1023] = '\0'; - if G_UNLIKELY (gethostname (hostbuf, 1023) != 0) { - g_warning (_("Could not get server hostname: %s!"), g_strerror (errno)); - strcpy (hostbuf, "localhost.localdomain"); - } - - uname (&name); - manager->priv->sysid = g_strconcat (name.sysname, - " ", - name.release, - NULL); - - manager->priv->hostname = g_strdup (hostbuf); - - manager->priv->servhost.data = (CARD8 *) g_strdup (hostbuf); - manager->priv->servhost.length = strlen ((char *) manager->priv->servhost.data); -} - -static void -gdm_xdmcp_manager_finalize (GObject *object) -{ - GdmXdmcpManager *manager; - - g_return_if_fail (object != NULL); - g_return_if_fail (GDM_IS_XDMCP_MANAGER (object)); - - manager = GDM_XDMCP_MANAGER (object); - - g_return_if_fail (manager->priv != NULL); - - if (manager->priv->socket_watch_id > 0) { - g_source_remove (manager->priv->socket_watch_id); - } - - g_slist_free (manager->priv->forward_queries); - g_slist_free (manager->priv->managed_forwards); - - g_free (manager->priv->sysid); - g_free (manager->priv->hostname); - g_free (manager->priv->multicast_address); - g_free (manager->priv->willing_script); - - /* FIXME: Free servhost */ - - G_OBJECT_CLASS (gdm_xdmcp_manager_parent_class)->finalize (object); -} - -GdmXdmcpManager * -gdm_xdmcp_manager_new (void) -{ - if (xdmcp_manager_object != NULL) { - g_object_ref (xdmcp_manager_object); - } else { - xdmcp_manager_object = g_object_new (GDM_TYPE_XDMCP_MANAGER, NULL); - g_object_add_weak_pointer (xdmcp_manager_object, - (gpointer *) &xdmcp_manager_object); - } - - return GDM_XDMCP_MANAGER (xdmcp_manager_object); -} |