~robert-ancell/lightdm/docstrings

« back to all changes in this revision

Viewing changes to src/xdmcp-server.c

  • Committer: Robert Ancell
  • Date: 2015-08-10 00:21:57 UTC
  • mfrom: (1709.1.454 trunk)
  • Revision ID: robert.ancell@canonical.com-20150810002157-39tqqq8wv006gwzq
Merge with trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * Copyright (C) 2010-2011 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
6
6
 * the terms of the GNU General Public License as published by the Free Software
7
7
 * Foundation, either version 3 of the License, or (at your option) any later
32
32
    /* Port to listen on */
33
33
    guint port;
34
34
 
 
35
    /* Address to listen on */
 
36
    gchar *listen_address;
 
37
 
35
38
    /* Listening sockets */
36
39
    GSocket *socket, *socket6;
37
40
 
74
77
}
75
78
 
76
79
void
 
80
xdmcp_server_set_listen_address (XDMCPServer *server, const gchar *listen_address)
 
81
{
 
82
    g_return_if_fail (server != NULL);
 
83
 
 
84
    g_free (server->priv->listen_address);
 
85
    server->priv->listen_address = g_strdup (listen_address);
 
86
}
 
87
 
 
88
const gchar *
 
89
xdmcp_server_get_listen_address (XDMCPServer *server)
 
90
{
 
91
    g_return_val_if_fail (server != NULL, NULL);
 
92
    return server->priv->listen_address;
 
93
}
 
94
 
 
95
void
77
96
xdmcp_server_set_hostname (XDMCPServer *server, const gchar *hostname)
78
97
{
79
98
    g_return_if_fail (server != NULL);
116
135
static gboolean
117
136
session_timeout_cb (XDMCPSession *session)
118
137
{
 
138
    session->priv->inactive_timeout = 0;
 
139
 
119
140
    g_debug ("Timing out unmanaged session %d", session->priv->id);
120
141
    g_hash_table_remove (session->priv->server->priv->sessions, GINT_TO_POINTER ((gint) session->priv->id));
121
142
    return FALSE;
153
174
    gssize n_written;
154
175
 
155
176
    g_debug ("Send %s", xdmcp_packet_tostring (packet));
156
 
              
 
177
 
157
178
    n_written = xdmcp_packet_encode (packet, data, 1024);
158
179
    if (n_written < 0)
159
180
      g_critical ("Failed to encode XDMCP packet");
213
234
        else
214
235
            response->Unwilling.status = g_strdup ("Server does not support authentication");
215
236
    }
216
 
  
 
237
 
217
238
    send_packet (socket, address, response);
218
239
 
219
240
    xdmcp_packet_free (response);
256
277
    }
257
278
}
258
279
 
 
280
static GInetAddress *
 
281
connection_to_address (XDMCPConnection *connection)
 
282
{
 
283
    switch (connection->type)
 
284
    {
 
285
    case XAUTH_FAMILY_INTERNET:
 
286
        if (connection->address.length == 4)
 
287
            return g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV4);
 
288
        else
 
289
            return NULL;
 
290
    case XAUTH_FAMILY_INTERNET6:
 
291
        if (connection->address.length == 16)
 
292
            return g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);
 
293
        else
 
294
            return NULL;
 
295
    default:
 
296
        return NULL;
 
297
    }
 
298
}
 
299
 
 
300
static gssize
 
301
find_address (GInetAddress **addresses, gsize length, GSocketFamily family)
 
302
{
 
303
    int i;
 
304
 
 
305
    for (i = 0; i < length; i++)
 
306
    {
 
307
        GInetAddress *address = addresses[i];
 
308
        if (address && g_inet_address_get_family (address) == family)
 
309
            return i;
 
310
    }
 
311
 
 
312
    return -1;
 
313
}
 
314
 
 
315
static XDMCPConnection *
 
316
choose_connection (XDMCPPacket *packet, GInetAddress *source_address)
 
317
{
 
318
    GInetAddress **addresses;
 
319
    gsize addresses_length, i;
 
320
    gssize index = -1;
 
321
 
 
322
    addresses_length = packet->Request.n_connections;
 
323
    addresses = malloc (sizeof (GInetAddress *) * addresses_length);
 
324
    for (i = 0; i < addresses_length; i++)
 
325
        addresses[i] = connection_to_address (&packet->Request.connections[i]);
 
326
 
 
327
    /* Use the address the request came in on as this is the least likely to have firewall / routing issues */
 
328
    for (i = 0; i < addresses_length && index < 0; i++)
 
329
        if (g_inet_address_equal (source_address, addresses[i]))
 
330
            index = i;
 
331
 
 
332
    /* Otherwise try and find an address that matches the incoming type */
 
333
    if (index < 0)
 
334
        index = find_address (addresses, addresses_length, g_inet_address_get_family (source_address));
 
335
 
 
336
    /* Otherwise use the first available */
 
337
    if (index < 0 && addresses_length > 0)
 
338
        index = 0;
 
339
 
 
340
    for (i = 0; i < addresses_length; i++)
 
341
        g_object_unref (addresses[i]);
 
342
    g_free (addresses);
 
343
 
 
344
    return &packet->Request.connections[index];
 
345
}
 
