~lightdm-team/lightdm/1.4

118 by robert.ancell at gmail
Add missing files
1
/*
2
 * Copyright (C) 2010 Robert Ancell.
3
 * Author: Robert Ancell <robert.ancell@canonical.com>
4
 * 
5
 * This program is free software: you can redistribute it and/or modify it under
6
 * the terms of the GNU General Public License as published by the Free Software
7
 * Foundation, either version 3 of the License, or (at your option) any later
8
 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9
 * license.
10
 */
11
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
12
#include <stdlib.h>
13
#include <string.h>
119 by robert.ancell at gmail
Use address provided by XDMCP display
14
#include <X11/X.h>
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
15
#define HASXDMAUTH
16
#include <X11/Xdmcp.h>
118 by robert.ancell at gmail
Add missing files
17
#include <gio/gio.h>
140 by robert.ancell at gmail
Make persistent connection to remote server with proper authorization
18
#include "ldm-marshal.h"
118 by robert.ancell at gmail
Add missing files
19
20
#include "xdmcp-server.h"
21
#include "xdmcp-protocol.h"
22
#include "xdmcp-session-private.h"
140 by robert.ancell at gmail
Make persistent connection to remote server with proper authorization
23
#include "xauth.h"
118 by robert.ancell at gmail
Add missing files
24
25
enum {
140 by robert.ancell at gmail
Make persistent connection to remote server with proper authorization
26
    NEW_SESSION,
118 by robert.ancell at gmail
Add missing files
27
    LAST_SIGNAL
28
};
29
static guint signals[LAST_SIGNAL] = { 0 };
30
31
struct XDMCPServerPrivate
32
{
135 by robert.ancell at gmail
Suport authentication and authorization better
33
    /* Port to listen on */
132 by robert.ancell at gmail
Make --test-mode which runs as the current user
34
    guint port;
118 by robert.ancell at gmail
Add missing files
35
141 by robert.ancell at gmail
Support XDMCP over IPv6
36
    /* Listening sockets */
37
    GSocket *socket, *socket6;
118 by robert.ancell at gmail
Add missing files
38
135 by robert.ancell at gmail
Suport authentication and authorization better
39
    /* Hostname to report to client */
118 by robert.ancell at gmail
Add missing files
40
    gchar *hostname;
41
135 by robert.ancell at gmail
Suport authentication and authorization better
42
    /* Status to report to clients */
118 by robert.ancell at gmail
Add missing files
43
    gchar *status;
44
135 by robert.ancell at gmail
Suport authentication and authorization better
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;
58
59
    /* Active XDMCP sessions */
118 by robert.ancell at gmail
Add missing files
60
    GHashTable *sessions;
61
};
62
63
G_DEFINE_TYPE (XDMCPServer, xdmcp_server, G_TYPE_OBJECT);
64
65
XDMCPServer *
132 by robert.ancell at gmail
Make --test-mode which runs as the current user
66
xdmcp_server_new (void)
67
{
68
    return g_object_new (XDMCP_SERVER_TYPE, NULL);
69
}
70
71
void
72
xdmcp_server_set_port (XDMCPServer *server, guint port)
73
{
74
    server->priv->port = port;
75
}
76
77
guint
78
xdmcp_server_get_port (XDMCPServer *server)
79
{
80
    return server->priv->port;
118 by robert.ancell at gmail
Add missing files
81
}
82
83
void
84
xdmcp_server_set_hostname (XDMCPServer *server, const gchar *hostname)
85
{
86
    g_free (server->priv->hostname);
87
    server->priv->hostname = g_strdup (hostname);
88
}
89
90
const gchar *
91
xdmcp_server_get_hostname (XDMCPServer *server)
92
{
93
    return server->priv->hostname;
94
}
95
96
void
97
xdmcp_server_set_status (XDMCPServer *server, const gchar *status)
98
{
99
    g_free (server->priv->status);
100
    server->priv->status = g_strdup (status);
101
}
102
103
const gchar *
104
xdmcp_server_get_status (XDMCPServer *server)
105
{
106
    return server->priv->status;
107
}
108
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
109
void
135 by robert.ancell at gmail
Suport authentication and authorization better
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;
165
}
166
167
static gboolean
168
session_timeout_cb (XDMCPSession *session)
169
{
170
    g_debug ("Timing out unmanaged session %d", session->priv->id);
171
    g_hash_table_remove (session->priv->server->priv->sessions, GINT_TO_POINTER ((gint) session->priv->id));
138 by robert.ancell at gmail
Get XDM-AUTHORIZATION-1 working, but only with session_key=0
172
    return FALSE;
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
173
}
174
118 by robert.ancell at gmail
Add missing files
175
static XDMCPSession *
176
add_session (XDMCPServer *server)
177
{
178
    XDMCPSession *session;
179
    guint16 id;
180
181
    do
182
    {
128 by Testy Tester
Fix some compiler warnings
183
        id = g_random_int () & 0xFFFFFFFF;
184
    } while (g_hash_table_lookup (server->priv->sessions, GINT_TO_POINTER ((gint) id)));
118 by robert.ancell at gmail
Add missing files
185
186
    session = xdmcp_session_new (id);
135 by robert.ancell at gmail
Suport authentication and authorization better
187
    session->priv->server = server;
129 by Testy Tester
Clean up on exit
188
    g_hash_table_insert (server->priv->sessions, GINT_TO_POINTER ((gint) id), g_object_ref (session));
135 by robert.ancell at gmail
Suport authentication and authorization better
189
    session->priv->inactive_timeout = g_timeout_add (10, (GSourceFunc) session_timeout_cb, session);
118 by robert.ancell at gmail
Add missing files
190
191
    return session;
192
}
193
194
static XDMCPSession *
195
get_session (XDMCPServer *server, guint16 id)
196
{
128 by Testy Tester
Fix some compiler warnings
197
    return g_hash_table_lookup (server->priv->sessions, GINT_TO_POINTER ((gint) id));
118 by robert.ancell at gmail
Add missing files
198
}
199
200
static void
201
send_packet (GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
202
{
203
    guchar data[1024];
204
    gssize n_written;
205
206
    g_debug ("Send %s", xdmcp_packet_tostring (packet));
207
              
208
    n_written = xdmcp_packet_encode (packet, data, 1024);
209
    if (n_written < 0)
210
      g_critical ("Failed to encode XDMCP packet");
211
    else
212
    {
213
        GError *error = NULL;
214
215
        if (g_socket_send_to (socket, address, (gchar *) data, n_written, NULL, &error) < 0)
216
            g_warning ("Error sending packet: %s", error->message);
217
218
        g_clear_error (&error);
219
    }
220
}
221
222
static void
223
handle_query (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
224
{
225
    XDMCPPacket *response;
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
226
    gchar **i;
135 by robert.ancell at gmail
Suport authentication and authorization better
227
    gboolean match_authentication = FALSE;
228
229
    /* If no authentication requested and we are configured for none then allow */
230
    if (packet->Query.authentication_names[0] == NULL && strcmp (server->priv->authentication_name, "") == 0)
231
        match_authentication = TRUE;
232
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
233
    for (i = packet->Query.authentication_names; *i; i++)
234
    {
135 by robert.ancell at gmail
Suport authentication and authorization better
235
        if (strcmp (*i, server->priv->authentication_name) == 0)
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
236
        {
135 by robert.ancell at gmail
Suport authentication and authorization better
237
            match_authentication = TRUE;
238
            break;
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
239
        }
240
    }
118 by robert.ancell at gmail
Add missing files
241
135 by robert.ancell at gmail
Suport authentication and authorization better
242
    if (match_authentication)
243
    {
244
        response = xdmcp_packet_alloc (XDMCP_Willing);
245
        response->Willing.authentication_name = g_strdup (server->priv->authentication_name);
246
        response->Willing.hostname = g_strdup (server->priv->hostname);
247
        response->Willing.status = g_strdup (server->priv->status);
248
    }
249
    else
250
    {
251
        response = xdmcp_packet_alloc (XDMCP_Unwilling);
252
        response->Willing.hostname = g_strdup (server->priv->hostname);
253
        response->Willing.status = g_strdup (server->priv->status);
254
    }
255
  
118 by robert.ancell at gmail
Add missing files
256
    send_packet (socket, address, response);
257
258
    xdmcp_packet_free (response);
259
}
260
261
static void
262
handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
263
{
119 by robert.ancell at gmail
Use address provided by XDMCP display
264
    int i;
118 by robert.ancell at gmail
Add missing files
265
    XDMCPPacket *response;
266
    XDMCPSession *session;
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
267
    guchar *authentication_data = NULL;
268
    gsize authentication_data_length = 0;
135 by robert.ancell at gmail
Suport authentication and authorization better
269
    gboolean match_authorization = FALSE;
270
    guchar *authorization_data = NULL;
271
    gsize authorization_data_length = 0;
137 by robert.ancell at gmail
Store authorization in files
272
    guchar *session_authorization_data = NULL;
273
    gsize session_authorization_data_length = 0;
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
274
    gchar **j;
142 by robert.ancell at gmail
Prep for XDMCP IPv6 support
275
    GInetAddress *address4 = NULL, *address6 = NULL;
138 by robert.ancell at gmail
Get XDM-AUTHORIZATION-1 working, but only with session_key=0
276
    XdmAuthKeyRec rho;
121 by robert.ancell at gmail
Keep a connection open to XDMCP X server to allow greeter->session transition, handle more XDMCP failures
277
  
135 by robert.ancell at gmail
Suport authentication and authorization better
278
    /* Must be using our authentication scheme */
279
    if (strcmp (packet->Request.authentication_name, server->priv->authentication_name) != 0)
280
    {
281
        response = xdmcp_packet_alloc (XDMCP_Decline);
282
        if (strcmp (server->priv->authentication_name, "") == 0)
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);
286
        response->Decline.authentication_name = g_strdup ("");
287
        send_packet (socket, address, response);
288
        xdmcp_packet_free (response);
289
        return;
290
    }
291
292
    /* Perform requested authentication */
293
    if (strcmp (server->priv->authentication_name, "XDM-AUTHENTICATION-1") == 0)
294
    {
295
        guchar input[8], key[8];
296
297
        memset (input, 0, 8);
298
        memcpy (input, packet->Request.authentication_data.data, packet->Request.authentication_data.length > 8 ? 8 : packet->Request.authentication_data.length);
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
299
300
        /* Setup key */
135 by robert.ancell at gmail
Suport authentication and authorization better
301
        memset (key, 0, 8);
302
        memcpy (key, server->priv->authentication_data, server->priv->authentication_data_length > 8 ? 8 : server->priv->authentication_data_length);
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
303
304
        /* Decode message from server */
135 by robert.ancell at gmail
Suport authentication and authorization better
305
        authentication_data = g_malloc (sizeof (guchar) * 8);
306
        authentication_data_length = 8;
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
307
138 by robert.ancell at gmail
Get XDM-AUTHORIZATION-1 working, but only with session_key=0
308
        XdmcpUnwrap (input, key, rho.data, authentication_data_length);
309
        XdmcpIncrementKey (&rho);
310
        XdmcpWrap (rho.data, key, authentication_data, authentication_data_length);
135 by robert.ancell at gmail
Suport authentication and authorization better
311
    }
312
313
    /* Check if they support our authorization */
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
314
    for (j = packet->Request.authorization_names; *j; j++)
315
    {
135 by robert.ancell at gmail
Suport authentication and authorization better
316
        if (strcmp (*j, server->priv->authorization_name) == 0)
317
        {
318
             match_authorization = TRUE;
319
             break;
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
320
        }
321
    }
136 by robert.ancell at gmail
Generate authorization keys for XDM-AUTHORIZATION-1
322
  
135 by robert.ancell at gmail
Suport authentication and authorization better
323
    if (!match_authorization)
324
    {
325
        response = xdmcp_packet_alloc (XDMCP_Decline);
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);
330
        response->Decline.authentication_name = g_strdup (packet->Request.authentication_name);
331
        response->Decline.authentication_data.data = authentication_data;
332
        response->Decline.authentication_data.length = authentication_data_length;
333
        send_packet (socket, address, response);
334
        xdmcp_packet_free (response);
335
        return;
336
    }
118 by robert.ancell at gmail
Add missing files
337
136 by robert.ancell at gmail
Generate authorization keys for XDM-AUTHORIZATION-1
338
    /* Perform requested authorization */
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)
347
    {
348
        gint i;
137 by robert.ancell at gmail
Store authorization in files
349
        guchar key[8], session_key[8];
136 by robert.ancell at gmail
Generate authorization keys for XDM-AUTHORIZATION-1
350
351
        /* Setup 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);
354
137 by robert.ancell at gmail
Store authorization in files
355
        /* Generate a private session key */
356
        // FIXME: Pick a good DES key?
139 by robert.ancell at gmail
Got XDM-AUTHORIZATION-1 working
357
        session_key[0] = 0;
358
        for (i = 1; i < 8; i++)
359
            session_key[i] = g_random_int () & 0xFF;
137 by robert.ancell at gmail
Store authorization in files
360
361
        /* Encrypt the session key and send it to the server */
138 by robert.ancell at gmail
Get XDM-AUTHORIZATION-1 working, but only with session_key=0
362
        authorization_data = g_malloc (8);
136 by robert.ancell at gmail
Generate authorization keys for XDM-AUTHORIZATION-1
363
        authorization_data_length = 8;
364
        XdmcpWrap (session_key, key, authorization_data, authorization_data_length);
137 by robert.ancell at gmail
Store authorization in files
365
138 by robert.ancell at gmail
Get XDM-AUTHORIZATION-1 working, but only with session_key=0
366
        /* Authorization data is the number received from the client followed by the private session key */
367
        session_authorization_data = g_malloc (16);
368
        session_authorization_data_length = 16;
369
        XdmcpDecrementKey (&rho);
370
        memcpy (session_authorization_data, rho.data, 8);
371
        memcpy (session_authorization_data + 8, session_key, 8);
136 by robert.ancell at gmail
Generate authorization keys for XDM-AUTHORIZATION-1
372
    }
