Resizing FreeRDP window
Let's start this new year (best wishes) with some RDP stuff, in this post I will talk of an implementation to resize the window in xfreerdp.
FreeRDP already had the smart-sizing option, it allows to see the window with a given aspect ratio: 100, 150 ou 180 percent.
With the MS-RDPEDISP specification, the client can send its monitors layout to the server in real time, that allows the server to react when an output is plugged or unplugged, or when the resolution changes. You can experiment that with mstsc in fullscreen mode, if you change resolution while the mstsc window is iconized, when you uniconize, it is supposed to resize.
You can also use that specification to make the RDP window resizable: you announce a monitor that has the size of the client window.
The protocol is quite trivial with only 2 messages exchanged:
- the server sends a display_control_caps packet containing the maximum number of monitors and resolution constraints;
- the client sends the monitor's resolutions (displaycontrol_monitor_layout packet). One would note that it gives more informations than the capabilities packet, as now we have the physical size of the screen and its orientation.
The channel and packet decoding was already there, it was just missing the wiring with the client implementation. It has been quite easy to do, the only subtility was the feedback loop between the user resizing the window by dragging the window corner and the server executing the reactivation sequence (that also resizes the window).
My test environment was a windows 2016 server and everything was just working fine. Just for completeness I did a test with a windows 2012 r2 server and problems arised.
Let's be a little more subtle
With windows 2012 server r2 I was freezing my own RDP session but also the whole server: unable to log in again when the bug had been triggered, even when using the console. And it was nothing complicated: just resize quickly the FreeRDP window and I was getting a black window and a frozen server.
After some bug analysis, I figured that I was probably sending a little too quickly the screen layouts. Sometime the reactivation sequence was not fully completed. Well in fact they were never finished, as I had wired the DesktopResize callback which is called as soon as we detect a difference between server and local resolution, and we're quite far from the end of the reactivation sequence. According to the spec you're not supposed to send anything else but negociate packets during the negociation sequence.
So I did the required changes, it was crashing a lot less often, but it was still freezing. The only workaround I've found is to limit the number of sent layouts per second to 5. I've reported the bug but I don't have any feedback.
It's quite interesting as it allows to do DoS on a server with a restricted used and a RDP connection, and even RDP bastion will not see anything illegitimate with resizes.
After a bug report, I figured that I had missed a detail in my implementation: when you use the graphical pipeline (_egfx channel), the server will not initiate a reactivation sequence but will just send a reset_graphics packet instead. Once this case handled correctly, it was working fine.
It has been pushed and merged in pull requests #4313 and #4332.
Next posts should also be on RDP as I'm actually working on a MS-RDPEVOR implementation, it is the equivalent of the TSMF channel (multimedia redirection) but for egfx. As this channel depends on the geometry tracking channel, I have already pushed a skeleton for this channel in this pull request.
Anyway it could also be a post on last CCC conferences, as I've seen some and they're really interesting. And I've not finished looking at the one that had a promising title.
So stay tuned...