Compare commits

...

121 Commits

Author SHA1 Message Date
metalefty
0579980e44
Merge pull request #3225 from metalefty/v0.10-h264
[v0.10] H264 cherry picks
2024-08-29 23:55:33 +09:00
matt335672
8bf9ed48af Further changes to selectable H.264 support
- Fix CI errors
- tconfig_load_gfx() removes H.264 from the supported codec list
  if significant errors are found loading the H.264 configuration
- tconfig_load_gfx() always produces a usable config, even if the
  specified file can't be loaded

(cherry picked from commit 5351511272)
2024-08-29 22:53:04 +09:00
matt335672
401cd845f8 Rework codec order in tconfig
Replaced codec idx values with a list of codecs from the
config file.

Added some logging for debugging

(cherry picked from commit 1ac216da1d)
2024-08-29 22:52:59 +09:00
Koichiro Iwao
5bbeb03848 GFX: use the preferred codec preferred in the config (H264 or RFX)
(cherry picked from commit 2c2585cc90)
2024-08-29 22:52:51 +09:00
Koichiro Iwao
689a2620d3 Introduce XRDP_H264 macro to indicate any H264 encoder enabled
(cherry picked from commit 7238f8f99d)
2024-08-29 22:52:44 +09:00
Koichiro Iwao
d56396b771 tconfig: add config which to prefer H264 vs RFX
(cherry picked from commit 07e4e23c7b)
2024-08-29 22:52:37 +09:00
Koichiro Iwao
89277e5aea x264: add CI test
(cherry picked from commit 72ede776ed)
2024-08-27 13:57:56 +09:00
Koichiro Iwao
abb5714f8f tconfig: refine logging
(cherry picked from commit b9d593bc11)
2024-08-27 13:14:02 +09:00
Koichiro Iwao
6b98637bac tconfig: set proper default value for fps_den
(cherry picked from commit 16ef3dc3a8)
2024-08-27 13:14:02 +09:00
Koichiro Iwao
1fcde20682 x264: Update x264 encoding parameters
(cherry picked from commit 6aeb364c8d)
2024-08-27 13:14:02 +09:00
Koichiro Iwao
12c9e79dee x264: apply encoding parameters per connection type
(cherry picked from commit 010b6a3dbf)
2024-08-27 13:14:02 +09:00
Koichiro Iwao
d083920824 tconfig: Makefile changes
(cherry picked from commit d50c2fd4e4)
2024-08-27 13:13:58 +09:00
Koichiro Iwao
427f501862 tconfig: add new toml config parser for gfx.toml
(cherry picked from commit b3513ba8df)
2024-08-27 09:58:16 +09:00
Jay Sorg
be3e3a3d0a rename old_capture_code to mark unused
(cherry picked from commit 2bed4f6b9b)
2024-08-07 23:17:43 +09:00
Jay Sorg
3c7b416375 change capture_code to enum
(cherry picked from commit 112a534f4c)
2024-08-07 23:16:58 +09:00
Jay Sorg
3a2e0eb8cd remove some unnecessary code
(cherry picked from commit 4dcf59c8f4)
2024-08-07 22:48:23 +09:00
Jay Sorg
099575056e fix for odd width, height
(cherry picked from commit 485e64ee76)
2024-08-07 22:31:51 +09:00
Jay Sorg
48a6cd4060 multimon fixes
(cherry picked from commit 96ff6fdba8)
2024-08-07 22:28:49 +09:00
Jay Sorg
9cb2afa052 format
(cherry picked from commit 57ed8e9d52)
2024-08-07 22:28:37 +09:00
Jay Sorg
565977bc81 xrdp_encoder.c changes for x264
(cherry picked from commit b583a8d510)
2024-08-07 22:28:28 +09:00
Jay Sorg
1d52a418ad add xrdp_encoder_x264.c/h
(cherry picked from commit ab97002c22)
2024-08-07 22:13:52 +09:00
Jay Sorg
2a02056346 add x264 to configure.ac
(cherry picked from commit e5e56a2ed9)
2024-08-07 22:13:34 +09:00
matt335672
82bec9d1dc
Merge pull request #3194 from matt335672/v0_10_chansrv_clip_fixes
[V0.10] chansrv clip fixes
2024-08-06 10:37:38 +01:00
matt335672
ace386d072 clipboard: Allow a file read to return 0 for EOF
When used with a FreeRDP client on Linux, a file copy operation from
the clipboard detects end-of-file by a read returning 0 bytes. This is
currently marked as an error.

It is assumed that mstsc.exe detects end-of-file in another way, which
is why this has not been found before.

(cherry picked from commit 0f6e731524)
2024-08-05 09:54:37 +01:00
matt335672
e59dc16be6 Remove unnecessary copy from clipboard_get_files()
The routine clipboard_get_files() parses a potentially long string,
and copies portions of it into a temporary buffer. This buffer is then
passed to clipboard_get_file() as pointer + length;

The buffer is inadequately sized for very long filenames which may
approach XFS_MAXFILENAMELEN in length. This can cause chansrv to fail
when the user copies such filenames.

It turns out the buffer is unnecessary, as the filenames can be
passed directly into clipboard_get_file() from the source string,
using pointer + length. This avoids the length limitation entirely.

(cherry picked from commit 34b5582460)
2024-08-05 09:54:26 +01:00
matt335672
f3070aef15 Allow for longer filenames from the redirector.
This commit ensures that filenames up to the maximum size supported
by our xfs can be supported.

(cherry picked from commit c3f7eec4f5)
2024-08-05 09:54:07 +01:00
matt335672
6c9d56efc2 Remove hard-coded filename limit for clipboard file lists
The limit of 256 characters for clipboard files is limiting for
many Asian locales, particularly as '%xx' notation is used to
communicate bytes with bit 7 set.

(cherry picked from commit a90228241d)
2024-08-05 09:53:55 +01:00
matt335672
f4153a493d Dynamically allocate XFS filesystem names
Replace the 256 byte buffer used for names in the XFS filesystem with a
dynamically allocated buffer.

The define XFS_MAXFILENAMELEN which used to be 255 has been retained,
but bumped to 1023. This value is no longer used for long-lived
allocations, but is used in chansrv_fuse.c for maintaining state
information for in-fligh I/O requests.

(cherry picked from commit d8b5435710)
2024-08-05 09:53:44 +01:00
metalefty
72892c1453
Merge pull request #3188 from metalefty/v0.10-tarball
[v0.10] Include {xrdp,sesman}.ini.in instead of substituted .ini in tarball
2024-08-01 20:58:59 +09:00
Koichiro Iwao
19bacc6e49 Include {xrdp,sesman}.ini.in instead of substituted .ini in tarball
These config files are intended to be substituted during the build
process. The substituted .ini files should not be included in release
tarballs.

Fixes:  #3187
2024-08-01 20:39:03 +09:00
metalefty
1c33f3d9af
Merge pull request #3185 from metalefty/v0.10-release
Release v0.10.1
2024-07-31 21:51:24 +09:00
metalefty
54932b55ef
Merge pull request #3183 from metalefty/v0.10-cherry-picks
[v0.10] cherry-picks
2024-07-31 21:48:28 +09:00
Koichiro Iwao
00b8b41344 Bump version to v0.10.1 2024-07-31 21:09:43 +09:00
Koichiro Iwao
4d9e9f91fa Update NEWS 2024-07-31 21:07:04 +09:00
matt335672
b343ca27b1 Replace binary blob with specified data
This commit changes the license response PDU to be constructed rather
than simply being contained as a binary blob.

Some constants in common/ms-rdpbcgr.h are renamed with the values
from the specification.

(cherry picked from commit 52dd88b576)
2024-07-30 10:46:12 +09:00
matt335672
3108a85e86 Remove Licensing exchange
Replaces the existing licensing exchange with a single PDU
saying the user will not issue a license.

This is necessary for clients on FIPS-compliant systems, as these
are unable to decode the licensing exchange packets, due to outdated
cyphers.

(cherry picked from commit cc4a4c95f2)
2024-07-30 10:46:03 +09:00
Koichiro Iwao
4d4ecdcaa4 GFX: selectable lossy compression levels
(cherry picked from commit e3c83c544c)
2024-07-30 10:45:41 +09:00
matt335672
da34d1e69d
Merge pull request #3175 from matt335672/v0_10_fix_potential_name_overflow
[V0.10] Fix potential name buffer overflows in redirector
2024-07-24 12:11:28 +01:00
matt335672
5223672437 Fix potential name buffer overflows in redirector
The state buffers used by the following structs in chansrv_fuse.c
are one byte too small for filenames of length XFS_MAXFILENAMELEN:-
- struct state_lookup
- struct state_create
- struct state_rename

In practice, there is no runtime danger, as XFS_MAXFILENAMELEN is 255,
and these buffers will be followed by non-byte aligned data. Nevertheless
this should be fixed to prevent problems if the value is changed.

(cherry picked from commit c9e84dc16c)
2024-07-23 12:29:43 +01:00
matt335672
2938c3d7b3
Merge pull request #3171 from matt335672/v0_10_fix_missing_pre_session_ipaddr
[V0.10] sesman: Copy IP address to pre_session_item struct
2024-07-22 09:46:30 +01:00
matt335672
4a90879555 sesman: Copy IP address to pre_session_item struct
struct pre_session_item has an entry for the start_ip_addr which is not
being filled in. This is not normally needed, as the IP address of the
session is passed into the session another way, but it is needed if the
session selection Policy contains the 'I' selector.

(cherry picked from commit a4f57572e6)
2024-07-19 12:01:47 +01:00
metalefty
a7d583a46d
Merge pull request from GHSA-7w22-h4w7-8j5j
Enforce no login screen if require_credentials is set
2024-07-11 09:37:12 +09:00
metalefty
d6fce2f173
Merge pull request #3152 from metalefty/v0.10-submodule
[v0.10] Support screens larger than 4096 pixels (update submodule)
2024-07-09 11:48:14 +09:00
Koichiro Iwao
2546bfa842 Support screens larger than 4096 pixels (update submodule)
Fixes:  #3083
2024-07-09 08:15:37 +09:00
metalefty
1d30c81323
Merge pull request #3150 from metalefty/v0.10-makedist
docs: always include docs/man/xrdp-mkfv1.8.in to dist tarball
2024-07-08 21:27:08 +09:00
Koichiro Iwao
e83dcc52eb docs: always include docs/man/xrdp-mkfv1.8.in to dist tarball
Files included in distribution tarball must always be enumerated,
not be enumerated conditionally.

Resolves:   #3149
2024-07-08 16:34:23 +09:00
matt335672
61b509f1d5 Enforce no login screen if require_credentials is set
If the setting require_credentials is true, there should be no way
for the user to get to a login screen.

This commit makes the following changes if this flag is active:-
- Makes the checks around TS_INFO_PACKET more explicit.
- Closes the connection if the first login attempt fails.

(cherry picked from commit 8ac2f6db34)
2024-06-27 11:55:26 +01:00
matt335672
8ddbe77e7c
Merge pull request #3127 from matt335672/v0_10_investigate_gfx_min_max_issue
[v0.10] Fix min/max monitor placing issue
2024-06-21 09:49:39 +01:00
matt335672
029059ef3d Fix min/max monitor placing issue
when a multi-monitor session has the top-left vertex of the primary
monitor at a desktop location other than (0,0), minimising and maximising
the session results in the (0,0) co-ordinate of the entire desktop being
placed at the top-left of the primary monitor.

The implementation seems to be at odds with [MS-RDPEGFX] 2.2.2.14 which
suggests the monitorDefArray of the RDPGFX_RESET_GRAPHICS_PDU should be
the same as that in the Monitor Layout PDU ([MS-RDPBCGR] 2.2.12.1)

(cherry picked from commit 095f0d0e4c)
2024-06-19 09:12:19 +01:00
matt335672
9a21e37f1f
Merge pull request #3122 from matt335672/v0_10_fix_server_24bpp_gfx
[v0.10] Don't use GFX if server max_bpp is <32
2024-06-19 09:02:55 +01:00
metalefty
0aa3a679c3
Merge pull request #3120 from metalefty/v0.10-libreoffice-image-clipboard
clipboard: fix a bug when pasting image to LibreOffice
2024-06-18 18:23:44 +09:00
Koichiro Iwao
e070902310
clipboard: tidy up bmp file header assembly
Sponsored by:   Krämer Pferdesport GmbH & Co KG
2024-06-18 11:13:40 +09:00
matt335672
90ca82fe52 Don't use GFX if server max_bpp is <32
(cherry picked from commit d2bab53364)
2024-06-17 13:24:26 +01:00
Koichiro Iwao
4968a34cd6
clipboard: fix a bug when pasting image to LibreOffice
While here, embed correct file size in BMP file header.

Fixes:          #3102
Sponsored by:   Krämer Pferdesport GmbH & Co KG
2024-06-17 21:08:30 +09:00
metalefty
7aa2b34ca0
Merge pull request #3088 from matt335672/v0_10_cherry_picks
Further cherry-picks for v0.10
2024-06-17 21:07:34 +09:00
matt335672
2319f56268 Replace 'dvorak' keyboard description with 'us(dvorak)'
In the words of @iskunk

It is no longer possible to refer to the Dvorak layout as just "dvorak"
(as when one would run "setxkbmap dvorak"); one must now use either
"us dvorak" or "us(dvorak)"

See https://bugs.debian.org/1063725

(cherry picked from commit a1b7c17906)
2024-06-12 14:09:31 +01:00
matt335672
a5ec4a3817 Add explicit object for the encoder finishing
On a resize, the encoder is deleted. At present this is done by asking
the encoder to exit, and then waiting a second.

- On slower systems, a second may not be enough, and so the encoder
  data structures are freed while they are still being used by the
  encoder.
- On quicker systems, resizes are delayed by hundreds of milliseconds
  longer than they need to be.

This commit adds a wait object which the encoder can use to signal it
has actually finished.

(cherry picked from commit 985b0de35e)
2024-06-10 18:54:26 +01:00
matt335672
a430eb93cb Prevent SEGV when resizing with GFX
The xrdp_enc_data contains a union for handling surface commands
and gfx commands. Memory processing is different for these two
options.

The default destructor for the encoder FIFO only knows about surface
commands. Consequently, if the encoder has queued GFX data when the
encoder is closed, the destructor processes the queued data as if
it contained surface commands rather than GFX commands. This typically
causes a SEGV as the drects field of the overlaid surface command
structure is not pointing at anything valid when it is freed.

(cherry picked from commit 809df89c08)
2024-06-10 18:54:18 +01:00
matt335672
0bef23f217 Fix session list processing
The get_sorted_session_displays() is broken in that it
doesn't produce a sorted list of displays.

The problem is the qsort comparison function which has 2 errors in 4 lines:-
1) The test is the wrong way round (i.e. arg1 < arg2 produces a +ve
   result instead of -ve)
2) Subtracting two unsigned ints in C will never return < 0

The broken function has been masked by other display checks which mean
that it is only visible in a few situations:-
1) Starting two sessions very closely to each other may allocate the
   same display to both sessions.
2) If /tmp is namespaced, the other display checks do not work, and
   more than two sessions cannot be started.

(cherry picked from commit 70f1b685ba)
2024-06-03 09:46:31 +01:00
matt335672
c32180ce5b Bump FreeBSD CI version to 13.3
(cherry picked from commit cbaaf221cd)
2024-06-01 10:35:17 +01:00
Schen
84901958a5 Fix a systemd dependency ("network-online.target")
- Fix a problem that the xrdp.service fail to auto-start when instructed to listen on a specific interface
- By changing the "network.target" systemd dependency to "network-online.target"
- The "network-online.target", in short, means at least one network interface has finished IP level setup.
- The previously used "network.target" is vague and does not provide such guarantee (ref: man systemd.special(7)).
- Which often cause "xrdp.service" fail to auto-start when the service is configured to listen on a specific interface (e.g. in xrdp.ini, "port=tcp://192.168.0.1:3389"). Because the interface may have not finish setting up its IP, when "xrdp.service" starts.

(cherry picked from commit 21e11de157)
2024-05-23 11:41:59 +01:00
matt335672
dcaa31ef16 chansrv FUSE fixes
1) [Regression] If the specified mountpoint is not immediately below an
   existing directory, the directory is not created.
2) The message to ask the user to unmount an existing mounted directory
   has been moved to the right place.

(cherry picked from commit e0a1339b34)
2024-05-22 09:55:01 +01:00
metalefty
763c1c5855
Merge pull request #3069 from metalefty/v0.10-release
Release v0.10.0
2024-05-10 23:11:16 +09:00
Koichiro Iwao
0872f9378f Bump version to 0.10.0 2024-05-10 22:40:01 +09:00
Koichiro Iwao
53e13abef1 Update NEWS 2024-05-10 22:40:01 +09:00
metalefty
8c614cdf9c
Merge pull request #3068 from metalefty/v0.10-update-news
Turn off cache explicitly when fetching NEWS from wiki
2024-05-10 17:58:22 +09:00
Koichiro Iwao
dad7766afc Turn off cache explicitly when fetching NEWS from wiki 2024-05-10 17:36:32 +09:00
metalefty
cc35ac63c9
Merge pull request #3034 from metalefty/v0.10-release
Release v0.10.0-beta.3
2024-04-19 23:43:44 +09:00
Koichiro Iwao
7ea81186c6 Add script to update NEWS from wiki 2024-04-19 11:57:51 +09:00
Koichiro Iwao
3329f60318 Bump version to v0.10.0-beta.3 2024-04-19 11:57:51 +09:00
Koichiro Iwao
492f8b5cf7 Update NEWS
It is still a beta release at the moment so release date is not
determined.
2024-04-19 11:57:47 +09:00
matt335672
0a7e556d7d
Merge pull request #3032 from matt335672/v0_10_update_rfxcodec
[V0.10] Merge updates from librfxcodec
2024-04-18 16:35:34 +01:00
matt335672
cb50f18da9 Merge updates from librfxcodec
1) add SSE2 simd for dwt_shift_rem and diff_count

   make dwt_shift_rem easier to read
   move common rlgr defines to common file
   move common dwt defines to common file

2) Fix 'make distcheck'

3) Fix compiler warnings on tests
2024-04-18 15:47:40 +01:00
matt335672
b45630e879
Merge pull request #3017 from matt335672/cherry_picks_to_v0_10
Cherry picks to v0 10
2024-04-15 20:37:47 +01:00
Jay Sorg
dfa52c1183 format change
(cherry picked from commit 898e1ca135)
2024-04-15 19:26:48 +01:00
Jay Sorg
7030a74ab9 gfx send multiple wire to surface messages when compressed data is larger than max_compressed_bytes
(cherry picked from commit 95bfb349a8)
2024-04-15 19:26:35 +01:00
matt335672
f688e680c9 Simplify allowed system calls for xrdp
- The command 'systemd-analyze syscall-filter' shows that the group
  @system-service added to the xrdp-service SystemCallFilter
  actually includes all of the other listed groups and individual
  services.  Consequently this line can be simplified to just specify
  @system-service.

- (reversion) The SystemCallErrorNumber setting in xrdp.service has been
  removed so that unauthorized system calls cause an immediate process exit.

(cherry picked from commit e0e9177f5e)
2024-04-12 11:16:37 +01:00
matt335672
252243ab6c Fix permissions on user socket directory
The user socket directory needs to be SGID so that they inherit
the group ownnership. Then xrdp can write to them.

(cherry picked from commit 200e4d84f4)
2024-03-27 09:50:27 +00:00
Jay Sorg
9dbe504878 remove per frame log entry when client frame acks is off
(cherry picked from commit 651fcf85b7)
2024-03-27 09:49:57 +00:00
matt335672
02dc01d31e Remove hard-coded version from scripts/run_astyle.sh
This script now works the same way as cppcheck. The version to
be used is specified once in the github CI action

(cherry picked from commit b9fd19e6b5)
2024-03-27 09:49:24 +00:00
matt335672
2ee512ba52 Remove unnecessary '-lrt' from common lib link
The '-lrt' added to the Makefile for the common library appears
to be unnecessary.

- On modern Linuxes, this library has been merged with libc, and the
  supplied library is empty.
- On older ones (e.g. Devuan 4), the library contains routines we
  do not use in xrdp (although we use 'shm_open()' in xorgxrdp).
- On FreeBSD 14 the library contains only mq_*  and timer_* routines
  which, again, are not required.

(cherry picked from commit e821eddb62)
2024-03-27 09:48:53 +00:00
matt335672
40b0eaf455 Improve performance on long fat networks (LFNs)
On Linux, the TCP send buffer size is increased to 32768 if it is less
that this (which it normally is). This however has the effect of disabling
dynamic buffer sizing, leading to a maximum available bandwidth of

max_bandwidth = 262144 (bits) / round_trip_time (secs)

This is not noticeable on a LAN with an RTT of around 0.5ms, but
very noticeable on a WAN with an RTT of 0.25s.

Comments in the config file and manpage in this area are improved, as
is the logging if the parameters are actually set.

(cherry picked from commit b23d6f89d5)
2024-03-27 09:48:16 +00:00
metalefty
fc34c2b4c8
Merge pull request #3007 from metalefty/v0.10-release
Bump version to v0.10.0-beta.2
2024-03-20 23:13:14 +09:00
Koichiro Iwao
a48ea06e9b Bump version to v0.10.0-beta.2 2024-03-20 23:12:25 +09:00
metalefty
04da549942
Merge pull request #3003 from matt335672/v0_10_detect_missing_drdynvc
[V0.10] detect missing drdynvc
2024-03-17 22:50:31 +09:00
matt335672
68f6113430 Load channel config in xrdp_wm_create()
This commit moves the '[Channels]' parsing code for xrdp.ini
from xrdp_wm_init() to an earlier location in xrdp_wm_create().

libxrdp can now check that drdynvc is not disabled before starting it,
and xrdp_wm can disable GFX if virtual channels are not available.
2024-03-15 10:31:58 +00:00
matt335672
84fd2a510b Start the drdynvc channel within xrdp_wm
The responsibility for starting the drdynvc channel is moved out of
libxrdp into the application. This will make it easier to allow the
application to check the channel is enabled before starting it.
2024-03-15 10:31:46 +00:00
metalefty
01d3dedfdf
Merge pull request #2987 from matt335672/fix_freebsd_core
Don't generate a corefile when generating SIGSEGV
2024-03-14 09:12:00 +09:00
matt335672
8e08066bc8 Don't generate a corefile when generating SIGSEGV
One of the tests uses a child process which generates SIGSEGV.
On FreeBSD this generates a corefile by default which breaks
the 'make distcheck' process.
2024-03-09 17:01:40 +00:00
metalefty
ac67abe9b6
Merge pull request #2985 from metalefty/v0.10-release
Release v0.10.0-beta.1
2024-03-10 00:00:14 +09:00
Koichiro Iwao
02c265c5a5 Bump version to v0.10.0-beta.1 2024-03-09 23:53:51 +09:00
Koichiro Iwao
fb2a863d12 Update NEWS
It is still draft because stil a beta release.
2024-03-09 23:53:25 +09:00
metalefty
19b4905018
Merge pull request #2983 from metalefty/v0.10-release-tarball
[v0.10] Add script to make release tarball
2024-03-08 23:26:49 +09:00
metalefty
c5e6c4e117
Merge pull request #2977 from metalefty/v0.10-cherry-pick
[v0.10] cherry picks
2024-03-08 23:22:16 +09:00
Koichiro Iwao
9985737e9b Add script to make release tarball 2024-03-08 22:23:13 +09:00
rowlap
790834a947 Remove duplicate DEBUG output
allow_multimon and new_cursors are printed twice

(cherry picked from commit bf81557cdc)
2024-03-06 17:20:47 +09:00
metalefty
7700fcb1dc
Merge pull request #2957 from metalefty/v0.10-cherry-pick
[v0.10] cherry picks
2024-03-04 09:05:39 +09:00
matt335672
d6cf81a4da Increase GFX output buffer size
Size the GFX output buffer pessimistically based on the largest monitor
in the configuration.

(cherry picked from commit 90e4aca26a)
2024-03-03 10:04:28 +09:00
Koichiro Iwao
ab2430ac76 Suppress some logs when no errors
This outputs per-frame logs when using VNC backend and on login screen.

(cherry picked from commit 0b4150ff48)
2024-03-01 00:06:14 +09:00
rowlap
72d30061b0 Remove tcutils channel from xrdp.ini
According to #1943 tcutils was removed, so update the channel section to match.

(cherry picked from commit 2a0c2a612f)
2024-02-27 22:32:41 +09:00
Derek Schrock
a7115cced2 Fall back to IPv4 if IPv6 capable but don't have an IPv6 address set
When xrdp is built with IPv6 support it will only fall back to IPv4 if
IPv6 is not supported (EAFNOSUPPORT).  However, if the system is IPv6
capable but doesn't have an IPv6 address set (at least inside a FreeBSD
jail) EPROTONOSUPPORT is returned from socket().

(cherry picked from commit 5afbca4954)
2024-02-26 20:57:01 +09:00
matt335672
83f9d4ec17 GFX: Fix disconnect on resize of busy windows
When a resize is underway on a busy X server, it is possible for a
queued EGFX cmd (order #62) to be processed after the decoder has been
deleted. This causes a client disconnect with no useful error message.

(cherry picked from commit 3430b8898c)
2024-02-24 00:52:00 +09:00
matt335672
d0edde791e Migrate github actions to Node 20
Github actions are transitioning to Node 20 ans Node 16 is EOL.

https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20
(cherry picked from commit 4ba026be38)
2024-02-22 22:51:49 +09:00
Koichiro Iwao
99cf0e19f7 Bump copyright year and make easier to bump
(cherry picked from commit ae249c6755)
2024-02-22 22:51:37 +09:00
Koichiro Iwao
9b33d299d0 GFX: Relegate some logs to LOG_LEVEL_DEBUG
(cherry picked from commit 7e305f9e24)
2024-02-22 22:51:14 +09:00
metalefty
c3cb8554b6
Merge pull request #2951 from metalefty/v0.10-monitor-hotplug
[v0.10] Fixes some problems with monitor hotplug
2024-02-21 00:41:30 +09:00
metalefty
12ff5d4814
Merge pull request #2952 from metalefty/v0.10-just-log-image-remotefx
[v0.10] Just log Image RemoteFX codec
2024-02-21 00:38:00 +09:00
Koichiro Iwao
8a1e6f74f7 Just log Image RemoteFX codec 2024-02-21 00:16:56 +09:00
matt335672
d769b402bc GFX: Prevent MM screen being written to the client
In GFX mode, if we're using xorgxrdp, frame updates are send directly
from the client, bypassing the screen buffer in xrdp_mm.

This commit only allows the xrdp_mm screen buffer to be invalidated
if the painter has drawn into it since the module was loaded. This
prevents the unused (and invalid) frame buffer being pushed to the client
in GFX mode with xorgxrdp.
2024-02-21 00:14:26 +09:00
matt335672
ab698c3d58 Clear memory allocated to resized bitmaps
This prevents valgrind errors when resizing the screen to
a larger size on GFX systems.
2024-02-21 00:14:26 +09:00
matt335672
355a71fe6d Prevent EGFX drawing while channel is down
Clear egfx_up as soon as the channel starts to close so that
xrdp_mm_draw_dirty() doesn't send data to a closed channel.
2024-02-21 00:14:26 +09:00
matt335672
ee37eb2803 EGFX: Ignore incoming messages after close sent 2024-02-21 00:14:26 +09:00
matt335672
74c2f7c4a7 Rework xrdp to support new module resize interface
This commit compiles.
2024-02-21 00:14:26 +09:00
matt335672
66a8e93f3c Change to the XUP module for the new resizing interface
Input message 300 to xorgxrdp which communicated a screen size
has been replaced with message 302 which sends a list of monitors
to xorgxrdp. This simplifies the initialisation and resize logic
somewhat, but a compatible version of xorgxrdp must be used
2024-02-21 00:14:26 +09:00
matt335672
9f422cc306 Update VNC module resize functionality
Significant updates for the VNC module:-
1) Support for the new API calls allowing both server and client
   multi-monitor resizes.
2) The s member variable of the vnc_screen_layout structure is no longer
   dynamically allocated.
3) The module server_width and server_height member variables are
   removed as these are just duplicating server_layout.total_width and
   server_layout.total_height.
4) When the server screens are resized, there is no need to restart the
   entire resize state machine as we already know at this point that
   the server supports resizing.
2024-02-21 00:14:26 +09:00
matt335672
dc6ac9758b Update neutrinordp module
Neutrinordp module now compiles with updated monitor resize
interface
2024-02-21 00:14:26 +09:00
matt335672
bfecd1887b Update module interfaces with new calls for resizing
This commit DOES NOT compile.

This change alters these module interface calls:-
1) mod_server_monitor_resize() (Call from xrdp to module). Updated.
2) server_reset() (Call from module to xrdp). Replaced.

The mod_server_monitor_resize() call is updated :-
1) to allow a monitor list to be passed in for a multimon resize
2) with an 'in_progress' return value which tells the caller whether or
   not to expect a callback.

The server_reset() call served two purposes up until now:-
1) To allow a module to resize a single monitor session. There
   is no way to request a multi-monitor resize from the module
2) (with bpp == 0) To signal to the mm resize state machine that
   a server screen resize hsa finished.

This is split into two calls:-
1) client_monitor_resize() to allow a mdule to request a
   multimon resize.
2) server_monitor_resize_done(). This is called by a module
   when a resize is completed.
2024-02-21 00:14:26 +09:00
matt335672
b0a30a3581 Add a client_resize_mode field
This stores what kind of resizing (if any) can be achieved with
a Deactivation-Reactivation sequence.
2024-02-21 00:14:26 +09:00
matt335672
1917b9c747 Fix sending of monitor layout PDU
From [MS-RCPBCGR] 3.3.5.12.1:-

> ...The contents of this PDU SHOULD NOT be compressed.
>
> This PDU MUST NOT be sent to a client that has not indicated support for
> it by setting the RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU flag (0x0040)
> in the earlyCapabilityFlags field of the Client Core Data (section
> 2.2.1.3.2).

Also, 2.2.12.1 specifies the source channel must be zero.

In testing, a compressed monitor layout PDU causes mstsc.exe
to exit with a protocol error.
2024-02-21 00:14:26 +09:00
matt335672
e00236193f Fixes some problems with monitor hotplug
This fixes some monitor hotplug issues with non-GFX codepaths.

1) The server_version_message() was working on an out-of-date
   copy of the client_info. As a result, the X server and the
   window manager did not agree on the number of windows
2) As a result of 1), a memory leak was found in the VNC module.
2024-02-21 00:14:26 +09:00
Koichiro Iwao
6272ae6018 Bump version to v0.9.90, v0.10.0 will be out soon 2024-02-08 22:04:35 +09:00
74 changed files with 3525 additions and 2022 deletions

View File

@ -4,7 +4,7 @@ FreeBSD_task:
SSL: libressl
matrix:
freebsd_instance:
image_family: freebsd-13-2
image_family: freebsd-13-3
prepare_script:
- pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs check imlib2 freetype2 cmocka
- git submodule update --init --recursive

View File

@ -113,7 +113,8 @@ jobs:
--disable-pixman"
CONF_FLAGS_amd64_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame
--enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter
--enable-pixman --with-imlib2 --with-freetype2 --enable-tests"
--enable-pixman --with-imlib2 --with-freetype2 --enable-tests
--enable-x264"
CONF_FLAGS_i386_max: "--enable-ipv6 --enable-jpeg --enable-mp3lame
--enable-opus --enable-rfxcodec --enable-painter
--disable-pixman --with-imlib2 --with-freetype2
@ -132,7 +133,7 @@ jobs:
echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH_${{ matrix.arch }}" >> $GITHUB_ENV
echo "CFLAGS=$CFLAGS_${{ matrix.arch }}" >> $GITHUB_ENV
echo "LDFLAGS=$LDFLAGS_${{ matrix.arch }}" >> $GITHUB_ENV
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: "Install Dependencies"
# See https://github.com/actions/runner-images/issues/7192
run: |
@ -173,9 +174,9 @@ jobs:
id: os
run: echo "image=$ImageOS" >>$GITHUB_OUTPUT
shell: bash
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Cache cppcheck
uses: actions/cache@v3
uses: actions/cache@v4
env:
cache-name: cache-cppcheck
with:
@ -202,9 +203,9 @@ jobs:
id: os
run: echo "image=$ImageOS" >>$GITHUB_OUTPUT
shell: bash
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Cache astyle
uses: actions/cache@v3
uses: actions/cache@v4
env:
cache-name: cache-astyle
with:
@ -213,6 +214,6 @@ jobs:
- run: sudo scripts/install_astyle_dependencies_with_apt.sh
- run: scripts/install_astyle.sh $ASTYLE_REPO $ASTYLE_VER
- name: Format code with astyle
run: scripts/run_astyle.sh
run: scripts/run_astyle.sh -v $ASTYLE_VER
- name: Check code formatting
run: git diff --exit-code

865
NEWS.md
View File