346
 
259
347
static void
260
348
handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
261
349
{
262
 
    int i;
263
350
    XDMCPPacket *response;
264
351
    XDMCPSession *session;
265
352
    guint8 *authentication_data = NULL;
271
358
    guint8 *session_authorization_data = NULL;
272
359
    gsize session_authorization_data_length = 0;
273
360
    gchar **j;
274
 
    guint16 family;
275
 
    GInetAddress *x_server_address = NULL;
 
361
    XDMCPConnection *connection;
276
362
    gchar *display_number;
277
363
    XdmAuthKeyRec rho;
278
364
 
279
 
    /* Try and find an IPv6 address */
280
 
    for (i = 0; i < packet->Request.n_connections; i++)
281
 
    {
282
 
        XDMCPConnection *connection = &packet->Request.connections[i];
283
 
        if (connection->type == XAUTH_FAMILY_INTERNET6 && connection->address.length == 16)
284
 
        {
285
 
            family = connection->type;
286
 
            x_server_address = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);
287
 
 
288
 
            /* We can't use link-local addresses, as we need to know what interface it is on */
289
 
            if (g_inet_address_get_is_link_local (x_server_address))
290
 
            {
291
 
                g_object_unref (x_server_address);
292
 
                x_server_address = NULL;
293
 
            }
294
 
            else
295
 
                break;
296
 
        }
297
 
    }
298
 
 
299
 
    /* If no IPv6 address, then try and find an IPv4 one */
300
 
    if (!x_server_address)
301
 
    {
302
 
        for (i = 0; i < packet->Request.n_connections; i++)
303
 
        {
304
 
            XDMCPConnection *connection = &packet->Request.connections[i];
305
 
            if (connection->type == XAUTH_FAMILY_INTERNET && connection->address.length == 4)
306
 
            {
307
 
                family = connection->type;
308
 
                x_server_address = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV4);
309
 
                break;
310
 
            }
311
 
        }
312
 
    }
 
365
    /* Choose an address to connect back on */
 
366
    connection = choose_connection (packet, g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)));
313
367
 
314
368
    /* Decline if haven't got an address we can connect on */
315
 
    if (!x_server_address)
 
369
    if (!connection)
316
370
    {
317
371
        response = xdmcp_packet_alloc (XDMCP_Decline);
318
372
        response->Decline.status = g_strdup ("No valid address found");
323
377
        xdmcp_packet_free (response);
324
378
        return;
325
379
    }
326
 
  
 
380
 
327
381
    /* Must be using our authentication scheme */
328
382
    if (strcmp (packet->Request.authentication_name, get_authentication_name (server)) != 0)
329
383
    {
428
482
    }
429
483
 
430
484
    session = add_session (server);
431
 
    session->priv->address = x_server_address;
 
485
    session->priv->address = connection_to_address (connection);
432
486
    session->priv->display_number = packet->Request.display_number;
433
487
    display_number = g_strdup_printf ("%d", packet->Request.display_number);
434
488
 
435
489
    /* We need to check if this is the loopback address and set the authority
436
490
     * for a local connection if this is so as XCB treats "127.0.0.1" as local
437
491
     * always */
438
 
    if (g_inet_address_get_is_loopback (x_server_address))
 
492
    if (g_inet_address_get_is_loopback (session->priv->address))
439
493
    {
440
494
        gchar hostname[1024];
441
495
        gethostname (hostname, 1024);
442
496
 
443
497
        session->priv->authority = x_authority_new (XAUTH_FAMILY_LOCAL,
444
 
                                              (guint8 *) hostname,
445
 
                                              strlen (hostname),
446
 
                                              display_number,
447
 
                                              authorization_name,
448
 
                                              session_authorization_data,
449
 
                                              session_authorization_data_length);
 
498
                                                    (guint8 *) hostname,
 
499
                                                    strlen (hostname),
 
500
                                                    display_number,
 
501
                                                    authorization_name,
 
502
                                                    session_authorization_data,
 
503
                                                    session_authorization_data_length);
450
504
    }
451
505
    else
452
 
        session->priv->authority = x_authority_new (family,
453
 
                                              g_inet_address_to_bytes (G_INET_ADDRESS (x_server_address)),
454
 
                                              g_inet_address_get_native_size (G_INET_ADDRESS (x_server_address)),
455
 
                                              display_number,
456
 
                                              authorization_name,
457
 
                                              session_authorization_data,
458
 
                                              session_authorization_data_length);
 
