stream-device: Create channels before first non-main channel connection

Due to ticket expiration, it is possible that the streaming channels for
the client are created after the ticket expires. Currently, streaming
channels are created dynamically when the guest starts streaming to the
server, which can happen at any time (for instance if you decide to start
the graphic server manually).
If the ticket has expired before the streaming channel is created,
authentication will fail and the client will not be able to connect.
To avoid this, create the channels when the first main channel connection
is made. This ensures that client will connect to all streaming channels.
This could be considered a temporary solution. There may be other
situations where it would be useful to connect new channels after the
ticket has expired, but enabling this behavior would require protocol
changes and a careful analysis of security implications.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
This commit is contained in:
Frediano Ziglio 2018-02-23 08:16:37 +00:00
parent 6bd9a486a9
commit 40ef0cb625
4 changed files with 31 additions and 3 deletions

View File

@ -117,6 +117,7 @@ struct RedsState {
RedStatFile *stat_file;
#endif
int allow_multiple_clients;
bool late_initialization_done;
/* Intermediate state for on going monitors config message from a single
* client, being passed to the guest */

View File

@ -1734,6 +1734,26 @@ static RedClient *reds_get_client(RedsState *reds)
return reds->clients->data;
}
/* Performs late initializations steps.
* This should be called when a client connects */
static void reds_late_initialization(RedsState *reds)
{
RedCharDevice *dev;
// do only once
if (reds->late_initialization_done) {
return;
}
// create stream channels for streaming devices
GLIST_FOREACH(reds->char_devices, RedCharDevice, dev) {
if (IS_STREAM_DEVICE(dev)) {
stream_device_create_channel(STREAM_DEVICE(dev));
}
}
reds->late_initialization_done = true;
}
static void
red_channel_capabilities_init_from_link_message(RedChannelCapabilities *caps,
const SpiceLinkMess *link_mess)
@ -1769,6 +1789,8 @@ static void reds_handle_main_link(RedsState *reds, RedLinkInfo *link)
spice_debug("trace");
spice_assert(reds->main_channel);
reds_late_initialization(reds);
link_mess = link->link_mess;
if (!reds->allow_multiple_clients) {
reds_disconnect(reds);

View File

@ -538,8 +538,8 @@ stream_device_finalize(GObject *object)
dev->msg_pos = 0;
}
static void
allocate_channels(StreamDevice *dev)
void
stream_device_create_channel(StreamDevice *dev)
{
if (dev->stream_channel) {
return;
@ -600,7 +600,7 @@ stream_device_port_event(RedCharDevice *char_dev, uint8_t event)
// reset device and channel on close/open
dev->opened = (event == SPICE_PORT_EVENT_OPENED);
if (dev->opened) {
allocate_channels(dev);
stream_device_create_channel(dev);
}
dev->hdr_pos = 0;
dev->msg_pos = 0;

View File

@ -43,6 +43,11 @@ typedef struct StreamDeviceClass StreamDeviceClass;
GType stream_device_get_type(void) G_GNUC_CONST;
StreamDevice *stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin);
/* Create channel for the streaming device.
* If the channel already exists the function does nothing.
*/
void stream_device_create_channel(StreamDevice *dev);
G_END_DECLS
#endif /* STREAM_DEVICE_H */