Commit message: [gsm] Delay the creation of the GsmXSMPClient until it really exists

We used to create the GsmXSMPClient before the XSMP connection is really
accepted. This can lead to some issues, though. An example is:
https://bugzilla.gnome.org/show_bug.cgi?id=598211#c19. Quoting:

 "What is happening is that a new client (probably metacity in your
 case) is opening an ICE connection in the GSM_MANAGER_PHASE_END_SESSION
 phase, which causes a new GsmXSMPClient to be added to the client
 store. The GSM_MANAGER_PHASE_EXIT phase then begins before the client
 has had a chance to establish a xsmp connection, which means that
 client->priv->conn will not be initialized at the point that xsmp_stop
 is called on the new unregistered client."

The fix is to create the GsmXSMPClient object when there's a real XSMP
connection. This implies moving the timeout that makes sure we don't
have an empty client to the XSMP server.

https://bugzilla.gnome.org/show_bug.cgi?id=598211
CVE: CVE-2017-11171
CWE: CWE-835
Vulnerability description: Bad reference counting in the context of accept_ice_connection() in gsm-xsmp-server.c in old versions of gnome-session up until version 2.29.92 allows a local attacker to establish ICE connections to gnome-session with invalid authentication data (an invalid magic cookie). Each failed authentication attempt will leak a file descriptor in gnome-session. When the maximum number of file descriptors is exhausted in the gnome-session process, it will enter an infinite loop trying to communicate without success, consuming 100% of the CPU. The graphical session associated with the gnome-session process will stop working correctly, because communication with gnome-session is no longer possible.

Project: gnome-session
File: gsm-xsmp-client.c

_parse_value_as_uint (const char *value,
                      guint      *uintval)
{
        char  *end_of_valid_uint;
        gulong ulong_value;
        guint  uint_value;

        errno = 0;
        ulong_value = strtoul (value, &end_of_valid_uint, 10);

        if (*value == '\0' || *end_of_valid_uint != '\0') {
                return FALSE;
        }

        uint_value = ulong_value;
        if (uint_value != ulong_value || errno == ERANGE) {
                return FALSE;
        }

        *uintval = uint_value;

        return TRUE;
}

Project: gnome-session
File: gsm-xsmp-client.c

client_iochannel_watch (GIOChannel    *channel,
                        GIOCondition   condition,
                        GsmXSMPClient *client)
{
        gboolean keep_going;

        g_object_ref (client);
        switch (IceProcessMessages (client->priv->ice_connection, NULL, NULL)) {
        case IceProcessMessagesSuccess:
                keep_going = TRUE;
                break;

        case IceProcessMessagesIOError:
                g_debug ("GsmXSMPClient: IceProcessMessagesIOError on '%s'", client->priv->description);
                gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FAILED);
                /* Emitting "disconnected" will eventually cause
                 * IceCloseConnection() to be called.
                 */
                gsm_client_disconnected (GSM_CLIENT (client));
                keep_going = FALSE;
                break;

        case IceProcessMessagesConnectionClosed:
                g_debug ("GsmXSMPClient: IceProcessMessagesConnectionClosed on '%s'",
                         client->priv->description);
                client->priv->ice_connection = NULL;
                keep_going = FALSE;
                break;

        default:
                g_assert_not_reached ();
        }
        g_object_unref (client);

         return keep_going;
 }

Project: gnome-session
File: gsm-xsmp-client.c

close_connection_callback (SmsConn     conn,
                           SmPointer   manager_data,
                           int         count,
                           char      **reason_msgs)
{
        GsmXSMPClient *client = manager_data;
        int            i;

        g_debug ("GsmXSMPClient: Client '%s' received CloseConnection", client->priv->description);
        for (i = 0; i < count; i++) {
                g_debug ("GsmXSMPClient:  close reason: '%s'", reason_msgs[i]);
        }
        SmFreeReasons (count, reason_msgs);

        gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FINISHED);
        gsm_client_disconnected (GSM_CLIENT (client));
}

Project: gnome-session
File: gsm-xsmp-client.c

create_client_key_file (GsmClient   *client,
                        const char  *desktop_file_path,
                        GError     **error) {
        GKeyFile *keyfile;

        keyfile = g_key_file_new ();

        if (desktop_file_path != NULL) {
                g_key_file_load_from_file (keyfile,
                                           desktop_file_path,
                                           G_KEY_FILE_KEEP_COMMENTS |
                                           G_KEY_FILE_KEEP_TRANSLATIONS,
                                           error);
        } else {
                set_desktop_file_keys_from_client (client, keyfile);
        }

        return keyfile;
}

Project: gnome-session
File: gsm-xsmp-client.c

debug_print_property (SmProp *prop)
{
        GString *tmp;
        int      i;

        switch (prop->type[0]) {
        case 'C': /* CARD8 */
                g_debug ("GsmXSMPClient:   %s = %d", prop->name, *(unsigned char *)prop->vals[0].value);
                break;

        case 'A': /* ARRAY8 */
                g_debug ("GsmXSMPClient:   %s = '%s'", prop->name, (char *)prop->vals[0].value);
                break;

        case 'L': /* LISTofARRAY8 */
                tmp = g_string_new (NULL);
                for (i = 0; i < prop->num_vals; i++) {
                        g_string_append_printf (tmp, "'%.*s' ", prop->vals[i].length,
                                                (char *)prop->vals[i].value);
                }
                g_debug ("GsmXSMPClient:   %s = %s", prop->name, tmp->str);
                g_string_free (tmp, TRUE);
                break;

        default:
                g_debug ("GsmXSMPClient:   %s = ??? (%s)", prop->name, prop->type);
                break;
        }
}

Project: gnome-session
File: gsm-xsmp-client.c

delete_properties_callback (SmsConn     conn,
                            SmPointer   manager_data,
                            int         num_props,
                            char      **prop_names)
{
        GsmXSMPClient *client = manager_data;
        int i;

        g_debug ("GsmXSMPClient: Delete properties from '%s'", client->priv->description);

        for (i = 0; i < num_props; i++) {
                delete_property (client, prop_names[i]);

                g_debug ("  %s", prop_names[i]);
        }

        free (prop_names);
}

