1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2007 Novell, Inc.
4  * Copyright (C) 2008 Red Hat, Inc.
5  * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "config.h"
23 
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <string.h>
32 
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <glib-object.h>
36 
37 #include <X11/ICE/ICElib.h>
38 #include <X11/ICE/ICEutil.h>
39 #include <X11/ICE/ICEconn.h>
40 #include <X11/SM/SMlib.h>
41 
42 /* Get the proto for _IceTransNoListen */
43 #define ICE_t
44 #define TRANS_SERVER
45 #include <X11/Xtrans/Xtrans.h>
46 #undef  ICE_t
47 #undef TRANS_SERVER
48 
49 #include "gsm-xsmp-server.h"
50 #include "gsm-xsmp-client.h"
51 #include "gsm-util.h"
52 
53 /* ICEauthority stuff */
54 /* Various magic numbers stolen from iceauth.c */
55 #define GSM_ICE_AUTH_RETRIES      10
56 #define GSM_ICE_AUTH_INTERVAL     2   /* 2 seconds */
57 #define GSM_ICE_AUTH_LOCK_TIMEOUT 600 /* 10 minutes */
58 
59 #define GSM_ICE_MAGIC_COOKIE_AUTH_NAME "MIT-MAGIC-COOKIE-1"
60 #define GSM_ICE_MAGIC_COOKIE_LEN       16
61 
62 #define GSM_XSMP_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_XSMP_SERVER, GsmXsmpServerPrivate))
63 
64 struct GsmXsmpServerPrivate
65 {
66         GsmStore       *client_store;
67 
68         IceListenObj   *xsmp_sockets;
69         int             num_xsmp_sockets;
70         int             num_local_xsmp_sockets;
71         gboolean        stopping;
72 };
73 
74 enum {
75         PROP_0,
76         PROP_CLIENT_STORE
77 };
78 
79 static void     gsm_xsmp_server_class_init  (GsmXsmpServerClass *klass);
80 static void     gsm_xsmp_server_init        (GsmXsmpServer      *xsmp_server);
81 static void     gsm_xsmp_server_finalize    (GObject         *object);
82 
83 static gpointer xsmp_server_object = NULL;
84 
85 G_DEFINE_TYPE (GsmXsmpServer, gsm_xsmp_server, G_TYPE_OBJECT)
86 
87 typedef struct {
88         GsmXsmpServer *server;
89         IceListenObj   listener;
90 } GsmIceConnectionData;
91 
92 typedef struct {
93         guint watch_id;
94         guint protocol_timeout;
95 } GsmIceConnectionWatch;
96 
97 static void
disconnect_ice_connection(IceConn ice_conn)98 disconnect_ice_connection (IceConn ice_conn)
99 {
100         IceSetShutdownNegotiation (ice_conn, FALSE);
101         IceCloseConnection (ice_conn);
102 }
103 
104 static void
free_ice_connection_watch(GsmIceConnectionWatch * data)105 free_ice_connection_watch (GsmIceConnectionWatch *data)
106 {
107         if (data->watch_id) {
108                 g_source_remove (data->watch_id);
109                 data->watch_id = 0;
110         }
111 
112         if (data->protocol_timeout) {
113                 g_source_remove (data->protocol_timeout);
114                 data->protocol_timeout = 0;
115         }
116 
117         g_free (data);
118 }
119 
120 static gboolean
ice_protocol_timeout(IceConn ice_conn)121 ice_protocol_timeout (IceConn ice_conn)
122 {
123         GsmIceConnectionWatch *data;
124 
125         g_debug ("GsmXsmpServer: ice_protocol_timeout for IceConn %p with status %d",
126                  ice_conn, IceConnectionStatus (ice_conn));
127 
128         data = ice_conn->context;
129 
130         free_ice_connection_watch (data);
131         disconnect_ice_connection (ice_conn);
132 
133         return FALSE;
134 }
135 
136 static gboolean
auth_iochannel_watch(GIOChannel * source,GIOCondition condition,IceConn ice_conn)137 auth_iochannel_watch (GIOChannel   *source,
138                       GIOCondition  condition,
139                       IceConn       ice_conn)
140 {
141 
142         GsmIceConnectionWatch *data;
143         gboolean               keep_going;
144 
145         data = ice_conn->context;
146 
147         switch (IceProcessMessages (ice_conn, NULL, NULL)) {
148         case IceProcessMessagesSuccess:
149                 keep_going = TRUE;
150                 break;
151         case IceProcessMessagesIOError:
152                 g_debug ("GsmXsmpServer: IceProcessMessages returned IceProcessMessagesIOError");
153                 free_ice_connection_watch (data);
154                 disconnect_ice_connection (ice_conn);
155                 keep_going = FALSE;
156                 break;
157         case IceProcessMessagesConnectionClosed:
158                 g_debug ("GsmXsmpServer: IceProcessMessages returned IceProcessMessagesConnectionClosed");
159                 free_ice_connection_watch (data);
160                 keep_going = FALSE;
161                 break;
162         default:
163                 g_assert_not_reached ();
164         }
165 
166         return keep_going;
167 }
168 
169 /* IceAcceptConnection returns a new ICE connection that is in a "pending" state,
170  * this is because authentification may be necessary.
171  * So we've to authenticate it, before accept_xsmp_connection() is called.
172  * Then each GsmXSMPClient will have its own IceConn watcher
173  */
174 static void
auth_ice_connection(IceConn ice_conn)175 auth_ice_connection (IceConn ice_conn)
176 {
177         GIOChannel            *channel;
178         GsmIceConnectionWatch *data;
179         int                    fd;
180 
181         g_debug ("GsmXsmpServer: auth_ice_connection()");
182 
183         fd = IceConnectionNumber (ice_conn);
184         fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
185         channel = g_io_channel_unix_new (fd);
186 
187         data = g_new0 (GsmIceConnectionWatch, 1);
188         ice_conn->context = data;
189 
190         data->protocol_timeout = g_timeout_add_seconds (5,
191                                                         (GSourceFunc)ice_protocol_timeout,
192                                                         ice_conn);
193         data->watch_id = g_io_add_watch (channel,
194                                          G_IO_IN | G_IO_ERR,
195                                          (GIOFunc)auth_iochannel_watch,
196                                          ice_conn);
197         g_io_channel_unref (channel);
198 }
199 
200 /* This is called (by glib via xsmp->ice_connection_watch) when a
201  * connection is first received on the ICE listening socket.
202  */
203 static gboolean
accept_ice_connection(GIOChannel * source,GIOCondition condition,GsmIceConnectionData * data)204 accept_ice_connection (GIOChannel           *source,
205                        GIOCondition          condition,
206                        GsmIceConnectionData *data)
207 {
208         IceConn         ice_conn;
209         IceAcceptStatus status;
210 
211         g_debug ("GsmXsmpServer: accept_ice_connection()");
212 
213         ice_conn = IceAcceptConnection (data->listener, &status);
214         if (status != IceAcceptSuccess) {
215                 g_debug ("GsmXsmpServer: IceAcceptConnection returned %d", status);
216                 return TRUE;
217         }
218 
219         auth_ice_connection (ice_conn);
220 
221         return TRUE;
222 }
223 
224 void
gsm_xsmp_server_start(GsmXsmpServer * server)225 gsm_xsmp_server_start (GsmXsmpServer *server)
226 {
227         GIOChannel *channel;
228         int         i;
229 
230         for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
231                 GsmIceConnectionData *data;
232 
233                 data = g_new0 (GsmIceConnectionData, 1);
234                 data->server = server;
235                 data->listener = server->priv->xsmp_sockets[i];
236 
237                 channel = g_io_channel_unix_new (IceGetListenConnectionNumber (server->priv->xsmp_sockets[i]));
238                 g_io_add_watch_full (channel,
239                                      G_PRIORITY_DEFAULT,
240                                      G_IO_IN | G_IO_HUP | G_IO_ERR,
241                                      (GIOFunc)accept_ice_connection,
242                                      data,
243                                      (GDestroyNotify)g_free);
244                 g_io_channel_unref (channel);
245         }
246 }
247 
248 void
gsm_xsmp_server_stop_accepting_new_clients(GsmXsmpServer * server)249 gsm_xsmp_server_stop_accepting_new_clients (GsmXsmpServer *server)
250 {
251         g_return_if_fail (GSM_IS_XSMP_SERVER (server));
252         g_debug ("gsm_xsmp_server_stop_accepting_new_clients");
253         server->priv->stopping = TRUE;
254 }
255 
256 void
gsm_xsmp_server_start_accepting_new_clients(GsmXsmpServer * server)257 gsm_xsmp_server_start_accepting_new_clients (GsmXsmpServer *server)
258 {
259         g_return_if_fail (GSM_IS_XSMP_SERVER (server));
260         g_debug ("gsm_xsmp_server_start");
261         server->priv->stopping = FALSE;
262 }
263 
264 static void
gsm_xsmp_server_set_client_store(GsmXsmpServer * xsmp_server,GsmStore * store)265 gsm_xsmp_server_set_client_store (GsmXsmpServer *xsmp_server,
266                                   GsmStore      *store)
267 {
268         g_return_if_fail (GSM_IS_XSMP_SERVER (xsmp_server));
269 
270         if (store != NULL) {
271                 g_object_ref (store);
272         }
273 
274         if (xsmp_server->priv->client_store != NULL) {
275                 g_object_unref (xsmp_server->priv->client_store);
276         }
277 
278         xsmp_server->priv->client_store = store;
279 }
280 
281 static void
gsm_xsmp_server_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)282 gsm_xsmp_server_set_property (GObject      *object,
283                               guint         prop_id,
284                               const GValue *value,
285                               GParamSpec   *pspec)
286 {
287         GsmXsmpServer *self;
288 
289         self = GSM_XSMP_SERVER (object);
290 
291         switch (prop_id) {
292         case PROP_CLIENT_STORE:
293                 gsm_xsmp_server_set_client_store (self, g_value_get_object (value));
294                 break;
295          default:
296                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
297                 break;
298         }
299 }
300 
301 static void
gsm_xsmp_server_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)302 gsm_xsmp_server_get_property (GObject    *object,
303                               guint       prop_id,
304                               GValue     *value,
305                               GParamSpec *pspec)
306 {
307         GsmXsmpServer *self;
308 
309         self = GSM_XSMP_SERVER (object);
310 
311         switch (prop_id) {
312         case PROP_CLIENT_STORE:
313                 g_value_set_object (value, self->priv->client_store);
314                 break;
315         default:
316                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
317                 break;
318         }
319 }
320 
321 /* This is called (by libSM) when XSMP is initiated on an ICE
322  * connection that was already accepted by accept_ice_connection.
323  */
324 static Status
accept_xsmp_connection(SmsConn sms_conn,GsmXsmpServer * server,unsigned long * mask_ret,SmsCallbacks * callbacks_ret,char ** failure_reason_ret)325 accept_xsmp_connection (SmsConn        sms_conn,
326                         GsmXsmpServer *server,
327                         unsigned long *mask_ret,
328                         SmsCallbacks  *callbacks_ret,
329                         char         **failure_reason_ret)
330 {
331         IceConn                ice_conn;
332         GsmClient             *client;
333         GsmIceConnectionWatch *data;
334 
335         if (server->priv->stopping) {
336                 g_debug ("GsmXsmpServer: In shutdown, rejecting new client");
337 
338                 *failure_reason_ret = strdup (_("Refusing new client connection because the session is currently being shut down\n"));
339                 return FALSE;
340         }
341 
342         ice_conn = SmsGetIceConnection (sms_conn);
343         data = ice_conn->context;
344 
345         /* Each GsmXSMPClient has its own IceConn watcher */
346         free_ice_connection_watch (data);
347 
348         client = gsm_xsmp_client_new (ice_conn);
349 
350         gsm_store_add (server->priv->client_store, gsm_client_peek_id (client), G_OBJECT (client));
351         /* the store will own the ref */
352         g_object_unref (client);
353 
354         gsm_xsmp_client_connect (GSM_XSMP_CLIENT (client), sms_conn, mask_ret, callbacks_ret);
355 
356         return TRUE;
357 }
358 
359 static void
ice_error_handler(IceConn conn,Bool swap,int offending_minor_opcode,unsigned long offending_sequence,int error_class,int severity,IcePointer values)360 ice_error_handler (IceConn       conn,
361                    Bool          swap,
362                    int           offending_minor_opcode,
363                    unsigned long offending_sequence,
364                    int           error_class,
365                    int           severity,
366                    IcePointer    values)
367 {
368         g_debug ("GsmXsmpServer: ice_error_handler (%p, %s, %d, %lx, %d, %d)",
369                  conn, swap ? "TRUE" : "FALSE", offending_minor_opcode,
370                  offending_sequence, error_class, severity);
371 
372         if (severity == IceCanContinue) {
373                 return;
374         }
375 
376         /* FIXME: the ICElib docs are completely vague about what we're
377          * supposed to do in this case. Need to verify that calling
378          * IceCloseConnection() here is guaranteed to cause neither
379          * free-memory-reads nor leaks.
380          */
381         IceCloseConnection (conn);
382 }
383 
384 static void
ice_io_error_handler(IceConn conn)385 ice_io_error_handler (IceConn conn)
386 {
387         g_debug ("GsmXsmpServer: ice_io_error_handler (%p)", conn);
388 
389         /* We don't need to do anything here; the next call to
390          * IceProcessMessages() for this connection will receive
391          * IceProcessMessagesIOError and we can handle the error there.
392          */
393 }
394 
395 static void
sms_error_handler(SmsConn conn,Bool swap,int offending_minor_opcode,unsigned long offending_sequence_num,int error_class,int severity,IcePointer values)396 sms_error_handler (SmsConn       conn,
397                    Bool          swap,
398                    int           offending_minor_opcode,
399                    unsigned long offending_sequence_num,
400                    int           error_class,
401                    int           severity,
402                    IcePointer    values)
403 {
404         g_debug ("GsmXsmpServer: sms_error_handler (%p, %s, %d, %lx, %d, %d)",
405                  conn, swap ? "TRUE" : "FALSE", offending_minor_opcode,
406                  offending_sequence_num, error_class, severity);
407 
408         /* We don't need to do anything here; if the connection needs to be
409          * closed, libSM will do that itself.
410          */
411 }
412 
413 static IceAuthFileEntry *
auth_entry_new(const char * protocol,const char * network_id)414 auth_entry_new (const char *protocol,
415                 const char *network_id)
416 {
417         IceAuthFileEntry *file_entry;
418         IceAuthDataEntry  data_entry;
419 
420         file_entry = malloc (sizeof (IceAuthFileEntry));
421 
422         file_entry->protocol_name = strdup (protocol);
423         file_entry->protocol_data = NULL;
424         file_entry->protocol_data_length = 0;
425         file_entry->network_id = strdup (network_id);
426         file_entry->auth_name = strdup (GSM_ICE_MAGIC_COOKIE_AUTH_NAME);
427         file_entry->auth_data = IceGenerateMagicCookie (GSM_ICE_MAGIC_COOKIE_LEN);
428         file_entry->auth_data_length = GSM_ICE_MAGIC_COOKIE_LEN;
429 
430         /* Also create an in-memory copy, which is what the server will
431          * actually use for checking client auth.
432          */
433         data_entry.protocol_name = file_entry->protocol_name;
434         data_entry.network_id = file_entry->network_id;
435         data_entry.auth_name = file_entry->auth_name;
436         data_entry.auth_data = file_entry->auth_data;
437         data_entry.auth_data_length = file_entry->auth_data_length;
438         IceSetPaAuthData (1, &data_entry);
439 
440         return file_entry;
441 }
442 
443 static gboolean
update_iceauthority(GsmXsmpServer * server,gboolean adding)444 update_iceauthority (GsmXsmpServer *server,
445                      gboolean       adding)
446 {
447         char             *filename;
448         char            **our_network_ids;
449         FILE             *fp;
450         IceAuthFileEntry *auth_entry;
451         GSList           *entries;
452         GSList           *e;
453         int               i;
454         int               ret;
455         gboolean          ok = FALSE;
456 
457         filename = IceAuthFileName ();
458         do {
459                 ret = IceLockAuthFile (filename,
460                                        GSM_ICE_AUTH_RETRIES,
461                                        GSM_ICE_AUTH_INTERVAL,
462                                        GSM_ICE_AUTH_LOCK_TIMEOUT);
463 
464         } while (ret != IceAuthLockSuccess && errno == EINTR);
465 
466         if (ret != IceAuthLockSuccess) {
467                 g_warning ("IceLockAuthFile failed: %m");
468                 return FALSE;
469         }
470 
471         our_network_ids = g_malloc (server->priv->num_local_xsmp_sockets * sizeof (char *));
472         for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
473                 our_network_ids[i] = IceGetListenConnectionString (server->priv->xsmp_sockets[i]);
474         }
475 
476         entries = NULL;
477 
478         fp = fopen (filename, "r+");
479         if (fp != NULL) {
480                 while ((auth_entry = IceReadAuthFileEntry (fp)) != NULL) {
481                         /* Skip/delete entries with no network ID (invalid), or with
482                          * our network ID; if we're starting up, an entry with our
483                          * ID must be a stale entry left behind by an old process,
484                          * and if we're shutting down, it won't be valid in the
485                          * future, so either way we want to remove it from the list.
486                          */
487                         if (!auth_entry->network_id) {
488                                 IceFreeAuthFileEntry (auth_entry);
489                                 continue;
490                         }
491 
492                         for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
493                                 if (!strcmp (auth_entry->network_id, our_network_ids[i])) {
494                                         IceFreeAuthFileEntry (auth_entry);
495                                         break;
496                                 }
497                         }
498                         if (i != server->priv->num_local_xsmp_sockets) {
499                                 continue;
500                         }
501 
502                         entries = g_slist_prepend (entries, auth_entry);
503                 }
504 
505                 rewind (fp);
506         } else {
507                 int fd;
508 
509                 if (errno != ENOENT) {
510                         g_warning ("Unable to read ICE authority file %s: %m", filename);
511                         goto cleanup;
512                 }
513 
514                 fd = open (filename, O_CREAT | O_WRONLY, 0600);
515                 fp = fdopen (fd, "w");
516                 if (!fp) {
517                         g_warning ("Unable to write to ICE authority file: %s", filename);
518                         if (fd != -1) {
519                                 close (fd);
520                         }
521                         goto cleanup;
522                 }
523         }
524 
525         if (adding) {
526                 for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
527                         entries = g_slist_append (entries,
528                                                   auth_entry_new ("ICE", our_network_ids[i]));
529                         entries = g_slist_prepend (entries,
530                                                    auth_entry_new ("XSMP", our_network_ids[i]));
531                 }
532         }
533 
534         for (e = entries; e; e = e->next) {
535                 IceAuthFileEntry *auth_entry = e->data;
536                 IceWriteAuthFileEntry (fp, auth_entry);
537                 IceFreeAuthFileEntry (auth_entry);
538         }
539         g_slist_free (entries);
540 
541         fclose (fp);
542         ok = TRUE;
543 
544  cleanup:
545         IceUnlockAuthFile (filename);
546         for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
547                 free (our_network_ids[i]);
548         }
549         g_free (our_network_ids);
550 
551         return ok;
552 }
553 
554 
555 static void
setup_listener(GsmXsmpServer * server)556 setup_listener (GsmXsmpServer *server)
557 {
558         char   error[256];
559         mode_t saved_umask;
560         char  *network_id_list;
561         int    i;
562         int    res;
563 
564         /* Set up sane error handlers */
565         IceSetErrorHandler (ice_error_handler);
566         IceSetIOErrorHandler (ice_io_error_handler);
567         SmsSetErrorHandler (sms_error_handler);
568 
569         /* Initialize libSM; we pass NULL for hostBasedAuthProc to disable
570          * host-based authentication.
571          */
572         res = SmsInitialize (PACKAGE,
573                              VERSION,
574                              (SmsNewClientProc)accept_xsmp_connection,
575                              server,
576                              NULL,
577                              sizeof (error),
578                              error);
579         if (! res) {
580                 gsm_util_init_error (TRUE, "Could not initialize libSM: %s", error);
581         }
582 
583         /* By default, IceListenForConnections will open one socket for each
584          * transport type known to X. We don't want connections from remote
585          * hosts, so for security reasons it would be best if ICE didn't
586          * even open any non-local sockets. So we use an internal ICElib
587          * method to disable them here. Unfortunately, there is no way to
588          * ask X what transport types it knows about, so we're forced to
589          * guess.
590          */
591         _IceTransNoListen ("tcp");
592 
593         /* Create the XSMP socket. Older versions of IceListenForConnections
594          * have a bug which causes the umask to be set to 0 on certain types
595          * of failures. Probably not an issue on any modern systems, but
596          * we'll play it safe.
597          */
598         saved_umask = umask (0);
599         umask (saved_umask);
600         res = IceListenForConnections (&server->priv->num_xsmp_sockets,
601                                        &server->priv->xsmp_sockets,
602                                        sizeof (error),
603                                        error);
604         if (! res) {
605                 gsm_util_init_error (TRUE, _("Could not create ICE listening socket: %s"), error);
606         }
607 
608         umask (saved_umask);
609 
610         /* Find the local sockets in the returned socket list and move them
611          * to the start of the list.
612          */
613         for (i = server->priv->num_local_xsmp_sockets = 0; i < server->priv->num_xsmp_sockets; i++) {
614                 char *id = IceGetListenConnectionString (server->priv->xsmp_sockets[i]);
615 
616                 if (!strncmp (id, "local/", sizeof ("local/") - 1) ||
617                     !strncmp (id, "unix/", sizeof ("unix/") - 1)) {
618                         if (i > server->priv->num_local_xsmp_sockets) {
619                                 IceListenObj tmp;
620                                 tmp = server->priv->xsmp_sockets[i];
621                                 server->priv->xsmp_sockets[i] = server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets];
622                                 server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets] = tmp;
623                         }
624                         server->priv->num_local_xsmp_sockets++;
625                 }
626                 free (id);
627         }
628 
629         if (server->priv->num_local_xsmp_sockets == 0) {
630                 gsm_util_init_error (TRUE, "IceListenForConnections did not return a local listener!");
631         }
632 
633         if (server->priv->num_local_xsmp_sockets != server->priv->num_xsmp_sockets) {
634                 /* Xtrans was apparently compiled with support for some
635                  * non-local transport besides TCP (which we disabled above); we
636                  * won't create IO watches on those extra sockets, so
637                  * connections to them will never be noticed, but they're still
638                  * there, which is inelegant.
639                  *
640                  * If the g_warning below is triggering for you and you want to
641                  * stop it, the fix is to add additional _IceTransNoListen()
642                  * calls above.
643                  */
644                 network_id_list = IceComposeNetworkIdList (server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets,
645                                                            server->priv->xsmp_sockets + server->priv->num_local_xsmp_sockets);
646                 g_warning ("IceListenForConnections returned %d non-local listeners: %s",
647                            server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets,
648                            network_id_list);
649                 free (network_id_list);
650         }
651 
652         /* Update .ICEauthority with new auth entries for our socket */
653         if (!update_iceauthority (server, TRUE)) {
654                 /* FIXME: is this really fatal? Hm... */
655                 gsm_util_init_error (TRUE,
656                                      "Could not update ICEauthority file %s",
657                                      IceAuthFileName ());
658         }
659 
660         network_id_list = IceComposeNetworkIdList (server->priv->num_local_xsmp_sockets,
661                                                    server->priv->xsmp_sockets);
662 
663         gsm_util_setenv ("SESSION_MANAGER", network_id_list);
664         g_debug ("GsmXsmpServer: SESSION_MANAGER=%s\n", network_id_list);
665         free (network_id_list);
666 }
667 
668 static GObject *
gsm_xsmp_server_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)669 gsm_xsmp_server_constructor (GType                  type,
670                              guint                  n_construct_properties,
671                              GObjectConstructParam *construct_properties)
672 {
673         GsmXsmpServer *xsmp_server;
674 
675         xsmp_server = GSM_XSMP_SERVER (G_OBJECT_CLASS (gsm_xsmp_server_parent_class)->constructor (type,
676                                                                                        n_construct_properties,
677                                                                                        construct_properties));
678         setup_listener (xsmp_server);
679 
680         return G_OBJECT (xsmp_server);
681 }
682 
683 static void
gsm_xsmp_server_class_init(GsmXsmpServerClass * klass)684 gsm_xsmp_server_class_init (GsmXsmpServerClass *klass)
685 {
686         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
687 
688         object_class->get_property = gsm_xsmp_server_get_property;
689         object_class->set_property = gsm_xsmp_server_set_property;
690         object_class->constructor = gsm_xsmp_server_constructor;
691         object_class->finalize = gsm_xsmp_server_finalize;
692 
693         g_object_class_install_property (object_class,
694                                          PROP_CLIENT_STORE,
695                                          g_param_spec_object ("client-store",
696                                                               NULL,
697                                                               NULL,
698                                                               GSM_TYPE_STORE,
699                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
700 
701         g_type_class_add_private (klass, sizeof (GsmXsmpServerPrivate));
702 }
703 
704 static void
gsm_xsmp_server_init(GsmXsmpServer * xsmp_server)705 gsm_xsmp_server_init (GsmXsmpServer *xsmp_server)
706 {
707         xsmp_server->priv = GSM_XSMP_SERVER_GET_PRIVATE (xsmp_server);
708 
709 }
710 
711 static void
gsm_xsmp_server_finalize(GObject * object)712 gsm_xsmp_server_finalize (GObject *object)
713 {
714         GsmXsmpServer *xsmp_server;
715 
716         g_return_if_fail (object != NULL);
717         g_return_if_fail (GSM_IS_XSMP_SERVER (object));
718 
719         xsmp_server = GSM_XSMP_SERVER (object);
720 
721         g_return_if_fail (xsmp_server->priv != NULL);
722 
723         IceFreeListenObjs (xsmp_server->priv->num_xsmp_sockets,
724                            xsmp_server->priv->xsmp_sockets);
725 
726         if (xsmp_server->priv->client_store != NULL) {
727                 g_object_unref (xsmp_server->priv->client_store);
728         }
729 
730         G_OBJECT_CLASS (gsm_xsmp_server_parent_class)->finalize (object);
731 }
732 
733 GsmXsmpServer *
gsm_xsmp_server_new(GsmStore * client_store)734 gsm_xsmp_server_new (GsmStore *client_store)
735 {
736         if (xsmp_server_object != NULL) {
737                 g_object_ref (xsmp_server_object);
738         } else {
739                 xsmp_server_object = g_object_new (GSM_TYPE_XSMP_SERVER,
740                                                    "client-store", client_store,
741                                                    NULL);
742 
743                 g_object_add_weak_pointer (xsmp_server_object,
744                                            (gpointer *) &xsmp_server_object);
745         }
746 
747         return GSM_XSMP_SERVER (xsmp_server_object);
748 }
749