~brian-murray/lightdm/bug-967229

« back to all changes in this revision

Viewing changes to src/xdmcp-server.c

  • Committer: robert.ancell at canonical
  • Date: 2011-02-12 00:48:57 UTC
  • Revision ID: robert.ancell@canonical.com-20110212004857-45gpv6k0m0uf0liv
Update changelog link

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2010-2011 Robert Ancell.
 
2
 * Copyright (C) 2010 Robert Ancell.
3
3
 * Author: Robert Ancell <robert.ancell@canonical.com>
4
4
 * 
5
5
 * This program is free software: you can redistribute it and/or modify it under
20
20
#include "xdmcp-server.h"
21
21
#include "xdmcp-protocol.h"
22
22
#include "xdmcp-session-private.h"
23
 
#include "xauthority.h"
 
23
#include "xauth.h"
24
24
 
25
25
enum {
26
26
    NEW_SESSION,
42
42
    /* Status to report to clients */
43
43
    gchar *status;
44
44
 
45
 
    /* XDM-AUTHENTICATION-1 key */
46
 
    gchar *key;
 
45
    /* Auhentication scheme to use */
 
46
    gchar *authentication_name;
 
47
 
 
48
    /* Auhentication data */  
 
49
    guchar *authentication_data;
 
50
    gsize authentication_data_length;
 
51
 
 
52
    /* Authorization scheme to use */
 
53
    gchar *authorization_name;
 
54
 
 
55
    /* Authorization data */
 
56
    guchar *authorization_data;
 
57
    gsize authorization_data_length;
47
58
 
48
59
    /* Active XDMCP sessions */
49
60
    GHashTable *sessions;
51
62
 
52
63
G_DEFINE_TYPE (XDMCPServer, xdmcp_server, G_TYPE_OBJECT);
53
64
 
54
 
/* Maximum number of milliseconds client will resend manage requests before giving up */
55
 
#define MANAGE_TIMEOUT 126000
56
 
 
57
65
XDMCPServer *
58
66
xdmcp_server_new (void)
59
67
{
63
71
void
64
72
xdmcp_server_set_port (XDMCPServer *server, guint port)
65
73
{
66
 
    g_return_if_fail (server != NULL);
67
74
    server->priv->port = port;
68
75
}
69
76
 
70
77
guint
71
78
xdmcp_server_get_port (XDMCPServer *server)
72
79
{
73
 
    g_return_val_if_fail (server != NULL, 0);
74
80
    return server->priv->port;
75
81
}
76
82
 
77
83
void
78
84
xdmcp_server_set_hostname (XDMCPServer *server, const gchar *hostname)
79
85
{
80
 
    g_return_if_fail (server != NULL);
81
 
 
82
86
    g_free (server->priv->hostname);
83
87
    server->priv->hostname = g_strdup (hostname);
84
88
}
86
90
const gchar *
87
91
xdmcp_server_get_hostname (XDMCPServer *server)
88
92
{
89
 
    g_return_val_if_fail (server != NULL, NULL);
90
93
    return server->priv->hostname;
91
94
}
92
95
 
93
96
void
94
97
xdmcp_server_set_status (XDMCPServer *server, const gchar *status)
95
98
{
96
 
    g_return_if_fail (server != NULL);
97
 
 
98
99
    g_free (server->priv->status);
99
100
    server->priv->status = g_strdup (status);
100
101
}
102
103
const gchar *
103
104
xdmcp_server_get_status (XDMCPServer *server)
104
105
{
105
 
    g_return_val_if_fail (server != NULL, NULL);
106
106
    return server->priv->status;
107
107
}
108
108
 
109
109
void
110
 
xdmcp_server_set_key (XDMCPServer *server, const gchar *key)
111
 
{
112
 
    g_return_if_fail (server != NULL);
113
 
    g_free (server->priv->key);
114
 
    server->priv->key = g_strdup (key);
 
110
xdmcp_server_set_authentication (XDMCPServer *server, const gchar *name, const guchar *data, gsize data_length)
 
111
{
 
112
    g_free (server->priv->authentication_name);
 
113
    server->priv->authentication_name = g_strdup (name);
 
114
    g_free (server->priv->authentication_data);
 
115
    server->priv->authentication_data = g_malloc (data_length);
 
116
    server->priv->authentication_data_length = data_length;
 
117
    memcpy (server->priv->authentication_data, data, data_length);
 
118
}
 
119
 
 
120
const gchar *
 
121
xdmcp_server_get_authentication_name (XDMCPServer *server)
 
122
{
 
123
    return server->priv->authentication_name;
 
124
}
 
125
 
 
126
const guchar *
 
127
xdmcp_server_get_authentication_data (XDMCPServer *server)
 
128
{
 
129
    return server->priv->authentication_data;
 
130
}
 
131
 
 
132
gsize
 
133
xdmcp_server_get_authentication_data_length (XDMCPServer *server)
 
134
{
 
135
    return server->priv->authentication_data_length;
 
136
}
 
137
 
 
138
void
 
139
xdmcp_server_set_authorization (XDMCPServer *server, const gchar *name, const guchar *data, gsize data_length)
 
140
{
 
141
    g_free (server->priv->authorization_name);
 
142
    server->priv->authorization_name = g_strdup (name);
 
143
    g_free (server->priv->authorization_data);
 
144
    server->priv->authorization_data = g_malloc (data_length);
 
145
    server->priv->authorization_data_length = data_length;
 
146
    memcpy (server->priv->authorization_data, data, data_length);
 
147
}
 
148
 
 
149
const gchar *
 
150
xdmcp_server_get_authorization_name (XDMCPServer *server)
 
151
{
 
152
    return server->priv->authorization_name;
 
153
}
 
154
 
 
155
const guchar *
 
156
xdmcp_server_get_authorization_data (XDMCPServer *server)
 
157
{
 
158
    return server->priv->authorization_data;
 
159
}
 
160
 
 
161
gsize
 
162
xdmcp_server_get_authorization_data_length (XDMCPServer *server)
 
163
{
 
164
    return server->priv->authorization_data_length;
115
165
}
116
166
 
117
167
static gboolean
136
186
    session = xdmcp_session_new (id);
137
187
    session->priv->server = server;
138
188
    g_hash_table_insert (server->priv->sessions, GINT_TO_POINTER ((gint) id), g_object_ref (session));
139
 
    session->priv->inactive_timeout = g_timeout_add (MANAGE_TIMEOUT, (GSourceFunc) session_timeout_cb, session);
 
189
    session->priv->inactive_timeout = g_timeout_add (10, (GSourceFunc) session_timeout_cb, session);
140
190
 
141
191
    return session;
142
192
}
150
200
static void
151
201
send_packet (GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
152
202
{
153
 
    guint8 data[1024];
 
203
    guchar data[1024];
154
204
    gssize n_written;
155
205
 
156
206
    g_debug ("Send %s", xdmcp_packet_tostring (packet));
162
212
    {
163
213
        GError *error = NULL;
164
214
 
165
 
        g_socket_send_to (socket, address, (gchar *) data, n_written, NULL, &error);
166
 
        if (error)
 
215
        if (g_socket_send_to (socket, address, (gchar *) data, n_written, NULL, &error) < 0)
167
216
            g_warning ("Error sending packet: %s", error->message);
 
217
 
168
218
        g_clear_error (&error);
169
219
    }
170
220
}
171
221
 
172
 
static const gchar *
173
 
get_authentication_name (XDMCPServer *server)
174
 
{
175
 
    if (server->priv->key)
176
 
        return "XDM-AUTHENTICATION-1";
177
 
    else
178
 
        return "";
179
 
}
180
 
 
181
222
static void
182
223
handle_query (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
183
224
{
184
225
    XDMCPPacket *response;
185
226
    gchar **i;
186
 
    gchar *authentication_name = NULL;
 
227
    gboolean match_authentication = FALSE;
187
228
 
188
229
    /* If no authentication requested and we are configured for none then allow */
189
 
    if (packet->Query.authentication_names[0] == NULL && server->priv->key == NULL)
190
 
        authentication_name = "";
 
230
    if (packet->Query.authentication_names[0] == NULL && strcmp (server->priv->authentication_name, "") == 0)
 
231
        match_authentication = TRUE;
191
232
 
192
233
    for (i = packet->Query.authentication_names; *i; i++)
193
234
    {
194
 
        if (strcmp (*i, get_authentication_name (server)) == 0 && server->priv->key != NULL)
 
235
        if (strcmp (*i, server->priv->authentication_name) == 0)
195
236
        {
196
 
            authentication_name = *i;
 
237
            match_authentication = TRUE;
197
238
            break;
198
239
        }
199
240
    }
200
241
 
201
 
    if (authentication_name)
 
242
    if (match_authentication)
202
243
    {
203
244
        response = xdmcp_packet_alloc (XDMCP_Willing);
204
 
        response->Willing.authentication_name = g_strdup (authentication_name);
 
245
        response->Willing.authentication_name = g_strdup (server->priv->authentication_name);
205
246
        response->Willing.hostname = g_strdup (server->priv->hostname);
206
247
        response->Willing.status = g_strdup (server->priv->status);
207
248
    }
208
249
    else
209
250
    {
210
251
        response = xdmcp_packet_alloc (XDMCP_Unwilling);
211
 
        response->Unwilling.hostname = g_strdup (server->priv->hostname);
212
 
        if (server->priv->key)
213
 
            response->Unwilling.status = g_strdup_printf ("No matching authentication, server requires %s", get_authentication_name (server));
214
 
        else
215
 
            response->Unwilling.status = g_strdup ("Server does not support authentication");
 
252
        response->Willing.hostname = g_strdup (server->priv->hostname);
 
253
        response->Willing.status = g_strdup (server->priv->status);
216
254
    }
217
255
  
218
256
    send_packet (socket, address, response);
220
258
    xdmcp_packet_free (response);
221
259
}
222
260
 
223
 
static guint8
224
 
atox (char c)
225
 
{
226
 
    if (c >= '0' && c <= '9')
227
 
        return c - '0';
228
 
    if (c >= 'a' && c <= 'f')
229
 
        return c - 'a' + 10;
230
 
    if (c >= 'A' && c <= 'F')
231
 
        return c - 'A' + 10;
232
 
    return 0;
233
 
}
234
 
 
235
 
static void
236
 
decode_key (const gchar *key, guint8 *data)
237
 
{
238
 
    gint i;
239
 
 
240
 
    memset (data, 0, sizeof (data));
241
 
    if (strncmp (key, "0x", 2) == 0 || strncmp (key, "0X", 2) == 0)
242
 
    {
243
 
        for (i = 0; i < 8; i++)
244
 
        {
245
 
            if (key[i*2] == '\0')
246
 
                break;
247
 
            data[i] |= atox (key[i*2]) << 8;
248
 
            if (key[i*2+1] == '\0')
249
 
                break;
250
 
            data[i] |= atox (key[i*2+1]);
251
 
        }
252
 
    }
253
 
    else
254
 
    {
255
 
        for (i = 1; i < 8 && key[i-1]; i++)
256
 
           data[i] = key[i-1];
257
 
    }
258
 
}
259
 
 
260
261
static void
261
262
handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
262
263
{
263
264
    int i;
264
265
    XDMCPPacket *response;
265
266
    XDMCPSession *session;
266
 
    guint8 *authentication_data = NULL;
 
267
    guchar *authentication_data = NULL;
267
268
    gsize authentication_data_length = 0;
268
269
    gboolean match_authorization = FALSE;
269
 
    gchar *authorization_name;
270
 
    guint8 *authorization_data = NULL;
 
270
    guchar *authorization_data = NULL;
271
271
    gsize authorization_data_length = 0;
272
 
    guint8 *session_authorization_data = NULL;
 
272
    guchar *session_authorization_data = NULL;
273
273
    gsize session_authorization_data_length = 0;
274
274
    gchar **j;
275
 
    guint16 family;
276
 
    GInetAddress *xserver_address = NULL;
277
 
    gchar *display_number;
 
275
    GInetAddress *address4 = NULL, *address6 = NULL;
278
276
    XdmAuthKeyRec rho;
279
 
 
280
 
    /* Try and find an IPv6 address */
281
 
    for (i = 0; i < packet->Request.n_connections; i++)
282
 
    {
283
 
        XDMCPConnection *connection = &packet->Request.connections[i];
284
 
        if (connection->type == XAUTH_FAMILY_INTERNET6 && connection->address.length == 16)
285
 
        {
286
 
            family = connection->type;
287
 
            xserver_address = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);
288
 
 
289
 
            /* We can't use link-local addresses, as we need to know what interface it is on */
290
 
            if (g_inet_address_get_is_link_local (xserver_address))
291
 
            {
292
 
                g_object_unref (xserver_address);
293
 
                xserver_address = NULL;
294
 
            }
295
 
            else
296
 
                break;
297
 
        }
298
 
    }
299
 
 
300
 
    /* If no IPv6 address, then try and find an IPv4 one */
301
 
    if (!xserver_address)
302
 
    {
303
 
        for (i = 0; i < packet->Request.n_connections; i++)
304
 
        {
305
 
            XDMCPConnection *connection = &packet->Request.connections[i];
306
 
            if (connection->type == XAUTH_FAMILY_INTERNET && connection->address.length == 4)
307
 
            {
308
 
                family = connection->type;
309
 
                xserver_address = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV4);
310
 
                break;
311
 
            }
312
 
        }
313
 
    }
314
 
 
315
 
    /* Decline if haven't got an address we can connect on */
316
 
    if (!xserver_address)
317
 
    {
318
 
        response = xdmcp_packet_alloc (XDMCP_Decline);
319
 
        response->Decline.status = g_strdup ("No valid address found");
320
 
        response->Decline.authentication_name = g_strdup (packet->Request.authentication_name);
321
 
        response->Decline.authentication_data.data = authentication_data;
322
 
        response->Decline.authentication_data.length = authentication_data_length;
323
 
        send_packet (socket, address, response);
324
 
        xdmcp_packet_free (response);
325
 
        return;
326
 
    }
327
277
  
328
278
    /* Must be using our authentication scheme */
329
 
    if (strcmp (packet->Request.authentication_name, get_authentication_name (server)) != 0)
 
279
    if (strcmp (packet->Request.authentication_name, server->priv->authentication_name) != 0)
330
280
    {
331
281
        response = xdmcp_packet_alloc (XDMCP_Decline);
332
 
        if (server->priv->key)
333
 
            response->Decline.status = g_strdup_printf ("Server only supports %s authentication", get_authentication_name (server));
334
 
        else
 
282
        if (strcmp (server->priv->authentication_name, "") == 0)
335
283
            response->Decline.status = g_strdup ("Server does not support authentication");
 
284
        else
 
285
            response->Decline.status = g_strdup_printf ("Server only supports %s authentication", server->priv->authentication_name);
336
286
        response->Decline.authentication_name = g_strdup ("");
337
287
        send_packet (socket, address, response);
338
288
        xdmcp_packet_free (response);
340
290
    }
341
291
 
342
292
    /* Perform requested authentication */
343
 
    if (server->priv->key)
 
293
    if (strcmp (server->priv->authentication_name, "XDM-AUTHENTICATION-1") == 0)
344
294
    {
345
 
        guint8 input[8], key[8];
 
295
        guchar input[8], key[8];
346
296
 
347
297
        memset (input, 0, 8);
348
298
        memcpy (input, packet->Request.authentication_data.data, packet->Request.authentication_data.length > 8 ? 8 : packet->Request.authentication_data.length);
349
299
 
350
300
        /* Setup key */
351
 
        decode_key (server->priv->key, key);
 
301
        memset (key, 0, 8);
 
302
        memcpy (key, server->priv->authentication_data, server->priv->authentication_data_length > 8 ? 8 : server->priv->authentication_data_length);
352
303
 
353
304
        /* Decode message from server */
354
 
        authentication_data = g_malloc (sizeof (guint8) * 8);
 
305
        authentication_data = g_malloc (sizeof (guchar) * 8);
355
306
        authentication_data_length = 8;
356
307
 
357
308
        XdmcpUnwrap (input, key, rho.data, authentication_data_length);
358
309
        XdmcpIncrementKey (&rho);
359
310
        XdmcpWrap (rho.data, key, authentication_data, authentication_data_length);
360
 
 
361
 
        authorization_name = g_strdup ("XDM-AUTHORIZATION-1");
362
311
    }
363
 
    else
364
 
        authorization_name = g_strdup ("MIT-MAGIC-COOKIE-1");
365
312
 
366
313
    /* Check if they support our authorization */
367
314
    for (j = packet->Request.authorization_names; *j; j++)
368
315
    {
369
 
        if (strcmp (*j, authorization_name) == 0)
 
316
        if (strcmp (*j, server->priv->authorization_name) == 0)
370
317
        {
371
318
             match_authorization = TRUE;
372
319
             break;
373
320
        }
374
321
    }
375
 
 
376
 
    /* Decline if don't support out authorization */
 
322
  
377
323
    if (!match_authorization)
378
324
    {
379
325
        response = xdmcp_packet_alloc (XDMCP_Decline);
380
 
        response->Decline.status = g_strdup_printf ("Server requires %s authorization", authorization_name);
381
 
        g_free (authorization_name);
 
326
        if (strcmp (server->priv->authorization_name, "") == 0)
 
327
            response->Decline.status = g_strdup ("Server does not support authorization");
 
328
        else
 
329
            response->Decline.status = g_strdup_printf ("Server only supports %s authorization", server->priv->authorization_name);
382
330
        response->Decline.authentication_name = g_strdup (packet->Request.authentication_name);
383
331
        response->Decline.authentication_data.data = authentication_data;
384
332
        response->Decline.authentication_data.length = authentication_data_length;
388
336
    }
389
337
 
390
338
    /* Perform requested authorization */
391
 
    if (server->priv->key)
 
339
    if (strcmp (server->priv->authorization_name, "MIT-MAGIC-COOKIE-1") == 0)
 
340
    {
 
341
        /* Data is the cookie */
 
342
        authorization_data = g_malloc (sizeof (guchar) * server->priv->authorization_data_length);
 
343
        memcpy (authorization_data, server->priv->authorization_data, server->priv->authorization_data_length);
 
344
        authorization_data_length = server->priv->authorization_data_length;
 
345
    }
 
346
    else if (strcmp (server->priv->authorization_name, "XDM-AUTHORIZATION-1") == 0)
392
347
    {
393
348
        gint i;
394
 
        guint8 key[8], session_key[8];
 
349
        guchar key[8], session_key[8];
395
350
 
396
351
        /* Setup key */
397
 
        decode_key (server->priv->key, key);
 
352
        memset (key, 0, 8);
 
353
        memcpy (key, server->priv->authentication_data, server->priv->authentication_data_length > 8 ? 8 : server->priv->authentication_data_length);
398
354
 
399
355
        /* Generate a private session key */
400
356
        // FIXME: Pick a good DES key?
414
370
        memcpy (session_authorization_data, rho.data, 8);
415
371
        memcpy (session_authorization_data + 8, session_key, 8);
416
372
    }
417
 
    else
418
 
    {
419
 
        XAuthority *auth;
420
 
 
421
 
        /* Data is the cookie */
422
 
        auth = xauth_new_cookie (XAUTH_FAMILY_WILD, NULL, 0, "");
423
 
        authorization_data = xauth_copy_authorization_data (auth);
424
 
        authorization_data_length = xauth_get_authorization_data_length (auth);
425
 
        session_authorization_data = xauth_copy_authorization_data (auth);
426
 
        session_authorization_data_length = xauth_get_authorization_data_length (auth);
427
 
 
428
 
        g_object_unref (auth);
 
373
 
 
374
    for (i = 0; i < packet->Request.n_connections; i++)
 
375
    {
 
376
        XDMCPConnection *connection;
 
377
 
 
378
        connection = &packet->Request.connections[i];
 
379
        switch (connection->type)
 
380
        {
 
381
        case FamilyInternet:
 
382
            if (connection->address.length == 4)
 
383
                address4 = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV4);
 
384
            break;
 
385
        case FamilyInternet6:
 
386
            if (connection->address.length == 16)
 
387
                address6 = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);          
 
388
            break;
 
389
        }
 
390
    }
 
391
 
 
392
    if (!address4) // FIXME: && !address6)
 
393
    {
 
394
        response = xdmcp_packet_alloc (XDMCP_Decline);
 
395
        response->Decline.status = g_strdup ("No valid address found");
 
396
        response->Decline.authentication_name = g_strdup (packet->Request.authentication_name);
 
397
        response->Decline.authentication_data.data = authentication_data;
 
398
        response->Decline.authentication_data.length = authentication_data_length;
 
399
        send_packet (socket, address, response);
 
400
        xdmcp_packet_free (response);
 
401
        return;
429
402
    }
430
403
 
431
404
    session = add_session (server);
432
 
    session->priv->address = xserver_address;
433
 
    session->priv->display_number = packet->Request.display_number;
434
 
    display_number = g_strdup_printf ("%d", packet->Request.display_number);
435
 
 
436
 
    /* We need to check if this is the loopback address and set the authority
437
 
     * for a local connection if this is so as XCB treats "127.0.0.1" as local
438
 
     * always */
439
 
    if (g_inet_address_get_is_loopback (xserver_address))
440
 
    {
441
 
        gchar hostname[1024];
442
 
        gethostname (hostname, 1024);
443
 
 
444
 
        session->priv->authority = xauth_new (XAUTH_FAMILY_LOCAL,
445
 
                                              (guint8 *) hostname,
446
 
                                              strlen (hostname),
447
 
                                              display_number,
448
 
                                              authorization_name,
449
 
                                              session_authorization_data,
450
 
                                              session_authorization_data_length);
451
 
    }
452
 
    else
453
 
        session->priv->authority = xauth_new (family,
454
 
                                              g_inet_address_to_bytes (G_INET_ADDRESS (xserver_address)),
455
 
                                              g_inet_address_get_native_size (G_INET_ADDRESS (xserver_address)),
456
 
                                              display_number,
457
 
                                              authorization_name,
458
 
                                              session_authorization_data,
459
 
                                              session_authorization_data_length);
460
 
    g_free (display_number);
 
405
    session->priv->address = address4;
 
406
    session->priv->address6 = address6;
 
407
    session->priv->authorization_name = g_strdup (server->priv->authorization_name);
 
408
    session->priv->authorization_data = session_authorization_data;
 
409
    session->priv->authorization_data_length = session_authorization_data_length;
461
410
 
462
411
    response = xdmcp_packet_alloc (XDMCP_Accept);
463
412
    response->Accept.session_id = xdmcp_session_get_id (session);
464
413
    response->Accept.authentication_name = g_strdup (packet->Request.authentication_name);
465
414
    response->Accept.authentication_data.data = authentication_data;
466
415
    response->Accept.authentication_data.length = authentication_data_length;
467
 
    response->Accept.authorization_name = authorization_name;
 
416
    response->Accept.authorization_name = g_strdup (server->priv->authorization_name);
468
417
    response->Accept.authorization_data.data = authorization_data;
469
418
    response->Accept.authorization_data.length = authorization_data_length;
470
419
    send_packet (socket, address, response);
475
424
handle_manage (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
476
425
{
477
426
    XDMCPSession *session;
478
 
    gboolean result;
479
427
 
480
428
    session = get_session (server, packet->Manage.session_id);
481
 
    if (!session)
482
 
    {
483
 
        XDMCPPacket *response;
484
 
 
485
 
        response = xdmcp_packet_alloc (XDMCP_Refuse);
486
 
        response->Refuse.session_id = packet->Manage.session_id;
487
 
        send_packet (socket, address, response);
488
 
        xdmcp_packet_free (response);
489
 
 
490
 
        return;
491
 
    }
492
 
 
493
 
    /* Ignore duplicate requests */
494
 
    if (session->priv->started)
495
 
    {
496
 
        if (session->priv->display_number != packet->Manage.display_number ||
497
 
            strcmp (session->priv->display_class, packet->Manage.display_class) != 0)
498
 
            g_debug ("Ignoring duplicate Manage with different data");
499
 
        return;
500
 
    }
501
 
 
502
 
    /* Reject if has changed display number */
503
 
    if (packet->Manage.display_number != session->priv->display_number)
504
 
    {
505
 
        XDMCPPacket *response;
506
 
 
507
 
        g_debug ("Received Manage for display number %d, but Request was %d", packet->Manage.display_number, session->priv->display_number);
508
 
        response = xdmcp_packet_alloc (XDMCP_Refuse);
509
 
        response->Refuse.session_id = packet->Manage.session_id;
510
 
        send_packet (socket, address, response);
511
 
        xdmcp_packet_free (response);
512
 
    }
513
 
 
514
 
    session->priv->display_class = g_strdup (packet->Manage.display_class);
515
 
 
516
 
    g_signal_emit (server, signals[NEW_SESSION], 0, session, &result);
517
 
    if (result)
518
 
    {
519
 
        /* Cancel the inactive timer */
520
 
        g_source_remove (session->priv->inactive_timeout);
521
 
 
522
 
        session->priv->started = TRUE;
 
429
    if (session)
 
430
    {
 
431
        gchar *display_address;
 
432
        gboolean result;
 
433
 
 
434
        /* Ignore duplicate requests */
 
435
        if (session->priv->started)
 
436
        {
 
437
            if (session->priv->display_number != packet->Manage.display_number ||
 
438
                strcmp (session->priv->display_class, packet->Manage.display_class) != 0)
 
439
                g_warning ("Duplicate Manage received with different data");
 
440
            return;
 
441
        }
 
442
 
 
443
        session->priv->display_number = packet->Manage.display_number;  
 
444
        session->priv->display_class = g_strdup (packet->Manage.display_class);
 
445
 
 
446
        g_signal_emit (server, signals[NEW_SESSION], 0, session, &result);
 
447
        if (result)
 
448
        {
 
449
            /* Cancel the inactive timer */
 
450
            g_source_remove (session->priv->inactive_timeout);
 
451
 
 
452
            session->priv->started = TRUE;
 
453
        }
 
454
        else
 
455
        {
 
456
            XDMCPPacket *response;
 
457
 
 
458
            response = xdmcp_packet_alloc (XDMCP_Failed);
 
459
            response->Failed.session_id = packet->Manage.session_id;
 
460
            response->Failed.status = g_strdup_printf ("Failed to connect to display %s", display_address);
 
461
            send_packet (socket, address, response);
 
462
            xdmcp_packet_free (response);
 
463
        }
 
464
 
 
465
        g_free (display_address);
523
466
    }
524
467
    else
525
468
    {
526
469
        XDMCPPacket *response;
527
470
 
528
 
        response = xdmcp_packet_alloc (XDMCP_Failed);
529
 
        response->Failed.session_id = packet->Manage.session_id;
530
 
        response->Failed.status = g_strdup_printf ("Failed to connect to display :%d", packet->Manage.display_number);
 
471
        response = xdmcp_packet_alloc (XDMCP_Refuse);
 
472
        response->Refuse.session_id = packet->Manage.session_id;
531
473
        send_packet (socket, address, response);
532
474
        xdmcp_packet_free (response);
533
475
    }
542
484
 
543
485
    session = get_session (server, packet->KeepAlive.session_id);
544
486
    if (session)
545
 
        alive = TRUE; // FIXME: xdmcp_session_get_alive (session);
 
487
        alive = TRUE; //xdmcp_session_get_alive (session);
546
488
 
547
489
    response = xdmcp_packet_alloc (XDMCP_Alive);
548
490
    response->Alive.session_running = alive;
560
502
    gssize n_read;
561
503
 
562
504
    n_read = g_socket_receive_from (socket, &address, data, 1024, NULL, &error);
563
 
    if (error)
564
 
        g_warning ("Failed to read from XDMCP socket: %s", error->message);
565
 
    g_clear_error (&error);
566
 
 
567
505
    if (n_read > 0)
568
506
    {
569
507
        XDMCPPacket *packet;
570
508
 
571
 
        packet = xdmcp_packet_decode ((guint8 *)data, n_read);
 
509
        packet = xdmcp_packet_decode ((guchar *)data, n_read);
572
510
        if (packet)
573
511
        {        
574
512
            g_debug ("Got %s", xdmcp_packet_tostring (packet));
597
535
            xdmcp_packet_free (packet);
598
536
        }
599
537
    }
 
538
    else
 
539
        g_warning ("Failed to read from XDMCP socket: %s", error->message);
 
540
 
 
541
    g_clear_error (&error);
600
542
 
601
543
    return TRUE;
602
544
}
628
570
{
629
571
    GSource *source;
630
572
    GError *error = NULL;
631
 
 
632
 
    g_return_val_if_fail (server != NULL, FALSE);
633
573
  
634
574
    server->priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, &error);
635
 
    if (error)
636
 
        g_warning ("Failed to create IPv4 XDMCP socket: %s", error->message);
637
 
    g_clear_error (&error);
638
 
  
639
575
    if (server->priv->socket)
640
576
    {
641
577
        source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
642
578
        g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
643
579
        g_source_attach (source, NULL);
644
580
    }
645
 
    
646
 
    server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, &error);
647
 
    if (error)
648
 
        g_warning ("Failed to create IPv6 XDMCP socket: %s", error->message);
 
581
    else
 
582
        g_warning ("Failed to create IPv4 XDMCP socket: %s", error->message);
649
583
    g_clear_error (&error);
650
 
 
 
584
    server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, &error);  
651
585
    if (server->priv->socket6)
652
586
    {
653
587
        source = g_socket_create_source (server->priv->socket6, G_IO_IN, NULL);
654
588
        g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
655
589
        g_source_attach (source, NULL);
656
590
    }
 
591
    else
 
592
        g_warning ("Failed to create IPv6 XDMCP socket: %s", error->message);
 
593
    g_clear_error (&error);
657
594
 
658
595
    if (!server->priv->socket && !server->priv->socket6)
659
596
        return FALSE;
670
607
    server->priv->hostname = g_strdup ("");
671
608
    server->priv->status = g_strdup ("");
672
609
    server->priv->sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
 
610
    server->priv->authentication_name = g_strdup ("");
 
611
    server->priv->authorization_name = g_strdup ("");
673
612
}
674
613
 
675
614
static void
685
624
        g_object_unref (self->priv->socket6);
686
625
    g_free (self->priv->hostname);
687
626
    g_free (self->priv->status);
688
 
    g_free (self->priv->key);
 
627
    g_free (self->priv->authentication_name);
 
628
    g_free (self->priv->authentication_data);
 
629
    g_free (self->priv->authorization_name);
 
630
    g_free (self->priv->authorization_data);
689
631
    g_hash_table_unref (self->priv->sessions);
690
 
  
691
 
    G_OBJECT_CLASS (xdmcp_server_parent_class)->finalize (object);  
692
632
}
693
633
 
694
634
static void