Project: gnome-session
File: gsm-xsmp-client.c

delete_property (GsmXSMPClient *client,
                 const char    *name)
{
        int     index;
        SmProp *prop;

        prop = find_property (client, name, &index);
        if (!prop) {
                return;
        }

#if 0
        /* This is wrong anyway; we can't unconditionally run the current
         * discard command; if this client corresponds to a GsmAppResumed,
         * and the current discard command is identical to the app's
         * discard_command, then we don't run the discard command now,
         * because that would delete a saved state we may want to resume
         * again later.
         */
        if (!strcmp (name, SmDiscardCommand)) {
                gsm_client_run_discard (GSM_CLIENT (client));
        }
#endif

        g_ptr_array_remove_index_fast (client->priv->props, index);
        SmFreeProperty (prop);
}

Project: gnome-session
File: gsm-xsmp-client.c

do_save_yourself (GsmXSMPClient *client,
                  int            save_type,
                  gboolean       allow_interact)
{
        g_assert (client->priv->conn != NULL);

        if (client->priv->next_save_yourself != -1) {
                /* Either we're currently doing a shutdown and there's a checkpoint
                 * queued after it, or vice versa. Either way, the new SaveYourself
                 * is redundant.
                 */
                g_debug ("GsmXSMPClient:   skipping redundant SaveYourself for '%s'",
                         client->priv->description);
        } else if (client->priv->current_save_yourself != -1) {
                g_debug ("GsmXSMPClient:   queuing new SaveYourself for '%s'",
                         client->priv->description);
                client->priv->next_save_yourself = save_type;
                client->priv->next_save_yourself_allow_interact = allow_interact;
        } else {
                client->priv->current_save_yourself = save_type;
                /* make sure we don't have anything queued */
                client->priv->next_save_yourself = -1;
                client->priv->next_save_yourself_allow_interact = FALSE;

                switch (save_type) {
                case SmSaveLocal:
                        /* Save state */
                        SmsSaveYourself (client->priv->conn,
                                         SmSaveLocal,
                                         FALSE,
                                         SmInteractStyleNone,
                                         FALSE);
                        break;

                default:
                        /* Logout */
                        if (!allow_interact) {
                                SmsSaveYourself (client->priv->conn,
                                                 save_type, /* save type */
                                                 TRUE, /* shutdown */
                                                 SmInteractStyleNone, /* interact style */
                                                 TRUE); /* fast */
                        } else {
                                SmsSaveYourself (client->priv->conn,
                                                 save_type, /* save type */
                                                 TRUE, /* shutdown */
                                                 SmInteractStyleAny, /* interact style */
                                                 FALSE /* fast */);
                        }
                        break;
                }
        }
}

Project: gnome-session
File: gsm-xsmp-client.c

 find_property (GsmXSMPClient *client,
                const char    *name,
               int           *index)
{
        SmProp *prop;
        int i;

        for (i = 0; i < client->priv->props->len; i++) {
                prop = client->priv->props->pdata[i];

                if (!strcmp (prop->name, name)) {
                        if (index) {
                                *index = i;
                        }
                        return prop;
                }
        }

        return NULL;
}

Project: gnome-session
File: gsm-xsmp-client.c

get_desktop_file_path (GsmXSMPClient *client)
{
        SmProp     *prop;
        char       *desktop_file_path = NULL;
        char      **dirs;
        const char *program_name;

        /* XSMP clients using eggsmclient defines a special property
         * pointing to their respective desktop entry file */
        prop = find_property (client, GsmDesktopFile, NULL);

        if (prop) {
                GFile *file = g_file_new_for_uri (prop->vals[0].value);
                desktop_file_path = g_file_get_path (file);
                g_object_unref (file);
                goto out;
        }

        /* If we can't get desktop file from GsmDesktopFile then we
         * try to find the desktop file from its program name */
        prop = find_property (client, SmProgram, NULL);
        program_name = prop->vals[0].value;

        dirs = gsm_util_get_autostart_dirs ();

        desktop_file_path =
                gsm_util_find_desktop_file_for_app_name (program_name,
                                                         dirs);

        g_strfreev (dirs);

out:
        g_debug ("GsmXSMPClient: desktop file for client %s is %s",
                 gsm_client_peek_id (GSM_CLIENT (client)),
                 desktop_file_path ? desktop_file_path : "(null)");

        return desktop_file_path;
}

Project: gnome-session
File: gsm-xsmp-client.c

gsm_xsmp_client_class_init (GsmXSMPClientClass *klass)
{
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
        GsmClientClass *client_class = GSM_CLIENT_CLASS (klass);

        object_class->finalize             = gsm_xsmp_client_finalize;
        object_class->constructor          = gsm_xsmp_client_constructor;
        object_class->get_property         = gsm_xsmp_client_get_property;
        object_class->set_property         = gsm_xsmp_client_set_property;

        client_class->impl_save                   = xsmp_save;
        client_class->impl_stop                   = xsmp_stop;
        client_class->impl_query_end_session      = xsmp_query_end_session;
        client_class->impl_end_session            = xsmp_end_session;
        client_class->impl_cancel_end_session     = xsmp_cancel_end_session;
        client_class->impl_get_app_name           = xsmp_get_app_name;
        client_class->impl_get_restart_style_hint = xsmp_get_restart_style_hint;
        client_class->impl_get_unix_process_id    = xsmp_get_unix_process_id;

        signals[REGISTER_REQUEST] =
                g_signal_new ("register-request",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GsmXSMPClientClass, register_request),
                              _boolean_handled_accumulator,
                              NULL,
                              gsm_marshal_BOOLEAN__POINTER,
                              G_TYPE_BOOLEAN,
                              1, G_TYPE_POINTER);
        signals[LOGOUT_REQUEST] =
                g_signal_new ("logout-request",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GsmXSMPClientClass, logout_request),
                              NULL,
                              NULL,
                              g_cclosure_marshal_VOID__BOOLEAN,
                              G_TYPE_NONE,
                              1, G_TYPE_BOOLEAN);

        g_object_class_install_property (object_class,
                                         PROP_ICE_CONNECTION,
                                         g_param_spec_pointer ("ice-connection",
                                                               "ice-connection",
                                                               "ice-connection",
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));

        g_type_class_add_private (klass, sizeof (GsmXSMPClientPrivate));
}

