~ubuntu-branches/ubuntu/trusty/remote-login-service/trusty

« back to all changes in this revision

Viewing changes to src/uccs-server.c

  • Committer: Package Import Robot
  • Author(s): Ted Gould
  • Date: 2012-09-13 11:16:17 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120913111617-4hascucrovrn3nov
Tags: 0.7.0-0ubuntu1
* New upstream release.
  - Fix NM service detection and fallback
  - Fix build on unoptimized build servers
  - Fix issues with multiple logins (LP: #1050810)
  - Support stored data in UCCS (LP: #1045836)
  - Check to insure TCCA is installed before using (LP: #1047939)
  - Ensure that the server is available before showing (LP: #1047940)
  - Make the UCCS server names translatable (LP: #1049694)
  - Fix error message that wasn't that bad (LP: #1041338)
  - Place the server marked as default first (LP: #1045838)
* debian/control:
  - Adding a build dep on libnm-glib
  - Adding a build dep on libsoup2.4-dev
* Dropping debian/patches as all upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
#include "config.h"
21
21
#endif
22
22
 
 
23
#include <glib/gi18n.h>
 
24
 
23
25
#include <json-glib/json-glib.h>
24
26
 
25
27
#include <gio/gunixinputstream.h>
42
44
static void json_waiters_notify (UccsServer * server, gboolean unlocked);
43
45
static GVariant * get_cached_domains (Server * server);
44
46
static Server * find_uri (Server * server, const gchar * uri);
 
47
static void evaluate_state (UccsServer * server);
 
48
static void nm_state_changed (NMClient *client, const GParamSpec *pspec, gpointer user_data);
45
49
 
46
50
typedef struct _json_callback_t json_callback_t;
47
51
struct _json_callback_t {
52
56
 
53
57
G_DEFINE_TYPE (UccsServer, uccs_server, SERVER_TYPE);
54
58
 
 
59
/* Static global client so we don't keep reallocating them.  We only need
 
60
   one really */
 
61
static NMClient * global_client = NULL;
 
62
 
55
63
static void
56
64
uccs_server_class_init (UccsServerClass *klass)
57
65
{
90
98
        self->json_stream = NULL;
91
99
        self->pass_stream = NULL;
92
100
 
 
101
        self->min_network = NM_STATE_CONNECTED_GLOBAL;
 
102
        self->last_network = NM_STATE_DISCONNECTED;
 
103
        self->nm_client = NULL;
 
104
        self->nm_signal = 0;
 
105
 
 
106
        /* Start as unavailable */
 
107
        self->parent.state = SERVER_STATE_UNAVAILABLE;
 
108
 
 
109
        if (global_client == NULL) {
 
110
                global_client = nm_client_new();
 
111
 
 
112
                if (global_client != NULL) {
 
113
                        g_object_add_weak_pointer(G_OBJECT(global_client), (gpointer *)&global_client);
 
114
                        self->nm_client = global_client;
 
115
                }
 
116
        } else {
 
117
                self->nm_client = g_object_ref(global_client);
 
118
        }
 
119
 
 
120
        if (self->nm_client != NULL) {
 
121
                self->nm_signal = g_signal_connect(self->nm_client, "notify::" NM_CLIENT_STATE, G_CALLBACK(nm_state_changed), self);
 
122
        }
 
123
 
 
124
        self->verify_server = TRUE;
 
125
        self->verified_server = FALSE;
 
126
        self->session = NULL;
 
127
 
 
128
        /* Need the soup session before the state changed */
 
129
        self->session = soup_session_sync_new();
 
130
 
 
131
        nm_state_changed(self->nm_client, NULL, self);
 
132
        evaluate_state(self);
 
133
 
 
134
        return;
 
135
}
 
136
 
 
137
/* Small function to try and figure out the state of the server and set the
 
138
   status appropriately */
 
139
static void
 
140
evaluate_state (UccsServer * server)
 
141
{
 
142
        ServerState tempstate = SERVER_STATE_ALLGOOD;
 
143
 
 
144
        if (server->exec == NULL) {
 
145
                tempstate = SERVER_STATE_UNAVAILABLE;
 
146
        }
 
147
 
 
148
        if (server->last_network < server->min_network) {
 
149
                tempstate = SERVER_STATE_UNAVAILABLE;
 
150
        }
 
151
 
 
152
        if (server->verify_server && !server->verified_server && server->min_network > NM_STATE_DISCONNECTED) {
 
153
                tempstate = SERVER_STATE_UNAVAILABLE;
 
154
        }
 
155
 
 
156
        if (tempstate != server->parent.state) {
 
157
                server->parent.state = tempstate;
 
158
                g_signal_emit_by_name(server, SERVER_SIGNAL_STATE_CHANGED, server->parent.state);
 
159
        }
 
160
 
93
161
        return;
94
162
}
95
163
 
118
186
                g_error_free(error);
119
187
        }
120
188
 
121
 
        return;
 
189
        return TRUE;
122
190
}
123
191
 
124
192
/* Clear the hash table by going through it and signaling */
148
216
        return;
149
217
}
150
218
 
151
 
/* Clean up references */
 
219
/* Clear the JSON task and waiters */
152
220
static void
153
 
uccs_server_dispose (GObject *object)
 
221
clear_json (UccsServer * self)
154
222
{
155
 
        UccsServer * self = UCCS_SERVER(object);
156
 
 
157
223
        if (self->json_watch != 0) {
158
224
                g_source_remove(self->json_watch);
159
225
                self->json_watch = 0;
178
244
 
179
245
        json_waiters_notify(self, FALSE);
180
246
 
 
247
        return;
 
248
}
 
249
 
 
250
/* Clean up references */
 
251
static void
 
252
uccs_server_dispose (GObject *object)
 
253
{
 
254
        UccsServer * self = UCCS_SERVER(object);
 
255
 
 
256
        g_clear_object(&self->session);
 
257
 
 
258
        if (self->nm_signal != 0) {
 
259
                g_signal_handler_disconnect(self->nm_client, self->nm_signal);
 
260
                self->nm_signal = 0;
 
261
        }
 
262
 
 
263
        g_clear_object(&self->nm_client);
 
264
 
 
265
        clear_json(self);
 
266
 
181
267
        if (self->lovers != NULL) {
182
268
                clear_hash(self);
183
269
        }
209
295
        return;
210
296
}
211
297
 
 
298
/* Callback from the message getting complete */
 
299
static void
 
300
verify_server_cb (SoupSession * session, SoupMessage * message, gpointer user_data)
 
301
{
 
302
        UccsServer * server = UCCS_SERVER(user_data);
 
303
        guint statuscode = 404;
 
304
 
 
305
        g_object_get(G_OBJECT(message), SOUP_MESSAGE_STATUS_CODE, &statuscode, NULL);
 
306
        g_debug("Verification came back with status: %d", statuscode);
 
307
 
 
308
        if (statuscode == 200) {
 
309
                server->verified_server = TRUE;
 
310
        } else {
 
311
                server->verified_server = FALSE;
 
312
        }
 
313
 
 
314
        evaluate_state(server);
 
315
 
 
316
        return;
 
317
}
 
318
 
 
319
/* Set up the process to verify the server */
 
320
static void
 
321
verify_server (UccsServer * server)
 
322
{
 
323
        g_return_if_fail(server->session != NULL);
 
324
 
 
325
        if (server->parent.uri == NULL) {
 
326
                return;
 
327
        }
 
328
 
 
329
        SoupMessage * message = soup_message_new("HEAD", server->parent.uri);
 
330
        soup_session_queue_message(server->session, message, verify_server_cb, server);
 
331
        g_debug("Getting HEAD from: %s", server->parent.uri);
 
332
 
 
333
        return;
 
334
}
 
335
 
 
336
/* Callback for when the Network Manger state changes */
 
337
static void
 
338
nm_state_changed (NMClient *client, const GParamSpec *pspec, gpointer user_data)
 
339
{
 
340
        g_return_if_fail(IS_UCCS_SERVER(user_data));
 
341
        UccsServer * server = UCCS_SERVER(user_data);
 
342
 
 
343
        if (server->nm_client == NULL || !nm_client_get_manager_running(server->nm_client)) {
 
344
                server->last_network = NM_STATE_DISCONNECTED;
 
345
        } else {
 
346
                server->last_network = nm_client_get_state(server->nm_client);
 
347
        }
 
348
 
 
349
        if (server->last_network == NM_STATE_DISCONNECTED) {
 
350
                server->verified_server = FALSE;
 
351
                soup_session_abort(server->session);
 
352
        }
 
353
 
 
354
        if (server->last_network == NM_STATE_CONNECTED_GLOBAL && server->verify_server && !server->verified_server) {
 
355
                verify_server(server);
 
356
        }
 
357
 
 
358
        evaluate_state(server);
 
359
 
 
360
        return;
 
361
}
 
362
 
 
363
/* Get the properties that can be sent by the greeter for this server */
212
364
static GVariant *
213
365
get_properties (Server * server)
214
366
{
234
386
        return g_variant_builder_end(&propbuilder);
235
387
}
236
388
 
 
389
/* Set the exec value for the server */
 
390
const gchar *
 
391
uccs_server_set_exec (UccsServer * server, const gchar * exec)
 
392
{
 
393
        g_return_val_if_fail(IS_UCCS_SERVER(server), NULL);
 
394
 
 
395
        g_clear_pointer(&server->exec, g_free);
 
396
 
 
397
        if (exec != NULL) {
 
398
                server->exec = g_find_program_in_path(exec);
 
399
        }
 
400
 
 
401
        evaluate_state(server);
 
402
 
 
403
        return server->exec;
 
404
}
 
405
 
 
406
/* Build a new uccs server from a keyfile and a group in it */
237
407
Server *
238
 
uccs_server_new_from_keyfile (GKeyFile * keyfile, const gchar * name)
 
408
uccs_server_new_from_keyfile (GKeyFile * keyfile, const gchar * groupname)
239
409
{
240
410
        g_return_val_if_fail(keyfile != NULL, NULL); /* NOTE: No way to check if that's really a keyfile :-( */
241
 
        g_return_val_if_fail(name != NULL, NULL);
242
 
 
243
 
        gchar * groupname = g_strdup_printf("%s %s", CONFIG_UCCS_PREFIX, name);
 
411
        g_return_val_if_fail(groupname != NULL, NULL);
244
412
 
245
413
        if (!g_key_file_has_group(keyfile, groupname)) {
246
 
                g_warning("Server '%s' specified but group '%s' was not found", name, groupname);
247
 
                g_free(groupname);
 
414
                g_warning("Server specified but group '%s' was not found", groupname);
248
415
                return NULL;
249
416
        }
250
417
 
251
418
        UccsServer * server = g_object_new(UCCS_SERVER_TYPE, NULL);
252
419
 
253
 
        if (g_key_file_has_key(keyfile, groupname, "Name", NULL)) {
254
 
                server->parent.name = g_key_file_get_string(keyfile, groupname, CONFIG_SERVER_NAME, NULL);
 
420
        if (g_key_file_has_key(keyfile, groupname, CONFIG_SERVER_NAME, NULL)) {
 
421
                gchar * keyname = g_key_file_get_string(keyfile, groupname, CONFIG_SERVER_NAME, NULL);
 
422
                server->parent.name = g_strdup(_(keyname));
 
423
                g_free(keyname);
255
424
        }
256
425
 
257
 
        if (g_key_file_has_key(keyfile, groupname, "URI", NULL)) {
 
426
        if (g_key_file_has_key(keyfile, groupname, CONFIG_SERVER_URI, NULL)) {
258
427
                server->parent.uri = g_key_file_get_string(keyfile, groupname, CONFIG_SERVER_URI, NULL);
259
428
        }
260
429
 
261
430
        if (g_key_file_has_key(keyfile, groupname, CONFIG_UCCS_EXEC, NULL)) {
262
 
                g_free(server->exec);
263
431
                gchar * key = g_key_file_get_string(keyfile, groupname, CONFIG_UCCS_EXEC, NULL);
264
 
                server->exec = g_find_program_in_path(key);
265
 
                g_free(key);
266
 
        }
267
 
 
268
 
        g_free(groupname);
 
432
                uccs_server_set_exec(server, key);
 
433
                g_free(key);
 
434
        }
 
435
 
 
436
        if (g_key_file_has_key(keyfile, groupname, CONFIG_UCCS_NETWORK, NULL)) {
 
437
                gchar * key = g_key_file_get_string(keyfile, groupname, CONFIG_UCCS_NETWORK, NULL);
 
438
 
 
439
                if (g_strcmp0(key, CONFIG_UCCS_NETWORK_NONE) == 0) {
 
440
                        server->min_network = NM_STATE_DISCONNECTED;
 
441
                } else if (g_strcmp0(key, CONFIG_UCCS_NETWORK_GLOBAL) == 0) {
 
442
                        server->min_network = NM_STATE_CONNECTED_GLOBAL;
 
443
                }
 
444
                /* NOTE: There is a possibility for other network types to be added here,
 
445
                   but they can be tricky to test.  Feel free to patch it, but please include
 
446
                   those tests :-) */
 
447
 
 
448
                g_free(key);
 
449
        }
 
450
 
 
451
        if (g_key_file_has_key(keyfile, groupname, CONFIG_UCCS_VERIFY, NULL)) {
 
452
                server->verify_server = g_key_file_get_boolean(keyfile, groupname, CONFIG_UCCS_VERIFY, NULL);
 
453
        }
 
454
 
 
455
        evaluate_state(server);
 
456
 
269
457
        return SERVER(server);
270
458
}
271
459
 
283
471
                }
284
472
 
285
473
                JsonObject * object = json_node_get_object(node);
286
 
                if (!json_object_has_member(object, "Protocol")) {
287
 
                        continue;
288
 
                }
289
 
 
290
 
                JsonNode * proto_node = json_object_get_member(object, "Protocol");
291
 
                if (JSON_NODE_TYPE(proto_node) != JSON_NODE_VALUE) {
292
 
                        continue;
293
 
                }
294
 
                if (json_node_get_value_type(proto_node) != G_TYPE_STRING) {
295
 
                        continue;
296
 
                }
297
 
 
298
 
                const gchar * proto = json_node_get_string(proto_node);
299
 
                Server * newserver = NULL;
300
 
 
301
 
                if (g_strcmp0(proto, "ICA") == 0 || g_strcmp0(proto, "ica") == 0) {
302
 
                        newserver = citrix_server_new_from_json(object);
303
 
                }
304
 
                else if (g_strcmp0(proto, "freerdp") == 0 || g_strcmp0(proto, "rdp") == 0 || g_strcmp0(proto, "RDP") == 0 || g_strcmp0(proto, "FreeRDP") == 0) {
305
 
                        newserver = rdp_server_new_from_json(object);
306
 
                }
307
 
 
308
 
                if (newserver == NULL) continue;
309
 
 
310
 
                server->subservers = g_list_append(server->subservers, newserver);
 
474
                Server * newserver = server_new_from_json(object);
 
475
                if (newserver != NULL) {
 
476
                        server->subservers = g_list_append(server->subservers, newserver);
 
477
                }
311
478
        }
312
479
 
313
480
        return TRUE;
317
484
static gboolean
318
485
parse_json (UccsServer * server, GInputStream * json)
319
486
{
320
 
        if (json == NULL) return; /* Shouldn't happen, but let's just handle it */
 
487
        if (json == NULL) return FALSE; /* Shouldn't happen, but let's just handle it */
321
488
 
322
489
        gboolean passed = TRUE;
323
490
        JsonParser * parser = json_parser_new();
366
533
                        g_warning("Malformed 'RemoteDesktopServer' entry.  Not an array but a: %s", json_node_type_name(rds_node));
367
534
                        passed = FALSE;
368
535
                }
 
536
                
 
537
                if (json_object_has_member(root_object, "DefaultServer")) {
 
538
                        JsonNode * ds_node = json_object_get_member(root_object, "DefaultServer");
 
539
                        if (JSON_NODE_TYPE(ds_node) == JSON_NODE_VALUE && json_node_get_value_type(ds_node) == G_TYPE_STRING) {
 
540
                                const gchar * default_server_name = json_node_get_string(ds_node);
 
541
                                if (default_server_name != NULL) {
 
542
                                        GList * lserver;
 
543
                                        for (lserver = server->subservers; lserver != NULL; lserver = g_list_next(lserver)) {
 
544
                                                Server * serv = SERVER(lserver->data);
 
545
                                                
 
546
                                                if (g_strcmp0(serv->name, default_server_name) == 0) {
 
547
                                                        serv->last_used = TRUE;
 
548
                                                        break;
 
549
                                                }
 
550
                                        }
 
551
                                        if (lserver == NULL && strlen(default_server_name) > 0) {
 
552
                                                g_warning("Could not find the 'DefaultServer' server.");
 
553
                                                passed = FALSE;
 
554
                                        }
 
555
                                }
 
556
                        } else {
 
557
                                g_warning("Malformed 'DefaultServer' entry.  Not a string value");
 
558
                                passed = FALSE;
 
559
                        }
 
560
                }
369
561
        } else {
370
562
                g_debug("No 'RemoteDesktopServers' found");
371
563
        }
469
661
 * @address: DBus address of the person unlocking us
470
662
 * @username: Username for the UCCS
471
663
 * @password: (allow-none) Password to use
 
664
 * @allowcache: If using cache is allowed
472
665
 * @callback: Function to call when we have an answer
473
666
 * @user_data: Data for the callback
474
667
 *
476
669
 * cache or from the network.
477
670
 */
478
671
void
479
 
uccs_server_unlock (UccsServer * server, const gchar * address, const gchar * username, const gchar * password, void (*callback) (UccsServer * server, gboolean unlocked, gpointer user_data), gpointer user_data)
 
672
uccs_server_unlock (UccsServer * server, const gchar * address, const gchar * username, const gchar * password, gboolean allowcache, void (*callback) (UccsServer * server, gboolean unlocked, gpointer user_data), gpointer user_data)
480
673
{
481
674
        g_return_if_fail(IS_UCCS_SERVER(server));
482
675
        g_return_if_fail(username != NULL);
484
677
 
485
678
        /* Check the current values we have, they might be NULL, which in
486
679
           that case they won't match */
487
 
        if (g_strcmp0(username, server->username) == 0 &&
 
680
        if (allowcache && g_strcmp0(username, server->username) == 0 &&
488
681
                        g_strcmp0(password, server->password) == 0) {
489
682
                g_hash_table_insert(server->lovers, g_strdup(address), GINT_TO_POINTER(TRUE));
490
683
 
495
688
                return;
496
689
        }
497
690
 
498
 
        if (server->username != NULL && (server->password != NULL || password == NULL)) {
499
 
                /* We've got stored values, but those weren't them */
500
 
 
501
 
                if (callback != NULL) {
502
 
                        callback(server, FALSE, user_data);
503
 
                }
504
 
 
505
 
                return;
506
 
        }
507
 
 
508
691
        g_return_if_fail(server->exec != NULL); /* Shouldn't happen, but I'd feel safer if we checked */
509
692
 
 
693
        /* If we're not going to allow the cache, just clear it right away */
 
694
        if (!allowcache) {
 
695
                clear_hash(server);
 
696
        }
 
697
 
510
698
        /* We're changing the username and password, if there were other
511
699
           people who had it, they need to know we're different now */
512
 
        clear_hash(server);
513
 
        server->username = g_strdup(username);
514
 
        server->password = g_strdup(password);
 
700
        if (g_strcmp0(username, server->username) != 0 ||
 
701
                        g_strcmp0(password, server->password) != 0) {
 
702
                clear_hash(server);
 
703
                clear_json(server);
 
704
 
 
705
                g_clear_pointer(&server->username, g_free);
 
706
                g_clear_pointer(&server->password, g_free);
 
707
 
 
708
                server->username = g_strdup(username);
 
709
                server->password = g_strdup(password);
 
710
        }
515
711
 
516
712
        /* Add ourselves to the queue */
517
713
        json_callback_t * json_callback = g_new0(json_callback_t, 1);
597
793
                return null_server_array();
598
794
        }
599
795
 
600
 
        if (g_list_length(server->subservers) == 0) {
601
 
                return null_server_array();
602
 
        }
603
 
 
604
796
        GVariantBuilder array;
605
797
        g_variant_builder_init(&array, G_VARIANT_TYPE_ARRAY);
606
798
        GList * lserver;
 
799
        gint servercnt = 0;
607
800
        for (lserver = server->subservers; lserver != NULL; lserver = g_list_next(lserver)) {
608
801
                Server * serv = SERVER(lserver->data);
 
802
 
 
803
                /* We only want servers that are all good */
 
804
                if (serv->state != SERVER_STATE_ALLGOOD) {
 
805
                        continue;
 
806
                }
 
807
 
 
808
                servercnt++;
609
809
                g_variant_builder_add_value(&array, server_get_variant(serv));
610
810
        }
611
811
 
 
812
        if (servercnt == 0) {
 
813
                g_variant_builder_clear(&array);
 
814
                return null_server_array();
 
815
        }
 
816
 
612
817
        return g_variant_builder_end(&array);
613
818
}
614
819