source: proiecte/PPPP/gdm/daemon/gdm-xdmcp-display-factory.c @ 134

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

gdm sources with the modifications for webcam

File size: 116.7 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
4 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include "config.h"
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <fcntl.h>
27#include <unistd.h>
28#include <string.h>
29#include <signal.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32#include <sys/utsname.h>
33
34#include <sys/socket.h>
35#include <netdb.h>
36#include <arpa/inet.h>
37#include <net/if.h>
38#ifdef HAVE_SYS_SOCKIO_H
39#include <sys/sockio.h>
40#endif
41#include <sys/ioctl.h>
42
43#include <errno.h>
44
45#include <glib.h>
46#include <glib/gi18n.h>
47#include <glib/gstdio.h>
48#include <glib-object.h>
49
50#include <X11/Xlib.h>
51#include <X11/Xmd.h>
52#include <X11/Xdmcp.h>
53
54#include "gdm-common.h"
55#include "gdm-xdmcp-greeter-display.h"
56#include "gdm-xdmcp-chooser-display.h"
57#include "gdm-display-factory.h"
58#include "gdm-xdmcp-display-factory.h"
59#include "gdm-display-store.h"
60#include "gdm-settings-direct.h"
61#include "gdm-settings-keys.h"
62
63/*
64 * On Sun, we need to define allow_severity and deny_severity to link
65 * against libwrap.
66 */
67#ifdef __sun
68#include <syslog.h>
69int allow_severity = LOG_INFO;
70int deny_severity = LOG_WARNING;
71#endif
72
73#define GDM_XDMCP_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_DISPLAY_FACTORY, GdmXdmcpDisplayFactoryPrivate))
74
75#define DEFAULT_PORT                  177
76#define DEFAULT_USE_MULTICAST         FALSE
77#define DEFAULT_MULTICAST_ADDRESS     "ff02::1"
78#define DEFAULT_HONOR_INDIRECT        TRUE
79#define DEFAULT_MAX_DISPLAYS_PER_HOST 1
80#define DEFAULT_MAX_DISPLAYS          16
81#define DEFAULT_MAX_PENDING_DISPLAYS  4
82#define DEFAULT_MAX_WAIT              30
83#define DEFAULT_MAX_WAIT_INDIRECT     30
84#define DEFAULT_WILLING_SCRIPT        GDMCONFDIR "/Xwilling"
85
86#define GDM_MAX_FORWARD_QUERIES 10
87#define GDM_FORWARD_QUERY_TIMEOUT 30
88#define MANAGED_FORWARD_INTERVAL 1500 /* 1.5 seconds */
89
90/* some extra XDMCP opcodes that xdm will happily ignore since they'll be
91 * the wrong XDMCP version anyway */
92#define GDM_XDMCP_PROTOCOL_VERSION 1001
93enum {
94        GDM_XDMCP_FIRST_OPCODE = 1000, /*just a marker, not an opcode */
95
96        GDM_XDMCP_MANAGED_FORWARD = 1000,
97                /* manager (master) -> manager
98                 * A packet with MANAGED_FORWARD is sent to the
99                 * manager that sent the forward query from the manager to
100                 * which forward query was sent.  It indicates that the forward
101                 * was fully processed and that the client now has either
102                 * a managed session, or has been sent denial, refuse or failed.
103                 * (if the denial gets lost then client gets dumped into the
104                 * chooser again).  This should be resent a few times
105                 * until some (short) timeout or until GOT_MANAGED_FORWARD
106                 * is sent.  GDM sends at most 3 packates with 1.5 seconds
107                 * between each.
108                 *
109                 * Argument is ARRAY8 with the address of the originating host */
110        GDM_XDMCP_GOT_MANAGED_FORWARD,
111                /* manager -> manager (master)
112                 * A single packet with GOT_MANAGED_FORWARD is sent to indicate
113                 * that we did receive the MANAGED_FORWARD packet.  The argument
114                 * must match the MANAGED_FORWARD one or it will just be ignored.
115                 *
116                 * Argument is ARRAY8 with the address of the originating host */
117        GDM_XDMCP_LAST_OPCODE /*just a marker, not an opcode */
118};
119
120/*
121 * We don't support XDM-AUTHENTICATION-1 and XDM-AUTHORIZATION-1.
122 *
123 * The latter would be quite useful to avoid sending unencrypted
124 * cookies over the wire. Unfortunately it isn't supported without
125 * XDM-AUTHENTICATION-1 which requires a key database with private
126 * keys from all X terminals on your LAN. Fun, fun, fun.
127 *
128 * Furthermore user passwords go over the wire in cleartext anyway,
129 * so protecting cookies is not that important.
130 */
131
132typedef struct _XdmAuth {
133        ARRAY8 authentication;
134        ARRAY8 authorization;
135} XdmAuthRec, *XdmAuthPtr;
136
137static XdmAuthRec serv_authlist = {
138        { (CARD16) 0, (CARD8 *) 0 },
139        { (CARD16) 0, (CARD8 *) 0 }
140};
141
142/* NOTE: Timeout and max are hardcoded */
143typedef struct _ForwardQuery {
144        time_t      acctime;
145        GdmAddress *dsp_address;
146        GdmAddress *from_address;
147} ForwardQuery;
148
149typedef struct _IndirectClient {
150        int         id;
151        GdmAddress *dsp_address;
152        GdmAddress *chosen_address;
153        time_t      acctime;
154} IndirectClient;
155
156typedef struct {
157        int                     times;
158        guint                   handler;
159        GdmAddress             *manager;
160        GdmAddress             *origin;
161        GdmXdmcpDisplayFactory *xdmcp_display_factory;
162} ManagedForward;
163
164struct GdmXdmcpDisplayFactoryPrivate
165{
166        GSList          *forward_queries;
167        GSList          *managed_forwards;
168        GSList          *indirect_clients;
169
170        int              socket_fd;
171        gint32           session_serial;
172        guint            socket_watch_id;
173        XdmcpBuffer      buf;
174
175        guint            num_sessions;
176        guint            num_pending_sessions;
177
178        char            *sysid;
179        char            *hostname;
180        ARRAY8           servhost;
181
182        /* configuration */
183        guint            port;
184        gboolean         use_multicast;
185        char            *multicast_address;
186        gboolean         honor_indirect;
187        char            *willing_script;
188        guint            max_displays_per_host;
189        guint            max_displays;
190        guint            max_pending_displays;
191        guint            max_wait;
192        guint            max_wait_indirect;
193};
194
195enum {
196        PROP_0,
197        PROP_PORT,
198        PROP_USE_MULTICAST,
199        PROP_MULTICAST_ADDRESS,
200        PROP_HONOR_INDIRECT,
201        PROP_WILLING_SCRIPT,
202        PROP_MAX_DISPLAYS_PER_HOST,
203        PROP_MAX_DISPLAYS,
204        PROP_MAX_PENDING_DISPLAYS,
205        PROP_MAX_WAIT,
206        PROP_MAX_WAIT_INDIRECT,
207};
208
209static void     gdm_xdmcp_display_factory_class_init    (GdmXdmcpDisplayFactoryClass *klass);
210static void     gdm_xdmcp_display_factory_init          (GdmXdmcpDisplayFactory      *manager);
211static void     gdm_xdmcp_display_factory_finalize      (GObject                     *object);
212
213static gpointer xdmcp_display_factory_object = NULL;
214
215G_DEFINE_TYPE (GdmXdmcpDisplayFactory, gdm_xdmcp_display_factory, GDM_TYPE_DISPLAY_FACTORY)
216
217/* Theory of operation:
218 *
219 * Process idles waiting for UDP packets on port 177.
220 * Incoming packets are decoded and checked against tcp_wrapper.
221 *
222 * A typical session looks like this:
223 *
224 * Display sends Query/BroadcastQuery to Manager.
225 *
226 * Manager selects an appropriate authentication scheme from the
227 * display's list of supported ones and sends Willing/Unwilling.
228 *
229 * Assuming the display accepts the auth. scheme it sends back a
230 * Request.
231 *
232 * If the manager accepts to service the display (i.e. loadavg is low)
233 * it sends back an Accept containing a unique SessionID. The
234 * SessionID is stored in an accept queue by the Manager. Should the
235 * manager refuse to start a session a Decline is sent to the display.
236 *
237 * The display returns a Manage request containing the supplied
238 * SessionID. The manager will then start a session on the display. In
239 * case the SessionID is not on the accept queue the manager returns
240 * Refuse. If the manager fails to open the display for connections
241 * Failed is returned.
242 *
243 * During the session the display periodically sends KeepAlive packets
244 * to the manager. The manager responds with Alive.
245 *
246 * Similarly the manager xpings the display once in a while and shuts
247 * down the connection on failure.
248 *
249 */
250
251GQuark
252gdm_xdmcp_display_factory_error_quark (void)
253{
254        static GQuark ret = 0;
255        if (ret == 0) {
256                ret = g_quark_from_static_string ("gdm_xdmcp_display_factory_error");
257        }
258
259        return ret;
260}
261
262static gint32
263get_next_session_serial (GdmXdmcpDisplayFactory *factory)
264{
265        gint32 serial;
266
267 again:
268        if (factory->priv->session_serial != G_MAXINT32) {
269                serial = factory->priv->session_serial++;
270        } else {
271                serial = g_random_int ();
272        }
273
274        if (serial == 0) {
275                goto again;
276        }
277
278        return serial;
279}
280
281/* for debugging */
282static const char *
283ai_family_str (struct addrinfo *ai)
284{
285        const char *str;
286        switch (ai->ai_family) {
287        case AF_INET:
288                str = "inet";
289                break;
290        case AF_INET6:
291                str = "inet6";
292                break;
293        case AF_UNIX:
294                str = "unix";
295                break;
296        case AF_UNSPEC:
297                str = "unspecified";
298                break;
299        default:
300                str = "unknown";
301                break;
302        }
303        return str;
304}
305
306/* for debugging */
307static const char *
308ai_type_str (struct addrinfo *ai)
309{
310        const char *str;
311        switch (ai->ai_socktype) {
312        case SOCK_STREAM:
313                str = "stream";
314                break;
315        case SOCK_DGRAM:
316                str = "datagram";
317                break;
318        case SOCK_SEQPACKET:
319                str = "seqpacket";
320                break;
321        case SOCK_RAW:
322                str = "raw";
323                break;
324        default:
325                str = "unknown";
326                break;
327        }
328        return str;
329}
330
331/* for debugging */
332static const char *
333ai_protocol_str (struct addrinfo *ai)
334{
335        const char *str;
336        switch (ai->ai_protocol) {
337        case 0:
338                str = "default";
339                break;
340        case IPPROTO_TCP:
341                str = "TCP";
342                break;
343        case IPPROTO_UDP:
344                str = "UDP";
345                break;
346        case IPPROTO_RAW:
347                str = "raw";
348                break;
349        default:
350                str = "unknown";
351                break;
352        }
353
354        return str;
355}
356
357/* for debugging */
358static char *
359ai_flags_str (struct addrinfo *ai)
360{
361        GString *str;
362
363        str = g_string_new ("");
364        if (ai->ai_flags == 0) {
365                g_string_append (str, "none");
366        } else {
367                if (ai->ai_flags & AI_PASSIVE) {
368                        g_string_append (str, "passive ");
369                }
370                if (ai->ai_flags & AI_CANONNAME) {
371                        g_string_append (str, "canon ");
372                }
373                if (ai->ai_flags & AI_NUMERICHOST) {
374                        g_string_append (str, "numhost ");
375                }
376                if (ai->ai_flags & AI_NUMERICSERV) {
377                        g_string_append (str, "numserv ");
378                }
379                if (ai->ai_flags & AI_V4MAPPED) {
380                        g_string_append (str, "v4mapped ");
381                }
382                if (ai->ai_flags & AI_ALL) {
383                        g_string_append (str, "all ");
384                }
385        }
386        return g_string_free (str, FALSE);
387}
388
389/* for debugging */
390static void
391debug_addrinfo (struct addrinfo *ai)
392{
393        char *str;
394        str = ai_flags_str (ai);
395        g_debug ("GdmXdmcpDisplayFactory: addrinfo family=%s type=%s proto=%s flags=%s",
396                 ai_family_str (ai),
397                 ai_type_str (ai),
398                 ai_protocol_str (ai),
399                 str);
400        g_free (str);
401}
402
403static int
404create_socket (struct addrinfo *ai)
405{
406        int sock;
407
408        sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
409        if (sock < 0) {
410                g_warning ("socket: %s", g_strerror (errno));
411                return sock;
412        }
413
414        if (bind (sock, ai->ai_addr, ai->ai_addrlen) < 0) {
415                g_warning ("bind: %s", g_strerror (errno));
416                close (sock);
417                return -1;
418        }
419
420        return sock;
421}
422
423static int
424do_bind (guint                     port,
425         int                       family,
426         struct sockaddr_storage * hostaddr)
427{
428        struct addrinfo  hints;
429        struct addrinfo *ai_list;
430        struct addrinfo *ai;
431        char             strport[NI_MAXSERV];
432        int              gaierr;
433        int              sock;
434
435        sock = -1;
436
437        memset (&hints, 0, sizeof (hints));
438        hints.ai_family = family;
439        hints.ai_socktype = SOCK_DGRAM;
440        hints.ai_flags = AI_PASSIVE;
441
442        snprintf (strport, sizeof (strport), "%u", port);
443
444        ai_list = NULL;
445        if ((gaierr = getaddrinfo (NULL, strport, &hints, &ai_list)) != 0) {
446                g_error ("Unable to connect to socket: %s", gai_strerror (gaierr));
447        }
448
449        /* should only be one but.. */
450        for (ai = ai_list; ai != NULL; ai = ai->ai_next) {
451                if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
452                        continue;
453                }
454
455                debug_addrinfo (ai);
456
457                if (sock < 0) {
458                        char       *host;
459                        char       *serv;
460                        GdmAddress *addr;
461
462                        addr = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen);
463
464                        host = NULL;
465                        serv = NULL;
466                        gdm_address_get_numeric_info (addr, &host, &serv);
467                        g_debug ("GdmXdmcpDisplayFactory: Attempting to bind to host %s port %s", host, serv);
468                        g_free (host);
469                        g_free (serv);
470                        gdm_address_free (addr);
471
472                        sock = create_socket (ai);
473                        if (sock >= 0) {
474                                if (hostaddr != NULL) {
475                                        memcpy (hostaddr, ai->ai_addr, ai->ai_addrlen);
476                                }
477                        }
478                }
479        }
480
481        freeaddrinfo (ai_list);
482
483        return sock;
484}
485
486static void
487setup_multicast (GdmXdmcpDisplayFactory *factory)
488{
489#ifdef ENABLE_IPV6
490        /* Checking and Setting Multicast options */
491        {
492                /*
493                 * socktemp is a temporary socket for getting info about
494                 * available interfaces
495                 */
496                int              socktemp;
497                int              i;
498                int              num;
499                char            *buf;
500                struct ipv6_mreq mreq;
501
502                /* For interfaces' list */
503                struct ifconf    ifc;
504                struct ifreq    *ifr;
505
506                socktemp = socket (AF_INET, SOCK_DGRAM, 0);
507#ifdef SIOCGIFNUM
508                if (ioctl (socktemp, SIOCGIFNUM, &num) < 0) {
509                        num = 64;
510                }
511#else
512                num = 64;
513#endif /* SIOCGIFNUM */
514                ifc.ifc_len = sizeof (struct ifreq) * num;
515                ifc.ifc_buf = buf = malloc (ifc.ifc_len);
516
517                if (ioctl (socktemp, SIOCGIFCONF, &ifc) >= 0) {
518                        ifr = ifc.ifc_req;
519                        num = ifc.ifc_len / sizeof (struct ifreq); /* No of interfaces */
520
521                        /* Joining multicast group with all interfaces */
522                        for (i = 0 ; i < num ; i++) {
523                                struct ifreq ifreq;
524                                int          ifindex;
525
526                                memset (&ifreq, 0, sizeof (ifreq));
527                                strncpy (ifreq.ifr_name, ifr[i].ifr_name, sizeof (ifreq.ifr_name));
528                                /* paranoia */
529                                ifreq.ifr_name[sizeof (ifreq.ifr_name) - 1] = '\0';
530
531                                if (ioctl (socktemp, SIOCGIFFLAGS, &ifreq) < 0) {
532                                        g_debug ("GdmXdmcpDisplayFactory: Could not get SIOCGIFFLAGS for %s",
533                                                 ifr[i].ifr_name);
534                                }
535
536                                ifindex = if_nametoindex (ifr[i].ifr_name);
537
538                                if ((!(ifreq.ifr_flags & IFF_UP) ||
539                                     (ifreq.ifr_flags & IFF_LOOPBACK)) ||
540                                    ((ifindex == 0 ) && (errno == ENXIO))) {
541                                        /* Not a valid interface or loopback interface*/
542                                        continue;
543                                }
544
545                                mreq.ipv6mr_interface = ifindex;
546                                inet_pton (AF_INET6,
547                                           factory->priv->multicast_address,
548                                           &mreq.ipv6mr_multiaddr);
549
550                                setsockopt (factory->priv->socket_fd,
551                                            IPPROTO_IPV6,
552                                            IPV6_JOIN_GROUP,
553                                            &mreq,
554                                            sizeof (mreq));
555                        }
556                }
557                g_free (buf);
558                close (socktemp);
559        }
560#endif /* ENABLE_IPV6 */
561}
562
563static void
564fd_set_close_on_exec (int fd)
565{
566        int flags;
567
568        flags = fcntl (fd, F_GETFD, 0);
569        if (flags < 0) {
570                return;
571        }
572
573        flags |= FD_CLOEXEC;
574
575        fcntl (fd, F_SETFD, flags);
576}
577
578static gboolean
579open_port (GdmXdmcpDisplayFactory *factory)
580{
581        struct sockaddr_storage serv_sa = { 0 };
582
583        g_debug ("GdmXdmcpDisplayFactory: Start up on host %s, port %d",
584                 factory->priv->hostname,
585                 factory->priv->port);
586
587        /* Open socket for communications */
588#ifdef ENABLE_IPV6
589        factory->priv->socket_fd = do_bind (factory->priv->port, AF_INET6, &serv_sa);
590        if (factory->priv->socket_fd < 0)
591#endif
592                factory->priv->socket_fd = do_bind (factory->priv->port, AF_INET, &serv_sa);
593
594        if G_UNLIKELY (factory->priv->socket_fd < 0) {
595                g_warning (_("Could not create socket!"));
596                return FALSE;
597        }
598
599        fd_set_close_on_exec (factory->priv->socket_fd);
600
601        if (factory->priv->use_multicast) {
602                setup_multicast (factory);
603        }
604
605        return TRUE;
606}
607
608#ifdef HAVE_TCPWRAPPERS
609
610        /*
611         * Avoids a warning, my tcpd.h file doesn't include this prototype, even
612         * though the library does include the function and the manpage mentions it
613         */
614        extern int hosts_ctl (char *daemon,
615                              char *client_name,
616                              char *client_addr,
617                              char *client_user);
618#endif
619
620static gboolean
621gdm_xdmcp_host_allow (GdmAddress *address)
622{
623#ifdef HAVE_TCPWRAPPERS
624        char       *client;
625        char       *host;
626        gboolean    ret;
627
628        host = NULL;
629        client = NULL;
630
631        /* Find client hostname */
632        gdm_address_get_hostname (address, &client);
633        gdm_address_get_numeric_info (address, &host, NULL);
634
635        /* Check with tcp_wrappers if client is allowed to access */
636        ret = hosts_ctl ("gdm", client, host, "");
637
638        g_free (host);
639        g_free (client);
640
641        return ret;
642#else /* HAVE_TCPWRAPPERS */
643        return (TRUE);
644#endif /* HAVE_TCPWRAPPERS */
645}
646
647typedef struct {
648        GdmAddress *address;
649        int         count;
650} CountDisplayData;
651
652static gboolean
653count_displays_from_host (const char       *id,
654                          GdmDisplay       *display,
655                          CountDisplayData *data)
656{
657        GdmAddress *address;
658
659        if (GDM_IS_XDMCP_DISPLAY (display)) {
660                address = gdm_xdmcp_display_get_remote_address (GDM_XDMCP_DISPLAY (display));
661
662                if (gdm_address_equal (address, data->address)) {
663                        data->count++;
664                }
665        }
666
667        return TRUE;
668}
669
670static int
671gdm_xdmcp_num_displays_from_host (GdmXdmcpDisplayFactory *factory,
672                                  GdmAddress             *address)
673{
674        CountDisplayData data;
675        GdmDisplayStore *store;
676
677        data.count = 0;
678        data.address = address;
679
680        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
681        gdm_display_store_foreach (store,
682                                   (GdmDisplayStoreFunc)count_displays_from_host,
683                                   &data);
684
685        return data.count;
686}
687
688typedef struct {
689        GdmAddress *address;
690        int         display_num;
691} LookupHostData;
692
693static gboolean
694lookup_by_host (const char     *id,
695                GdmDisplay     *display,
696                LookupHostData *data)
697{
698        GdmAddress *this_address;
699        int         disp_num;
700
701        if (! GDM_IS_XDMCP_DISPLAY (display)) {
702                return FALSE;
703        }
704
705        this_address = gdm_xdmcp_display_get_remote_address (GDM_XDMCP_DISPLAY (display));
706        gdm_display_get_x11_display_number (display, &disp_num, NULL);
707
708        if (gdm_address_equal (this_address, data->address)
709            && disp_num == data->display_num) {
710                return TRUE;
711        }
712
713        return FALSE;
714}
715
716static GdmDisplay *
717gdm_xdmcp_display_lookup_by_host (GdmXdmcpDisplayFactory *factory,
718                                  GdmAddress             *address,
719                                  int                     display_num)
720{
721        GdmDisplay      *display;
722        LookupHostData  *data;
723        GdmDisplayStore *store;
724
725        data = g_new0 (LookupHostData, 1);
726        data->address = address;
727        data->display_num = display_num;
728
729        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
730        display = gdm_display_store_find (store,
731                                          (GdmDisplayStoreFunc)lookup_by_host,
732                                          data);
733        g_free (data);
734
735        return display;
736}
737
738static char *
739get_willing_output (GdmXdmcpDisplayFactory *factory)
740{
741        char  *output;
742        char **argv;
743        FILE  *fd;
744        char   buf[256];
745
746        output = NULL;
747        buf[0] = '\0';
748
749        if (factory->priv->willing_script == NULL) {
750                goto out;
751        }
752
753        argv = NULL;
754        if (! g_shell_parse_argv (factory->priv->willing_script, NULL, &argv, NULL)) {
755                goto out;
756        }
757
758        if (argv == NULL ||
759            argv[0] == NULL ||
760            g_access (argv[0], X_OK) != 0) {
761                goto out;
762        }
763
764        fd = popen (factory->priv->willing_script, "r");
765        if (fd == NULL) {
766                goto out;
767        }
768
769        if (fgets (buf, sizeof (buf), fd) == NULL) {
770                pclose (fd);
771                goto out;
772        }
773
774        pclose (fd);
775
776        output = g_strdup (buf);
777
778 out:
779        return output;
780}
781
782static void
783gdm_xdmcp_send_willing (GdmXdmcpDisplayFactory *factory,
784                        GdmAddress             *address)
785{
786        ARRAY8        status;
787        XdmcpHeader   header;
788        static char  *last_status = NULL;
789        static time_t last_willing = 0;
790        char         *host;
791
792        host = NULL;
793        gdm_address_get_numeric_info (address, &host, NULL);
794        g_debug ("GdmXdmcpDisplayFactory: Sending WILLING to %s", host);
795        g_free (host);
796
797        if (last_willing == 0 || time (NULL) - 3 > last_willing) {
798                char *s;
799
800                g_free (last_status);
801
802                s = get_willing_output (factory);
803                if (s != NULL) {
804                        last_status = s;
805                } else {
806                        last_status = g_strdup (factory->priv->sysid);
807                }
808        }
809
810        if (! gdm_address_is_local (address) &&
811            gdm_xdmcp_num_displays_from_host (factory, address) >= factory->priv->max_displays_per_host) {
812                /*
813                 * Don't translate, this goes over the wire to servers where we
814                 * don't know the charset or language, so it must be ascii
815                 */
816                status.data = (CARD8 *) g_strdup_printf ("%s (Server is busy)",
817                                                         last_status);
818        } else {
819                status.data = (CARD8 *) g_strdup (last_status);
820        }
821
822        status.length = strlen ((char *) status.data);
823
824        header.opcode   = (CARD16) WILLING;
825        header.length   = 6 + serv_authlist.authentication.length;
826        header.length  += factory->priv->servhost.length + status.length;
827        header.version  = XDM_PROTOCOL_VERSION;
828        XdmcpWriteHeader (&factory->priv->buf, &header);
829
830        /* Hardcoded authentication */
831        XdmcpWriteARRAY8 (&factory->priv->buf, &serv_authlist.authentication);
832        XdmcpWriteARRAY8 (&factory->priv->buf, &factory->priv->servhost);
833        XdmcpWriteARRAY8 (&factory->priv->buf, &status);
834
835        XdmcpFlush (factory->priv->socket_fd,
836                    &factory->priv->buf,
837                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
838                    (int)sizeof (struct sockaddr_storage));
839
840        g_free (status.data);
841}
842
843static void
844gdm_xdmcp_send_unwilling (GdmXdmcpDisplayFactory *factory,
845                          GdmAddress             *address,
846                          int                     type)
847{
848        ARRAY8        status;
849        XdmcpHeader   header;
850        static time_t last_time = 0;
851        char         *host;
852
853        /* only send at most one packet per second,
854           no harm done if we don't send it at all */
855        if (last_time + 1 >= time (NULL)) {
856                return;
857        }
858
859        host = NULL;
860        gdm_address_get_numeric_info (address, &host, NULL);
861        g_debug ("GdmXdmcpDisplayFactory: Sending UNWILLING to %s", host);
862        g_warning (_("Denied XDMCP query from host %s"), host);
863        g_free (host);
864
865        /*
866         * Don't translate, this goes over the wire to servers where we
867         * don't know the charset or language, so it must be ascii
868         */
869        status.data = (CARD8 *) "Display not authorized to connect";
870        status.length = strlen ((char *) status.data);
871
872        header.opcode = (CARD16) UNWILLING;
873        header.length = 4 + factory->priv->servhost.length + status.length;
874        header.version = XDM_PROTOCOL_VERSION;
875        XdmcpWriteHeader (&factory->priv->buf, &header);
876
877        XdmcpWriteARRAY8 (&factory->priv->buf, &factory->priv->servhost);
878        XdmcpWriteARRAY8 (&factory->priv->buf, &status);
879        XdmcpFlush (factory->priv->socket_fd,
880                    &factory->priv->buf,
881                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
882                    (int)sizeof (struct sockaddr_storage));
883
884        last_time = time (NULL);
885}
886
887#define SIN(__s)   ((struct sockaddr_in *) __s)
888#define SIN6(__s)  ((struct sockaddr_in6 *) __s)
889
890static void
891set_port_for_request (GdmAddress *address,
892                      ARRAY8     *port)
893{
894        struct sockaddr_storage *ss;
895
896        ss = gdm_address_peek_sockaddr_storage (address);
897
898        /* we depend on this being 2 elsewhere as well */
899        port->length = 2;
900
901        switch (ss->ss_family) {
902        case AF_INET:
903                port->data = (CARD8 *)g_memdup (&(SIN (ss)->sin_port), port->length);
904                break;
905        case AF_INET6:
906                port->data = (CARD8 *)g_memdup (&(SIN6 (ss)->sin6_port), port->length);
907                break;
908        default:
909                port->data = NULL;
910                break;
911        }
912}
913
914static void
915set_address_for_request (GdmAddress *address,
916                         ARRAY8     *addr)
917{
918        struct sockaddr_storage *ss;
919
920        ss = gdm_address_peek_sockaddr_storage (address);
921
922        switch (ss->ss_family) {
923        case AF_INET:
924                addr->length = sizeof (struct in_addr);
925                addr->data = g_memdup (&SIN (ss)->sin_addr, addr->length);
926                break;
927        case AF_INET6:
928                addr->length = sizeof (struct in6_addr);
929                addr->data = g_memdup (&SIN6 (ss)->sin6_addr, addr->length);
930                break;
931        default:
932                addr->length = 0;
933                addr->data = NULL;
934                break;
935        }
936
937}
938
939static void
940gdm_xdmcp_send_forward_query (GdmXdmcpDisplayFactory  *factory,
941                              IndirectClient          *ic,
942                              GdmAddress              *address,
943                              GdmAddress              *display_address,
944                              ARRAYofARRAY8Ptr         authlist)
945{
946        XdmcpHeader              header;
947        int                      i;
948        ARRAY8                   addr;
949        ARRAY8                   port;
950        char                    *host;
951        char                    *serv;
952
953        g_assert (ic != NULL);
954        g_assert (ic->chosen_address != NULL);
955
956        host = NULL;
957        gdm_address_get_numeric_info (ic->chosen_address, &host, NULL);
958        g_debug ("GdmXdmcpDisplayFactory: Sending forward query to %s",
959                   host);
960        g_free (host);
961
962        host = NULL;
963        serv = NULL;
964        gdm_address_get_numeric_info (display_address, &host, &serv);
965        g_debug ("GdmXdmcpDisplayFactory: Query contains %s:%s",
966                 host, serv);
967        g_free (host);
968        g_free (serv);
969
970        set_port_for_request (address, &port);
971        set_address_for_request (display_address, &addr);
972
973        header.version = XDM_PROTOCOL_VERSION;
974        header.opcode = (CARD16) FORWARD_QUERY;
975        header.length = 0;
976        header.length += 2 + addr.length;
977        header.length += 2 + port.length;
978        header.length += 1;
979        for (i = 0; i < authlist->length; i++) {
980                header.length += 2 + authlist->data[i].length;
981        }
982
983        XdmcpWriteHeader (&factory->priv->buf, &header);
984        XdmcpWriteARRAY8 (&factory->priv->buf, &addr);
985        XdmcpWriteARRAY8 (&factory->priv->buf, &port);
986        XdmcpWriteARRAYofARRAY8 (&factory->priv->buf, authlist);
987
988        XdmcpFlush (factory->priv->socket_fd,
989                    &factory->priv->buf,
990                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (ic->chosen_address),
991                    (int)sizeof (struct sockaddr_storage));
992
993        g_free (port.data);
994        g_free (addr.data);
995}
996
997static void
998handle_any_query (GdmXdmcpDisplayFactory  *factory,
999                  GdmAddress              *address,
1000                  ARRAYofARRAY8Ptr         authentication_names,
1001                  int                      type)
1002{
1003        gdm_xdmcp_send_willing (factory, address);
1004}
1005
1006static void
1007handle_direct_query (GdmXdmcpDisplayFactory  *factory,
1008                     GdmAddress              *address,
1009                     int                      len,
1010                     int                      type)
1011{
1012        ARRAYofARRAY8 clnt_authlist;
1013        int           expected_len;
1014        int           i;
1015        int           res;
1016
1017        res = XdmcpReadARRAYofARRAY8 (&factory->priv->buf, &clnt_authlist);
1018        if G_UNLIKELY (! res) {
1019                g_warning (_("Could not extract authlist from packet"));
1020                return;
1021        }
1022
1023        expected_len = 1;
1024
1025        for (i = 0 ; i < clnt_authlist.length ; i++) {
1026                expected_len += 2 + clnt_authlist.data[i].length;
1027        }
1028
1029        if (len == expected_len) {
1030                handle_any_query (factory, address, &clnt_authlist, type);
1031        } else {
1032                g_warning (_("Error in checksum"));
1033        }
1034
1035        XdmcpDisposeARRAYofARRAY8 (&clnt_authlist);
1036}
1037
1038static void
1039gdm_xdmcp_handle_broadcast_query (GdmXdmcpDisplayFactory *factory,
1040                                  GdmAddress             *address,
1041                                  int                     len)
1042{
1043        if (gdm_xdmcp_host_allow (address)) {
1044                handle_direct_query (factory, address, len, BROADCAST_QUERY);
1045        } else {
1046                /* just ignore it */
1047        }
1048}
1049
1050static void
1051gdm_xdmcp_handle_query (GdmXdmcpDisplayFactory *factory,
1052                        GdmAddress             *address,
1053                        int                     len)
1054{
1055        if (gdm_xdmcp_host_allow (address)) {
1056                handle_direct_query (factory, address, len, QUERY);
1057        } else {
1058                gdm_xdmcp_send_unwilling (factory, address, QUERY);
1059        }
1060}
1061
1062static IndirectClient *
1063indirect_client_create (GdmXdmcpDisplayFactory *factory,
1064                        GdmAddress             *dsp_address)
1065{
1066        IndirectClient *ic;
1067
1068        ic = g_new0 (IndirectClient, 1);
1069        ic->dsp_address = gdm_address_copy (dsp_address);
1070
1071        factory->priv->indirect_clients = g_slist_prepend (factory->priv->indirect_clients, ic);
1072
1073        return ic;
1074}
1075
1076static void
1077indirect_client_destroy (GdmXdmcpDisplayFactory *factory,
1078                         IndirectClient         *ic)
1079{
1080        if (ic == NULL) {
1081                return;
1082        }
1083
1084        factory->priv->indirect_clients = g_slist_remove (factory->priv->indirect_clients, ic);
1085
1086        ic->acctime = 0;
1087
1088        {
1089                char *host;
1090
1091                host = NULL;
1092                gdm_address_get_numeric_info (ic->dsp_address, &host, NULL);
1093                g_debug ("GdmXdmcpDisplayFactory: Disposing IndirectClient for %s", host);
1094                g_free (host);
1095        }
1096
1097        g_free (ic->dsp_address);
1098        ic->dsp_address = NULL;
1099        g_free (ic->chosen_address);
1100        ic->chosen_address = NULL;
1101
1102        g_free (ic);
1103}
1104
1105static IndirectClient *
1106indirect_client_lookup_by_chosen (GdmXdmcpDisplayFactory *factory,
1107                                  GdmAddress             *chosen_address,
1108                                  GdmAddress             *origin_address)
1109{
1110        GSList         *li;
1111        char           *host;
1112        IndirectClient *ret;
1113
1114        g_assert (chosen_address != NULL);
1115        g_assert (origin_address != NULL);
1116
1117        ret = NULL;
1118
1119        for (li = factory->priv->indirect_clients; li != NULL; li = li->next) {
1120                IndirectClient *ic = li->data;
1121
1122                if (ic != NULL
1123                    && ic->chosen_address != NULL
1124                    && gdm_address_equal (ic->chosen_address, chosen_address)) {
1125                        if (gdm_address_equal (ic->dsp_address, origin_address)) {
1126                                ret = ic;
1127                                goto out;
1128                        } else if (gdm_address_is_loopback (ic->dsp_address)
1129                                   && gdm_address_is_local (origin_address)) {
1130                                ret = ic;
1131                                goto out;
1132                        }
1133                }
1134        }
1135
1136        gdm_address_get_numeric_info (chosen_address, &host, NULL);
1137
1138        g_debug ("GdmXdmcpDisplayFactory: Chosen %s host not found", host);
1139        g_free (host);
1140 out:
1141        return ret;
1142}
1143
1144/* lookup by origin */
1145static IndirectClient *
1146indirect_client_lookup (GdmXdmcpDisplayFactory *factory,
1147                        GdmAddress             *address)
1148{
1149        GSList         *li;
1150        GSList         *qlist;
1151        IndirectClient *ret;
1152        time_t          curtime;
1153
1154        g_assert (address != NULL);
1155
1156        curtime = time (NULL);
1157        ret = NULL;
1158
1159        qlist = g_slist_copy (factory->priv->indirect_clients);
1160
1161        for (li = qlist; li != NULL; li = li->next) {
1162                IndirectClient *ic;
1163                char           *host;
1164                char           *serv;
1165
1166                ic = (IndirectClient *) li->data;
1167
1168                if (ic == NULL) {
1169                        continue;
1170                }
1171
1172                host = NULL;
1173                serv = NULL;
1174                gdm_address_get_numeric_info (ic->dsp_address, &host, &serv);
1175
1176                g_debug ("GdmXdmcpDisplayFactory: comparing %s:%s", host, serv);
1177                if (gdm_address_equal (ic->dsp_address, address)) {
1178                        ret = ic;
1179                        g_free (host);
1180                        g_free (serv);
1181                        break;
1182                }
1183
1184                if (ic->acctime > 0 && curtime > ic->acctime + factory->priv->max_wait_indirect) {
1185                        g_debug ("GdmXdmcpDisplayFactory: Disposing stale forward query from %s:%s",
1186                                 host, serv);
1187
1188                        indirect_client_destroy (factory, ic);
1189                }
1190
1191                g_free (host);
1192                g_free (serv);
1193        }
1194
1195        g_slist_free (qlist);
1196
1197        if (ret == NULL) {
1198                char *host;
1199
1200                host = NULL;
1201                gdm_address_get_numeric_info (address, &host, NULL);
1202                g_debug ("GdmXdmcpDisplayFactory: Host %s not found",
1203                         host);
1204                g_free (host);
1205        }
1206
1207        return ret;
1208}
1209
1210static void
1211gdm_xdmcp_handle_indirect_query (GdmXdmcpDisplayFactory *factory,
1212                                 GdmAddress             *address,
1213                                 int                     len)
1214{
1215        ARRAYofARRAY8    clnt_authlist;
1216        int              expected_len;
1217        int              i;
1218        int              res;
1219        IndirectClient  *ic;
1220
1221        if (! gdm_xdmcp_host_allow (address)) {
1222                /* ignore the request */
1223                return;
1224        }
1225
1226        if (! factory->priv->honor_indirect) {
1227                /* ignore it */
1228                return;
1229        }
1230
1231        if (factory->priv->num_sessions > factory->priv->max_displays ||
1232            (!gdm_address_is_local (address) &&
1233             gdm_xdmcp_num_displays_from_host (factory, address) > factory->priv->max_displays_per_host)) {
1234                g_debug ("GdmXdmcpDisplayFactory: reached maximum number of clients - ignoring indirect query");
1235                return;
1236        }
1237
1238        res = XdmcpReadARRAYofARRAY8 (&factory->priv->buf, &clnt_authlist);
1239        if G_UNLIKELY (! res) {
1240                g_warning (_("Could not extract authlist from packet"));
1241                return;
1242        }
1243
1244        expected_len = 1;
1245
1246        for (i = 0 ; i < clnt_authlist.length ; i++) {
1247                expected_len += 2 + clnt_authlist.data[i].length;
1248        }
1249
1250        /* Try to look up the display in
1251         * the pending list. If found send a FORWARD_QUERY to the
1252         * chosen manager. Otherwise alloc a new indirect display. */
1253
1254        if (len != expected_len) {
1255                g_warning (_("Error in checksum"));
1256                goto out;
1257        }
1258
1259
1260        ic = indirect_client_lookup (factory, address);
1261
1262        if (ic != NULL && ic->chosen_address != NULL) {
1263                /* if user chose us, then just send willing */
1264                if (gdm_address_is_local (ic->chosen_address)) {
1265                        g_debug ("GdmXdmcpDisplayFactory: the chosen address is local - dropping indirect");
1266
1267                        /* get rid of indirect, so that we don't get
1268                         * the chooser */
1269                        indirect_client_destroy (factory, ic);
1270                        gdm_xdmcp_send_willing (factory, address);
1271                } else if (gdm_address_is_loopback (address)) {
1272                        /* woohoo! fun, I have no clue how to get
1273                         * the correct ip, SO I just send forward
1274                         * queries with all the different IPs */
1275                        const GList *list = gdm_address_peek_local_list ();
1276
1277                        g_debug ("GdmXdmcpDisplayFactory: the chosen address is a loopback");
1278
1279                        while (list != NULL) {
1280                                GdmAddress *saddr = list->data;
1281
1282                                if (! gdm_address_is_loopback (saddr)) {
1283                                        /* forward query to * chosen host */
1284                                        gdm_xdmcp_send_forward_query (factory,
1285                                                                      ic,
1286                                                                      address,
1287                                                                      saddr,
1288                                                                      &clnt_authlist);
1289                                }
1290
1291                                list = list->next;
1292                        }
1293                } else {
1294                        /* or send forward query to chosen host */
1295                        gdm_xdmcp_send_forward_query (factory,
1296                                                      ic,
1297                                                      address,
1298                                                      address,
1299                                                      &clnt_authlist);
1300                }
1301        } else if (ic == NULL) {
1302                ic = indirect_client_create (factory, address);
1303                if (ic != NULL) {
1304                        gdm_xdmcp_send_willing (factory, address);
1305                }
1306        } else  {
1307                gdm_xdmcp_send_willing (factory, address);
1308        }
1309
1310out:
1311        XdmcpDisposeARRAYofARRAY8 (&clnt_authlist);
1312}
1313
1314static void
1315forward_query_destroy (GdmXdmcpDisplayFactory *factory,
1316                       ForwardQuery           *q)
1317{
1318        if (q == NULL) {
1319                return;
1320        }
1321
1322        factory->priv->forward_queries = g_slist_remove (factory->priv->forward_queries, q);
1323
1324        q->acctime = 0;
1325
1326        {
1327                char *host;
1328
1329                host = NULL;
1330                gdm_address_get_numeric_info (q->dsp_address, &host, NULL);
1331                g_debug ("GdmXdmcpDisplayFactory: Disposing %s", host);
1332                g_free (host);
1333        }
1334
1335        g_free (q->dsp_address);
1336        q->dsp_address = NULL;
1337        g_free (q->from_address);
1338        q->from_address = NULL;
1339
1340        g_free (q);
1341}
1342
1343static gboolean
1344remove_oldest_forward (GdmXdmcpDisplayFactory *factory)
1345{
1346        GSList       *li;
1347        ForwardQuery *oldest = NULL;
1348
1349        for (li = factory->priv->forward_queries; li != NULL; li = li->next) {
1350                ForwardQuery *query = li->data;
1351
1352                if (oldest == NULL || query->acctime < oldest->acctime) {
1353                        oldest = query;
1354                }
1355        }
1356
1357        if (oldest != NULL) {
1358                forward_query_destroy (factory, oldest);
1359                return TRUE;
1360        } else {
1361                return FALSE;
1362        }
1363}
1364
1365static ForwardQuery *
1366forward_query_create (GdmXdmcpDisplayFactory *factory,
1367                         GdmAddress             *mgr_address,
1368                         GdmAddress             *dsp_address)
1369{
1370        ForwardQuery *q;
1371        int           count;
1372
1373        count = g_slist_length (factory->priv->forward_queries);
1374
1375        while (count > GDM_MAX_FORWARD_QUERIES && remove_oldest_forward (factory)) {
1376                count--;
1377        }
1378
1379        q = g_new0 (ForwardQuery, 1);
1380        q->dsp_address = gdm_address_copy (dsp_address);
1381        q->from_address = gdm_address_copy (mgr_address);
1382
1383        factory->priv->forward_queries = g_slist_prepend (factory->priv->forward_queries, q);
1384
1385        return q;
1386}
1387
1388static ForwardQuery *
1389forward_query_lookup (GdmXdmcpDisplayFactory *factory,
1390                          GdmAddress             *address)
1391{
1392        GSList       *li;
1393        GSList       *qlist;
1394        ForwardQuery *ret;
1395        time_t        curtime;
1396
1397        curtime = time (NULL);
1398        ret = NULL;
1399
1400        qlist = g_slist_copy (factory->priv->forward_queries);
1401
1402        for (li = qlist; li != NULL; li = li->next) {
1403                ForwardQuery *q;
1404                char         *host;
1405                char         *serv;
1406
1407                q = (ForwardQuery *) li->data;
1408
1409                if (q == NULL) {
1410                        continue;
1411                }
1412
1413                host = NULL;
1414                serv = NULL;
1415                gdm_address_get_numeric_info (q->dsp_address, &host, &serv);
1416
1417                g_debug ("GdmXdmcpDisplayFactory: comparing %s:%s", host, serv);
1418                if (gdm_address_equal (q->dsp_address, address)) {
1419                        ret = q;
1420                        g_free (host);
1421                        g_free (serv);
1422                        break;
1423                }
1424
1425                if (q->acctime > 0 &&  curtime > q->acctime + GDM_FORWARD_QUERY_TIMEOUT) {
1426                        g_debug ("GdmXdmcpDisplayFactory: Disposing stale forward query from %s:%s",
1427                                 host, serv);
1428
1429                        forward_query_destroy (factory, q);
1430                }
1431
1432                g_free (host);
1433                g_free (serv);
1434        }
1435
1436        g_slist_free (qlist);
1437
1438        if (ret == NULL) {
1439                char *host;
1440
1441                host = NULL;
1442                gdm_address_get_numeric_info (address, &host, NULL);
1443                g_debug ("GdmXdmcpDisplayFactory: Host %s not found",
1444                         host);
1445                g_free (host);
1446        }
1447
1448        return ret;
1449}
1450
1451static gboolean
1452create_address_from_request (ARRAY8      *req_addr,
1453                             ARRAY8      *req_port,
1454                             int          family,
1455                             GdmAddress **address)
1456{
1457        uint16_t         port;
1458        char             host_buf [NI_MAXHOST];
1459        char             serv_buf [NI_MAXSERV];
1460        char            *serv;
1461        const char      *host;
1462        struct addrinfo  hints;
1463        struct addrinfo *ai_list;
1464        struct addrinfo *ai;
1465        int              gaierr;
1466        gboolean         found;
1467
1468        if (address != NULL) {
1469                *address = NULL;
1470        }
1471
1472        if (req_addr == NULL) {
1473                return FALSE;
1474        }
1475
1476        serv = NULL;
1477        if (req_port != NULL) {
1478                /* port must always be length 2 */
1479                if (req_port->length != 2) {
1480                        return FALSE;
1481                }
1482
1483                memcpy (&port, req_port->data, 2);
1484                snprintf (serv_buf, sizeof (serv_buf), "%d", ntohs (port));
1485                serv = serv_buf;
1486        } else {
1487                /* assume XDM_UDP_PORT */
1488                snprintf (serv_buf, sizeof (serv_buf), "%d", XDM_UDP_PORT);
1489                serv = serv_buf;
1490        }
1491
1492        host = NULL;
1493        if (req_addr->length == 4) {
1494                host = inet_ntop (AF_INET,
1495                                  (const void *)req_addr->data,
1496                                  host_buf,
1497                                  sizeof (host_buf));
1498        } else if (req_addr->length == 16) {
1499                host = inet_ntop (AF_INET6,
1500                                  (const void *)req_addr->data,
1501                                  host_buf,
1502                                  sizeof (host_buf));
1503        }
1504
1505        if (host == NULL) {
1506                g_warning (_("Bad address"));
1507                return FALSE;
1508        }
1509
1510        memset (&hints, 0, sizeof (hints));
1511        hints.ai_family = family;
1512        hints.ai_flags = AI_V4MAPPED; /* this should convert IPv4 address to IPv6 if needed */
1513        if ((gaierr = getaddrinfo (host, serv, &hints, &ai_list)) != 0) {
1514                g_warning ("Unable get address: %s", gai_strerror (gaierr));
1515                return FALSE;
1516        }
1517
1518        /* just take the first one */
1519        ai = ai_list;
1520
1521        found = FALSE;
1522        if (ai != NULL) {
1523                found = TRUE;
1524                if (address != NULL) {
1525                        *address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen);
1526                }
1527        }
1528
1529        freeaddrinfo (ai_list);
1530
1531        return found;
1532}
1533
1534static void
1535gdm_xdmcp_whack_queued_managed_forwards (GdmXdmcpDisplayFactory *factory,
1536                                         GdmAddress             *address,
1537                                         GdmAddress             *origin)
1538{
1539        GSList *li;
1540
1541        for (li = factory->priv->managed_forwards; li != NULL; li = li->next) {
1542                ManagedForward *mf = li->data;
1543
1544                if (gdm_address_equal (mf->manager, address) &&
1545                    gdm_address_equal (mf->origin, origin)) {
1546                        factory->priv->managed_forwards = g_slist_remove_link (factory->priv->managed_forwards, li);
1547                        g_slist_free_1 (li);
1548                        g_source_remove (mf->handler);
1549                        /* mf freed by glib */
1550                        return;
1551                }
1552        }
1553}
1554
1555static void
1556gdm_xdmcp_handle_forward_query (GdmXdmcpDisplayFactory *factory,
1557                                GdmAddress             *address,
1558                                int                     len)
1559{
1560        ARRAY8                   clnt_addr;
1561        ARRAY8                   clnt_port;
1562        ARRAYofARRAY8            clnt_authlist;
1563        int                      i;
1564        int                      explen;
1565        GdmAddress              *disp_address;
1566        char                    *host;
1567        char                    *serv;
1568
1569        disp_address = NULL;
1570
1571        /* Check with tcp_wrappers if client is allowed to access */
1572        if (! gdm_xdmcp_host_allow (address)) {
1573                char *host2;
1574
1575                host2 = NULL;
1576                gdm_address_get_numeric_info (address, &host2, NULL);
1577
1578                g_warning ("%s: Got FORWARD_QUERY from banned host %s",
1579                           "gdm_xdmcp_handle_forward query",
1580                           host2);
1581                g_free (host2);
1582                return;
1583        }
1584
1585        /* Read display address */
1586        if G_UNLIKELY (! XdmcpReadARRAY8 (&factory->priv->buf, &clnt_addr)) {
1587                g_warning (_("%s: Could not read display address"),
1588                           "gdm_xdmcp_handle_forward_query");
1589                return;
1590        }
1591
1592        /* Read display port */
1593        if G_UNLIKELY (! XdmcpReadARRAY8 (&factory->priv->buf, &clnt_port)) {
1594                XdmcpDisposeARRAY8 (&clnt_addr);
1595                g_warning (_("%s: Could not read display port number"),
1596                           "gdm_xdmcp_handle_forward_query");
1597                return;
1598        }
1599
1600        /* Extract array of authentication names from Xdmcp packet */
1601        if G_UNLIKELY (! XdmcpReadARRAYofARRAY8 (&factory->priv->buf, &clnt_authlist)) {
1602                XdmcpDisposeARRAY8 (&clnt_addr);
1603                XdmcpDisposeARRAY8 (&clnt_port);
1604                g_warning (_("%s: Could not extract authlist from packet"),
1605                           "gdm_xdmcp_handle_forward_query");
1606                return;
1607        }
1608
1609        /* Crude checksumming */
1610        explen = 1;
1611        explen += 2 + clnt_addr.length;
1612        explen += 2 + clnt_port.length;
1613
1614        for (i = 0 ; i < clnt_authlist.length ; i++) {
1615                char *s = g_strndup ((char *) clnt_authlist.data[i].data,
1616                                     clnt_authlist.length);
1617                g_debug ("GdmXdmcpDisplayFactory: authlist: %s", s);
1618                g_free (s);
1619
1620                explen += 2 + clnt_authlist.data[i].length;
1621        }
1622
1623        if G_UNLIKELY (len != explen) {
1624                g_warning (_("%s: Error in checksum"),
1625                           "gdm_xdmcp_handle_forward_query");
1626                goto out;
1627        }
1628
1629        if (! create_address_from_request (&clnt_addr, &clnt_port, gdm_address_get_family_type (address), &disp_address)) {
1630                g_warning ("Unable to parse address for request");
1631                goto out;
1632        }
1633
1634        gdm_xdmcp_whack_queued_managed_forwards (factory,
1635                                                 address,
1636                                                 disp_address);
1637
1638        host = NULL;
1639        serv = NULL;
1640        gdm_address_get_numeric_info (disp_address, &host, &serv);
1641        g_debug ("GdmXdmcpDisplayFactory: Got FORWARD_QUERY for display: %s, port %s",
1642                 host, serv);
1643        g_free (host);
1644        g_free (serv);
1645
1646        /* Check with tcp_wrappers if display is allowed to access */
1647        if (gdm_xdmcp_host_allow (disp_address)) {
1648                ForwardQuery *q;
1649
1650                q = forward_query_lookup (factory, disp_address);
1651                if (q != NULL) {
1652                        forward_query_destroy (factory, q);
1653                }
1654
1655                forward_query_create (factory, address, disp_address);
1656
1657                gdm_xdmcp_send_willing (factory, disp_address);
1658        }
1659
1660 out:
1661
1662        gdm_address_free (disp_address);
1663
1664        XdmcpDisposeARRAYofARRAY8 (&clnt_authlist);
1665        XdmcpDisposeARRAY8 (&clnt_port);
1666        XdmcpDisposeARRAY8 (&clnt_addr);
1667}
1668
1669static void
1670gdm_xdmcp_really_send_managed_forward (GdmXdmcpDisplayFactory *factory,
1671                                       GdmAddress      *address,
1672                                       GdmAddress      *origin)
1673{
1674        ARRAY8      addr;
1675        XdmcpHeader header;
1676        char       *host;
1677
1678        host = NULL;
1679        gdm_address_get_numeric_info (address, &host, NULL);
1680        g_debug ("GdmXdmcpDisplayFactory: Sending MANAGED_FORWARD to %s", host);
1681        g_free (host);
1682
1683        set_address_for_request (origin, &addr);
1684
1685        header.opcode = (CARD16) GDM_XDMCP_MANAGED_FORWARD;
1686        header.length = 4 + addr.length;
1687        header.version = GDM_XDMCP_PROTOCOL_VERSION;
1688        XdmcpWriteHeader (&factory->priv->buf, &header);
1689
1690        XdmcpWriteARRAY8 (&factory->priv->buf, &addr);
1691        XdmcpFlush (factory->priv->socket_fd,
1692                    &factory->priv->buf,
1693                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
1694                    (int)sizeof (struct sockaddr_storage));
1695
1696        g_free (addr.data);
1697}
1698
1699static gboolean
1700managed_forward_handler (ManagedForward *mf)
1701{
1702        if (mf->xdmcp_display_factory->priv->socket_fd > 0) {
1703                gdm_xdmcp_really_send_managed_forward (mf->xdmcp_display_factory,
1704                                                       mf->manager,
1705                                                       mf->origin);
1706        }
1707
1708        mf->times++;
1709        if (mf->xdmcp_display_factory->priv->socket_fd <= 0 || mf->times >= 2) {
1710                mf->xdmcp_display_factory->priv->managed_forwards = g_slist_remove (mf->xdmcp_display_factory->priv->managed_forwards, mf);
1711                mf->handler = 0;
1712                /* mf freed by glib */
1713                return FALSE;
1714        }
1715        return TRUE;
1716}
1717
1718static void
1719managed_forward_free (ManagedForward *mf)
1720{
1721        gdm_address_free (mf->origin);
1722        gdm_address_free (mf->manager);
1723        g_free (mf);
1724}
1725
1726static void
1727gdm_xdmcp_send_managed_forward (GdmXdmcpDisplayFactory *factory,
1728                                GdmAddress             *address,
1729                                GdmAddress             *origin)
1730{
1731        ManagedForward *mf;
1732
1733        gdm_xdmcp_really_send_managed_forward (factory, address, origin);
1734
1735        mf = g_new0 (ManagedForward, 1);
1736        mf->times = 0;
1737        mf->xdmcp_display_factory = factory;
1738
1739        mf->manager = gdm_address_copy (address);
1740        mf->origin = gdm_address_copy (origin);
1741
1742        mf->handler = g_timeout_add_full (G_PRIORITY_DEFAULT,
1743                                          MANAGED_FORWARD_INTERVAL,
1744                                          (GSourceFunc)managed_forward_handler,
1745                                          mf,
1746                                          (GDestroyNotify)managed_forward_free);
1747        factory->priv->managed_forwards = g_slist_prepend (factory->priv->managed_forwards, mf);
1748}
1749
1750static void
1751gdm_xdmcp_send_got_managed_forward (GdmXdmcpDisplayFactory *factory,
1752                                    GdmAddress             *address,
1753                                    GdmAddress             *origin)
1754{
1755        ARRAY8      addr;
1756        XdmcpHeader header;
1757        char       *host;
1758
1759        host = NULL;
1760        gdm_address_get_numeric_info (address, &host, NULL);
1761        g_debug ("GdmXdmcpDisplayFactory: Sending GOT_MANAGED_FORWARD to %s", host);
1762        g_free (host);
1763
1764        set_address_for_request (origin, &addr);
1765
1766        header.opcode = (CARD16) GDM_XDMCP_GOT_MANAGED_FORWARD;
1767        header.length = 4 + addr.length;
1768        header.version = GDM_XDMCP_PROTOCOL_VERSION;
1769        XdmcpWriteHeader (&factory->priv->buf, &header);
1770
1771        XdmcpWriteARRAY8 (&factory->priv->buf, &addr);
1772        XdmcpFlush (factory->priv->socket_fd,
1773                    &factory->priv->buf,
1774                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
1775                    (int)sizeof (struct sockaddr_storage));
1776}
1777
1778static gboolean
1779count_sessions (const char             *id,
1780                GdmDisplay             *display,
1781                GdmXdmcpDisplayFactory *factory)
1782{
1783        if (GDM_IS_XDMCP_DISPLAY (display)) {
1784                int status;
1785
1786                status = gdm_display_get_status (display);
1787
1788                if (status == GDM_DISPLAY_MANAGED) {
1789                        factory->priv->num_sessions++;
1790                } else if (status == GDM_DISPLAY_UNMANAGED) {
1791                        factory->priv->num_pending_sessions++;
1792                }
1793        }
1794
1795        return TRUE;
1796}
1797
1798static void
1799gdm_xdmcp_recount_sessions (GdmXdmcpDisplayFactory *factory)
1800{
1801        GdmDisplayStore *store;
1802
1803        factory->priv->num_sessions = 0;
1804        factory->priv->num_pending_sessions = 0;
1805
1806        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
1807        gdm_display_store_foreach (store,
1808                                   (GdmDisplayStoreFunc)count_sessions,
1809                                   factory);
1810}
1811
1812static gboolean
1813purge_displays (const char             *id,
1814                GdmDisplay             *display,
1815                GdmXdmcpDisplayFactory *factory)
1816{
1817        if (GDM_IS_XDMCP_DISPLAY (display)) {
1818                int status;
1819                time_t currtime;
1820                time_t acctime;
1821
1822                currtime = time (NULL);
1823                status = gdm_display_get_status (display);
1824                acctime = gdm_display_get_creation_time (display);
1825
1826                if (status == GDM_DISPLAY_UNMANAGED &&
1827                    currtime > acctime + factory->priv->max_wait) {
1828                        /* return TRUE to remove display */
1829                        return TRUE;
1830                }
1831        }
1832
1833        return FALSE;
1834}
1835
1836static void
1837gdm_xdmcp_displays_purge (GdmXdmcpDisplayFactory *factory)
1838{
1839        GdmDisplayStore *store;
1840
1841        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
1842
1843        gdm_display_store_foreach_remove (store,
1844                                          (GdmDisplayStoreFunc)purge_displays,
1845                                          factory);
1846
1847        gdm_xdmcp_recount_sessions (factory);
1848}
1849
1850typedef struct {
1851        const char *hostname;
1852        int         display_num;
1853} RemoveHostData;
1854
1855static gboolean
1856remove_host (const char     *id,
1857             GdmDisplay     *display,
1858             RemoveHostData *data)
1859{
1860        char *hostname;
1861        int   disp_num;
1862
1863        if (! GDM_IS_XDMCP_DISPLAY (display)) {
1864                return FALSE;
1865        }
1866
1867        gdm_display_get_remote_hostname (display, &hostname, NULL);
1868        gdm_display_get_x11_display_number (display, &disp_num, NULL);
1869
1870        if (disp_num == data->display_num &&
1871            hostname != NULL &&
1872            data->hostname != NULL &&
1873            strcmp (hostname, data->hostname) == 0) {
1874                /* return TRUE to remove */
1875                return TRUE;
1876        }
1877
1878        return FALSE;
1879}
1880
1881static void
1882display_dispose_check (GdmXdmcpDisplayFactory *factory,
1883                       const char             *hostname,
1884                       int                     display_num)
1885{
1886        RemoveHostData  *data;
1887        GdmDisplayStore *store;
1888
1889        if (hostname == NULL) {
1890                return;
1891        }
1892
1893        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
1894
1895        g_debug ("GdmXdmcpDisplayFactory: display_dispose_check (%s:%d)", hostname, display_num);
1896
1897        data = g_new0 (RemoveHostData, 1);
1898        data->hostname = hostname;
1899        data->display_num = display_num;
1900        gdm_display_store_foreach_remove (store,
1901                                          (GdmDisplayStoreFunc)remove_host,
1902                                          data);
1903        g_free (data);
1904
1905        gdm_xdmcp_recount_sessions (factory);
1906}
1907
1908static void
1909gdm_xdmcp_send_decline (GdmXdmcpDisplayFactory *factory,
1910                        GdmAddress             *address,
1911                        const char             *reason)
1912{
1913        XdmcpHeader      header;
1914        ARRAY8           authentype;
1915        ARRAY8           authendata;
1916        ARRAY8           status;
1917        ForwardQuery    *fq;
1918        char            *host;
1919
1920        host = NULL;
1921        gdm_address_get_numeric_info (address, &host, NULL);
1922        g_debug ("GdmXdmcpDisplayFactory: Sending DECLINE to %s", host);
1923        g_free (host);
1924
1925        authentype.data   = (CARD8 *) 0;
1926        authentype.length = (CARD16)  0;
1927
1928        authendata.data   = (CARD8 *) 0;
1929        authendata.length = (CARD16)  0;
1930
1931        status.data       = (CARD8 *) reason;
1932        status.length     = strlen ((char *) status.data);
1933
1934        header.version    = XDM_PROTOCOL_VERSION;
1935        header.opcode     = (CARD16) DECLINE;
1936        header.length     = 2 + status.length;
1937        header.length    += 2 + authentype.length;
1938        header.length    += 2 + authendata.length;
1939
1940        XdmcpWriteHeader (&factory->priv->buf, &header);
1941        XdmcpWriteARRAY8 (&factory->priv->buf, &status);
1942        XdmcpWriteARRAY8 (&factory->priv->buf, &authentype);
1943        XdmcpWriteARRAY8 (&factory->priv->buf, &authendata);
1944
1945        XdmcpFlush (factory->priv->socket_fd,
1946                    &factory->priv->buf,
1947                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
1948                    (int)sizeof (struct sockaddr_storage));
1949
1950        /* Send MANAGED_FORWARD to indicate that the connection
1951         * reached some sort of resolution */
1952        fq = forward_query_lookup (factory, address);
1953        if (fq != NULL) {
1954                gdm_xdmcp_send_managed_forward (factory, fq->from_address, address);
1955                forward_query_destroy (factory, fq);
1956        }
1957}
1958
1959static void
1960on_hostname_selected (GdmXdmcpChooserDisplay *display,
1961                      const char             *hostname,
1962                      GdmXdmcpDisplayFactory *factory)
1963{
1964        struct addrinfo  hints;
1965        struct addrinfo *ai_list;
1966        struct addrinfo *ai;
1967        int              gaierr;
1968        GdmAddress      *address;
1969        IndirectClient  *ic;
1970
1971        g_debug ("GdmXdmcpDisplayFactory: hostname selected: %s", hostname);
1972
1973        address = gdm_xdmcp_display_get_remote_address (GDM_XDMCP_DISPLAY (display));
1974
1975        g_assert (address != NULL);
1976
1977        ic = indirect_client_lookup (factory, address);
1978
1979        if (ic->chosen_address != NULL) {
1980                gdm_address_free (ic->chosen_address);
1981                ic->chosen_address = NULL;
1982        }
1983
1984        memset (&hints, 0, sizeof (hints));
1985        hints.ai_family = gdm_address_get_family_type (address);
1986        hints.ai_flags = AI_V4MAPPED; /* this should convert IPv4 address to IPv6 if needed */
1987        if ((gaierr = getaddrinfo (hostname, NULL, &hints, &ai_list)) != 0) {
1988                g_warning ("Unable get address: %s", gai_strerror (gaierr));
1989                return;
1990        }
1991
1992        /* just take the first one */
1993        ai = ai_list;
1994
1995        if (ai != NULL) {
1996                char *ip;
1997                ic->chosen_address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen);
1998
1999                ip = NULL;
2000                gdm_address_get_numeric_info (ic->chosen_address, &ip, NULL);
2001                g_debug ("GdmXdmcpDisplayFactory: hostname resolves to %s", ip);
2002                g_free (ip);
2003        }
2004
2005        freeaddrinfo (ai_list);
2006}
2007
2008static GdmDisplay *
2009gdm_xdmcp_display_create (GdmXdmcpDisplayFactory *factory,
2010                          const char             *hostname,
2011                          GdmAddress             *address,
2012                          int                     displaynum)
2013{
2014        GdmDisplay      *display;
2015        GdmDisplayStore *store;
2016        gboolean         use_chooser;
2017
2018        g_debug ("GdmXdmcpDisplayFactory: Creating xdmcp display for %s:%d", hostname, displaynum);
2019
2020        use_chooser = FALSE;
2021        if (factory->priv->honor_indirect) {
2022                IndirectClient *ic;
2023
2024                ic = indirect_client_lookup (factory, address);
2025
2026                /* This was an indirect thingie and nothing was yet chosen,
2027                 * use a chooser */
2028                if (ic != NULL && ic->chosen_address == NULL) {
2029                        use_chooser = TRUE;
2030                }
2031        }
2032
2033        if (use_chooser) {
2034                display = gdm_xdmcp_chooser_display_new (hostname,
2035                                                         displaynum,
2036                                                         address,
2037                                                         get_next_session_serial (factory));
2038                g_signal_connect (display, "hostname-selected", G_CALLBACK (on_hostname_selected), factory);
2039        } else {
2040                display = gdm_xdmcp_greeter_display_new (hostname,
2041                                                         displaynum,
2042                                                         address,
2043                                                         get_next_session_serial (factory));
2044        }
2045
2046        if (display == NULL) {
2047                goto out;
2048        }
2049
2050        if (! gdm_display_prepare (display)) {
2051                gdm_display_unmanage (display);
2052                g_object_unref (display);
2053                display = NULL;
2054                goto out;
2055        }
2056
2057        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
2058        gdm_display_store_add (store, display);
2059
2060        factory->priv->num_pending_sessions++;
2061 out:
2062
2063        return display;
2064}
2065
2066static void
2067gdm_xdmcp_send_accept (GdmXdmcpDisplayFactory *factory,
2068                       GdmAddress             *address,
2069                       CARD32                  session_id,
2070                       ARRAY8Ptr               authentication_name,
2071                       ARRAY8Ptr               authentication_data,
2072                       ARRAY8Ptr               authorization_name,
2073                       ARRAY8Ptr               authorization_data)
2074{
2075        XdmcpHeader header;
2076        char       *host;
2077
2078        header.version    = XDM_PROTOCOL_VERSION;
2079        header.opcode     = (CARD16) ACCEPT;
2080        header.length     = 4;
2081        header.length    += 2 + authentication_name->length;
2082        header.length    += 2 + authentication_data->length;
2083        header.length    += 2 + authorization_name->length;
2084        header.length    += 2 + authorization_data->length;
2085
2086        XdmcpWriteHeader (&factory->priv->buf, &header);
2087        XdmcpWriteCARD32 (&factory->priv->buf, session_id);
2088        XdmcpWriteARRAY8 (&factory->priv->buf, authentication_name);
2089        XdmcpWriteARRAY8 (&factory->priv->buf, authentication_data);
2090        XdmcpWriteARRAY8 (&factory->priv->buf, authorization_name);
2091        XdmcpWriteARRAY8 (&factory->priv->buf, authorization_data);
2092
2093        XdmcpFlush (factory->priv->socket_fd,
2094                    &factory->priv->buf,
2095                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
2096                    (int)sizeof (struct sockaddr_storage));
2097
2098        host = NULL;
2099        gdm_address_get_numeric_info (address, &host, NULL);
2100        g_debug ("GdmXdmcpDisplayFactory: Sending ACCEPT to %s with SessionID=%ld",
2101                 host,
2102                 (long)session_id);
2103        g_free (host);
2104}
2105
2106static void
2107gdm_xdmcp_handle_request (GdmXdmcpDisplayFactory *factory,
2108                          GdmAddress             *address,
2109                          int                     len)
2110{
2111        CARD16        clnt_dspnum;
2112        ARRAY16       clnt_conntyp;
2113        ARRAYofARRAY8 clnt_addr;
2114        ARRAY8        clnt_authname;
2115        ARRAY8        clnt_authdata;
2116        ARRAYofARRAY8 clnt_authorization_names;
2117        ARRAY8        clnt_manufacturer;
2118        int           explen;
2119        int           i;
2120        gboolean      mitauth;
2121        gboolean      entered;
2122        char         *hostname;
2123
2124        mitauth = FALSE;
2125        entered = FALSE;
2126
2127        hostname = NULL;
2128        gdm_address_get_numeric_info (address, &hostname, NULL);
2129        g_debug ("GdmXdmcpDisplayFactory: Got REQUEST from %s", hostname);
2130
2131        /* Check with tcp_wrappers if client is allowed to access */
2132        if (! gdm_xdmcp_host_allow (address)) {
2133                g_warning (_("%s: Got REQUEST from banned host %s"),
2134                           "gdm_xdmcp_handle_request",
2135                           hostname);
2136                goto out;
2137        }
2138
2139        gdm_xdmcp_displays_purge (factory); /* Purge pending displays */
2140
2141        /* Remote display number */
2142        if G_UNLIKELY (! XdmcpReadCARD16 (&factory->priv->buf, &clnt_dspnum)) {
2143                g_warning (_("%s: Could not read Display Number"),
2144                           "gdm_xdmcp_handle_request");
2145                goto out;
2146        }
2147
2148        /* We don't care about connection type. Address says it all */
2149        if G_UNLIKELY (! XdmcpReadARRAY16 (&factory->priv->buf, &clnt_conntyp)) {
2150                g_warning (_("%s: Could not read Connection Type"),
2151                           "gdm_xdmcp_handle_request");
2152                goto out;
2153        }
2154
2155        /* This is TCP/IP - we don't care */
2156        if G_UNLIKELY (! XdmcpReadARRAYofARRAY8 (&factory->priv->buf, &clnt_addr)) {
2157                g_warning (_("%s: Could not read Client Address"),
2158                           "gdm_xdmcp_handle_request");
2159                XdmcpDisposeARRAY16 (&clnt_conntyp);
2160                goto out;
2161        }
2162
2163        /* Read authentication type */
2164        if G_UNLIKELY (! XdmcpReadARRAY8 (&factory->priv->buf, &clnt_authname)) {
2165                g_warning (_("%s: Could not read Authentication Names"),
2166                           "gdm_xdmcp_handle_request");
2167                XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
2168                XdmcpDisposeARRAY16 (&clnt_conntyp);
2169                goto out;
2170        }
2171
2172        /* Read authentication data */
2173        if G_UNLIKELY (! XdmcpReadARRAY8 (&factory->priv->buf, &clnt_authdata)) {
2174                g_warning (_("%s: Could not read Authentication Data"),
2175                           "gdm_xdmcp_handle_request");
2176                XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
2177                XdmcpDisposeARRAY16 (&clnt_conntyp);
2178                XdmcpDisposeARRAY8 (&clnt_authname);
2179                goto out;
2180        }
2181
2182        /* Read and select from supported authorization list */
2183        if G_UNLIKELY (! XdmcpReadARRAYofARRAY8 (&factory->priv->buf, &clnt_authorization_names)) {
2184                g_warning (_("%s: Could not read Authorization List"),
2185                           "gdm_xdmcp_handle_request");
2186                XdmcpDisposeARRAY8 (&clnt_authdata);
2187                XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
2188                XdmcpDisposeARRAY16 (&clnt_conntyp);
2189                XdmcpDisposeARRAY8 (&clnt_authname);
2190                goto out;
2191        }
2192
2193        /* libXdmcp doesn't terminate strings properly so we cheat and use strncmp () */
2194        for (i = 0 ; i < clnt_authorization_names.length ; i++) {
2195                if (clnt_authorization_names.data[i].length == 18 &&
2196                    strncmp ((char *) clnt_authorization_names.data[i].data, "MIT-MAGIC-COOKIE-1", 18) == 0) {
2197                        mitauth = TRUE;
2198                }
2199        }
2200
2201        /* Manufacturer ID */
2202        if G_UNLIKELY (! XdmcpReadARRAY8 (&factory->priv->buf, &clnt_manufacturer)) {
2203                g_warning (_("%s: Could not read Manufacturer ID"),
2204                           "gdm_xdmcp_handle_request");
2205                XdmcpDisposeARRAY8 (&clnt_authname);
2206                XdmcpDisposeARRAY8 (&clnt_authdata);
2207                XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
2208                XdmcpDisposeARRAYofARRAY8 (&clnt_authorization_names);
2209                XdmcpDisposeARRAY16 (&clnt_conntyp);
2210                goto out;
2211        }
2212
2213        /* Crude checksumming */
2214        explen = 2;                 /* Display Number */
2215        explen += 1 + 2 * clnt_conntyp.length; /* Connection Type */
2216        explen += 1;                /* Connection Address */
2217        for (i = 0 ; i < clnt_addr.length ; i++) {
2218                explen += 2 + clnt_addr.data[i].length;
2219        }
2220        explen += 2 + clnt_authname.length; /* Authentication Name */
2221        explen += 2 + clnt_authdata.length; /* Authentication Data */
2222        explen += 1;                /* Authorization Names */
2223        for (i = 0 ; i < clnt_authorization_names.length ; i++) {
2224                explen += 2 + clnt_authorization_names.data[i].length;
2225        }
2226
2227        explen += 2 + clnt_manufacturer.length;
2228
2229        if G_UNLIKELY (explen != len) {
2230                g_warning (_("%s: Failed checksum from %s"),
2231                           "gdm_xdmcp_handle_request",
2232                           hostname);
2233
2234                XdmcpDisposeARRAY8 (&clnt_authname);
2235                XdmcpDisposeARRAY8 (&clnt_authdata);
2236                XdmcpDisposeARRAY8 (&clnt_manufacturer);
2237                XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
2238                XdmcpDisposeARRAYofARRAY8 (&clnt_authorization_names);
2239                XdmcpDisposeARRAY16 (&clnt_conntyp);
2240                goto out;
2241        }
2242
2243        {
2244                char *s = g_strndup ((char *) clnt_manufacturer.data, clnt_manufacturer.length);
2245                g_debug ("GdmXdmcpDisplayFactory: xdmcp_pending=%d, MaxPending=%d, xdmcp_sessions=%d, MaxSessions=%d, ManufacturerID=%s",
2246                         factory->priv->num_pending_sessions,
2247                         factory->priv->max_pending_displays,
2248                         factory->priv->num_sessions,
2249                         factory->priv->max_displays,
2250                         s != NULL ? s : "");
2251                g_free (s);
2252        }
2253
2254        /* Check if ok to manage display */
2255        if (mitauth &&
2256            factory->priv->num_sessions < factory->priv->max_displays &&
2257            (gdm_address_is_local (address) ||
2258             gdm_xdmcp_num_displays_from_host (factory, address) < factory->priv->max_displays_per_host)) {
2259                entered = TRUE;
2260        }
2261
2262        if (entered) {
2263
2264                /* Check if we are already talking to this host */
2265                display_dispose_check (factory, hostname, clnt_dspnum);
2266
2267                if (factory->priv->num_pending_sessions >= factory->priv->max_pending_displays) {
2268                        g_debug ("GdmXdmcpDisplayFactory: maximum pending");
2269                        /* Don't translate, this goes over the wire to servers where we
2270                         * don't know the charset or language, so it must be ascii */
2271                        gdm_xdmcp_send_decline (factory, address, "Maximum pending servers");
2272                } else {
2273                        GdmDisplay *display;
2274
2275                        display = gdm_xdmcp_display_create (factory,
2276                                                            hostname,
2277                                                            address,
2278                                                            clnt_dspnum);
2279
2280                        if (display != NULL) {
2281                                ARRAY8  authentication_name;
2282                                ARRAY8  authentication_data;
2283                                ARRAY8  authorization_name;
2284                                ARRAY8  authorization_data;
2285                                gint32  session_number;
2286                                GArray *cookie;
2287                                char   *name;
2288
2289                                gdm_display_get_x11_cookie (display, &cookie, NULL);
2290
2291                                gdm_display_get_x11_display_name (display, &name, NULL);
2292
2293                                g_debug ("GdmXdmcpDisplayFactory: Sending authorization key for display %s", name);
2294                                g_free (name);
2295
2296                                g_debug ("GdmXdmcpDisplayFactory: cookie len %d", (int) cookie->len);
2297
2298                                session_number = gdm_xdmcp_display_get_session_number (GDM_XDMCP_DISPLAY (display));
2299
2300                                /* the send accept will fail if cookie is null */
2301                                g_assert (cookie != NULL);
2302
2303                                authentication_name.data   = NULL;
2304                                authentication_name.length = 0;
2305                                authentication_data.data   = NULL;
2306                                authentication_data.length = 0;
2307
2308                                authorization_name.data     = (CARD8 *) "MIT-MAGIC-COOKIE-1";
2309                                authorization_name.length   = strlen ((char *) authorization_name.data);
2310
2311                                authorization_data.data     = (CARD8 *) cookie->data;
2312                                authorization_data.length   = cookie->len;
2313
2314                                /* the addrs are NOT copied */
2315                                gdm_xdmcp_send_accept (factory,
2316                                                       address,
2317                                                       session_number,
2318                                                       &authentication_name,
2319                                                       &authentication_data,
2320                                                       &authorization_name,
2321                                                       &authorization_data);
2322
2323                                g_array_free (cookie, TRUE);
2324                        }
2325                }
2326        } else {
2327                /* Don't translate, this goes over the wire to servers where we
2328                 * don't know the charset or language, so it must be ascii */
2329                if ( ! mitauth) {
2330                        gdm_xdmcp_send_decline (factory,
2331                                                address,
2332                                                "Only MIT-MAGIC-COOKIE-1 supported");
2333                } else if (factory->priv->num_sessions >= factory->priv->max_displays) {
2334                        g_warning ("Maximum number of open XDMCP sessions reached");
2335                        gdm_xdmcp_send_decline (factory,
2336                                                address,
2337                                                "Maximum number of open sessions reached");
2338                } else {
2339                        g_debug ("GdmXdmcpDisplayFactory: Maximum number of open XDMCP sessions from host %s reached",
2340                                 hostname);
2341                        gdm_xdmcp_send_decline (factory,
2342                                                address,
2343                                                "Maximum number of open sessions from your host reached");
2344                }
2345        }
2346
2347        XdmcpDisposeARRAY8 (&clnt_authname);
2348        XdmcpDisposeARRAY8 (&clnt_authdata);
2349        XdmcpDisposeARRAY8 (&clnt_manufacturer);
2350        XdmcpDisposeARRAYofARRAY8 (&clnt_addr);
2351        XdmcpDisposeARRAYofARRAY8 (&clnt_authorization_names);
2352        XdmcpDisposeARRAY16 (&clnt_conntyp);
2353 out:
2354        g_free (hostname);
2355}
2356
2357static gboolean
2358lookup_by_session_id (const char *id,
2359                      GdmDisplay *display,
2360                      gpointer    data)
2361{
2362        CARD32 sessid;
2363        CARD32 session_id;
2364
2365        sessid = GPOINTER_TO_INT (data);
2366
2367        if (! GDM_IS_XDMCP_DISPLAY (display)) {
2368                return FALSE;
2369        }
2370
2371        session_id = gdm_xdmcp_display_get_session_number (GDM_XDMCP_DISPLAY (display));
2372
2373        if (session_id == sessid) {
2374                return TRUE;
2375        }
2376
2377        return FALSE;
2378}
2379
2380static GdmDisplay *
2381gdm_xdmcp_display_lookup (GdmXdmcpDisplayFactory *factory,
2382                          CARD32                  sessid)
2383{
2384        GdmDisplay      *display;
2385        GdmDisplayStore *store;
2386
2387        if (sessid == 0) {
2388                return NULL;
2389        }
2390
2391        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
2392        display = gdm_display_store_find (store,
2393                                          (GdmDisplayStoreFunc)lookup_by_session_id,
2394                                          GINT_TO_POINTER (sessid));
2395
2396        return display;
2397}
2398
2399static void
2400gdm_xdmcp_send_failed (GdmXdmcpDisplayFactory *factory,
2401                       GdmAddress             *address,
2402                       CARD32                  sessid)
2403{
2404        XdmcpHeader header;
2405        ARRAY8      status;
2406
2407        g_debug ("GdmXdmcpDisplayFactory: Sending FAILED to %ld", (long)sessid);
2408
2409        /*
2410         * Don't translate, this goes over the wire to servers where we
2411         * don't know the charset or language, so it must be ascii
2412         */
2413        status.data    = (CARD8 *) "Failed to start session";
2414        status.length  = strlen ((char *) status.data);
2415
2416        header.version = XDM_PROTOCOL_VERSION;
2417        header.opcode  = (CARD16) FAILED;
2418        header.length  = 6 + status.length;
2419
2420        XdmcpWriteHeader (&factory->priv->buf, &header);
2421        XdmcpWriteCARD32 (&factory->priv->buf, sessid);
2422        XdmcpWriteARRAY8 (&factory->priv->buf, &status);
2423
2424        XdmcpFlush (factory->priv->socket_fd,
2425                    &factory->priv->buf,
2426                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
2427                    (int)sizeof (struct sockaddr_storage));
2428}
2429
2430static void
2431gdm_xdmcp_send_refuse (GdmXdmcpDisplayFactory *factory,
2432                       GdmAddress             *address,
2433                       CARD32                  sessid)
2434{
2435        XdmcpHeader   header;
2436        ForwardQuery *fq;
2437
2438        g_debug ("GdmXdmcpDisplayFactory: Sending REFUSE to %ld",
2439                 (long)sessid);
2440
2441        header.version = XDM_PROTOCOL_VERSION;
2442        header.opcode  = (CARD16) REFUSE;
2443        header.length  = 4;
2444
2445        XdmcpWriteHeader (&factory->priv->buf, &header);
2446        XdmcpWriteCARD32 (&factory->priv->buf, sessid);
2447
2448        XdmcpFlush (factory->priv->socket_fd,
2449                    &factory->priv->buf,
2450                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
2451                    (int)sizeof (struct sockaddr_storage));
2452
2453        /*
2454         * This was from a forwarded query quite apparently so
2455         * send MANAGED_FORWARD
2456         */
2457        fq = forward_query_lookup (factory, address);
2458        if (fq != NULL) {
2459                gdm_xdmcp_send_managed_forward (factory, fq->from_address, address);
2460                forward_query_destroy (factory, fq);
2461        }
2462}
2463
2464static void
2465gdm_xdmcp_handle_manage (GdmXdmcpDisplayFactory *factory,
2466                         GdmAddress             *address,
2467                         int                     len)
2468{
2469        CARD32              clnt_sessid;
2470        CARD16              clnt_dspnum;
2471        ARRAY8              clnt_dspclass;
2472        GdmDisplay         *display;
2473        ForwardQuery       *fq;
2474        char               *host;
2475
2476        host = NULL;
2477        gdm_address_get_numeric_info (address, &host, NULL);
2478        g_debug ("GdmXdmcpDisplayFactory: Got MANAGE from %s", host);
2479
2480        /* Check with tcp_wrappers if client is allowed to access */
2481        if (! gdm_xdmcp_host_allow (address)) {
2482                g_warning (_("%s: Got Manage from banned host %s"),
2483                           "gdm_xdmcp_handle_manage",
2484                           host);
2485                g_free (host);
2486                return;
2487        }
2488
2489        /* SessionID */
2490        if G_UNLIKELY (! XdmcpReadCARD32 (&factory->priv->buf, &clnt_sessid)) {
2491                g_warning (_("%s: Could not read Session ID"),
2492                           "gdm_xdmcp_handle_manage");
2493                goto out;
2494        }
2495
2496        /* Remote display number */
2497        if G_UNLIKELY (! XdmcpReadCARD16 (&factory->priv->buf, &clnt_dspnum)) {
2498                g_warning (_("%s: Could not read Display Number"),
2499                           "gdm_xdmcp_handle_manage");
2500                goto out;
2501        }
2502
2503        /* Display Class */
2504        if G_UNLIKELY (! XdmcpReadARRAY8 (&factory->priv->buf, &clnt_dspclass)) {
2505                g_warning (_("%s: Could not read Display Class"),
2506                           "gdm_xdmcp_handle_manage");
2507                goto out;
2508        }
2509
2510        {
2511                char *s = g_strndup ((char *) clnt_dspclass.data, clnt_dspclass.length);
2512                g_debug ("GdmXdmcpDisplayFactory: Got display=%d, SessionID=%ld Class=%s from %s",
2513                         (int)clnt_dspnum,
2514                         (long)clnt_sessid,
2515                         s != NULL ? s : "",
2516                         host);
2517
2518                g_free (s);
2519        }
2520
2521        display = gdm_xdmcp_display_lookup (factory, clnt_sessid);
2522        if (display != NULL &&
2523            gdm_display_get_status (display) == GDM_DISPLAY_PREPARED) {
2524                char *name;
2525
2526                name = NULL;
2527                gdm_display_get_x11_display_name (display, &name, NULL);
2528                g_debug ("GdmXdmcpDisplayFactory: Looked up %s", name);
2529                g_free (name);
2530
2531                if (factory->priv->honor_indirect) {
2532                        IndirectClient *ic;
2533
2534                        ic = indirect_client_lookup (factory, address);
2535
2536                        /* This was an indirect thingie and nothing was yet chosen,
2537                         * use a chooser */
2538                        if (ic != NULL && ic->chosen_address == NULL) {
2539                                g_debug ("GdmXdmcpDisplayFactory: use chooser");
2540                                /*d->use_chooser = TRUE;
2541                                  d->indirect_id = ic->id;*/
2542                        } else {
2543                                /*d->indirect_id = 0;
2544                                  d->use_chooser = FALSE;*/
2545                                if (ic != NULL) {
2546                                        indirect_client_destroy (factory, ic);
2547                                }
2548                        }
2549                } else {
2550
2551                }
2552
2553                /* this was from a forwarded query quite apparently so
2554                 * send MANAGED_FORWARD */
2555                fq = forward_query_lookup (factory, address);
2556                if (fq != NULL) {
2557                        gdm_xdmcp_send_managed_forward (factory, fq->from_address, address);
2558                        forward_query_destroy (factory, fq);
2559                }
2560
2561                factory->priv->num_sessions++;
2562                factory->priv->num_pending_sessions--;
2563
2564                /* Start greeter/session */
2565                if (! gdm_display_manage (display)) {
2566                        gdm_xdmcp_send_failed (factory, address, clnt_sessid);
2567                        g_debug ("GdmXdmcpDisplayFactory: Failed to manage display");
2568                }
2569        } else if (display != NULL &&
2570                   gdm_display_get_status (display) == GDM_DISPLAY_MANAGED) {
2571                g_debug ("GdmXdmcpDisplayFactory: Session id %ld already managed",
2572                         (long)clnt_sessid);
2573        } else {
2574                g_warning ("GdmXdmcpDisplayFactory: Failed to look up session id %ld",
2575                           (long)clnt_sessid);
2576                gdm_xdmcp_send_refuse (factory, address, clnt_sessid);
2577        }
2578
2579 out:
2580        XdmcpDisposeARRAY8 (&clnt_dspclass);
2581        g_free (host);
2582}
2583
2584static void
2585gdm_xdmcp_handle_managed_forward (GdmXdmcpDisplayFactory *factory,
2586                                  GdmAddress             *address,
2587                                  int                     len)
2588{
2589        ARRAY8              clnt_address;
2590        char               *host;
2591        GdmAddress         *disp_address;
2592        IndirectClient     *ic;
2593
2594        host = NULL;
2595        gdm_address_get_numeric_info (address, &host, NULL);
2596        g_debug ("GdmXdmcpDisplayFactory: Got MANAGED_FORWARD from %s",
2597                   host);
2598
2599        /* Check with tcp_wrappers if client is allowed to access */
2600        if (! gdm_xdmcp_host_allow (address)) {
2601                g_warning ("GdmXdmcpDisplayFactory: Got MANAGED_FORWARD from banned host %s",
2602                           host);
2603                g_free (host);
2604                return;
2605        }
2606        g_free (host);
2607
2608        /* Hostname */
2609        if G_UNLIKELY ( ! XdmcpReadARRAY8 (&factory->priv->buf, &clnt_address)) {
2610                g_warning (_("%s: Could not read address"),
2611                           "gdm_xdmcp_handle_managed_forward");
2612                return;
2613        }
2614
2615        disp_address = NULL;
2616        if (! create_address_from_request (&clnt_address, NULL, gdm_address_get_family_type (address), &disp_address)) {
2617                g_warning ("Unable to parse address for request");
2618                XdmcpDisposeARRAY8 (&clnt_address);
2619                return;
2620        }
2621
2622        ic = indirect_client_lookup_by_chosen (factory, address, disp_address);
2623        if (ic != NULL) {
2624                indirect_client_destroy (factory, ic);
2625        }
2626
2627        /* Note: we send GOT even on not found, just in case our previous
2628         * didn't get through and this was a second managed forward */
2629        gdm_xdmcp_send_got_managed_forward (factory, address, disp_address);
2630
2631        gdm_address_free (disp_address);
2632
2633        XdmcpDisposeARRAY8 (&clnt_address);
2634}
2635
2636static void
2637gdm_xdmcp_handle_got_managed_forward (GdmXdmcpDisplayFactory *factory,
2638                                      GdmAddress             *address,
2639                                      int                     len)
2640{
2641        GdmAddress *disp_address;
2642        ARRAY8      clnt_address;
2643        char       *host;
2644
2645        host = NULL;
2646        gdm_address_get_numeric_info (address, &host, NULL);
2647        g_debug ("GdmXdmcpDisplayFactory: Got MANAGED_FORWARD from %s",
2648                   host);
2649
2650        if (! gdm_xdmcp_host_allow (address)) {
2651                g_warning ("%s: Got GOT_MANAGED_FORWARD from banned host %s",
2652                           "gdm_xdmcp_handle_request", host);
2653                g_free (host);
2654                return;
2655        }
2656        g_free (host);
2657
2658        /* Hostname */
2659        if G_UNLIKELY ( ! XdmcpReadARRAY8 (&factory->priv->buf, &clnt_address)) {
2660                g_warning (_("%s: Could not read address"),
2661                           "gdm_xdmcp_handle_got_managed_forward");
2662                return;
2663        }
2664
2665        if (! create_address_from_request (&clnt_address, NULL, gdm_address_get_family_type (address), &disp_address)) {
2666                g_warning (_("%s: Could not read address"),
2667                           "gdm_xdmcp_handle_got_managed_forward");
2668                XdmcpDisposeARRAY8 (&clnt_address);
2669                return;
2670        }
2671
2672        gdm_xdmcp_whack_queued_managed_forwards (factory, address, disp_address);
2673
2674        gdm_address_free (disp_address);
2675
2676        XdmcpDisposeARRAY8 (&clnt_address);
2677}
2678
2679static void
2680gdm_xdmcp_send_alive (GdmXdmcpDisplayFactory *factory,
2681                      GdmAddress             *address,
2682                      CARD16                  dspnum,
2683                      CARD32                  sessid)
2684{
2685        XdmcpHeader header;
2686        GdmDisplay *display;
2687        int         send_running = 0;
2688        CARD32      send_sessid = 0;
2689
2690        display = gdm_xdmcp_display_lookup (factory, sessid);
2691        if (display == NULL) {
2692                display = gdm_xdmcp_display_lookup_by_host (factory, address, dspnum);
2693        }
2694
2695        if (display != NULL) {
2696                int status;
2697
2698                send_sessid = gdm_xdmcp_display_get_session_number (GDM_XDMCP_DISPLAY (display));
2699                status = gdm_display_get_status (display);
2700
2701                if (status == GDM_DISPLAY_MANAGED) {
2702                        send_running = 1;
2703                }
2704        }
2705
2706        g_debug ("GdmXdmcpDisplayFactory: Sending ALIVE to %ld (running %d, sessid %ld)",
2707                 (long)sessid,
2708                 send_running,
2709                 (long)send_sessid);
2710
2711        header.version = XDM_PROTOCOL_VERSION;
2712        header.opcode = (CARD16) ALIVE;
2713        header.length = 5;
2714
2715        XdmcpWriteHeader (&factory->priv->buf, &header);
2716        XdmcpWriteCARD8 (&factory->priv->buf, send_running);
2717        XdmcpWriteCARD32 (&factory->priv->buf, send_sessid);
2718
2719        XdmcpFlush (factory->priv->socket_fd,
2720                    &factory->priv->buf,
2721                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (address),
2722                    (int)sizeof (struct sockaddr_storage));
2723}
2724
2725static void
2726gdm_xdmcp_handle_keepalive (GdmXdmcpDisplayFactory *factory,
2727                            GdmAddress             *address,
2728                            int                     len)
2729{
2730        CARD16 clnt_dspnum;
2731        CARD32 clnt_sessid;
2732        char *host;
2733
2734        host = NULL;
2735        gdm_address_get_numeric_info (address, &host, NULL);
2736        g_debug ("GdmXdmcpDisplayFactory: Got KEEPALIVE from %s", host);
2737
2738        /* Check with tcp_wrappers if client is allowed to access */
2739        if (! gdm_xdmcp_host_allow (address)) {
2740                g_warning (_("%s: Got KEEPALIVE from banned host %s"),
2741                           "gdm_xdmcp_handle_keepalive",
2742                           host);
2743                g_free (host);
2744                return;
2745        }
2746        g_free (host);
2747
2748        /* Remote display number */
2749        if G_UNLIKELY (! XdmcpReadCARD16 (&factory->priv->buf, &clnt_dspnum)) {
2750                g_warning (_("%s: Could not read Display Number"),
2751                           "gdm_xdmcp_handle_keepalive");
2752                return;
2753        }
2754
2755        /* SessionID */
2756        if G_UNLIKELY (! XdmcpReadCARD32 (&factory->priv->buf, &clnt_sessid)) {
2757                g_warning (_("%s: Could not read Session ID"),
2758                           "gdm_xdmcp_handle_keepalive");
2759                return;
2760        }
2761
2762        gdm_xdmcp_send_alive (factory, address, clnt_dspnum, clnt_sessid);
2763}
2764
2765static const char *
2766opcode_string (int opcode)
2767{
2768        static const char * const opcode_names[] = {
2769                NULL,
2770                "BROADCAST_QUERY",
2771                "QUERY",
2772                "INDIRECT_QUERY",
2773                "FORWARD_QUERY",
2774                "WILLING",
2775                "UNWILLING",
2776                "REQUEST",
2777                "ACCEPT",
2778                "DECLINE",
2779                "MANAGE",
2780                "REFUSE",
2781                "FAILED",
2782                "KEEPALIVE",
2783                "ALIVE"
2784        };
2785        static const char * const gdm_opcode_names[] = {
2786                "MANAGED_FORWARD",
2787                "GOT_MANAGED_FORWARD"
2788        };
2789
2790
2791        if (opcode < G_N_ELEMENTS (opcode_names)) {
2792                return opcode_names [opcode];
2793        } else if (opcode >= GDM_XDMCP_FIRST_OPCODE &&
2794                   opcode < GDM_XDMCP_LAST_OPCODE) {
2795                return gdm_opcode_names [opcode - GDM_XDMCP_FIRST_OPCODE];
2796        } else {
2797                return "UNKNOWN";
2798        }
2799}
2800
2801static gboolean
2802decode_packet (GIOChannel             *source,
2803               GIOCondition            cond,
2804               GdmXdmcpDisplayFactory *factory)
2805{
2806        struct sockaddr_storage clnt_ss;
2807        GdmAddress             *address;
2808        gint                    ss_len;
2809        XdmcpHeader             header;
2810        char                   *host;
2811        char                   *port;
2812        int                     res;
2813
2814        g_debug ("GdmXdmcpDisplayFactory: decode_packet: GIOCondition %d", (int)cond);
2815
2816        if ( ! (cond & G_IO_IN)) {
2817                return TRUE;
2818        }
2819
2820        ss_len = sizeof (clnt_ss);
2821        res = XdmcpFill (factory->priv->socket_fd, &factory->priv->buf, (XdmcpNetaddr)&clnt_ss, &ss_len);
2822        if G_UNLIKELY (! res) {
2823                g_debug ("GdmXdmcpDisplayFactory: Could not create XDMCP buffer!");
2824                return TRUE;
2825        }
2826
2827        res = XdmcpReadHeader (&factory->priv->buf, &header);
2828        if G_UNLIKELY (! res) {
2829                g_warning (_("GdmXdmcpDisplayFactory: Could not read XDMCP header!"));
2830                return TRUE;
2831        }
2832
2833        if G_UNLIKELY (header.version != XDM_PROTOCOL_VERSION &&
2834                       header.version != GDM_XDMCP_PROTOCOL_VERSION) {
2835                g_warning (_("XMDCP: Incorrect XDMCP version!"));
2836                return TRUE;
2837        }
2838
2839        address = gdm_address_new_from_sockaddr ((struct sockaddr *) &clnt_ss, ss_len);
2840        if (address == NULL) {
2841                g_warning (_("XMDCP: Unable to parse address"));
2842                return TRUE;
2843        }
2844
2845        gdm_address_debug (address);
2846
2847        host = NULL;
2848        port = NULL;
2849        gdm_address_get_numeric_info (address, &host, &port);
2850
2851        g_debug ("GdmXdmcpDisplayFactory: Received opcode %s from client %s : %s",
2852                 opcode_string (header.opcode),
2853                 host,
2854                 port);
2855
2856        switch (header.opcode) {
2857        case BROADCAST_QUERY:
2858                gdm_xdmcp_handle_broadcast_query (factory, address, header.length);
2859                break;
2860
2861        case QUERY:
2862                gdm_xdmcp_handle_query (factory, address, header.length);
2863                break;
2864
2865        case INDIRECT_QUERY:
2866                gdm_xdmcp_handle_indirect_query (factory, address, header.length);
2867                break;
2868
2869        case FORWARD_QUERY:
2870                gdm_xdmcp_handle_forward_query (factory, address, header.length);
2871                break;
2872
2873        case REQUEST:
2874                gdm_xdmcp_handle_request (factory, address, header.length);
2875                break;
2876
2877        case MANAGE:
2878                gdm_xdmcp_handle_manage (factory, address, header.length);
2879                break;
2880
2881        case KEEPALIVE:
2882                gdm_xdmcp_handle_keepalive (factory, address, header.length);
2883                break;
2884
2885        case GDM_XDMCP_MANAGED_FORWARD:
2886                gdm_xdmcp_handle_managed_forward (factory, address, header.length);
2887                break;
2888
2889        case GDM_XDMCP_GOT_MANAGED_FORWARD:
2890                gdm_xdmcp_handle_got_managed_forward (factory, address, header.length);
2891                break;
2892
2893        default:
2894                g_debug ("GdmXdmcpDisplayFactory: Unknown opcode from client %s : %s",
2895                         host,
2896                         port);
2897
2898                break;
2899        }
2900
2901        g_free (host);
2902        g_free (port);
2903
2904        gdm_address_free (address);
2905
2906        return TRUE;
2907}
2908
2909static gboolean
2910gdm_xdmcp_display_factory_start (GdmDisplayFactory *base_factory)
2911{
2912        gboolean                ret;
2913        GIOChannel             *ioc;
2914        GdmXdmcpDisplayFactory *factory = GDM_XDMCP_DISPLAY_FACTORY (base_factory);
2915        gboolean                res;
2916
2917        g_return_val_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory), FALSE);
2918        g_return_val_if_fail (factory->priv->socket_fd == -1, FALSE);
2919
2920        /* read configuration */
2921        res = gdm_settings_direct_get_uint    (GDM_KEY_UDP_PORT,
2922                                               &(factory->priv->port));
2923        res = gdm_settings_direct_get_boolean (GDM_KEY_MULTICAST,
2924                                               &(factory->priv->use_multicast));
2925        res = gdm_settings_direct_get_string  (GDM_KEY_MULTICAST_ADDR,
2926                                               &(factory->priv->multicast_address));
2927        res = gdm_settings_direct_get_boolean (GDM_KEY_INDIRECT,
2928                                               &(factory->priv->honor_indirect));
2929        res = gdm_settings_direct_get_uint    (GDM_KEY_DISPLAYS_PER_HOST,
2930                                               &(factory->priv->max_displays_per_host));
2931        res = gdm_settings_direct_get_uint    (GDM_KEY_MAX_SESSIONS,
2932                                               &(factory->priv->max_displays));
2933        res = gdm_settings_direct_get_uint    (GDM_KEY_MAX_PENDING,
2934                                               &(factory->priv->max_pending_displays));
2935        res = gdm_settings_direct_get_uint    (GDM_KEY_MAX_WAIT,
2936                                               &(factory->priv->max_wait));
2937        res = gdm_settings_direct_get_uint    (GDM_KEY_MAX_WAIT_INDIRECT,
2938                                               &(factory->priv->max_wait_indirect));
2939        res = gdm_settings_direct_get_string  (GDM_KEY_WILLING,
2940                                               &(factory->priv->willing_script));
2941
2942        ret = open_port (factory);
2943        if (! ret) {
2944                return ret;
2945        }
2946
2947        g_debug ("GdmXdmcpDisplayFactory: Starting to listen on XDMCP port");
2948
2949        ioc = g_io_channel_unix_new (factory->priv->socket_fd);
2950
2951        g_io_channel_set_encoding (ioc, NULL, NULL);
2952        g_io_channel_set_buffered (ioc, FALSE);
2953
2954        factory->priv->socket_watch_id = g_io_add_watch_full (ioc,
2955                                                              G_PRIORITY_DEFAULT,
2956                                                              G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
2957                                                              (GIOFunc)decode_packet,
2958                                                              factory,
2959                                                              NULL);
2960        g_io_channel_unref (ioc);
2961
2962        return ret;
2963}
2964
2965static gboolean
2966gdm_xdmcp_display_factory_stop (GdmDisplayFactory *base_factory)
2967{
2968        GdmXdmcpDisplayFactory *factory = GDM_XDMCP_DISPLAY_FACTORY (base_factory);
2969
2970        g_return_val_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory), FALSE);
2971        g_return_val_if_fail (factory->priv->socket_fd != -1, FALSE);
2972
2973        if (factory->priv->socket_watch_id > 0) {
2974                g_source_remove (factory->priv->socket_watch_id);
2975                factory->priv->socket_watch_id = 0;
2976        }
2977
2978        if (factory->priv->socket_fd > 0) {
2979                VE_IGNORE_EINTR (close (factory->priv->socket_fd));
2980                factory->priv->socket_fd = -1;
2981        }
2982
2983        return TRUE;
2984}
2985
2986void
2987gdm_xdmcp_display_factory_set_port (GdmXdmcpDisplayFactory *factory,
2988                                    guint                   port)
2989{
2990        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
2991
2992        factory->priv->port = port;
2993}
2994
2995static void
2996gdm_xdmcp_display_factory_set_use_multicast (GdmXdmcpDisplayFactory *factory,
2997                                             gboolean                use_multicast)
2998{
2999        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3000
3001        factory->priv->use_multicast = use_multicast;
3002}
3003
3004static void
3005gdm_xdmcp_display_factory_set_multicast_address (GdmXdmcpDisplayFactory *factory,
3006                                                 const char             *address)
3007{
3008        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3009
3010        g_free (factory->priv->multicast_address);
3011        factory->priv->multicast_address = g_strdup (address);
3012}
3013
3014static void
3015gdm_xdmcp_display_factory_set_honor_indirect (GdmXdmcpDisplayFactory *factory,
3016                                              gboolean                honor_indirect)
3017{
3018        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3019
3020        factory->priv->honor_indirect = honor_indirect;
3021}
3022
3023static void
3024gdm_xdmcp_display_factory_set_max_displays_per_host (GdmXdmcpDisplayFactory *factory,
3025                                                     guint                   num)
3026{
3027        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3028
3029        factory->priv->max_displays_per_host = num;
3030}
3031
3032static void
3033gdm_xdmcp_display_factory_set_max_displays (GdmXdmcpDisplayFactory *factory,
3034                                            guint                   num)
3035{
3036        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3037
3038        factory->priv->max_displays = num;
3039}
3040
3041static void
3042gdm_xdmcp_display_factory_set_max_pending_displays (GdmXdmcpDisplayFactory *factory,
3043                                                    guint                   num)
3044{
3045        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3046
3047        factory->priv->max_pending_displays = num;
3048}
3049
3050static void
3051gdm_xdmcp_display_factory_set_max_wait (GdmXdmcpDisplayFactory *factory,
3052                                        guint                   num)
3053{
3054        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3055
3056        factory->priv->max_wait = num;
3057}
3058
3059static void
3060gdm_xdmcp_display_factory_set_max_wait_indirect (GdmXdmcpDisplayFactory *factory,
3061                                                 guint                   num)
3062{
3063        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3064
3065        factory->priv->max_wait_indirect = num;
3066}
3067
3068static void
3069gdm_xdmcp_display_factory_set_willing_script (GdmXdmcpDisplayFactory *factory,
3070                                              const char             *script)
3071{
3072        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (factory));
3073
3074        g_free (factory->priv->willing_script);
3075        factory->priv->willing_script = g_strdup (script);
3076}
3077
3078static void
3079gdm_xdmcp_display_factory_set_property (GObject       *object,
3080                                        guint          prop_id,
3081                                        const GValue  *value,
3082                                        GParamSpec    *pspec)
3083{
3084        GdmXdmcpDisplayFactory *self;
3085
3086        self = GDM_XDMCP_DISPLAY_FACTORY (object);
3087
3088        switch (prop_id) {
3089        case PROP_PORT:
3090                gdm_xdmcp_display_factory_set_port (self, g_value_get_uint (value));
3091                break;
3092        case PROP_USE_MULTICAST:
3093                gdm_xdmcp_display_factory_set_use_multicast (self, g_value_get_boolean (value));
3094                break;
3095        case PROP_MULTICAST_ADDRESS:
3096                gdm_xdmcp_display_factory_set_multicast_address (self, g_value_get_string (value));
3097                break;
3098        case PROP_HONOR_INDIRECT:
3099                gdm_xdmcp_display_factory_set_honor_indirect (self, g_value_get_boolean (value));
3100                break;
3101        case PROP_MAX_DISPLAYS_PER_HOST:
3102                gdm_xdmcp_display_factory_set_max_displays_per_host (self, g_value_get_uint (value));
3103                break;
3104        case PROP_MAX_DISPLAYS:
3105                gdm_xdmcp_display_factory_set_max_displays (self, g_value_get_uint (value));
3106                break;
3107        case PROP_MAX_PENDING_DISPLAYS:
3108                gdm_xdmcp_display_factory_set_max_pending_displays (self, g_value_get_uint (value));
3109                break;
3110        case PROP_MAX_WAIT:
3111                gdm_xdmcp_display_factory_set_max_wait (self, g_value_get_uint (value));
3112                break;
3113        case PROP_MAX_WAIT_INDIRECT:
3114                gdm_xdmcp_display_factory_set_max_wait_indirect (self, g_value_get_uint (value));
3115                break;
3116        case PROP_WILLING_SCRIPT:
3117                gdm_xdmcp_display_factory_set_willing_script (self, g_value_get_string (value));
3118                break;
3119        default:
3120                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3121                break;
3122        }
3123}
3124
3125static void
3126gdm_xdmcp_display_factory_get_property (GObject    *object,
3127                                        guint       prop_id,
3128                                        GValue     *value,
3129                                        GParamSpec *pspec)
3130{
3131        GdmXdmcpDisplayFactory *self;
3132
3133        self = GDM_XDMCP_DISPLAY_FACTORY (object);
3134
3135        switch (prop_id) {
3136        case PROP_PORT:
3137                g_value_set_uint (value, self->priv->port);
3138                break;
3139        case PROP_USE_MULTICAST:
3140                g_value_set_boolean (value, self->priv->use_multicast);
3141                break;
3142        case PROP_MULTICAST_ADDRESS:
3143                g_value_set_string (value, self->priv->multicast_address);
3144                break;
3145        case PROP_HONOR_INDIRECT:
3146                g_value_set_boolean (value, self->priv->honor_indirect);
3147                break;
3148        case PROP_MAX_DISPLAYS_PER_HOST:
3149                g_value_set_uint (value, self->priv->max_displays_per_host);
3150                break;
3151        case PROP_MAX_DISPLAYS:
3152                g_value_set_uint (value, self->priv->max_displays);
3153                break;
3154        case PROP_MAX_PENDING_DISPLAYS:
3155                g_value_set_uint (value, self->priv->max_pending_displays);
3156                break;
3157        case PROP_MAX_WAIT:
3158                g_value_set_uint (value, self->priv->max_wait);
3159                break;
3160        case PROP_MAX_WAIT_INDIRECT:
3161                g_value_set_uint (value, self->priv->max_wait_indirect);
3162                break;
3163        case PROP_WILLING_SCRIPT:
3164                g_value_set_string (value, self->priv->willing_script);
3165                break;
3166        default:
3167                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3168                break;
3169        }
3170}
3171
3172static void
3173gdm_xdmcp_display_factory_class_init (GdmXdmcpDisplayFactoryClass *klass)
3174{
3175        GObjectClass           *object_class = G_OBJECT_CLASS (klass);
3176        GdmDisplayFactoryClass *factory_class = GDM_DISPLAY_FACTORY_CLASS (klass);
3177
3178        object_class->get_property = gdm_xdmcp_display_factory_get_property;
3179        object_class->set_property = gdm_xdmcp_display_factory_set_property;
3180        object_class->finalize = gdm_xdmcp_display_factory_finalize;
3181
3182        factory_class->start = gdm_xdmcp_display_factory_start;
3183        factory_class->stop = gdm_xdmcp_display_factory_stop;
3184
3185        g_object_class_install_property (object_class,
3186                                         PROP_PORT,
3187                                         g_param_spec_uint ("port",
3188                                                            "UDP port",
3189                                                            "UDP port",
3190                                                            0,
3191                                                            G_MAXINT,
3192                                                            DEFAULT_PORT,
3193                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3194        g_object_class_install_property (object_class,
3195                                         PROP_USE_MULTICAST,
3196                                         g_param_spec_boolean ("use-multicast",
3197                                                               NULL,
3198                                                               NULL,
3199                                                               DEFAULT_USE_MULTICAST,
3200                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3201        g_object_class_install_property (object_class,
3202                                         PROP_MULTICAST_ADDRESS,
3203                                         g_param_spec_string ("multicast-address",
3204                                                              "multicast-address",
3205                                                              "multicast-address",
3206                                                              DEFAULT_MULTICAST_ADDRESS,
3207                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3208        g_object_class_install_property (object_class,
3209                                         PROP_HONOR_INDIRECT,
3210                                         g_param_spec_boolean ("honor-indirect",
3211                                                               NULL,
3212                                                               NULL,
3213                                                               DEFAULT_HONOR_INDIRECT,
3214                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3215        g_object_class_install_property (object_class,
3216                                         PROP_WILLING_SCRIPT,
3217                                         g_param_spec_string ("willing-script",
3218                                                              "willing-script",
3219                                                              "willing-script",
3220                                                              DEFAULT_WILLING_SCRIPT,
3221                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3222        g_object_class_install_property (object_class,
3223                                         PROP_MAX_DISPLAYS_PER_HOST,
3224                                         g_param_spec_uint ("max-displays-per-host",
3225                                                            "max-displays-per-host",
3226                                                            "max-displays-per-host",
3227                                                            0,
3228                                                            G_MAXINT,
3229                                                            DEFAULT_MAX_DISPLAYS_PER_HOST,
3230                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3231        g_object_class_install_property (object_class,
3232                                         PROP_MAX_DISPLAYS,
3233                                         g_param_spec_uint ("max-displays",
3234                                                            "max-displays",
3235                                                            "max-displays",
3236                                                            0,
3237                                                            G_MAXINT,
3238                                                            DEFAULT_MAX_DISPLAYS,
3239                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3240        g_object_class_install_property (object_class,
3241                                         PROP_MAX_PENDING_DISPLAYS,
3242                                         g_param_spec_uint ("max-pending-displays",
3243                                                            "max-pending-displays",
3244                                                            "max-pending-displays",
3245                                                            0,
3246                                                            G_MAXINT,
3247                                                            DEFAULT_MAX_PENDING_DISPLAYS,
3248                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3249        g_object_class_install_property (object_class,
3250                                         PROP_MAX_WAIT,
3251                                         g_param_spec_uint ("max-wait",
3252                                                            "max-wait",
3253                                                            "max-wait",
3254                                                            0,
3255                                                            G_MAXINT,
3256                                                            DEFAULT_MAX_WAIT,
3257                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3258        g_object_class_install_property (object_class,
3259                                         PROP_MAX_WAIT_INDIRECT,
3260                                         g_param_spec_uint ("max-wait-indirect",
3261                                                            "max-wait-indirect",
3262                                                            "max-wait-indirect",
3263                                                            0,
3264                                                            G_MAXINT,
3265                                                            DEFAULT_MAX_WAIT_INDIRECT,
3266                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
3267
3268        g_type_class_add_private (klass, sizeof (GdmXdmcpDisplayFactoryPrivate));
3269}
3270
3271static void
3272gdm_xdmcp_display_factory_init (GdmXdmcpDisplayFactory *factory)
3273{
3274        char           hostbuf[1024];
3275        struct utsname name;
3276
3277        factory->priv = GDM_XDMCP_DISPLAY_FACTORY_GET_PRIVATE (factory);
3278
3279        factory->priv->socket_fd = -1;
3280
3281        factory->priv->session_serial = g_random_int ();
3282
3283        /* Fetch and store local hostname in XDMCP friendly format */
3284        hostbuf[1023] = '\0';
3285        if G_UNLIKELY (gethostname (hostbuf, 1023) != 0) {
3286                g_warning (_("Could not get server hostname: %s!"), g_strerror (errno));
3287                strcpy (hostbuf, "localhost.localdomain");
3288        }
3289
3290        uname (&name);
3291        factory->priv->sysid = g_strconcat (name.sysname,
3292                                            " ",
3293                                            name.release,
3294                                            NULL);
3295
3296        factory->priv->hostname = g_strdup (hostbuf);
3297
3298        factory->priv->servhost.data   = (CARD8 *) g_strdup (hostbuf);
3299        factory->priv->servhost.length = strlen ((char *) factory->priv->servhost.data);
3300}
3301
3302static void
3303gdm_xdmcp_display_factory_finalize (GObject *object)
3304{
3305        GdmXdmcpDisplayFactory *factory;
3306
3307        g_return_if_fail (object != NULL);
3308        g_return_if_fail (GDM_IS_XDMCP_DISPLAY_FACTORY (object));
3309
3310        factory = GDM_XDMCP_DISPLAY_FACTORY (object);
3311
3312        g_return_if_fail (factory->priv != NULL);
3313
3314        if (factory->priv->socket_watch_id > 0) {
3315                g_source_remove (factory->priv->socket_watch_id);
3316        }
3317
3318        if (factory->priv->socket_fd > 0) {
3319                close (factory->priv->socket_fd);
3320                factory->priv->socket_fd = -1;
3321        }
3322
3323        g_slist_free (factory->priv->forward_queries);
3324        g_slist_free (factory->priv->managed_forwards);
3325
3326        g_free (factory->priv->sysid);
3327        g_free (factory->priv->hostname);
3328        g_free (factory->priv->multicast_address);
3329        g_free (factory->priv->willing_script);
3330
3331        /* FIXME: Free servhost */
3332
3333        G_OBJECT_CLASS (gdm_xdmcp_display_factory_parent_class)->finalize (object);
3334}
3335
3336GdmXdmcpDisplayFactory *
3337gdm_xdmcp_display_factory_new (GdmDisplayStore *store)
3338{
3339        if (xdmcp_display_factory_object != NULL) {
3340                g_object_ref (xdmcp_display_factory_object);
3341        } else {
3342                xdmcp_display_factory_object = g_object_new (GDM_TYPE_XDMCP_DISPLAY_FACTORY,
3343                                                             "display-store", store,
3344                                                             NULL);
3345                g_object_add_weak_pointer (xdmcp_display_factory_object,
3346                                           (gpointer *) &xdmcp_display_factory_object);
3347        }
3348
3349        return GDM_XDMCP_DISPLAY_FACTORY (xdmcp_display_factory_object);
3350}
Note: See TracBrowser for help on using the repository browser.