Project: gnome-session
File: gsm-xsmp-client.c

gsm_xsmp_client_constructor (GType                  type,
                             guint                  n_construct_properties,
                             GObjectConstructParam *construct_properties)
{
        GsmXSMPClient *client;

        client = GSM_XSMP_CLIENT (G_OBJECT_CLASS (gsm_xsmp_client_parent_class)->constructor (type,
                                                                                              n_construct_properties,
                                                                                              construct_properties));
        setup_connection (client);

        return G_OBJECT (client);
}

Project: gnome-session
File: gsm-xsmp-client.c

gsm_xsmp_client_finalize (GObject *object)
{
        GsmXSMPClient *client = (GsmXSMPClient *) object;

        g_debug ("GsmXSMPClient: xsmp_finalize (%s)", client->priv->description);
        gsm_xsmp_client_disconnect (client);

        g_free (client->priv->description);
        g_ptr_array_foreach (client->priv->props, (GFunc)SmFreeProperty, NULL);
        g_ptr_array_free (client->priv->props, TRUE);

        G_OBJECT_CLASS (gsm_xsmp_client_parent_class)->finalize (object);
}

Project: gnome-session
File: gsm-xsmp-client.c

gsm_xsmp_client_get_property (GObject    *object,
                              guint       prop_id,
                              GValue     *value,
                              GParamSpec *pspec)
{
        GsmXSMPClient *self;

        self = GSM_XSMP_CLIENT (object);

        switch (prop_id) {
        case PROP_ICE_CONNECTION:
                g_value_set_pointer (value, self->priv->ice_connection);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
        }
}

Project: gnome-session
File: gsm-xsmp-client.c

gsm_xsmp_client_init (GsmXSMPClient *client)
{
        client->priv = GSM_XSMP_CLIENT_GET_PRIVATE (client);

        client->priv->props = g_ptr_array_new ();
        client->priv->current_save_yourself = -1;
        client->priv->next_save_yourself = -1;
        client->priv->next_save_yourself_allow_interact = FALSE;
}

Project: gnome-session
File: gsm-xsmp-client.c

gsm_xsmp_client_new (IceConn ice_conn)
{
        GsmXSMPClient *xsmp;

        xsmp = g_object_new (GSM_TYPE_XSMP_CLIENT,
                             "ice-connection", ice_conn,
                             NULL);

        return GSM_CLIENT (xsmp);
}

Project: gnome-session
File: gsm-xsmp-client.c

gsm_xsmp_client_set_property (GObject       *object,
                              guint          prop_id,
                              const GValue  *value,
                              GParamSpec    *pspec)
{
        GsmXSMPClient *self;

        self = GSM_XSMP_CLIENT (object);

        switch (prop_id) {
        case PROP_ICE_CONNECTION:
                gsm_client_set_ice_connection (self, g_value_get_pointer (value));
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
        }
}

Project: gnome-session
File: gsm-xsmp-client.c

interact_done_callback (SmsConn   conn,
                        SmPointer manager_data,
                        Bool      cancel_shutdown)
{
        GsmXSMPClient *client = manager_data;

        g_debug ("GsmXSMPClient: Client '%s' received InteractDone(cancel_shutdown = %s)",
                 client->priv->description,
                 cancel_shutdown ? "True" : "False");

        gsm_client_end_session_response (GSM_CLIENT (client),
                                         TRUE, FALSE, cancel_shutdown,
                                         NULL);
}

Project: gnome-session
File: gsm-xsmp-client.c

prop_to_command (SmProp *prop)
{
        GString *str;
        int i, j;
        gboolean need_quotes;

        str = g_string_new (NULL);
        for (i = 0; i < prop->num_vals; i++) {
                char *val = prop->vals[i].value;

                need_quotes = FALSE;
                for (j = 0; j < prop->vals[i].length; j++) {
                        if (!g_ascii_isalnum (val[j]) && !strchr ("-_=:./", val[j])) {
                                need_quotes = TRUE;
                                break;
                        }
                }

                if (i > 0) {
                        g_string_append_c (str, ' ');
                }

                if (!need_quotes) {
                        g_string_append_printf (str,
                                                "%.*s",
                                                prop->vals[i].length,
                                                (char *)prop->vals[i].value);
                } else {
                        g_string_append_c (str, '\'');
                        while (val < (char *)prop->vals[i].value + prop->vals[i].length) {
                                if (*val == '\'') {
                                        g_string_append (str, "'\''");
                                } else {
                                        g_string_append_c (str, *val);
                                }
                                val++;
                        }
                        g_string_append_c (str, '\'');
                }
        }

        return g_string_free (str, FALSE);
}

Project: gnome-session
File: gsm-xsmp-client.c

register_client_callback (SmsConn    conn,
                          SmPointer  manager_data,
                          char      *previous_id)
{
        GsmXSMPClient *client = manager_data;
        gboolean       handled;
        char          *id;

        g_debug ("GsmXSMPClient: Client '%s' received RegisterClient(%s)",
                 client->priv->description,
                 previous_id ? previous_id : "NULL");


        /* There are three cases:
         * 1. id is NULL - we'll use a new one
         * 2. id is known - we'll use known one
         * 3. id is unknown - this is an error
         */
        id = g_strdup (previous_id);

        handled = FALSE;
        g_signal_emit (client, signals[REGISTER_REQUEST], 0, &id, &handled);
        if (! handled) {
                g_debug ("GsmXSMPClient:  RegisterClient not handled!");
                g_free (id);
                free (previous_id);
                g_assert_not_reached ();
                return FALSE;
        }

        if (IS_STRING_EMPTY (id)) {
                g_debug ("GsmXSMPClient:   rejected: invalid previous_id");
                free (previous_id);
                return FALSE;
        }

        g_object_set (client, "startup-id", id, NULL);

        set_description (client);

        g_debug ("GsmXSMPClient: Sending RegisterClientReply to '%s'", client->priv->description);

        SmsRegisterClientReply (conn, id);

        if (IS_STRING_EMPTY (previous_id)) {
                /* Send the initial SaveYourself. */
                g_debug ("GsmXSMPClient: Sending initial SaveYourself");
                SmsSaveYourself (conn, SmSaveLocal, False, SmInteractStyleNone, False);
                client->priv->current_save_yourself = SmSaveLocal;
        }

        gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_REGISTERED);

        g_free (id);
        free (previous_id);

        return TRUE;
}