506
        session->priv->authority = x_authority_new (connection->type,
 
507
                                                    connection->address.data,
 
508
                                                    connection->address.length,
 
509
                                                    display_number,
 
510
                                                    authorization_name,
 
511
                                                    session_authorization_data,
 
512
                                                    session_authorization_data_length);
459
513
    g_free (display_number);
460
514
 
461
515
    response = xdmcp_packet_alloc (XDMCP_Accept);
516
570
    if (result)
517
571
    {
518
572
        /* Cancel the inactive timer */
519
 
        g_source_remove (session->priv->inactive_timeout);
 
573
        if (session->priv->inactive_timeout)
 
574
            g_source_remove (session->priv->inactive_timeout);
520
575
 
521
576
        session->priv->started = TRUE;
522
577
    }
569
624
 
570
625
        packet = xdmcp_packet_decode ((guint8 *)data, n_read);
571
626
        if (packet)
572
 
        {        
 
627
        {
573
628
            g_debug ("Got %s", xdmcp_packet_tostring (packet));
574
629
 
575
630
            switch (packet->opcode)
583
638
                handle_request (server, socket, address, packet);
584
639
                break;
585
640
            case XDMCP_Manage:
586
 
                handle_manage (server, socket, address, packet);              
 
641
                handle_manage (server, socket, address, packet);
587
642
                break;
588
643
            case XDMCP_KeepAlive:
589
644
                handle_keep_alive (server, socket, address, packet);
601
656
}
602
657
 
603
658
static GSocket *
604
 
open_udp_socket (GSocketFamily family, guint port, GError **error)
 
659
open_udp_socket (GSocketFamily family, guint port, const gchar *listen_address, GError **error)
605
660
{
606
661
    GSocket *socket;
607
662
    GSocketAddress *address;
608
663
    gboolean result;
609
 
  
 
664
 
610
665
    socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, error);
611
666
    if (!socket)
612
667
        return NULL;
613
668
 
614
 
    address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
 
669
    if (listen_address) 
 
670
    {
 
671
        GList *addresses;
 
672
 
 
673
        addresses = g_resolver_lookup_by_name (g_resolver_get_default (), listen_address, NULL, error);
 
674
        if (!addresses)
 
675
        {
 
676
            g_object_unref (socket);
 
677
            return NULL;
 
678
        }
 
679
        address = g_inet_socket_address_new (addresses->data, port);
 
680
        g_resolver_free_addresses (addresses);
 
681
    }
 
682
    else
 
683
        address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
615
684
    result = g_socket_bind (socket, address, TRUE, error);
616
685
    if (!result)
617
686
    {
629
698
    GError *error = NULL;
630
699
 
631
700
    g_return_val_if_fail (server != NULL, FALSE);
632
 
  
633
 
    server->priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, &error);
 
701
 
 
702
    server->priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, server->priv->listen_address, &error);
634
703
    if (error)
635
704
        g_warning ("Failed to create IPv4 XDMCP socket: %s", error->message);
636
705
    g_clear_error (&error);
637
 
  
 
706
 
638
707
    if (server->priv->socket)
639
708
    {
640
709
        source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
641
710
        g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
642
711
        g_source_attach (source, NULL);
643
712
    }
644
 
    
645
 
    server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, &error);
 
713
 
 
714
    server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, server->priv->listen_address, &error);
646
715
    if (error)
647
716
        g_warning ("Failed to create IPv6 XDMCP socket: %s", error->message);
648
717
    g_clear_error (&error);
677
746
    XDMCPServer *self;
678
747
 
679
748
    self = XDMCP_SERVER (object);
680
 
  
 
749
 
681
750
    if (self->priv->socket)
682
751
        g_object_unref (self->priv->socket);
683
752
    if (self->priv->socket6)
684
753
        g_object_unref (self->priv->socket6);
 
754
    g_free (self->priv->listen_address);
685
755
    g_free (self->priv->hostname);
686
756
    g_free (self->priv->status);
687
757
    g_free (self->priv->key);
688
758
    g_hash_table_unref (self->priv->sessions);
689
 
  
690
 
    G_OBJECT_CLASS (xdmcp_server_parent_class)->finalize (object);  
 
759
 
 
760
    G_OBJECT_CLASS (xdmcp_server_parent_class)->finalize (object);
691
761
}
692
762
 
693
763
static void
695
765
{
696
766
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
697
767
 
698
 
    object_class->finalize = xdmcp_server_finalize;  
 
768
    object_class->finalize = xdmcp_server_finalize;
699
769
 
700
770
    g_type_class_add_private (klass, sizeof (XDMCPServerPrivate));
701
771
 
702
772
    signals[NEW_SESSION] =
703
 
        g_signal_new ("new-session",
 
773
        g_signal_new (XDMCP_SERVER_SIGNAL_NEW_SESSION,
704
774
                      G_TYPE_FROM_CLASS (klass),
705
775
                      G_SIGNAL_RUN_LAST,
706
776
                      G_STRUCT_OFFSET (XDMCPServerClass, new_session),