@ -1,651 +1,262 @@
# Release notes for xrdp v0.9.19 (2022/03/17)
# Release notes for xrdp v0.10.1 (2024/07/31)
## General announcements
* Running xrdp and xrdp-sesman on separate hosts is still supported by this release, but is now deprecated. This is not secure. A future release will replace the TCP socket used between these processes with a Unix Domain Socket, and then cross-host running will not be possible.
## New features
* Both inbound and outbound clipboards can now be restricted for text, files or images [Sponsored by @CyberTrust @clear-code and @kenhys] (#2087)
A clipboard bugfix included in this release is sponsored by Krämer Pferdesport GmbH & Co KG. We very much appreciate the sponsorship.
## Bug fixes
* [CVE-2022-23613](https://www.cve.org/CVERecord?id=CVE-2022-23613): Privilege escalation on xrdp-sesman (This fix is also in the out-of-band v0.9.18.1 release)
* The versions of imlib2 used on RHEL 7 and 8 are now detected correctly (#2118)
* Some situations where zombie processes could exist have been resolved (#2146, #2151, #2168)
* Some null-pointer exceptions which can happen in the logging module have been addressed (#2149)
* Some minor logging errors have been corrected (#2152)
* The signal handling in sesman has been reworked to prevent race conditions when a child exits. This has also made it possible to reliably reload the sesman configuration with SIGHUP (#1729, #2168)
## Internal changes
* Versions 0.13 and later of checklib can undefine the pre-processor symbol `HAVE_STDINT_H`. The xrdp tests now build successfully against these versions (#2124)
* OpenSSL packaging changes (#2130):-
- The OpenSSL 3 EVP interface is now fully supported
- When building against OpenSSL 3, an internal implementation of the RC4 cipher is used instead of the implementation from the OpenSSL legacy provider
- The wrapping of the OpenSSL library has been improved which should make it simpler to provide an alternative cryptographic provider in the future, if required
- The logging of TLS/non-TLS security negotiation has been improved
* cppcheck version used for CI bumped to 2.7 (#2140)
* The `s_check()` macro which is easily mis-used has been removed (#2144)
* Status values for the DRDYNVC channel are now available in `libxrdp/xrdp_channel.h`
## Changes for packagers or developers
* On OpenSSL 3 systems, there is now no need to build with the `-Wno-error=deprecated-declarations` flag
## Known issues
* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
-----------------------
# Release notes for xrdp v0.9.18.1 (2022/02/08)
This is a security fix release that includes fixes for the following privilege escalation vulnerability.
* [CVE-2022-23613: Privilege escalation on xrdp-sesman](https://www.cve.org/CVERecord?id=CVE-2022-23613)
Users who uses xrdp v0.9.17 or v0.9.18 are recommended to update to this version.
## Special thanks
Thanks to [Gilad Kleinman](https://github.com/giladkl) reporting the vulnerability and reviewing fix.
-----------------------
# Release notes for xrdp v0.9.18 (2022/01/10)
## General announcements
* Running xrdp and xrdp-sesman on separate hosts is still supported by this release, but is now deprecated. This is not secure. A future release will replace the TCP socket used between these processes with a Unix Domain Socket, and then cross-host running will not be possible.
* Special thanks for @trishume for contributing code to the RFX codec
## New features
* Backgrounds and logos on the login screen can now be zoomed and scaled (#1962)
* Small change for Alpine Linux support (#2005)
* loongarch support (#2057)
* Improved Fail2ban support (#1976)
## Bug fixes
* Logging is improved for security protocol level decisions (#1974, #1975)
* An unnecessary log error message which is always generated when running neutrinordp has been removed (#2016)
* An incorrect development log message has been fixed (#2074)
* Some informational and error messages written to the console on stdout have been removed or replaced with log messages (#2078 #2080)
* Failure to attach to the memory area shared with xorgxrdp is now logged (#2065)
* A regression in the VNC module logging which might cause a connection to drop out has been identified and fixed (#1989)
* Remote drive redirection now works if printer redirection is also requested by the client (#327)
* Some file names could not be copied from the client to the server over the clipboard. This is now fixed (#1992, #1995)
* A config value has been added which allows copy-pasting of files to work with Nautilus for GNOME 3 versions >= 3.29.92 (#1994, #1996)
* Clipboard now works properly when files can't be read (#1997 #2001)
* (xorgxrdp v0.2.18) The screen is fully refreshed after initialising shared memory which should fix black screen problems like #1964
* An incorrect initialisation reported by @qarmin has been fixed (#1909)
* Some minor memory leaks have been fixed (#2014 #2028)
* A hard hang in chansrv when copying files from the remote system has been addressed (#2032)
* Users can now capitalise username and password on the login screen if required (#2061)
* Some failed size checks in the fastpath code with `--enable-devel-streamcheck` have been addressed (#2066,#2070)
* Log level for clipboard restriction has been promoted from DEVEL DEBUG to INFO (#2088)
* A buffer overflow in the RFX codec associated with large screens has been fixed (#2087)
## Internal changes
* Some 64-bit packages are removed during the 32-bit CI build process in an attempt to make this more robust (#1985)
* Minor improvements to error checking and logging for file copy-paste (#1996)
* Now uses cppcheck 2.6 for CI builds (#2008)
* Generated systemd unit files now ignored by git (#2006)
* More internal tests (#2015)
* Some unnecessary files have been removed from the distribution (#2030)
* The `which` command in shell scripts has been replaced with `command -v` (#2067)
* Additional unit tests added for `g_file_get_size()` (#1988)
* A compiler warning with -O3 on gcc 11.1 has been addressed (#2105)
* An unused declaration for xrdp_wm_drdynvc_up has been removed (#2098)
* The SCP V0 code has been unified, which will make it easier to update and replace (#2011)
* Monitor processing unit tests for existing xrdp_sec function have been added (#1932)
* The librfxcodec has been updated as part of #2087, and also to add stack frames to assemble code to assist debugging
## Changes for packagers or developers
* The `--with-imlib2` option has been added. If xrdp is built with imlib2, the login screen supports more image formats for the background and logo, and better quality zooming and scaling (#1962)
## Known issues
* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
-----------------------
# Release notes for xrdp v0.9.17 (2021/08/31)
## General announcements
* Running xrdp and xrdp-sesman on separate hosts is still supported by this release, but is now deprecated. This is not secure. A future release will replace the TCP socket used between these processes with a Unix Domain Socket, and then cross-host running will not be possible.
## New features
* The IP address, port, and user name of NeutrinoRDP Proxy connection are logged in xrdp.log - these connections may not have a sesman log to use (#1873)
* The performance settings for NeutrinoRDP can be now configured (#1903)
* Support for Alpine Linux in startwm.sh (#1965)
* clipboard: log file transfer for the purpose of audit (#1954)
* Client's Keyboard layout now can be overridden by xrdp configuration for debugging purposes (#1952)
## Bug fixes
* PAM_USER environment variable is not set when using pam_exec module (#1882)
* Allow common channel settings to be overridden for modules as well as chansrv (#1899)
* The text only-copy/paste interface for the VNC module (used only when chansrv is not active) has been improved (#1900)
* The unsupported `tcutils` utility has been removed (#1943)
* The quality of TLS logging has been improved (#1926)
* Keyboard information is now passed correctly through NeuutrinoRDP, and can be overridden if required (#1934)
* A message is now logged in the sesman log for unsuccessful login attempts detailing the user used (#1947)
## Internal changes
* astyle formatting is now checked during CI builds (#1879)
* Generalise development build options, and add --enable-devel-streamcheck (#1887)
* Now uses cppcheck 2.5 for CI builds (#1938)
* The SCP protocol is now using a standard `struct trans` for messaging rather than its own thing (#1925)
## Changes for packagers or developers
* The `--enable-xrdpdebug` developer option has been replaced with finer-grained `--enable-devel-*` options. Consequently, specifying `--enable-xrdpdebug` is now an error (#1913)
## Known issues
* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
-----------------------
# Release notes for xrdp v0.9.16 (2021/04/30)
## New features
* On-the-fly resolution change now supported for Xvnc and Xorg (#448, #1820) - thanks to @Nexarian for this significant first contribution. See the following YouTube video for a demo.
* [Windows] https://youtu.be/cZ0ebieZHeA
* [Mac] https://youtu.be/6kfAkyLUgFY
* xrdp can now use key algorithms other than RSA for TLS (#1776)
* Do not spit on the console 2nd stage (inspired by Debian) #1762
* Unified and improved logging (#1742, #1767, #1802, #1806, #1807, #1826, #1843) - thanks to @aquesnel for this detailed work.
* Other logging level fixes (#1864)
* chansrv can now work on `DISPLAY=:0` so it can be used with x11vnc/Vino/etc sessions (#1849)
## Bug fixes
* Fix some regressions in sesman auth modules (#1769)
* Minor manpage fixes (#1787)
* Fix TS_PLAY_SOUND_PDU_DATA to set the correct frequency and duration (#1793)
* Fix password leakage to logs in NeutrinoRDP module (#1872) - thanks to @TOMATO-ONE for reporting.
## Internal changes
* cppcheck version for CI bumped to 2.4 (#1771, #1836)
* FreeBSD version for CI bumped to 12-2 (#1804)
* Support for check unit test framework added (#1843, #1860)
* FreeBSD FUSE module now compiles under CI but needs additional work (#1856)
* Compilation support added for additional Debian platforms (#1818)
* Refactoring:-
* Confusing preprocessor macro USE_NOPAM replaced with USE_PAM (#1800)
* Window manager states in xrdp executable now use symbolic constants instead of numbers (#1803)
* Documentation improvements
* KRDC added to client list (#1817)
* Platform support tier added (#1822)
* README file revised (#1863)
* Don't install test+development executables by default (#1858)
## Changes for packagers
These changes are likely to impact operating system package builders and those building xrdp from source.
* (#1843, #1860) This release introduces an additional optional compile-time dependency on the `check` unit test framework. The dependency is recommended when packaging for compile-time tests.
* (#1858) The executables `memtest` and `tcp_proxy` are no longer copied to the sbin directory on a package install.
## Known issues
* On-the-fly resolution change requires the Microsoft Store version of Remote Desktop client but sometimes crashes on connect (#1869)
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
-----------------------
# Release notes for xrdp v0.9.15 (2020/12/28)
## New features
* Allow token sign in without autologon for SSO (#1667 #1668)
* Norwegian keyboard support (#1675)
* Improved config support for chansrv (#1635)
* Unified chansrv, sesman and libxrdp logging (#1633 #1708 #1738) - thanks to @aquesnel
* Support SUSE move to /usr/etc (#1702)
* Parameters may now be specified for user-specified shell (#1270 #1695)
* xrdp executables now allow alternative config files to be specified with -c (#1588 #1650 #1651)
* sesrun improvements (#1741)
* Drive redirection location can now be specified (#1048)
* Now compiles on RISC-V (#1761)
## Bug fixes
* Additional buffer overflow checks (#1662)
* FUSE support now builds on 32-bit platforms (#1682)
* genkeymap array size conflict fixed (#1691)
* Buffering issue with neutrinordp over a slow link fixed (#1608 1634)
* Various documentation fixes (#1704 #1741 #1755 #1759)
* Prevent PAM info message from causing authentication failure (#1727)
* Cosmetic fixes for minor issues (#1751 #1755 #1749)
* Try harder to clean up socket files on session exit (#1740 #1756)
* xrdp-chansrv become defunct in docker while file copy (#1658)
## Internal changes
* Compilation warnings with newer compilers (#1659 #1680)
* Continuation Integration checks on 32-bit platforms now include FUSE support (#1682)
* Continuation Integration builds now default to the Ubuntu Focal platform (#1666)
* FUSE type tidy-ups (#1686)
* Switch from Travis CI to GitHub Actions (#1728 #1732)
* Easier to set up console logging for utilities (#1711)
-----------------------
# Release notes for xrdp v0.9.14 (2020/08/31)
## New features
* VNC multi-monitor support if you are using a suitable Xvnc server #1343
* VNC sessions now resize by default on reconnection if you are using a suitable Xvnc server #1343
* Support Slackware for PAM #1558 #1560
* Support Programmer Dvorak Keyboard #1663
**[HEADS UP]** The VNC changes are significant. They described in more detail on the following wiki page.
* [Xvnc backend : Multi monitor and resize support](https://github.com/neutrinolabs/xrdp/wiki/Xvnc-backend-:-Multi-monitor-and-resize-support)
## Bug fixes
* Fix odd shift key behavior (workaround) #397 #1522
* Fix Xorg path in the document for Arch Linux #1448 #1529
* Fix Xorg path in the document for CentOS 8 #1646 #1647
* Fix internal username/password buffer is smaller than RDP protocol specification #1648 #1653
* Fix possible memory out-of-bounds accesses #1549
* Fix memory allocation overflow #1557
* Prevent chansrv input channels being scanned during a server reset #1595
* Ignore TS_MULTIFRAGMENTUPDATE_CAPABILITYSET from client if fp disabled #1593
* Minor manpage fixes #1611
## Other changes
* CI error fixes
* Introduce cppcheck
## Known issues
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
# Release notes for xrdp v0.9.13.1 (2020/06/30)
This is a security fix release that includes fixes for the following local buffer overflow vulnerability.
* [CVE-2020-4044: Local users can perform a buffer overflow attack against the xrdp-sesman service and then impersonate it](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-4044)
This update is recommended for all xrdp users.
## Special thanks
Thanks to [Ashley Newson](https://github.com/ashleynewson) reporting the vulnerability and reviewing fix.
-----------------------
# Release notes for xrdp v0.9.13 (2020/03/11)
This release is an intermediate bugfix release. The previous version v0.9.12 has some regressions on drive redirection.
## Bug fixes (drive redirection related)
* Fix chansrv crashes with segmentation fault (regression in #1449) #1487
* Drive redirection now supports Guacamole client #1505 #1507
* Prevent a coredump in the event of a corrupted file system #1507
* Resolve double-free in `chansrv_fuse` #1469
## Bug fixes (other)
* Fix the issue `xrdp --version | less` will show empty output #1471 #1472
* Fix some warnings found by cppcheck #1479 #1481 #1484 #1485
## Other changes
* Add FreeBSD CI test #1466
* Move Microsoft-defined constants into separate includes #1470
* Perform cppcheck during CI test #1493
* Support mousex button 8/9 #1478
## Known issues
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.12 (2019/12/28)
## Bug fixes
* Fix "The log reference is NULL" error when sesman startup #1425
* Fix behavior when shmem_id changes #1439
* Make vsock config accept -1 for cid and port #1441
* Cleanup refresh rect and check stream bounds #1437
* Significant improvements in drive redirection #1449
* Fix build on macOS Catalina #1462
## Other changes
* Proprietary microphone redirection via rdpsnd is now default off
RDP compatible microphone redirection is on instead #1427
* Skip connecting to chansrv when no channels enabled #1393
* Add openSUSE's pam rules #1442
* Do not terminate xrdp daemon when caught SIGHUP #1319
## Known issues
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
# Release notes for xrdp v0.9.11 (2019/08/19)
## New features
* Suppress output (do not draw screen when client window is minimized) #1330
* Audio input (microphone) redirection compatible with [MS-RDPEAI](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeai/d04ffa42-5a0f-4f80-abb1-cc26f71c9452) #1369
* Now xrdp can listen on more than one port #1124 #1366
## Bug fixes
* Fix the issue audio redirection sometimes sounds with long delay #1363
* Check term event for more responsive shutdown #1372
## Known issues
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.11 (2019/08/19)
## New features
* Suppress output (do not draw screen when client window is minimized) #1330
* Audio input (microphone) redirection compatible with [MS-RDPEAI](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpeai/d04ffa42-5a0f-4f80-abb1-cc26f71c9452) #1369
* Now xrdp can listen on more than one port #1124 #1366
## Bug fixes
* Fix the issue audio redirection sometimes sounds with long delay #1363
* Check term event for more responsive shutdown #1372
## Known issues
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.10 (2019/04/18)
## Special thanks
Thank you for matt335672 contributing to lots of improvements in drive redirection!
## New features
* Restrict outbound (server->client) clipboard transfer, configured in `sesman.ini` #1298
## Bug fixes
* Fix the issue libscp v1 not setting width but height twice #1293
* Fix the issue reconnecting to session causes duplicate drive entries in fuse fs #1299
* Fix default_wm and reconnect_sh refer wrong path after sesman caught SIGUP #1315 #1331
* Shutdown xrdp more responsively #1325
* Improve remote file lookup in drive redirection #996 #1327
* Overwriting & appending to existing files is are now supported #1327
## Other changes
* Add Danish Keyboard #1290
* Put xrdp- prefix to some executables appear in man page #1313
* Replace some URLs from SF.net to xrdp.org #1313
## Known issues
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.9 (2018/12/25)
## Release cycle
From the next release, release cycle will be changed from quarterly to every
4 months. xrdp will be released in April, August, December.
## New features
* Disconnection by idle timeout (requires xorgxrdp v0.2.9 or later) #1227
* Glyph cache v2 (fixes no font issue on iOS/macOS/Android client) #367 #1235
## Bug fixes
* Fix xrdp-chansrv crashes caused in drive redirection #1202 #1225
* Fix build with FDK AAC v2 #1257
* Do not enable RemoteApp if the INFO_RAIL flag is not set (RDP-RDP proxy) #1253
## Other changes
* Add Spanish Latin Amarican keyboard #1237 #1240 #1244
* Dynamic channel improvements #1222 #1224
* Remove some deprecated sesman session types #1232
* Refactoring and cleanups
## Known issues
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.8 (2018/09/25)
## Deprecation notice
We removed TLSv1 and TLSv1.1 from the default config. The current default is TLSv1.2
and TLSv1.3. Users can whenever re-enable these early TLS versions by editing xrdp.
To use TLSv1.3, OpenSSL or LibreSSL must support TLSv1.3. You can know the OpenSSL
or LibreSSL version by `xrdp --version` command that compiled with xrdp.
## Other topics
Pulseaudio modules has been removed from xrdp source tree since it is actually
independent and not part of xrdp. The repository has been moved to:
https://github.com/neutrinolabs/pulseaudio-module-xrdp
If you want to use audio redirection, make sure install the module separately.
## New features
* Add TLSv1.3 support #1193
## Bug fixes
* Ensure unmount redirected drive on fatal X error #1140
## Other changes
* Show more helpful message if xrdp-dis failed #1206
* Pass pulse socket name via environment variable #1198
* Fix xrdp's log path in man page #1168
# Release notes for xrdp v0.9.7 (2018/06/29)
## Deprecation notice
x11rdp has been removed from xrdp reposiory and stored in the separate repository.
Checkout [x11rdp repository](https://github.com/neutrionlabs/x11rdp) if you still need x11rdp.
In most cases, [xorgxrdp](https://github.com/neutrinolabs/xorgxrdp) can replace x11rdp.
## Bug fixes
* Fix endianness detection on ppc64el #1082
* Fix a bug xrdp file copy slow #1112 #1132
* Copy the PAM session environment for the reconnect script #1120
* Accept fullpath for DefaultWindowManager, ReconnectScript #1147
## Other changes
* Add PAM support for Arch Linux #1078
* Show OpenSSL version to '--version' CLI option #1096
* Separate x11rdp from xrdp repository #1104
* Support sesrun start xorgxrdp sessions #1108
* Show configure summary when configure is done #1126 #1134 #1137
* Less spit on the console when sesman starts #1142
* Fix memory leaks #1146
* Separate rc script for FreeBSD into xrdp and xrdp-sesman #1153
* Improve documents and helps
## Known issues
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.6 (2018/03/26)
## Compatibility notice
Exclamation mark (`!`) has been removed from comment out symbol of config files.
Use number sign (`#`) or semicolon (`;`) instead. As a result of this change, now
you can use exclamation mark as config value such as in `tls_ciphers`.
```
tls_ciphers=HIGH:!aNULL:!eNULL:!EXPORT:!RC4
```
See also: #1033
## macOS supports
Please note that xrdp still doesn't support macOS officially so far.
However, a volunteer is working on macOS compatibility.
* Generate dylibs for macOS #1015
* Add PAM support for macOS #1021
## Bug fixes
* Make listen check before daemon fork #988
* Fix xrdp sometimes become zombie processes #1000
* Include hostname in sesman password file name #1006 #1007 #1076
* Fix default startwm.sh to use bash explicitly #1009 #1049
* Fix the issue FreeBSD doesn't acknowledge terminated sessions #1016 #1030
## Other changes
* Add Swiss French keyboard #1053
* Improve perfect forward secrecy, explicitly enable ECDHE/DHE #1024 #1052 #1063
* Lots of leak fixes, cleanups and refactoring
## Known issues
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
-----------------------
# Release notes for xrdp v0.9.5 (2017/12/27)
Please consider sponsoring or making a donation to the project if you like xrdp. We accept financial contributions via [Open Collective](https://opencollective.com/xrdp-project). Direct donations to each developer via GitHub Sponsors are also welcomed.
## Security fixes
* Fix local denial of service [CVE-2017-16927](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16927) #958 #979
* Unauthenticated RDP security scan finding / partial auth bypass (no CVE). Thanks to @txtdawg for reporting this.
## New features
* Add a new log level TRACE more verbose than DEBUG #835 #944
* SSH agent forwarding via RDP #867 #868 FreeRDP/FreeRDP#4122
* Support horizontal wheel properly #928
* GFX-RFX lossy compression levels are now selectable depending on connection type on the client (#3183, backport of #2973)
## Bug fixes
* A regression in the code for creating the chansrv FUSE directory has been fixed (#3088, backport of #3082)
* Fix a systemd dependency ("network-online.target") (#3088, backport of #3086)
* A problem in session list processing which could result in incorrect display assignments has been fixed (#3088, backport of #3103)
* A problem in GFX resizing which could lead to a SEGV in xrdp has been fixed (#3088, backport of #3107)
* A problem with the US Dvorak keyboard layout has been resolved (#3088, backport of #3112)
* A regression bug when pasting image to LibreOffice has been fixed [Sponsored by Krämer Pferdesport GmbH & Co KG] (#3102 #3120)
* Fix a regression when the server tries to negotiate GFX when max_bpp is not high enough (#3118 #3122)
* Fix a GFX multi-monitor screen placing issue on minimise/maximize (#3075 #3127)
* Fix an issue some files are not included properly in release tarball (#3149 #3150)
* Using 'I' in the session selection policy now works correctly (#3167 #3171)
* A potential name buffer overflow in the redirector has been fixed [no security implications] (#3175)
* Screens wider than 4096 pixels should now be supported (#3083)
* An unnecessary licensing exchange during connection setup has been removed. This was causing problems for FIPS-compliant clients (#3132 backport of #3143)
* Avoid use of hard-coded sesman port #895
* Workaround for corrupted display with Windows Server 2008 using NeutrinoRDP #869
* Fix glitch in audio redirection by AAC #910 #936
* Implement vsock support #930 #935 #948
* Avoid 100% CPU usage on SSL accept #956
## Internal changes
* FreeBSD CI bumped to 13.3 (#3088, backport of #3104)
## Other changes
* Add US Dvorak keyboard #929
* Suppress some misleading logs #964
* Add Finnish keyboard #972
* Add more user-friendlier description about Xorg config #974
* Renew pulseaudio document #984 #985
* Lots of cleanups and refactoring
## Changes for users
* None since v0.10.0.
* If moving from v0.9.x, read the v0.10.0 release note.
## Known issues
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
## Changes for packagers or developers
* None since v0.10.0.
* If moving from v0.9.x, read the v0.10.0 release note.
-----------------------
# Release notes for xrdp v0.9.4 (2017/09/28)
# Release notes for xrdp v0.10.0 (2024/05/10)
## New features
* Accept prefill credentials in base64 form #153 #811
* Indroduce AAC encoder to audio redirection (requires Windows 10 client)
This section notes changes since the [v0.10 branch](#branch-v010) was created.
## Bugfixes
* Fix ocasional SEGV in drive redirection #838
* Fix client's IP addresses in xrdp-sesman.log are always logged as `0.0.0.0` #878 #882
* Fix `ls_background_image` didn't accept full path #776 #853
* Fix misuse of hidelogwindow #414 #876
* Fix WTSVirtualChannelWrite return code #859
* Fix no longer needed socket files remained in the socket dir #812 #831
* Make creating socket path a bit more robust #823
## General announcements
The biggest news of this release is that [Graphic Pipeline Extension](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegfx/da5c75f9-cd99-450c-98c4-014a496942b0) also called GFX in short has been supported. xrdp v0.10 with GFX achieves more frame rates and less bandwidth compared to v0.9. There is a significant performance improvement especially if the client is Windows 11's mstsc.exe or Microsoft Remote Desktop for Mac. GFX H.264/AVC 444 mode and hardware-accelerated encoding are not supported in this version yet.
## Other changes
* Add Belgian keyboard #858
* Add a PAM file for FreeBSD #824
* Several refactorings and cosmetic changes
GFX implementation in xrdp is sponsored by an enterprise sponsor. @CyberTrust is also one of the sponsors. We very much appreciate the sponsorship. It helped us to accelerate xrdp development and land GFX earlier!
## Known issues
* Windows 10 (1703) shows black blank screen in RemoteFX mode
* This issue is already fixed at Insider Preview build 16273
Please consider sponsoring or making a donation to the project if you like xrdp. We accept financial contributions via [Open Collective](https://opencollective.com/xrdp-project). Direct donations to each developer via GitHub Sponsors are also welcomed.
-----------------------
## Highlights
This section describes the most user-visible new or changed features in xrdp since v0.9.19. See [Branch v0.10](#branch-v010) for all changes relative to v0.9.19.
# Release notes for xrdp v0.9.3.1 (2017/08/16)
This release fixes a trivial packaging issue #848 occurred in v0.9.3. The issue only affects systemd systems. This release is principally for distro packagers or users who compile & install xrdp from source.
Users who running xrdp on these systems don't need to upgrade from v0.9.3 to v0.9.3.1.
* Linux systems without systemd
* non-Linux systems such as BSD operating systems
-----------------------
# Release notes for xrdp v0.9.3 (2017/07/15)
## New features
* Log user-friendly messages when certificate/privkey is inaccessible
## Bugfixes
* Now sesman sets mandatory LOGNAME environment variable #725
* Now sesman ensures socket directory present #801
* Exit with failure status if port already in use #644
* Eliminate some hard coded paths
* Fix glitches with IPv4 struct initialization #803
* Fix some keyboard layout integration (UK, Spanish)
* Fix handle OS when IPv6 disabled #714
* Fix issues around systemd session #778
* Fix protocol error when 32 bit color and non RemoteFX session #737 #804
* Fix sesadmin shows error when no sessions #797
* Fix TLS spins 100% CPU #728
* Fix Xvnc backend disconnects when some data copied to clipboard #755
* Pick up the first section if given section(domain) doesn't match anything #750
## Other changes
* Change xrdp-chansrv log path to include display number
* Optimize startwm.sh for SUSE
* Several cleanups and optimizations
## Known issues
* Windows 10 (1703) shows black blank screen in RemoteFX mode
-----------------------
# Release notes for xrdp v0.9.2 (2017/03/30)
## New features
* RemoteFX codec support is now enabled by default.
* Bitmap updates support is now enabled by default.
* TLS ciphers suites and version is now logged.
* Connected computer name is now logged.
* Switched to Xorg (xorgxrdp) as the default backend now.
* Miscellaneous RemoteFX codec mode improvements.
* Socket directory is configurable at the compile time.
## Bugfixes
* Parallels client for MacOS / iOS can now connect (audio redirection must be disabled on client or xrdp server though).
* MS RDP client for iOS can now connect using TLS security layer.
* MS RDP client for Android can now connect to xrdp.
* Large resolutions (4K) can be used with RemoteFX graphics.
* Multiple RemoteApps can be opened throguh NeutrinoRDP proxy.
* tls_ciphers in xrdp.ini is not limited to 63 chars anymore, it's variable-length.
* Fixed an issue where tls_ciphers were ignored and rdp security layer could be used instead.
* Kill disconnected sessions feature is working with Xorg (xorgxrdp) backend.
* Miscellaneous code cleanup and memory issues fixes.
-----------------------
# Release notes for xrdp v0.9.1 (2016/12/21)
## New features
* New xorgxrdp backend using existing Xorg with additional modules
* Improvements to X11rdp backend
* Support for IPv6 (disabled by default)
* Initial support for RemoteFX Codec (disabled by default)
* Support for TLS security layer (preferred over RDP layer if supported by the client)
* Support for disabling deprecated SSLv3 protocol and for selecting custom cipher suites in xrdp.ini
* Support for bidirectional fastpath (enabled in both directions by default)
* Support clients that don't support drawing orders, such as MS RDP client for Android, ChromeRDP (disabled by default)
* More configurable login screen
* Support for new virtual channels:
* rdpdr: device redirection
* rdpsnd: audio output
* cliprdr: clipboard
* xrdpvr: xrdp video redirection channel (can be used along with NeutrinoRDP client)
* Support for disabling virtual channels globally or by session type
* Allow to specify the path for backends (Xorg, X11rdp, Xvnc)
* Added files for systemd support
* Multi-monitor support
* xrdp-chansrv stroes logs in `${XDG_DATA_HOME}/xrdp` now
* Added GFX support with multi-monitor support (including monitor hot plug/unplug) (#2256 #2338 #2595 #2879 #2891 #2911 #2929 #2933)
* Touchpad inertial scrolling (#2364, #2424). Thanks to new contributor @seflerZ
* New look of login screen (#2366)
* Scaled login screen on higher DPI monitors (#2341, #2427, #2435)
* This feature works automatically when monitor DPI information is sent by the client (i.e. a full-screen session)
* Native platform tools are now provided to manipulate .fv1 format font files.
* The format of the date and time in the log file has been changed to ISO 8601 with milliseconds (#2386 #2541)
* xrdp-sesman now supports a `--reload` switch to allow for the configuration to be changed when sessions are active (#2416)
## Security fixes
* User's password could be recovered from the Xvnc password file
* X11 authentication was not used
None
## New features
* If the client announces support for the Image RemoteFX codec it is logged (back-port of #2946)
## Bug fixes
* Fix some monitor hotplug issues (#2951)
* GFX: Fix disconnect on resize of busy windows (#2962 #2957)
* Fall back to IPv4 if IPv6 capable but don't have an IPv6 address set (#2967 #2957)
* Remove tcutils channel from xrdp.ini (#2970 #2957)
* Don't generate a corefile when generating SIGSEGV during unit testing (#2987)
* If the drdynvc static channel isn't available, disable GFX gracefully (#3003)
* A buffer misconfiguration which affects performance on high bandwidth, high latency links has been addressed (cherry-pick of #2910)
* A permissions fix for the socketdir update in #2731 has been issued (cherry-pick of #3011)
## Internal changes
* Adjust log level not too verbose (#2954 #2972 #2957)
* Migrate GitHub actions to Node 20 (#2955 #2957)
* Bump copyright year and make easier to bump (#2956 #2957)
* Remove duplicate DEBUG output (#2976 #2977)
* Add script to make release tarball (#2983)
* Syscall filter for xrdp updated (cherry-pick of #3017)
* GFX memory usage for large screens is greatly improved (cherry-pick of #3013)
* librfxcodec SSE2 performance improvements (#3032)
## Known issues
* On-the-fly resolution change with the Microsoft Store version of Remote Desktop client sometimes crashes on connect (#1869)
* xrdp's login dialog is not relocated at the center of the new resolution after on-the-fly resolution change happens (#1867)
## Changes for users
* If moving from v0.9.x, read the '[User changes](#user-changes)' for the v0.10 branch below.
## Changes for packagers or developers
* If moving from v0.9.x, read the '[User changes](#user-changes)' and '[Significant changes for packagers or developers section](#significant-changes-for-packagers-or-developers)' sections for the v0.10 branch below.
-----------------------
# Branch v0.10
This branch was forked from development on 2024-02-08 in preparation for testing and release of v0.10.1.
The changes in this section are relative to version v0.9.19 of xrdp.
## User changes
* The [x11rdp](/neutrinolabs/x11rdp) X server is no longer supported. Users will need to move to xorgxrdp (#2489)
* Running xrdp and xrdp-sesman on separate hosts is no longer supported.
* There are some changes to `xrdp.ini` and `sesman.ini` which break backwards compatibility. In particular:-
* `sesman.ini/Globals/ListenAddress` is not longer used. A warning message is generated if this is found in the configuration, but the configuration will continue to work.
* `sesman.ini/Globals/ListenPort` is now a path to a socket, or an unqualified socket in a default directory. If the old default value `3350` is found, a warning is generated and a default value is used instead. The configuration will continue to work.
* The `ip` and `pamsessionmng` parameters are no longer required in sections in `xrdp.ini` to locate the sesman port. Unnecessary usages of this parameter now generate warnings. The configuration will continue to work.
* The 'C' field for the session allocation policy has been replaced with `Policy=Separate`. This field is has a very specific specialist purpose, and will not be used by the vast majority of users. The renaming makes it much clearer what is happening (#2251 #2239). Any uses of the 'C' field will generate warnings, **and the configuration will require updating**
* The format of the date and time in the log file has been changed to ISO 8601 with milliseconds (#2386 #2541)
Users are urged to heed any generated configuration warnings and update their configurations. Later major versions of xrdp may remove these warnings, or introduce other behaviours for the affected parameters.
## Security fixes
This branch provides following important security fixes reported by [Team BT5 (BoB 11th)](https://github.com/Team-BT5). We appreciate their great help with making and reviewing patches for them.
* [CVE-2022-23468](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23468)
* [CVE-2022-23477](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23477)
* [CVE-2022-23478](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23478)
* [CVE-2022-23479](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23479)
* [CVE-2022-23480](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23480)
* [CVE-2022-23481](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23481)
* [CVE-2022-23483](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23483)
* [CVE-2022-23482](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23482)
* [CVE-2022-23484](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23484)
* [CVE-2022-23493](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23493)
The following issue was reported by [@gafusss](https://github.com/gafusss)
* [CVE-2023-40184](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-40184)
Other security fixes:-
* [CVE-2023-42822: Unchecked access to font glyph info](https://www.cve.org/CVERecord?id=CVE-2023-42822)
## New features
* Added GFX support with multi-monitor support (including monitor hot plug/unplug) (#2256 #2338 #2595 #2879 #2891 #2911 #2929 #2933)
* Add Ulalaca that enables remote access to macOS's native screen (developed by [team unstablers](https://unstabler.pl/))
* Ulalaca is still heavy in development, not suitable for production use yet
* `sessionbroker` and `sessionprojector` are also required, see also [README](https://github.com/unstabler/ulalaca)
* Scaled login screen on higher DPI monitors (#2341, #2427, #2435)
* This feature works automatically when monitor DPI information is sent by the client (i.e. a full-screen session)
* Native platform tools are now provided to manipulate .fv1 format font files.
* Touchpad inertial scrolling (#2364, #2424). Thanks to new contributor @seflerZ
* New look of login screen (#2366)
* Record codec GUID to identify unknown codc (#2401)
* OpenSuSE Tumbleweed move to /usr/lib/pam.d is now supported in the installation scripts (#2413)
* xrdp-sesman now supports a `--reload` switch to allow for the configuration to be changed when sessions are active (#2416)
* VNC backend session now supports extra mouse buttons 6, 7 and 8 (#2426)
* `LogFile=<stdout>` redirects log to stdout, which is useful for debugging (#2407)
* xrdp-sesrun and xrdp-sesadmin can now authenticate automatically as the logged-in user without a password (#2472)
* Empty passwords are no longer automatically passed though to sesman for authentication (#2487)
* BSD setusercontext() is now supported (#2225, #2473)
* The FUSE mount path can now be qualified with the display name or display string (#2528)
* Debian: use startup command from /usr/share/xsession if DISPLAY_SESSION is set (#2522)
* The directory where PAM configuration files is installed can now be set with `--with-pamconfdir` (#2552 #2557)
* Some classes of 'blue screen' failures have been addressed:-
* X server failures are now reported as a separate error from window manager (#2592)
* sesman failures are reported immediately (#2640)
* Allow longer UserWindowManager strings (#2651)
* Some changes have been made to made it easier to implement AppArmor support in the future (#2265):-
* `g_file_open()` has been replaced with `g_file_open_ro()` and `g_file_open_rw()` calls
* the starting of the X server with no-new-privileges can now be disabled by the administrator
* On systemd-based systems, system call filtering is used to restrict the system calls that the xrdp process can make (#2697 #2719)
* GNOME and KDE keyrings should now be supported out-of-the-box on Debian and Arch (#2776)
* Implement vsock support for FreeBSD #2798
* Side buttons on some mice are now supported by NeutrinoRDP (#2864). Thanks to new contributor @naruhito for this patch.
* Support for the Elbrus E2K architecture (#2872). Thanks to new contributor @r-a-sattarov for this patch.
* Just log Image RemoteFX codec (#2946)
## Bug fixes
* A missing directive to link libxrdpapi with libcommon has been added (#2185)
* Some sesman config warning messages could be lost. This has now been fixed (#2198)
* Moving sesman to a Unix domain socket fixes a number of issues related to firewalls and Ipv4/v6 connectivity issues (#1596 #1805 #1855)
* Secondary groups are now added correctly on Linux from /etc/security/group.conf (#1978).
* The `--disable-static` switch for `configure` now works (#1467 #2257)
* Windows RDS compatibility has been improved, so some old clients (e.g. Wyse Sx0) can now be used again with xrdp in non-TLS mode (#2166)
* PAM_RHOST is now set for the PAM stack (#2251, #392)
* A minor spacing issue in a sesman log message has been fixed (#2282)
* MSTSC crashes when resolution is changed by maximizing on a different monitor (#2291 #2300)
* Fix swapped `require_credentials`/`enable_token_login` config options in xrdp.ini manpage (#2391)
* Passwords are no longer left on the heap in sesman (#1599 #2438)
* Set permissions on pcsc socket dir to owner only (#2454 #2459)
* The Kerberos authentication module has been reworked and tested (#2453)
* Minor documentation fixes (#2481 #2581)
* The correct message is now generated when the session limit is reached (#642)
* sesman now returns better information to xrdp when session creation fails (#909, #1921)
* MaxLoginRetry limit for sesman now works (#1739)
* On systems where the same user can have multiple names, the correct session is now reconnected (#1823)
* On FreeBSD, the correct peer is now logged for xorgxrdp connections (#146)
* In some situations, xrdp sessions can be bootstrapped on system startup (#1303)
* Don't try to listen on the scard socket if it isn't there (#2504)
* Fix some noise of MP3/AAC audio redirection and add some parameters to tweak sounds (#2519 #2608)
* Memory management fixes to list module (#2536 #2575)
* Session is not now started until X server is fully active (#2492)
* Fix potential NULL dereferences in chansrv (#2573)
* An erroneous free in the smartcard handling code has been removed (#2607)
* An unnecessary 'check.h' include was removed which prevented compilation on Arch systems (#2649)
* No user session created with xrdp and pam_systemd_home account module (#1684)
* Homedir gets not correctly created at first login (#350)
* pam_setcred never returns xrdp-sesman is hung (#1323)
* chansrv should no longer hang occasionally in developer builds on session exit (#2145)
* Environment variables set by PAM modules are no longer restricted to around 250 characters (#2711)
* Checking group membership should now work better on systems using directory services (#2806 #2815)
* Pasting more than 32K characters of text to the clipboard now succeeds (#1839 #2810)
* An incompatibility with FreeRDP 2.11.2 in the drive redirector has been fixed (#2834 #2838)
* Unicode bugs have been fixed (#942 #2603)
## Internal changes
* SCP (Sesman Control Protocol) has been refactored from separate V0 and V1 protocols to a simplified V2 protocol running on top of a new library 'libipm' (#2163).
* libipm provides a way to pass file descriptors between processes (#2494)
* SCP connections are now only supported on top of Unix Domain Sockets (#2207 #2235 #2247)
* Monitor processing logic, which was in two places, has now been unified (#1895 #2301)
* Simplifications to transport connect logic (#2204)
* The fields in `struct trans` and `struct xrdp_client_info` used for storing client addressing information have been simplified (#2251)
* A couple of string utility functions have been added to parse character strings like the one used for the session allocation policy (#2251)
* cppcheck version used for CI bumped to 2.13.0 (#2520 #2737 #2785 #2886). Note that #2785 greatly increases cppcheck scan times.
* cppcheck install script no longer installs z3 for cppcheck >= 2.8 (#2782)
* The physical desktop size information sent from the client is now recorded in more situations (#2310)
* Simple maintenance improvements (#2354)
* An opaque type is now used for the auth_info handle used by the sesman auth module (#2362)
* CI updates to cope with github upgrades (#2394)
* GUIDs created for new sessions are now compliant with RFC4122 random UUIDs (#2420)
* Some 'magic numbers' have been replaced with constants (#2421)
* FreeBSD CI now runs a 'make check' (#2490)
* FreeBSD CI now runs on FreeBSD 13.2 (#2621 #2896)
* Some logging improvements on audio redirection (#2537)
* Extra executables : waitforx (#2492 #2591 #2586) xrdp-sesexec (#2644)
* The poll() system call now replaces select() for monitoring file descriptors (#2497 #2568)
* sigaction() now replaces signal() for increased portability (#2813)
* Other portability changes (#2909)
* Some extra convenience functions were added for handling lists of strings (#2576)
* `g_malloc`, `g_free`, `g_memset`, `g_memcpy`, and `g_memmove` are now macros. These should not be used in new code (#2609)
* config_ac.h is now used consistently (#2667)
* as mentioned above, `g_file_open()` has been replaced with `g_file_open_ro()` and `g_file_open_rw()` calls
* The separate fifo packages in the common directory and chansrv have now been merged (#2686)
* Unicode conversions are now provided by explicit functions rather than relying on C library `mbstowcs()`/`wcstombs()` functions (#2794)
* Some test timeouts have been increased for slow CI machines (#2901)
* `g_obj_wait()` can now take a zero timeout (#2904)
* POSIX shared memory is now used to communicate with `xorgxrdp` rather than System-V shared memory (#2709 #2786 #2889)
## Significant changes for packagers or developers
* The libscp.so shared library is replaced with libipm.so
* A new shared library libsesman.so contains shared code for sesman and related executables (#2601)
* The default setting for `--with-socketdir` is now `/var/run/xrdp` rather than `/tmp/.xrdp`. The new setting works for installations where `/tmp` is polyinstantiated ( see #1482 for more details)
* The permissions of the socketdir have changed from 1777 to 755 (owned by root). Within this directory are the sesman socket and user-specific directories. The user-specific directories store the session sockets used by each user (#2731).
It is recommended not to use the same `--with-socketdir` setting for v0.9.x and v0.10.x packages as the differing permissions can cause problems on package downgrades. See #3066 for an example of where this can be a problem.
* Passing `--disable-static` to `configure` prevents unused static libraries being installed by `make install`.
* The `simple.c` example xrdpapi program has been updated to work with logging changes, and is now built as part of the CI (#2276)
* If the `xrdp-mkfv1` utility is to be built, the switch `--with-freetype2` must be passed to `./configure`.
* Minimum supported autoconf version is now 2.69 (#2408)
* Add xrdp-sesman.system to distributed files (#2466 #2467)
* A developer-only utility to exercise the auth module selected at configure time has been provided (#2453)
* Extra executables have been added to this release in pkglibexecdir
* The default systemd unit files have been changed to no longer fork (#2672)

View File

@ -71,6 +71,6 @@ libcommon_la_SOURCES = \
$(PIXMAN_SOURCES)
libcommon_la_LIBADD = \
-lpthread -lrt \
-lpthread \
$(OPENSSL_LIBS) \
$(DLOPEN_LIBS)

View File

@ -58,6 +58,10 @@
#define SEC_TAG_CLI_4 0xc004 /* CS_CLUSTER? */
#define SEC_TAG_CLI_MONITOR 0xc005 /* CS_MONITOR */
#define SEC_TAG_CLI_MONITOR_EX 0xc008 /* CS_MONITOR_EX */
#define SEC_TAG_SRV_INFO 0x0c01 /* SC_CORE */
#define SEC_TAG_SRV_CRYPT 0x0c02 /* SC_SECURITY */
#define SEC_TAG_SRV_CHANNELS 0x0c03 /* SC_NET? */
/* Client Core Data: colorDepth, postBeta2ColorDepth (2.2.1.3.2) */
#define RNS_UD_COLOR_4BPP 0xCA00
@ -74,6 +78,7 @@
/* Client Core Data: earlyCapabilityFlags (2.2.1.3.2) */
#define RNS_UD_CS_WANT_32BPP_SESSION 0x0002
#define RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU 0x0040
#define RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL 0x0100
/* Client Core Data: connectionType (2.2.1.3.2) */
@ -158,9 +163,16 @@
#define RDP5_NO_CURSOR_SHADOW 0x20
#define RDP5_NO_CURSORSETTINGS 0x40 /* disables cursor blinking */
/* LICENSE_PREAMBLE (2.2.1.12.1.1) */
#define ERROR_ALERT 0xff
#define PREAMBLE_VERSION_3_0 0x03
/* LICENSE_BINARY_BLOB (2.2.1.12.1.2) */
#define LICENCE_TAG_USER 0x000f /* BB_CLIENT_USER_NAME_BLOB */
#define LICENCE_TAG_HOST 0x0010 /* BB_CLIENT_MACHINE_NAME_BLOB */
#define BB_ERROR_BLOB 0x0004
/* LICENSE_ERROR_MESSAGE (2.2.1.12.1.3) */
#define STATUS_VALID_CLIENT 0x00000007
#define ST_NO_TRANSITION 0x00000002
/* Maps to generalCapabilitySet in T.128 page 138 */
@ -448,17 +460,14 @@
#define RDP_DATA_PDU_LOGON 38
#define RDP_DATA_PDU_FONT2 39
#define RDP_DATA_PDU_DISCONNECT 47
#define PDUTYPE2_MONITOR_LAYOUT_PDU 55
/* TS_SECURITY_HEADER: flags (2.2.8.1.1.2.1) */
/* TODO: to be renamed */
#define SEC_CLIENT_RANDOM 0x0001 /* SEC_EXCHANGE_PKT? */
#define SEC_EXCHANGE_PKT 0x0001
#define SEC_ENCRYPT 0x0008
#define SEC_LOGON_INFO 0x0040 /* SEC_INFO_PKT */
#define SEC_LICENCE_NEG 0x0080 /* SEC_LICENSE_PKT */
#define SEC_TAG_SRV_INFO 0x0c01 /* SC_CORE */
#define SEC_TAG_SRV_CRYPT 0x0c02 /* SC_SECURITY */
#define SEC_TAG_SRV_CHANNELS 0x0c03 /* SC_NET? */
#define SEC_INFO_PKT 0x0040
#define SEC_LICENSE_PKT 0x0080
#define SEC_LICENSE_ENCRYPT_CS 0x0280
/* Slow-Path Input Event: messageType (2.2.8.1.1.3.1.1) */
/* TODO: to be renamed */

View File

@ -378,6 +378,7 @@ g_tcp_socket(void)
{
switch (errno)
{
case EPROTONOSUPPORT: /* if IPv6 is supported, but don't have an IPv6 address */
case EAFNOSUPPORT: /* if IPv6 not supported, retry IPv4 */
LOG(LOG_LEVEL_INFO, "IPv6 not supported, falling back to IPv4");
rv = (int)socket(AF_INET, SOCK_STREAM, 0);
@ -433,23 +434,6 @@ g_tcp_socket(void)
}
}
option_len = sizeof(option_value);
if (getsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *)&option_value,
&option_len) == 0)
{
if (option_value < (1024 * 32))
{
option_value = 1024 * 32;
option_len = sizeof(option_value);
if (setsockopt(rv, SOL_SOCKET, SO_SNDBUF, (char *)&option_value,
option_len) < 0)
{
LOG(LOG_LEVEL_ERROR, "g_tcp_socket: setsockopt() failed");
}
}
}
return rv;
}

View File

@ -67,6 +67,23 @@ struct display_size_description
unsigned int session_height;
};
enum client_resize_mode
{
CRMODE_NONE,
CRMODE_SINGLE_SCREEN,
CRMODE_MULTI_SCREEN
};
enum xrdp_capture_code
{
CC_SIMPLE = 0,
CC_SUF_A16 = 1,
CC_SUF_RFX = 2,
CC_SUF_A2 = 3,
CC_GFX_PRO = 4,
CC_GFX_A2 = 5
};
/**
* Information about the xrdp client
*
@ -163,7 +180,7 @@ struct xrdp_client_info
int mcs_early_capability_flags;
int max_fastpath_frag_bytes;
int capture_code;
int pad0; /* unused */
int capture_format;
char certificate[1024];
@ -218,6 +235,12 @@ struct xrdp_client_info
int large_pointer_support_flags;
int gfx;
// Can we resize the desktop by using a Deactivation-Reactivation Sequence?
enum client_resize_mode client_resize_mode;
int pad1; /* unused; unicode_input_state */
enum xrdp_capture_code capture_code;
};
enum xrdp_encoder_flags
@ -237,6 +260,6 @@ enum xrdp_encoder_flags
/* yyyymmdd of last incompatible change to xrdp_client_info */
/* also used for changes to all the xrdp installed headers */
#define CLIENT_INFO_CURRENT_VERSION 20230425
#define CLIENT_INFO_CURRENT_VERSION 20240514
#endif

View File

@ -1,7 +1,8 @@
# Process this file with autoconf to produce a configure script
AC_PREREQ([2.69])
AC_INIT([xrdp], [0.9.80], [xrdp-devel@googlegroups.com])
AC_INIT([xrdp], [0.10.1], [xrdp-devel@googlegroups.com])
AC_DEFINE([VERSION_YEAR], 2024, [Copyright year])
AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in)
AM_INIT_AUTOMAKE([1.7.2 foreign])
AC_CONFIG_MACRO_DIR([m4])
@ -166,7 +167,10 @@ AC_ARG_ENABLE(pixman, AS_HELP_STRING([--enable-pixman],
[Use pixman library (default: no)]),
[], [enable_pixman=no])
AM_CONDITIONAL(XRDP_PIXMAN, [test x$enable_pixman = xyes])
AC_ARG_ENABLE(x264, AS_HELP_STRING([--enable-x264],
[Use x264 library (default: no)]),
[], [enable_x264=no])
AM_CONDITIONAL(XRDP_X264, [test x$enable_x264 = xyes])
AC_ARG_ENABLE(painter, AS_HELP_STRING([--disable-painter],
[Do not use included painter library (default: no)]),
[], [enable_painter=yes])
@ -466,6 +470,8 @@ fi
AS_IF( [test "x$enable_pixman" = "xyes"] , [PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.1.0)] )
AS_IF( [test "x$enable_x264" = "xyes"] , [PKG_CHECK_MODULES(XRDP_X264, x264 >= 0.3.0)] )
# checking for TurboJPEG
if test "x$enable_tjpeg" = "xyes"
then
@ -623,6 +629,7 @@ echo " fdkaac $enable_fdkaac"
echo " jpeg $enable_jpeg"
echo " turbo jpeg $enable_tjpeg"
echo " rfxcodec $enable_rfxcodec"
echo " x264 $enable_x264"
echo " painter $enable_painter"
echo " pixman $enable_pixman"
echo " fuse $enable_fuse"

View File

@ -1,9 +1,3 @@
if USE_FREETYPE2
MKFV1_MAN = xrdp-mkfv1.8
else
MKFV1_MAN =
endif
man_MANS = \
xrdp-dis.1 \
sesman.ini.5 \
@ -15,10 +9,13 @@ man_MANS = \
xrdp-sesadmin.8 \
xrdp-sesman.8 \
xrdp-sesrun.8 \
xrdp-dumpfv1.8 \
$(MKFV1_MAN)
xrdp-dumpfv1.8
EXTRA_DIST = $(man_MANS:=.in)
EXTRA_DIST = xrdp-mkfv1.8.in $(man_MANS:=.in)
if USE_FREETYPE2
man_MANS += xrdp-mkfv1.8
endif
SUBST_VARS = sed \
-e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \

View File

@ -133,9 +133,12 @@ by \fBseparator\fP.
.TP
\fBrequire_credentials\fP=\fI[true|false]\fP
If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP requires clients to include username and
password initial connection phase. In other words, xrdp doesn't allow clients to show login
screen if set to true. If not specified, defaults to \fBfalse\fP.
If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP requires clients
to include username and password initial connection phase. In other
words, xrdp doesn't allow clients to show login screen if set to true.
It follows that an incorrect password will cause the login to immediately
fail without displaying the login screen. If not specified, defaults
to \fBfalse\fP.
.TP
\fBsecurity_layer\fP=\fI[tls|rdp|negotiate]\fP
@ -177,7 +180,9 @@ If set to \fB1\fP, \fBtrue\fP or \fByes\fP, no buffering will be performed in th
\fBtcp_send_buffer_bytes\fP=\fIbuffer_size\fP
.TP
\fBtcp_recv_buffer_bytes\fP=\fIbuffer_size\fP
Specify send/recv buffer sizes in bytes. The default value depends on operating system.
Specify send/recv buffer sizes in bytes. The default value depends on
the operating system. It is recommended not to set these on systems with
dynamic TCP buffer sizing
.TP
\fBtls_ciphers\fP=\fIcipher_suite\fP

View File

@ -2,7 +2,7 @@
Description=xrdp daemon
Documentation=man:xrdp(8) man:xrdp.ini(5)
Requires=xrdp-sesman.service
After=network.target xrdp-sesman.service
After=network-online.target xrdp-sesman.service
[Service]
Type=exec
@ -10,9 +10,7 @@ EnvironmentFile=-@sysconfdir@/sysconfig/xrdp
EnvironmentFile=-@sysconfdir@/default/xrdp
ExecStart=@sbindir@/xrdp $XRDP_OPTIONS --nodaemon
SystemCallArchitectures=native
SystemCallFilter=@basic-io @file-system @io-event @ipc @network-io @process
SystemCallFilter=@signal @system-service ioctl madvise sysinfo uname
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
[Install]
WantedBy=multi-user.target

@ -1 +1 @@
Subproject commit ab9b65cee1d96eefe154de721fb375f7a4d3946a
Subproject commit c6b41afa6986d5e6df18778a342b407cae40e1b5

View File

@ -1136,43 +1136,10 @@ libxrdp_orders_send_font(struct xrdp_session *session,
}
/*****************************************************************************/
/* Note : if this is called on a multimon setup, the client is resized
* to a single monitor */
int EXPORT_CC
libxrdp_reset(struct xrdp_session *session,
unsigned int width, unsigned int height, int bpp)
libxrdp_reset(struct xrdp_session *session)
{
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_reset:");
if (session->client_info != 0)
{
struct xrdp_client_info *client_info = session->client_info;
/* older client can't resize */
if (client_info->build <= 419)
{
return 0;
}
/* if same (and only one monitor on client) don't need to do anything */
if (client_info->display_sizes.session_width == width &&
client_info->display_sizes.session_height == height &&
client_info->bpp == bpp &&
(client_info->display_sizes.monitorCount == 0 || client_info->multimon == 0))
{
return 0;
}
client_info->display_sizes.session_width = width;
client_info->display_sizes.session_height = height;
client_info->display_sizes.monitorCount = 0;
client_info->bpp = bpp;
client_info->multimon = 0;
}
else
{
LOG(LOG_LEVEL_ERROR, "libxrdp_reset: session->client_info is NULL");
return 1;
}
/* this will send any lingering orders */
if (xrdp_orders_reset((struct xrdp_orders *)session->orders) != 0)
@ -1439,6 +1406,23 @@ libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
return 1;
}
/*****************************************************************************/
int
libxrdp_drdynvc_start(struct xrdp_session *session)
{
struct xrdp_rdp *rdp;
struct xrdp_sec *sec;
struct xrdp_channel *chan;
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_drdynvc_start:");
rdp = (struct xrdp_rdp *) (session->rdp);
sec = rdp->sec_layer;
chan = sec->chan_layer;
return xrdp_channel_drdynvc_start(chan);
}
/*****************************************************************************/
int
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
@ -1801,6 +1785,19 @@ libxrdp_send_session_info(struct xrdp_session *session, const char *data,
static void
sanitise_extended_monitor_attributes(struct monitor_info *monitor_layout)
{
if (monitor_layout->physical_width == 0
&& monitor_layout->physical_width == 0
&& monitor_layout->orientation == 0
&& monitor_layout->desktop_scale_factor == 0
&& monitor_layout->device_scale_factor == 0)
{
/* Module expects us to provide defaults */
monitor_layout->orientation = ORIENTATION_LANDSCAPE;
monitor_layout->desktop_scale_factor = 100;
monitor_layout->device_scale_factor = 100;
return;
}
/* if EITHER physical_width or physical_height are
* out of range, BOTH must be ignored.
*/
@ -1891,16 +1888,16 @@ libxrdp_process_monitor_stream(struct stream *s,
{
uint32_t num_monitor;
uint32_t monitor_index;
struct monitor_info monitors[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS];
struct monitor_info *monitor_layout;
struct xrdp_rect all_monitors_encompassing_bounds = {0};
int got_primary = 0;
int monitor_struct_stream_check_bytes;
const char *monitor_struct_stream_check_message;
LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:");
if (description == NULL)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "libxrdp_process_monitor_stream: description was"
LOG_DEVEL(LOG_LEVEL_ERROR,
"libxrdp_process_monitor_stream: description was"
" null. Valid pointer to allocated description expected.");
return SEC_PROCESS_MONITORS_ERR;
}
@ -1948,7 +1945,7 @@ libxrdp_process_monitor_stream(struct stream *s,
" from [MS-RDPEDISP] 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT.";
}
description->monitorCount = num_monitor;
memset(monitors, 0, sizeof(monitors[0]) * num_monitor);
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
{
@ -1960,7 +1957,8 @@ libxrdp_process_monitor_stream(struct stream *s,
return SEC_PROCESS_MONITORS_ERR;
}
monitor_layout = description->minfo + monitor_index;
monitor_layout = &monitors[monitor_index];
if (full_parameters != 0)
{
in_uint32_le(s, monitor_layout->flags);
@ -2026,8 +2024,6 @@ libxrdp_process_monitor_stream(struct stream *s,
in_uint32_le(s, monitor_layout->desktop_scale_factor);
in_uint32_le(s, monitor_layout->device_scale_factor);
sanitise_extended_monitor_attributes(monitor_layout);
/*
* 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT
*/
@ -2056,130 +2052,10 @@ libxrdp_process_monitor_stream(struct stream *s,
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
}
}
if (monitor_index == 0)
{
all_monitors_encompassing_bounds.left = monitor_layout->left;
all_monitors_encompassing_bounds.top = monitor_layout->top;
all_monitors_encompassing_bounds.right = monitor_layout->right;
all_monitors_encompassing_bounds.bottom = monitor_layout->bottom;
}
else
{
all_monitors_encompassing_bounds.left =
MIN(monitor_layout->left,
all_monitors_encompassing_bounds.left);
all_monitors_encompassing_bounds.top =
MIN(monitor_layout->top,
all_monitors_encompassing_bounds.top);
all_monitors_encompassing_bounds.right =
MAX(all_monitors_encompassing_bounds.right,
monitor_layout->right);
all_monitors_encompassing_bounds.bottom =
MAX(all_monitors_encompassing_bounds.bottom,
monitor_layout->bottom);
}
if (monitor_layout->is_primary == TS_MONITOR_PRIMARY)
{
got_primary = 1;
}
}
if (!got_primary)
{
/* no primary monitor was set,
* choose the leftmost monitor as primary.
*/
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
{
monitor_layout = description->minfo + monitor_index;
if (monitor_layout->left
== all_monitors_encompassing_bounds.left
&& monitor_layout->top
== all_monitors_encompassing_bounds.top)
{
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
break;
}
}
}
/* set wm geometry if the encompassing area is well formed.
Otherwise, log and return an error.
*/
if (all_monitors_encompassing_bounds.right
> all_monitors_encompassing_bounds.left
&& all_monitors_encompassing_bounds.bottom
> all_monitors_encompassing_bounds.top)
{
description->session_width =
all_monitors_encompassing_bounds.right
- all_monitors_encompassing_bounds.left + 1;
description->session_height =
all_monitors_encompassing_bounds.bottom
- all_monitors_encompassing_bounds.top + 1;
}
else
{
LOG(LOG_LEVEL_ERROR, "libxrdp_process_monitor_stream:"
" The area encompassing the monitors is not a"
" well-formed rectangle. Received"
" (top: %d, left: %d, right: %d, bottom: %d)."
" This will prevent initialization.",
all_monitors_encompassing_bounds.top,
all_monitors_encompassing_bounds.left,
all_monitors_encompassing_bounds.right,
all_monitors_encompassing_bounds.bottom);
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
}
/* Make sure virtual desktop size is OK
* 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR)
*/
if (description->session_width
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH
|| description->session_width
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH
|| description->session_height
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT
|| description->session_height
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT)
{
LOG(LOG_LEVEL_ERROR,
"libxrdp_process_monitor_stream: Client supplied virtual"
" desktop width or height is invalid."
" Allowed width range: min %d, max %d. Width received: %d."
" Allowed height range: min %d, max %d. Height received: %d",
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH,
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH,
description->session_width,
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT,
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT,
description->session_width);
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
}
/* keep a copy of non negative monitor info values for xrdp_wm usage */
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
{
monitor_layout = description->minfo_wm + monitor_index;
g_memcpy(monitor_layout,
description->minfo + monitor_index,
sizeof(struct monitor_info));
monitor_layout->left =
monitor_layout->left - all_monitors_encompassing_bounds.left;
monitor_layout->top =
monitor_layout->top - all_monitors_encompassing_bounds.top;
monitor_layout->right =
monitor_layout->right - all_monitors_encompassing_bounds.left;
monitor_layout->bottom =
monitor_layout->bottom - all_monitors_encompassing_bounds.top;
}
return 0;
return libxrdp_init_display_size_description(
num_monitor, monitors, description);
}
/*****************************************************************************/
@ -2283,6 +2159,163 @@ libxrdp_process_monitor_ex_stream(struct stream *s,
return 0;
}
/*****************************************************************************/
int
libxrdp_init_display_size_description(
unsigned int num_monitor,
const struct monitor_info *monitors,
struct display_size_description *description)
{
unsigned int monitor_index;
struct monitor_info *monitor_layout;
struct xrdp_rect all_monitors_encompassing_bounds = {0};
int got_primary = 0;
/* Caller should have checked this, so don't log an error */
if (num_monitor > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
{
return SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS;
}
description->monitorCount = num_monitor;
for (monitor_index = 0 ; monitor_index < num_monitor; ++monitor_index)
{
monitor_layout = &description->minfo[monitor_index];
*monitor_layout = monitors[monitor_index];
sanitise_extended_monitor_attributes(monitor_layout);
if (monitor_index == 0)
{
all_monitors_encompassing_bounds.left = monitor_layout->left;
all_monitors_encompassing_bounds.top = monitor_layout->top;
all_monitors_encompassing_bounds.right = monitor_layout->right;
all_monitors_encompassing_bounds.bottom = monitor_layout->bottom;
}
else
{
all_monitors_encompassing_bounds.left =
MIN(monitor_layout->left,
all_monitors_encompassing_bounds.left);
all_monitors_encompassing_bounds.top =
MIN(monitor_layout->top,
all_monitors_encompassing_bounds.top);
all_monitors_encompassing_bounds.right =
MAX(all_monitors_encompassing_bounds.right,
monitor_layout->right);
all_monitors_encompassing_bounds.bottom =
MAX(all_monitors_encompassing_bounds.bottom,
monitor_layout->bottom);
}
if (monitor_layout->is_primary == TS_MONITOR_PRIMARY)
{
if (got_primary)
{
// Already got one - don't have two
monitor_layout->is_primary = 0;
}
else
{
got_primary = 1;
}
}
}
if (!got_primary)
{
/* no primary monitor was set,
* choose the leftmost monitor as primary.
*/
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
{
monitor_layout = description->minfo + monitor_index;
if (monitor_layout->left
== all_monitors_encompassing_bounds.left
&& monitor_layout->top
== all_monitors_encompassing_bounds.top)
{
monitor_layout->is_primary = TS_MONITOR_PRIMARY;
break;
}
}
}
/* set wm geometry if the encompassing area is well formed.
Otherwise, log and return an error.
*/
if (all_monitors_encompassing_bounds.right
> all_monitors_encompassing_bounds.left
&& all_monitors_encompassing_bounds.bottom
> all_monitors_encompassing_bounds.top)
{
description->session_width =
all_monitors_encompassing_bounds.right
- all_monitors_encompassing_bounds.left + 1;
description->session_height =
all_monitors_encompassing_bounds.bottom
- all_monitors_encompassing_bounds.top + 1;
}
else
{
LOG(LOG_LEVEL_ERROR, "libxrdp_init_display_size_description:"
" The area encompassing the monitors is not a"
" well-formed rectangle. Received"
" (top: %d, left: %d, right: %d, bottom: %d)."
" This will prevent initialization.",
all_monitors_encompassing_bounds.top,
all_monitors_encompassing_bounds.left,
all_monitors_encompassing_bounds.right,
all_monitors_encompassing_bounds.bottom);
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
}
/* Make sure virtual desktop size is OK
* 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR)
*/
if (description->session_width
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH
|| description->session_width
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH
|| description->session_height
> CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT
|| description->session_height
< CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT)
{
LOG(LOG_LEVEL_ERROR,
"libxrdp_init_display_size_description: Calculated virtual"
" desktop width or height is invalid."
" Allowed width range: min %d, max %d. Width received: %d."
" Allowed height range: min %d, max %d. Height received: %d",
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH,
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH,
description->session_width,
CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT,
CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT,
description->session_width);
return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP;
}
/* keep a copy of non negative monitor info values for xrdp_wm usage */
for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index)
{
monitor_layout = description->minfo_wm + monitor_index;
*monitor_layout = description->minfo[monitor_index];
monitor_layout->left =
monitor_layout->left - all_monitors_encompassing_bounds.left;
monitor_layout->top =
monitor_layout->top - all_monitors_encompassing_bounds.top;
monitor_layout->right =
monitor_layout->right - all_monitors_encompassing_bounds.left;
monitor_layout->bottom =
monitor_layout->bottom - all_monitors_encompassing_bounds.top;
}
return 0;
}
/*****************************************************************************/
int EXPORT_CC
libxrdp_planar_compress(char *in_data, int width, int height,

View File

@ -437,6 +437,10 @@ int
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type);
int
xrdp_rdp_send_data_from_channel(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type, int channel_id,
int compress);
int
xrdp_rdp_send_fastpath(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type);
int

View File

@ -24,6 +24,7 @@
#include "xrdp_rail.h"
struct list;
struct monitor_info;
/* struct xrdp_client_info moved to xrdp_client_info.h */
@ -195,8 +196,7 @@ libxrdp_orders_send_font(struct xrdp_session *session,
struct xrdp_font_char *font_char,
int font_index, int char_index);
int
libxrdp_reset(struct xrdp_session *session,
unsigned int width, unsigned int height, int bpp);
libxrdp_reset(struct xrdp_session *session);
int
libxrdp_orders_send_raw_bitmap2(struct xrdp_session *session,
int width, int height, int bpp, char *data,
@ -241,6 +241,8 @@ int
libxrdp_disable_channel(struct xrdp_session *session, int channel_id,
int is_disabled);
int
libxrdp_drdynvc_start(struct xrdp_session *session);
int
libxrdp_drdynvc_open(struct xrdp_session *session, const char *name,
int flags, struct xrdp_drdynvc_procs *procs,
int *chan_id);
@ -346,4 +348,21 @@ int EXPORT_CC
libxrdp_process_monitor_ex_stream(struct stream *s,
struct display_size_description *description);
/**
* Convert a list of monitors into a full description
*
* Monitor data is sanitised during the conversion
*
* @param num_monitor Monitor count (> 0)
* @param monitors List of monitors
* @param[out] description Display size description
*
* @return 0 if the data is processed, non-zero if there is an error.
*/
int
libxrdp_init_display_size_description(
unsigned int num_monitor,
const struct monitor_info *monitors,
struct display_size_description *description);
#endif

View File

@ -48,6 +48,7 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self)
struct stream *s;
uint32_t i;
struct display_size_description *description;
int rv = 0;
make_stream(s);
init_stream(s, 8192);
@ -74,14 +75,13 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self)
s_mark_end(s);
if (xrdp_rdp_send_data(self, s, 0x37) != 0)
{
free_stream(s);
return 1;
}
// [MS-RDPBCGR]
// - 2.2.12.1 - ...the pduSource field MUST be set to zero.
// - 3.3.5.12.1 - The contents of this PDU SHOULD NOT be compressed
rv = xrdp_rdp_send_data_from_channel(self, s,
PDUTYPE2_MONITOR_LAYOUT_PDU, 0, 0);
free_stream(s);
return 0;
return rv;
}
/*****************************************************************************/
@ -120,6 +120,45 @@ xrdp_caps_process_general(struct xrdp_rdp *self, struct stream *s,
return 0;
}
/*****************************************************************************/
static int
xrdp_caps_process_bitmap(struct xrdp_rdp *self, struct stream *s,
int len)
{
/* [MS-RDPBCGR] 2.2.7.1.2 */
int desktopResizeFlag;
if (len < 14 + 2)
{
LOG(LOG_LEVEL_ERROR, "Not enough bytes in the stream: "
"len 16, remaining %d", len);
return 1;
}
in_uint8s(s, 14);
in_uint16_le(s, desktopResizeFlag);
/* Work out what kind of client resizing we can do from the server */
int early_cap_flags = self->client_info.mcs_early_capability_flags;
if (desktopResizeFlag == 0)
{
self->client_info.client_resize_mode = CRMODE_NONE;
LOG(LOG_LEVEL_INFO, "Client cannot be resized by xrdp");
}
else if ((early_cap_flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) == 0)
{
self->client_info.client_resize_mode = CRMODE_SINGLE_SCREEN;
LOG(LOG_LEVEL_INFO, "Client supports single-screen resizes by xrdp");
}
else
{
self->client_info.client_resize_mode = CRMODE_MULTI_SCREEN;
LOG(LOG_LEVEL_INFO, "Client supports multi-screen resizes by xrdp");
}
return 0;
}
/*****************************************************************************/
/*
* Process [MS-RDPBCGR] TS_ORDER_CAPABILITYSET (2.2.7.1.3) message.
@ -603,6 +642,12 @@ xrdp_caps_process_codecs(struct xrdp_rdp *self, struct stream *s, int len)
g_memcpy(self->client_info.h264_prop, s->p, i1);
self->client_info.h264_prop_len = i1;
}
/* other known codec but not supported yet */
else if (g_memcmp(codec_guid, XR_CODEC_GUID_IMAGE_REMOTEFX, 16) == 0)
{
LOG(LOG_LEVEL_INFO, "xrdp_caps_process_codecs: Image RemoteFX(%s), codec id [%d], properties len [%d]",
codec_guid_str, codec_id, codec_properties_length);
}
else
{
LOG(LOG_LEVEL_WARNING, "xrdp_caps_process_codecs: unknown(%s), codec id [%d], properties len [%d]",
@ -760,7 +805,8 @@ xrdp_caps_process_confirm_active(struct xrdp_rdp *self, struct stream *s)
break;
case CAPSTYPE_BITMAP:
LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
"capabilitySetType = CAPSTYPE_BITMAP - Ignored");
"capabilitySetType = CAPSTYPE_BITMAP");
xrdp_caps_process_bitmap(self, s, len);
break;
case CAPSTYPE_ORDER:
LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
@ -1331,8 +1377,11 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self)
return 1;
}
/* send Monitor Layout PDU for dual monitor */
if (self->client_info.display_sizes.monitorCount > 0 &&
/* send Monitor Layout PDU for multi-monitor */
int early_cap_flags = self->client_info.mcs_early_capability_flags;
if ((early_cap_flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) != 0 &&
self->client_info.display_sizes.monitorCount > 0 &&
self->client_info.multimon == 1)
{
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_caps_send_demand_active: sending monitor layout pdu");

View File

@ -752,46 +752,63 @@ xrdp_channel_drdynvc_send_capability_request(struct xrdp_channel *self)
int
xrdp_channel_drdynvc_start(struct xrdp_channel *self)
{
int index;
int count;
struct mcs_channel_item *ci;
struct mcs_channel_item *dci;
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: drdynvc_channel_id %d", self->drdynvc_channel_id);
int rv = 0;
LOG_DEVEL(LOG_LEVEL_INFO,
"xrdp_channel_drdynvc_start: drdynvc_channel_id %d",
self->drdynvc_channel_id);
if (self->drdynvc_channel_id != -1)
{
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_channel_drdynvc_start: already started");
return 0;
}
dci = NULL;
count = self->mcs_layer->channel_list->count;
for (index = 0; index < count; index++)
{
ci = (struct mcs_channel_item *)
list_get_item(self->mcs_layer->channel_list, index);
if (ci != NULL)
{
if (g_strcasecmp(ci->name, "drdynvc") == 0)
{
dci = ci;
}
}
}
if (dci != NULL)
{
self->drdynvc_channel_id = (dci->chanid - MCS_GLOBAL_CHANNEL) - 1;
LOG_DEVEL(LOG_LEVEL_DEBUG,
"Initializing Dynamic Virtual Channel with channel id %d",
self->drdynvc_channel_id);
xrdp_channel_drdynvc_send_capability_request(self);
LOG_DEVEL(LOG_LEVEL_INFO,
"xrdp_channel_drdynvc_start: already started");
}
else
{
LOG(LOG_LEVEL_WARNING,
"Dynamic Virtual Channel named 'drdynvc' not found, "
"channel not initialized");
int index;
int count;
struct mcs_channel_item *ci;
struct mcs_channel_item *dci;
dci = NULL;
count = self->mcs_layer->channel_list->count;
for (index = 0; index < count; index++)
{
ci = (struct mcs_channel_item *)
list_get_item(self->mcs_layer->channel_list, index);
if (ci != NULL)
{
if (g_strcasecmp(ci->name, DRDYNVC_SVC_CHANNEL_NAME) == 0)
{
dci = ci;
break;
}
}
}
if (dci == NULL)
{
LOG(LOG_LEVEL_WARNING, "Static channel '%s' not found.",
DRDYNVC_SVC_CHANNEL_NAME);
rv = -1;
}
else if (dci->disabled)
{
LOG(LOG_LEVEL_WARNING, "Static channel '%s' is disabled.",
DRDYNVC_SVC_CHANNEL_NAME);
rv = -1;
}
else
{
self->drdynvc_channel_id = (dci->chanid - MCS_GLOBAL_CHANNEL) - 1;
LOG_DEVEL(LOG_LEVEL_DEBUG, DRDYNVC_SVC_CHANNEL_NAME
"Initializing Dynamic Virtual Channel with channel id %d",
self->drdynvc_channel_id);
xrdp_channel_drdynvc_send_capability_request(self);
}
}
return 0;
if (rv != 0)
{
LOG(LOG_LEVEL_WARNING, "Dynamic channels will not be available");
}
return rv;
}
/*****************************************************************************/

View File

@ -585,11 +585,13 @@ xrdp_rdp_send(struct xrdp_rdp *self, struct stream *s, int pdu_type)
}
/*****************************************************************************/
/* Send a [MS-RDPBCGR] Data PDU with for the given pduType2 with the headers
/* Send a [MS-RDPBCGR] Data PDU for the given pduType2 from
* the specified source with the headers
added and data compressed */
int
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type)
xrdp_rdp_send_data_from_channel(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type, int channel_id,
int compress)
{
int len;
int ctype;
@ -614,7 +616,8 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
clen = len;
tocomplen = pdulen - 18;
if (self->client_info.rdp_compression && self->session->up_and_running)
if (compress && self->client_info.rdp_compression &&
self->session->up_and_running)
{
mppc_enc = self->mppc_enc;
if (compress_rdp(mppc_enc, (tui8 *)(s->p + 18), tocomplen))
@ -643,7 +646,8 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
else
{
LOG_DEVEL(LOG_LEVEL_TRACE,
"xrdp_rdp_send_data: compress_rdp failed, sending "
"xrdp_rdp_send_data_from_channel: "
"compress_rdp failed, sending "
"uncompressed data. type %d, flags %d",
mppc_enc->protocol_type, mppc_enc->flags);
}
@ -652,11 +656,11 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
/* TS_SHARECONTROLHEADER */
out_uint16_le(s, pdulen); /* totalLength */
out_uint16_le(s, pdutype); /* pduType */
out_uint16_le(s, self->mcs_channel); /* pduSource */
out_uint16_le(s, channel_id); /* pduSource */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding header [MS-RDPBCGR] TS_SHARECONTROLHEADER "
"totalLength %d, pduType.type %s (%d), pduType.PDUVersion %d, "
"pduSource %d", pdulen, PDUTYPE_TO_STR(pdutype & 0xf),
pdutype & 0xf, ((pdutype & 0xfff0) >> 4), self->mcs_channel);
pdutype & 0xf, ((pdutype & 0xfff0) >> 4), channel_id);
/* TS_SHAREDATAHEADER */
out_uint32_le(s, self->share_id);
@ -673,13 +677,26 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_rdp_send_data: xrdp_sec_send failed");
LOG(LOG_LEVEL_ERROR, "xrdp_rdp_send_data_from_channel: "
"xrdp_sec_send failed");
return 1;
}
return 0;
}
/*****************************************************************************/
/* Send a [MS-RDPBCGR] Data PDU on the MCS channel for the given pduType2
* with the headers added and data compressed */
int
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type)
{
return xrdp_rdp_send_data_from_channel(self, s, data_pdu_type,
self->mcs_channel, 1);
}
/*****************************************************************************/
/* returns the fastpath rdp byte count */
int
@ -1306,7 +1323,6 @@ xrdp_rdp_process_data_font(struct xrdp_rdp *self, struct stream *s)
self->session->callback(self->session->id, 0x555a, 0, 0,
0, 0);
}
xrdp_channel_drdynvc_start(self->sec_layer->chan_layer);
}
else
{

View File

@ -43,207 +43,6 @@ static tui8 g_pad_92[48] =
92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92
};
/*****************************************************************************/
/* Licensing request v2 PDU
*
* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
* [MS-RDPELE] SERVER_LICENSE_REQUEST with PREAMBLE_VERSION_2_0
*/
/* some compilers need unsigned char to avoid warnings */
static tui8 g_lic1[322] =
{
/* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
* flags (2) = 0x0080 (SEC_LICENSE_PKT)
* flagsHi (2) = unused (arbitrary data)
* [MS-RDPBCGR] LICENSE_PREAMBLE
* bMsgType (1) = 0x01 (LICENSE_REQUEST)
* flags (1) = 0x02 (PREAMBLE_VERSION_2_0)
* wMsgSize (2) = 318 (excludes the 4 bytes TS_SECURITY_HEADER Basic)
*/
0x80, 0x00, 0x3e, 0x01, 0x01, 0x02, 0x3e, 0x01,
/* [MS-RDPELE] SERVER_LICENSE_REQUEST
* ServerRandom (32) = <see hex below>
*/
0x7b, 0x3c, 0x31, 0xa6, 0xae, 0xe8, 0x74, 0xf6,
0xb4, 0xa5, 0x03, 0x90, 0xe7, 0xc2, 0xc7, 0x39,
0xba, 0x53, 0x1c, 0x30, 0x54, 0x6e, 0x90, 0x05,
0xd0, 0x05, 0xce, 0x44, 0x18, 0x91, 0x83, 0x81,
/* [MS-RDPELE] SERVER_LICENSE_REQUEST - ProductInfo
* [MS-RDPELE] PRODUCT_INFO
* dwVersion (4) = 0x00040000
* cbCompanyName (4) = 0x0000002c (44)
*/
0x00, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00,
/*
* pbCompanyName (44) = UTF-16("Microsoft Corporation")
* cbProductId (4) = 0x00000008 (8)
*/
0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00,
0x74, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00,
0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00,
0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
/*
* pbProductId (8) = UTF-16("236")
*/
0x32, 0x00, 0x33, 0x00, 0x36, 0x00, 0x00, 0x00,
/* [MS-RDPELE] SERVER_LICENSE_REQUEST - KeyExchangeList
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
* wBlobType (2) = 0x000d (BB_KEY_EXCHG_ALG_BLOB)
* wBlobLen (2) = 0x0004 (4)
* blobData (4) = 0x00000001 (KEY_EXCHANGE_ALG_RSA)
*/
0x0d, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
/* [MS-RDPELE] SERVER_LICENSE_REQUEST - ServerCertificate
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
* wBlobType (2) = BB_CERTIFICATE_BLOB (0x0003)
* wBlobLen (2) = 0x00b8 (184)
* blobData = <SERVER_CERTIFICATE>
*
* [MS-RDPBCGR] SERVER_CERTIFICATE
* dwVersion (31 bits) = 0x00000001 (CERT_CHAIN_VERSION_1)
* t (1 bit) = 0 (temporary certificate)
*/
0x03, 0x00, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00,
/*
* certData = <PROPRIETARYSERVERCERTIFICATE>
*
* [MS-RDPBCGR] PROPRIETARYSERVERCERTIFICATE
* dwSigAlgId (4) = 0x00000001 (SIGNATURE_ALG_RSA)
* dwKeyAlgId (4) = 0x00000001 (KEY_EXCHANGE_ALG_RSA)
* wPublicKeyBlobType (2) = 0x0006 (BB_RSA_KEY_BLOB)
* wPublicKeyBlobLen (2) = 0x005c (92)
* PublicKeyBlob = <RSA_PUBLIC_KEY>
*
* [MS-RDPBCGR] RSA_PUBLIC_KEY
* magic (4) = 0x31415352
* keylen (4) = 0x00000048 (72)
* bitlen (4) = 0x00000200 (512)
* datalen (4) = 0x0000003f (63)
* pubExp (4) = 0x00010001 (65537)
*/
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x06, 0x00, 0x5c, 0x00, 0x52, 0x53, 0x41, 0x31,
0x48, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
0x3f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
/*
* modulus (72) = <see hex below>
*/
0x01, 0xc7, 0xc9, 0xf7, 0x8e, 0x5a, 0x38, 0xe4,
0x29, 0xc3, 0x00, 0x95, 0x2d, 0xdd, 0x4c, 0x3e,
0x50, 0x45, 0x0b, 0x0d, 0x9e, 0x2a, 0x5d, 0x18,
0x63, 0x64, 0xc4, 0x2c, 0xf7, 0x8f, 0x29, 0xd5,
0x3f, 0xc5, 0x35, 0x22, 0x34, 0xff, 0xad, 0x3a,
0xe6, 0xe3, 0x95, 0x06, 0xae, 0x55, 0x82, 0xe3,
0xc8, 0xc7, 0xb4, 0xa8, 0x47, 0xc8, 0x50, 0x71,
0x74, 0x29, 0x53, 0x89, 0x6d, 0x9c, 0xed, 0x70,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* [MS-RDPELE] SERVER_LICENSE_REQUEST - ServerCertificate
* [MS-RDPBCGR] LICENSE_BINARY_BLOB - blobData
* [MS-RDPBCGR] SERVER_CERTIFICATE - certData
* [MS-RDPBCGR] PROPRIETARYSERVERCERTIFICATE
* wSignatureBlobType (2) = 0x0008 (BB_RSA_SIGNATURE_BLOB)
* wSignatureBlobLen (2) = 0x0048 (72)
* SignatureBlob (72) = <see hex below, calculated using [MS-RDPBCGR] 5.3.3.1.2>
*/
0x08, 0x00, 0x48, 0x00, 0xa8, 0xf4, 0x31, 0xb9,
0xab, 0x4b, 0xe6, 0xb4, 0xf4, 0x39, 0x89, 0xd6,
0xb1, 0xda, 0xf6, 0x1e, 0xec, 0xb1, 0xf0, 0x54,
0x3b, 0x5e, 0x3e, 0x6a, 0x71, 0xb4, 0xf7, 0x75,
0xc8, 0x16, 0x2f, 0x24, 0x00, 0xde, 0xe9, 0x82,
0x99, 0x5f, 0x33, 0x0b, 0xa9, 0xa6, 0x94, 0xaf,
0xcb, 0x11, 0xc3, 0xf2, 0xdb, 0x09, 0x42, 0x68,
0x29, 0x56, 0x58, 0x01, 0x56, 0xdb, 0x59, 0x03,
0x69, 0xdb, 0x7d, 0x37, 0x00, 0x00, 0x00, 0x00,
/* <last 4 bytes of SignatureBlob>
*
* [MS-RDPELE] SERVER_LICENSE_REQUEST - ScopeList
* [MS-RDPELE] SCOPE_LIST
* ScopeCount (4) = 0x00000001 (1)
* ScopeArray = <LICENSE_BINARY_BLOB>
*
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
* wBlobType (2) = 0x000e (BB_SCOPE_BLOB)
* wBlobLen (2) = 0x000e (14)
* blobData (14) = ISO-8859-1("microsoft.com")
*/
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0e, 0x00, 0x0e, 0x00, 0x6d, 0x69, 0x63, 0x72,
0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f,
0x6d, 0x00
};
/*****************************************************************************/
/* Licensing success response v2 PDU
*
* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
* [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT
*/
/* some compilers need unsigned char to avoid warnings */
static tui8 g_lic2[20] =
{
/* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
* flags (2) = 0x0080 (SEC_LICENSE_PKT)
* flagsHi (2) = unused (arbitrary data)
* [MS-RDPBCGR] LICENSE_PREAMBLE
* bMsgType (1) = 0xff (ERROR_ALERT)
* flags (1) = 0x02 (PREAMBLE_VERSION_2_0)
* wMsgSize (2) = 0x10 (16, excludes the 4 bytes TS_SECURITY_HEADER Basic)
*/
0x80, 0x00, 0x10, 0x00, 0xff, 0x02, 0x10, 0x00,
/*
* [MS-RDPBCGR] LICENSE_ERROR_MESSAGE
* dwErrorCode (4) = 0x00000007 (STATUS_VALID_CLIENT)
* dwStateTransition (4) = 0x00000002 (ST_NO_TRANSITION)
* bbErrorInfo = <LICENSE_BINARY_BLOB>
*/
0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
/*
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
* wBlobType (2) = 0x1428 <ignored by client> (should be 0x0004 BB_ERROR_BLOB)
* wBlobLen (2) = 0x0000 (0)
*/
0x28, 0x14, 0x00, 0x00
};
/*****************************************************************************/
/* Licensing success response v3 PDU
*
* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
* [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT
*
* used for Media Center Edition
*/
/* some compilers need unsigned char to avoid warnings */
static tui8 g_lic3[20] =
{
/* S */
/* [MS-RDPBCGR] TS_SECURITY_HEADER - Basic
* flags (2) = 0x0280 (SEC_LICENSE_PKT | SEC_LICENSE_ENCRYPT_CS)
* flagsHi (2) = unused (arbitrary data)
* [MS-RDPBCGR] LICENSE_PREAMBLE
* bMsgType (1) = 0xff (ERROR_ALERT)
* flags (1) = 0x03 (PREAMBLE_VERSION_3_0)
* wMsgSize (2) = 0x0010 (16, excludes the 4 bytes TS_SECURITY_HEADER Basic)
*/
0x80, 0x02, 0x10, 0x00, 0xff, 0x03, 0x10, 0x00,
/*
* [MS-RDPBCGR] LICENSE_ERROR_MESSAGE
* dwErrorCode (4) = 0x00000007 (STATUS_VALID_CLIENT)
* dwStateTransition (4) = 0x00000002 (ST_NO_TRANSITION)
* bbErrorInfo = <LICENSE_BINARY_BLOB>
*/
0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
/*
* [MS-RDPBCGR] LICENSE_BINARY_BLOB
* wBlobType (2) = 0x99f3 <ignored by client> (should be 0x0004 BB_ERROR_BLOB)
* wBlobLen (2) = 0x0000 (0)
*/
0xf3, 0x99, 0x00, 0x00
};
static const tui8 g_fips_reverse_table[256] =
{
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
@ -1012,6 +811,25 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s)
return 1;
}
// If we require credentials, don't continue if they're not provided
if (self->rdp_layer->client_info.require_credentials)
{
if ((flags & RDP_LOGON_AUTO) == 0)
{
LOG(LOG_LEVEL_ERROR, "Server is configured to require that the "
"client enable auto logon with credentials, but the client did "
"not request auto logon.");
return 1;
}
if (len_user == 0 || len_password == 0)
{
LOG(LOG_LEVEL_ERROR, "Server is configured to require that the "
"client enable auto logon with credentials, but the client did "
"not supply both a username and password.");
return 1;
}
}
if (flags & RDP_LOGON_AUTO)
{
if (ts_info_utf16_in(s, len_password, self->rdp_layer->client_info.password, sizeof(self->rdp_layer->client_info.password)) != 0)
@ -1033,18 +851,12 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s)
}
else
{
// Skip the password
if (!s_check_rem_and_log(s, len_password + 2, "Parsing [MS-RDPBCGR] TS_INFO_PACKET Password"))
{
return 1;
}
in_uint8s(s, len_password + 2);
if (self->rdp_layer->client_info.require_credentials)
{
LOG(LOG_LEVEL_ERROR, "Server is configured to require that the "
"client enable auto logon with credentials, but the client did "
"not request auto logon.");
return 1; /* credentials on cmd line is mandatory */
}
}
if (self->rdp_layer->client_info.domain_user_separator[0] != '\0'
&& self->rdp_layer->client_info.domain[0] != '\0')
@ -1159,43 +971,10 @@ xrdp_sec_process_logon_info(struct xrdp_sec *self, struct stream *s)
return 0;
}
/*****************************************************************************/
/* returns error */
static int
xrdp_sec_send_lic_initial(struct xrdp_sec *self)
{
struct stream *s;
make_stream(s);
init_stream(s, 8192);
if (xrdp_mcs_init(self->mcs_layer, s) != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_sec_send_lic_initial: xrdp_mcs_init failed");
free_stream(s);
return 1;
}
out_uint8a(s, g_lic1, sizeof(g_lic1));
s_mark_end(s);
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPELE] SERVER_LICENSE_REQUEST");
if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
{
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPELE] SERVER_LICENSE_REQUEST failed");
free_stream(s);
return 1;
}
free_stream(s);
return 0;
}
/*****************************************************************************/
/*
* Send a [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT
* See also: [MS-RDPELE] 1.3.3 Licensing PDU Flows
* Send a [MS-RDPBCGR] Server License Error PDU (2.2.1.12) with
* STATUS_VALID_CLIENT
*/
/* returns error */
static int
@ -1213,45 +992,34 @@ xrdp_sec_send_lic_response(struct xrdp_sec *self)
return 1;
}
out_uint8a(s, g_lic2, sizeof(g_lic2));
/* [MS-RDPBCGR] TS_SECURITY_HEADER */
/* A careful reading of [MS-RDPBCGR] 2.2.1.12 shows that a securityHeader
* MUST be included, and provided the flag fields of the header does
* not contain SEC_ENCRYPT, it is always possible to send a basic
* security header */
out_uint16_le(s, SEC_LICENSE_PKT | SEC_LICENSE_ENCRYPT_CS); /* flags */
out_uint16_le(s, 0); /* flagsHi */
/* [MS-RDPBCGR] LICENSE_VALID_CLIENT_DATA */
/* preamble (LICENSE_PREAMBLE) */
out_uint8(s, ERROR_ALERT);
out_uint8(s, PREAMBLE_VERSION_3_0);
out_uint16_le(s, 16); /* Message size, including pre-amble */
/* validClientMessage */
/* From [MS-RDPBCGR] 2.2.12.1, dwStateTransition must be ST_NO_TRANSITION,
* and the bbErrorInfo field must contain an empty blob of type
* BB_ERROR_BLOB */
out_uint32_le(s, STATUS_VALID_CLIENT); /* dwErrorCode */
out_uint32_le(s, ST_NO_TRANSITION); /* dwStateTransition */
out_uint16_le(s, BB_ERROR_BLOB); /* wBlobType */
out_uint16_le(s, 0); /* wBlobLen */
s_mark_end(s);
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT");
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPBCGR] Server License Error PDU with STATUS_VALID_CLIENT");
if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
{
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT failed");
free_stream(s);
return 1;
}
free_stream(s);
return 0;
}
/*****************************************************************************/
/* returns error */
static int
xrdp_sec_send_media_lic_response(struct xrdp_sec *self)
{
struct stream *s;
make_stream(s);
init_stream(s, 8192);
if (xrdp_mcs_init(self->mcs_layer, s) != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_sec_send_media_lic_response: xrdp_mcs_init failed");
free_stream(s);
return 1;
}
out_uint8a(s, g_lic3, sizeof(g_lic3));
s_mark_end(s);
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT");
if (xrdp_mcs_send(self->mcs_layer, s, MCS_GLOBAL_CHANNEL) != 0)
{
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPELE] LICENSE_ERROR_MESSAGE with STATUS_VALID_CLIENT failed");
LOG(LOG_LEVEL_ERROR, "Sending [MS-RDPBCGR] Server License Error PDU with STATUS_VALID_CLIENT failed");
free_stream(s);
return 1;
}
@ -1620,7 +1388,7 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan)
}
}
if (flags & SEC_CLIENT_RANDOM) /* 0x01 TS_SECURITY_PACKET */
if (flags & SEC_EXCHANGE_PKT) /* 0x01 TS_SECURITY_PACKET */
{
if (!s_check_rem_and_log(s, 4, "Parsing [MS-RDPBCGR] TS_SECURITY_PACKET"))
{
@ -1659,7 +1427,7 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan)
return 0;
}
if (flags & SEC_LOGON_INFO) /* 0x40 SEC_INFO_PKT */
if (flags & SEC_INFO_PKT)
{
if (xrdp_sec_process_logon_info(self, s) != 0)
{
@ -1667,31 +1435,6 @@ xrdp_sec_recv(struct xrdp_sec *self, struct stream *s, int *chan)
return 1;
}
if (self->rdp_layer->client_info.is_mce)
{
if (xrdp_sec_send_media_lic_response(self) != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_sec_recv: xrdp_sec_send_media_lic_response failed");
return 1;
}
LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_sec_recv: out 'send demand active'");
return -1; /* special error that means send demand active */
}
if (xrdp_sec_send_lic_initial(self) != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_sec_recv: xrdp_sec_send_lic_initial failed");
return 1;
}
*chan = 1; /* just set a non existing channel and exit */
LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_sec_recv: out channel 1 (non-existing channel)");
return 0;
}
if (flags & SEC_LICENCE_NEG) /* 0x80 SEC_LICENSE_PKT */
{
if (xrdp_sec_send_lic_response(self) != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_sec_recv: xrdp_sec_send_lic_response failed");
@ -2146,6 +1889,12 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec *self, struct stream *s)
LOG(LOG_LEVEL_WARNING,
"client requested gfx protocol with insufficient color depth");
}
else if (client_info->max_bpp > 0 && client_info->max_bpp < 32)
{
LOG(LOG_LEVEL_WARNING, "Client requested gfx protocol "
"but the server configuration is limited to %d bpp.",
client_info->max_bpp);
}
else
{
LOG(LOG_LEVEL_INFO, "client supports gfx protocol");

10
mc/mc.h
View File

@ -31,6 +31,9 @@
struct source_info;
/* Defined in xrdp_client_info.h */
struct monitor_info;
struct mod
{
int size; /* size of this struct */
@ -81,7 +84,10 @@ struct mod
int box_left, int box_top,
int box_right, int box_bottom,
int x, int y, char *data, int data_len);
int (*server_reset)(struct mod *v, int width, int height, int bpp);
int (*client_monitor_resize)(struct mod *v, int width, int height,
int num_monitors,
const struct monitor_info *monitors);
int (*server_monitor_resize_done)(struct mod *v);
int (*server_get_channel_count)(struct mod *v);
int (*server_query_channel)(struct mod *v, int index,
char *channel_name,
@ -92,7 +98,7 @@ struct mod
int total_data_len, int flags);
int (*server_bell_trigger)(struct mod *v);
int (*server_chansrv_in_use)(struct mod *v);
tintptr server_dumby[100 - 27]; /* align, 100 minus the number of server
tintptr server_dumby[100 - 28]; /* align, 100 minus the number of server
functions above */
/* common */
tintptr handle; /* pointer to self as long */

View File

@ -877,8 +877,12 @@ lxrdp_server_version_message(struct mod *mod)
/******************************************************************************/
static int
lxrdp_server_monitor_resize(struct mod *mod, int width, int height)
lxrdp_server_monitor_resize(struct mod *mod, int width, int height,
int num_monitors,
const struct monitor_info *monitors,
int *in_progress)
{
*in_progress = 0;
return 0;
}

View File

@ -88,7 +88,10 @@ struct mod
int (*mod_suppress_output)(struct mod *mod, int suppress,
int left, int top, int right, int bottom);
int (*mod_server_monitor_resize)(struct mod *mod,
int width, int height);
int width, int height,
int num_monitors,
const struct monitor_info *monitors,
int *in_progress);
int (*mod_server_monitor_full_invalidate)(struct mod *mod,
int width, int height);
int (*mod_server_version_message)(struct mod *mod);
@ -126,7 +129,10 @@ struct mod
int box_left, int box_top,
int box_right, int box_bottom,
int x, int y, char *data, int data_len);
int (*server_reset)(struct mod *v, int width, int height, int bpp);
int (*client_monitor_resize)(struct mod *v, int width, int height,
int num_monitors,
const struct monitor_info *monitors);
int (*server_monitor_resize_done)(struct mod *v);
int (*server_get_channel_count)(struct mod *v);
int (*server_query_channel)(struct mod *v, int index,
char *channel_name,
@ -191,7 +197,7 @@ struct mod
int flags, int frame_id);
int (*server_session_info)(struct mod *v, const char *data,
int data_bytes);
tintptr server_dumby[100 - 46]; /* align, 100 minus the number of server
tintptr server_dumby[100 - 47]; /* align, 100 minus the number of server
functions above */
/* common */
tintptr handle; /* pointer to self as long */

View File

@ -95,7 +95,8 @@ in
libfdk-aac-dev \
libimlib2-dev \
libopus-dev \
libpixman-1-dev"
libpixman-1-dev \
libx264-dev"
;;
*)
echo "unsupported feature set: $FEATURE_SET"

65
scripts/make_release_tarball.sh Executable file
View File

@ -0,0 +1,65 @@
#!/bin/sh
#
# Script to generate release tarball
#
# This script will generate release tarball. If the repository HEAD is not
# tagged, the script will be aborted. Target GitHub repository, branch can be
# customized by GH_* envirnment variable.
#
# Usage:
# Just execute the script. This script is intended to be run by maintainers
# so build dependencies are not taken care of.
#
# $ ./scripts/make_release_tarball.sh
# (snip)
# ===============================================
# Release tarball has been generated at:
# /tmp/tmp.q8kme7m7/xrdp-0.9.22.1.tar.gz
#
# CHECKSUM:
# 3ca220d6941ca6dab6a8bd1b50fcffffcf386ce01fbbc350099fdc83684380e0 xrdp-0.9.22.1.tar.gz
#
# Copy tarball to /home/meta/github/metalefty/xrdp? [y/N] y
#
# If the script is executed with BATCH=yes, the full path of the release
# tarball will be printed on the last line. Clip it using tail command.
#
# $ BATCH=yes ./scripts/make_release_tarball.sh | tail -n1
set -e
: ${GH_ACCOUNT:=neutrinolabs}
: ${GH_PROJECT:=xrdp}
: ${GH_BRANCH:=v0.10}
: ${BATCH:=""}
WRKDIR=$(mktemp -d)
# clean checkout
git clone --recursive --branch "${GH_BRANCH}" "https://github.com/${GH_ACCOUNT}/${GH_PROJECT}.git" "${WRKDIR}"
cd "${WRKDIR}"
git diff --no-ext-diff --quiet --exit-code # check if there's no changes on working tree
RELVER=$(git describe --tags --exact-match HEAD) # check if working HEAD refs a release tag
./bootstrap
./configure
make distcheck
echo
echo ===============================================
echo Release tarball has been generated at:
echo ${WRKDIR}/xrdp-${RELVER#v}.tar.gz
echo
echo CHECKSUM:
sha256sum xrdp-${RELVER#v}.tar.gz
echo
if [ -z "${BATCH}" ]; then
echo -n "Copy tarball to ${OLDPWD}? [y/N] "
read -t 60 copy_tarball
case "${copy_tarball}" in
[Yy]*) cp -i xrdp-${RELVER#v}.tar.gz "${OLDPWD}"; exit ;;
esac
else
echo ${WRKDIR}/xrdp-${RELVER#v}.tar.gz
fi

View File

@ -2,12 +2,15 @@
# Script to run astyle on the code
#
# Usage: /path/to/run_astyle.sh
# Usage: /path/to/run_astyle.sh [ -v ASTYLE_VER]
#
# - If -v ASTYLE_VER is specified, that version of astyle is run from
# ~/astyle.local (whether or not it's there!). Use install_astyle.sh
# to install a new version.
# Note: the script must be run from the root directory of the xrdp repository
INSTALL_ROOT=~/astyle.local
ASTYLE_FROM_XRDP=$INSTALL_ROOT/3.4.12/usr/bin/astyle
MIN_ASTYLE_VER="3.1"
# ----------------------------------------------------------------------------
@ -15,53 +18,66 @@ MIN_ASTYLE_VER="3.1"
# ----------------------------------------------------------------------------
usage()
{
echo "** Usage: $0"
echo " e.g. $0"
echo "** Usage: $0 [ -v version]"
echo " e.g. $0 -v 3.4.12"
} >&2
# ----------------------------------------------------------------------------
# M A I N
# ----------------------------------------------------------------------------
# Figure out ASTYLE setting, if any. Currently '-v' must be the first
# argument on the command line.
case "$1" in
-v) # Version is separate parameter
if [ $# -ge 2 ]; then
ASTYLE="$INSTALL_ROOT/$2/usr/bin/astyle"
shift 2
else
echo "** ignoring '-v' with no arg" >&2
shift 1
fi
;;
-v*) # Version is in same parameter
# ${parameter#word} is not supported by classic Bourne shell,
# but it is on bash, dash, etc. If it doesn't work on your shell,
# don't use this form!
ASTYLE="$INSTALL_ROOT/${1#-v}/usr/bin/astyle"
shift 1
esac
if [ -z "$ASTYLE" ]; then
ASTYLE=astyle
fi
if [ $# -ne 0 ]; then
usage
exit 1
fi
# check if the built-in astyle meets the minimum requrements
ASTYLE_FROM_OS_VER_OUTPUT=`astyle --version | grep "Artistic Style Version" | cut -d' ' -f4`
ASTYLE=""
ERROR_MESSAGE=""
if [ ! -z "$ASTYLE_FROM_OS_VER_OUTPUT" ]; then
# astyle is installed, so check if it's version meets the minimum requirements
LOWEST_VERSION=`echo -e "$MIN_ASTYLE_VER\n$ASTYLE_FROM_OS_VER_OUTPUT" | sort -V | head -n1`
if [ "$MIN_ASTYLE_VER" = "$LOWEST_VERSION" ]; then
ASTYLE=astyle
else
# check if the selected astyle meets the minimum requrements
ASTYLE_VER_OUTPUT=`$ASTYLE --version 2>/dev/null | grep "Artistic Style Version" | cut -d' ' -f4`
if [ ! -z "$ASTYLE_VER_OUTPUT" ]; then
# Check the version meets the minimum requirements
LOWEST_VERSION=`{ echo "$MIN_ASTYLE_VER" ; echo "$ASTYLE_VER_OUTPUT"; } | sort -V | head -n1`
if [ "$MIN_ASTYLE_VER" != "$LOWEST_VERSION" ]; then
ERROR_MESSAGE="The version of astyle installed does not meet the minimum version requirement: >= $MIN_ASTYLE_VER "
fi
else
elif [ "$ASTYLE" = astyle ]; then
ERROR_MESSAGE="astyle is not installed on the system path"
fi
if [ -z "$ASTYLE" ]; then
# astyle from the os is invlid, fallback to the xrdp version if it is installed
if [ -x "$ASTYLE_FROM_XRDP" ]; then
ASTYLE="$ASTYLE_FROM_XRDP"
ERROR_MESSAGE=""
else
ERROR_MESSAGE="${ERROR_MESSAGE}\nastyle $MIN_ASTYLE_VER is not installed at the expected path: $ASTYLE_FROM_XRDP"
fi
else
ERROR_MESSAGE="Can't find $ASTYLE"
fi
if [ ! -z "$ERROR_MESSAGE" ]; then
echo "$ERROR_MESSAGE"
echo "$ERROR_MESSAGE" >&2
exit 1
fi
if [ ! -f "astyle_config.as" ]; then
echo "$0 must be run from the root xrdp repository directory which "
echo "contains the 'astyle_config.as' file."
echo "$0 must be run from the root xrdp repository directory which " >&2
echo "contains the 'astyle_config.as' file." >&2
exit 2
fi
@ -72,3 +88,5 @@ ASTYLE_FLAGS="--options=astyle_config.as --exclude=third_party ./\*.c ./\*.h"
echo "Command: $ASTYLE $ASTYLE_FLAGS"
"$ASTYLE" $ASTYLE_FLAGS
}
exit $?

5
scripts/update_news.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
curl -s -H 'Cache-Control: no-cache' \
https://raw.githubusercontent.com/wiki/neutrinolabs/xrdp/NEWS-v0.10.md > \
$(git rev-parse --show-superproject-working-tree --show-toplevel | head -1)/NEWS.md

View File

@ -27,6 +27,7 @@ xrdp_sesman_SOURCES = \
scp_process.h \
sesman.c \
sesman.h \
sesman.ini.in \
sesexec_control.c \
sesexec_control.h \
session_list.c \
@ -52,7 +53,7 @@ SUFFIXES = .in
.in:
$(subst_verbose)$(SUBST_VARS) $< > $@
dist_sesmansysconf_DATA = \
nodist_sesmansysconf_DATA = \
sesman.ini
dist_sesmansysconf_SCRIPTS = \
@ -64,3 +65,5 @@ SUBDIRS = \
sesexec \
tools \
chansrv
CLEANFILES = $(nodist_sesmansysconf_DATA)

View File

@ -202,7 +202,7 @@ struct state_lookup
{
fuse_req_t req; /* Original FUSE request from lookup */
fuse_ino_t pinum; /* inum of parent directory */
char name[XFS_MAXFILENAMELEN];
char name[XFS_MAXFILENAMELEN + 1];
/* Name to look up */
fuse_ino_t existing_inum;
/* inum of an existing entry */
@ -241,7 +241,7 @@ struct state_create
fuse_req_t req; /* Original FUSE request from lookup */
struct fuse_file_info fi; /* File info struct passed to open */
fuse_ino_t pinum; /* inum of parent directory */
char name[XFS_MAXFILENAMELEN];
char name[XFS_MAXFILENAMELEN + 1];
/* Name of file in parent directory */
mode_t mode; /* Mode of file to create */
};
@ -280,7 +280,7 @@ struct state_rename
fuse_req_t req; /* Original FUSE request from lookup */
fuse_ino_t pinum; /* inum of parent of file */
fuse_ino_t new_pinum; /* inum of new parent of file */
char name[XFS_MAXFILENAMELEN];
char name[XFS_MAXFILENAMELEN + 1];
/* New name of file in new parent dir */
};
@ -540,10 +540,25 @@ xfuse_init(void)
return -1;
}
g_snprintf(g_fuse_clipboard_path, 255, "%s/.clipboard", g_fuse_root_path);
g_snprintf(g_fuse_clipboard_path, sizeof(g_fuse_clipboard_path),
"%s/.clipboard", g_fuse_root_path);
/* if FUSE mount point does not exist, create it */
if (!g_directory_exist(g_fuse_root_path))
{
(void)g_create_path(g_fuse_root_path);
if (!g_create_dir(g_fuse_root_path))
{
LOG(LOG_LEVEL_ERROR, "mkdir %s failed (%s)",
g_fuse_root_path, g_get_strerror());
return -1;
}
}
/* Get the characteristics of the parent directory of the FUSE mount
* point. Used by xfuse_path_in_xfuse_fs() */
g_fuse_root_parent_dev = -1;
g_fuse_root_parent_ino = -1;
p = (char *)g_strrchr(g_fuse_root_path, '/');
if (p != NULL)
{
@ -554,11 +569,6 @@ xfuse_init(void)
g_fuse_root_parent_ino = g_file_get_inode_num(g_fuse_root_path);
*p = '/';
}
else
{
g_fuse_root_parent_dev = -1;
g_fuse_root_parent_ino = -1;
}
if (g_fuse_root_parent_dev == -1 || g_fuse_root_parent_ino == -1)
{
@ -568,18 +578,6 @@ xfuse_init(void)
return -1;
}
/* if FUSE mount point does not exist, create it */
if (!g_directory_exist(g_fuse_root_path))
{
(void)g_create_path(g_fuse_root_path);
if (!g_create_dir(g_fuse_root_path))
{
LOG(LOG_LEVEL_ERROR, "mkdir %s failed. If %s is already mounted, you must "
"first unmount it", g_fuse_root_path, g_fuse_root_path);
return -1;
}
}
/* setup xrdp file system */
if (xfuse_init_xrdp_fs())
{
@ -906,14 +904,16 @@ static int xfuse_init_lib(struct fuse_args *args)
{
if (fuse_parse_cmdline(args, &g_mount_point, 0, 0) < 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "fuse_parse_cmdline() failed");
LOG(LOG_LEVEL_ERROR, "fuse_parse_cmdline() failed");
fuse_opt_free_args(args);
return -1;
}
if ((g_ch = fuse_mount(g_mount_point, args)) == 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "fuse_mount() failed");
LOG(LOG_LEVEL_ERROR, "FUSE mount on %s failed."
" If %s is already mounted, you must first unmount it",
g_mount_point, g_mount_point);
fuse_opt_free_args(args);
return -1;
}
@ -921,7 +921,7 @@ static int xfuse_init_lib(struct fuse_args *args)
g_se = fuse_lowlevel_new(args, &g_xfuse_ops, sizeof(g_xfuse_ops), 0);
if (g_se == 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "fuse_lowlevel_new() failed");
LOG(LOG_LEVEL_ERROR, "fuse_lowlevel_new() failed");
fuse_unmount(g_mount_point, g_ch);
g_ch = 0;
fuse_opt_free_args(args);

View File

@ -264,6 +264,8 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
struct xfs_fs *xfs = g_new0(struct xfs_fs, 1);
XFS_INODE_ALL *xino1 = NULL;
XFS_INODE_ALL *xino2 = NULL;
char *xino1_name = NULL;
char *xino2_name = NULL;
if (xfs != NULL)
{
@ -279,10 +281,14 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
if (!grow_xfs(xfs, INODE_TABLE_ALLOCATION_INITIAL) ||
xfs->inode_table == NULL ||
(xino1 = g_new0(XFS_INODE_ALL, 1)) == NULL ||
(xino2 = g_new0(XFS_INODE_ALL, 1)) == NULL)
(xino2 = g_new0(XFS_INODE_ALL, 1)) == NULL ||
(xino1_name = strdup(".")) == NULL ||
(xino2_name = strdup(".delete-pending")) == NULL)
{
free(xino1);
free(xino2);
free(xino1_name);
free(xino2_name);
xfs_delete_xfs_fs(xfs);
xfs = NULL;
}
@ -306,7 +312,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
xino1->pub.atime = time(0);
xino1->pub.mtime = xino1->pub.atime;
xino1->pub.ctime = xino1->pub.atime;
strcpy(xino1->pub.name, ".");
xino1->pub.name = xino1_name;
xino1->pub.generation = xfs->generation;
xino1->pub.is_redirected = 0;
xino1->pub.device_id = 0;
@ -328,7 +334,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
xino2->pub.atime = time(0);
xino2->pub.mtime = xino2->pub.atime;
xino2->pub.ctime = xino2->pub.atime;
strcpy(xino2->pub.name, ".delete-pending");
xino2->pub.name = xino2_name;
xino2->pub.generation = xfs->generation;
xino2->pub.is_redirected = 0;
xino2->pub.device_id = 0;
@ -349,6 +355,17 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
return xfs;
}
/* ------------------------------------------------------------------------ */
static void
xfs_free_inode(XFS_INODE_ALL *xino)
{
if (xino != NULL)
{
free(xino->pub.name);
free(xino);
}
}
/* ------------------------------------------------------------------------ */
void
xfs_delete_xfs_fs(struct xfs_fs *xfs)
@ -363,7 +380,7 @@ xfs_delete_xfs_fs(struct xfs_fs *xfs)
size_t i;
for (i = 0 ; i < xfs->inode_count; ++i)
{
free(xfs->inode_table[i]);
xfs_free_inode(xfs->inode_table[i]);
}
}
free(xfs->inode_table);
@ -407,9 +424,14 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
if (xfs->free_count > 0 ||
grow_xfs(xfs, INODE_TABLE_ALLOCATION_GRANULARITY))
{
XFS_INODE_ALL *xino = NULL;
if ((xino = g_new0(XFS_INODE_ALL, 1)) != NULL)
XFS_INODE_ALL *xino = g_new0(XFS_INODE_ALL, 1);
char *cpyname = strdup(name);
if (xino == NULL || cpyname == NULL)
{
free(xino);
free(cpyname);
}
else
{
fuse_ino_t inum = xfs->free_list[--xfs->free_count];
if (xfs->inode_table[inum] != NULL)
@ -433,7 +455,7 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
xino->pub.atime = time(0);
xino->pub.mtime = xino->pub.atime;
xino->pub.ctime = xino->pub.atime;
strcpy(xino->pub.name, name);
xino->pub.name = cpyname;
xino->pub.generation = xfs->generation;
xino->pub.is_redirected = parent->pub.is_redirected;
xino->pub.device_id = parent->pub.device_id;
@ -498,7 +520,7 @@ xfs_remove_entry(struct xfs_fs *xfs, fuse_ino_t inum)
* so that the caller can distinguish re-uses of the same inum.
*/
++xfs->generation;
free(xino);
xfs_free_inode(xino);
}
}
}
@ -844,8 +866,15 @@ xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
XFS_INODE_ALL *xino;
XFS_INODE_ALL *parent;
XFS_INODE *dest;
char *cpyname;
if (xfs_check_move_entry(xfs, inum, new_parent_inum, name))
/* Copy the new name. We'll either end up freeing it, or we'll
* use it to replace something else (which gets freed instead) */
if ((cpyname = strdup(name)) == NULL)
{
result = ENOMEM;
}
else if (xfs_check_move_entry(xfs, inum, new_parent_inum, name))
{
xino = xfs->inode_table[inum];
parent = xfs->inode_table[new_parent_inum];
@ -862,19 +891,31 @@ xfs_move_entry(struct xfs_fs *xfs, fuse_ino_t inum,
unlink_inode_from_parent(xino);
link_inode_into_directory_node(parent, xino);
strcpy(xino->pub.name, name);
/* Swap the copy name and the inode name so we end up with the
* right name, and the old one gets freed */
char *t = xino->pub.name;
xino->pub.name = cpyname;
cpyname = t;
}
else if (strcmp(xino->pub.name, name) != 0)
{
/* Same directory, but name has changed */
if ((dest = xfs_lookup_in_dir(xfs, new_parent_inum, name)) != NULL)
{
/* Name collision - remove destination entry */
xfs_remove_entry(xfs, dest->inum);
}
strcpy(xino->pub.name, name);
/* Swap the copy name and the inode name so we end up with the
* right name, and the old one gets freed */
char *t = xino->pub.name;
xino->pub.name = cpyname;
cpyname = t;
}
result = 0;
}
free (cpyname);
return result;
}

View File

@ -29,7 +29,11 @@
#include "arch.h"
#define XFS_MAXFILENAMELEN 255
/* Maximum length of filename supported (in bytes).
* This is a sensible limit to a filename length. It is not used by
* this module to allocate long-lived storage, so it can be increased
* if necessary */
#define XFS_MAXFILENAMELEN 1023
/*
* Incomplete types for the public interface
@ -37,6 +41,9 @@
struct xfs_fs;
struct xfs_dir_handle;
/**
* Describe an inode in the XFS filesystem
*/
typedef struct xfs_inode
{
fuse_ino_t inum; /* File serial number. */
@ -47,7 +54,7 @@ typedef struct xfs_inode
time_t atime; /* Time of last access. */
time_t mtime; /* Time of last modification. */
time_t ctime; /* Time of last status change. */
char name[XFS_MAXFILENAMELEN + 1]; /* Short name */
char *name; /* Short name (dynamically allocated) */
tui32 generation; /* Changes if inode is reused */
char is_redirected; /* file is on redirected device */
tui32 device_id; /* device ID of redirected device */

View File

@ -181,14 +181,8 @@ x-special/gnome-copied-files
#include "ms-rdpeclip.h"
#include "xrdp_constants.h"
static char g_bmp_image_header[] =
{
/* this is known to work */
//0x42, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
/* THIS IS BEING SENT BY WIN2008 */
0x42, 0x4d, 0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00
};
#define BMPFILEHEADER_LEN 14
#define BMPINFOHEADER_LEN 40
extern int g_cliprdr_chan_id; /* in chansrv.c */
@ -1135,6 +1129,7 @@ clipboard_process_data_response_for_image(struct stream *s,
{
XSelectionRequestEvent *lxev;
int len;
struct stream *bmp_hs;
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: "
"CLIPRDR_DATA_RESPONSE_FOR_IMAGE");
@ -1148,20 +1143,45 @@ clipboard_process_data_response_for_image(struct stream *s,
{
return 0;
}
g_free(g_clip_c2s.data);
g_clip_c2s.data = (char *) g_malloc(len + 14, 0);
g_clip_c2s.data = (char *) g_malloc(len + BMPFILEHEADER_LEN, 0);
if (g_clip_c2s.data == 0)
{
g_clip_c2s.total_bytes = 0;
return 0;
}
g_clip_c2s.total_bytes = len;
g_clip_c2s.total_bytes = len + BMPFILEHEADER_LEN;
g_clip_c2s.read_bytes_done = g_clip_c2s.total_bytes;
g_memcpy(g_clip_c2s.data, g_bmp_image_header, 14);
in_uint8a(s, g_clip_c2s.data + 14, len);
/*
* Assemble bitmap file header
* https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header
*/
make_stream(bmp_hs);
if (bmp_hs == 0)
{
g_free(g_clip_c2s.data);
g_clip_c2s.total_bytes = 0;
return 0;
}
init_stream(bmp_hs, BMPFILEHEADER_LEN);
out_uint8(bmp_hs, 'B');
out_uint8(bmp_hs, 'M');
out_uint32_le(bmp_hs, g_clip_c2s.total_bytes);
out_uint16_le(bmp_hs, 0);
out_uint16_le(bmp_hs, 0);
out_uint32_le(bmp_hs, BMPFILEHEADER_LEN + BMPINFOHEADER_LEN);
/* Copy header and data to output stream */
g_memcpy(g_clip_c2s.data, bmp_hs->data, BMPFILEHEADER_LEN);
in_uint8a(s, g_clip_c2s.data + BMPFILEHEADER_LEN, len);
free_stream(bmp_hs);
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_process_data_response_for_image: calling "
"clipboard_provide_selection_c2s");
clipboard_provide_selection_c2s(lxev, lxev->target);
return 0;
}

View File

@ -26,6 +26,7 @@
#include <config_ac.h>
#endif
#include <ctype.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
@ -52,8 +53,8 @@ extern char g_fuse_clipboard_path[];
struct cb_file_info
{
char pathname[256];
char filename[256];
char *pathname;
char *filename;
int flags;
int size;
tui64 time;
@ -82,6 +83,103 @@ timeval2wintime(struct timeval *tv)
}
#endif
/**
* Gets a useable filename from a file specification passed to us
*
* The passed-in specification may contain instances of RFC3986 encoded
* octets '%xx' where 'x' is a hex digit (e.g. %20 == ASCII SPACE). For
* UTF-8, there may be many of these (e.g. %E6%97%A5 maps to the U+65E5
* Unicode character)
*
* The result must be free'd by the caller.
*/
static char *
decode_rfc3986(const char *rfc3986, int len)
{
char *result = (char *)malloc(len + 1);
if (result != NULL)
{
int i = 0;
int j = 0;
/* Copy the passed-in filename so we can modify it */
while (i < len)
{
/* Check for %xx for a character (e.g. %20 == ASCII 32 == SPACE) */
if (rfc3986[i] == '%' && (len - i) > 2 &&
isxdigit(rfc3986[i + 1]) && isxdigit(rfc3986[i + 2]))
{
char jchr[] = { rfc3986[i + 1], rfc3986[i + 2], '\0' };
result[j++] = g_htoi(jchr);
i += 3;
}
else
{
result[j++] = rfc3986[i++];
}
}
result[j] = '\0';
}
return result;
}
/**
* Allocates a alloc_cb_file_info struct
*
* The memory for the struct is allocated in such a way that a single
* free() call can be used to de-allocate it
*
* Filename elements are copied into the struct
*/
static struct cb_file_info *
alloc_cb_file_info(const char *full_name)
{
struct cb_file_info *result = NULL;
/* Find the last path separator in the string */
const char *psep = strrchr(full_name, '/');
/* Separate the name into a path and an unqualified name */
const char *path_ptr = "/";
unsigned int path_len = 1;
const char *name_ptr;
if (psep == NULL)
{
name_ptr = full_name;
}
else if (psep == full_name)
{
name_ptr = full_name + 1;
}
else
{
path_ptr = full_name;
path_len = psep - full_name;
name_ptr = psep + 1;
}
/* Allocate a block big enough for the struct, and
* for both the strings */
unsigned int name_len = strlen(name_ptr);
unsigned int alloc_size = sizeof(struct cb_file_info) +
(path_len + 1) + (name_len + 1);
result = (struct cb_file_info *)malloc(alloc_size);
if (result != NULL)
{
/* Get a pointer to the first byte past the struct */
result->pathname = (char *)(result + 1);
result->filename = result->pathname + path_len + 1;
memcpy(result->pathname, path_ptr, path_len);
result->pathname[path_len] = '\0';
memcpy(result->filename, name_ptr, name_len);
result->filename[name_len] = '\0';
}
return result;
}
/***
* See MS-RDPECLIP 3.1.5.4.7
*
@ -113,54 +211,13 @@ clipboard_send_filecontents_response_fail(int streamId)
return rv;
}
/*****************************************************************************/
/* this will replace %20 or any hex with the space or correct char
* returns error */
static int
clipboard_check_file(char *filename)
{
char lfilename[256];
char jchr[8];
int lindex;
int index;
g_memset(lfilename, 0, 256);
lindex = 0;
index = 0;
while (filename[index] != 0)
{
if (filename[index] == '%')
{
jchr[0] = filename[index + 1];
jchr[1] = filename[index + 2];
jchr[2] = 0;
index += 3;
lfilename[lindex] = g_htoi(jchr);
lindex++;
}
else
{
lfilename[lindex] = filename[index];
lindex++;
index++;
}
}
LOG_DEVEL(LOG_LEVEL_DEBUG, "[%s] [%s]", filename, lfilename);
g_strcpy(filename, lfilename);
return 0;
}
/*****************************************************************************/
static int
clipboard_get_file(const char *file, int bytes)
{
int sindex;
int pindex;
int flags;
char full_fn[256]; /* /etc/xrdp/xrdp.ini */
char filename[256]; /* xrdp.ini */
char pathname[256]; /* /etc/xrdp */
char *full_fn;
struct cb_file_info *cfi;
int result = 1;
/* x-special/gnome-copied-files */
if ((g_strncmp(file, "copy", 4) == 0) && (bytes == 4))
@ -171,35 +228,23 @@ clipboard_get_file(const char *file, int bytes)
{
return 0;
}
sindex = 0;
flags = CB_FILE_ATTRIBUTE_ARCHIVE;
/* text/uri-list */
/* x-special/gnome-copied-files */
if (g_strncmp(file, "file://", 7) == 0)
if (bytes > 7 && g_strncmp(file, "file://", 7) == 0)
{
sindex = 7;
full_fn = decode_rfc3986(file + 7, bytes - 7);
}
pindex = bytes;
while (pindex > sindex)
else
{
if (file[pindex] == '/')
{
break;
}
pindex--;
full_fn = decode_rfc3986(file, bytes);
}
g_memset(pathname, 0, 256);
g_memset(filename, 0, 256);
g_memcpy(pathname, file + sindex, pindex - sindex);
if (pathname[0] == 0)
if (full_fn == NULL)
{
pathname[0] = '/';
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: Out of memory");
return 1;
}
g_memcpy(filename, file + pindex + 1, (bytes - 1) - pindex);
/* this should replace %20 with space */
clipboard_check_file(pathname);
clipboard_check_file(filename);
g_snprintf(full_fn, 255, "%s/%s", pathname, filename);
/*
* Before we look at the file, see if it's in the FUSE filesystem. If it is,
@ -209,68 +254,69 @@ clipboard_get_file(const char *file, int bytes)
{
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: Can't add client-side file "
"%s to clipboard", full_fn);
return 1;
}
if (g_directory_exist(full_fn))
else if (g_directory_exist(full_fn))
{
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: file [%s] is a directory, "
"not supported", full_fn);
flags |= CB_FILE_ATTRIBUTE_DIRECTORY;
return 1;
}
if (!g_file_exist(full_fn))
else if (!g_file_exist(full_fn))
{
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: file [%s] does not exist",
full_fn);
return 1;
}
else if ((cfi = alloc_cb_file_info(full_fn)) == NULL)
{
LOG(LOG_LEVEL_ERROR, "clipboard_get_file: Out of memory");
}
else
{
cfi = (struct cb_file_info *)g_malloc(sizeof(struct cb_file_info), 1);
list_add_item(g_files_list, (tintptr)cfi);
g_strcpy(cfi->filename, filename);
g_strcpy(cfi->pathname, pathname);
cfi->size = g_file_get_size(full_fn);
cfi->flags = flags;
cfi->flags = CB_FILE_ATTRIBUTE_ARCHIVE;
cfi->time = (g_time1() + CB_EPOCH_DIFF) * 10000000LL;
LOG_DEVEL(LOG_LEVEL_DEBUG, "ok filename [%s] pathname [%s] size [%d]",
cfi->filename, cfi->pathname, cfi->size);
result = 0;
}
return 0;
free(full_fn);
return result;
}
/*****************************************************************************/
/*
* Calls clipboard_get_file() for each filename in a list.
*
* List items are separated by line terminators. Blank items are ignored */
static int
clipboard_get_files(const char *files, int bytes)
{
int index;
int file_index;
char file[512];
const char *start = files;
const char *end = files + bytes;
const char *p;
file_index = 0;
for (index = 0; index < bytes; index++)
for (p = start ; p < end ; ++p)
{
if (files[index] == '\n' || files[index] == '\r')
if (*p == '\n' || *p == '\r')
{
if (file_index > 0)
/* Skip zero-length files (which might be caused by
* multiple line terminators */
if (p > start)
{
if (clipboard_get_file(file, file_index) == 0)
{
}
file_index = 0;
/* Get file. Errors are logged */
(void)clipboard_get_file(start, p - start);
}
}
else
{
file[file_index] = files[index];
file_index++;
/* Move the start of filename pointer to either 'end', or
* the next character which will either be a filename or
* another terminator */
start = p + 1;
}
}
if (file_index > 0)
if (end > start)
{
if (clipboard_get_file(file, file_index) == 0)
{
}
(void)clipboard_get_file(start, end - start);
}
if (g_files_list->count < 1)
{
@ -492,10 +538,12 @@ clipboard_send_file_data(int streamId, int lindex,
make_stream(s);
init_stream(s, cbRequested + 64);
size = g_file_read(fd, s->data + 12, cbRequested);
if (size < 1)
// If we're at end-of-file, 0 is a valid response
if (size < 0)
{
LOG_DEVEL(LOG_LEVEL_ERROR, "clipboard_send_file_data: read error, want %d got %d",
cbRequested, size);
LOG_DEVEL(LOG_LEVEL_ERROR,
"clipboard_send_file_data: read error, want %d got [%s]",
cbRequested, g_get_strerror());
free_stream(s);
g_file_close(fd);
clipboard_send_filecontents_response_fail(streamId);

View File

@ -53,6 +53,7 @@
#include "log.h"
#include "chansrv.h"
#include "chansrv_fuse.h"
#include "chansrv_xfs.h"
#include "devredir.h"
#include "smartcard.h"
#include "ms-rdpefs.h"
@ -1249,7 +1250,13 @@ devredir_proc_query_dir_response(IRP *irp,
return -1;
}
// Size the filename buffer so it's big enough for
// storing the file in our filesystem if we need to.
#ifdef XFS_MAXFILENAMELEN
char filename[XFS_MAXFILENAMELEN + 1];
#else
char filename[256];
#endif
tui64 LastAccessTime;
tui64 LastWriteTime;
tui64 EndOfFile;

View File

@ -102,6 +102,14 @@ process_sys_login_request(struct pre_session_item *psi)
}
else
{
/*
* Copy the IP address of the requesting user, anticipating a
* successful login. We need this so we can search for a session
* with a matching IP address if required.
*/
g_snprintf(psi->start_ip_addr, sizeof(psi->start_ip_addr),
"%s", ip_addr);
/* Create a sesexec process to handle the login
*
* We won't check for the user being valid here, as this might
@ -323,6 +331,9 @@ process_logout_request(struct pre_session_item *psi)
static int
create_xrdp_socket_path(uid_t uid)
{
// Owner all permissions, group read+execute
#define RWX_PERMS 0x750
int rv = 1;
const char *sockdir_group = g_cfg->sec.session_sockdir_group;
int gid = 0; // Default if no group specified
@ -330,14 +341,21 @@ create_xrdp_socket_path(uid_t uid)
char sockdir[XRDP_SOCKETS_MAXPATH];
g_snprintf(sockdir, sizeof(sockdir), XRDP_SOCKET_PATH, (int)uid);
// Create directory permissions 0x750, if it doesn't exist already.
int old_umask = g_umask_hex(0x750 ^ 0x777);
// Create directory permissions RWX_PERMS, if it doesn't exist already
// (our os_calls layer doesn't allow us to set the SGID bit here)
int old_umask = g_umask_hex(RWX_PERMS ^ 0x777);
if (!g_directory_exist(sockdir) && !g_create_dir(sockdir))
{
LOG(LOG_LEVEL_ERROR,
"create_xrdp_socket_path: Can't create %s [%s]",
sockdir, g_get_strerror());
}
else if (g_chmod_hex(sockdir, RWX_PERMS | 0x2000) != 0)
{
LOG(LOG_LEVEL_ERROR,
"create_xrdp_socket_path: Can't set SGID bit on %s [%s]",
sockdir, g_get_strerror());
}
else if (sockdir_group != NULL && sockdir_group[0] != '\0' &&
g_getgroup_info(sockdir_group, &gid) != 0)
{
@ -358,6 +376,7 @@ create_xrdp_socket_path(uid_t uid)
(void)g_umask_hex(old_umask);
return rv;
#undef RWX_PERMS
}
/******************************************************************************/

View File

@ -579,8 +579,9 @@ print_version(void)
{
g_writeln("xrdp-sesman %s", PACKAGE_VERSION);
g_writeln(" The xrdp session manager");
g_writeln(" Copyright (C) 2004-2023 Jay Sorg, "
"Neutrino Labs, and all contributors.");
g_writeln(" Copyright (C) 2004-%d Jay Sorg, "
"Neutrino Labs, and all contributors.",
VERSION_YEAR);
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
g_writeln("%s", "");

View File

@ -209,9 +209,12 @@ x_server_running_check_ports(int display)
/******************************************************************************/
/* Helper function for get_sorted_display_list():qsort() */
static int
icmp(const void *i1, const void *i2)
icmp(const void *v1, const void *v2)
{
return *(const unsigned int *)i2 - *(const unsigned int *)i1;
// Pointers point to unsigned ints
unsigned int i1 = *(unsigned int *)v1;
unsigned int i2 = *(unsigned int *)v2;
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
/******************************************************************************/

View File

@ -108,6 +108,9 @@ START_TEST(test_g_signal_child_stop_1)
pid = g_fork();
if (pid == 0)
{
// Before raising the signal, change directory to a non-writeable
// one to avoid generating a corefile.
g_set_current_dir("/");
raise(SIGSEGV);
}
ck_assert_int_ne(pid, 0);

View File

@ -1,4 +1,5 @@
AM_CPPFLAGS = \
-DXRDP_TOP_SRCDIR=\"$(top_srcdir)\" \
-I$(top_builddir) \
-I$(top_srcdir)/xrdp \
-I$(top_srcdir)/libxrdp \
@ -18,7 +19,14 @@ EXTRA_DIST = \
test_not4_8bit.bmp \
test_not4_24bit.bmp \
test1.jpg \
test_alpha_blend.png
test_alpha_blend.png \
gfx/gfx.toml\
gfx/gfx_codec_order_undefined.toml \
gfx/gfx_codec_h264_preferred.toml \
gfx/gfx_codec_h264_only.toml \
gfx/gfx_codec_rfx_preferred.toml \
gfx/gfx_codec_rfx_preferred_odd.toml \
gfx/gfx_codec_rfx_only.toml
TESTS = test_xrdp
check_PROGRAMS = test_xrdp
@ -28,6 +36,7 @@ test_xrdp_SOURCES = \
test_xrdp_main.c \
test_xrdp_egfx.c \
test_xrdp_region.c \
test_tconfig.c \
test_bitmap_load.c
test_xrdp_CFLAGS = \
@ -47,6 +56,7 @@ test_xrdp_LDADD = \
$(top_builddir)/libxrdp/libxrdp.la \
$(top_builddir)/libpainter/src/libpainter.la \
$(top_builddir)/librfxcodec/src/librfxencode.la \
$(top_builddir)/third_party/tomlc99/libtoml.la \
$(top_builddir)/xrdp/lang.o \
$(top_builddir)/xrdp/xrdp_mm.o \
$(top_builddir)/xrdp/xrdp_wm.o \
@ -60,8 +70,16 @@ test_xrdp_LDADD = \
$(top_builddir)/xrdp/xrdp_encoder.o \
$(top_builddir)/xrdp/xrdp_process.o \
$(top_builddir)/xrdp/xrdp_login_wnd.o \
$(top_builddir)/xrdp/xrdp_tconfig.o \
$(top_builddir)/xrdp/xrdp_main_utils.o \
$(PIXMAN_LIBS) \
$(IMLIB2_LIBS) \
@CHECK_LIBS@ \
@CMOCKA_LIBS@
if XRDP_X264
AM_CPPFLAGS += -DXRDP_X264 $(XRDP_X264_CFLAGS)
test_xrdp_LDADD += \
$(top_builddir)/xrdp/xrdp_encoder_x264.o \
$(XRDP_X264_LIBS)
endif

40
tests/xrdp/gfx/gfx.toml Normal file
View File

@ -0,0 +1,40 @@
[codec]
order = [ "H.264", "RFX" ]
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
# inherits default
[x264.wan]
vbv_max_bitrate = 15000
vbv_buffer_size = 1500
[x264.broadband_high]
preset = "superfast"
vbv_max_bitrate = 8000
vbv_buffer_Size = 800
[x264.satellite]
preset = "superfast"
vbv_max_bitrate = 5000
vbv_buffer_size = 500
[x264.broadband_low]
preset = "veryfast"
tune = "zerolatency"
vbv_max_bitrate = 1600
vbv_buffer_size = 66
[x264.modem]
preset = "fast"
tune = "zerolatency"
vbv_max_bitrate = 1200
vbv_buffer_size = 50

View File

@ -0,0 +1,18 @@
[codec]
order = [ "H.264" ]
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
[x264.wan]
[x264.broadband_high]
[x264.satellite]
[x264.broadband_low]
[x264.modem]

View File

@ -0,0 +1,18 @@
[codec]
order = [ "H.264", "RFX" ]
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
[x264.wan]
[x264.broadband_high]
[x264.satellite]
[x264.broadband_low]
[x264.modem]

View File

@ -0,0 +1,18 @@
[codec]
order = [ ]
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
[x264.wan]
[x264.broadband_high]
[x264.satellite]
[x264.broadband_low]
[x264.modem]

View File

@ -0,0 +1,18 @@
[codec]
order = [ "RFX" ]
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
[x264.wan]
[x264.broadband_high]
[x264.satellite]
[x264.broadband_low]
[x264.modem]

View File

@ -0,0 +1,18 @@
[codec]
order = [ "RFX", "H.264" ]
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
[x264.wan]
[x264.broadband_high]
[x264.satellite]
[x264.broadband_low]
[x264.modem]

View File

@ -0,0 +1,18 @@
[codec]
order = [ "RFX", "H.264", "RFX" ]
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
[x264.wan]
[x264.broadband_high]
[x264.satellite]
[x264.broadband_low]
[x264.modem]

View File

@ -0,0 +1,9 @@
[codec]
order = [ "H.264", "RFX" ]
[x264.lan]
[x264.wan]
[x264.broadband_high]
[x264.satellite]
[x264.broadband_low]
[x264.modem]

117
tests/xrdp/test_tconfig.c Normal file
View File

@ -0,0 +1,117 @@
#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include "xrdp_tconfig.h"
#include "test_xrdp.h"
#include "xrdp.h"
#define GFXCONF_STUBDIR XRDP_TOP_SRCDIR "/tests/xrdp/gfx/"
START_TEST(test_tconfig_gfx_always_success)
{
ck_assert_int_eq(1, 1);
}
END_TEST
START_TEST(test_tconfig_gfx_x264_load_basic)
{
struct xrdp_tconfig_gfx gfxconfig;
int rv = tconfig_load_gfx(GFXCONF_STUBDIR "/gfx.toml", &gfxconfig);
ck_assert_int_eq(rv, 0);
/* default */
ck_assert_str_eq(gfxconfig.x264_param[0].preset, "ultrafast");
ck_assert_str_eq(gfxconfig.x264_param[0].tune, "zerolatency");
ck_assert_str_eq(gfxconfig.x264_param[0].profile, "main");
ck_assert_int_eq(gfxconfig.x264_param[0].vbv_max_bitrate, 0);
ck_assert_int_eq(gfxconfig.x264_param[0].vbv_buffer_size, 0);
ck_assert_int_eq(gfxconfig.x264_param[0].fps_num, 24);
ck_assert_int_eq(gfxconfig.x264_param[0].fps_den, 1);
}
END_TEST
START_TEST(test_tconfig_gfx_codec_order)
{
struct xrdp_tconfig_gfx gfxconfig;
/* H264 earlier */
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_h264_preferred.toml", &gfxconfig);
ck_assert_int_eq(gfxconfig.codec.codec_count, 2);
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_H264);
ck_assert_int_eq(gfxconfig.codec.codecs[1], XTC_RFX);
/* H264 only */
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_h264_only.toml", &gfxconfig);
ck_assert_int_eq(gfxconfig.codec.codec_count, 1);
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_H264);
/* RFX earlier */
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_rfx_preferred.toml", &gfxconfig);
ck_assert_int_eq(gfxconfig.codec.codec_count, 2);
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
ck_assert_int_eq(gfxconfig.codec.codecs[1], XTC_H264);
/* RFX appears twice like: RFX, H264, RFX */
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_rfx_preferred_odd.toml", &gfxconfig);
ck_assert_int_eq(gfxconfig.codec.codec_count, 2);
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
ck_assert_int_eq(gfxconfig.codec.codecs[1], XTC_H264);
/* RFX only */
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_rfx_only.toml", &gfxconfig);
ck_assert_int_eq(gfxconfig.codec.codec_count, 1);
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
/* H264 is preferred if order undefined */
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_codec_order_undefined.toml", &gfxconfig);
ck_assert_int_eq(gfxconfig.codec.codec_count, 2);
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_H264);
ck_assert_int_eq(gfxconfig.codec.codecs[1], XTC_RFX);
}
END_TEST
START_TEST(test_tconfig_gfx_missing_file)
{
struct xrdp_tconfig_gfx gfxconfig;
/* Check RFX config is returned if the file doesn't exist */
tconfig_load_gfx(GFXCONF_STUBDIR "/no_such_file.toml", &gfxconfig);
ck_assert_int_eq(gfxconfig.codec.codec_count, 1);
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
}
END_TEST
START_TEST(test_tconfig_gfx_missing_h264)
{
struct xrdp_tconfig_gfx gfxconfig;
/* Check RFX config only is returned if H.264 parameters are missing */
tconfig_load_gfx(GFXCONF_STUBDIR "/gfx_missing_h264.toml", &gfxconfig);
ck_assert_int_eq(gfxconfig.codec.codec_count, 1);
ck_assert_int_eq(gfxconfig.codec.codecs[0], XTC_RFX);
}
END_TEST
/******************************************************************************/
Suite *
make_suite_tconfig_load_gfx(void)
{
Suite *s;
TCase *tc_tconfig_load_gfx;
s = suite_create("GfxLoad");
tc_tconfig_load_gfx = tcase_create("xrdp_tconfig_load_gfx");
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_always_success);
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_x264_load_basic);
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_codec_order);
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_missing_file);
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_missing_h264);
suite_add_tcase(s, tc_tconfig_load_gfx);
return s;
}

View File

@ -6,5 +6,6 @@
Suite *make_suite_test_bitmap_load(void);
Suite *make_suite_egfx_base_functions(void);
Suite *make_suite_region(void);
Suite *make_suite_tconfig_load_gfx(void);
#endif /* TEST_XRDP_H */

View File

@ -57,6 +57,7 @@ int main (void)
sr = srunner_create (make_suite_test_bitmap_load());
srunner_add_suite(sr, make_suite_egfx_base_functions());
srunner_add_suite(sr, make_suite_region());
srunner_add_suite(sr, make_suite_tconfig_load_gfx());
srunner_set_tap(sr, "-");
srunner_run_all (sr, CK_ENV);

431
vnc/vnc.c
View File

@ -149,17 +149,13 @@ log_screen_layout(const enum logLevels lvl, const char *source,
* @param a First structure
* @param b Second structure
*
* @return Suitable for sorting structures with ID as the primary key
* @return Suitable for sorting structures on (x, y, width, height)
*/
static int cmp_vnc_screen(const struct vnc_screen *a,
const struct vnc_screen *b)
{
int result = 0;
if (a->id != b->id)
{
result = a->id - b->id;
}
else if (a->x != b->x)
if (a->x != b->x)
{
result = a->x - b->x;
}
@ -211,9 +207,7 @@ static int vnc_screen_layouts_equal(const struct vnc_screen_layout *a,
* @return != 0 for error
*
* @pre The next octet read from v->trans is the number of screens
* @pre layout is not already allocated
*
* @post if call is successful, layout->s must be freed after use.
* @post Returned structure is in increasing ID order
* @post layout->total_width is untouched
* @post layout->total_height is untouched
@ -225,10 +219,8 @@ read_extended_desktop_size_rect(struct vnc *v,
struct stream *s;
int error;
unsigned int count;
struct vnc_screen *screens;
layout->count = 0;
layout->s = NULL;
make_stream(s);
init_stream(s, 8192);
@ -239,46 +231,41 @@ read_extended_desktop_size_rect(struct vnc *v,
{
/* Get the number of screens */
in_uint8(s, count);
in_uint8s(s, 3);
error = trans_force_read_s(v->trans, s, 16 * count);
if (error == 0)
if (count <= 0 || count > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
{
screens = g_new(struct vnc_screen, count);
if (screens == NULL)
{
LOG(LOG_LEVEL_ERROR,
"VNC : Can't alloc for %d screens", count);
error = 1;
}
else
LOG(LOG_LEVEL_ERROR,
"Bad monitor count %d in ExtendedDesktopSize rectangle",
count);
error = 1;
}
else
{
in_uint8s(s, 3);
error = trans_force_read_s(v->trans, s, 16 * count);
if (error == 0)
{
unsigned int i;
for (i = 0 ; i < count ; ++i)
{
in_uint32_be(s, screens[i].id);
in_uint16_be(s, screens[i].x);
in_uint16_be(s, screens[i].y);
in_uint16_be(s, screens[i].width);
in_uint16_be(s, screens[i].height);
in_uint32_be(s, screens[i].flags);
in_uint32_be(s, layout->s[i].id);
in_uint16_be(s, layout->s[i].x);
in_uint16_be(s, layout->s[i].y);
in_uint16_be(s, layout->s[i].width);
in_uint16_be(s, layout->s[i].height);
in_uint32_be(s, layout->s[i].flags);
}
/* sort monitors in increasing ID order */
qsort(screens, count, sizeof(screens[0]),
/* sort monitors in increasing (x,y) order */
qsort(layout->s, count, sizeof(layout->s[0]),
(int (*)(const void *, const void *))cmp_vnc_screen);
layout->count = count;
}
}
}
free_stream(s);
if (error == 0)
{
layout->count = count;
layout->s = screens;
}
return error;
}
@ -326,88 +313,76 @@ send_set_desktop_size(struct vnc *v, const struct vnc_screen_layout *layout)
}
/**************************************************************************//**
* Sets up a single-screen vnc_screen_layout structure
*
* @param layout Structure to set up
* @param width New client width
* @param height New client height
*
* @pre layout->count must be valid
* @pre layout->s must be valid
* Initialises a vnc_screen_layout as a single screen
* @param[in] width Screen Width
* @param[in] height Screen Height
* @param[out] layout Layout to initialise
*/
static void
set_single_screen_layout(struct vnc_screen_layout *layout,
int width, int height)
init_single_screen_layout(int width, int height,
struct vnc_screen_layout *layout)
{
int id = 0;
int flags = 0;
layout->total_width = width;
layout->total_height = height;
if (layout->count == 0)
{
/* No previous layout */
layout->s = g_new(struct vnc_screen, 1);
}
else
{
/* Keep the ID and flags from the previous first screen */
id = layout->s[0].id;
flags = layout->s[0].flags;
if (layout->count > 1)
{
g_free(layout->s);
layout->s = g_new(struct vnc_screen, 1);
}
}
layout->count = 1;
layout->s[0].id = id;
layout->s[0].id = 0;
layout->s[0].x = 0;
layout->s[0].y = 0;
layout->s[0].width = width;
layout->s[0].height = height;
layout->s[0].flags = flags;
layout->s[0].flags = 0;
}
/**************************************************************************//**
* Resize the client as a single screen
* Resize the client to match the server_layout
*
* @param v VNC object
* @param update_in_progress True if there's a painter update in progress
* @param width New client width
* @param height New client height
* @return != 0 for error
*
* The new client layout is recorded in v->client_layout. If the client was
* multi-screen before this call, it won't be afterwards.
* The new client layout is recorded in v->client_layout.
*/
static int
resize_client(struct vnc *v, int update_in_progress, int width, int height)
resize_client_to_server(struct vnc *v, int update_in_progress)
{
int error = 0;
unsigned int i;
const struct vnc_screen_layout *sl = &v->server_layout;
struct monitor_info client_mons[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS] = {0};
if (v->client_layout.count != 1 ||
v->client_layout.total_width != width ||
v->client_layout.total_height != height)
if (sl->count <= 0 ||
sl->count > CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
{
if (update_in_progress)
{
error = v->server_end_update(v);
}
LOG(LOG_LEVEL_ERROR, "%s: Programming error. Bad monitors %d",
__func__, sl->count);
return 1;
}
// Convert the server monitors into client monitors
for (i = 0; i < sl->count; ++i)
{
client_mons[i].left = sl->s[i].x;
client_mons[i].top = sl->s[i].y;
client_mons[i].right = sl->s[i].x + sl->s[i].width - 1;
client_mons[i].bottom = sl->s[i].y + sl->s[i].height - 1;
}
if (update_in_progress && v->server_end_update(v) != 0)
{
error = 1;
}
else
{
error = v->client_monitor_resize(v, sl->total_width, sl->total_height,
sl->count, client_mons);
if (error == 0)
{
error = v->server_reset(v, width, height, v->server_bpp);
if (error == 0)
{
set_single_screen_layout(&v->client_layout, width, height);
if (update_in_progress)
{
error = v->server_begin_update(v);
}
}
v->client_layout = *sl;
}
if (update_in_progress && v->server_begin_update(v) != 0)
{
error = 1;
}
}
@ -416,50 +391,53 @@ resize_client(struct vnc *v, int update_in_progress, int width, int height)
/**************************************************************************//**
* Resize the attached client from a layout
* Resize the server to the client layout
*
* @param v VNC object
* @param update_in_progress True if there's a painter update in progress
* @param layout Desired layout from server
* @return != 0 for error
*
* This has some limitations. We have no way to move multiple screens about
* on a connected client, and so we are not able to change the client unless
* we're changing to a single screen layout.
* The new client layout is recorded in v->client_layout.
*/
static int
resize_client_from_layout(struct vnc *v,
int update_in_progress,
const struct vnc_screen_layout *layout)
resize_server_to_client_layout(struct vnc *v)
{
int error = 0;
if (!vnc_screen_layouts_equal(&v->client_layout, layout))
if (v->resize_supported != VRSS_SUPPORTED)
{
LOG(LOG_LEVEL_ERROR, "%s: Asked to resize server, but not possible",
__func__);
error = 1;
}
else if (vnc_screen_layouts_equal(&v->server_layout, &v->client_layout))
{
LOG(LOG_LEVEL_DEBUG, "Server layout is the same "
"as the client layout");
v->resize_status = VRS_DONE;
}
else
{
/*
* we don't have the capability to resize to anything other
* than a single screen.
* If we've only got one screen, and the other side has
* only got one screen, we will preserve their screen ID
* and any flags. This may prevent us sending an unwanted
* SetDesktopSize message if the screen dimensions are
* a match. We can't do this with more than one screen,
* as we have no way to map different IDs
*/
if (layout->count != 1)
if (v->server_layout.count == 1 && v->client_layout.count == 1)
{
LOG(LOG_LEVEL_ERROR,
"VNC Resize to %d screen(s) from %d screen(s) "
"not implemented",
v->client_layout.count, layout->count);
LOG(LOG_LEVEL_DEBUG, "VNC "
"setting screen id to %d from server",
v->server_layout.s[0].id);
/* Dump some useful info, in case we get here when we don't
* need to */
log_screen_layout(LOG_LEVEL_ERROR, "OldLayout", &v->client_layout);
log_screen_layout(LOG_LEVEL_ERROR, "NewLayout", layout);
error = 1;
}
else
{
error = resize_client(v,
update_in_progress,
layout->total_width,
layout->total_height);
v->client_layout.s[0].id = v->server_layout.s[0].id;
v->client_layout.s[0].flags = v->server_layout.s[0].flags;
}
LOG(LOG_LEVEL_DEBUG, "Changing server layout");
error = send_set_desktop_size(v, &v->client_layout);
v->resize_status = VRS_WAITING_FOR_RESIZE_CONFIRM;
}
return error;
@ -927,7 +905,6 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
"x=%d, y=%d geom=%dx%d",
x, y, cx, cy);
error = read_extended_desktop_size_rect(v, &layout);
g_free(layout.s);
}
break;
@ -944,7 +921,7 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
* Parses an entire framebuffer update message from the wire, and returns the
* first matching ExtendedDesktopSize encoding if found.
*
* Caller can check for a match by examining match_layout.s after the call
* Caller can check for a match by examining match_layout.count after the call
*
* @param v VNC object
* @param match Function to call to check for a match
@ -952,8 +929,6 @@ skip_encoding(struct vnc *v, int x, int y, int cx, int cy,
* @param [out] match_y Matching y parameter for an encoding (if needed)
* @param [out] match_layout Returned layout for the encoding
* @return != 0 for error
*
* @post After a successful call, match_layout.s must be free'd
*/
static int
find_matching_extended_rect(struct vnc *v,
@ -971,8 +946,7 @@ find_matching_extended_rect(struct vnc *v,
int cx;
int cy;
encoding_type encoding;
match_layout->s = NULL;
int found = 0;
make_stream(s);
init_stream(s, 8192);
@ -1002,14 +976,14 @@ find_matching_extended_rect(struct vnc *v,
in_uint32_be(s, encoding);
if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE &&
match_layout->s == NULL &&
!found &&
match(x, y, cx, cy))
{
LOG(LOG_LEVEL_DEBUG,
"VNC matched ExtendedDesktopSize rectangle "
"x=%d, y=%d geom=%dx%d",
x, y, cx, cy);
found = 1;
error = read_extended_desktop_size_rect(v, match_layout);
if (match_x)
{
@ -1065,6 +1039,7 @@ send_update_request_for_resize_status(struct vnc *v)
switch (v->resize_status)
{
case VRS_WAITING_FOR_FIRST_UPDATE:
case VRS_WAITING_FOR_RESIZE_CONFIRM:
/*
* Ask for an immediate, minimal update.
*/
@ -1078,20 +1053,6 @@ send_update_request_for_resize_status(struct vnc *v)
error = lib_send_copy(v, s);
break;
case VRS_WAITING_FOR_RESIZE_CONFIRM:
/*
* Ask for a deferred minimal update.
*/
out_uint8(s, RFB_C2S_FRAMEBUFFER_UPDATE_REQUEST);
out_uint8(s, 1); /* incremental == 1 : Changes only */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
out_uint16_be(s, 1);
out_uint16_be(s, 1);
s_mark_end(s);
error = lib_send_copy(v, s);
break;
default:
/*
* Ask for a full update from the server
@ -1102,8 +1063,8 @@ send_update_request_for_resize_status(struct vnc *v)
out_uint8(s, 0); /* incremental == 0 : Full update */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
out_uint16_be(s, v->server_width);
out_uint16_be(s, v->server_height);
out_uint16_be(s, v->server_layout.total_width);
out_uint16_be(s, v->server_layout.total_height);
s_mark_end(s);
error = lib_send_copy(v, s);
}
@ -1159,12 +1120,15 @@ lib_framebuffer_first_update(struct vnc *v)
&layout);
if (error == 0)
{
if (layout.s != NULL)
if (layout.count > 0)
{
LOG(LOG_LEVEL_DEBUG, "VNC server supports resizing");
v->resize_supported = VRSS_SUPPORTED;
v->server_layout = layout;
/* Force the client geometry over to the server */
log_screen_layout(LOG_LEVEL_INFO, "OldLayout", &layout);
log_screen_layout(LOG_LEVEL_INFO, "ClientLayout", &v->client_layout);
log_screen_layout(LOG_LEVEL_INFO, "OldServerLayout", &layout);
/*
* If we've only got one screen, and the other side has
@ -1184,32 +1148,19 @@ lib_framebuffer_first_update(struct vnc *v)
v->client_layout.s[0].flags = layout.s[0].flags;
}
if (vnc_screen_layouts_equal(&layout, &v->client_layout))
{
LOG(LOG_LEVEL_DEBUG, "Server layout is the same "
"as the client layout");
v->resize_status = VRS_DONE;
}
else
{
LOG(LOG_LEVEL_DEBUG, "Server layout differs from "
"the client layout. Changing server layout");
error = send_set_desktop_size(v, &v->client_layout);
v->resize_status = VRS_WAITING_FOR_RESIZE_CONFIRM;
}
resize_server_to_client_layout(v);
}
else
{
LOG(LOG_LEVEL_DEBUG, "VNC server does not support resizing");
v->resize_supported = VRSS_NOT_SUPPORTED;
/* Force client to same size as server */
LOG(LOG_LEVEL_DEBUG, "Resizing client to server %dx%d",
v->server_width, v->server_height);
error = resize_client(v, 0, v->server_width, v->server_height);
v->server_layout.total_width, v->server_layout.total_height);
error = resize_client_to_server(v, 0);
v->resize_status = VRS_DONE;
}
g_free(layout.s);
}
if (error == 0)
@ -1224,7 +1175,7 @@ lib_framebuffer_first_update(struct vnc *v)
* Looks for a resize confirm in a framebuffer update request
*
* If the server supports resizes from us, this is used to find the
* reply to our initial resize request. See The RFB community wiki for details.
* reply to our resize request. See The RFB community wiki for details.
*
* @param v VNC object
* @return != 0 for error
@ -1243,18 +1194,17 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
&layout);
if (error == 0)
{
if (layout.s != NULL)
if (layout.count > 0)
{
if (response_code == 0)
{
LOG(LOG_LEVEL_DEBUG, "VNC server successfully resized");
log_screen_layout(LOG_LEVEL_INFO, "NewLayout", &layout);
v->server_layout = layout;
// If this resize was requested by the client mid-session
// (dynamic resize), we need to tell xrdp_mm that
// it's OK to continue with the resize state machine.
// We do this by sending a reset with bpp == 0
error = v->server_reset(v, v->server_width,
v->server_height, 0);
error = v->server_monitor_resize_done(v);
}
else
{
@ -1263,14 +1213,11 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v)
response_code,
rfb_get_eds_status_msg(response_code));
/* Force client to same size as server */
LOG(LOG_LEVEL_WARNING, "Resizing client to server %dx%d",
v->server_width, v->server_height);
error = resize_client(v, 0, v->server_width, v->server_height);
LOG(LOG_LEVEL_WARNING, "Resizing client to server");
error = resize_client_to_server(v, 0);
}
v->resize_status = VRS_DONE;
}
g_free(layout.s);
}
if (error == 0)
@ -1415,9 +1362,8 @@ lib_framebuffer_update(struct vnc *v)
else if (encoding == RFB_ENC_DESKTOP_SIZE)
{
/* Server end has resized */
v->server_width = cx;
v->server_height = cy;
error = resize_client(v, 1, cx, cy);
init_single_screen_layout(cx, cy, &v->server_layout);
error = resize_client_to_server(v, 1);
}
else if (encoding == RFB_ENC_EXTENDED_DESKTOP_SIZE)
{
@ -1427,11 +1373,14 @@ lib_framebuffer_update(struct vnc *v)
/* If this is a reply to a request from us, x == 1 */
if (error == 0 && x != 1)
{
v->server_width = layout.total_width;
v->server_height = layout.total_height;
error = resize_client_from_layout(v, 1, &layout);
if (!vnc_screen_layouts_equal(&v->server_layout, &layout))
{
v->server_layout = layout;
log_screen_layout(LOG_LEVEL_INFO, "NewServerLayout",
&v->server_layout);
error = resize_client_to_server(v, 1);
}
}
g_free(layout.s);
}
else
{
@ -1456,8 +1405,8 @@ lib_framebuffer_update(struct vnc *v)
out_uint8(s, 1); /* incremental == 1 : Changes only */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
out_uint16_be(s, v->server_width);
out_uint16_be(s, v->server_height);
out_uint16_be(s, v->server_layout.total_width);
out_uint16_be(s, v->server_layout.total_height);
s_mark_end(s);
error = lib_send_copy(v, s);
}
@ -1831,8 +1780,11 @@ lib_mod_connect(struct vnc *v)
if (error == 0)
{
in_uint16_be(s, v->server_width);
in_uint16_be(s, v->server_height);
int width;
int height;
in_uint16_be(s, width);
in_uint16_be(s, height);
init_single_screen_layout(width, height, &v->server_layout);
init_stream(pixel_format, 8192);
v->server_msg(v, "VNC receiving pixel format", 0);
@ -2000,6 +1952,7 @@ lib_mod_connect(struct vnc *v)
if (error == 0)
{
v->resize_supported = VRSS_UNKNOWN;
v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE;
error = send_update_request_for_resize_status(v);
}
@ -2061,33 +2014,40 @@ lib_mod_end(struct vnc *v)
/**************************************************************************//**
* Initialises the client layout from the Windows monitor definition.
*
* @param [out] layout Our layout
* @param [in] client_info WM info
* @param v VNC module
* @param [in] width session width
* @param [in] height session height
* @param [in] num_monitors (can be 0, meaning one monitor)
* @param [in] monitors Monitor definitions for num_monitors > 0
* @param [in] multimon_configured Whether multimon is configured
*/
static void
init_client_layout(struct vnc_screen_layout *layout,
const struct xrdp_client_info *client_info)
init_client_layout(struct vnc *v,
int width, int height,
int num_monitors,
const struct monitor_info *monitors)
{
uint32_t i;
layout->total_width = client_info->display_sizes.session_width;
layout->total_height = client_info->display_sizes.session_height;
layout->count = client_info->display_sizes.monitorCount;
layout->s = g_new(struct vnc_screen, layout->count);
for (i = 0 ; i < client_info->display_sizes.monitorCount ; ++i)
struct vnc_screen_layout *layout = &v->client_layout;
if (!v->multimon_configured || num_monitors < 1)
{
/* Use minfo_wm, as this is normalised for a top-left of (0,0)
* as required by RFC6143 */
layout->s[i].id = i;
layout->s[i].x = client_info->display_sizes.minfo_wm[i].left;
layout->s[i].y = client_info->display_sizes.minfo_wm[i].top;
layout->s[i].width = client_info->display_sizes.minfo_wm[i].right -
client_info->display_sizes.minfo_wm[i].left + 1;
layout->s[i].height = client_info->display_sizes.minfo_wm[i].bottom -
client_info->display_sizes.minfo_wm[i].top + 1;
layout->s[i].flags = 0;
init_single_screen_layout(width, height, layout);
}
else
{
layout->total_width = width;
layout->total_height = height;
layout->count = num_monitors;
unsigned int i;
for (i = 0 ; i < layout->count; ++i)
{
layout->s[i].id = i;
layout->s[i].x = monitors[i].left;
layout->s[i].y = monitors[i].top;
layout->s[i].width = monitors[i].right - monitors[i].left + 1;
layout->s[i].height = monitors[i].bottom - monitors[i].top + 1;
layout->s[i].flags = 0;
}
}
}
@ -2132,19 +2092,16 @@ lib_mod_set_param(struct vnc *v, const char *name, const char *value)
const struct xrdp_client_info *client_info =
(const struct xrdp_client_info *) value;
g_free(v->client_layout.s);
v->multimon_configured = client_info->multimon;
/* Save monitor information from the client */
if (!client_info->multimon || client_info->display_sizes.monitorCount < 1)
{
set_single_screen_layout(&v->client_layout,
client_info->display_sizes.session_width,
client_info->display_sizes.session_height);
}
else
{
init_client_layout(&v->client_layout, client_info);
}
/* Save monitor information from the client
* Use minfo_wm, as this is normalised for a top-left of (0,0)
* as required by RFC6143 */
init_client_layout(v,
client_info->display_sizes.session_width,
client_info->display_sizes.session_height,
client_info->display_sizes.monitorCount,
client_info->display_sizes.minfo_wm);
log_screen_layout(LOG_LEVEL_DEBUG, "client_info", &v->client_layout);
}
@ -2185,6 +2142,10 @@ lib_mod_check_wait_objs(struct vnc *v)
if (v->trans != 0)
{
rv = trans_check_wait_objs(v->trans);
if (rv != 0)
{
LOG(LOG_LEVEL_ERROR, "VNC server closed connection");
}
}
}
return rv;
@ -2217,8 +2178,8 @@ lib_mod_suppress_output(struct vnc *v, int suppress,
out_uint8(s, 0); /* incremental == 0 : Full contents */
out_uint16_be(s, 0);
out_uint16_be(s, 0);
out_uint16_be(s, v->server_width);
out_uint16_be(s, v->server_height);
out_uint16_be(s, v->server_layout.total_width);
out_uint16_be(s, v->server_layout.total_height);
s_mark_end(s);
error = lib_send_copy(v, s);
free_stream(s);
@ -2237,12 +2198,29 @@ lib_mod_server_version_message(struct vnc *v)
/******************************************************************************/
/* return error */
int
lib_mod_server_monitor_resize(struct vnc *v, int width, int height)
lib_mod_server_monitor_resize(struct vnc *v, int width, int height,
int num_monitors,
const struct monitor_info *monitors,
int *in_progress)
{
int error = 0;
set_single_screen_layout(&v->client_layout, width, height);
v->resize_status = VRS_WAITING_FOR_FIRST_UPDATE;
error = send_update_request_for_resize_status(v);
int error;
*in_progress = 0;
init_client_layout(v, width, height, num_monitors, monitors);
if ((error = resize_server_to_client_layout(v)) == 0)
{
// If we're waiting for a confirmation, send an update request.
// According to the spec this should not be needed, but
// it works around a buggy VNC server not sending an
// ExtendedDesktopSize rectangle if the desktop change is
// small (eg. same dimensions, but 2 monitors -> 1 monitor)
if (v->resize_status == VRS_WAITING_FOR_RESIZE_CONFIRM &&
(error = send_update_request_for_resize_status(v)) == 0)
{
*in_progress = 1;
}
}
return error;
}
@ -2298,7 +2276,6 @@ mod_exit(tintptr handle)
return 0;
}
trans_delete(v->trans);
g_free(v->client_layout.s);
vnc_clip_exit(v);
g_free(v);
return 0;

View File

@ -27,6 +27,7 @@
#include "os_calls.h"
#include "defines.h"
#include "guid.h"
#include "ms-rdpbcgr.h"
#define CURRENT_MOD_VER 4
@ -46,8 +47,8 @@ struct vnc_screen_layout
int total_width;
int total_height;
unsigned int count;
/* For comparison, screens are sorted in increasing order of ID */
struct vnc_screen *s;
/* For comparison, screens are sorted in x, y, width, height) order */
struct vnc_screen s[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS];
};
/**
@ -60,11 +61,21 @@ enum vnc_resize_status
VRS_DONE
};
enum vnc_resize_support_status
{
VRSS_NOT_SUPPORTED,
VRSS_SUPPORTED,
VRSS_UNKNOWN
};
struct source_info;
/* Defined in vnc_clip.c */
struct vnc_clipboard_data;
/* Defined in xrdp_client_info.h */
struct monitor_info;
struct vnc
{
int size; /* size of this struct */
@ -85,7 +96,10 @@ struct vnc
int (*mod_suppress_output)(struct vnc *v, int suppress,
int left, int top, int right, int bottom);
int (*mod_server_monitor_resize)(struct vnc *v,
int width, int height);
int width, int height,
int num_monitors,
const struct monitor_info *monitors,
int *in_progress);
int (*mod_server_monitor_full_invalidate)(struct vnc *v,
int width, int height);
int (*mod_server_version_message)(struct vnc *v);
@ -123,7 +137,10 @@ struct vnc
int box_left, int box_top,
int box_right, int box_bottom,
int x, int y, char *data, int data_len);
int (*server_reset)(struct vnc *v, int width, int height, int bpp);
int (*client_monitor_resize)(struct vnc *v, int width, int height,
int num_monitors,
const struct monitor_info *monitors);
int (*server_monitor_resize_done)(struct vnc *v);
int (*server_get_channel_count)(struct vnc *v);
int (*server_query_channel)(struct vnc *v, int index,
char *channel_name,
@ -134,7 +151,7 @@ struct vnc
int total_data_len, int flags);
int (*server_bell_trigger)(struct vnc *v);
int (*server_chansrv_in_use)(struct vnc *v);
tintptr server_dumby[100 - 27]; /* align, 100 minus the number of server
tintptr server_dumby[100 - 28]; /* align, 100 minus the number of server
functions above */
/* common */
tintptr handle; /* pointer to self as long */
@ -142,8 +159,6 @@ struct vnc
tintptr painter;
struct source_info *si;
/* mod data */
int server_width;
int server_height;
int server_bpp;
char mod_name[256];
int mod_mouse_state;
@ -164,8 +179,11 @@ struct vnc
int suppress_output;
unsigned int enabled_encodings_mask;
/* Resizeable support */
int multimon_configured;
struct vnc_screen_layout client_layout;
struct vnc_screen_layout server_layout;
enum vnc_resize_status resize_status;
enum vnc_resize_support_status resize_supported;
};
/*

View File

@ -19,6 +19,7 @@ AM_CPPFLAGS = \
$(IMLIB2_CFLAGS)
XRDP_EXTRA_LIBS =
XRDP_EXTRA_SOURCES =
if XRDP_RFXCODEC
AM_CPPFLAGS += -DXRDP_RFXCODEC
@ -26,6 +27,13 @@ AM_CPPFLAGS += -I$(top_srcdir)/librfxcodec/include
XRDP_EXTRA_LIBS += $(top_builddir)/librfxcodec/src/.libs/librfxencode.a
endif
if XRDP_X264
AM_CPPFLAGS += -DXRDP_X264
AM_CPPFLAGS += $(XRDP_X264_CFLAGS)
XRDP_EXTRA_LIBS += $(XRDP_X264_LIBS)
XRDP_EXTRA_SOURCES += xrdp_encoder_x264.c xrdp_encoder_x264.h
endif
if XRDP_PIXMAN
AM_CPPFLAGS += -DXRDP_PIXMAN
AM_CPPFLAGS += $(PIXMAN_CFLAGS)
@ -46,6 +54,7 @@ xrdp_SOURCES = \
lang.c \
xrdp.c \
xrdp.h \
xrdp.ini.in \
xrdp_bitmap.c \
xrdp_bitmap_load.c \
xrdp_bitmap_common.c \
@ -63,7 +72,10 @@ xrdp_SOURCES = \
xrdp_egfx.c \
xrdp_egfx.h \
xrdp_wm.c \
xrdp_main_utils.c
xrdp_main_utils.c \
xrdp_tconfig.c \
xrdp_tconfig.h \
$(XRDP_EXTRA_SOURCES)
xrdp_LDADD = \
$(top_builddir)/common/libcommon.la \
@ -93,9 +105,12 @@ SUFFIXES = .in
$(subst_verbose)$(SUBST_VARS) $< > $@
dist_xrdpsysconf_DATA = \
xrdp.ini \
gfx.toml \
xrdp_keyboard.ini
nodist_xrdpsysconf_DATA = \
xrdp.ini
xrdppkgdatadir=$(datadir)/xrdp
dist_xrdppkgdata_DATA = \
@ -110,3 +125,5 @@ dist_xrdppkgdata_DATA = \
sans-18.fv1 \
cursor0.cur \
cursor1.cur
CLEANFILES = $(nodist_xrdpsysconf_DATA)

40
xrdp/gfx.toml Normal file
View File

@ -0,0 +1,40 @@
[codec]
order = [ "H.264", "RFX" ]
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
# inherits default
[x264.wan]
vbv_max_bitrate = 15000
vbv_buffer_size = 1500
[x264.broadband_high]
preset = "superfast"
vbv_max_bitrate = 8000
vbv_buffer_Size = 800
[x264.satellite]
preset = "superfast"
vbv_max_bitrate = 5000
vbv_buffer_size = 500
[x264.broadband_low]
preset = "veryfast"
tune = "zerolatency"
vbv_max_bitrate = 1600
vbv_buffer_size = 66
[x264.modem]
preset = "fast"
tune = "zerolatency"
vbv_max_bitrate = 1200
vbv_buffer_size = 50

View File

@ -53,8 +53,9 @@ print_version(void)
{
g_writeln("xrdp %s", PACKAGE_VERSION);
g_writeln(" A Remote Desktop Protocol Server.");
g_writeln(" Copyright (C) 2004-2020 Jay Sorg, "
"Neutrino Labs, and all contributors.");
g_writeln(" Copyright (C) 2004-%d Jay Sorg, "
"Neutrino Labs, and all contributors.",
VERSION_YEAR);
g_writeln(" See https://github.com/neutrinolabs/xrdp for more information.");
g_writeln("%s", "");

View File

@ -38,6 +38,14 @@
#include "xrdp_client_info.h"
#include "log.h"
#if defined(XRDP_X264) || defined(XRDP_OPENH264) || defined(XRDP_NVENC)
#if !defined(XRDP_H264)
#define XRDP_H264 1
#endif
#else
#undef XRDP_H264
#endif
/* xrdp.c */
long
g_xrdp_sync(long (*sync_func)(long param1, long param2), long sync_param1,
@ -502,6 +510,9 @@ int
xrdp_mm_check_wait_objs(struct xrdp_mm *self);
int
xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id);
void
xrdp_mm_efgx_add_dirty_region_to_planar_list(struct xrdp_mm *self,
struct xrdp_region *dirty_region);
int
xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self,
struct xrdp_bitmap *bitmap,
@ -591,7 +602,10 @@ server_draw_text(struct xrdp_mod *mod, int font,
int box_right, int box_bottom,
int x, int y, char *data, int data_len);
int
server_reset(struct xrdp_mod *mod, int width, int height, int bpp);
client_monitor_resize(struct xrdp_mod *mod, int width, int height,
int num_monitors, const struct monitor_info *monitors);
int
server_monitor_resize_done(struct xrdp_mod *mod);
int
is_channel_allowed(struct xrdp_wm *wm, int channel_id);
int

View File

@ -35,7 +35,10 @@ tcp_nodelay=true
; if the network connection disappear without close messages the connection will be closed
tcp_keepalive=true
; set tcp send/recv buffer (for experts)
; set tcp send/recv buffer
; These parameters are largely historic. On systems with dynamic TCP
; buffer sizes, setting them manually will either impact performance or
; waste memory
#tcp_send_buffer_bytes=32768
#tcp_recv_buffer_bytes=32768
@ -85,7 +88,8 @@ max_bpp=32
new_cursors=true
; fastpath - can be 'input', 'output', 'both', 'none'
use_fastpath=both
; when true, userid/password *must* be passed on cmd line
; when true, userid/password *must* be passed on cmd line. If the password
; is incorrect, the login will fail
#require_credentials=true
; when true, the userid will be used to try to authenticate
#enable_token_login=true
@ -219,7 +223,6 @@ drdynvc=true
cliprdr=true
rail=true
xrdpvr=true
tcutils=true
; for debugging xrdp, in section xrdp1, change port=-1 to this:
#port=/tmp/.xrdp/xrdp_display_10

View File

@ -301,8 +301,6 @@ xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
return 1;
}
self->width = width;
self->height = height;
Bpp = 4;
switch (self->bpp)
@ -318,8 +316,28 @@ xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height)
break;
}
g_free(self->data);
self->data = (char *)g_malloc(width * height * Bpp, 0);
/* To prevent valgrind errors (particularly on a screen resize),
clear extra memory */
unsigned long old_size = self->width * self->height * Bpp;
unsigned long new_size = width * height * Bpp;
char *new_data = (char *)realloc(self->data, new_size);
if (new_data == NULL)
{
return 1;
}
self->width = width;
self->height = height;
if (new_data != self->data)
{
self->data = new_data;
memset(self->data, 0, new_size);
}
else if (new_size > old_size)
{
memset(self->data + old_size, 0, new_size - old_size);
}
self->line_size = width * Bpp;
return 0;
}

View File

@ -392,8 +392,11 @@ xrdp_egfx_send_frame_start(struct xrdp_egfx *egfx, int frame_id, int timestamp)
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_frame_start:");
s = xrdp_egfx_frame_start(egfx->bulk, frame_id, timestamp);
error = xrdp_egfx_send_s(egfx, s);
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_start: xrdp_egfx_send_s "
"error %d", error);
if (error != 0)
{
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_start: xrdp_egfx_send_s "
"error %d", error);
}
free_stream(s);
return error;
}
@ -434,8 +437,11 @@ xrdp_egfx_send_frame_end(struct xrdp_egfx *egfx, int frame_id)
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_frame_end:");
s = xrdp_egfx_frame_end(egfx->bulk, frame_id);
error = xrdp_egfx_send_s(egfx, s);
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_end: xrdp_egfx_send_s "
"error %d", error);
if (error != 0)
{
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_frame_end: xrdp_egfx_send_s "
"error %d", error);
}
free_stream(s);
return error;
}
@ -769,7 +775,7 @@ xrdp_egfx_process_frame_ack(struct xrdp_egfx *egfx, struct stream *s)
in_uint32_le(s, queueDepth);
in_uint32_le(s, intframeId);
in_uint32_le(s, totalFramesDecoded);
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_process_frame_ack: queueDepth %d"
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_process_frame_ack: queueDepth %d"
" intframeId %d totalFramesDecoded %d",
queueDepth, intframeId, totalFramesDecoded);
if (egfx->frame_ack != NULL)
@ -869,7 +875,7 @@ xrdp_egfx_process(struct xrdp_egfx *egfx, struct stream *s)
in_uint16_le(s, flags);
in_uint32_le(s, pduLength);
s->end = holdp + pduLength;
LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_process: cmdId 0x%x flags %d"
LOG(LOG_LEVEL_TRACE, "xrdp_egfx_process: cmdId 0x%x flags %d"
" pduLength %d", cmdId, flags, pduLength);
if (pduLength < 8)
{
@ -1121,6 +1127,10 @@ xrdp_egfx_shutdown_close_connection(struct xrdp_egfx *egfx)
return error;
}
// Ignore any messages we haven't processed yet
egfx->caps_advertise = NULL;
egfx->frame_ack = NULL;
return error;
}

View File

@ -222,6 +222,10 @@ xrdp_egfx_send_wire_to_surface2(struct xrdp_egfx *egfx, int surface_id,
int codec_id, int codec_context_id,
int pixel_format,
void *bitmap_data, int bitmap_data_length);
/*
* NB: mi below must be such that the (top,left) co-ordinate of
* the primary monitor is (0.0)
*/
struct stream *
xrdp_egfx_reset_graphics(struct xrdp_egfx_bulk *bulk, int width, int height,
int monitor_count, struct monitor_info *mi);

View File

@ -28,21 +28,55 @@
#include "thread_calls.h"
#include "fifo.h"
#include "xrdp_egfx.h"
#include "string_calls.h"
#ifdef XRDP_RFXCODEC
#include "rfxcodec_encode.h"
#endif
#ifdef XRDP_X264
#include "xrdp_encoder_x264.h"
#endif
#define DEFAULT_XRDP_GFX_FRAMES_IN_FLIGHT 2
/* limits used for validate env var XRDP_GFX_FRAMES_IN_FLIGHT */
#define MIN_XRDP_GFX_FRAMES_IN_FLIGHT 1
#define MAX_XRDP_GFX_FRAMES_IN_FLIGHT 16
#define DEFAULT_XRDP_GFX_MAX_COMPRESSED_BYTES (3 * 1024 * 1024)
/* limits used for validate env var XRDP_GFX_MAX_COMPRESSED_BYTES */
#define MIN_XRDP_GFX_MAX_COMPRESSED_BYTES (64 * 1024)
#define MAX_XRDP_GFX_MAX_COMPRESSED_BYTES (256 * 1024 * 1024)
#define XRDP_SURCMD_PREFIX_BYTES 256
#define OUT_DATA_BYTES_DEFAULT_SIZE (16 * 1024 * 1024)
#ifdef XRDP_RFXCODEC
/* LH3 LL3, HH3 HL3, HL2 LH2, LH1 HH2, HH1 HL1 todo check this */
static const unsigned char g_rfx_quantization_values[] =
/*
* LH3 LL3, HH3 HL3, HL2 LH2, LH1 HH2, HH1 HL1
* https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdprfx/3e9c8af4-7539-4c9d-95de-14b1558b902c
*/
/* standard quality */
static const unsigned char g_rfx_quantization_values_std[] =
{
0x66, 0x66, 0x77, 0x87, 0x98,
0x76, 0x77, 0x88, 0x98, 0x99
};
/* low quality */
static const unsigned char g_rfx_quantization_values_lq[] =
{
0x66, 0x66, 0x77, 0x87, 0x98,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA /* TODO: tentative value */
};
/* ultra low quality */
static const unsigned char g_rfx_quantization_values_ulq[] =
{
0x66, 0x66, 0x77, 0x87, 0x98,
0xBB, 0xBB, 0xBB, 0xBB, 0xBB /* TODO: tentative value */
};
#endif
struct enc_rect
@ -59,11 +93,13 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
#ifdef XRDP_RFXCODEC
static int
process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
static int
process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
#endif
#ifdef XRDP_X264
static int
process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
#endif
static int
process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc);
/*****************************************************************************/
/* Item destructor for self->fifo_to_proc */
@ -71,8 +107,15 @@ static void
xrdp_enc_data_destructor(void *item, void *closure)
{
XRDP_ENC_DATA *enc = (XRDP_ENC_DATA *)item;
g_free(enc->u.sc.drects);
g_free(enc->u.sc.crects);
if (ENC_IS_BIT_SET(enc->flags, ENC_FLAGS_GFX_BIT))
{
g_free(enc->u.gfx.cmd);
}
else
{
g_free(enc->u.sc.drects);
g_free(enc->u.sc.crects);
}
g_free(enc);
}
@ -117,53 +160,80 @@ xrdp_encoder_create(struct xrdp_mm *mm)
return NULL;
}
self->mm = mm;
self->process_enc = process_enc_egfx;
if (client_info->jpeg_codec_id != 0)
{
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting jpeg codec session");
self->codec_id = client_info->jpeg_codec_id;
self->in_codec_mode = 1;
self->codec_quality = client_info->jpeg_prop[0];
client_info->capture_code = 0;
client_info->capture_code = CC_SIMPLE;
client_info->capture_format = XRDP_a8b8g8r8;
self->process_enc = process_enc_jpg;
}
#ifdef XRDP_X264
else if (mm->egfx_flags & XRDP_EGFX_H264)
{
LOG(LOG_LEVEL_INFO,
"xrdp_encoder_create: starting h264 codec session gfx");
self->in_codec_mode = 1;
client_info->capture_code = CC_GFX_A2;
client_info->capture_format = XRDP_nv12_709fr;
self->gfx = 1;
}
else if (client_info->h264_codec_id != 0)
{
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting h264 codec session");
self->codec_id = client_info->h264_codec_id;
self->in_codec_mode = 1;
client_info->capture_code = CC_SUF_A2;
client_info->capture_format = XRDP_nv12;
self->process_enc = process_enc_h264;
}
#endif
#ifdef XRDP_RFXCODEC
else if (mm->egfx_flags & XRDP_EGFX_RFX_PRO)
{
LOG(LOG_LEVEL_INFO,
"xrdp_encoder_create: starting gfx rfx pro codec session");
self->in_codec_mode = 1;
client_info->capture_code = 4;
self->process_enc = process_enc_egfx;
client_info->capture_code = CC_GFX_PRO;
self->gfx = 1;
self->quants = (const char *) g_rfx_quantization_values;
self->num_quants = 2;
self->quant_idx_y = 0;
self->quant_idx_u = 1;
self->quant_idx_v = 1;
switch (client_info->mcs_connection_type)
{
case CONNECTION_TYPE_MODEM:
case CONNECTION_TYPE_BROADBAND_LOW:
case CONNECTION_TYPE_SATELLITE:
self->quants = (const char *) g_rfx_quantization_values_ulq;
break;
case CONNECTION_TYPE_BROADBAND_HIGH:
case CONNECTION_TYPE_WAN:
self->quants = (const char *) g_rfx_quantization_values_lq;
break;
case CONNECTION_TYPE_LAN:
case CONNECTION_TYPE_AUTODETECT: /* not implemented yet */
default:
self->quants = (const char *) g_rfx_quantization_values_std;
}
}
else if (client_info->rfx_codec_id != 0)
{
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting rfx codec session");
self->codec_id = client_info->rfx_codec_id;
self->in_codec_mode = 1;
client_info->capture_code = 2;
client_info->capture_code = CC_SUF_RFX;
self->process_enc = process_enc_rfx;
self->codec_handle_rfx = rfxcodec_encode_create(mm->wm->screen->width,
mm->wm->screen->height,
RFX_FORMAT_YUV, 0);
}
#endif
else if (client_info->h264_codec_id != 0)
{
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting h264 codec session");
self->codec_id = client_info->h264_codec_id;
self->in_codec_mode = 1;
client_info->capture_code = 3;
client_info->capture_format = XRDP_nv12;
self->process_enc = process_enc_h264;
}
else
{
g_free(self);
@ -186,12 +256,50 @@ xrdp_encoder_create(struct xrdp_mm *mm)
g_snprintf(buf, 1024, "xrdp_%8.8x_encoder_event_processed", pid);
self->xrdp_encoder_event_processed = g_create_wait_obj(buf);
g_snprintf(buf, 1024, "xrdp_%8.8x_encoder_term", pid);
self->xrdp_encoder_term = g_create_wait_obj(buf);
self->xrdp_encoder_term_request = g_create_wait_obj(buf);
self->xrdp_encoder_term_done = g_create_wait_obj(buf);
if (client_info->gfx)
{
// Magic numbers... Why?
self->frames_in_flight = 2;
self->max_compressed_bytes = 3145728;
const char *env_var = g_getenv("XRDP_GFX_FRAMES_IN_FLIGHT");
self->frames_in_flight = DEFAULT_XRDP_GFX_FRAMES_IN_FLIGHT;
if (env_var != NULL)
{
int fif = g_atoix(env_var);
if (fif >= MIN_XRDP_GFX_FRAMES_IN_FLIGHT &&
fif <= MAX_XRDP_GFX_FRAMES_IN_FLIGHT)
{
self->frames_in_flight = fif;
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
"XRDP_GFX_FRAMES_IN_FLIGHT set to %d", fif);
}
else
{
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
"XRDP_GFX_FRAMES_IN_FLIGHT set but invalid %s",
env_var);
}
}
env_var = g_getenv("XRDP_GFX_MAX_COMPRESSED_BYTES");
self->max_compressed_bytes = DEFAULT_XRDP_GFX_MAX_COMPRESSED_BYTES;
if (env_var != NULL)
{
int mcb = g_atoix(env_var);
if (mcb >= MIN_XRDP_GFX_MAX_COMPRESSED_BYTES &&
mcb <= MAX_XRDP_GFX_MAX_COMPRESSED_BYTES)
{
self->max_compressed_bytes = mcb;
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
"XRDP_GFX_MAX_COMPRESSED_BYTES set to %d", mcb);
}
else
{
LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: "
"XRDP_GFX_MAX_COMPRESSED_BYTES set but invalid %s",
env_var);
}
}
LOG_DEVEL(LOG_LEVEL_INFO, "Using %d max_compressed_bytes for encoder",
self->max_compressed_bytes);
}
else
{
@ -225,8 +333,12 @@ xrdp_encoder_delete(struct xrdp_encoder *self)
return;
}
/* tell worker thread to shut down */
g_set_wait_obj(self->xrdp_encoder_term);
g_sleep(1000);
g_set_wait_obj(self->xrdp_encoder_term_request);
g_obj_wait(&self->xrdp_encoder_term_done, 1, NULL, 0, 5000);
if (!g_is_wait_obj_set(self->xrdp_encoder_term_done))
{
LOG(LOG_LEVEL_WARNING, "Encoder failed to shut down cleanly");
}
#ifdef XRDP_RFXCODEC
for (index = 0; index < 16; index++)
@ -247,7 +359,7 @@ xrdp_encoder_delete(struct xrdp_encoder *self)
{
if (self->codec_handle_h264_gfx[index] != NULL)
{
rfxcodec_encode_destroy(self->codec_handle_h264_gfx[index]);
xrdp_encoder_x264_delete(self->codec_handle_h264_gfx[index]);
}
}
if (self->codec_handle_h264 != NULL)
@ -259,7 +371,8 @@ xrdp_encoder_delete(struct xrdp_encoder *self)
/* destroy wait objects used for signalling */
g_delete_wait_obj(self->xrdp_encoder_event_to_proc);
g_delete_wait_obj(self->xrdp_encoder_event_processed);
g_delete_wait_obj(self->xrdp_encoder_term);
g_delete_wait_obj(self->xrdp_encoder_term_request);
g_delete_wait_obj(self->xrdp_encoder_term_done);
/* cleanup fifos */
fifo_delete(self->fifo_to_proc, NULL);
@ -515,6 +628,61 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
}
#endif
#if defined(XRDP_X264)
/*****************************************************************************/
static int
out_RFX_AVC420_METABLOCK(struct xrdp_egfx_rect *dst_rect,
struct stream *s,
struct xrdp_egfx_rect *rects,
int num_rects)
{
struct xrdp_region *reg;
struct xrdp_rect rect;
int index;
int count;
/* RFX_AVC420_METABLOCK */
s_push_layer(s, iso_hdr, 4); /* numRegionRects, set later */
reg = xrdp_region_create(NULL);
if (reg == NULL)
{
return 1;
}
for (index = 0; index < num_rects; index++)
{
rect.left = MAX(0, rects[index].x1 - dst_rect->x1 - 1);
rect.top = MAX(0, rects[index].y1 - dst_rect->y1 - 1);
rect.right = MIN(dst_rect->x2 - dst_rect->x1,
rects[index].x2 - dst_rect->x1 + 1);
rect.bottom = MIN(dst_rect->y2 - dst_rect->y1,
rects[index].y2 - dst_rect->y1 + 1);
xrdp_region_add_rect(reg, &rect);
}
index = 0;
while (xrdp_region_get_rect(reg, index, &rect) == 0)
{
out_uint16_le(s, rect.left);
out_uint16_le(s, rect.top);
out_uint16_le(s, rect.right);
out_uint16_le(s, rect.bottom);
index++;
}
xrdp_region_delete(reg);
count = index;
while (index > 0)
{
out_uint8(s, 23); /* qp */
out_uint8(s, 100); /* quality level 0..100 */
index--;
}
s_push_layer(s, mcs_hdr, 0);
s_pop_layer(s, iso_hdr);
out_uint32_le(s, count); /* numRegionRects */
s_pop_layer(s, mcs_hdr);
return 0;
}
/*****************************************************************************/
/* called from encoder thread */
static int
@ -524,27 +692,267 @@ process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
return 0;
}
#ifdef XRDP_RFXCODEC
#endif
/*****************************************************************************/
static int
gfx_send_done(struct xrdp_encoder *self, XRDP_ENC_DATA *enc,
int comp_bytes, int pad_bytes, char *comp_pad_data,
int got_frame_id, int frame_id, int is_last)
{
XRDP_ENC_DATA_DONE *enc_done;
enc_done = g_new0(XRDP_ENC_DATA_DONE, 1);
if (enc_done == NULL)
{
return 1;
}
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_GFX_BIT);
enc_done->enc = enc;
enc_done->last = is_last;
enc_done->pad_bytes = pad_bytes;
enc_done->comp_bytes = comp_bytes;
enc_done->comp_pad_data = comp_pad_data;
if (got_frame_id)
{
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_FRAME_ID_BIT);
enc_done->frame_id = frame_id;
}
/* inform main thread done */
tc_mutex_lock(self->mutex);
fifo_add_item(self->fifo_processed, enc_done);
tc_mutex_unlock(self->mutex);
/* signal completion for main thread */
g_set_wait_obj(self->xrdp_encoder_event_processed);
return 0;
}
/*****************************************************************************/
static struct stream *
gfx_wiretosurface1(struct xrdp_encoder *self,
struct xrdp_egfx_bulk *bulk, struct stream *in_s,
struct xrdp_enc_gfx_cmd *enc_gfx_cmd)
XRDP_ENC_DATA *enc)
{
#ifdef XRDP_X264
int index;
int surface_id;
int codec_id;
int pixel_format;
int num_rects_d;
int num_rects_c;
struct stream *rv;
short left;
short top;
short width;
short height;
short twidth;
short theight;
int bitmap_data_length;
int flags;
struct xrdp_egfx_rect *d_rects;
struct xrdp_egfx_rect *c_rects;
struct xrdp_egfx_rect dst_rect;
int error;
struct stream ls;
struct stream *s;
short *crects;
struct xrdp_enc_gfx_cmd *enc_gfx_cmd = &(enc->u.gfx);
int mon_index;
int connection_type;
connection_type = self->mm->wm->client_info->mcs_connection_type;
s = &ls;
g_memset(s, 0, sizeof(struct stream));
s->size = self->max_compressed_bytes;
s->data = g_new(char, s->size);
if (s->data == NULL)
{
return NULL;
}
s->p = s->data;
if (!s_check_rem(in_s, 11))
{
g_free(s->data);
return NULL;
}
in_uint16_le(in_s, surface_id);
in_uint16_le(in_s, codec_id);
in_uint8(in_s, pixel_format);
in_uint32_le(in_s, flags);
mon_index = (flags >> 28) & 0xF;
in_uint16_le(in_s, num_rects_d);
if ((num_rects_d < 1) || (num_rects_d > 16 * 1024) ||
(!s_check_rem(in_s, num_rects_d * 8)))
{
g_free(s->data);
return NULL;
}
d_rects = g_new0(struct xrdp_egfx_rect, num_rects_d);
if (d_rects == NULL)
{
g_free(s->data);
return NULL;
}
for (index = 0; index < num_rects_d; index++)
{
in_uint16_le(in_s, left);
in_uint16_le(in_s, top);
in_uint16_le(in_s, width);
in_uint16_le(in_s, height);
d_rects[index].x1 = left;
d_rects[index].y1 = top;
d_rects[index].x2 = left + width;
d_rects[index].y2 = top + height;
}
if (!s_check_rem(in_s, 2))
{
g_free(s->data);
g_free(d_rects);
return NULL;
}
in_uint16_le(in_s, num_rects_c);
if ((num_rects_c < 1) || (num_rects_c > 16 * 1024) ||
(!s_check_rem(in_s, num_rects_c * 8)))
{
g_free(s->data);
g_free(d_rects);
return NULL;
}
c_rects = g_new0(struct xrdp_egfx_rect, num_rects_c);
if (c_rects == NULL)
{
g_free(s->data);
g_free(d_rects);
return NULL;
}
crects = g_new(short, num_rects_c * 4);
if (crects == NULL)
{
g_free(s->data);
g_free(c_rects);
g_free(d_rects);
return NULL;
}
g_memcpy(crects, in_s->p, num_rects_c * 2 * 4);
for (index = 0; index < num_rects_c; index++)
{
in_uint16_le(in_s, left);
in_uint16_le(in_s, top);
in_uint16_le(in_s, width);
in_uint16_le(in_s, height);
c_rects[index].x1 = left;
c_rects[index].y1 = top;
c_rects[index].x2 = left + width;
c_rects[index].y2 = top + height;
}
if (!s_check_rem(in_s, 8))
{
g_free(s->data);
g_free(c_rects);
g_free(d_rects);
g_free(crects);
return NULL;
}
in_uint16_le(in_s, left);
in_uint16_le(in_s, top);
in_uint16_le(in_s, width);
in_uint16_le(in_s, height);
twidth = width;
theight = height;
dst_rect.x1 = 0;
dst_rect.y1 = 0;
dst_rect.x2 = width;
dst_rect.y2 = height;
LOG_DEVEL(LOG_LEVEL_INFO, "gfx_wiretosurface1: left %d top "
"%d width %d height %d mon_index %d",
left, top, width, height, mon_index);
/* RFX_AVC420_METABLOCK */
if (out_RFX_AVC420_METABLOCK(&dst_rect, s, d_rects, num_rects_d) != 0)
{
g_free(s->data);
g_free(c_rects);
g_free(d_rects);
g_free(crects);
LOG(LOG_LEVEL_INFO, "10");
return NULL;
}
g_free(c_rects);
g_free(d_rects);
if (ENC_IS_BIT_SET(flags, 0))
{
/* already compressed */
out_uint8a(s, enc_gfx_cmd->data, enc_gfx_cmd->data_bytes);
}
else
{
/* assume NV12 format */
if (twidth * theight * 3 / 2 > enc_gfx_cmd->data_bytes)
{
g_free(s->data);
g_free(crects);
return NULL;
}
bitmap_data_length = s_rem_out(s);
if (self->codec_handle_h264_gfx[mon_index] == NULL)
{
self->codec_handle_h264_gfx[mon_index] =
xrdp_encoder_x264_create();
if (self->codec_handle_h264_gfx[mon_index] == NULL)
{
g_free(s->data);
g_free(crects);
return NULL;
}
}
error = xrdp_encoder_x264_encode(
self->codec_handle_h264_gfx[mon_index], 0,
0, 0,
width, height, twidth, theight, 0,
enc_gfx_cmd->data,
crects, num_rects_c,
s->p, &bitmap_data_length,
connection_type, NULL);
if (error == 0)
{
xstream_seek(s, bitmap_data_length);
}
else
{
g_free(s->data);
g_free(crects);
return NULL;
}
}
s_mark_end(s);
bitmap_data_length = (int) (s->end - s->data);
rv = xrdp_egfx_wire_to_surface1(bulk, surface_id,
codec_id,
pixel_format, &dst_rect,
s->data, bitmap_data_length);
g_free(s->data);
g_free(crects);
return rv;
#else
(void)self;
(void)bulk;
(void)in_s;
(void)enc_gfx_cmd;
(void)enc;
return NULL;
#endif
}
/*****************************************************************************/
static struct stream *
gfx_wiretosurface2(struct xrdp_encoder *self,
struct xrdp_egfx_bulk *bulk, struct stream *in_s,
struct xrdp_enc_gfx_cmd *enc_gfx_cmd)
XRDP_ENC_DATA *enc)
{
#ifdef XRDP_RFXCODEC
int index;
int surface_id;
int codec_id;
@ -561,10 +969,10 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
int bitmap_data_length;
struct rfx_tile *tiles;
struct rfx_rect *rfxrects;
int tiles_compressed;
int flags;
int total_tiles;
int tiles_written;
int do_free;
int do_send;
int mon_index;
if (!s_check_rem(in_s, 15))
@ -641,6 +1049,9 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
in_uint16_le(in_s, top);
in_uint16_le(in_s, width);
in_uint16_le(in_s, height);
LOG_DEVEL(LOG_LEVEL_INFO, "gfx_wiretosurface2: left %d top "
"%d width %d height %d mon_index %d",
left, top, width, height, mon_index);
if (self->codec_handle_prfx_gfx[mon_index] == NULL)
{
self->codec_handle_prfx_gfx[mon_index] = rfxcodec_encode_create(
@ -649,60 +1060,80 @@ gfx_wiretosurface2(struct xrdp_encoder *self,
RFX_FORMAT_YUV,
RFX_FLAGS_RLGR1 | RFX_FLAGS_PRO1);
if (self->codec_handle_prfx_gfx[mon_index] == NULL)
{
return NULL;
}
}
do_free = 0;
do_send = 0;
if (ENC_IS_BIT_SET(flags, 0))
{
/* already compressed */
bitmap_data_length = enc_gfx_cmd->data_bytes;
bitmap_data = enc_gfx_cmd->data;
do_send = 1;
}
else
{
bitmap_data_length = self->max_compressed_bytes;
bitmap_data = g_new(char, bitmap_data_length);
if (bitmap_data == NULL)
{
g_free(tiles);
g_free(rfxrects);
return NULL;
}
do_free = 1;
tiles_written = rfxcodec_encode(self->codec_handle_prfx_gfx[mon_index],
bitmap_data,
&bitmap_data_length,
enc_gfx_cmd->data,
width, height,
((width + 63) & ~63) * 4,
rfxrects, num_rects_d,
tiles, num_rects_c,
self->quants, self->num_quants);
if (tiles_written > 0)
{
do_send = 1;
}
}
g_free(tiles);
g_free(rfxrects);
rv = NULL;
if (do_send)
bitmap_data_length = self->max_compressed_bytes;
bitmap_data = g_new(char, bitmap_data_length);
if (bitmap_data == NULL)
{
g_free(tiles);
g_free(rfxrects);
return NULL;
}
rv = NULL;
tiles_written = 0;
total_tiles = num_rects_c;
for (;;)
{
tiles_compressed =
rfxcodec_encode(self->codec_handle_prfx_gfx[mon_index],
bitmap_data,
&bitmap_data_length,
enc->u.gfx.data,
width, height,
((width + 63) & ~63) * 4,
rfxrects, num_rects_d,
tiles + tiles_written, total_tiles - tiles_written,
self->quants, self->num_quants);
if (tiles_compressed < 1)
{
break;
}
tiles_written += tiles_compressed;
rv = xrdp_egfx_wire_to_surface2(bulk, surface_id,
codec_id, codec_context_id,
pixel_format,
bitmap_data, bitmap_data_length);
if (rv == NULL)
{
break;
}
LOG_DEVEL(LOG_LEVEL_ERROR, "gfx_wiretosurface2: "
"tiles_compressed %d total_tiles %d tiles_written %d",
tiles_compressed, total_tiles,
tiles_written);
if (tiles_written >= total_tiles)
{
/* ok, done with last tile set */
break;
}
/* we have another tile set, send this one to main thread */
if (gfx_send_done(self, enc, (int)(rv->end - rv->data), 0,
rv->data, 0, 0, 0) != 0)
{
free_stream(rv);
rv = NULL;
break;
}
g_free(rv); /* don't call free_stream() here so s->data is valid */
rv = NULL;
bitmap_data_length = self->max_compressed_bytes;
}
if (do_free)
{
g_free(bitmap_data);
}
g_free(tiles);
g_free(rfxrects);
g_free(bitmap_data);
return rv;
#else
(void)self;
(void)bulk;
(void)in_s;
(void)enc;
return NULL;
#endif
}
/*****************************************************************************/
@ -902,20 +1333,14 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
struct stream *s;
struct stream in_s;
struct xrdp_egfx_bulk *bulk;
XRDP_ENC_DATA_DONE *enc_done;
struct fifo *fifo_processed;
tbus mutex;
tbus event_processed;
int cmd_id;
int cmd_bytes;
int frame_id;
int got_frame_id;
int error;
char *holdp;
char *holdend;
fifo_processed = self->fifo_processed;
mutex = self->mutex;
event_processed = self->xrdp_encoder_event_processed;
bulk = self->mm->egfx->bulk;
g_memset(&in_s, 0, sizeof(in_s));
in_s.data = enc->u.gfx.cmd;
@ -937,13 +1362,14 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
}
holdend = in_s.end;
in_s.end = holdp + cmd_bytes;
LOG_DEVEL(LOG_LEVEL_INFO, "process_enc_egfx: cmd_id %d", cmd_id);
switch (cmd_id)
{
case XR_RDPGFX_CMDID_WIRETOSURFACE_1: /* 0x0001 */
s = gfx_wiretosurface1(self, bulk, &in_s, &(enc->u.gfx));
s = gfx_wiretosurface1(self, bulk, &in_s, enc);
break;
case XR_RDPGFX_CMDID_WIRETOSURFACE_2: /* 0x0002 */
s = gfx_wiretosurface2(self, bulk, &in_s, &(enc->u.gfx));
s = gfx_wiretosurface2(self, bulk, &in_s, enc);
break;
case XR_RDPGFX_CMDID_SOLIDFILL: /* 0x0004 */
s = gfx_solidfill(self, bulk, &in_s);
@ -973,44 +1399,32 @@ process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc)
default:
break;
}
if (s == NULL)
{
LOG(LOG_LEVEL_ERROR, "process_enc_egfx: cmd_id %d s = nil", cmd_id);
return 1;
}
/* setup for next cmd */
in_s.p = holdp + cmd_bytes;
in_s.end = holdend;
/* setup enc_done struct */
enc_done = g_new0(XRDP_ENC_DATA_DONE, 1);
if (enc_done == NULL)
if (s != NULL)
{
free_stream(s);
return 1;
/* send message to main thread */
error = gfx_send_done(self, enc, (int) (s->end - s->data),
0, s->data, got_frame_id, frame_id,
!s_check_rem(&in_s, 8));
if (error != 0)
{
LOG(LOG_LEVEL_ERROR, "process_enc_egfx: gfx_send_done failed "
"error %d", error);
free_stream(s);
return 1;
}
g_free(s); /* don't call free_stream() here so s->data is valid */
}
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_GFX_BIT);
enc_done->enc = enc;
enc_done->last = !s_check_rem(&in_s, 8);
enc_done->comp_bytes = (int) (s->end - s->data);
enc_done->comp_pad_data = s->data;
if (got_frame_id)
else
{
ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_FRAME_ID_BIT);
enc_done->frame_id = frame_id;
LOG_DEVEL(LOG_LEVEL_INFO, "process_enc_egfx: nil");
}
g_free(s); /* don't call free_stream() here so s->data is valid */
/* inform main thread done */
tc_mutex_lock(mutex);
fifo_add_item(fifo_processed, enc_done);
tc_mutex_unlock(mutex);
/* signal completion for main thread */
g_set_wait_obj(event_processed);
}
return 0;
}
#endif
/**
* Encoder thread main loop
*****************************************************************************/
@ -1045,7 +1459,7 @@ proc_enc_msg(void *arg)
event_to_proc = self->xrdp_encoder_event_to_proc;
term_obj = g_get_term();
lterm_obj = self->xrdp_encoder_term;
lterm_obj = self->xrdp_encoder_term_request;
cont = 1;
while (cont)
@ -1096,6 +1510,7 @@ proc_enc_msg(void *arg)
}
} /* end while (cont) */
g_set_wait_obj(self->xrdp_encoder_term_done);
LOG_DEVEL(LOG_LEVEL_DEBUG, "proc_enc_msg: thread exit");
return 0;
}

View File

@ -24,7 +24,8 @@ struct xrdp_encoder
int max_compressed_bytes;
tbus xrdp_encoder_event_to_proc;
tbus xrdp_encoder_event_processed;
tbus xrdp_encoder_term;
tbus xrdp_encoder_term_request;
tbus xrdp_encoder_term_done;
struct fifo *fifo_to_proc;
struct fifo *fifo_processed;
tbus mutex;

256
xrdp/xrdp_encoder_x264.c Normal file
View File

@ -0,0 +1,256 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2016-2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* x264 Encoder
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <x264.h>
#include "xrdp.h"
#include "arch.h"
#include "os_calls.h"
#include "xrdp_encoder_x264.h"
#include "xrdp_tconfig.h"
#define X264_MAX_ENCODERS 16
struct x264_encoder
{
x264_t *x264_enc_han;
char *yuvdata;
x264_param_t x264_params;
int width;
int height;
};
struct x264_global
{
struct x264_encoder encoders[X264_MAX_ENCODERS];
struct xrdp_tconfig_gfx_x264_param x264_param[NUM_CONNECTION_TYPES];
};
/*****************************************************************************/
void *
xrdp_encoder_x264_create(void)
{
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_encoder_x264_create:");
struct x264_global *xg;
struct xrdp_tconfig_gfx gfxconfig;
xg = g_new0(struct x264_global, 1);
tconfig_load_gfx(GFX_CONF, &gfxconfig);
memcpy(&xg->x264_param, &gfxconfig.x264_param,
sizeof(struct xrdp_tconfig_gfx_x264_param) * NUM_CONNECTION_TYPES);
return xg;
}
/*****************************************************************************/
int
xrdp_encoder_x264_delete(void *handle)
{
struct x264_global *xg;
struct x264_encoder *xe;
int index;
if (handle == NULL)
{
return 0;
}
xg = (struct x264_global *) handle;
for (index = 0; index < 16; index++)
{
xe = &(xg->encoders[index]);
if (xe->x264_enc_han != NULL)
{
x264_encoder_close(xe->x264_enc_han);
}
g_free(xe->yuvdata);
}
g_free(xg);
return 0;
}
/*****************************************************************************/
int
xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
int width, int height, int twidth, int theight,
int format, const char *data,
short *crects, int num_crects,
char *cdata, int *cdata_bytes, int connection_type,
int *flags_ptr)
{
struct x264_global *xg;
struct x264_encoder *xe;
const char *src8;
char *dst8;
int index;
x264_nal_t *nals;
int num_nals;
int frame_size;
int x264_width_height;
int flags;
int x;
int y;
int cx;
int cy;
int ct; /* connection_type */
x264_picture_t pic_in;
x264_picture_t pic_out;
LOG(LOG_LEVEL_TRACE, "xrdp_encoder_x264_encode:");
flags = 0;
xg = (struct x264_global *) handle;
xe = &(xg->encoders[session % X264_MAX_ENCODERS]);
/* validate connection type */
ct = connection_type;
if (ct > CONNECTION_TYPE_LAN || ct < CONNECTION_TYPE_MODEM)
{
ct = CONNECTION_TYPE_LAN;
}
if ((xe->x264_enc_han == NULL) ||
(xe->width != width) || (xe->height != height))
{
if (xe->x264_enc_han != NULL)
{
LOG(LOG_LEVEL_INFO, "xrdp_encoder_x264_encode: "
"x264_encoder_close %p", xe->x264_enc_han);
x264_encoder_close(xe->x264_enc_han);
xe->x264_enc_han = NULL;
g_free(xe->yuvdata);
xe->yuvdata = NULL;
flags |= 2;
}
if ((width > 0) && (height > 0))
{
x264_param_default_preset(&(xe->x264_params),
xg->x264_param[ct].preset,
xg->x264_param[ct].tune);
xe->x264_params.i_threads = 1;
xe->x264_params.i_width = (width + 15) & ~15;
xe->x264_params.i_height = (height + 15) & ~15;
xe->x264_params.i_fps_num = xg->x264_param[ct].fps_num;
xe->x264_params.i_fps_den = xg->x264_param[ct].fps_den;
xe->x264_params.rc.i_rc_method = X264_RC_CRF;
xe->x264_params.rc.i_vbv_max_bitrate = xg->x264_param[ct].vbv_max_bitrate;
xe->x264_params.rc.i_vbv_buffer_size = xg->x264_param[ct].vbv_buffer_size;
x264_param_apply_profile(&(xe->x264_params),
xg->x264_param[ct].profile);
xe->x264_enc_han = x264_encoder_open(&(xe->x264_params));
LOG(LOG_LEVEL_INFO, "xrdp_encoder_x264_encode: "
"x264_encoder_open rv %p for width %d height %d",
xe->x264_enc_han, width, height);
if (xe->x264_enc_han == NULL)
{
return 1;
}
xe->yuvdata = g_new(char, width * height * 2);
if (xe->yuvdata == NULL)
{
x264_encoder_close(xe->x264_enc_han);
xe->x264_enc_han = NULL;
return 2;
}
flags |= 1;
}
xe->width = width;
xe->height = height;
}
if ((data != NULL) && (xe->x264_enc_han != NULL))
{
x264_width_height = xe->x264_params.i_width * xe->x264_params.i_height;
for (index = 0; index < num_crects; index++)
{
src8 = data;
dst8 = xe->yuvdata;
x = crects[index * 4 + 0];
y = crects[index * 4 + 1];
cx = crects[index * 4 + 2];
cy = crects[index * 4 + 3];
LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_x264_encode: x %d y %d "
"cx %d cy %d", x, y, cx, cy);
src8 += twidth * y + x;
dst8 += xe->x264_params.i_width * (y - top) + (x - left);
for (; cy > 0; cy -= 1)
{
g_memcpy(dst8, src8, cx);
src8 += twidth;
dst8 += xe->x264_params.i_width;
}
}
for (index = 0; index < num_crects; index++)
{
src8 = data;
src8 += twidth * theight;
dst8 = xe->yuvdata;
dst8 += x264_width_height;
x = crects[index * 4 + 0];
y = crects[index * 4 + 1];
cx = crects[index * 4 + 2];
cy = crects[index * 4 + 3];
src8 += twidth * (y / 2) + x;
dst8 += xe->x264_params.i_width * ((y - top) / 2) + (x - left);
for (; cy > 0; cy -= 2)
{
g_memcpy(dst8, src8, cx);
src8 += twidth;
dst8 += xe->x264_params.i_width;
}
}
g_memset(&pic_in, 0, sizeof(pic_in));
pic_in.img.i_csp = X264_CSP_NV12;
pic_in.img.i_plane = 2;
pic_in.img.plane[0] = (unsigned char *) (xe->yuvdata);
pic_in.img.plane[1] = (unsigned char *)
(xe->yuvdata + x264_width_height);
pic_in.img.i_stride[0] = xe->x264_params.i_width;
pic_in.img.i_stride[1] = xe->x264_params.i_width;
num_nals = 0;
frame_size = x264_encoder_encode(xe->x264_enc_han, &nals, &num_nals,
&pic_in, &pic_out);
LOG(LOG_LEVEL_TRACE, "i_type %d", pic_out.i_type);
if (frame_size < 1)
{
return 3;
}
if (*cdata_bytes < frame_size)
{
return 4;
}
g_memcpy(cdata, nals[0].p_payload, frame_size);
*cdata_bytes = frame_size;
}
if (flags_ptr != NULL)
{
*flags_ptr = flags;
}
return 0;
}

39
xrdp/xrdp_encoder_x264.h Normal file
View File

@ -0,0 +1,39 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2016-2024
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* libx264 Encoder
*/
#ifndef _XRDP_ENCODER_X264_H
#define _XRDP_ENCODER_X264_H
#include "arch.h"
void *
xrdp_encoder_x264_create(void);
int
xrdp_encoder_x264_delete(void *handle);
int
xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
int width, int height, int twidth, int theight,
int format, const char *data,
short *crects, int num_crects,
char *cdata, int *cdata_bytes, int connection_type,
int *flags_ptr);
#endif

View File

@ -86,7 +86,7 @@ rdp_layout_pt=0x00000816
; <rdp layout name> = <X11 keyboard layout value>
[default_layouts_map]
rdp_layout_us=us
rdp_layout_us_dvorak=dvorak
rdp_layout_us_dvorak=us(dvorak)
rdp_layout_us_dvp=us(dvp)
rdp_layout_dk=dk
rdp_layout_de=de
@ -125,7 +125,7 @@ layouts_map=default_layouts_map
[rdp_layouts_map_mac]
rdp_layout_us=us
rdp_layout_us_dvorak=dvorak
rdp_layout_us_dvorak=us(dvorak)
rdp_layout_us_dvp=us(dvp)
rdp_layout_dk=dk
rdp_layout_de=de

View File

@ -716,47 +716,45 @@ xrdp_listen_process_startup_params(struct xrdp_listen *self)
if (startup_params->tcp_send_buffer_bytes > 0)
{
bytes = startup_params->tcp_send_buffer_bytes;
LOG(LOG_LEVEL_INFO, "setting send buffer to %d bytes",
bytes);
if (g_sck_set_send_buffer_bytes(ltrans->sck, bytes) != 0)
{
LOG(LOG_LEVEL_WARNING, "error setting send buffer");
}
else if (g_sck_get_send_buffer_bytes(ltrans->sck, &bytes) != 0)
{
LOG(LOG_LEVEL_WARNING, "error getting send buffer");
}
else if (bytes != startup_params->tcp_send_buffer_bytes)
{
LOG(LOG_LEVEL_WARNING, "send buffer set to %d "
"bytes but %d bytes requested", bytes,
startup_params->tcp_send_buffer_bytes);
}
else
{
if (g_sck_get_send_buffer_bytes(ltrans->sck, &bytes) != 0)
{
LOG(LOG_LEVEL_WARNING, "error getting send "
"buffer");
}
else
{
LOG(LOG_LEVEL_INFO, "send buffer set to %d "
"bytes", bytes);
}
LOG(LOG_LEVEL_INFO, "send buffer set to %d bytes", bytes);
}
}
if (startup_params->tcp_recv_buffer_bytes > 0)
{
bytes = startup_params->tcp_recv_buffer_bytes;
LOG(LOG_LEVEL_INFO, "setting recv buffer to %d bytes",
bytes);
if (g_sck_set_recv_buffer_bytes(ltrans->sck, bytes) != 0)
{
LOG(LOG_LEVEL_WARNING, "error setting recv buffer");
}
else if (g_sck_get_recv_buffer_bytes(ltrans->sck, &bytes) != 0)
{
LOG(LOG_LEVEL_WARNING, "error getting recv buffer");
}
else if (bytes != startup_params->tcp_recv_buffer_bytes)
{
LOG(LOG_LEVEL_WARNING, "recv buffer set to %d "
"bytes but %d bytes requested", bytes,
startup_params->tcp_recv_buffer_bytes);
}
else
{
if (g_sck_get_recv_buffer_bytes(ltrans->sck, &bytes) != 0)
{
LOG(LOG_LEVEL_WARNING, "error getting recv "
"buffer");
}
else
{
LOG(LOG_LEVEL_INFO, "recv buffer set to %d "
"bytes", bytes);
}
LOG(LOG_LEVEL_INFO, "recv buffer set to %d bytes", bytes);
}
}
}

View File

@ -1458,8 +1458,6 @@ load_xrdp_config(struct xrdp_config *config, const char *xrdp_ini, int bpp)
LOG(LOG_LEVEL_DEBUG, "tcp_keepalive: %d", globals->tcp_keepalive);
LOG(LOG_LEVEL_DEBUG, "tcp_send_buffer_bytes: %d", globals->tcp_send_buffer_bytes);
LOG(LOG_LEVEL_DEBUG, "tcp_recv_buffer_bytes: %d", globals->tcp_recv_buffer_bytes);
LOG(LOG_LEVEL_DEBUG, "new_cursors: %d", globals->new_cursors);
LOG(LOG_LEVEL_DEBUG, "allow_multimon: %d", globals->allow_multimon);
LOG(LOG_LEVEL_DEBUG, "grey: %d", globals->grey);
LOG(LOG_LEVEL_DEBUG, "black: %d", globals->black);

View File

@ -396,7 +396,8 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self)
self->mod->server_draw_line = server_draw_line;
self->mod->server_add_char = server_add_char;
self->mod->server_draw_text = server_draw_text;
self->mod->server_reset = server_reset;
self->mod->client_monitor_resize = client_monitor_resize;
self->mod->server_monitor_resize_done = server_monitor_resize_done;
self->mod->server_get_channel_count = server_get_channel_count;
self->mod->server_query_channel = server_query_channel;
self->mod->server_get_channel_id = server_get_channel_id;
@ -1094,25 +1095,32 @@ cleanup:
/******************************************************************************/
static int
xrdp_mm_egfx_invalidate_all(struct xrdp_mm *self)
xrdp_mm_egfx_invalidate_wm_screen(struct xrdp_mm *self)
{
struct xrdp_rect xr_rect;
struct xrdp_bitmap *screen;
int error;
int error = 0;
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_all:");
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_wm_screen:");
screen = self->wm->screen;
xr_rect.left = 0;
xr_rect.top = 0;
xr_rect.right = screen->width;
xr_rect.bottom = screen->height;
if (self->wm->screen_dirty_region == NULL)
// Only invalidate the WM screen if the module is using the WM screen,
// or we haven't loaded the module yet.
//
// Otherwise we may send client updates which conflict with the
// updates sent directly from the module via the encoder.
if (self->mod_uses_wm_screen_for_gfx || self->mod_handle == 0)
{
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
struct xrdp_bitmap *screen = self->wm->screen;
struct xrdp_rect xr_rect;
xr_rect.left = 0;
xr_rect.top = 0;
xr_rect.right = screen->width;
xr_rect.bottom = screen->height;
if (self->wm->screen_dirty_region == NULL)
{
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
}
error = xrdp_region_add_rect(self->wm->screen_dirty_region, &xr_rect);
}
error = xrdp_region_add_rect(self->wm->screen_dirty_region, &xr_rect);
return error;
}
@ -1262,7 +1270,6 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
struct xrdp_mm *self;
struct xrdp_bitmap *screen;
int index;
int best_index;
int best_h264_index;
int best_pro_index;
int error;
@ -1270,6 +1277,10 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
int flags;
struct ver_flags_t *ver_flags;
#if !defined(XRDP_H264)
UNUSED_VAR(best_h264_index);
#endif
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise:");
self = (struct xrdp_mm *) user;
screen = self->wm->screen;
@ -1290,7 +1301,6 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
}
/* sort by version */
g_qsort(ver_flags, caps_count, sizeof(struct ver_flags_t), cmpverfunc);
best_index = -1;
best_h264_index = -1;
best_pro_index = -1;
for (index = 0; index < caps_count; index++)
@ -1337,19 +1347,34 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
break;
}
}
if (best_pro_index >= 0)
int best_index = -1;
struct xrdp_tconfig_gfx_codec_order *co = &self->wm->gfx_config->codec;
char cobuff[64];
LOG(LOG_LEVEL_INFO, "Codec search order is %s",
tconfig_codec_order_to_str(co, cobuff, sizeof(cobuff)));
for (index = 0 ; index < co->codec_count ; ++index)
{
best_index = best_pro_index;
self->egfx_flags = XRDP_EGFX_RFX_PRO;
}
/* prefer h264, todo use setting in xrdp.ini for this */
if (best_h264_index >= 0)
{
#if defined(XRDP_X264) || defined(XRDP_NVENC)
best_index = best_h264_index;
self->egfx_flags = XRDP_EGFX_H264;
#if defined(XRDP_H264)
if (co->codecs[index] == XTC_H264 && best_h264_index >= 0)
{
LOG(LOG_LEVEL_INFO, "Matched H264 mode");
best_index = best_h264_index;
self->egfx_flags = XRDP_EGFX_H264;
break;
}
#endif
if (co->codecs[index] == XTC_RFX && best_pro_index >= 0)
{
LOG(LOG_LEVEL_INFO, "Matched RFX mode");
best_index = best_pro_index;
self->egfx_flags = XRDP_EGFX_RFX_PRO;
break;
}
}
if (best_index >= 0)
{
LOG(LOG_LEVEL_INFO, " replying version 0x%8.8x flags 0x%8.8x",
@ -1362,14 +1387,14 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count,
error = xrdp_egfx_send_reset_graphics(self->egfx,
screen->width, screen->height,
self->wm->client_info->display_sizes.monitorCount,
self->wm->client_info->display_sizes.minfo_wm);
self->wm->client_info->display_sizes.minfo);
LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_reset_graphics "
"error %d monitorCount %d",
error, self->wm->client_info->display_sizes.monitorCount);
self->egfx_up = 1;
xrdp_mm_egfx_create_surfaces(self);
self->encoder = xrdp_encoder_create(self);
xrdp_mm_egfx_invalidate_all(self);
xrdp_mm_egfx_invalidate_wm_screen(self);
if (self->resize_data != NULL
&& self->resize_data->state == WMRZ_EGFX_INITALIZING)
@ -1635,6 +1660,7 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
struct xrdp_rdp *rdp;
struct xrdp_sec *sec;
struct xrdp_channel *chan;
int in_progress;
LOG_DEVEL(LOG_LEVEL_TRACE, "process_display_control_monitor_layout_data:");
@ -1697,6 +1723,7 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
if (error == 0 && module != 0)
{
xrdp_egfx_shutdown_close_connection(wm->mm->egfx);
mm->egfx_up = 0;
}
advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSING);
break;
@ -1725,13 +1752,15 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
{
xrdp_egfx_shutdown_delete(wm->mm->egfx);
mm->egfx = NULL;
mm->egfx_up = 0;
}
advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE);
break;
case WMRZ_SERVER_MONITOR_RESIZE:
error = module->mod_server_monitor_resize(
module, desc_width, desc_height);
module, desc_width, desc_height,
description->description.monitorCount,
description->description.minfo,
&in_progress);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
@ -1739,30 +1768,27 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
" mod_server_monitor_resize failed %d", error);
return advance_error(error, mm);
}
advance_resize_state_machine(
mm, WMRZ_SERVER_VERSION_MESSAGE_START);
break;
case WMRZ_SERVER_VERSION_MESSAGE_START:
error = module->mod_server_version_message(module);
if (error != 0)
else if (in_progress)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" mod_server_version_message failed %d", error);
return advance_error(error, mm);
// Call is proceeding asynchronously
advance_resize_state_machine(
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING);
}
else
{
// Call is done
advance_resize_state_machine(
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED);
}
advance_resize_state_machine(
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING);
break;
// Not processed here. Processed in server_reset
// Not processed here. Processed in client_monitor_resize
// case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING:
case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED:
advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESET);
break;
case WMRZ_XRDP_CORE_RESET:
// TODO: Unify this logic with server_reset
error = libxrdp_reset(
wm->session, desc_width, desc_height, wm->screen->bpp);
sync_dynamic_monitor_data(wm, &(description->description));
error = libxrdp_reset(wm->session);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
@ -1813,7 +1839,6 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
" xrdp_bitmap_resize failed %d", error);
return advance_error(error, mm);
}
sync_dynamic_monitor_data(wm, &(description->description));
advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZE);
break;
case WMRZ_EGFX_INITIALIZE:
@ -1845,20 +1870,13 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm)
// Ack all frames to speed up resize.
module->mod_frame_ack(module, 0, INT_MAX);
}
// Restart module output
// Restart module output after invalidating
// the screen. This causes an automatic redraw.
xrdp_bitmap_invalidate(wm->screen, 0);
rdp = (struct xrdp_rdp *) (wm->session->rdp);
xrdp_rdp_suppress_output(rdp,
0, XSO_REASON_DYNAMIC_RESIZE,
0, 0, desc_width, desc_height);
/* redraw */
error = xrdp_bitmap_invalidate(wm->screen, 0);
if (error != 0)
{
LOG_DEVEL(LOG_LEVEL_INFO,
"process_display_control_monitor_layout_data:"
" xrdp_bitmap_invalidate failed %d", error);
return advance_error(error, mm);
}
advance_resize_state_machine(mm, WMRZ_COMPLETE);
break;
default:
@ -2686,6 +2704,14 @@ xrdp_mm_process_login_response(struct xrdp_mm *self)
self->wm->pamerrortxt);
}
if (self->wm->client_info->require_credentials)
{
/* Credentials had to be specified, but were invalid */
g_set_wait_obj(self->wm->pro_layer->self_term_event);
LOG(LOG_LEVEL_ERROR, "require_credentials is set, "
"but the user could not be logged in");
}
if (server_closed)
{
if (login_result == E_SCP_LOGIN_NOT_AUTHENTICATED)
@ -3476,7 +3502,7 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
y = enc_done->y;
cx = enc_done->cx;
cy = enc_done->cy;
if (!enc_done->continuation)
if (client_ack && !enc_done->continuation)
{
libxrdp_fastpath_send_frame_marker(self->wm->session, 0,
enc_done->frame_id);
@ -3488,7 +3514,7 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
x, y, x + cx, y + cy,
32, self->encoder->codec_id,
cx, cy);
if (enc_done->last)
if (client_ack && enc_done->last)
{
libxrdp_fastpath_send_frame_marker(self->wm->session, 1,
enc_done->frame_id);
@ -3534,6 +3560,39 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self)
return 0;
}
/*****************************************************************************/
void
xrdp_mm_efgx_add_dirty_region_to_planar_list(struct xrdp_mm *self,
struct xrdp_region *dirty_region)
{
int jndex = 0;
struct xrdp_rect rect;
int error = xrdp_region_get_rect(dirty_region, jndex, &rect);
if (error == 0)
{
if (self->wm->screen_dirty_region == NULL)
{
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
}
do
{
xrdp_region_add_rect(self->wm->screen_dirty_region, &rect);
jndex++;
error = xrdp_region_get_rect(dirty_region, jndex, &rect);
}
while (error == 0);
if (self->mod_handle != 0)
{
// Module has been writing to WM screen using GFX
self->mod_uses_wm_screen_for_gfx = 1;
}
}
}
/*****************************************************************************/
static int
xrdp_mm_draw_dirty(struct xrdp_mm *self)
@ -4116,11 +4175,13 @@ server_egfx_cmd(struct xrdp_mod *mod,
mm = wm->mm;
if (mm->encoder == NULL)
{
// This can happen when we are in the resize state machine, if
// there are messages queued up by the X server
if (data != NULL)
{
g_munmap(data, data_bytes);
}
return 1;
return 0;
}
enc = g_new0(struct xrdp_enc_data, 1);
if (enc == NULL)
@ -4432,17 +4493,70 @@ server_draw_text(struct xrdp_mod *mod, int font,
x, y, data, data_len);
}
/*****************************************************************************/
int
client_monitor_resize(struct xrdp_mod *mod, int width, int height,
int num_monitors, const struct monitor_info *monitors)
{
int error = 0;
struct xrdp_wm *wm;
struct display_size_description *display_size_data;
LOG_DEVEL(LOG_LEVEL_TRACE, "client_monitor_resize:");
wm = (struct xrdp_wm *)(mod->wm);
if (wm == 0 || wm->mm == 0 || wm->client_info == 0)
{
return 1;
}
if (wm->client_info->client_resize_mode == CRMODE_NONE)
{
LOG(LOG_LEVEL_WARNING, "Server is not allowed to resize this client");
return 1;
}
if (wm->client_info->client_resize_mode == CRMODE_SINGLE_SCREEN &&
num_monitors > 1)
{
LOG(LOG_LEVEL_WARNING,
"Server cannot resize this client with multiple monitors");
return 1;
}
display_size_data = g_new0(struct display_size_description, 1);
if (display_size_data == NULL)
{
LOG(LOG_LEVEL_ERROR, "client_monitor_resize: Out of memory");
return 1;
}
error = libxrdp_init_display_size_description(num_monitors,
monitors,
display_size_data);
if (error)
{
LOG(LOG_LEVEL_ERROR, "client_monitor_resize:"
" libxrdp_init_display_size_description"
" failed with error %d.", error);
free(display_size_data);
return error;
}
list_add_item(wm->mm->resize_queue, (tintptr)display_size_data);
g_set_wait_obj(wm->mm->resize_ready);
return 0;
}
/*****************************************************************************/
/* Note : if this is called on a multimon setup, the client is resized
* to a single monitor */
int
server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
server_monitor_resize_done(struct xrdp_mod *mod)
{
struct xrdp_wm *wm;
struct xrdp_mm *mm;
LOG(LOG_LEVEL_TRACE, "server_reset:");
LOG(LOG_LEVEL_TRACE, "server_monitor_resize_done:");
wm = (struct xrdp_wm *)(mod->wm);
if (wm == 0)
@ -4450,78 +4564,25 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp)
return 1;
}
mm = wm->mm;
if (mm == 0)
{
return 1;
}
if (wm->client_info == 0)
{
return 1;
}
/* older client can't resize */
if (wm->client_info->build <= 419)
if (mm->resize_data != NULL
&& mm->resize_data->state
== WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING)
{
return 0;
LOG(LOG_LEVEL_INFO,
"server_monitor_resize_done: Advancing server monitor resized.");
advance_resize_state_machine(
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED);
}
// bpp of zero is impossible.
// This is a signal from xup that
// It is finished resizing.
if (bpp == 0)
{
if (mm == 0)
{
return 1;
}
if (!xrdp_wm_can_resize(wm))
{
return 1;
}
if (mm->resize_data == NULL)
{
mm->mod->mod_server_monitor_full_invalidate(mm->mod, width, height);
return 0;
}
if (mm->resize_data != NULL
&& mm->resize_data->state
== WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING)
{
LOG(LOG_LEVEL_INFO,
"server_reset: Advancing server monitor resized.");
advance_resize_state_machine(
mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED);
}
else if (mm->resize_data != NULL
&& mm->resize_data->description.session_height == 0
&& mm->resize_data->description.session_width == 0)
{
mm->mod->mod_server_monitor_full_invalidate(mm->mod, width, height);
}
return 0;
}
/* if same (and only one monitor on client) don't need to do anything */
if (wm->client_info->display_sizes.session_width == (uint32_t)width &&
wm->client_info->display_sizes.session_height == (uint32_t)height &&
wm->client_info->bpp == bpp &&
(wm->client_info->display_sizes.monitorCount == 0 ||
wm->client_info->multimon == 0))
{
return 0;
}
/* reset lib, client_info gets updated in libxrdp_reset */
if (libxrdp_reset(wm->session, width, height, bpp) != 0)
{
return 1;
}
/* reset cache */
xrdp_cache_reset(wm->cache, wm->client_info);
/* resize the main window */
xrdp_bitmap_resize(wm->screen, wm->client_info->display_sizes.session_width,
wm->client_info->display_sizes.session_height);
/* load some stuff */
xrdp_wm_load_static_colors_plus(wm, 0);
xrdp_wm_load_static_pointers(wm);
return 0;
}

View File

@ -95,18 +95,8 @@ xrdp_painter_send_dirty(struct xrdp_painter *self)
if (self->session->client_info->gfx)
{
if (self->wm->screen_dirty_region == NULL)
{
self->wm->screen_dirty_region = xrdp_region_create(self->wm);
}
jndex = 0;
error = xrdp_region_get_rect(self->dirty_region, jndex, &rect);
while (error == 0)
{
xrdp_region_add_rect(self->wm->screen_dirty_region, &rect);
jndex++;
error = xrdp_region_get_rect(self->dirty_region, jndex, &rect);
}
xrdp_mm_efgx_add_dirty_region_to_planar_list(self->wm->mm,
self->dirty_region);
}
else
{

424
xrdp/xrdp_tconfig.c Normal file
View File

@ -0,0 +1,424 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Koichiro Iwao
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @file xrdp_tconfig.c
* @brief TOML config loader
* @author Koichiro Iwao
*
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "arch.h"
#include "os_calls.h"
#include "parse.h"
#include "toml.h"
#include "ms-rdpbcgr.h"
#include "xrdp_tconfig.h"
#include "string_calls.h"
#define TCLOG(log_level, args...) LOG(log_level, "TConfig: " args)
#define X264_DEFAULT_PRESET "ultrafast"
#define X264_DEFAULT_TUNE "zerolatency"
#define X264_DEFAULT_PROFILE "main"
#define X264_DEFAULT_FPS_NUM 24
#define X264_DEFAULT_FPS_DEN 1
const char *
tconfig_codec_order_to_str(
const struct xrdp_tconfig_gfx_codec_order *codec_order,
char *buff,
unsigned int bufflen)
{
if (bufflen < (8 * codec_order->codec_count))
{
snprintf(buff, bufflen, "???");
}
else
{
unsigned int p = 0;
int i;
for (i = 0 ; i < codec_order->codec_count; ++i)
{
if (p > 0)
{
buff[p++] = ',';
}
switch (codec_order->codecs[i])
{
case XTC_H264:
buff[p++] = 'H';
buff[p++] = '2';
buff[p++] = '6';
buff[p++] = '4';
break;
case XTC_RFX:
buff[p++] = 'R';
buff[p++] = 'F';
buff[p++] = 'X';
break;
default:
buff[p++] = '?';
buff[p++] = '?';
buff[p++] = '?';
}
}
buff[p++] = '\0';
}
return buff;
}
static int
tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type,
struct xrdp_tconfig_gfx_x264_param *param)
{
TCLOG(LOG_LEVEL_TRACE, "[x264]");
if (connection_type > NUM_CONNECTION_TYPES)
{
TCLOG(LOG_LEVEL_ERROR, "[x264] Invalid connection type is given");
return 1;
}
toml_table_t *x264 = toml_table_in(tfile, "x264");
if (!x264)
{
TCLOG(LOG_LEVEL_WARNING, "[x264] x264 params are not defined");
return 1;
}
toml_table_t *x264_ct =
toml_table_in(x264, rdpbcgr_connection_type_names[connection_type]);
toml_datum_t datum;
if (!x264_ct)
{
TCLOG(LOG_LEVEL_WARNING, "x264 params for connection type [%s] is not defined",
rdpbcgr_connection_type_names[connection_type]);
return 1;
}
/* preset */
datum = toml_string_in(x264_ct, "preset");
if (datum.ok)
{
g_strncpy(param[connection_type].preset,
datum.u.s,
sizeof(param[connection_type].preset) - 1);
free(datum.u.s);
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"[x264.%s] preset is not set, adopting the default value \""
X264_DEFAULT_PRESET "\"",
rdpbcgr_connection_type_names[connection_type]);
g_strncpy(param[connection_type].preset,
X264_DEFAULT_PRESET,
sizeof(param[connection_type].preset) - 1);
}
/* tune */
datum = toml_string_in(x264_ct, "tune");
if (datum.ok)
{
g_strncpy(param[connection_type].tune,
datum.u.s,
sizeof(param[connection_type].tune) - 1);
free(datum.u.s);
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"[x264.%s] tune is not set, adopting the default value \""
X264_DEFAULT_TUNE"\"",
rdpbcgr_connection_type_names[connection_type]);
g_strncpy(param[connection_type].tune,
X264_DEFAULT_TUNE,
sizeof(param[connection_type].tune) - 1);
}
/* profile */
datum = toml_string_in(x264_ct, "profile");
if (datum.ok)
{
g_strncpy(param[connection_type].profile,
datum.u.s,
sizeof(param[connection_type].profile) - 1);
free(datum.u.s);
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"[x264.%s] profile is not set, adopting the default value \""
X264_DEFAULT_PROFILE"\"",
rdpbcgr_connection_type_names[connection_type]);
g_strncpy(param[connection_type].profile,
X264_DEFAULT_PROFILE,
sizeof(param[connection_type].profile) - 1);
}
/* vbv_max_bitrate */
datum = toml_int_in(x264_ct, "vbv_max_bitrate");
if (datum.ok)
{
param[connection_type].vbv_max_bitrate = datum.u.i;
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"[x264.%s] vbv_max_bitrate is not set, adopting the default value [0]",
rdpbcgr_connection_type_names[connection_type]);
param[connection_type].vbv_max_bitrate = 0;
}
/* vbv_buffer_size */
datum = toml_int_in(x264_ct, "vbv_buffer_size");
if (datum.ok)
{
param[connection_type].vbv_buffer_size = datum.u.i;
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"[x264.%s] vbv_buffer_size is not set, adopting the default value [0]",
rdpbcgr_connection_type_names[connection_type]);
param[connection_type].vbv_buffer_size = 0;
}
/* fps_num */
datum = toml_int_in(x264_ct, "fps_num");
if (datum.ok)
{
param[connection_type].fps_num = datum.u.i;
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"[x264.%s] fps_num is not set, adopting the default value [%d]",
rdpbcgr_connection_type_names[connection_type],
X264_DEFAULT_FPS_NUM);
param[connection_type].fps_num = X264_DEFAULT_FPS_NUM;
}
/* fps_den */
datum = toml_int_in(x264_ct, "fps_den");
if (datum.ok)
{
param[connection_type].fps_den = datum.u.i;
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"[x264.%s] fps_den is not set, adopting the default value [%d]",
rdpbcgr_connection_type_names[connection_type],
X264_DEFAULT_FPS_DEN);
param[connection_type].fps_den = X264_DEFAULT_FPS_DEN;
}
return 0;
}
static int tconfig_load_gfx_order(toml_table_t *tfile, struct xrdp_tconfig_gfx *config)
{
char buff[64];
/*
* This config loader is not responsible to check if xrdp is built with
* H264/RFX support. Just loads configurations as-is.
*/
TCLOG(LOG_LEVEL_TRACE, "[codec]");
int h264_found = 0;
int rfx_found = 0;
config->codec.codec_count = 0;
toml_table_t *codec;
toml_array_t *order;
if ((codec = toml_table_in(tfile, "codec")) != NULL &&
(order = toml_array_in(codec, "order")) != NULL)
{
for (int i = 0; ; i++)
{
toml_datum_t datum = toml_string_at(order, i);
if (datum.ok)
{
if (h264_found == 0 &&
(g_strcasecmp(datum.u.s, "h264") == 0 ||
g_strcasecmp(datum.u.s, "h.264") == 0))
{
h264_found = 1;
config->codec.codecs[config->codec.codec_count] = XTC_H264;
++config->codec.codec_count;
}
if (rfx_found == 0 &&
g_strcasecmp(datum.u.s, "rfx") == 0)
{
rfx_found = 1;
config->codec.codecs[config->codec.codec_count] = XTC_RFX;
++config->codec.codec_count;
}
free(datum.u.s);
}
else
{
break;
}
}
}
if (h264_found == 0 && rfx_found == 0)
{
/* prefer H264 if no priority found */
config->codec.codecs[0] = XTC_H264;
config->codec.codecs[1] = XTC_RFX;
config->codec.codec_count = 2;
TCLOG(LOG_LEVEL_WARNING, "[codec] could not get GFX codec order, "
"using default order %s",
tconfig_codec_order_to_str(&config->codec, buff, sizeof(buff)));
return 1;
}
TCLOG(LOG_LEVEL_DEBUG, "[codec] %s",
tconfig_codec_order_to_str(&config->codec, buff, sizeof(buff)));
return 0;
}
/**
* Determines whether a codec is enabled
* @param co Ordered codec list
* @param code Code of codec to look for
* @return boolean
*/
static int
codec_enabled(const struct xrdp_tconfig_gfx_codec_order *co,
enum xrdp_tconfig_codecs code)
{
for (unsigned short i = 0; i < co->codec_count; ++i)
{
if (co->codecs[i] == code)
{
return 1;
}
}
return 0;
}
/**
* Disables a Codec by removing it from the codec list
* @param co Ordered codec list
* @param code Code of codec to remove from list
*
* The order of the passed-in codec list is preserved.
*/
static void
disable_codec(struct xrdp_tconfig_gfx_codec_order *co,
enum xrdp_tconfig_codecs code)
{
unsigned short j = 0;
for (unsigned short i = 0; i < co->codec_count; ++i)
{
if (co->codecs[i] != code)
{
co->codecs[j++] = co->codecs[i];
}
}
co->codec_count = j;
}
int
tconfig_load_gfx(const char *filename, struct xrdp_tconfig_gfx *config)
{
FILE *fp;
char errbuf[200];
toml_table_t *tfile;
int rv = 0;
/* Default to just RFX support. in case we can't load anything */
config->codec.codec_count = 1;
config->codec.codecs[0] = XTC_RFX;
memset(config->x264_param, 0, sizeof(config->x264_param));
if ((fp = fopen(filename, "r")) == NULL)
{
TCLOG(LOG_LEVEL_ERROR, "Error loading GFX config file %s (%s)",
filename, g_get_strerror());
return 1;
}
if ((tfile = toml_parse_file(fp, errbuf, sizeof(errbuf))) == NULL)
{
TCLOG(LOG_LEVEL_ERROR, "Error in GFX config file %s - %s", filename, errbuf);
fclose(fp);
return 1;
}
TCLOG(LOG_LEVEL_INFO, "Loading GFX config file %s", filename);
fclose(fp);
/* Load GFX codec order */
tconfig_load_gfx_order(tfile, config);
/* H.264 configuration */
if (codec_enabled(&config->codec, XTC_H264))
{
/* First of all, read the default params */
if (tconfig_load_gfx_x264_ct(tfile, 0, config->x264_param) != 0)
{
/* We can't read the H.264 defaults. Disable H.264 */
LOG(LOG_LEVEL_WARNING, "H.264 support will be disabled");
disable_codec(&config->codec, XTC_H264);
rv = 1;
}
else
{
/* Copy default params to other connection types, and
* then override them */
for (int ct = CONNECTION_TYPE_MODEM; ct < NUM_CONNECTION_TYPES;
ct++)
{
config->x264_param[ct] = config->x264_param[0];
tconfig_load_gfx_x264_ct(tfile, ct, config->x264_param);
}
}
}
toml_free(tfile);
return rv;
}

104
xrdp/xrdp_tconfig.h Normal file
View File

@ -0,0 +1,104 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Koichiro Iwao
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* @file xrdp_tconfig.c
* @brief TOML config loader and structures
* @author Koichiro Iwao
*
*/
#ifndef _XRDP_TCONFIG_H_
#define _XRDP_TCONFIG_H_
/* The number of connection types in MS-RDPBCGR 2.2.1.3.2 */
#define NUM_CONNECTION_TYPES 7
#define GFX_CONF XRDP_CFG_PATH "/gfx.toml"
/* nc stands for new config */
struct xrdp_tconfig_gfx_x264_param
{
char preset[16];
char tune[16];
char profile[16];
int vbv_max_bitrate;
int vbv_buffer_size;
int fps_num;
int fps_den;
};
enum xrdp_tconfig_codecs
{
XTC_H264,
XTC_RFX
};
struct xrdp_tconfig_gfx_codec_order
{
enum xrdp_tconfig_codecs codecs[2];
unsigned short codec_count;
};
struct xrdp_tconfig_gfx
{
struct xrdp_tconfig_gfx_codec_order codec;
/* store x264 parameters for each connection type */
struct xrdp_tconfig_gfx_x264_param x264_param[NUM_CONNECTION_TYPES];
};
static const char *const rdpbcgr_connection_type_names[] =
{
"default", /* for xrdp internal use */
"modem",
"broadband_low",
"satellite",
"broadband_high",
"wan",
"lan",
"autodetect",
0
};
/**
* Provide a string representation of a codec order
*
* @param codec_order Codec order struct
* @param buff Buffer for result
* @param bufflen Length of above
* @return Convenience copy of buff
*/
const char *
tconfig_codec_order_to_str(
const struct xrdp_tconfig_gfx_codec_order *codec_order,
char *buff,
unsigned int bufflen);
/**
* Loads the GFX config from the specified file
*
* @param filename Name of file to load
* @param config Struct to receive result
* @return 0 for success
*
* In the event of failure, an error is logged. A minimal
* useable configuration is always returned
*/
int
tconfig_load_gfx(const char *filename, struct xrdp_tconfig_gfx *config);
#endif

View File

@ -29,6 +29,7 @@
#include "fifo.h"
#include "guid.h"
#include "xrdp_client_info.h"
#include "xrdp_tconfig.h"
#define MAX_NR_CHANNELS 16
#define MAX_CHANNEL_NAME 16
@ -64,7 +65,10 @@ struct xrdp_mod
int (*mod_suppress_output)(struct xrdp_mod *v, int suppress,
int left, int top, int right, int bottom);
int (*mod_server_monitor_resize)(struct xrdp_mod *v,
int width, int height);
int width, int height,
int num_monitors,
const struct monitor_info *monitors,
int *in_progress);
int (*mod_server_monitor_full_invalidate)(struct xrdp_mod *v,
int width, int height);
int (*mod_server_version_message)(struct xrdp_mod *v);
@ -106,7 +110,10 @@ struct xrdp_mod
int box_left, int box_top,
int box_right, int box_bottom,
int x, int y, char *data, int data_len);
int (*server_reset)(struct xrdp_mod *v, int width, int height, int bpp);
int (*client_monitor_resize)(struct xrdp_mod *v, int width, int height,
int num_monitors,
const struct monitor_info *monitors);
int (*server_monitor_resize_done)(struct xrdp_mod *v);
int (*server_get_channel_count)(struct xrdp_mod *v);
int (*server_query_channel)(struct xrdp_mod *v, int index,
char *channel_name,
@ -185,7 +192,7 @@ struct xrdp_mod
int (*server_egfx_cmd)(struct xrdp_mod *v,
char *cmd, int cmd_bytes,
char *data, int data_bytes);
tintptr server_dumby[100 - 49]; /* align, 100 minus the number of server
tintptr server_dumby[100 - 50]; /* align, 100 minus the number of server
functions above */
/* common */
tintptr handle; /* pointer to self as int */
@ -347,7 +354,6 @@ enum display_resize_state
WMRZ_EGFX_CONN_CLOSED,
WRMZ_EGFX_DELETE,
WMRZ_SERVER_MONITOR_RESIZE,
WMRZ_SERVER_VERSION_MESSAGE_START,
WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING,
WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED,
WMRZ_XRDP_CORE_RESET,
@ -370,8 +376,6 @@ enum display_resize_state
(status) == WMRZ_EGFX_CONN_CLOSED ? "WMRZ_EGFX_CONN_CLOSED" : \
(status) == WRMZ_EGFX_DELETE ? "WMRZ_EGFX_DELETE" : \
(status) == WMRZ_SERVER_MONITOR_RESIZE ? "WMRZ_SERVER_MONITOR_RESIZE" : \
(status) == WMRZ_SERVER_VERSION_MESSAGE_START ? \
"WMRZ_SERVER_VERSION_MESSAGE_START" : \
(status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING ? \
"WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING" : \
(status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED ? \
@ -436,6 +440,7 @@ struct xrdp_mm
int egfx_up;
enum xrdp_egfx_flags egfx_flags;
int gfx_delay_autologin;
int mod_uses_wm_screen_for_gfx;
/* Resize on-the-fly control */
struct display_control_monitor_layout_data *resize_data;
struct list *resize_queue;
@ -562,6 +567,8 @@ struct xrdp_wm
/* configuration derived from xrdp.ini */
struct xrdp_config *xrdp_config;
/* configuration derived from gfx.toml */
struct xrdp_tconfig_gfx *gfx_config;
struct xrdp_region *screen_dirty_region;
int last_screen_draw_time;

View File

@ -29,6 +29,54 @@
#include "log.h"
#include "string_calls.h"
/*****************************************************************************/
static void
xrdp_wm_load_channel_config(struct xrdp_wm *self)
{
struct list *names = list_create();
names->auto_free = 1;
struct list *values = list_create();
values->auto_free = 1;
if (file_by_name_read_section(self->session->xrdp_ini,
"Channels", names, values) == 0)
{
int chan_id;
int chan_count = libxrdp_get_channel_count(self->session);
const char *disabled_str = NULL;
for (chan_id = 0 ; chan_id < chan_count ; ++chan_id)
{
char chan_name[16];
if (libxrdp_query_channel(self->session, chan_id, chan_name,
NULL) == 0)
{
int disabled = 1; /* Channels disabled if not found */
int index;
for (index = 0; index < names->count; index++)
{
const char *q = (const char *)list_get_item(names, index);
const char *r = (const char *)list_get_item(values, index);
if (g_strcasecmp(q, chan_name) == 0)
{
disabled = !g_text2bool(r);
break;
}
}
disabled_str = (disabled) ? "disabled" : "enabled";
LOG(LOG_LEVEL_DEBUG, "xrdp_wm_load_channel_config: "
"channel %s channel id %d is %s",
chan_name, chan_id, disabled_str);
libxrdp_disable_channel(self->session, chan_id, disabled);
}
}
}
list_delete(names);
list_delete(values);
}
/*****************************************************************************/
struct xrdp_wm *
xrdp_wm_create(struct xrdp_process *owner,
@ -66,8 +114,26 @@ xrdp_wm_create(struct xrdp_process *owner,
self->target_surface = self->screen;
self->current_surface_index = 0xffff; /* screen */
/* to store configuration from xrdp.ini */
/* to store configuration from xrdp.ini, gfx.toml */
self->xrdp_config = g_new0(struct xrdp_config, 1);
self->gfx_config = g_new0(struct xrdp_tconfig_gfx, 1);
/* Load the channel config so libxrdp can check whether
drdynvc is enabled or not */
xrdp_wm_load_channel_config(self);
// Start drdynvc if available.
if (libxrdp_drdynvc_start(self->session) == 0)
{
// drdynvc is started. callback() will
// be notified when capabilities are received.
}
else if (self->client_info->gfx)
{
LOG(LOG_LEVEL_WARNING, "Disabling GFX as '"
DRDYNVC_SVC_CHANNEL_NAME "' isn't available");
self->client_info->gfx = 0;
}
return self;
}
@ -97,6 +163,11 @@ xrdp_wm_delete(struct xrdp_wm *self)
g_free(self->xrdp_config);
}
if (self->gfx_config)
{
g_free(self->gfx_config);
}
/* free self */
g_free(self);
}
@ -564,9 +635,7 @@ xrdp_wm_init(struct xrdp_wm *self)
{
int fd;
int index;
struct list *names;
struct list *values;
char *q;
const char *q;
const char *r;
char param[256];
char default_section_name[256];
@ -579,6 +648,8 @@ xrdp_wm_init(struct xrdp_wm *self)
load_xrdp_config(self->xrdp_config, self->session->xrdp_ini,
self->screen->bpp);
tconfig_load_gfx(XRDP_CFG_PATH "/gfx.toml", self->gfx_config);
/* Remove a font loaded on the previous config */
xrdp_font_delete(self->default_font);
self->painter->font = NULL; /* May be set to the default_font */
@ -590,48 +661,6 @@ xrdp_wm_init(struct xrdp_wm *self)
/* Scale the login screen values */
xrdp_login_wnd_scale_config_values(self);
/* global channels allow */
names = list_create();
names->auto_free = 1;
values = list_create();
values->auto_free = 1;
if (file_by_name_read_section(self->session->xrdp_ini,
"Channels", names, values) == 0)
{
int chan_id;
int chan_count = libxrdp_get_channel_count(self->session);
const char *disabled_str = NULL;
for (chan_id = 0 ; chan_id < chan_count ; ++chan_id)
{
char chan_name[16];
if (libxrdp_query_channel(self->session, chan_id, chan_name,
NULL) == 0)
{
int disabled = 1; /* Channels disabled if not found */
for (index = 0; index < names->count; index++)
{
q = (char *) list_get_item(names, index);
if (g_strcasecmp(q, chan_name) == 0)
{
r = (const char *) list_get_item(values, index);
disabled = !g_text2bool(r);
break;
}
}
disabled_str = (disabled) ? "disabled" : "enabled";
LOG(LOG_LEVEL_DEBUG, "xrdp_wm_init: "
"channel %s channel id %d is %s",
chan_name, chan_id, disabled_str);
libxrdp_disable_channel(self->session, chan_id, disabled);
}
}
}
list_delete(names);
list_delete(values);
xrdp_wm_load_static_colors_plus(self, autorun_name);
xrdp_wm_load_static_pointers(self);
self->screen->bg_color = self->xrdp_config->cfg_globals.ls_top_window_bg_color;
@ -645,9 +674,9 @@ xrdp_wm_init(struct xrdp_wm *self)
fd = g_file_open_ro(self->session->xrdp_ini);
if (fd != -1)
{
names = list_create();
struct list *names = list_create();
names->auto_free = 1;
values = list_create();
struct list *values = list_create();
values->auto_free = 1;
/* pick up the first section name except for 'globals', 'Logging', 'channels'
@ -656,7 +685,7 @@ xrdp_wm_init(struct xrdp_wm *self)
default_section_name[0] = '\0';
for (index = 0; index < names->count; index++)
{
q = (char *)list_get_item(names, index);
q = (const char *)list_get_item(names, index);
if ((g_strncasecmp("globals", q, 8) != 0) &&
(g_strncasecmp("Logging", q, 8) != 0) &&
(g_strncasecmp("LoggingPerLogger", q, 17) != 0) &&
@ -714,8 +743,8 @@ xrdp_wm_init(struct xrdp_wm *self)
{
for (index = 0; index < names->count; index++)
{
q = (char *)list_get_item(names, index);
r = (char *)list_get_item(values, index);
q = (const char *)list_get_item(names, index);
r = (const char *)list_get_item(values, index);
if (g_strncasecmp("password", q, 255) == 0)
{

View File

@ -28,8 +28,10 @@
#include "string_calls.h"
static int
send_server_monitor_resize(
struct mod *mod, struct stream *s, int width, int height, int bpp);
send_server_monitor_update(struct mod *v, struct stream *s,
int width, int height,
int num_monitors,
const struct monitor_info *monitors);
static int
send_server_monitor_full_invalidate(
@ -224,13 +226,6 @@ lib_mod_connect(struct mod *mod)
error = send_server_version_message(mod, s);
}
if (error == 0)
{
/* send screen size message */
error = send_server_monitor_resize(
mod, s, mod->width, mod->height, mod->bpp);
}
if (error == 0)
{
error = send_server_monitor_full_invalidate(
@ -1466,33 +1461,30 @@ send_server_version_message(struct mod *mod, struct stream *s)
/******************************************************************************/
/* return error */
static int
send_server_monitor_resize(
struct mod *mod, struct stream *s, int width, int height, int bpp)
send_server_monitor_update(struct mod *mod, struct stream *s,
int width, int height,
int num_monitors,
const struct monitor_info *monitors)
{
/* send screen size message */
/* send monitor update message */
init_stream(s, 8192);
s_push_layer(s, iso_hdr, 4);
out_uint16_le(s, 103);
out_uint32_le(s, 300);
out_uint32_le(s, 302);
out_uint32_le(s, width);
out_uint32_le(s, height);
/*
TODO: The bpp here is only necessary for initial creation. We should
modify XUP to require this only on server initialization, but not on
resize. Microsoft's RDP protocol does not support changing
the bpp on resize.
*/
out_uint32_le(s, bpp);
out_uint32_le(s, num_monitors);
out_uint32_le(s, 0);
out_uint8a(s, monitors, sizeof(monitors[0]) * num_monitors);
s_mark_end(s);
int len = (int)(s->end - s->data);
s_pop_layer(s, iso_hdr);
out_uint32_le(s, len);
int rv = lib_send_copy(mod, s);
LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_resize:"
" sent resize message with following properties to"
" xorgxrdp backend width=%d, height=%d, bpp=%d, return value=%d",
width, height, bpp, rv);
LOG_DEVEL(LOG_LEVEL_DEBUG, "send_server_monitor_update:"
" sent monitor updsate message with following properties to"
" xorgxrdp backend width=%d, height=%d, num=%d, return value=%d",
width, height, num_monitors, rv);
return rv;
}
@ -1542,12 +1534,16 @@ lib_send_server_version_message(struct mod *mod)
/******************************************************************************/
/* return error */
static int
lib_send_server_monitor_resize(struct mod *mod, int width, int height)
lib_send_server_monitor_resize(struct mod *mod, int width, int height,
int num_monitors,
const struct monitor_info *monitors,
int *in_progress)
{
/* send screen size message */
struct stream *s;
make_stream(s);
int rv = send_server_monitor_resize(mod, s, width, height, mod->bpp);
int rv = send_server_monitor_update(mod, s, width, height,
num_monitors, monitors);
*in_progress = (rv == 0);
free_stream(s);
return rv;
}
@ -1802,7 +1798,7 @@ lib_mod_process_message(struct mod *mod, struct stream *s)
LOG(LOG_LEVEL_INFO, "Received memory_allocation_complete"
" command. width: %d, height: %d",
width, height);
rv = mod->server_reset(mod, width, height, 0);
rv = mod->server_monitor_resize_done(mod);
break;
}
s->p = phold + len;
@ -1897,6 +1893,10 @@ lib_mod_check_wait_objs(struct mod *mod)
if (mod->trans != 0)
{
rv = trans_check_wait_objs(mod->trans);
if (rv != 0)
{
LOG(LOG_LEVEL_ERROR, "Xorg server closed connection");
}
}
}

View File

@ -55,7 +55,10 @@ struct mod
int (*mod_suppress_output)(struct mod *v, int suppress,
int left, int top, int right, int bottom);
int (*mod_server_monitor_resize)(struct mod *v,
int width, int height);
int width, int height,
int num_monitors,
const struct monitor_info *monitors,
int *in_progress);
int (*mod_server_monitor_full_invalidate)(struct mod *v,
int width, int height);
int (*mod_server_version_message)(struct mod *v);
@ -94,7 +97,10 @@ struct mod
int box_left, int box_top,
int box_right, int box_bottom,
int x, int y, char *data, int data_len);
int (*server_reset)(struct mod *v, int width, int height, int bpp);
int (*client_monitor_resize)(struct mod *v, int width, int height,
int num_monitors,
const struct monitor_info *monitors);
int (*server_monitor_resize_done)(struct mod *v);
int (*server_get_channel_count)(struct mod *v);
int (*server_query_channel)(struct mod *v, int index,
char *channel_name,
@ -170,7 +176,7 @@ struct mod
int (*server_egfx_cmd)(struct mod *v,
char *cmd, int cmd_bytes,
char *data, int data_bytes);
tintptr server_dumby[100 - 49]; /* align, 100 minus the number of server
tintptr server_dumby[100 - 50]; /* align, 100 minus the number of server
functions above */
/* common */
tintptr handle; /* pointer to self as long */