Project: gnome-session
File: gsm-xsmp-client.c

save_yourself_done_callback (SmsConn   conn,
                             SmPointer manager_data,
                             Bool      success)
{
        GsmXSMPClient *client = manager_data;

        g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfDone(success = %s)",
                 client->priv->description,
                 success ? "True" : "False");

	if (client->priv->current_save_yourself != -1) {
		SmsSaveComplete (client->priv->conn);
		client->priv->current_save_yourself = -1;
	}

        /* If success is false then the application couldn't save data. Nothing
         * the session manager can do about, though. FIXME: we could display a
         * dialog about this, I guess. */
        gsm_client_end_session_response (GSM_CLIENT (client),
                                         TRUE, FALSE, FALSE,
                                         NULL);

        if (client->priv->next_save_yourself) {
                int      save_type = client->priv->next_save_yourself;
                gboolean allow_interact = client->priv->next_save_yourself_allow_interact;

                client->priv->next_save_yourself = -1;
                client->priv->next_save_yourself_allow_interact = -1;
                do_save_yourself (client, save_type, allow_interact);
        }
}

Project: gnome-session
File: gsm-xsmp-client.c

save_yourself_phase2_request_callback (SmsConn   conn,
                                       SmPointer manager_data)
{
        GsmXSMPClient *client = manager_data;

        g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfPhase2Request",
                 client->priv->description);

        client->priv->current_save_yourself = -1;

        /* this is a valid response to SaveYourself and therefore
           may be a response to a QES or ES */
        gsm_client_end_session_response (GSM_CLIENT (client),
                                         TRUE, TRUE, FALSE,
                                         NULL);
}

Project: gnome-session
File: gsm-xsmp-client.c

save_yourself_request_callback (SmsConn   conn,
                                SmPointer manager_data,
                                int       save_type,
                                Bool      shutdown,
                                int       interact_style,
                                Bool      fast,
                                Bool      global)
{
        GsmXSMPClient *client = manager_data;

        g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfRequest(%s, %s, %s, %s, %s)",
                 client->priv->description,
                 save_type == SmSaveLocal ? "SmSaveLocal" :
                 save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth",
                 shutdown ? "Shutdown" : "!Shutdown",
                 interact_style == SmInteractStyleAny ? "SmInteractStyleAny" :
                 interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" :
                 "SmInteractStyleNone", fast ? "Fast" : "!Fast",
                 global ? "Global" : "!Global");

        /* Examining the g_debug above, you can see that there are a total
         * of 72 different combinations of options that this could have been
         * called with. However, most of them are stupid.
         *
         * If @shutdown and @global are both TRUE, that means the caller is
         * requesting that a logout message be sent to all clients, so we do
         * that. We use @fast to decide whether or not to show a
         * confirmation dialog. (This isn't really what @fast is for, but
         * the old gnome-session and ksmserver both interpret it that way,
         * so we do too.) We ignore @save_type because we pick the correct
         * save_type ourselves later based on user prefs, dialog choices,
         * etc, and we ignore @interact_style, because clients have not used
         * it correctly consistently enough to make it worth honoring.
         *
         * If @shutdown is TRUE and @global is FALSE, the caller is
         * confused, so we ignore the request.
         *
         * If @shutdown is FALSE and @save_type is SmSaveGlobal or
         * SmSaveBoth, then the client wants us to ask some or all open
         * applications to save open files to disk, but NOT quit. This is
         * silly and so we ignore the request.
         *
         * If @shutdown is FALSE and @save_type is SmSaveLocal, then the
         * client wants us to ask some or all open applications to update
         * their current saved state, but not log out. At the moment, the
         * code only supports this for the !global case (ie, a client
         * requesting that it be allowed to update *its own* saved state,
         * but not having everyone else update their saved state).
         */

        if (shutdown && global) {
                g_debug ("GsmXSMPClient:   initiating shutdown");
                g_signal_emit (client, signals[LOGOUT_REQUEST], 0, !fast);
        } else if (!shutdown && !global) {
                g_debug ("GsmXSMPClient:   initiating checkpoint");
                do_save_yourself (client, SmSaveLocal, TRUE);
        } else {
                g_debug ("GsmXSMPClient:   ignoring");
        }
}

Project: gnome-session
File: gsm-xsmp-client.c

set_desktop_file_keys_from_client (GsmClient *client,
                                   GKeyFile  *keyfile)
{
        SmProp *prop;
        char   *name;
        char   *comment;

        prop = find_property (GSM_XSMP_CLIENT (client), SmProgram, NULL);
        name = g_strdup (prop->vals[0].value);

        comment = g_strdup_printf ("Client %s which was automatically saved",
                                   gsm_client_peek_startup_id (client));

        g_key_file_set_string (keyfile,
                               G_KEY_FILE_DESKTOP_GROUP,
                               G_KEY_FILE_DESKTOP_KEY_NAME,
                               name);

        g_key_file_set_string (keyfile,
                               G_KEY_FILE_DESKTOP_GROUP,
                               G_KEY_FILE_DESKTOP_KEY_COMMENT,
                               comment);

        g_key_file_set_string (keyfile,
                               G_KEY_FILE_DESKTOP_GROUP,
                               G_KEY_FILE_DESKTOP_KEY_ICON,
                               "system-run");

        g_key_file_set_string (keyfile,
                               G_KEY_FILE_DESKTOP_GROUP,
                               G_KEY_FILE_DESKTOP_KEY_TYPE,
                               "Application");

        g_key_file_set_boolean (keyfile,
                                G_KEY_FILE_DESKTOP_GROUP,
                                G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY,
                                TRUE);

        g_free (name);
        g_free (comment);
}