373
119 by robert.ancell at gmail
Use address provided by XDMCP display
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;
142 by robert.ancell at gmail
Prep for XDMCP IPv6 support
385
        case FamilyInternet6:
119 by robert.ancell at gmail
Use address provided by XDMCP display
386
            if (connection->address.length == 16)
387
                address6 = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);          
142 by robert.ancell at gmail
Prep for XDMCP IPv6 support
388
            break;
119 by robert.ancell at gmail
Use address provided by XDMCP display
389
        }
390
    }
391
142 by robert.ancell at gmail
Prep for XDMCP IPv6 support
392
    if (!address4) // FIXME: && !address6)
121 by robert.ancell at gmail
Keep a connection open to XDMCP X server to allow greeter->session transition, handle more XDMCP failures
393
    {
394
        response = xdmcp_packet_alloc (XDMCP_Decline);
395
        response->Decline.status = g_strdup ("No valid address found");
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
396
        response->Decline.authentication_name = g_strdup (packet->Request.authentication_name);
135 by robert.ancell at gmail
Suport authentication and authorization better
397
        response->Decline.authentication_data.data = authentication_data;
398
        response->Decline.authentication_data.length = authentication_data_length;
121 by robert.ancell at gmail
Keep a connection open to XDMCP X server to allow greeter->session transition, handle more XDMCP failures
399
        send_packet (socket, address, response);
400
        xdmcp_packet_free (response);
401
        return;
402
    }
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
403
118 by robert.ancell at gmail
Add missing files
404
    session = add_session (server);
142 by robert.ancell at gmail
Prep for XDMCP IPv6 support
405
    session->priv->address = address4;
406
    session->priv->address6 = address6;
137 by robert.ancell at gmail
Store authorization in files
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;
118 by robert.ancell at gmail
Add missing files
410
411
    response = xdmcp_packet_alloc (XDMCP_Accept);
412
    response->Accept.session_id = xdmcp_session_get_id (session);
123 by robert.ancell at gmail
Support XDM-AUTHENTICATION-1
413
    response->Accept.authentication_name = g_strdup (packet->Request.authentication_name);
414
    response->Accept.authentication_data.data = authentication_data;
415
    response->Accept.authentication_data.length = authentication_data_length;
135 by robert.ancell at gmail
Suport authentication and authorization better
416
    response->Accept.authorization_name = g_strdup (server->priv->authorization_name);
417
    response->Accept.authorization_data.data = authorization_data;
418
    response->Accept.authorization_data.length = authorization_data_length;
118 by robert.ancell at gmail
Add missing files
419
    send_packet (socket, address, response);
420
    xdmcp_packet_free (response);
421
}
422
423
static void
424
handle_manage (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
425
{
426
    XDMCPSession *session;
427
428
    session = get_session (server, packet->Manage.session_id);
429
    if (session)
430
    {
140 by robert.ancell at gmail
Make persistent connection to remote server with proper authorization
431
        gboolean result;
121 by robert.ancell at gmail
Keep a connection open to XDMCP X server to allow greeter->session transition, handle more XDMCP failures
432
433
        /* Ignore duplicate requests */
434
        if (session->priv->started)
435
        {
436
            if (session->priv->display_number != packet->Manage.display_number ||
437
                strcmp (session->priv->display_class, packet->Manage.display_class) != 0)
438
                g_warning ("Duplicate Manage received with different data");
439
            return;
440
        }
441
140 by robert.ancell at gmail
Make persistent connection to remote server with proper authorization
442
        session->priv->display_number = packet->Manage.display_number;  
443
        session->priv->display_class = g_strdup (packet->Manage.display_class);
444
445
        g_signal_emit (server, signals[NEW_SESSION], 0, session, &result);
446
        if (result)
447
        {
448
            /* Cancel the inactive timer */
449
            g_source_remove (session->priv->inactive_timeout);
450
451
            session->priv->started = TRUE;
452
        }
453
        else
121 by robert.ancell at gmail
Keep a connection open to XDMCP X server to allow greeter->session transition, handle more XDMCP failures
454
        {
455
            XDMCPPacket *response;
456
457
            response = xdmcp_packet_alloc (XDMCP_Failed);
458
            response->Failed.session_id = packet->Manage.session_id;
397 by Robert Ancell
Fix some compile warnings
459
            response->Failed.status = g_strdup_printf ("Failed to connect to display :%d", packet->Manage.display_number);
121 by robert.ancell at gmail
Keep a connection open to XDMCP X server to allow greeter->session transition, handle more XDMCP failures
460
            send_packet (socket, address, response);
461
            xdmcp_packet_free (response);
462
        }
118 by robert.ancell at gmail
Add missing files
463
    }
464
    else
465
    {
121 by robert.ancell at gmail
Keep a connection open to XDMCP X server to allow greeter->session transition, handle more XDMCP failures
466
        XDMCPPacket *response;
467
118 by robert.ancell at gmail
Add missing files
468
        response = xdmcp_packet_alloc (XDMCP_Refuse);
469
        response->Refuse.session_id = packet->Manage.session_id;
470
        send_packet (socket, address, response);
471
        xdmcp_packet_free (response);
472
    }
473
}
474
475
static void
476
handle_keep_alive (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
477
{
478
    XDMCPPacket *response;
479
    XDMCPSession *session;
480
    gboolean alive = FALSE;
481
482
    session = get_session (server, packet->KeepAlive.session_id);
483
    if (session)
484
        alive = TRUE; //xdmcp_session_get_alive (session);
485
486
    response = xdmcp_packet_alloc (XDMCP_Alive);
487
    response->Alive.session_running = alive;
488
    response->Alive.session_id = alive ? packet->KeepAlive.session_id : 0;
489
    send_packet (socket, address, response);
490
    xdmcp_packet_free (response);
491
}
492
493
static gboolean
494
read_cb (GSocket *socket, GIOCondition condition, XDMCPServer *server)
495
{
496
    GSocketAddress *address;
497
    gchar data[1024];
498
    GError *error = NULL;
499
    gssize n_read;
500
501
    n_read = g_socket_receive_from (socket, &address, data, 1024, NULL, &error);
502
    if (n_read > 0)
503
    {
504
        XDMCPPacket *packet;
505
506
        packet = xdmcp_packet_decode ((guchar *)data, n_read);
507
        if (packet)
508
        {        
509
            g_debug ("Got %s", xdmcp_packet_tostring (packet));
510
511
            switch (packet->opcode)
512
            {
513
            case XDMCP_BroadcastQuery:
514
            case XDMCP_Query:
515
            case XDMCP_IndirectQuery:
516
                handle_query (server, socket, address, packet);
517
                break;
518
            case XDMCP_Request:
519
                handle_request (server, socket, address, packet);
520
                break;
521
            case XDMCP_Manage:
522
                handle_manage (server, socket, address, packet);              
523
                break;
524
            case XDMCP_KeepAlive:
525
                handle_keep_alive (server, socket, address, packet);
526
                break;
527
            default:
528
                g_warning ("Got unexpected XDMCP packet %d", packet->opcode);
529
                break;
530
            }
531
532
            xdmcp_packet_free (packet);
533
        }
534
    }
535
    else
536
        g_warning ("Failed to read from XDMCP socket: %s", error->message);
537
538
    g_clear_error (&error);
539
540
    return TRUE;
541
}
542
141 by robert.ancell at gmail
Support XDMCP over IPv6
543
static GSocket *
544
open_udp_socket (GSocketFamily family, guint port, GError **error)
545
{
546
    GSocket *socket;
547
    GSocketAddress *address;
548
    gboolean result;
549
  
550
    socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, error);
551
    if (!socket)
552
        return NULL;
553
554
    address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
555
    result = g_socket_bind (socket, address, TRUE, error);
556
    if (!result)
557
    {
558
        g_object_unref (socket);
559
        return NULL;
560
    }
561
562
    return socket;
563
}
564
118 by robert.ancell at gmail
Add missing files
565
gboolean
566
xdmcp_server_start (XDMCPServer *server)
567
{
568
    GSource *source;
569
    GError *error = NULL;
570
  
141 by robert.ancell at gmail
Support XDMCP over IPv6
571
    server->priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, &error);
572
    if (server->priv->socket)
573
    {
574
        source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
575
        g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
576
        g_source_attach (source, NULL);
577
    }
578
    else
579
        g_warning ("Failed to create IPv4 XDMCP socket: %s", error->message);
580
    g_clear_error (&error);
581
    server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, &error);  