Project: gnome-session
File: gsm-xsmp-client.c

set_properties_callback (SmsConn     conn,
                         SmPointer   manager_data,
                         int         num_props,
                         SmProp    **props)
{
        GsmXSMPClient *client = manager_data;
        int            i;

        g_debug ("GsmXSMPClient: Set properties from client '%s'", client->priv->description);

        for (i = 0; i < num_props; i++) {
                delete_property (client, props[i]->name);
                g_ptr_array_add (client->priv->props, props[i]);

                debug_print_property (props[i]);

                if (!strcmp (props[i]->name, SmProgram))
                        set_description (client);
        }

        free (props);

}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_cancel_end_session (GsmClient *client,
                         GError   **error)
{
        GsmXSMPClient *xsmp = (GsmXSMPClient *) client;

        g_debug ("GsmXSMPClient: xsmp_cancel_end_session ('%s')", xsmp->priv->description);

        if (xsmp->priv->conn == NULL) {
                g_set_error (error,
                             GSM_CLIENT_ERROR,
                             GSM_CLIENT_ERROR_NOT_REGISTERED,
                             "Client is not registered");
                return FALSE;
        }

        SmsShutdownCancelled (xsmp->priv->conn);

        /* reset the state */
        xsmp->priv->current_save_yourself = -1;
        xsmp->priv->next_save_yourself = -1;
        xsmp->priv->next_save_yourself_allow_interact = FALSE;

        return TRUE;
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_end_session (GsmClient *client,
                  guint      flags,
                  GError   **error)
{
        gboolean phase2;

        if (GSM_XSMP_CLIENT (client)->priv->conn == NULL) {
                g_set_error (error,
                             GSM_CLIENT_ERROR,
                             GSM_CLIENT_ERROR_NOT_REGISTERED,
                             "Client is not registered");
                return FALSE;
        }

        phase2 = (flags & GSM_CLIENT_END_SESSION_FLAG_LAST);

        if (phase2) {
                xsmp_save_yourself_phase2 (client);
        } else {
                gboolean allow_interact;
                int      save_type;

                /* we gave a chance to interact to the app during
                 * xsmp_query_end_session(), now it's too late to interact */
                allow_interact = FALSE;

                if (flags & GSM_CLIENT_END_SESSION_FLAG_SAVE) {
                        save_type = SmSaveBoth;
                } else {
                        save_type = SmSaveGlobal;
                }

                do_save_yourself (GSM_XSMP_CLIENT (client),
                                  save_type, allow_interact);
        }

        return TRUE;
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_get_discard_command (GsmClient *client)
{
        SmProp *prop;

        prop = find_property (GSM_XSMP_CLIENT (client), SmDiscardCommand, NULL);

        if (!prop || strcmp (prop->type, SmLISTofARRAY8) != 0) {
                return NULL;
        }

        return prop_to_command (prop);
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_get_restart_command (GsmClient *client)
{
        SmProp *prop;

        prop = find_property (GSM_XSMP_CLIENT (client), SmRestartCommand, NULL);

        if (!prop || strcmp (prop->type, SmLISTofARRAY8) != 0) {
                return NULL;
        }

        return prop_to_command (prop);
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_get_restart_style_hint (GsmClient *client)
{
        SmProp               *prop;
        GsmClientRestartStyle hint;

        g_debug ("GsmXSMPClient: getting restart style");
        hint = GSM_CLIENT_RESTART_IF_RUNNING;

        prop = find_property (GSM_XSMP_CLIENT (client), SmRestartStyleHint, NULL);

        if (!prop || strcmp (prop->type, SmCARD8) != 0) {
                return GSM_CLIENT_RESTART_IF_RUNNING;
        }

        switch (((unsigned char *)prop->vals[0].value)[0]) {
        case SmRestartIfRunning:
                hint = GSM_CLIENT_RESTART_IF_RUNNING;
                break;
        case SmRestartAnyway:
                hint = GSM_CLIENT_RESTART_ANYWAY;
                break;
        case SmRestartImmediately:
                hint = GSM_CLIENT_RESTART_IMMEDIATELY;
                break;
        case SmRestartNever:
                hint = GSM_CLIENT_RESTART_NEVER;
                break;
        default:
                break;
        }

        return hint;
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_get_unix_process_id (GsmClient *client)
{
        SmProp  *prop;
        guint    pid;
        gboolean res;

        g_debug ("GsmXSMPClient: getting pid");

        prop = find_property (GSM_XSMP_CLIENT (client), SmProcessID, NULL);

        if (!prop || strcmp (prop->type, SmARRAY8) != 0) {
                return 0;
        }

        pid = 0;
        res = _parse_value_as_uint ((char *)prop->vals[0].value, &pid);
        if (! res) {
                pid = 0;
        }

        return pid;
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_interact (GsmClient *client)
{
        GsmXSMPClient *xsmp = (GsmXSMPClient *) client;

        g_debug ("GsmXSMPClient: xsmp_interact ('%s')", xsmp->priv->description);

        SmsInteract (xsmp->priv->conn);
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_query_end_session (GsmClient *client,
                        guint      flags,
                        GError   **error)
{
        gboolean allow_interact;
        int      save_type;

        if (GSM_XSMP_CLIENT (client)->priv->conn == NULL) {
                g_set_error (error,
                             GSM_CLIENT_ERROR,
                             GSM_CLIENT_ERROR_NOT_REGISTERED,
                             "Client is not registered");
                return FALSE;
        }

        allow_interact = !(flags & GSM_CLIENT_END_SESSION_FLAG_FORCEFUL);

        /* we don't want to save the session state, but we just want to know if
         * there's user data the client has to save and we want to give the
         * client a chance to tell the user about it. This is consistent with
         * the manager not setting GSM_CLIENT_END_SESSION_FLAG_SAVE for this
         * phase. */
        save_type = SmSaveGlobal;

        do_save_yourself (GSM_XSMP_CLIENT (client), save_type, allow_interact);
        return TRUE;
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_save (GsmClient *client,
           GError   **error)
{
        GsmClientRestartStyle restart_style;

        GKeyFile *keyfile = NULL;
        char     *desktop_file_path = NULL;
        char     *exec_program = NULL;
        char     *exec_discard = NULL;
        char     *startup_id = NULL;
        GError   *local_error;

        g_debug ("GsmXSMPClient: saving client with id %s",
                 gsm_client_peek_id (client));

        local_error = NULL;

        restart_style = xsmp_get_restart_style_hint (client);
        if (restart_style == GSM_CLIENT_RESTART_NEVER) {
                goto out;
        }

        exec_program = xsmp_get_restart_command (client);
        if (!exec_program) {
                goto out;
        }

        desktop_file_path = get_desktop_file_path (GSM_XSMP_CLIENT (client));

        keyfile = create_client_key_file (client,
                                          desktop_file_path,
                                          &local_error);

        if (local_error) {
                goto out;
        }

        g_object_get (client,
                      "startup-id", &startup_id,
                      NULL);

        g_key_file_set_string (keyfile,
                               G_KEY_FILE_DESKTOP_GROUP,
                               GSM_AUTOSTART_APP_STARTUP_ID_KEY,
                               startup_id);

        g_key_file_set_string (keyfile,
                               G_KEY_FILE_DESKTOP_GROUP,
                               G_KEY_FILE_DESKTOP_KEY_EXEC,
                               exec_program);

        exec_discard = xsmp_get_discard_command (client);
        if (exec_discard)
                g_key_file_set_string (keyfile,
                                       G_KEY_FILE_DESKTOP_GROUP,
                                       GSM_AUTOSTART_APP_DISCARD_KEY,
                                       exec_discard);

out:
        g_free (desktop_file_path);
        g_free (exec_program);
        g_free (exec_discard);
        g_free (startup_id);

        if (local_error != NULL) {
                g_propagate_error (error, local_error);
                g_key_file_free (keyfile);

                return NULL;
        }

        return keyfile;
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_save_yourself_phase2 (GsmClient *client)
{
        GsmXSMPClient *xsmp = (GsmXSMPClient *) client;

        g_debug ("GsmXSMPClient: xsmp_save_yourself_phase2 ('%s')", xsmp->priv->description);

        SmsSaveYourselfPhase2 (xsmp->priv->conn);
}

Project: gnome-session
File: gsm-xsmp-client.c

xsmp_stop (GsmClient *client,
           GError   **error)
{
        GsmXSMPClient *xsmp = (GsmXSMPClient *) client;

        g_debug ("GsmXSMPClient: xsmp_stop ('%s')", xsmp->priv->description);

        if (xsmp->priv->conn == NULL) {
                g_set_error (error,
                             GSM_CLIENT_ERROR,
                             GSM_CLIENT_ERROR_NOT_REGISTERED,
                             "Client is not registered");
                return FALSE;
        }

        SmsDie (xsmp->priv->conn);

        return TRUE;
}

Project: gnome-session
File: gsm-xsmp-server.c

auth_entry_new (const char *protocol,
                const char *network_id)
{
        IceAuthFileEntry *file_entry;
        IceAuthDataEntry  data_entry;

        file_entry = malloc (sizeof (IceAuthFileEntry));

        file_entry->protocol_name = strdup (protocol);
        file_entry->protocol_data = NULL;
        file_entry->protocol_data_length = 0;
        file_entry->network_id = strdup (network_id);
        file_entry->auth_name = strdup (GSM_ICE_MAGIC_COOKIE_AUTH_NAME);
        file_entry->auth_data = IceGenerateMagicCookie (GSM_ICE_MAGIC_COOKIE_LEN);
        file_entry->auth_data_length = GSM_ICE_MAGIC_COOKIE_LEN;

        /* Also create an in-memory copy, which is what the server will
         * actually use for checking client auth.
         */
        data_entry.protocol_name = file_entry->protocol_name;
        data_entry.network_id = file_entry->network_id;
        data_entry.auth_name = file_entry->auth_name;
        data_entry.auth_data = file_entry->auth_data;
        data_entry.auth_data_length = file_entry->auth_data_length;
        IceSetPaAuthData (1, &data_entry);

        return file_entry;
}

Project: gnome-session
File: gsm-xsmp-server.c

gsm_xsmp_server_class_init (GsmXsmpServerClass *klass)
{
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);

        object_class->get_property = gsm_xsmp_server_get_property;
        object_class->set_property = gsm_xsmp_server_set_property;
        object_class->constructor = gsm_xsmp_server_constructor;
        object_class->finalize = gsm_xsmp_server_finalize;

        g_object_class_install_property (object_class,
                                         PROP_CLIENT_STORE,
                                         g_param_spec_object ("client-store",
                                                              NULL,
                                                              NULL,
                                                              GSM_TYPE_STORE,
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));

        g_type_class_add_private (klass, sizeof (GsmXsmpServerPrivate));
}

Project: gnome-session
File: gsm-xsmp-server.c

gsm_xsmp_server_constructor (GType                  type,
                             guint                  n_construct_properties,
                             GObjectConstructParam *construct_properties)
{
        GsmXsmpServer *xsmp_server;

        xsmp_server = GSM_XSMP_SERVER (G_OBJECT_CLASS (gsm_xsmp_server_parent_class)->constructor (type,
                                                                                       n_construct_properties,
                                                                                       construct_properties));
        setup_listener (xsmp_server);

        return G_OBJECT (xsmp_server);
}

Project: gnome-session
File: gsm-xsmp-server.c

gsm_xsmp_server_finalize (GObject *object)
{
        GsmXsmpServer *xsmp_server;

        g_return_if_fail (object != NULL);
        g_return_if_fail (GSM_IS_XSMP_SERVER (object));

        xsmp_server = GSM_XSMP_SERVER (object);

        g_return_if_fail (xsmp_server->priv != NULL);

        IceFreeListenObjs (xsmp_server->priv->num_xsmp_sockets, 
                           xsmp_server->priv->xsmp_sockets);

        if (xsmp_server->priv->client_store != NULL) {
                g_object_unref (xsmp_server->priv->client_store);
        }

        G_OBJECT_CLASS (gsm_xsmp_server_parent_class)->finalize (object);
}

Project: gnome-session
File: gsm-xsmp-server.c

gsm_xsmp_server_get_property (GObject    *object,
                              guint       prop_id,
                              GValue     *value,
                              GParamSpec *pspec)
{
        GsmXsmpServer *self;

        self = GSM_XSMP_SERVER (object);

        switch (prop_id) {
        case PROP_CLIENT_STORE:
                g_value_set_object (value, self->priv->client_store);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
        }
}

Project: gnome-session
File: gsm-xsmp-server.c

gsm_xsmp_server_new (GsmStore *client_store)
{
        if (xsmp_server_object != NULL) {
                g_object_ref (xsmp_server_object);
        } else {
                xsmp_server_object = g_object_new (GSM_TYPE_XSMP_SERVER,
                                                   "client-store", client_store,
                                                   NULL);

                g_object_add_weak_pointer (xsmp_server_object,
                                           (gpointer *) &xsmp_server_object);
        }

        return GSM_XSMP_SERVER (xsmp_server_object);
}

Project: gnome-session
File: gsm-xsmp-server.c

gsm_xsmp_server_set_client_store (GsmXsmpServer *xsmp_server,
                                  GsmStore      *store)
{
        g_return_if_fail (GSM_IS_XSMP_SERVER (xsmp_server));

        if (store != NULL) {
                g_object_ref (store);
        }

        if (xsmp_server->priv->client_store != NULL) {
                g_object_unref (xsmp_server->priv->client_store);
        }

        xsmp_server->priv->client_store = store;
}

Project: gnome-session
File: gsm-xsmp-server.c

gsm_xsmp_server_set_property (GObject      *object,
                              guint         prop_id,
                              const GValue *value,
                              GParamSpec   *pspec)
{
        GsmXsmpServer *self;

        self = GSM_XSMP_SERVER (object);

        switch (prop_id) {
        case PROP_CLIENT_STORE:
                gsm_xsmp_server_set_client_store (self, g_value_get_object (value));
                break;
         default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
        }
}

Project: gnome-session
File: gsm-xsmp-server.c

gsm_xsmp_server_start (GsmXsmpServer *server)
{
        GIOChannel *channel;
        int         i;

        for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
                GsmIceConnectionData *data;

                data = g_new0 (GsmIceConnectionData, 1);
                data->server = server;
                data->listener = server->priv->xsmp_sockets[i];

                channel = g_io_channel_unix_new (IceGetListenConnectionNumber (server->priv->xsmp_sockets[i]));
                g_io_add_watch_full (channel,
                                     G_PRIORITY_DEFAULT,
                                     G_IO_IN | G_IO_HUP | G_IO_ERR,
                                     (GIOFunc)accept_ice_connection,
                                     data,
                                     (GDestroyNotify)g_free);
                g_io_channel_unref (channel);
        }
}

Project: gnome-session
File: gsm-xsmp-server.c

ice_error_handler (IceConn       conn,
                   Bool          swap,
                   int           offending_minor_opcode,
                   unsigned long offending_sequence,
                   int           error_class,
                   int           severity,
                   IcePointer    values)
{
        g_debug ("GsmXsmpServer: ice_error_handler (%p, %s, %d, %lx, %d, %d)",
                 conn, swap ? "TRUE" : "FALSE", offending_minor_opcode,
                 offending_sequence, error_class, severity);

        if (severity == IceCanContinue) {
                return;
        }

        /* FIXME: the ICElib docs are completely vague about what we're
         * supposed to do in this case. Need to verify that calling
         * IceCloseConnection() here is guaranteed to cause neither
         * free-memory-reads nor leaks.
         */
        IceCloseConnection (conn);
}

Project: gnome-session
File: gsm-xsmp-server.c

ice_io_error_handler (IceConn conn)
{
        g_debug ("GsmXsmpServer: ice_io_error_handler (%p)", conn);

        /* We don't need to do anything here; the next call to
         * IceProcessMessages() for this connection will receive
         * IceProcessMessagesIOError and we can handle the error there.
         */
}

Project: gnome-session
File: gsm-xsmp-server.c

setup_listener (GsmXsmpServer *server)
{
        char   error[256];
        mode_t saved_umask;
        char  *network_id_list;
        int    i;
        int    res;

        /* Set up sane error handlers */
        IceSetErrorHandler (ice_error_handler);
        IceSetIOErrorHandler (ice_io_error_handler);
        SmsSetErrorHandler (sms_error_handler);

        /* Initialize libSM; we pass NULL for hostBasedAuthProc to disable
         * host-based authentication.
         */
        res = SmsInitialize (PACKAGE,
                             VERSION,
                             (SmsNewClientProc)accept_xsmp_connection,
                             server,
                             NULL,
                             sizeof (error),
                             error);
        if (! res) {
                gsm_util_init_error (TRUE, "Could not initialize libSM: %s", error);
        }

#ifdef HAVE_X11_XTRANS_XTRANS_H
        /* By default, IceListenForConnections will open one socket for each
         * transport type known to X. We don't want connections from remote
         * hosts, so for security reasons it would be best if ICE didn't
         * even open any non-local sockets. So we use an internal ICElib
         * method to disable them here. Unfortunately, there is no way to
         * ask X what transport types it knows about, so we're forced to
         * guess.
         */
        _IceTransNoListen ("tcp");
#endif

        /* Create the XSMP socket. Older versions of IceListenForConnections
         * have a bug which causes the umask to be set to 0 on certain types
         * of failures. Probably not an issue on any modern systems, but
         * we'll play it safe.
         */
        saved_umask = umask (0);
        umask (saved_umask);
        res = IceListenForConnections (&server->priv->num_xsmp_sockets,
                                       &server->priv->xsmp_sockets,
                                       sizeof (error),
                                       error);
        if (! res) {
                gsm_util_init_error (TRUE, _("Could not create ICE listening socket: %s"), error);
        }

        umask (saved_umask);

        /* Find the local sockets in the returned socket list and move them
         * to the start of the list.
         */
        for (i = server->priv->num_local_xsmp_sockets = 0; i < server->priv->num_xsmp_sockets; i++) {
                char *id = IceGetListenConnectionString (server->priv->xsmp_sockets[i]);

                if (!strncmp (id, "local/", sizeof ("local/") - 1) ||
                    !strncmp (id, "unix/", sizeof ("unix/") - 1)) {
                        if (i > server->priv->num_local_xsmp_sockets) {
                                IceListenObj tmp;
                                tmp = server->priv->xsmp_sockets[i];
                                server->priv->xsmp_sockets[i] = server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets];
                                server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets] = tmp;
                        }
                        server->priv->num_local_xsmp_sockets++;
                }
                free (id);
        }

        if (server->priv->num_local_xsmp_sockets == 0) {
                gsm_util_init_error (TRUE, "IceListenForConnections did not return a local listener!");
        }

#ifdef HAVE_X11_XTRANS_XTRANS_H
        if (server->priv->num_local_xsmp_sockets != server->priv->num_xsmp_sockets) {
                /* Xtrans was apparently compiled with support for some
                 * non-local transport besides TCP (which we disabled above); we
                 * won't create IO watches on those extra sockets, so
                 * connections to them will never be noticed, but they're still
                 * there, which is inelegant.
                 *
                 * If the g_warning below is triggering for you and you want to
                 * stop it, the fix is to add additional _IceTransNoListen()
                 * calls above.
                 */
                network_id_list = IceComposeNetworkIdList (server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets,
                                                           server->priv->xsmp_sockets + server->priv->num_local_xsmp_sockets);
                g_warning ("IceListenForConnections returned %d non-local listeners: %s",
                           server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets,
                           network_id_list);
                free (network_id_list);
        }
#endif

        /* Update .ICEauthority with new auth entries for our socket */
        if (!update_iceauthority (server, TRUE)) {
                /* FIXME: is this really fatal? Hm... */
                gsm_util_init_error (TRUE,
                                     "Could not update ICEauthority file %s",
                                     IceAuthFileName ());
        }

        network_id_list = IceComposeNetworkIdList (server->priv->num_local_xsmp_sockets,
                                                   server->priv->xsmp_sockets);

        gsm_util_setenv ("SESSION_MANAGER", network_id_list);
        g_debug ("GsmXsmpServer: SESSION_MANAGER=%s\n", network_id_list);
        free (network_id_list);
}

Project: gnome-session
File: gsm-xsmp-server.c

sms_error_handler (SmsConn       conn,
                   Bool          swap,
                   int           offending_minor_opcode,
                   unsigned long offending_sequence_num,
                   int           error_class,
                   int           severity,
                   IcePointer    values)
{
        g_debug ("GsmXsmpServer: sms_error_handler (%p, %s, %d, %lx, %d, %d)",
                 conn, swap ? "TRUE" : "FALSE", offending_minor_opcode,
                 offending_sequence_num, error_class, severity);

        /* We don't need to do anything here; if the connection needs to be
         * closed, libSM will do that itself.
         */
}

Project: gnome-session
File: gsm-xsmp-server.c

update_iceauthority (GsmXsmpServer *server,
                     gboolean       adding)
{
        char             *filename;
        char            **our_network_ids;
        FILE             *fp;
        IceAuthFileEntry *auth_entry;
        GSList           *entries;
        GSList           *e;
        int               i;
        gboolean          ok = FALSE;

        filename = IceAuthFileName ();
        if (IceLockAuthFile (filename,
                             GSM_ICE_AUTH_RETRIES,
                             GSM_ICE_AUTH_INTERVAL,
                             GSM_ICE_AUTH_LOCK_TIMEOUT) != IceAuthLockSuccess) {
                return FALSE;
        }

        our_network_ids = g_malloc (server->priv->num_local_xsmp_sockets * sizeof (char *));
        for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
                our_network_ids[i] = IceGetListenConnectionString (server->priv->xsmp_sockets[i]);
        }

        entries = NULL;

        fp = fopen (filename, "r+");
        if (fp != NULL) {
                while ((auth_entry = IceReadAuthFileEntry (fp)) != NULL) {
                        /* Skip/delete entries with no network ID (invalid), or with
                         * our network ID; if we're starting up, an entry with our
                         * ID must be a stale entry left behind by an old process,
                         * and if we're shutting down, it won't be valid in the
                         * future, so either way we want to remove it from the list.
                         */
                        if (!auth_entry->network_id) {
                                IceFreeAuthFileEntry (auth_entry);
                                continue;
                        }

                        for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
                                if (!strcmp (auth_entry->network_id, our_network_ids[i])) {
                                        IceFreeAuthFileEntry (auth_entry);
                                        break;
                                }
                        }
                        if (i != server->priv->num_local_xsmp_sockets) {
                                continue;
                        }

                        entries = g_slist_prepend (entries, auth_entry);
                }

                rewind (fp);
        } else {
                int fd;

                if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
                        g_warning ("Unable to read ICE authority file: %s", filename);
                        goto cleanup;
                }

                fd = open (filename, O_CREAT | O_WRONLY, 0600);
                fp = fdopen (fd, "w");
                if (!fp) {
                        g_warning ("Unable to write to ICE authority file: %s", filename);
                        if (fd != -1) {
                                close (fd);
                        }
                        goto cleanup;
                }
        }

        if (adding) {
                for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
                        entries = g_slist_append (entries,
                                                  auth_entry_new ("ICE", our_network_ids[i]));
                        entries = g_slist_prepend (entries,
                                                   auth_entry_new ("XSMP", our_network_ids[i]));
                }
        }

        for (e = entries; e; e = e->next) {
                IceAuthFileEntry *auth_entry = e->data;
                IceWriteAuthFileEntry (fp, auth_entry);
                IceFreeAuthFileEntry (auth_entry);
        }
        g_slist_free (entries);

        fclose (fp);
        ok = TRUE;

 cleanup:
        IceUnlockAuthFile (filename);
        for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) {
                free (our_network_ids[i]);
        }
        g_free (our_network_ids);

        return ok;
}