582
    if (server->priv->socket6)
583
    {
584
        source = g_socket_create_source (server->priv->socket6, G_IO_IN, NULL);
585
        g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
586
        g_source_attach (source, NULL);
587
    }
588
    else
589
        g_warning ("Failed to create IPv6 XDMCP socket: %s", error->message);
590
    g_clear_error (&error);
591
592
    if (!server->priv->socket && !server->priv->socket6)
593
        return FALSE;
118 by robert.ancell at gmail
Add missing files
594
595
    return TRUE;
596
}
597
598
static void
599
xdmcp_server_init (XDMCPServer *server)
600
{
601
    server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server, XDMCP_SERVER_TYPE, XDMCPServerPrivate);
602
132 by robert.ancell at gmail
Make --test-mode which runs as the current user
603
    server->priv->port = XDM_UDP_PORT;
118 by robert.ancell at gmail
Add missing files
604
    server->priv->hostname = g_strdup ("");
605
    server->priv->status = g_strdup ("");
137 by robert.ancell at gmail
Store authorization in files
606
    server->priv->sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
135 by robert.ancell at gmail
Suport authentication and authorization better
607
    server->priv->authentication_name = g_strdup ("");
608
    server->priv->authorization_name = g_strdup ("");
118 by robert.ancell at gmail
Add missing files
609
}
610
611
static void
129 by Testy Tester
Clean up on exit
612
xdmcp_server_finalize (GObject *object)
613
{
614
    XDMCPServer *self;
615
616
    self = XDMCP_SERVER (object);
617
  
618
    if (self->priv->socket)
619
        g_object_unref (self->priv->socket);
141 by robert.ancell at gmail
Support XDMCP over IPv6
620
    if (self->priv->socket6)
621
        g_object_unref (self->priv->socket6);
129 by Testy Tester
Clean up on exit
622
    g_free (self->priv->hostname);
623
    g_free (self->priv->status);
135 by robert.ancell at gmail
Suport authentication and authorization better
624
    g_free (self->priv->authentication_name);
625
    g_free (self->priv->authentication_data);
626
    g_free (self->priv->authorization_name);
627
    g_free (self->priv->authorization_data);
129 by Testy Tester
Clean up on exit
628
    g_hash_table_unref (self->priv->sessions);
629
}
630
631
static void
118 by robert.ancell at gmail
Add missing files
632
xdmcp_server_class_init (XDMCPServerClass *klass)
633
{
634
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
635
129 by Testy Tester
Clean up on exit
636
    object_class->finalize = xdmcp_server_finalize;  
118 by robert.ancell at gmail
Add missing files
637
638
    g_type_class_add_private (klass, sizeof (XDMCPServerPrivate));
639
140 by robert.ancell at gmail
Make persistent connection to remote server with proper authorization
640
    signals[NEW_SESSION] =
641
        g_signal_new ("new-session",
118 by robert.ancell at gmail
Add missing files
642
                      G_TYPE_FROM_CLASS (klass),
643
                      G_SIGNAL_RUN_LAST,
140 by robert.ancell at gmail
Make persistent connection to remote server with proper authorization
644
                      G_STRUCT_OFFSET (XDMCPServerClass, new_session),
645
                      g_signal_accumulator_true_handled,
646
                      NULL,
647
                      ldm_marshal_BOOLEAN__OBJECT,
648
                      G_TYPE_BOOLEAN, 1, XDMCP_SESSION_TYPE);
118 by robert.ancell at gmail
Add missing files
649
}