Compare commits

...

1073 Commits

Author SHA1 Message Date
Virtually Nick
47b9360d46
GUACAMOLE-1714: Merge update guacenc for const parameters/values introduced in FFmpeg 5.0. 2023-02-02 20:36:32 -05:00
Mike Jumper
98c2a6adcb
GUACAMOLE-377: Merge correction ensuring users receive a proper frame boundary when joining. 2023-01-24 14:25:09 -08:00
Alex Leitner
3b0a9bac75 GUACAMOLE-377: Send a sync instruction to users when synchronizing surfaces. 2023-01-23 20:55:01 +00:00
Mike Jumper
f6893ed319 Merge 1.5.0 changes back to master. 2023-01-10 21:54:05 -08:00
James Muehlner
a5214c971a
GUACAMOLE-1604: Merge version number bumps for 1.5.0. 2023-01-10 17:16:43 -08:00
Mike Jumper
ccfcef8c0f GUACAMOLE-1604: Add explicit libtool version info for libguac-terminal. 2023-01-10 17:08:15 -08:00
Mike Jumper
1a7a57ed19 GUACAMOLE-1604: Update libtool version info for libguac (interfaces added and changed).
The only changed interface here is the guac_user_info struct, which now
has a "name" member.
2023-01-10 17:07:16 -08:00
Mike Jumper
eac064bde9 GUACAMOLE-1604: Bump version number to 1.5.0. 2023-01-10 17:02:06 -08:00
Virtually Nick
4afc1d85ce Merge 1.5.0 changes back to master. 2023-01-04 15:53:11 -05:00
Virtually Nick
818b5f79df
GUACAMOLE-1538: Merge add missing documentation for libguac-terminal. 2023-01-04 15:51:05 -05:00
Mike Jumper
8ef60bfa9d GUACAMOLE-1538: Document parameters of libguac-terminal handlers. 2023-01-04 12:40:21 -08:00
Mike Jumper
d90e0e97fe GUACAMOLE-1538: Add missing documentation for libguac-terminal functions. 2023-01-04 12:22:02 -08:00
Mike Jumper
ec7964e8fb GUACAMOLE-1538: Return number of bytes written for guac_terminal_write() and guac_terminal_printf(). 2023-01-04 12:05:02 -08:00
James Muehlner
add7ce361b Merge 1.5.0 changes back to master. 2022-11-29 03:46:57 +00:00
James Muehlner
7d16f67d6d
GUACAMOLE-1293: Merge fix for double acquisition/release of rwlock. 2022-11-28 14:31:44 -08:00
Mike Jumper
e3adb97085 GUACAMOLE-1293: Do not re-acquire __users_lock while already held for writing.
Per POSIX spec, the behavior of acquiring a read lock on a rwlock that's
already acquired for writing is undefined. From the documentation for
pthread_rwlock_rdlock():

"... Results are undefined if the calling thread holds a write lock on
rwlock at the time the call is made."
2022-11-28 13:37:41 -08:00
Mike Jumper
55941823ec Merge 1.5.0 changes back to master. 2022-11-25 23:24:08 -08:00
Mike Jumper
07acce8a76
GUACAMOLE-1293: Merge support for notifying when a user has joined/left a connection. 2022-11-25 23:23:13 -08:00
Virtually Nick
5b1677f21a GUACAMOLE-1293: Fix copy-pasta and style issues; add user ID to information passed to client. 2022-11-25 21:57:44 -05:00
Virtually Nick
623c398005 GUACAMOLE-1293: Change new user info member to simply "name" to clarify its purpose. 2022-11-24 18:13:06 -05:00
Virtually Nick
aa92239edd GUACAMOLE-1293: Rename new enum values to be more consistent with existing code. 2022-11-08 07:45:38 -05:00
Virtually Nick
897712c743 GUACAMOLE-1293: Update and add debug logging. 2022-11-08 07:45:38 -05:00
Virtually Nick
02b24d0101 GUACAMOLE-1293: Simplify the assignment of strings/constants. 2022-11-08 07:45:38 -05:00
Virtually Nick
26eadc37a3 GUACAMOLE-1293: Move to status code plus arguments for msg instruction. 2022-11-08 07:45:38 -05:00
Virtually Nick
6d7156bc70 GUACAMOLE-1293: Update struct member that stores human-readable name. 2022-11-08 07:45:38 -05:00
Virtually Nick
6312e1720d GUACAMOLE-1293: Add support for notifying owner of users joining and leaving. 2022-11-08 07:45:38 -05:00
Virtually Nick
cb7ae25177 GUACAMOLE-1293: Add support for the name handshake instruction. 2022-11-08 07:45:38 -05:00
Virtually Nick
a4adb3f5c0 GUACAMOLE-1293: Add protocol support for msg instruction. 2022-11-08 07:45:38 -05:00
Dan Fandrich
5cf408ebbb GUACAMOLE-1714: Adapt to const parameters of ffmpeg 5.0. 2022-11-07 12:16:35 -08:00
Mike Jumper
3ca6bb0a61
GUACAMOLE-1708: Merge correction to missing Czech keyboard character mapping. 2022-11-06 09:05:52 -08:00
Max
457a169c49 GUACAMOLE-1708: Added Czech keyboard keymap fix missing char 2022-11-06 12:17:21 +01:00
Mike Jumper
bad381cebe
GUACAMOLE-1708: Merge RDP support for Czech keyboard layout. 2022-11-05 08:56:56 -07:00
Max
6171da6d0b GUACAMOLE-1708: Added Czech keyboard keymap for RDP 2022-11-01 21:56:23 +01:00
Mike Jumper
067f2a91a0
GUACAMOLE-1682: Merge automatic newline normalization of terminal clipboard. 2022-10-18 12:41:48 -07:00
Alex Leitner
bc52485570 GUACAMOLE-1682: Normalize conflicting newline encodings in clipboards between Linux and Windows systems for ssh sessions. 2022-10-18 19:38:56 +00:00
Mike Jumper
b20afa275a
GUACAMOLE-1669: Merge fix for RSA key upgrade failure if FIPS mode is enabled. 2022-09-13 14:45:55 -07:00
James Muehlner
b096e47f57 GUACAMOLE-1669: Include ext-info-c in preferred KEX algorithms to ensure RSA key upgrades can happen. 2022-09-13 21:39:38 +00:00
Mike Jumper
4d211e0c9e
GUACAMOLE-1674: Merge changes removing NLA from negotiation if FIPS is enabled. 2022-09-08 09:44:47 -07:00
James Muehlner
dffbeac57a GUACAMOLE-1674: Warn about NLA mode if FIPS mode is enabled, or disable if possible. 2022-08-30 23:23:56 +00:00
Mike Jumper
0361adc01f
GUACAMOLE-1669: Merge FIPS support for SSH connections. 2022-08-24 15:29:46 -07:00
James Muehlner
1971a9dad2 GUACAMOLE-1669: Prefer FIPS compliant ciphers and algorithms when FIPS mode is enabled. 2022-08-24 22:23:46 +00:00
Virtually Nick
5dbf4820ab Merge 1.5.0 changes back to master. 2022-08-19 15:48:51 -04:00
Virtually Nick
b2eb13a178
GUACAMOLE-1540: Merge correct automated retrieval of Docker build dependencies. 2022-08-19 15:30:31 -04:00
Michael Jumper
2bc9d5ff01 GUACAMOLE-1540: Correct regex stripping of package version (major number may have multiple digits). 2022-08-19 12:12:29 -07:00
Michael Jumper
5918cc9f7c GUACAMOLE-1540: Ignore failures to find packages associated with libraries we build ourselves. 2022-08-19 12:12:29 -07:00
James Muehlner
15f6e9f678 Merge 1.5.0 changes back to master. 2022-08-16 18:48:31 +00:00
James Muehlner
b5addfe3da
GUACAMOLE-1540: Merge Alpine Linux docker base image with manual library builds. 2022-08-16 09:40:45 -07:00
Michael Jumper
7f4246b6d5 GUACAMOLE-1540: Manual build all core protocol libraries for Docker image using Alpine Linux base. 2022-08-16 08:39:54 -07:00
Virtually Nick
6ab82446bb
GUACAMOLE-1652: Merge only call SSL init functions when the library version requires it. 2022-07-30 07:36:37 -04:00
James Muehlner
9c93337d97 GUACAMOLE-1652: Migrate OpenSSL initialization to modern methods for OpenSSL >= 1.1.0. 2022-07-30 02:24:31 +00:00
James Muehlner
cdee93ae25 GUACAMOLE-1652: Only call SSL init functions when the library version requires it. 2022-07-30 02:22:36 +00:00
Mike Jumper
eee3ac092c
GUACAMOLE-1622: Merge correction to terminal resize regression. 2022-07-13 16:20:19 -07:00
Alex Leitner
5bb56ed5ba GUACAMOLE-1622: Restructured code to resolve scrollbar resizing bug where the scrollbar would clip off the side of the terminal. This fix also resolves the issue where the text would blur at certain intervals of resizing the window. 2022-07-13 21:57:47 +00:00
Mike Jumper
0aae5eeadb
GUACAMOLE-1636: Merge corrections to typos within RDP comments/documentation. 2022-07-13 13:55:05 -07:00
Jimmy
6d994db9d2 GUACAMOLE-1636: Fix a typo mistake invokved. 2022-07-13 23:47:13 +03:00
Jimmy
cba5484be0 GUACAMOLE-1636: Fix a typo mistake recieved. 2022-07-13 23:41:42 +03:00
Jimmy
4048dd4900 GUACAMOLE-1636: Fix a typo mistake assicated. 2022-07-13 23:32:12 +03:00
Jimmy
98556fbe2e GUACAMOLE-1636: Fix a typo mistake coordinare. 2022-07-13 23:24:06 +03:00
Jimmy
f438a36612 GUACAMOLE-1636: Fix a typo mistake synchonize. 2022-07-13 23:17:50 +03:00
Jimmy
e8d966aec6 GUACAMOLE-1636: Fix a typo mistake Versoin. 2022-07-13 23:10:36 +03:00
Jimmy
523532a52d GUACAMOLE-1636: Fix a typo mistake offscren. 2022-07-13 23:02:37 +03:00
Mike Jumper
51c640fdbd
GUACAMOLE-1436: Merge addition of missing FreeRDP winpr headers. 2022-07-05 12:09:00 -07:00
Virtually Nick
4cf1bfae0e
GUACAMOLE-377: Merge update unit tests for new prototype of guac_protocol_send_sync(). 2022-07-05 14:30:57 -04:00
Michael Jumper
9642afc468 GUACAMOLE-377: Update unit tests for new prototype of guac_protocol_send_sync().
The new guac_protocol_send_sync() requires an additional parameter: the
number of logical frames associated with the sync.
2022-07-05 10:58:38 -07:00
James Muehlner
ffb6c809be
GUACAMOLE-1622: Merge addition of margins to ssh sessions. 2022-06-22 09:32:00 -07:00
Alex Leitner
64ea9c4d1f GUACAMOLE-1622: Clarified comments to describe if param is a pointer. 2022-06-21 16:16:52 +00:00
Alex Leitner
a5834fd319 GUACAMOLE-1622: Separated logic into single responsibility functions. 2022-06-16 17:09:41 +00:00
Alex Leitner
1e9cd9137b GUACAMOLE-1622: Added margins to ssh sessions. 2022-06-15 16:59:20 +00:00
James Muehlner
d4cd9b3e3a
GUACAMOLE-377: Merge support for RemoteFX. 2022-06-09 17:41:23 -07:00
Michael Jumper
31f1b2c7c4 GUACAMOLE-377: Rename single-letter "e" event arguments variable to "args" for readability. 2022-06-09 09:02:11 -07:00
Michael Jumper
ce27936ed5 GUACAMOLE-377: Add frame boundaries around cursor set operations if otherwise absent. 2022-06-09 09:02:11 -07:00
Michael Jumper
b7f05b9e4f GUACAMOLE-377: Ensure backing surface of underlying FreeRDP GDI implementation is resized when desktop is resized. 2022-06-09 09:02:11 -07:00
Michael Jumper
d5761ad625 GUACAMOLE-377: Warn about required color depth only if actually overridden. 2022-06-09 09:02:11 -07:00
Michael Jumper
b26f9d64d6 GUACAMOLE-377: Clarify usage of EndPaint to detect frames. 2022-06-09 09:02:11 -07:00
Michael Jumper
da80163e24 GUACAMOLE-377: Enable graphics pipeline extension by default. 2022-06-09 09:02:11 -07:00
Michael Jumper
28396ae345 GUACAMOLE-377: Expect explicit RDP frame boundaries only after at least one frame boundary has been received. 2022-05-18 15:43:54 -07:00
Michael Jumper
a0e9f6ed9b GUACAMOLE-377: Leverage client timestamp tracking for RDP frame duration. 2022-05-18 15:43:54 -07:00
Michael Jumper
bde8cdee46 GUACAMOLE-377: Add general RDP support for frame markers. 2022-05-18 15:43:54 -07:00
Michael Jumper
669e02b4dc GUACAMOLE-377: Leverage RDPGFX to report remote frame statistics to the client. 2022-05-12 13:50:20 -07:00
Michael Jumper
52c8683bcf GUACAMOLE-377: Add protocol-level support for reporting remote frame statistics. 2022-05-12 13:50:20 -07:00
Michael Jumper
c19eab9691 GUACAMOLE-377: Revise processing lag calculations to consider cumulative processing lag. 2022-05-12 13:50:20 -07:00
Michael Jumper
dd85c54961 GUACAMOLE-377: Add handling for EndPaint required by software GDI implementation of RDPGFX. 2022-05-12 13:50:20 -07:00
Michael Jumper
c795bf9e4a GUACAMOLE-377: Control RemoteFX / GFX support with "enable-gfx" parameter. 2022-05-12 13:50:20 -07:00
Michael Jumper
c469300941 GUACAMOLE-377: Support for RDPGFX. 2022-05-12 13:50:20 -07:00
James Muehlner
81300052e0
GUACAMOLE-1595: Merge mouse mask initialization fix. 2022-05-02 17:24:58 -07:00
Michael Jumper
df4e5c6fdf GUACAMOLE-1595: Ensure all mouse buttons are initially released when terminal starts. 2022-05-03 00:20:08 +00:00
Virtually Nick
a175a3d902
GUACAMOLE-1312: Merge add Canadian French RDP keymap 2022-03-23 09:58:58 -04:00
Kaven Rousseau
9cbd768210 GUACAMOLE-1312: Added fr_ca keymap 2022-03-17 16:13:42 -04:00
Virtually Nick
c716a07abc Merge 1.5.0 changes back to master. 2022-03-17 15:24:48 -04:00
Virtually Nick
c880f02fe8
GUACAMOLE-1115: Merge ensure RDP print process does not block itself from completing. 2022-03-17 15:20:51 -04:00
Michael Jumper
ce88fa4d4a GUACAMOLE-1115: Forcibly kill any outstanding PDF filter job when cleaning up resources. 2022-03-17 18:35:38 +00:00
Michael Jumper
d734bac590 GUACAMOLE-1115: Do not hold general RDP message lock while waiting for print operations.
Holding the message lock will block handling of things like mouse and
keyboard events, as the message lock must be acquired before sending the
corresponding messages to the RDP server. If mouse and keyboard events
are blocked, then handling of further Guacamole instructions like "ack"
is also blocked. If the print job is blocked until an "ack" is received,
this results in deadlock.
2022-03-17 18:35:20 +00:00
Mike Jumper
75a11b05b2
GUACAMOLE-1543: Merge changes moving recording structures/functions to the public API. 2022-03-01 09:58:50 -08:00
James Muehlner
854b5ecbb8 GUACAMOLE-1543: Move recording functionality from common to libguac. 2022-03-01 04:01:44 +00:00
Mike Jumper
d8073f9b17
GUACAMOLE-1538: Merge corrections to libguac-terminal build and scope. 2022-02-28 16:56:04 -08:00
James Muehlner
46e813343e GUACAMOLE-1538: Only the core functionality of the terminal lib should be public. 2022-03-01 00:33:55 +00:00
James Muehlner
ad0155b5f5 GUACAMOLE-1538: Make it clear which functions are getters by adding _get_ to the name of each. 2022-02-24 12:02:36 -08:00
James Muehlner
0856e94ece GUACAMOLE-1538 Use dashes instead of underscores in filenames for consistency with libguac public API. 2022-02-24 11:12:05 -08:00
James Muehlner
1c97cdb115 GUACAMOLE-1538: Autogenerate docs for new library. 2022-02-23 13:49:32 -08:00
James Muehlner
ce2ffdf75f GUACAMOLE-1538: Improve code style and cleanliness. 2022-02-22 20:37:42 -08:00
James Muehlner
6dd33a8d90 GUACAMOLE-1538: Do not use terminal internals outside of terminal code. 2022-02-22 16:06:48 -08:00
James Muehlner
589e0ecd03 GUACAMOLE-1538 - Consolidate clipboard handling; opaque clipboard struct to avoid exposing internal guac_common_clipboard. 2022-02-22 14:04:47 -08:00
James Muehlner
037045a054 GUACAMOLE-1538: Explicitly include the common lib; ensure no undefined symbols. 2022-02-22 11:07:30 -08:00
James Muehlner
63bf5b329c GUACAMOLE-1538: Rename library to match conventions. 2022-02-22 09:41:08 -08:00
Mike Jumper
dc9dfe562f
GUACAMOLE-1540: Merge changes correcting Docker-specific search for FreeRDP install location. 2022-02-21 17:32:23 -08:00
James Muehlner
757928dfa1 GUACAMOLE-1540: Search for libfreerdp2 installation directly instead of checking links. 2022-02-21 16:57:48 -08:00
Virtually Nick
a0faa02616
GUACAMOLE-1538: Merge refactor libguac_terminal for easier extensibility, and migrate to shared library. 2022-02-21 14:30:40 -05:00
James Muehlner
44d76da21a GUACAMOLE-1538: Use an options struct instead of hardcoding params in constructor. 2022-02-21 11:27:20 -08:00
James Muehlner
05c6131cf3 GUACAMOLE-1538: Update libguac_terminal to be a shared library. 2022-02-21 11:27:13 -08:00
Mike Jumper
001347b4e8
GUACAMOLE-1540: Merge migration of guacd Docker image to Ubuntu 21.10. 2022-02-18 16:20:17 -08:00
James Muehlner
edce11fcb4 GUACAMOLE-1540: Build using Ubuntu 21.10 as a base instead of buster-slim. 2022-02-18 15:48:18 -08:00
James Muehlner
e78d589e25
GUACAMOLE-876: Merge null-check fix for RDP open file check. 2022-02-18 13:50:03 -08:00
Michael Jumper
06461cac53 GUACAMOLE-876: Test for open files only if filesystem has been allocated. 2022-02-18 13:40:15 -08:00
Virtually Nick
8e94b00587
GUACAMOLE-1495: Merge add keymap for Polish keyboard layout for RDP 2022-02-17 12:46:01 -05:00
Virtually Nick
9245d02bc5
GUACAMOLE-462: Merge create recordings/typescripts with group read permission. 2022-02-17 12:43:51 -05:00
Michael Jumper
4d41b38a24 GUACAMOLE-462: Create recordings/typescripts with group read permission.
Previously, all recordings/typescripts were strictly readable by the
service user that created them (guacd). This prevents reading by other
services like the Guacamole web application. Instead,
recordings/typescripts should at least be group-readable.
2022-02-17 09:25:28 -08:00
Mike Jumper
29535e6cb8
GUACAMOLE-876: Merge changes deferring reconnect-to-resize until active transfers are complete. 2022-02-02 09:56:41 -08:00
Virtually Nick
10126444bf GUACAMOLE-876: Avoid disrupting open files and active print jobs to update display. 2022-02-01 21:45:10 -05:00
Mike Jumper
23612720ce
GUACAMOLE-745: Merge support for OpenSSH-format private keys / Ed25519. 2022-01-12 11:38:12 -08:00
Joshua Roys
f84db7d166 GUACAMOLE-745: Support OpenSSH private keys & ED25519
Let libssh2 parse PEM and ssh-native keys. Requires libssh2 1.9.0+
compiled against a crypto backend supporting ed25519.
2022-01-12 09:02:11 -05:00
ClassicGOD
a1d0d0aea4
GUACAMOLE-1495: add entry for pl_pl_qwerty
Add pl_pl_qwerty.keymap to rdp_keymaps
2022-01-10 20:31:41 +01:00
ClassicGOD
534158c1cb
GUACAMOLE-1495: add pl_pl_qwerty keymap
Add keymap file for Polish keyboard layout
2022-01-10 20:28:11 +01:00
Mike Jumper
56dca9880d
GUACAMOLE-1435: Merge correction to FreeRDP plugin entrypoint return type. 2022-01-03 21:59:57 -08:00
Virtually Nick
703f258b06 GUACAMOLE-1435: Correctly return UINT for DVCPluginEntry 2022-01-03 20:15:11 -05:00
Virtually Nick
bce1d2a434 GUACAMOLE-1436: Add winpr file.h dependencies as required. 2021-12-27 09:42:57 -05:00
Virtually Nick
084ddaf81f Merge 1.4.0 changes back to master. 2021-12-25 10:21:40 -05:00
Virtually Nick
be9041fefd
GUACAMOLE-478: Merge add clipboard line ending normalization option for RDP. 2021-12-25 10:18:39 -05:00
Michael Jumper
09bd4af77e GUACAMOLE-478: Add optional clipboard line ending normalization for RDP. 2021-12-25 00:31:17 -08:00
Michael Jumper
7472310a03 GUACAMOLE-478: Implement encoding translation functions for normalizing newline sequences. 2021-12-25 00:07:47 -08:00
Virtually Nick
27db57f704 Merge 1.4.0 changes back to master. 2021-12-24 19:24:36 -05:00
Virtually Nick
1f6f45e6e9
GUACAMOLE-1190: Merge explicitly use "localhost" as guacd default bind host, matching default of webapp. 2021-12-24 19:23:53 -05:00
Michael Jumper
e3e75464fb GUACAMOLE-1190: Explicitly use "localhost" as guacd default bind host, matching default of webapp. 2021-12-24 15:45:28 -08:00
Virtually Nick
90322cd4d3 Merge 1.4.0 changes back to master. 2021-12-19 22:17:47 -05:00
Virtually Nick
b9cc76058b
GUACAMOLE-1047: Merge notify connecting client of invalid connection IDs. 2021-12-19 18:39:15 -05:00
Michael Jumper
daa052398e GUACAMOLE-1047: Remove unnecessary use of snprintf() in favor of guacd_log(). 2021-12-18 15:13:10 -08:00
Virtually Nick
6760974912 Merge 1.4.0 changes back to master. 2021-12-11 07:44:56 -05:00
Virtually Nick
e84317ff86
GUACAMOLE-1411: Merge bump version numbers to 1.4.0. 2021-12-11 07:44:19 -05:00
Michael Jumper
a1a758f13c GUACAMOLE-1411: Update libtool version info for libguac (interfaces added and changed). 2021-12-10 23:55:16 -08:00
Michael Jumper
8dc92e69ca GUACAMOLE-1411: Bump version numbers to 1.4.0. 2021-12-10 23:51:34 -08:00
Virtually Nick
73ac4fcdbe
GUACAMOLE-1330: Merge dynamically allocate AVPacket when possible 2021-11-08 18:47:03 -05:00
Michael Jumper
bc6b5cef25 GUACAMOLE-1330: Dynamically allocate AVPacket when supported (static allocation deprecated as of libavcodec 58.133.100). 2021-11-08 15:24:36 -08:00
Virtually Nick
491be8382a
GUACAMOLE-1416: Merge fix unreleased terminal lock in ssh_client_thread 2021-09-10 10:40:10 -04:00
ycaibb
329171a950 GUACAMOLE-1416: Fix unreleased the lock in the ssh_client_thread
GUACAMOLE-1416: Fix unreleased the lock ssh_client->term_channel_lock in the ssh_client_thread.
2021-09-10 22:26:32 +08:00
Virtually Nick
12b8eac514
GUACAMOLE-1388: Merge ensure RDP-specific resources are cleaned up after channel disconnect. 2021-07-29 19:54:35 -04:00
Michael Jumper
2524af80a9 GUACAMOLE-1388: Ensure RDP-specific resources are cleaned up after channel disconnect.
Without these changes, RDP-specific resources like the CLIPRDR and RDPEI
channels may remain from past connections if the RDP connection is
dynamically reconnected via the "Reconnect" display resize method,
resulting in assertion failures or memory errors if those stale
resources are reused after reconnect is completed.
2021-07-28 15:50:18 -07:00
Virtually Nick
91d79da49f
GUACAMOLE-1386: Merge add proper RDP mapping of "Meta" ("Windows") key. 2021-07-27 09:51:48 -04:00
Michael Jumper
eb52b4e258 GUACAMOLE-1386: Add proper RDP mapping of "Meta" ("Windows") key. 2021-07-26 19:59:12 -07:00
Mike Jumper
278745d6d8
GUACAMOLE-1064: Merge Norwegian keyboard layout for RDP. 2021-06-02 22:34:29 -07:00
Øyvind Harboe
910c87bda0 GUACAMOLE-1064: add Norwegian keyboard
Tested on top of Guacamole 1.3.0

The following works beyond a simple smoke-test:

- æøå
- \
- |
- dead acute á
- dead grave à
- dead umlaut ö
- dead cirumflex ê
- dead tilde ~
2021-06-03 07:02:05 +02:00
Mike Jumper
31b4246e18
GUACAMOLE-1350: Merge corrections for defined but unused leave_handlers. 2021-05-25 11:44:35 -07:00
Jimmy
a91c4b3869 GUACAMOLE-1350: Add code to join leave_handler when connecting in other protocols. 2021-05-25 02:03:07 +03:00
Jimmy
26d87aa5d3 GUACAMOLE-1350: Add code to join leave_handler when connecting in rdp. 2021-05-24 01:11:28 +03:00
Mike Jumper
44145f681a
GUACAMOLE-1215: Merge correction for escaping of backslashes in JSON strings. 2021-05-17 12:25:23 -07:00
Virtually Nick
0182de6d18 GUACAMOLE-1215: Add backslash to list of JSON-escaped characters. 2021-05-17 14:15:38 -04:00
Mike Jumper
df25aa9fdc
GUACAMOLE-1276: Merge correction for 32-bit truncation regression affecting RDP uploads. 2021-05-14 10:51:13 -07:00
Virtually Nick
68fc594247 GUACAMOLE-1276: Correct file upload offset type. 2021-05-14 09:19:28 -04:00
Virtually Nick
a6a7e8ac26
GUACAMOLE-1201: Merge throttle outbound audio data to avoid overflowing RDP server audio input buffer. 2021-05-01 22:10:11 -04:00
Michael Jumper
189d8fab30 GUACAMOLE-1201: Throttle outbound audio data to avoid overflowing RDP server audio input buffer.
The RDP specification for the AUDIO_INPUT channel requires that all
audio be sent in packets of a specific size. Guacamole does correctly
limit itself to sending packets of this size to the RDP server, but will
send quite a few of these packets all at once if it has received more
audio data than the RDP packet size. This is OK in principle (the
Guacamole client should be able to send audio in packets of whatever
size it chooses), but may overwhelm the software running within the RDP
server if the amount of data received exceeds the available buffer
space, resulting in dropped samples.

As there is no way to know the size of the remote audio buffer, we need
to instead ensure that audio is streamed as close to real time as
possible, with each audio packet of N bytes not being sent until roughly
the amount of time represented by those N bytes has elapsed since the
last packet. This throttling ensures that software expecting to process
audio in real time should never run out of buffer space.

That said, if we never exceed the per-packet data rate and occasionally
send a packet earlier than real time would dictate, unavoidable latency
in sending/receiving audio data would accumulate over time. For example,
if each audio packet represents 10ms of audio data, but we receive that
audio packet 10.1ms after the previous packet, we need to adjust the
timing of the next audio packet(s) to account for that additional 0.1ms.
Simply waiting 10ms after sending each packet would cause that 0.1ms to
accumulate each time it occurs, eventually resulting in noticable
latency and finally running out of buffer space.

Thus, these changes:

1. Leverage a flush thread and per-packet scheduling to ensure that each
   flushed audio packet does not exceed the equivalent real time rate.
2. Calculate the amount of additional latency from the amount of data
   received beyond the required packet size, and amortize scheduling
   corrections to account for that latency over the next several audio
   packets.

This ensures that audio is streamed exactly as it is received if the
audio matches the packet size of the RDP server, and audio that is
received in a different size or varying sizes is buffered and throttled
to keep things within the expectations of software running within the
RDP server.
2021-05-01 16:23:32 -07:00
Virtually Nick
e90e438cf6
GUACAMOLE-1283: Merge add synchronization around absolutely all outbound RDP messages. 2021-04-17 13:11:32 -04:00
Michael Jumper
bf6922b31e GUACAMOLE-1283: Remove redundant parameters from guac_rdp_audio_buffer callback.
The buffer and data parameters of the guac_rdp_audio_buffer flush
handler are redundant now that the guac_rdp_audio_buffer is being passed
to the handler. They can instead be referenced as audio_buffer->packet
and audio_buffer->data respectively.
2021-04-13 17:47:56 -07:00
Michael Jumper
27e762d06f GUACAMOLE-1283: Add synchronization around absolutely all outbound RDP messages.
The FreeRDP library is intended to be threadsafe, but is not reliably so
with respect to legacy RDP encryption and outbound messages. When
outbound messages are sent by multiple threads, the encryption key used
for legacy RDP encryption may not be updated correctly, resulting in a
fatal connection error like:

"ERRINFO_DECRYPT_FAILED (0x00001192):(a) Decryption using Standard RDP
Security mechanisms (section 5.3.6) failed. (b) Session key creation
using Standard RDP Security mechanisms (section 5.3.5) failed."
2021-04-08 15:43:15 -07:00
Virtually Nick
b2ae2fdf00
GUACAMOLE-1307: Merge use VerifyCertificateEx callback if supported. 2021-03-10 14:38:43 -05:00
Michael Jumper
1b78f611d3 GUACAMOLE-1307: Use VerifyCertificateEx callback if supported. 2021-03-09 22:53:11 -08:00
James Muehlner
e2a136f41e
GUACAMOLE-1302: Merge support for forcing lossless compression in VNC and RDP connections. 2021-03-03 19:31:25 -08:00
Michael Jumper
18a0362dab GUACAMOLE-1302: Add RDP support for forcing lossless compression. 2021-03-03 19:29:14 -08:00
Michael Jumper
c2b7e2d039 GUACAMOLE-1302: Add VNC support for forcing lossless compression. 2021-03-03 19:29:14 -08:00
Michael Jumper
27f8403178 GUACAMOLE-1302: Always use lossless compression for text-based protocols leveraging the terminal. 2021-03-03 19:29:14 -08:00
Michael Jumper
0729a6cc73 GUACAMOLE-1302: Add surface/display level support for forcing lossless compression. 2021-03-03 19:29:14 -08:00
Virtually Nick
d9d5c79644
GUACAMOLE-1305: Merge fix pt-br keyboard layout 2021-03-03 16:19:20 -05:00
Higor Cavalcanti
650e7ad90f GUACAMOLE-1305: Fix pt-br keyboard layout. Key being recognized as right shift. 2021-03-03 16:49:59 -03:00
Virtually Nick
7bbab0efdd
GUACAMOLE-1174: Merge correct handling of truncated parameters when appending to URLs. 2021-02-21 20:32:47 -05:00
Michael Jumper
a920932703 GUACAMOLE-1174: Correct logic detecting truncation of appended parameter.
The previous implementation passed `length - str_len` to `snprintf()`,
yet compared the return value to `length`. This is incorrect, as
`length` is not the buffer size provided to `snprintf()`.
2021-02-21 15:05:53 -08:00
Michael Jumper
c7935736da GUACAMOLE-1174: Add unit tests for URL utility functions. 2021-02-21 15:05:53 -08:00
Michael Jumper
7f55399304 GUACAMOLE-1174: Clarify behavior of URL parameter appending function. 2021-02-21 14:15:17 -08:00
Mike Jumper
5428ac5057
GUACAMOLE-1174: Merge support for Kubernetes "exec" API call. 2021-02-21 11:09:53 -08:00
Tomer Gabel
a8cf250c98 GUACAMOLE-1047: Changed returned status code per review 2021-02-14 16:21:54 +02:00
James Muehlner
ca1fbd5e98
GUACAMOLE-1204: Merge addition of server-side support for multi-touch events. 2021-02-11 20:53:22 -08:00
Michael Jumper
d16ba33dee GUACAMOLE-1204: Add support for including touch events within session recordings. 2021-02-11 20:12:21 -08:00
Michael Jumper
5eb2867733 GUACAMOLE-1204: Add RDP support for multi-touch events via RDPEI channel. 2021-02-11 20:12:21 -08:00
Michael Jumper
048a59310b GUACAMOLE-1204: Add support for declaring layer multi-touch capabilities. 2021-02-11 20:12:21 -08:00
Michael Jumper
c88c0d1c89 GUACAMOLE-1204: Add libguac support for processing the "touch" instruction. 2021-02-11 20:12:21 -08:00
Virtually Nick
4a38d39694
GUACAMOLE-1277: Merge unswap - and _ on fr-be-azerty keymap 2021-02-02 15:54:12 -05:00
Sander Vanheule
841dc28e9b GUACAMOLE-1277: Unswap -/_ on fr-be-azerty keymap
When using the fr-be-azerty remote keyboard layout on an RDP connection,
the dash ('-') and underscore ('_') are swapped.

Underscore and dash are located on the same key on a Belgian azerty
layout. Dash should be the normal/unshifted character, and underscore
should be the shifted character. The current mapping has this the other
way around, so let's fix this.

Signed-off-by: Sander Vanheule <Sander.Vanheule@UGent.be>
2021-02-02 19:53:51 +01:00
Mike Jumper
c122a5f14a
GUACAMOLE-1133: Merge build-time sanity check for libvncserver usage of gcrypt. 2021-01-24 14:15:35 -08:00
Nick Couchman
5cee64514f GUACAMOLE-1133: Add gcrypt build dependency for Docker image. 2021-01-23 22:16:58 -05:00
Nick Couchman
b40b7e7bf6 GUACAMOLE-1133: Add build check for headers when libvncserver includes gcrypt support. 2021-01-23 22:04:38 -05:00
Mike Jumper
6d526cb60f
GUACAMOLE-1133: Merge addition of GCrypt initialization to VNC startup process. 2021-01-22 21:33:10 -08:00
Nick Couchman
46bed49a43 GUACAMOLE-1133: initialize GCrypt in VNC protocol prior to client start-up. 2021-01-21 21:14:18 -05:00
Virtually Nick
c769d18cf6
GUACAMOLE-1263: Merge mark freed memory as freed prior to calling rfbClientCleanup(). 2021-01-15 14:51:36 -05:00
Michael Jumper
612c5eba20 GUACAMOLE-1263: Mark freed memory as freed prior to calling rfbClientCleanup().
Older versions of libvncclient did not free all memory within
rfbClientCleanup(), but this has been corrected as of their 0.9.12
release. As guacamole-server may well be built against older versions of
libvncclient, we can't simply remove the manual free() calls, but we
should be sure to set any memory that we free ourselves to NULL so that
rfbClientCleanup() does not attempt to free it again.
2021-01-15 11:46:16 -08:00
Virtually Nick
fe62300223
GUACAMOLE-1259: Merge include missing config.h header for sake of conditional Stream_Free(). 2021-01-10 13:09:39 -05:00
Michael Jumper
0b6b14b71e GUACAMOLE-1259: Include missing config.h header for sake of conditional Stream_Free().
The changes introduced by GUACAMOLE-1181 (commit 2c86e20) were made
conditional as older versions of FreeRDP will automatically free the
wStream, resulting in a double-free if we attempt to do so ourselves.

The macro controlling that conditional code is defined within config.h,
which is missing here. Without that macro, the call to Stream_Free()
always occurs, and we get a double-free with older FreeRDP.
2021-01-09 21:15:50 -08:00
Virtually Nick
1c3e86dc2c
GUACAMOLE-1191: Merge always disable the glyph cache due to stability issues. 2021-01-09 22:46:12 -05:00
Michael Jumper
9dc793b0e5 GUACAMOLE-1191: Always disable the glyph cache, as FreeRDP no longer considers the feature to be stable. 2021-01-09 17:49:32 -08:00
Virtually Nick
1e6c42594f
GUACAMOLE-1254: Merge add support for libuuid as alternative to OSSP UUID. 2021-01-07 12:21:11 -05:00
Michael Jumper
430182dce2 GUACAMOLE-1254: Add unit tests for unique ID generation. 2021-01-06 22:51:07 -08:00
Michael Jumper
f710e00d26 GUACAMOLE-1254: Use libuuid rather than OSSP UUID if available.
The libuuid library is widely available (part of util-linux) and much
more frequently updated. The OSSP UUID library works great, but was last
updated in 2008 and causes some confusion for users that have libuuid.
2021-01-06 20:58:22 -08:00
Mike Jumper
53f981f864
GUACAMOLE-1245: Merge support for specifying Wake-on-LAN port. 2020-12-30 21:06:13 -08:00
Nick Couchman
a37668e9f5 GUACAMOLE-1245: Add support for specifying Wake-on-LAN port. 2020-12-30 16:50:38 -05:00
Nick Couchman
68c5dd1730 Merge 1.3.0 changes back to master. 2020-12-25 07:31:03 -05:00
Virtually Nick
90e15cb706
GUACAMOLE-1241: Merge avoid double-free when building against FreeRDP development snapshot. 2020-12-25 07:30:06 -05:00
Michael Jumper
9475c0b6fa GUACAMOLE-1241: Build against Debian repository that has non-snapshot version of FreeRDP.
Debian stable currently provides a FreeRDP package that is a snapshot of
commit 2693389a103394e035edc2a01055ca2c9ccccb21, whereas
stable-backports provides a FreeRDP package from release 2.2.0. Only a
release or release candidate can be relied upon for consistent behavior.
2020-12-24 13:15:58 -08:00
Michael Jumper
218f8d36b1 GUACAMOLE-1241: Disable build against FreeRDP development snapshots unless *explicitly* overridden. 2020-12-22 20:53:06 -08:00
Nick Couchman
d20b385834 Merge 1.3.0 changes back to master. 2020-12-22 19:05:16 -05:00
Virtually Nick
b608bb1513
GUACAMOLE-1242: Merge move "connection closed" log message to debug level. 2020-12-22 18:02:35 -05:00
Michael Jumper
3196f9f0d0 GUACAMOLE-1242: Move "connection closed" log message to debug level.
It is expected under normal circumstances that the connection may be
abruptly closed, including during the handshake. For example, this will
commonly occur when a TCP load balancer is performing a simple service
health check.

An message noting that the connection has been closed during the
Guacamole protocol handshake is really only of benefit when debugging,
where that information may provide useful context. If not debugging, the
message amounts to log noise.
2020-12-22 13:00:48 -08:00
Virtually Nick
2fc3a43e87
GUACAMOLE-1225: Merge fix simple typo, verfying -> verifying, in code documentation 2020-12-21 08:00:29 -05:00
Tim Gates
ced24fde7d
GUACAMOLE-1225: fix simple typo, verfying -> verifying
There is a small typo in src/libguac/tests/parser/read.c, src/libguac/tests/socket/fd_send_instruction.c, src/libguac/tests/socket/nested_send_instruction.c.

Should read `verifying` rather than `verfying`.

Fixes https://issues.apache.org/jira/browse/GUACAMOLE-1225
2020-12-21 17:04:52 +11:00
Michael Jumper
c6e8ad7a38 Merge 1.3.0 changes back to master. 2020-12-09 17:29:20 -08:00
Mike Jumper
47c7450f0f
GUACAMOLE-1110: Merge changes adding a guacd service group. 2020-12-09 17:28:17 -08:00
benrubson
4a5a350f59 GUACAMOLE-1110: Create a proper dedicated service group 2020-12-07 10:35:06 +01:00
Virtually Nick
b48e34fc3e
GUACAMOLE-1227: Merge build support for generic VNC credentials only if supported by libvncclient. 2020-12-03 07:14:34 -05:00
Michael Jumper
d40db7cd3c GUACAMOLE-1227: Build support for generic VNC credentials only if supported by libvncclient. 2020-12-02 22:55:16 -08:00
Yaroslav Nikonorov
004f57e19a GUACAMOLE-1174: Add prototype and docstrings for guac_kubernetes_append_endpoint_param function. 2020-11-18 15:30:34 +02:00
Yaroslav Nikonorov
7809447c3f GUACAMOLE-1174: Add parameters to the endpoint path using function guac_kubernetes_append_endpoint_param. 2020-11-18 14:57:59 +02:00
Yaroslav Nikonorov
7a1ba51bae GUACAMOLE-1174: Determine parameter delimiter, compute the buffer string length, fix the buffer string length usage, verify buffer null terminated. 2020-11-18 14:52:24 +02:00
Michael Jumper
9df3e294c3 Merge 1.3.0 changes back to master. 2020-11-03 14:29:52 -08:00
Mike Jumper
7fcddef117
GUACAMOLE-1205: Merge version number bump to 1.3.0. 2020-11-03 14:29:21 -08:00
Nick Couchman
c867d392d0 GUACAMOLE-1205: Update Guacamole Server version numbers for 1.3.0 release 2020-11-03 14:54:55 -05:00
Nick Couchman
8faeea18f8 Merge 1.3.0 changes back to master. 2020-11-03 14:02:38 -05:00
Virtually Nick
c2c67ee34d
GUACAMOLE-221: Merge handle FREERDP_ERROR_* constants only when defined. 2020-11-03 13:54:31 -05:00
Michael Jumper
1e3fc25268 GUACAMOLE-221: Handle FREERDP_ERROR_* constants only when defined.
Only FreeRDP 2.0.0-rc3 and later support all the constants used within
src/protocols/rdp/error.c.
2020-11-03 10:14:51 -08:00
Nick Couchman
299b7b4370 Merge 1.3.0 changes back to master. 2020-11-02 22:17:33 -05:00
Virtually Nick
1e856d4e2d
GUACAMOLE-221: Merge rely on FreeRDP error code if no RDP disconnect reason is available. 2020-11-02 22:16:43 -05:00
Nick Couchman
5124e78e05 Merge 1.3.0 changes back to master. 2020-11-02 20:35:00 -05:00
Virtually Nick
4d3280e817
GUACAMOLE-221: Merge terminate keep-alive thread immediately upon guac_socket_free(). 2020-11-02 20:09:18 -05:00
Michael Jumper
8041585379 GUACAMOLE-221: Increase verbosity of logged FreeRDP-related errors. 2020-11-02 15:40:29 -08:00
Michael Jumper
2a4ecda216 GUACAMOLE-221: Terminate keep-alive thread immediately upon guac_socket_free().
The keep-alive interval is identical to the timed client free used by
guacd. This results in a race condition where there is a random chance
that guacd will assume that the client has failed to terminate in a
timely manner simply because guac_socket_free() is waiting for the
keep-alive thread to finish.
2020-11-02 14:57:43 -08:00
Nick Couchman
e3df475bda Merge 1.3.0 changes back to master. 2020-11-02 16:16:22 -05:00
Virtually Nick
c48feb30f5
GUACAMOLE-221: Merge ensure guacd always enables broadcast socket keep-alive. 2020-11-02 16:00:59 -05:00
Michael Jumper
1e550b58d9 GUACAMOLE-221: Ensure guacd always enables broadcast socket keep-alive. 2020-11-02 12:51:58 -08:00
Michael Jumper
1e8d9d92a5 GUACAMOLE-221: Rely on FreeRDP error code if no RDP disconnect reason is available. 2020-11-02 12:38:06 -08:00
Nick Couchman
7563402631 Merge 1.3.0 changes back to master. 2020-10-30 10:13:25 -04:00
Virtually Nick
0be71a8c67
GUACAMOLE-1182: Merge ensure converted clipboard data is freed after being sent. 2020-10-30 10:12:25 -04:00
Nick Couchman
4e6ad1939f Merge 1.3.0 changes back to master. 2020-10-30 08:34:16 -04:00
Virtually Nick
c7d3814450
GUACAMOLE-1181: Merge rely on automatic freeing of wStream only for FreeRDP 2.0.0-rc3 through 2.0.0-rc4. 2020-10-29 22:23:35 -04:00
Michael Jumper
c1ad6115a2 GUACAMOLE-1181: Warn users if the internal behavior of their version of FreeRDP cannot be tested and may be unreliable. 2020-10-29 18:29:47 -07:00
Michael Jumper
256487c95a GUACAMOLE-1181: Only free wStream after send if FreeRDP requires this. 2020-10-29 18:29:47 -07:00
Michael Jumper
2c86e20ab9 GUACAMOLE-1181: Free wStream after send is complete/cancelled. 2020-10-28 20:23:37 -07:00
Michael Jumper
683ef1722e GUACAMOLE-1182: Ensure converted clipboard data is freed after being sent. 2020-10-28 16:36:50 -07:00
Yaroslav Nikonorov
79239e3be0 GUACAMOLE-1174: Create function for appending endpoint params, fix endpoint params overwriting. 2020-10-20 12:44:38 +03:00
Yaroslav Nikonorov
6b58e2e5a9 GUACAMOLE-1174: Free exec_command setting. 2020-10-20 12:44:38 +03:00
Yaroslav Nikonorov
164f792b86 GUACAMOLE-1174: Remove option use-exec, add snprintf result validation, fix code formatting. 2020-10-08 13:18:58 +03:00
Mike Jumper
2aa0218cc7
GUACAMOLE-1190: Merge guacd support for listening on IPv6 addresses. 2020-10-08 00:32:32 -07:00
Jonas Zeiger
8d683b560c GUACAMOLE-1190: Specify correct address family when creating socket 2020-10-07 10:02:28 +02:00
Virtually Nick
c449d83790
GUACAMOLE-1185: Merge fix typo in RDP audio input comment. 2020-10-03 07:45:38 -04:00
Jimmy
d6a817f58c GUACAMOLE-1185: Fixed one typo mistake. 2020-09-28 10:35:05 +03:00
Michael Jumper
ceabd68e28 Merge 1.3.0 changes back to master. 2020-09-27 16:36:00 -07:00
Mike Jumper
558eb149f4
GUACAMOLE-1031: Merge correction to handling of RDP SFTP upload directory. 2020-09-27 16:34:56 -07:00
Michael Jumper
3e1e1bd268 Merge 1.3.0 changes back to master. 2020-09-20 20:35:26 -07:00
Mike Jumper
aa870debad
GUACAMOLE-221: Merge server-side support for parameter prompting. 2020-09-20 20:31:34 -07:00
Nick Couchman
3e19583b29 GUACAMOLE-221: Switch VNC credentials to NULL when parameter is not passed 2020-09-20 14:41:29 -04:00
Nick Couchman
9e1dada14b GUACAMOLE-221: Add CUnit tests for guac_strdup() 2020-09-20 14:41:29 -04:00
Nick Couchman
3b4007c9fa GUACAMOLE-221: Tweak logic for when RDP domain is requested. 2020-09-20 14:41:29 -04:00
Nick Couchman
bfb54f72a0 GUACAMOLE-221: Clean up libguac, protocol changes, and documentation. 2020-09-20 14:41:29 -04:00
Nick Couchman
6605f217c5 GUACAMOLE-221: Rollback changes to SSH protocol prompting 2020-09-17 21:12:33 -04:00
Nick Couchman
b6d3edb749 GUACAMOLE-221: Move VNC and RDP argv to new callback. 2020-09-17 21:12:33 -04:00
Nick Couchman
f70fdfc612 GUACAMOLE-221: Add back in SSH credential argv support; fix style and comments. 2020-09-15 14:48:15 -04:00
Nick Couchman
ec3cdfd17b GUACAMOLE-221: We need to flush the socket after sending required. 2020-09-15 14:48:15 -04:00
Nick Couchman
26b9850d87 GUACAMOLE-221: Remove bad rebase code. 2020-09-15 14:48:15 -04:00
Nick Couchman
98dbf15d0b GUACAMOLE-221: Fix up SSH terminal prompt fallback. 2020-09-15 14:48:15 -04:00
Nick Couchman
e8feeabfef GUACAMOLE-221: Implement CUnit tests for protocol version comparison and conversion. 2020-09-15 14:48:15 -04:00
Nick Couchman
0db61198e9 GUACAMOLE-221: Fix up lots of comments, streamline code, and fix SSH mutex lock. 2020-09-15 14:48:15 -04:00
Nick Couchman
bc8ed4e104 GUACAMOLE-221: Implement guacd support for verifying that client can accept the required instruction. 2020-09-15 14:48:15 -04:00
Nick Couchman
b00b629b96 GUACAMOLE-221: Clean up VNC mutex; update comments. 2020-09-15 14:48:15 -04:00
Nick Couchman
0761908a77 GUACAMOLE-221: Sockets start keep alive by default. 2020-09-15 14:48:15 -04:00
Nick Couchman
c579e7337f GUACAMOLE-221: Implement function for sending required to client owner. 2020-09-15 14:48:15 -04:00
Nick Couchman
5ec2551761 GUACAMOLE-221: Use constants for parameters updated via argv or required instructions. 2020-09-15 14:48:15 -04:00
Nick Couchman
5881209f12 GUACAMOLE-221: Move keep-alives to protocol implementation and only send required instruction to owner. 2020-09-15 14:48:15 -04:00
Nick Couchman
5c309f5cb1 GUACAMOLE-221: Move away from reserved function names. 2020-09-15 14:48:15 -04:00
Nick Couchman
7759f9b1c0 GUACAMOLE-221: Add socket keepalive when sending required fields. 2020-09-15 14:48:15 -04:00
Nick Couchman
51b9c9c103 GUACAMOLE-221: Remove manual addition of null terminator 2020-09-15 14:48:15 -04:00
Nick Couchman
4318083511 GUACAMOLE-221: Fix up style, comments, and variable names. 2020-09-15 14:48:15 -04:00
Nick Couchman
939d954810 GUACAMOLE-221: Extract array writing in protocol into common function and document. 2020-09-15 14:48:15 -04:00
Nick Couchman
76ef6332cc GUACAMOLE-221: Make lock, condition, and flags specific to credentials. 2020-09-15 14:48:15 -04:00
Nick Couchman
7369bed22c GUACAMOLE-221: Add support for sending multiple params in required. 2020-09-15 14:48:15 -04:00
Nick Couchman
21a5d9ee62 GUACAMOLE-221: Add protocol functions for sending prompt to client. 2020-09-15 14:48:15 -04:00
Yaroslav Nikonorov
7683a17d69 GUACAMOLE-1174: Added exec call implementation for kubernetes protocol 2020-09-10 19:59:03 +03:00
Virtually Nick
382d72a26a
GUACAMOLE-1158: Merge handle received clipboard data only if copy has not been disabled. 2020-08-24 15:47:42 -04:00
Michael Jumper
df33cd0874 GUACAMOLE-1158: Handle received clipboard data only if copy has not been disabled. 2020-08-24 12:23:01 -07:00
Mike Jumper
be01e7e93a
GUACAMOLE-1151: Merge exclusion of NetBeans project directory via .gitignore. 2020-08-08 23:45:46 -07:00
Nick Couchman
7ee9c64c04 GUACAMOLE-1151: Add .gitignore entry for NetBeans project directory 2020-08-05 16:43:43 -04:00
Virtually Nick
a2fb09021b
GUACAMOLE-221: Merge add convenience API for automatically handling received "argv" streams. 2020-07-08 08:30:47 -04:00
Michael Jumper
0cdc51acd1 GUACAMOLE-221: Correct faulty double-increment of args (should advance ONE at a time). 2020-07-06 18:19:08 -07:00
Michael Jumper
aa3a9cde6c GUACAMOLE-221: Migrate Kubernetes handling of "argv" to guac_argv_*() convenience API. 2020-07-06 18:19:08 -07:00
Michael Jumper
08a57d3375 GUACAMOLE-221: Migrate telnet handling of "argv" to guac_argv_*() convenience API. 2020-07-06 18:19:08 -07:00
Michael Jumper
2f6de25418 GUACAMOLE-221: Migrate SSH handling of "argv" to guac_argv_*() convenience API. 2020-07-06 18:19:08 -07:00
Michael Jumper
f8f2c7f747 GUACAMOLE-221: Allow callers to request that argument values be automatically echoed to all connected users. 2020-07-06 18:19:08 -07:00
Michael Jumper
a8151c40c4 GUACAMOLE-221: Implement libguac convenience API for awaiting and processing argument streams. 2020-07-06 18:19:08 -07:00
Mike Jumper
f0dee00d33
GUACAMOLE-1110: Merge support for running the "guacd" Docker image as a specific service user. 2020-07-02 22:34:35 -07:00
Mike Jumper
3fc3880f0e
GUACAMOLE-1122: Merge fix for build failure due to conditionally-missing variable declaration. 2020-07-02 22:30:58 -07:00
Nick Couchman
d35a97d28e GUACAMOLE-1122: Correct scope of settings variable for RDP user file handler." 2020-07-02 16:50:23 -04:00
Mathias
7d06113cbe
GUACAMOLE-1110: Replace user nobody with guacd 2020-06-30 12:41:35 +02:00
Virtually Nick
c10ceab7e8
GUACAMOLE-1114: Merge fix the destruction of some thread mutexes 2020-06-26 14:19:39 -05:00
Jimmy
d34745a40b GUACAMOLE-1114: Clean up clipboard mutex lock. 2020-06-26 23:19:23 +03:00
Jimmy
264192fd25 GUACAMOLE-1114: Clean up print job mutex lock 2020-06-26 23:18:02 +03:00
Nick Couchman
79c6e5787d Merge staging/1.2.0 changes back to master. 2020-06-25 17:56:43 -04:00
Virtually Nick
6042222d44
GUACAMOLE-474: Merge properly enforce file new upload/download restrictions. 2020-06-25 17:52:11 -04:00
Michael Jumper
7de6ba7ea9 GUACAMOLE-474: Do not allow RDPDR file downloads via "get" instructions if downloads are disabled. 2020-06-25 14:43:37 -07:00
Michael Jumper
630798503c GUACAMOLE-474: Ensure RDPDR "Download" folder behaves as a normal folder if downloads are disabled. 2020-06-25 14:43:37 -07:00
Michael Jumper
f4ff5f337c GUACAMOLE-474: Enforce upload disable option at low level, warning if not blocked at higher level as expected. 2020-06-25 14:43:37 -07:00
Michael Jumper
d8c32b1e82 GUACAMOLE-474: Enforce download disable option at low level, warning if not blocked at higher level as expected. 2020-06-25 14:41:39 -07:00
Mathias
86176ff770
GUACAMOLE-1110: Shrinks container footprint, higher security and reliability check
Dockage image size will reduced by install only package dependencies (without recommendations). The guacd process runs as a non-privileged user and will be checked by netcat.
2020-06-25 17:51:29 +02:00
Nick Couchman
45a0cd943b Merge staging/1.2.0 changes back to master. 2020-06-24 20:19:10 -04:00
Virtually Nick
99fce8fa19
GUACAMOLE-465: Merge correct usage of printf-like guacenc_log(). 2020-06-24 20:16:58 -04:00
Michael Jumper
af2c109079 GUACAMOLE-465: Correct printf-style format string (should be "%s" for strings, not "%d"). 2020-06-24 17:14:25 -07:00
Michael Jumper
4ac0940e81 GUACAMOLE-465: Remove redundant newline character from calls to guacenc_log(). 2020-06-24 17:14:23 -07:00
Virtually Nick
3a87dd0c96
GUACAMOLE-465: Merge remove superfluous access check prior to attempting file deletion. 2020-06-24 20:10:34 -04:00
Nick Couchman
37965a961e Merge staging/1.2.0 changes back to master. 2020-06-24 20:09:05 -04:00
Virtually Nick
9ee956f765
GUACAMOLE-465: Merge correct possible leak of malloc'd video structure. 2020-06-24 20:08:20 -04:00
Michael Jumper
096a067b1f GUACAMOLE-465: Correct possible leak of malloc'd video structure. 2020-06-24 13:56:16 -07:00
Michael Jumper
8d9049942d GUACAMOLE-465: Remove superfluous access check prior to attempting file deletion. 2020-06-24 13:41:03 -07:00
Nick Couchman
708769b4c3 Merge staging/1.2.0 changes back to master. 2020-06-24 13:11:17 -04:00
Virtually Nick
614f38767e
GUACAMOLE-465: Merge produce MPEG-4 output within a proper container. 2020-06-24 13:10:32 -04:00
Nick Couchman
f1f1b0d438 Merge staging/1.2.0 changes back to master. 2020-06-24 12:59:34 -04:00
Virtually Nick
4815f62358
GUACAMOLE-966: Merge bump libguac version number for 1.2.0. 2020-06-24 12:58:40 -04:00
Nick Couchman
025525f93a Merge staging/1.2.0 changes back to master. 2020-06-24 12:55:34 -04:00
Virtually Nick
debd888cf5
GUACAMOLE-518: Merge correct behavior of keys typed with AltGr. 2020-06-24 12:54:37 -04:00
Michael Jumper
3e73e392a0 GUACAMOLE-966: Bump libguac version number for 1.2.0 (interfaces added, none changed or removed). 2020-06-24 02:37:35 -07:00
Michael Jumper
fb94ef9e9a GUACAMOLE-495: Add whitespace and reflow as necessary to improve readability. 2020-06-24 02:25:02 -07:00
Michael Jumper
628f2fd815 GUACAMOLE-518: Ensure all keys are released even if the key pressed client-side is unknown except through dead keys. 2020-06-24 00:54:39 -07:00
Michael Jumper
3798d85bd1 GUACAMOLE-518: Count client-side pressed keys independently of server-side keys. 2020-06-24 00:54:39 -07:00
Michael Jumper
2407157d00 GUACAMOLE-518: Handle modifier status correctly when multiple modifier keys are involved. 2020-06-24 00:54:39 -07:00
Michael Jumper
7d17e6898a GUACAMOLE-518: Remove unused GUAC_KEYSYMS_* constants. 2020-06-24 00:54:39 -07:00
Michael Jumper
337f3bbff2 GUACAMOLE-518: Map both Right Alt and AltGr to Windows' Right Alt.
Windows expects the Right Alt key to be sent for AltGr.
2020-06-23 22:05:18 -07:00
Michael Jumper
9b891e2360 GUACAMOLE-495: Update guacenc mangpage - the MPEG-4 output is no longer a raw stream. 2020-06-23 15:48:41 -07:00
Michael Jumper
81601d99fe GUACAMOLE-465: Reformat/reflow comments to match established style. 2020-06-23 15:40:04 -07:00
Nick Couchman
e8deeeae97 Merge staging/1.2.0 changes back to master. 2020-06-23 14:19:37 -04:00
Virtually Nick
5f5080994f
GUACAMOLE-518: Merge correct Caps Lock and Shift behavior within RDP keymap translation system. 2020-06-23 14:18:58 -04:00
Michael Jumper
60944f1092 GUACAMOLE-518: Keep locally-tracked keyboard lock status in sync with remote changes to keyboard locks. 2020-06-23 11:11:19 -07:00
Michael Jumper
a246403137 GUACAMOLE-518: Update German keymap to define behavior of Caps Lock.
On German keyboards, Caps Lock behaves like Shift, affects all
characters except dead keys, "°", "<", ">", "-", "_", and any keys
requiring AltGr, and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
3f375a4501 GUACAMOLE-518: Update Swiss German keymap to define behavior of Caps Lock.
On Swiss German keyboards, Caps Lock turns all letters uppercase and is
undone by Shift, except for letters which instead rely on Shift to
determine their identity (accented letters).

For example, the key directly to the right of "P" produces "ü" if no
modifiers or locks are active. With Shift pressed, the key changes
identity to "è", with the state of Caps Lock determining the case:

| Shift | Caps  | Result |
|-------|-------|--------|
|       |       | "ü"    |
|       |   X   | "Ü"    |
|   X   |       | "è"    |
|   X   |   X   | "È"    |

This goes for all accented characters in the Swiss German layout.
2020-06-23 11:11:19 -07:00
Michael Jumper
e8153f9002 GUACAMOLE-518: Update French keymap to define behavior of Caps Lock.
On French keyboards, Caps Lock behaves like Shift, affects all
characters including dead keys but excluding "<", ">", "²", and any keys
requiring AltGr, and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
568e037012 GUACAMOLE-518: Update Swiss French keymap to define behavior of Caps Lock.
On Swiss French keyboards, Caps Lock affects only non-accented letters
and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
31d05de72a GUACAMOLE-518: Update Belgian French keymap to define behavior of Caps Lock.
On Belgian French keyboards, Caps Lock behaves like Shift, affects all
characters including dead keys but excluding "<", ">", "²", "³", and any
keys requiring AltGr, and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
f884ab76b1 GUACAMOLE-518: Update Italian keymap to define behavior of Caps Lock.
On Italian keyboards, Caps Lock affects only non-accented letters and is
undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
1117cf052c GUACAMOLE-518: Update Turkish-Q keymap to define behavior of Caps Lock.
On Turkish-Q keyboards, Caps Lock affects only letters (including
accented letters) except for "é", and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
b69248048c GUACAMOLE-518: Update Swedish keymap to define behavior of Caps Lock.
On Swedish keyboards, Caps Lock affects only letters (including accented
letters) and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
38737a8353 GUACAMOLE-518: Update Brazilian Portuguese keymap to define behavior of Caps Lock.
On Brazilian Portuguese keyboards, Caps Lock affects only letters
(including accented letters) and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
5c1a2fc44c GUACAMOLE-518: Update Latin American keymap to define behavior of Caps Lock.
On Latin American keyboards, Caps Lock affects only letters (including
accented letters) and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
ba3d1de3bb GUACAMOLE-518: Update Spanish keymap to define behavior of Caps Lock.
On Spanish keyboards, Caps Lock affects only letters (including accented
letters) and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
2cec040b9e GUACAMOLE-518: Update Danish keymap to define behavior of Caps Lock.
On Danish keyboards, Caps Lock affects only letters (including accented
letters) and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
e9652becfd GUACAMOLE-518: Update Hungarian keymap to define behavior of Caps Lock.
On Hungarian keyboards, Caps Lock affects only letters (including
accented letters) except those requiring AltGr, and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
31a415cc59 GUACAMOLE-518: Update UK English keymap to define behavior of Caps Lock.
On UK English keyboards, Caps Lock affects only letters (including
accented letters) and is undone by Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
024e281252 GUACAMOLE-518: Update US English keymap to define behavior of Caps Lock.
On US English keyboards, Caps Lock affects only letters and is undone by
Shift.
2020-06-23 11:11:19 -07:00
Michael Jumper
48b3d5038f GUACAMOLE-518: Automatically release any automatically-pressed keys after user has released all keys on the client side. 2020-06-23 11:11:19 -07:00
Michael Jumper
cb6ffd06e6 GUACAMOLE-518: Allow multiple possible definitions (means of typing a particular key) for each keysym. 2020-06-23 11:11:19 -07:00
Michael Jumper
67450d89f3 GUACAMOLE-518: Correct signedness of keyboard flag variables. 2020-06-22 10:05:37 -07:00
Michael Jumper
96c4c208b4 GUACAMOLE-518: Ensure keyboard state is always updated for all keys pressed/released. 2020-06-22 10:05:37 -07:00
Michael Jumper
7fd54c56a8 GUACAMOLE-518: Modifications to generate.pl should result in regeneration of all keymaps. 2020-06-21 21:05:43 -07:00
Michael Jumper
ce0982fefd GUACAMOLE-518: Track and update modifier states based on overall flags, not keysyms. 2020-06-21 21:05:43 -07:00
Nick Couchman
0c784d434c Merge staging/1.2.0 changes back to master. 2020-06-20 20:53:18 -04:00
Virtually Nick
120be65dbc
GUACAMOLE-1076: Merge correct RemoteApp launch behavior. 2020-06-20 20:51:21 -04:00
Michael Jumper
7598f5a95a GUACAMOLE-1076: Use proper constants to represent RemoteApp high contrast support flags. 2020-06-20 16:09:43 -07:00
Michael Jumper
d5608fb8a2 GUACAMOLE-1076: Send same System Parameters Update PDUs as Apache Guacamole 1.0.0 and older. 2020-06-20 15:09:00 -07:00
Michael Jumper
a7732e72be GUACAMOLE-1076: Ensure Client Information PDU is sent during RAIL handshake (required by spec). 2020-06-20 14:32:53 -07:00
Michael Jumper
6a50d3076c GUACAMOLE-1076: Set RAIL flag for expanding environment variables within RemoteApp arguments (match v1.0.0 behavior). 2020-06-20 14:14:29 -07:00
Michael Jumper
29b055b511 Merge 1.2.0 changes back to master. 2020-06-18 12:52:30 -07:00
Mike Jumper
f899fe0b2f
GUACAMOLE-1053: Merge restoration of proper locking on RDP structures. 2020-06-18 12:51:34 -07:00
Grigory Trenin
d76502d169 GUACAMOLE-1053: guacd segfaults when user actively presses keys at RDP disconnect time 2020-06-18 05:57:33 -04:00
Michael Jumper
787ae317fc Merge 1.2.0 changes back to master. 2020-06-17 14:12:12 -07:00
Mike Jumper
e82eb45a74
GUACAMOLE-513: Merge improvements to Wake-on-LAN error handling and wait behavior. 2020-06-17 14:11:27 -07:00
Nick Couchman
db4b155c51 GUACAMOLE-513: Update default WoL boot wait time to 0. 2020-06-17 15:27:12 -04:00
Virtually Nick
72489d5690
GUACAMOLE-1103: Merge fix the incorrect comment on enable_sftp variable in RDP 2020-06-17 14:10:16 -04:00
Jimmy
2c2f372def GUACAMOLE-1103: Fixed the incorrect comment of the enable_sftp variable of the guac_rdp_settings structure. 2020-06-17 23:01:13 +03:00
Nick Couchman
e51c269a51 GUACAMOL-513: Correctly handle unknown address families. 2020-06-17 06:50:43 -04:00
Nick Couchman
b0bcb30346 GUACAMOLE-513: Merge socket calls and handle IP family determination correctly. 2020-06-16 16:48:51 -04:00
Nick Couchman
ec305903d0 GUACAMOLE-513: Add guac_error handling for WoL 2020-06-16 15:06:51 -04:00
Nick Couchman
57c4dbf454 GUACAMOLE-513: No need to close socket when socket was never opened. 2020-06-16 11:50:36 -04:00
Nick Couchman
30bbb892db GUACAMOLE-513: Handle cases where socket open fails. 2020-06-09 19:29:22 -04:00
Michael Jumper
b8ecfe2425 Merge 1.2.0 changes back to master. 2020-06-09 10:43:10 -07:00
Mike Jumper
9ca382e2aa
GUACAMOLE-513: Merge addition of new defaults.h header to Makefile.am. 2020-06-09 10:42:37 -07:00
Nick Couchman
0c59897da9 GUACAMOLE-513: New defaults header needs to be in Makefile.am 2020-06-09 13:06:40 -04:00
Michael Jumper
b6568d11b3 Merge 1.2.0 changes back to master. 2020-06-09 01:15:43 -07:00
Mike Jumper
65c07b75cc
GUACAMOLE-513: Merge support for Wake-on-LAN. 2020-06-09 01:15:11 -07:00
Michael Jumper
a5a89bcf1d Merge 1.2.0 changes back to master. 2020-06-08 10:42:40 -07:00
Mike Jumper
32723d229f
GUACAMOLE-474: Merge corrections to file upload/download build failures. 2020-06-08 10:40:05 -07:00
Nick Couchman
2aa2ccc90c GUACAMOLE-513: Properly close WOL socket. 2020-06-07 20:33:19 -04:00
Nick Couchman
df8030d9bb GUACAMOLE-513: Implement defaults header for protocol constants. 2020-06-07 20:27:42 -04:00
Nick Couchman
42e223f4a6 GUACAMOLE-474: Correct variable name and scope errors in RDP fs code. 2020-06-07 19:51:02 -04:00
Michael Jumper
4dce306a04 Merge 1.2.0 changes back to master. 2020-06-07 16:31:08 -07:00
Mike Jumper
e526174009
GUACAMOLE-474: Merge support for selectively disabling file uploads and downloads. 2020-06-07 16:30:37 -07:00
Nick Couchman
af89f828eb Merge staging/1.2.0 changes back to master. 2020-06-07 07:22:05 -04:00
Virtually Nick
d03d45fbf0
GUACAMOLE-1059: Merge correct verification of sound format index. 2020-06-07 07:20:22 -04:00
Michael Jumper
4184a52c98 GUACAMOLE-1059: Sound format index should be checked against maximum number of formats, not byte size of array. 2020-06-06 23:50:28 -07:00
Nick Couchman
ec093d3cea GUACAMOLE-474: Minor style and debug message tweaks. 2020-05-29 07:39:39 -04:00
Michael Jumper
029563a4b9 Merge 1.2.0 changes back to master. 2020-05-25 02:43:01 -07:00
Mike Jumper
8d895f13c7
GUACAMOLE-1059: Merge explicit non-fatal check for invalid RDP audio format request. 2020-05-25 02:41:51 -07:00
Nick Couchman
ff34146f57 GUACAMOLE-1059: Log array boundary violation for sound formats. 2020-05-24 08:55:58 -04:00
Nick Couchman
234f5aff1a GUACAMOLE-1059: Check array boundary for sound formats. 2020-05-16 21:12:53 -04:00
Michael Jumper
a0e11dc817 Merge staging/1.2.0 changes back to master. 2020-05-07 14:10:33 -07:00
Mike Jumper
0bf65ce8b0
GUACAMOLE-1059: Merge changes leveraging appropriate FreeRDP checks to verify input stream length. 2020-05-07 14:09:47 -07:00
Nick Couchman
557e2f5944 GUACAMOLE-1059: Fine tune comments and log messages. 2020-05-06 10:17:20 -04:00
Nick Couchman
47bf3ab672 GUACAMOLE-1059: Verify correct number of bytes for incoming wave. 2020-05-05 17:15:47 -04:00
Nick Couchman
315a8a7179 GUACAMOLE-1059: Correctly handle issues processing audio input formats. 2020-05-05 16:53:13 -04:00
Nick Couchman
e761e47cd0 GUACAMOLE-1059: Add missing checks and fix up warning messages. 2020-05-05 16:33:59 -04:00
Nick Couchman
71769b9715 GUACAMOLE-1059: Add missing check for manually copied buffer. 2020-05-04 19:49:15 -04:00
Nick Couchman
ac9e5e91f6 GUACAMOLE-1059: Remove bad check of audio stream against body_size. 2020-05-04 17:53:38 -04:00
Nick Couchman
98f0c271fb GUACAMOLE-1059: Add explanatory comments and additional logging. 2020-05-04 17:45:17 -04:00
Nick Couchman
8560ff9718 GUACAMOLE-1059: Move rdpsnd body size check to correct location. 2020-05-04 12:11:37 -04:00
Nick Couchman
ce28575b3a GUACAMOLE-1059: Use FreeRDP function for verifying Stream length before reading. 2020-05-04 08:48:40 -04:00
Tomer Gabel
8838199f5c GUACAMOLE-1047: Notify connecting client on unrecognized connection ID 2020-04-23 16:53:17 +03:00
Nick Couchman
f910d29083 GUACAMOLE-1031: Add call for RDP to pay attention to upload directory 2020-04-16 12:20:58 -04:00
Nick Couchman
02a7291742 GUACAMOLE-513: Adjust names of constants and fix style. 2020-04-15 09:42:22 -04:00
Mike Jumper
9c37fc5617
GUACAMOLE-949: Merge removal of unused UNIX_TIME macro. 2020-04-13 23:16:25 -07:00
Nick Couchman
a55e1893dd GUACAMOLE-949: Remove unused UNIX_TIME macro. 2020-04-02 15:53:51 -04:00
Nick Couchman
b077013c30 GUACAMOLE-474: Hide Download folder if downloads are disabled. 2020-04-02 14:58:06 -04:00
Nick Couchman
bbb794966b Merge staging/1.2.0 changes back to master. 2020-03-22 20:30:42 -04:00
Virtually Nick
e78eb589d9
GUACAMOLE-952: Merge correct security negotiation behavior for Hyper-V / VMConnect. 2020-03-22 20:29:33 -04:00
Michael Jumper
04b8633410 GUACAMOLE-952: Add security negotiation mode specific to Hyper-V / VMConnect. 2020-03-22 16:27:55 -07:00
Michael Jumper
aa8c8cac84 GUACAMOLE-952: Remove incorrect Preconnection PDU warning left over from old FreeRDP support. 2020-03-22 16:27:55 -07:00
Nick Couchman
a0d4bacbc6 GUACAMOLE-513: Support determining IPv4 or IPv6. 2020-03-19 09:12:15 -04:00
Nick Couchman
0feda1fa2f GUACAMOLE-513: Make packet size a constant. 2020-03-19 09:12:15 -04:00
Nick Couchman
45e46bd245 GUACAMOLE-513: Move sleep to protocol implementations; update comments and headers. 2020-03-19 09:12:15 -04:00
Nick Couchman
3dc2591517 GUACAMOLE-513: Add debug logging for sending WoL. 2020-03-19 09:12:15 -04:00
Nick Couchman
3d4a27607d GUACAMOLE-513: Implement settings and code for Wake-on-LAN support. 2020-03-18 13:29:58 -04:00
Virtually Nick
fba6ef461c
GUACAMOLE-982: Merge fix the error log message when the creating thread of RDP client fails 2020-03-09 18:45:11 -04:00
Jimmy
fa86d18353 GUACAMOLE-982: Fix the error log message when the creating thread of RDP client fails. 2020-03-09 23:16:28 +02:00
Nick Couchman
f47491eaca Merge staging/1.2.0 changes back to master. 2020-03-02 18:38:03 -05:00
Virtually Nick
e4407167ab
GUACAMOLE-979: Merge ensure all FreeRDP settings strings are independent duplicates of their corresponding Guacamole settings. 2020-03-02 18:36:33 -05:00
Virtually Nick
253213b29d
GUACAMOLE-978: Merge respond to Handshake/HandshakeEx PDU received via RAIL with client Handshake PDU. 2020-03-02 18:35:53 -05:00
Michael Jumper
5e1b92cb65 GUACAMOLE-979: Ensure all FreeRDP settings strings are independent duplicates of their corresponding Guacamole settings.
FreeRDP 2.0.0 will automatically free all settings strings when the
settings structure is freed. As we will also do the same for our own
settings strings, the FreeRDP settings must be kept independent. There
is no guarantee that the FreeRDP settings will be pushed before an error
causes the connection to abort, nor that the FreeRDP settings will not
need to be pushed multiple times due to an automatic reconnect.
2020-03-02 15:02:03 -08:00
Michael Jumper
789463ce76 GUACAMOLE-978: Respond to Handshake/HandshakeEx PDU received via RAIL with client Handshake PDU. 2020-03-02 14:15:27 -08:00
Nick Couchman
cc688485db Merge staging/1.2.0 changes back to master. 2020-02-28 13:51:13 -05:00
Virtually Nick
cf845be5ee
GUACAMOLE-917: Merge add missing non-dead tilde to German keymap for RDP. 2020-02-28 13:49:45 -05:00
Michael Jumper
28983d964b GUACAMOLE-917: Add missing non-dead tilde to German keymap for RDP. 2020-02-28 10:47:22 -08:00
Michael Jumper
0832dda409 Merge 1.2.0 changes back to master. 2020-02-26 18:51:06 -08:00
Mike Jumper
4b4b11da57
GUACAMOLE-966: Merge bump of guacamole-server version number to 1.2.0. 2020-02-26 18:50:30 -08:00
Nick Couchman
34d798a0ff GUACAMOLE-966: Bump server version to 1.2.0 2020-02-25 20:45:54 -05:00
Nick Couchman
811d2f70e4 Merge staging/1.2.0 changes back to master. 2020-02-24 22:50:10 -05:00
Virtually Nick
83d2f30f8b
GUACAMOLE-818: Merge break SFTP directory JSON at blob boundaries. Do not skip entries. 2020-02-24 21:14:49 -05:00
Michael Jumper
8ea9b14a80 GUACAMOLE-818: Break SFTP directory JSON at blob boundaries. Do not skip entries.
The intent of the previous version of the SFTP directory listing code
was to break the JSON transfer at blob boundaries, waiting for an ack
before sending the next blob, however the ordering of the "blob_written"
and directory read checks could result in a directory entry being
skipped at the boundary of each blob.

The proper order would be to check the "blob_written" flag first,
however the "blob_written" flag is unnecessary. It's simpler and more
correct to just break out of the loop once the desired blob has been
flushed.
2020-02-24 17:58:29 -08:00
Virtually Nick
d2ee11f15a
GUACAMOLE-962: Merge allow misbehaving RDP servers to use OpaqueRect and PatBlt. 2020-02-24 20:27:20 -05:00
Michael Jumper
a80cd8db06 GUACAMOLE-962: Restore OpaqueRect and PatBlt handlers.
This commit effectively reverts commit 9855d875c7.

With relaxed order checks enabled, FreeRDP will indeed invoke the
OpaqueRect and PatBlt handlers (even though we do not announce support
for those orders) as long as handlers are provided.
2020-02-24 16:48:14 -08:00
Michael Jumper
3b0abe376e GUACAMOLE-962: Request relaxed RDP order checks if supported by FreeRDP. 2020-02-24 16:48:14 -08:00
Mike Jumper
090bb3bbea
GUACAMOLE-958: Merge changes correcting race condition and potential deadlock in guacd_timed_client_free(). 2020-02-13 09:49:35 -08:00
Jonas Zeiger
783aa85c1b GUACAMOLE-958: Avoid race/deadlock in guacd_timed_client_free() 2020-02-12 15:06:25 +01:00
Virtually Nick
5ecad1c3d9
GUACAMOLE-947: Merge fix the initialization issue of CLIPRDR_FORMAT_LIST object 2020-02-06 16:54:39 -05:00
Jimmy
659cdd09a0 GUACAMOLE-947: Fix the initialization issue of CLIPRDR_FORMAT_LIST object. 2020-02-06 18:17:40 +02:00
Sean Reid
fe0658dd36 GUACAMOLE-465: resolved issues brought up in PR159 and added compatibility with recent versions of libavcodec 2020-02-02 16:34:40 -05:00
Sean Reid
fb237d4fc9 GUACAMOLE-465: resolved issues brought up in PR159 (unneeded dynamic mem allocation, style guide violations) 2020-02-02 16:34:40 -05:00
Sean Reid
bb825de73b GUACAMOLE-465: added dependency to libavformat as first step to supporting other types of codecs and containers in guacenc. migrated existing functionality to use the libavformat library for writing the files. there is not differnce to the user with this patch, but it provides a good base to finish this new feature from later 2020-02-02 16:34:40 -05:00
Nick Couchman
1a699686b9 GUACAMOLE-474: Implement logic to disable file transfers in each protocol. 2020-01-26 03:33:08 -05:00
Nick Couchman
42e382062c GUACAMOLE-474: Add parameter processing for file upload/download disable. 2020-01-26 03:33:08 -05:00
Mike Jumper
68a6285818
GUACAMOLE-625: Merge changes correcting failing build due to trailing whitespace in Makefile.am. 2020-01-24 08:09:32 -08:00
Nick Couchman
0e845a2914 GUACAMOLE-625: Remove trailing whitespace in Makefile.am and fix style 2020-01-24 10:32:25 -05:00
Virtually Nick
550e13ae9f
GUACAMOLE-625: Merge include Latin American RDP keymap 2020-01-24 10:07:10 -05:00
Adolfo Gómez García
b13fae7a9f GUACAMOLE-625: Included Latin American keymap 2020-01-24 10:50:23 +01:00
Nick Couchman
0aecca3e04 Merge staging/1.1.0 changes back to master. 2020-01-22 16:25:39 -05:00
Virtually Nick
a054073ec7
GUACAMOLE-935: Merge do not assign SVC plugin context as it may be automatically freed. 2020-01-22 16:23:38 -05:00
Michael Jumper
8ebe5c571a GUACAMOLE-935: Do not assign SVC plugin context as it may be automatically freed.
FreeRDP version 2.0.0-rc0 and older will automatically free whatever
entry_points->pInterface is set to when the channel plugin is unloaded.
This doesn't happen in later versions, but will result in a double-free
upon disconnect for 2.0.0-rc0 in our case. As we don't need pInterface,
we can safely set this to NULL and avoid the issue entirely.
2020-01-22 11:10:50 -08:00
James Muehlner
28f7d3694e Merge 1.1.0 changes back to master. 2020-01-21 23:30:27 -08:00
James Muehlner
3bc00c429a
GUACAMOLE-935: Merge fix for differing rdpBitmap free behavior. 2020-01-21 23:28:46 -08:00
Michael Jumper
87a3c7392b GUACAMOLE-935: Periods within regexes must be escaped if intended to match literal periods. 2020-01-21 22:35:26 -08:00
Michael Jumper
49df9f04e0 GUACAMOLE-935: Use C preprocessor to determine FreeRDP version rather than running a test program.
AC_RUN_IFELSE cannot be used when cross-compiling, whereas AC_EGREP_CPP
can.
2020-01-21 22:40:18 -08:00
Michael Jumper
26dfc533bd GUACAMOLE-935: Free internals of rdpBitmap only when required.
In FreeRDP 2.0.0-rc0 and earlier, Bitmap_Free(bitmap) invokes the free
handler of the given bitmap, frees bitmap->data, and then frees the
bitmap. The implementation-specific free handler needs to be aware only
of the implementation's own concerns.

After FreeRDP 2.0.0-rc0, Bitmap_Free(bitmap) only invokes the
implementation-specific free handler, and it's on the implementation to
know that bitmap->data must be manually freed with _aligned_free() and
bitmap must be freed with free(). The implementation-specific free
handler must be aware of the internals of the library.

See commit 8dda26a.
2020-01-21 22:35:26 -08:00
James Muehlner
75b658c6c9
GUACAMOLE-934: Merge support for the Play Sound PDU. 2020-01-21 22:08:44 -08:00
James Muehlner
24b6a3f357
GUACAMOLE-931: Merge FreeRDP user home directory safety checks. 2020-01-21 21:43:49 -08:00
Michael Jumper
b21d19d37d GUACAMOLE-934: Correct waveform calculation. Switch to triangle wave to reduce aliasing distortion. 2020-01-21 00:03:42 -08:00
Michael Jumper
b8148b0daf GUACAMOLE-934: Handle potential lack of available audio streams. 2020-01-20 21:16:36 -08:00
Michael Jumper
ddc09b161a GUACAMOLE-934: Add support for the Play Sound PDU. 2020-01-20 18:36:06 -08:00
Michael Jumper
32f8f20852 GUACAMOLE-931: Verify that home directory is both a directory and writable for sake of FreeRDP initialization. 2020-01-20 11:49:11 -08:00
Nick Couchman
a447b3dc1a Merge staging/1.1.0 changes back to master. 2020-01-20 03:51:47 -05:00
Virtually Nick
0cd9ba387b
GUACAMOLE-929: Merge update copyright date to 2020. 2020-01-20 03:50:29 -05:00
Michael Jumper
35e44db713 GUACAMOLE-929: Update copyright date to 2020. 2020-01-19 13:36:09 -08:00
Nick Couchman
cc8d879a12 Merge staging/1.1.0 changes back to master. 2020-01-18 06:16:54 -05:00
Virtually Nick
77f6168729
GUACAMOLE-928: Merge keep FreeRDP plugins of Docker image within /usr/local/guacamole 2020-01-18 06:15:23 -05:00
Virtually Nick
a384e749e2
GUACAMOLE-927: Merge automatically set $HOME for sake of FreeRDP initialization process 2020-01-18 06:13:45 -05:00
Michael Jumper
2c6be5afd1 GUACAMOLE-928: Keep all build artifacts of Docker image within /usr/local/guacamole, including FreeRDP plugins. 2020-01-17 16:15:31 -08:00
Michael Jumper
0676e70325 GUACAMOLE-927: Abort RDP connection if FreeRDP fails to initialize. 2020-01-17 15:54:56 -08:00
Michael Jumper
39f7d5a843 GUACAMOLE-927: Automatically set $HOME for sake of FreeRDP initialization process. 2020-01-17 15:50:47 -08:00
Nick Couchman
fd2c5b9259 Merge staging/1.1.0 changes back to master. 2020-01-16 15:06:56 -05:00
Virtually Nick
39defa27fa
GUACAMOLE-249: Merge automatically determine correct location for FreeRDP plugins. 2020-01-16 15:04:45 -05:00
Michael Jumper
be5cdf52c1 GUACAMOLE-249: Allow detected FreeRDP plugin directory to be overridden with --with-freerdp-plugin-dir. 2020-01-16 11:57:14 -08:00
Michael Jumper
37dceed8ec GUACAMOLE-249: Automatically determine correct location for FreeRDP plugins. 2020-01-15 21:55:27 -08:00
Virtually Nick
65b4722a1a
GUACAMOLE-249: Merge remove extra warning resulting from merge 2020-01-14 19:17:22 -05:00
Michael Jumper
fcac1a26f8 GUACAMOLE-249: Remove extra warning resulting from merge.
If the admin intentionally disables both copy and paste, then there is
no need to log a warning that this is the case; it was intentional. A
warning will likely set off alarm bells within production log monitoring
systems.
2020-01-14 15:50:23 -08:00
Nick Couchman
956c5f293e Merge staging/1.1.0 changes back to master. 2020-01-14 16:27:09 -05:00
Virtually Nick
3e22526ad9
GUACAMOLE-249: Merge migrate to FreeRDP 2.x 2020-01-14 14:21:26 -05:00
Michael Jumper
99b00a8cc0 GUACAMOLE-249: Add -Werror to CPPFLAGS for FreeRDP tests to ensure tests fail when pointers are incompatible. 2020-01-13 18:17:56 -08:00
Michael Jumper
de3300ed89 GUACAMOLE-249: Preserve CPPFLAGS such that modifications needed for FreeRDP tests affect only FreeRDP tests. 2020-01-13 18:17:32 -08:00
Michael Jumper
3dfd2467c3 GUACAMOLE-249: Remove RAIL callback typecasts, relying instead on configure tests to check need for const. 2020-01-13 16:34:02 -08:00
Michael Jumper
e5fdda1286 GUACAMOLE-249: Remove CLIPRDR callback typecasts, relying instead on configure tests to check need for const. 2020-01-13 16:34:02 -08:00
Michael Jumper
308d7a09a8 GUACAMOLE-249: Support rdpGlyph callback format used in FreeRDP 2.0.0-rc3 and older (used UINT32 instead of INT32). 2020-01-13 16:34:02 -08:00
Michael Jumper
9a34caf40f GUACAMOLE-249: The FreeRDPConvertColor() function is also known as ConvertColor(), but was only available as ConvertColor() in older FreeRDP 2.0.0 release candidates. 2020-01-13 16:08:17 -08:00
Michael Jumper
eaae203e94 GUACAMOLE-249: Ensure RAIL message handlers are accepted by compiler regardless of whether const is required. 2020-01-13 15:41:56 -08:00
Michael Jumper
4282da662f GUACAMOLE-249: Restructure audio input such that audio buffer can be separately linked.
On some platforms, the libguacai-client.so plugin for FreeRDP reports an
unlinked symbol:

    undefined symbol: guac_freerdp_dynamic_channel_collection_add	(/usr/local/lib/freerdp2/libguacai-client.so)

This symbol is actually unused within the plugin, but may be referenced
due to being defined within a function in a common piece of source
shared between the plugin and the RDP support.

Separating the actual common components such that they can be included
by both the RDP support and the libguacai-client.so plugin removes the
potential for unused pieces being flagged as missing.
2020-01-12 22:04:01 -08:00
Michael Jumper
e9846945c7 GUACAMOLE-249: Test endianness of platform without violating strict aliasing rules.
Dereferencing a uint8_t array as uint32_t causes a build failure with
some compilers as it breaks strict aliasing rules.
2020-01-12 14:34:44 -08:00
Michael Jumper
4b1243fbf8 GUACAMOLE-249: Ensure CLIPRDR message handlers are accepted by compiler regardless of whether const is required.
Without a typecast, errors like the following are generated by the
compiler:

    channels/cliprdr.c: In function 'guac_rdp_cliprdr_channel_connected':
    channels/cliprdr.c:477:27: error: assignment from incompatible pointer type [-Werror]
         cliprdr->MonitorReady = guac_rdp_cliprdr_monitor_ready;
                               ^
    channels/cliprdr.c:478:31: error: assignment from incompatible pointer type [-Werror]
         cliprdr->ServerFormatList = guac_rdp_cliprdr_format_list;
                                   ^
    channels/cliprdr.c:479:38: error: assignment from incompatible pointer type [-Werror]
         cliprdr->ServerFormatDataRequest = guac_rdp_cliprdr_format_data_request;
                                          ^
    channels/cliprdr.c:480:39: error: assignment from incompatible pointer type [-Werror]
         cliprdr->ServerFormatDataResponse = guac_rdp_cliprdr_format_data_response;
                                           ^
    cc1: all warnings being treated as errors

This is because FreeRDP commit 65812bd added const to the pointer
argument of each of these handlers, wheras older versions of FreeRDP
lack const here. Our implementations of these functions declare const
and thus do not match the older prototype, though they are compatible
with it.
2020-01-12 14:06:34 -08:00
Michael Jumper
5e9c7cdb42 GUACAMOLE-249: Correct typo: "of common RDPDR header" should be "of the common RDPDR header". 2020-01-11 20:24:12 -08:00
Michael Jumper
01c731e241 GUACAMOLE-249: Clean up documentation for arbitrary pipe SVC. No need to say "automatically" everywhere. 2020-01-11 20:22:23 -08:00
Michael Jumper
92d97a3244 GUACAMOLE-249: Correct typo: "indicating" should be "indicates". 2020-01-11 20:21:00 -08:00
Michael Jumper
e9670df145 GUACAMOLE-249: Correct typo: "updating" should be "update". 2020-01-11 20:19:51 -08:00
Michael Jumper
a3d9a685e8 GUACAMOLE-249: Handle failure to send either response required for monitor ready. 2020-01-11 20:18:27 -08:00
Michael Jumper
f805a80bc1 GUACAMOLE-249: Switch return type of guac_rdp_cache_bitmap() back to void - it doesn't fail, and isn't dictated by the FreeRDP API. 2020-01-11 20:14:35 -08:00
Michael Jumper
62ee36142d GUACAMOLE-249: Refactor guac_freerdp_channels_load_plugin() to log a warning if plugin limits are reached. 2020-01-09 14:12:08 -08:00
Michael Jumper
b3a713bf7a GUACAMOLE-249: Clean up basename logic of file downloads. Add unit test. 2020-01-09 13:36:37 -08:00
Michael Jumper
c4f6c5161c GUACAMOLE-249: Remove accidentally-inserted "0" from end of comment. 2020-01-09 13:11:45 -08:00
Michael Jumper
feb376ea1e GUACAMOLE-249: Fix misspelled "instruction" and "have" in comments. 2020-01-09 13:10:05 -08:00
Michael Jumper
2139d40e97 GUACAMOLE-249: Remove accidental double spaces from RDP comments. 2020-01-09 13:00:56 -08:00
Michael Jumper
55959b5456 GUACAMOLE-249: Until parameter prompting is available, do not auto-negotiate for NLA if username and password have not been provided. 2020-01-06 13:47:19 -08:00
Michael Jumper
666c4fb299 GUACAMOLE-249: Do not include "extended mode" NLA in security negotiation as negotiation fails (see FreeRDP defaults). 2020-01-06 13:39:59 -08:00
Michael Jumper
67c5bdfdfe GUACAMOLE-249: Do not attempt to free SVC-specific data if it hasn't actually been allocated. 2020-01-06 13:35:35 -08:00
Michael Jumper
dc8c60f30f GUACAMOLE-249: freerdp_channels_data() is already the default value of ReceiveChannelData. 2020-01-06 13:22:24 -08:00
Michael Jumper
80988cd6f4 GUACAMOLE-249: Provide SetNull and SetDefault implementations for rdpPointer. 2020-01-06 13:09:51 -08:00
Michael Jumper
1f24c47e29 GUACAMOLE-249: Remove empty struct definitions added by Include What You Use. 2020-01-06 11:40:08 -08:00
Michael Jumper
0677a9ae4d GUACAMOLE-249: Common surface should still pay attention to dirty flag, regardless of the new special case for unrealized surfaces. 2020-01-06 11:18:10 -08:00
Michael Jumper
a54a12362c GUACAMOLE-249: Use ReadColor() / WriteColor() around FreeRDPConvertColor().
The latter expects color input to be in an intermediate representation
resulting from using ReadColor(), and produces color output which cannot
be used until converted back with WriteColor().
2020-01-06 11:04:44 -08:00
Michael Jumper
e325dbc672 GUACAMOLE-249: Add/remove headers as necessary based on run through Include What You Use (IWYU) tool. 2020-01-04 13:07:28 -08:00
Michael Jumper
9855d875c7 GUACAMOLE-249: Remove handlers for PatBlt and OpaqueRect. FreeRDP will not invoke these if the corresponding OrderSupport element is FALSE, thus they will never be called. 2020-01-04 11:53:11 -08:00
Michael Jumper
2bbc4bfbff GUACAMOLE-249: Move keyboard-related source back to root of RDP (ease merge). Not truly needed as much as the rest of the restructure. 2020-01-04 11:50:08 -08:00
Michael Jumper
f57382f885 GUACAMOLE-249: Determine FreeRDP pixel format corresponding to local Cairo surfaces based on local platform endianness. 2020-01-04 01:11:12 -08:00
Michael Jumper
555973f6b0 GUACAMOLE-249: Remove unnecessary bitmap conversion - will happen automatically when FreeRDP invokes bitmap->Decompress(). 2020-01-04 00:00:21 -08:00
Michael Jumper
902c5e1bd4 GUACAMOLE-249: Alpha component must be in highest-order byte. 2020-01-03 23:42:34 -08:00
Michael Jumper
1bc9384ea8 GUACAMOLE-249: Claim support only for RDP orders that are explicitly supported, independently of any FreeRDP defaults. 2020-01-03 17:29:16 -08:00
Michael Jumper
36f227586e GUACAMOLE-249: Defer draws to unrealized (server-side) buffers until they are actually needed client-side.
Though deferred creation of buffers is already intended, creation was
not actually being deferred in practice as the act of initializing the
buffer with a solid rect of color was causing the buffer to be realized,
even if that initialization process is the only drawing operation that
will ever occur to that buffer.
2020-01-03 16:35:37 -08:00
Michael Jumper
2d4412316f GUACAMOLE-249: Do not draw background for glyphs when "redundant" (transparent). 2020-01-01 20:33:46 -08:00
Michael Jumper
d7151e0d84 GUACAMOLE-249: Push FreeRDP settings in preconnect hander (OrderSupport is reset otherwise).
We set the values within the OrderSupport array to match which RDP
messages we have implemented within guac_rdp_push_settings(). This array
is reset to its default values prior to the preconnect handler being
invoked, thus guac_rdp_push_settings() MUST be invoked within the
preconnect handler for its settings to have the intended effect.

Without proper values within OrderSupport, the initial RDP negotiation
process will claim support for messages that we don't actually support,
resulting in graphical artifacts and unexpected behavior.
2019-12-31 16:23:39 -08:00
Michael Jumper
7ef1dcafba GUACAMOLE-249: Convert absolutely all rdpBitmaps before attempting to draw. 2019-12-31 16:17:36 -08:00
Michael Jumper
f33416949f GUACAMOLE-249: RAIL plugin for FreeRDP 2.0.0 requires that the Client Execute PDU be sent manually. 2019-12-30 17:43:39 -08:00
Michael Jumper
8dda26af54 GUACAMOLE-249: Free rdpBitmap and rdpGlyph within custom free handlers (not automatically freed like rdpPointer). 2019-12-30 16:11:13 -08:00
Michael Jumper
0926864ecb GUACAMOLE-249: Redirect FreeRDP log messages to debug level of guac_client_log(). 2019-12-29 18:44:41 -08:00
Michael Jumper
9ad3bc9a49 GUACAMOLE-249: Log RDPDR debug messages at GUAC_LOG_DEBUG level. 2019-12-29 18:12:01 -08:00
Michael Jumper
6940875e6e GUACAMOLE-249: Refactor away old stream.h and guac_rdp_stream. 2019-12-29 18:04:51 -08:00
Michael Jumper
d2083a1aed GUACAMOLE-249: Refactor RDPDR to be more documentable. Document RDPDR fully. 2019-12-29 18:04:51 -08:00
Michael Jumper
36545cc92c GUACAMOLE-249: Document absolutely all parameters and return types for RDP support. 2019-12-29 18:04:51 -08:00
Michael Jumper
a54c61e860 GUACAMOLE-249: Support for OpaqueRect MUST NOT be claimed without supporting PatBlt. OpaqueRect implies PatBlt and vice versa. 2019-12-28 19:36:43 -08:00
Michael Jumper
fbb759ab82 GUACAMOLE-249: Correct mismatched ifndef/define header include check. 2019-12-28 19:36:43 -08:00
Michael Jumper
ab05502494 GUACAMOLE-249: Correct missing/incorrect documentation for RDP callback parameters. 2019-12-28 19:36:43 -08:00
Michael Jumper
12febd5162 GUACAMOLE-249: Remove unused SEC_TO_UNIX_EPOCH constant. 2019-12-27 21:12:39 -08:00
Michael Jumper
6c239a7b98 GUACAMOLE-249: Use filesystem constants defined by FreeRDP and WinPR headers rather than defining our own. 2019-12-27 21:12:18 -08:00
Michael Jumper
598b86a4cf GUACAMOLE-249: Correct @file annotations within Doxygen comments of renamed headers. 2019-12-27 20:55:06 -08:00
Michael Jumper
69831995cb GUACAMOLE-249: Remove prototype for guac_rdp_bitmap_decompress(), which is no longer defined nor used. 2019-12-27 15:24:25 -08:00
Michael Jumper
47a1dcc82e GUACAMOLE-249: Message flags of clipboard data response must be set to CB_RESPONSE_OK for data to be accepted. 2019-12-25 02:04:13 -08:00
Michael Jumper
0c7091198f GUACAMOLE-249: Use correct start location of clipboard buffer (accidentally used pointer to end). 2019-12-25 02:03:23 -08:00
Michael Jumper
bced87cff9 GUACAMOLE-249: FreeRDP 2.0.0 requires the Clipboard Capabilities PDU to be manually sent. 2019-12-25 01:34:57 -08:00
Michael Jumper
024fc2a1f7 GUACAMOLE-249: Callbacks for "drdynvc" plugin should return CHANNEL_RC_OK, including entry point. 2019-12-23 19:26:49 -08:00
Michael Jumper
4752863b5b GUACAMOLE-249: Remove now-unnecessary status.h FreeRDP compatibility header. 2019-12-23 13:35:32 -08:00
Michael Jumper
d7bbee35b0 GUACAMOLE-249: Reorganize includes to match code standard. 2019-12-23 13:32:36 -08:00
Michael Jumper
a63dcb46b2 GUACAMOLE-249: Rename and restructure RDP source files more sensibly. 2019-12-23 13:29:37 -08:00
Michael Jumper
827951dcf6 GUACAMOLE-249: Remove RDP constant definitions which are defined within FreeRDP headers. 2019-12-22 21:24:07 -08:00
Michael Jumper
875d51c1ed GUACAMOLE-249: Dynamically wrap channel entry points (FreeRDP will refuse to associate the same entry point with multiple channels). 2019-12-22 20:34:30 -08:00
Michael Jumper
664586ea54 GUACAMOLE-249: VirtualChannelEntryEx entry point is supposed to accept a PCHANNEL_ENTRY_POINTS_EX. 2019-12-22 17:33:35 -08:00
Michael Jumper
4612e79b8d GUACAMOLE-249: Remove "guacsnd" plugin in favor of leveraging common SVC implementation. 2019-12-22 14:29:01 -08:00
Michael Jumper
3255b182ab GUACAMOLE-249: Remove "guacsvc" plugin in favor of leveraging common SVC implementation. 2019-12-22 14:07:01 -08:00
Michael Jumper
352b9c517c GUACAMOLE-249: Add common SVC plugin implementation as future simplified basis for RDPSND, RDPDR, etc. 2019-12-22 13:36:35 -08:00
Michael Jumper
7b93b3d2e9 GUACAMOLE-249: Gradually reassemble received chunks of RDPSND data. 2019-12-21 22:51:43 -08:00
Michael Jumper
a7352b1429 GUACAMOLE-249: Remove lock around usage of FreeRDP (new library appears threadsafe). 2019-12-21 20:02:17 -08:00
Michael Jumper
ee4d91ea98 GUACAMOLE-249: Migrate RDPDR support to FreeRDP 2.0.0 plugin API. 2019-12-21 19:53:44 -08:00
Michael Jumper
68710a6702 GUACAMOLE-249: Migrate loading of RDPDR support (guacdr plugin) to abstract function. 2019-12-21 19:53:44 -08:00
Michael Jumper
6f2b124472 GUACAMOLE-249: Migrate RDPSND support to FreeRDP 2.0.0 plugin API. 2019-12-21 19:41:00 -08:00
Michael Jumper
0497a33ece GUACAMOLE-249: Migrate loading of RDPSND support ("guacsnd" plugin) to abstract function. 2019-12-21 19:41:00 -08:00
Michael Jumper
f3cef7e2f0 GUACAMOLE-249: Add example for testing arbitrary SVC support. 2019-12-21 13:42:30 -08:00
Michael Jumper
233c0555c3 GUACAMOLE-249: Migrate SVC support to FreeRDP 2.0.0 plugin API. 2019-12-21 13:42:30 -08:00
Virtually Nick
c97b8f287e
GUACAMOLE-901: Merge add Belgian French keymap 2019-11-29 12:28:41 -05:00
Jukka-Pekka Virtanen
1822e59ac3 GUACAMOLE-901: Belgian French keymap
Add Belgian French keymap file and add it to build process. Keymap is
based on https://commons.wikimedia.org/wiki/File:Belgian_pc_keyboard.svg
2019-11-19 11:53:02 +02:00
Michael Jumper
fa0ad267b8 GUACAMOLE-249: Update Docker build to use FreeRDP 2.0.0. 2019-11-04 19:26:04 -08:00
Mike Jumper
6ae6ea587b
GUACAMOLE-871: Merge support for DECTECM private mode sequence (show/hide cursor). 2019-10-16 09:54:19 -07:00
Maxime Coste
199c2a0961 GUACAMOLE-871: Add support for hidden cursor (DECTECM) 2019-10-15 20:24:51 +11:00
Michael Jumper
77a32398e5 GUACAMOLE-249: Migrate to plugin naming style used by FreeRDP 2.0.0. 2019-10-14 14:13:19 -07:00
Michael Jumper
6dc8b57ca4 GUACAMOLE-249: Update RAIL (RemoteApp) support to FreeRDP 2.0.0 API. 2019-10-14 11:15:43 -07:00
Michael Jumper
07f6e6afc2 GUACAMOLE-249: Remove guac_rdp_dvc_list, relying instead on the DVC channel collection within rdpSettings. 2019-10-13 15:30:21 -07:00
Michael Jumper
eab07b4a61 GUACAMOLE-249: Add trace-level logging of received and sent CLIPRDR PDUs. 2019-10-13 14:28:06 -07:00
Michael Jumper
de493ba959 GUACAMOLE-249: Send Format List Response PDU after successfully processing a Format List PDU. 2019-10-13 14:28:06 -07:00
Michael Jumper
9dd1555c81 GUACAMOLE-249: Do not include CB_RESPONSE_OK flag in Format List PDU.
The CLIPRDR specification requires that the msgFlags field for the
Format List PDU be set to 0x0000. The function within FreeRDP overrides
this value to 0x0000, but it is still incorrect to attempt to set it.
2019-10-13 14:28:06 -07:00
Michael Jumper
8c7984d201 GUACAMOLE-249: Free GDI implementation. Do not allocate cache (unnecessary). 2019-10-13 14:28:06 -07:00
Michael Jumper
b64b8f375a GUACAMOLE-249: Restore support for CLIPRDR channel. 2019-10-13 14:28:06 -07:00
Michael Jumper
831606a4e9 GUACAMOLE-249: Use pkg-config to determine location of FreeRDP headers. 2019-10-11 17:56:21 -07:00
Michael Jumper
cc7cd78e5b GUACAMOLE-249: Centralize handling of connected channels. 2019-10-08 11:44:26 -07:00
Michael Jumper
16be3af03c GUACAMOLE-249: Load FreeRDP plugins regardless of entry point interface.
Most plugins built into FreeRDP implement the PVIRTUALCHANNELENTRYEX
entry point, but the FreeRDP standard function for loading plugins only
supports PVIRTUALCHANNELENTRY. It appears that only the commandline
argument parser included with FreeRDP was updated to leverage the new
entry points.
2019-10-06 14:44:26 -07:00
Michael Jumper
b89ed7ff15 GUACAMOLE-249: Migrate wait mechanism to event handle interface. 2019-10-06 14:32:12 -07:00
Michael Jumper
17045d5d3a GUACAMOLE-249: Use reversed byte order for colors locally (verification needed). 2019-09-29 16:08:27 -07:00
Michael Jumper
7904d9c002 GUACAMOLE-249: Initialize FreeRDP's GDI implementation (default GDI handlers will otherwise fail). 2019-09-29 15:44:34 -07:00
Michael Jumper
7a7ffc2c19 GUACAMOLE-249: Add missing pixel format parameter to pointer image copy. 2019-09-29 15:44:34 -07:00
Michael Jumper
65fe6c9735 GUACAMOLE-249: Correct incorrect syntax introduced by initial partial migration (commit a5b62aa82). 2019-09-29 15:44:34 -07:00
Michael Jumper
c311d8bde9 GUACAMOLE-249: Rely on default bitmap/GDI/pointer handlers for all but those that must be overridden. 2019-09-29 15:44:34 -07:00
Michael Jumper
1e692094be GUACAMOLE-249: Correct remaining void returns from BOOL handlers. 2019-09-29 15:44:34 -07:00
Michael Jumper
7332e633dc GUACAMOLE-249: Add "nla-ext" option for extended NLA mode. 2019-09-29 15:44:34 -07:00
Michael Jumper
2ed0d042a3 GUACAMOLE-249: Default to negotiated security mode, not old "RDP" encryption. 2019-09-29 14:34:05 -07:00
Michael Jumper
a76e307176 GUACAMOLE-249: RDP "DisableEncryption" settings flag has been inverted and renamed to "UseRdpSecurityLayer". 2019-09-29 14:25:47 -07:00
Michael Jumper
6886665f65 GUACAMOLE-249: Comment out usage of old event interface. 2019-09-29 14:15:41 -07:00
Michael Jumper
703ce5c223 GUACAMOLE-249: Remove usage of old FreeRDP channels interface. 2019-09-29 14:15:13 -07:00
Michael Jumper
ad7ab67571 GUACAMOLE-249: The freerdp/gdi/gdi.h header is required to access contents of rdpGdi struct. 2019-09-22 14:58:23 -07:00
Michael Jumper
9fa9adbd58 GUACAMOLE-249: Migrate to libwinpr "CF_*" constants for clipboard formats.
The "CB_FORMAT_*" constants which used to be defined by FreeRDP no
longer exist.
2019-09-22 14:58:23 -07:00
Michael Jumper
3b560044bc GUACAMOLE-249: Correct prototype of certificate verification callback. If accepting the certificate, request that FreeRDP not store it. 2019-09-22 14:49:30 -07:00
Michael Jumper
82664b4e6b GUACAMOLE-249: Correct prototypes of GDI handlers. 2019-09-22 14:49:30 -07:00
Michael Jumper
fbfbaff540 GUACAMOLE-249: Correct prototypes of pointer handlers. 2019-09-22 14:49:30 -07:00
Michael Jumper
e4a68d776f GUACAMOLE-249: Correct prototypes of glyph handlers. 2019-09-22 14:49:30 -07:00
Michael Jumper
9b08a716d6 GUACAMOLE-249: Comment out remaining usage of SVC. 2019-09-22 14:49:03 -07:00
Michael Jumper
554251cc72 GUACAMOLE-249: Remove usage of CLRCONV. 2019-09-22 14:49:00 -07:00
Michael Jumper
17d31d94b7 GUACAMOLE-249: Remove all legacy FreeRDP compatibility. 2019-09-22 14:48:56 -07:00
Michael Jumper
a5b62aa82e GUACAMOLE-249: Migrate to newer API (partial). 2019-09-22 14:48:26 -07:00
Mike Jumper
b181026e58
GUACAMOLE-861: Merge correction to RDPDR filesystem timestamp conversion. 2019-08-22 10:25:55 -07:00
unknown
4cc9c2d3e1 GUACAMOLE-861: Fixes WINDOWS_TIME calculation
This fixes the UNIX time to FILETIME conversion in WINDOWS_TIME macro,
according to MSDN (addition instead of subtraction).
2019-08-21 23:05:45 +03:00
Virtually Nick
f34be230aa
GUACAMOLE-859: Merge correct Caps Lock keysym sent via RDP 2019-08-13 21:11:46 -04:00
Weston Thayer
a189c9ab8a GUACAMOLE-859: Remove +ext from Caps Lock keymapping.
When connected with a Guacamole RDP session, the keysym for Caps Lock (0xffe5) is sent over RDP as scancode 0xe03a. Windows does not understand this scancode, thus does not generate the correct VK (Virtual Key) events. Removing +ext from the keymap sends the scancode 0x003a, which is correctly recognized by Windows as Caps Lock. This enables Windows applications to listen for key down and key up events on the Caps Lock key while connected via a Guacamole RDP session.

Note: this issue likely went un-noticed for a long time because it only impacts the key up and down events for the Caps Lock key, not Caps Lock's effect on sending uppercase [A-Z] characters.
2019-08-13 21:00:26 -04:00
Mike Jumper
51463209a8
GUACAMOLE-514: Merge support for VNC authentication involving usernames. 2019-08-12 18:02:24 -07:00
Nick Couchman
7ac840090e GUACAMOLE-514: Slight correction to debug message. 2019-08-12 19:45:45 -04:00
Nick Couchman
61d12f1668 GUACAMOLE-514: VNC client should abort on credential error. 2019-08-09 13:08:36 -04:00
Nick Couchman
f21621e677 GUACAMOLE-514: Remove x509 support. 2019-08-09 13:05:40 -04:00
Nick Couchman
88425160ae GUACAMOLE-514: Write x509 authentication factors to temp files. 2019-08-09 13:05:40 -04:00
Nick Couchman
b9001f4ec7 GUACAMOLE-514: Add missing parameter tag. 2019-08-09 13:05:40 -04:00
Nick Couchman
4329739d3e GUACAMOLE-514: Remove CRL check flag. 2019-08-09 13:05:40 -04:00
Nick Couchman
90d55956d0 GUACAMOLE-514: use correct client in log call. 2019-08-09 13:05:40 -04:00
Nick Couchman
51ae8a41a1 GUACAMOLE-514: Add guacd support for extended VNC credentials. 2019-08-09 13:05:40 -04:00
Nick Couchman
f962eab27a Merge 1.1.0 changes back to master. 2019-08-09 13:01:54 -04:00
Virtually Nick
381ff1a421
GUACAMOLE-630: Merge expose terminal color/font changes. 2019-08-09 13:01:05 -04:00
Michael Jumper
43269920db GUACAMOLE-630: Clarify usage of argv-related guac_user_callback implementations. 2019-08-07 20:16:01 -07:00
Michael Jumper
f56df8b8be GUACAMOLE-630: Automatically send current color scheme and font to users joining SSH, telnet, and Kubernetes connections. 2019-08-04 12:52:00 -07:00
Michael Jumper
ccfcfb116d GUACAMOLE-630: Persist details of color scheme and font changes. 2019-08-04 12:44:43 -07:00
Michael Jumper
4dabea37af GUACAMOLE-630: Allow guac_terminal_parse_color_scheme() to dictate color scheme format. 2019-08-04 11:55:45 -07:00
Michael Jumper
0516d599cf GUACAMOLE-630: Disallow NULL color schemes.
A color scheme string should always be provided, even if blank.
Disallowing NULL allows assumptions to be made which simplifies the
logic surrounding persisting provided configuration values.
2019-08-04 11:45:41 -07:00
Michael Jumper
b5191caddc GUACAMOLE-630: Accept pre-defined color schemes in all cases, not just during terminal creation. 2019-08-04 11:37:42 -07:00
Michael Jumper
0c7898c55a GUACAMOLE-630: Expose terminal font/color configuration changes to connected clients. 2019-08-03 19:53:07 -07:00
Nick Couchman
289ceac222 Merge 1.1.0 changes back to master. 2019-08-03 17:16:45 -04:00
Virtually Nick
e25f83d629
GUACAMOLE-623: Merge add support for adjusting terminal for Kubernetes via "argv". 2019-08-03 17:14:30 -04:00
Michael Jumper
e6835795f0 GUACAMOLE-623: Add support for setting terminal font for Kubernetes via "argv". 2019-08-03 14:04:30 -07:00
Nick Couchman
b6005cc8a0 Merge 1.1.0 changes back to master. 2019-07-31 12:39:32 -04:00
Virtually Nick
95039ea3b3
GUACAMOLE-629: Merge allow "argv" instructions to be sent from server to client. 2019-07-31 12:37:51 -04:00
Michael Jumper
ca073db5b6 GUACAMOLE-629: Add convenience functions for immediately sending the current value of a connection parameter. 2019-07-30 14:05:50 -07:00
Michael Jumper
c3a295e9b7 GUACAMOLE-629: Add convenience function for automatically splitting data across a series of blob instructions. 2019-07-30 14:05:50 -07:00
Michael Jumper
c47aa0cea1 GUACAMOLE-629: Define constant for maximum blob size. 2019-07-30 13:34:24 -07:00
Michael Jumper
c1b8250300 GUACAMOLE-629: Move constants for Guacamole protocol to dedicated "*-constants.h" header. 2019-07-30 13:33:18 -07:00
Michael Jumper
a763d47bc7 GUACAMOLE-629: Add support for sending "argv" instructions from server to client. 2019-07-30 13:06:46 -07:00
Michael Jumper
a3101e9744 Merge 1.1.0 changes back to master. 2019-07-26 14:38:25 -07:00
Mike Jumper
c26672e281
GUACAMOLE-422: Merge explicit handling of "nop" instruction. 2019-07-26 14:37:54 -07:00
Nick Couchman
26bb10a486 GUACAMOLE-422: Add empty handler and trace logging for nop instruction. 2019-07-23 14:29:50 -04:00
Mike Jumper
41b0c21322
GUACAMOLE-847: Merge fix for leaked RDPSND packet memory. 2019-07-20 12:15:18 -07:00
Frank Riley
87a5479ff8 GUACAMOLE-847: Fix severe memory leak when using audio with RDP 2019-07-20 06:14:36 -07:00
Mike Jumper
b4ef38c064
GUACAMOLE-837: Merge RDP support for Hungarian keyboards. 2019-07-11 21:20:08 -07:00
Nick Couchman
ce7bea66cf Merge 1.1.0 changes back to master. 2019-07-11 09:10:26 -04:00
Virtually Nick
1a9d1e8b71
GUACAMOLE-547: Merge copy password from settings. 2019-07-11 09:08:12 -04:00
fgiuba
55add063c5 GUACAMOLE-547: Add missing space between brackets. 2019-07-11 13:37:03 +02:00
fgiuba
9228d2637a GUACAMOLE-547: Do not ignore password from settings. 2019-07-11 13:37:03 +02:00
P-Zs
8f1826d3e4 GUACAMOLE-837: Update Makefile.am to reference the new Hungarian keymap file 2019-07-10 00:55:31 +02:00
P-Zs
badee3274b GUACAMOLE-837: Add Hungarian RDP keymap file to code base 2019-07-10 00:55:31 +02:00
Michael Jumper
e149fd4f70 Merge 1.1.0 changes back to master. 2019-06-20 00:47:46 -07:00
Mike Jumper
7e9b97007e
GUACAMOLE-547: Merge support for SSH NONE authentication method. 2019-06-20 00:46:55 -07:00
Nick Couchman
1baa91f852 GUACAMOLE-547: Minor changes to function documentation. 2019-06-19 12:38:05 -04:00
Nick Couchman
22874e2388 GUACAMOLE-547: Document return value of credential handler. 2019-06-18 17:59:33 -04:00
Nick Couchman
3511991e2f GUACAMOLE-547: Fixes for style and documentation. 2019-06-18 07:52:05 -04:00
Nick Couchman
9a51d513f2 GUACAMOLE-547: Provide documentation for the new callback function. 2019-06-18 07:37:02 -04:00
Nick Couchman
3d15454097 GUACAMOLE-547: Use a call-back function for getting the password. 2019-06-18 07:37:02 -04:00
Nick Couchman
4641da06ac GUACAMOLE-547: Relocate NULL check and log when NONE succeeds. 2019-06-18 07:37:02 -04:00
Nick Couchman
b7dca0ed16 GUACAMOLE-547: Add support for SSH NONE authentication method. 2019-06-18 07:37:02 -04:00
Michael Jumper
a1c382c8ce Merge 1.1.0 changes back to master. 2019-04-30 17:26:21 -07:00
Mike Jumper
8b53be49f3
GUACAMOLE-422: Merge changes to Guacamole protocol handshake adding flexibility and timezone support. 2019-04-30 17:25:26 -07:00
Nick Couchman
bf741a46d6 GUACAMOLE-422: Minor style and debug changes. 2019-04-27 21:37:26 -04:00
Virtually Nick
652ca302cb
GUACAMOLE-772: Merge reduce Docker image size for guacd 2019-04-25 15:41:45 -04:00
Nick Couchman
93a240b8ad GUACAMOLE-422: Add debugging and check argument count. 2019-04-24 22:21:18 -04:00
Mike Jumper
5e8f5eaa50
GUACAMOLE-296: Merge changes linking libwinpr / libwinpr-utils as needed. 2019-04-24 15:35:16 -07:00
Mike Jumper
fc68113d75
GUACAMOLE-414: Merge support for libvncclient's TLS threadsafety callbacks. 2019-04-24 15:29:32 -07:00
Nick Couchman
4b43de963e GUACAMOLE-422: Break handshake out into separate function; NULL out timezone when not received. 2019-04-22 11:49:46 -04:00
Nick Couchman
588e0f194a GUACAMOLE-422: Fix return documentation on opcode handler function. 2019-04-19 15:50:29 -04:00
Nick Couchman
ab12b2aa8e GUACAMOLE-422: More substantial comment for protocol version; NULL out timezone at beginning of handshake. 2019-04-19 15:48:14 -04:00
Nick Couchman
98cb7ccf67 GUACAMOLE-422: Fix comment and style. 2019-04-17 15:12:46 -04:00
Nick Couchman
75c0deac1f GUACAMOLE-422: Update comment style for consistency. 2019-04-17 15:03:27 -04:00
Nick Couchman
54f88531d4 GUACAMOLE-422: Try to avoid memory leaks with mimetypes. 2019-04-17 15:00:46 -04:00
Nick Couchman
340aef5362 GUACAMOLE-422: Update to remove first argument 2019-04-17 14:41:35 -04:00
Nick Couchman
379fce2d77 GUACAMOLE-422: Rename new opcode handler function. 2019-04-11 17:21:36 -04:00
Nick Couchman
c750b18f60 GUACAMOLE-422: Handle sending version internally. 2019-04-11 17:18:27 -04:00
Nick Couchman
2f57564f5d GUACAMOLE-422: Remove duplicate code and migrate handshake to user handlers. 2019-04-11 17:18:27 -04:00
Nick Couchman
2b68925ec9 GUACAMOLE-422: Add protocol version as initial item passed back in args. 2019-04-11 17:18:27 -04:00
Nick Couchman
0ee47e0186 GUACAMOLE-422: Change handshake to ignore order of opcodes. 2019-04-11 17:18:27 -04:00
Nick Couchman
5480b288e8 GUACAMOLE-422: Remove NULL check for parser argv. 2019-04-11 17:18:27 -04:00
Nick Couchman
5caa8a25f7 GUACAMOLE-422: SSH parameter should use handshake for default. 2019-04-11 17:18:27 -04:00
Nick Couchman
6fae0b4b23 GUACAMOLE-422: Use timezone from handshake when parameter does not exist. 2019-04-11 17:18:27 -04:00
Nick Couchman
f70aa4939f GUACAMOLE-422: Add client timezone to handshake. 2019-04-11 17:16:43 -04:00
Nick Couchman
cd3432e594 Merge 1.1.0 changes back to master. 2019-04-10 06:18:53 -04:00
Virtually Nick
b90e566e1b
GUACAMOLE-637: Merge add missing libguac include path to tests. 2019-04-10 06:14:28 -04:00
Michael Jumper
0c25782036 GUACAMOLE-637: Add missing libguac include path to RDP and common-ssh tests. 2019-04-09 23:36:03 -07:00
James Muehlner
6dad6cd919 Merge 1.1.0 changes back to master. 2019-04-09 21:52:28 -07:00
James Muehlner
dd4c3968d1 GUACAMOLE-637: Merge migration to new libguac string functions. 2019-04-09 21:49:16 -07:00
Mike Jumper
dc71987fca
GUACAMOLE-764: Merge correction to size of RDP file read/write offsets (all should be 64-bit). 2019-04-09 11:25:15 -07:00
m-khan-glyptodon
871f31353b GUACAMOLE-764: Updated variable type for offsets to uint64_t to increase rdp write to a 64-bit addressable space 2019-04-08 15:27:58 -07:00
m-khan-glyptodon
2db7ffbaab GUACAMOLE-764: Updated variable type for offsets to uint64_t to increase rdp read to a 64-bit addressable space 2019-04-08 15:00:59 -07:00
Mathias
61070cb367
GUACAMOLE-772: Switched runtime image to debian slim 2019-04-08 12:28:46 +02:00
Michael Jumper
f8ec709e33 GUACAMOLE-637: Correct naming of SFTP unit tests. 2019-04-07 16:51:53 -07:00
Michael Jumper
cda7bca126 GUACAMOLE-637: Add RDP filesystem and SFTP unit tests for path depth. 2019-04-07 16:51:33 -07:00
Michael Jumper
6e2be38ae2 GUACAMOLE-637: Add path depth limits to generated paths in unit tests. 2019-04-07 16:36:16 -07:00
Michael Jumper
986f7f5d64 GUACAMOLE-637: Use same logic for RDP filesystem path normalization as SFTP. 2019-04-07 16:30:27 -07:00
Michael Jumper
1591980579 GUACAMOLE-637: Simplify SFTP path normalization logic. Correct behavior to match documentation. 2019-04-07 16:14:00 -07:00
Michael Jumper
591e494dfd GUACAMOLE-637: Add unit tests for RDP filesystem path normalization. 2019-04-07 13:56:52 -07:00
Michael Jumper
f19754cfa6 GUACAMOLE-637: Add unit tests for SFTP path normalization. 2019-04-07 13:50:53 -07:00
Michael Jumper
24ab5ca85b GUACAMOLE-637: Remove unnecessary .gitignore files. Universally exclude test output. Remove duplicated exclusions. 2019-04-07 11:50:43 -07:00
Nick Couchman
1b8e31b70c GUACAMOLE-296: Add checks for Stream functions in winpr libraries. 2019-03-24 16:12:20 -04:00
Michael Jumper
ffe0b57faa Merge 1.1.0 changes back to master. 2019-03-24 13:00:45 -07:00
Nick Couchman
a4521208ba GUACAMOLE-414: Remove unnecessary rfbconfig include. 2019-03-24 15:09:58 -04:00
Mike Jumper
3989c40da6
GUACAMOLE-694: Merge addition of "ca-certificates" dependency for Docker image. 2019-03-24 12:03:19 -07:00
Nick Couchman
a6f2ab9d93 GUACAMOLE-414: Use correct formatting for string from strerror. 2019-03-10 17:41:45 -04:00
Nick Couchman
bfc6c1e6e0 GUACAMOLE-414: Convert errors to strings from ptread_mutex_lock and unlock. 2019-03-10 17:40:34 -04:00
Nick Couchman
36817f3774 GUACAMOLE-414: Clean up style and move mutex init to client allocation. 2019-03-10 17:33:14 -04:00
Nick Couchman
df4c93b3e8 GUACAMOLE-414: Use configure checks for finding TLS locking support. 2019-03-10 15:22:49 -04:00
Nick Couchman
c90c057e12 GUACAMOLE-414: Add version checks for TLS locking. 2019-03-09 21:46:02 -05:00
Nick Couchman
e9a10d66b7 GUACAMOLE-414: Add pthread lock and callbacks for TLS write locking. 2019-03-09 21:27:30 -05:00
Virtually Nick
5e2ddb890a
GUACAMOLE-381: Merge add parameters for disabling clipboard copy/paste. 2019-02-24 22:41:47 -05:00
Nick Couchman
1300b64bb9 GUACAMOLE-694: Add ca-certificates packages as runtime dependency. 2019-02-22 04:59:09 -05:00
Michael Jumper
228cea4af1 GUACAMOLE-381: Disable outbound transfers from terminal protocols if "disable-copy" is set. 2019-02-19 12:11:24 -08:00
Michael Jumper
254615509a GUACAMOLE-381: Disable or ignore outbound clipboard transfers for VNC/RDP if "disable-copy" is set. 2019-02-19 11:45:30 -08:00
Michael Jumper
993d5c5707 GUACAMOLE-381: Disable inbound clipboard transfer if "disable-paste" is set. 2019-02-19 11:40:32 -08:00
Michael Jumper
7d2b7126db GUACAMOLE-381: Add copy/paste disable flags for all supported protocols. 2019-02-19 11:34:18 -08:00
Nick Couchman
802e5b5547 Merge 1.1.0 changes back to master. 2019-02-09 14:55:07 -05:00
Virtually Nick
67a2b75fe6
GUACAMOLE-729: Merge bump version to 1.1.0 2019-02-09 14:49:36 -05:00
Michael Jumper
cb227cc3a1 GUACAMOLE-729: Bump version number of guacctl. 2019-02-09 11:38:16 -08:00
Michael Jumper
a0d030a7ae GUACAMOLE-729: Update libtool version info for libguac (interfaces added and changed). 2019-02-09 11:20:06 -08:00
Michael Jumper
193f721c7b GUACAMOLE-729: Bump version number to 1.1.0. 2019-02-09 11:18:26 -08:00
Virtually Nick
7065ff5586
GUACAMOLE-712: Merge add Danish to RDP 2019-02-06 09:01:33 -05:00
netromnetrom
aeb9b99a6c
Merge pull request #2 from netromnetrom/patch-1
Patch 1
2019-02-06 12:01:19 +01:00
netromnetrom
877eca691c
Merge pull request #1 from netromnetrom/patch-2
Patch 2
2019-02-06 11:58:08 +01:00
Mike Jumper
63ede7e406
GUACAMOLE-693: Merge update to NOTICE copyright year (2018 -> 2019). 2019-01-24 16:44:21 -08:00
Michael Jumper
c6feef6c86 GUACAMOLE-637: Clarify purpose of initial empty path component. Fix normalization logic to ensure that empty component is always present. 2019-01-23 20:28:09 -08:00
Michael Jumper
350d8e5995 GUACAMOLE-637: Document failsafe behavior of guac_strlcat() in the event the destination buffer is not terminated as required. 2019-01-23 19:02:19 -08:00
Michael Jumper
ba8fd17394 GUACAMOLE-637: "concatentation" ... not "contatenation". 2019-01-23 18:53:06 -08:00
Michael Jumper
9fb713d804 GUACAMOLE-637: Correct grammar of documentation for guac_strl*() unit tests. 2019-01-23 18:51:53 -08:00
Michael Jumper
b7761e9a2e GUACAMOLE-637: The $^ variable is non-portable and specific to GNU Make. As otherwise POSIX-compliant platforms may not provide this variable, we shouldn't use it here. 2019-01-23 18:44:45 -08:00
Michael Jumper
789e3883d6 GUACAMOLE-637: Not all systems place Perl in /usr/bin. The line #!/usr/bin/env perl should be used for portability. 2019-01-23 18:44:45 -08:00
Michael Jumper
7da837b42a GUACAMOLE-637: The __BSD_VISIBLE macro is required for strlcpy() and strlcat() to be available in libc's string.h. 2019-01-23 18:44:45 -08:00
Michael Jumper
e6c5da315e GUACAMOLE-637: Add unit tests for guac_strljoin(). 2019-01-23 18:44:45 -08:00
Michael Jumper
258946cd88 GUACAMOLE-637: Correctly handle string lengths as size_t (unsigned). 2019-01-23 18:44:45 -08:00
Michael Jumper
068f33aaef GUACAMOLE-637: Add unit tests for guac_strlcat(). 2019-01-23 18:44:45 -08:00
Michael Jumper
dec3642905 GUACAMOLE-637: Add unit tests for guac_strlcpy(). 2019-01-23 18:44:45 -08:00
Michael Jumper
fdd3292f09 GUACAMOLE-637: Simplify path translation logic. Update to use guac_strl*(). Fix return values. 2019-01-23 18:44:45 -08:00
Michael Jumper
3549da0dd1 GUACAMOLE-637: Replace usages of strncat() with guac_strlcat(). 2019-01-23 18:44:45 -08:00
Michael Jumper
e5c1147cf6 GUACAMOLE-637: Replace usages of strncpy() with guac_strlcpy(). 2019-01-23 18:44:45 -08:00
Michael Jumper
5bf6a1479c GUACAMOLE-637: Add convenience function for joining an array of strings using a given delimiter. 2019-01-23 18:44:45 -08:00
Michael Jumper
a78f254611 GUACAMOLE-637: Add strlcat() implementation. Use libc strlcat() if available. 2019-01-23 18:44:45 -08:00
Michael Jumper
d7909a77aa GUACAMOLE-637: Add strlcpy() implementation. Use libc strlcpy() if available. 2019-01-23 18:44:45 -08:00
Michael Jumper
f6953e1317 GUACAMOLE-637: Use proper namespaced path for Guacamole headers within libguac source. 2019-01-23 18:44:45 -08:00
Nick Couchman
10e06c15c9 GUACAMOLE-693: Update copyright year to 2019. 2019-01-23 17:15:13 -05:00
netromnetrom
7b7c8a1b02
Update Makefile.am 2019-01-22 16:24:56 +01:00
netromnetrom
a06edb9deb
Update and rename dk_dk_qwerty.keymap to da_dk_qwerty.keymap 2019-01-22 14:36:05 +01:00
Nick Couchman
768b2ba0f5 GUACAMOLE-661: Merge mark "nest" instruction and socket as deprecated. 2019-01-07 12:45:18 -05:00
Michael Jumper
d73b86b4b7 GUACAMOLE-661: Mark "nest" instruction and socket as deprecated. 2019-01-07 09:37:08 -08:00
Nick Couchman
bb9560716d GUACAMOLE-662: Merge correct behavior of nested socket. 2019-01-07 06:34:28 -05:00
Michael Jumper
cc4671d7a1 GUACAMOLE-662: Correct handling of buffering within nested socket.
The nested socket implementation seems to have never been properly
updated since guac_socket was changed to rely on implementation-specific
buffering. This meant that absolutely every write resulted in a nest
instruction being sent to the parent socket.

Data should instead be built up within the internal buffer, with each
flush writing as much of the internal buffer as possible within a nest
instruction, leaving any partial UTF-8 characters at the end of the
buffer for later completion with future writes.
2019-01-06 17:09:35 -08:00
Michael Jumper
47ad6f4b59 GUACAMOLE-662: Properly initialize nested socket index (fixes GUACAMOLE-510). 2019-01-06 17:09:35 -08:00
Nick Couchman
aba7b987d3 GUACAMOLE-662: Merge fix handling of unit tests within buid. 2019-01-06 19:42:12 -05:00
Michael Jumper
b6477ea7ae GUACAMOLE-354: Merge RDP keymap for Swiss-German keyboards. 2018-12-04 10:58:34 -08:00
Andrin
01142e6dd8 GUACAMOLE-354: Fixed keyboard name. 2018-12-04 08:30:36 +01:00
Nick Couchman
bbb6afaf46 GUACAMOLE-638: Merge avcodec_register_all() should be used only if not deprecated. 2018-11-21 07:24:20 -05:00
Andrin
9486ec7cc4 GUACAMOLE-354: Add Swiss-German keymap for RDP 2018-11-20 14:10:36 +01:00
Michael Jumper
476b431041 GUACAMOLE-662: Migrate tests to test runners generated by new convenience script. Remove unnecessary test runners. 2018-11-17 18:06:40 -08:00
Michael Jumper
877bf59cb6 GUACAMOLE-662: Force line-buffered output. 2018-11-17 12:41:48 -08:00
Michael Jumper
ca4009c982 GUACAMOLE-662: Log test output in TAP format. 2018-11-17 12:41:48 -08:00
Michael Jumper
d7118fda70 GUACAMOLE-662: Add utility script for automatically generating CUnit test runners. 2018-11-16 22:23:55 -08:00
Michael Jumper
2827af33d6 GUACAMOLE-662: Correct fork logic (main test process should be PARENT, not child). 2018-11-16 12:53:42 -08:00
Michael Jumper
867e63b524 GUACAMOLE-638: avcodec_register_all() should be used only if not deprecated. 2018-11-12 16:36:15 -08:00
Michael Jumper
0d435e2435 GUACAMOLE-422: Merge support for specifying the timezone of RDP and SSH sessions. 2018-11-12 09:12:19 -08:00
Nick Couchman
7b1ba3f269 GUACAMOLE-422: Fix spelling mistake. 2018-11-12 12:09:51 -05:00
Nick Couchman
d1b3695282 GUACAMOLE-422: Fix type in strerror() 2018-11-12 11:56:57 -05:00
Nick Couchman
f61539c4e7 GUACAMOLE-422: Quick fixes for style and logging. 2018-11-12 11:55:07 -05:00
Nick Couchman
9a944637be GUACAMOLE-422: Fix function declaration for pushing settings. 2018-11-11 17:25:12 -05:00
Nick Couchman
4bd19160de GUACAMOLE-422: Add logging for RDP timzeone. 2018-11-11 17:22:03 -05:00
Nick Couchman
b3be9eb869 GUACAMOLE-422: Revert addition of logging for setting TZ variable. 2018-11-11 16:07:20 -05:00
Nick Couchman
0b71559017 GUACAMOLE-422: Add errno header. 2018-11-11 15:48:02 -05:00
Nick Couchman
e2b4de9d95 GAUCAMOLE-422: Add warning messages when TZ cannot be set. 2018-11-11 15:45:24 -05:00
Nick Couchman
d7ed452d69 GUACAMOLE-422: Update comments on timezone settings. 2018-11-11 15:30:17 -05:00
Nick Couchman
5536b836ad GUACAMOLE-422: Add support for passing through TZ in SSH. 2018-11-11 14:11:40 -05:00
Nick Couchman
ffdc98d024 GUACAMOLE-422: Support timezone redirection in RDP via TZ variable. 2018-11-11 14:09:23 -05:00
Nick Couchman
381c5d1a76 GUACAMOLE-630: Merge allow font parameters of active terminal session to be changed. 2018-11-11 14:03:58 -05:00
Michael Jumper
5683be0ea3 GUACAMOLE-630: Allow SSH/telnet font family and size to be updated. 2018-11-10 14:22:23 -08:00
Michael Jumper
9e28de70ec GUACAMOLE-630: Separate setting of font family/size from terminal display initialization. 2018-11-10 14:22:23 -08:00
Nick Couchman
d2cb7a9ce9 GUACAMOLE-630: Merge allow color scheme of active terminals to be changed. 2018-11-10 10:45:56 -05:00
Michael Jumper
0cf24219d8 GUACAMOLE-630: Define maximum "argv" stream length for SSH and telnet with symbolic constants. 2018-11-09 20:27:28 -08:00
Nick Couchman
e132c79348 GUACAMOLE-649: Merge add support for setting LANG environment variable via SSH. 2018-11-09 20:40:29 -05:00
Michael Jumper
edbdd08476 GUACAMOLE-649: Allow SSH connection to continue despite failure to set LANG environment variable. 2018-11-08 19:29:32 -08:00
Michael Jumper
454682979e GUACAMOLE-649: Add support for setting LANG environment variable via SSH. 2018-11-04 21:20:47 -08:00
Michael Jumper
f293c5e9c0 GUACAMOLE-630: Do not entirely reset terminal state when color scheme is changed. 2018-10-22 23:23:27 -07:00
Michael Jumper
dcab540839 GUACAMOLE-630: Persist semantics of default foreground/background with dedicated palette pseudo-indexes. 2018-10-22 23:23:27 -07:00
Michael Jumper
2f16eadb35 GUACAMOLE-630: Allow color scheme to be changed from webapp via argv streams. 2018-10-22 23:23:27 -07:00
Michael Jumper
6f9f2189f2 GUACAMOLE-630: Separate color scheme parsing into own files. 2018-10-22 23:23:27 -07:00
Michael Jumper
6f49194640 Merge 1.0.0 changes back to master. 2018-10-16 09:05:37 -07:00
Michael Jumper
0ffda8aaf0 GUACAMOLE-527: Merge correction to order of SFTP parameters for VNC. 2018-10-16 09:03:02 -07:00
Nick Couchman
34c088882b GUACAMOLE-527: Correct issue with order of VNC SFTP settings. 2018-10-16 09:27:45 -04:00
Nick Couchman
f8d2bd13b1 GUACAMOLE-353: Merge clarify applicability of ASF header when transcluded into generated build files. 2018-10-03 10:11:56 -04:00
Michael Jumper
d851f10a48 GUACAMOLE-353: Clarify applicability of ASF header when transcluded into generated build files. 2018-10-02 20:37:49 -07:00
Nick Couchman
356dcef9e8 GUACAMOLE-623: Merge include dependencies of Kubernetes support in Docker image build. 2018-09-27 21:25:30 -04:00
Nick Couchman
7352d66819 GUACAMOLE-623: Merge start terminal once Kubernetes connection is ready. 2018-09-27 21:23:58 -04:00
Michael Jumper
64b1572d13 GUACAMOLE-623: Include dependences of Kubernetes support in Docker image build. 2018-09-27 09:34:53 -07:00
Michael Jumper
7374b29364 GUACAMOLE-623: Start terminal once Kubernetes connection is ready (necessary since merge of GUACAMOLE-622). 2018-09-27 09:33:31 -07:00
Nick Couchman
b0be808036 GUACAMOLE-623: Merge fix build against older libwebsockets. 2018-09-27 04:36:15 -04:00
Michael Jumper
9c593bde89 GUACAMOLE-623: Kill connection if libwebsockets is destroying the underlying WebSocket.
Older versions of libwebsockets will not necessarily invoke close events
under all circumstances, and will instead sometimes summarily destroy
the WebSocket. Thankfully there is another event for that, and newer
versions of libwebsockets continue to define that event. We can hook
into both to handle disconnect.
2018-09-26 22:31:25 -07:00
Michael Jumper
44d3433ea9 GUACAMOLE-623: Explicitly bypass certificate checks if requested.
For older versions of libwebsockets, simply requesting that OpenSSL
ignore the verification result is insufficient, as libwebsockets
manually checks and confirms the verification result, producing an error
in all but specific cases.
2018-09-26 22:01:46 -07:00
Michael Jumper
7ee624844a GUACAMOLE-623: Remove unnecessary initialization of pwsi.
The pwsi member was previously used to ensure the lws structure was made
available to invocations of the event callback early in the connection
lifecycle such that the underlyin guac_client could always be retrieved.
Since the migration to guac_kubernetes_lws_current_client, this is not
necessary, and isn't supported in older versions of libwebsockets
anyway.
2018-09-26 21:52:53 -07:00
Michael Jumper
b48a1b3a5d GUACAMOLE-623: Use libwebsockets' dummy callback only if defined. 2018-09-26 21:51:07 -07:00
Michael Jumper
d8618b0682 GUACAMOLE-623: Support older libwebsockets SSL initialization. 2018-09-26 21:50:19 -07:00
Nick Couchman
af93cfb32a GUACAMOLE-623: Merge include Kubernetes plugin in dist directories. 2018-09-26 12:56:45 -04:00
Michael Jumper
acfc759527 GUACAMOLE-623: Include Kubernetes plugin in dist directories. 2018-09-26 09:40:50 -07:00
Nick Couchman
760f7a649a GUACAMOLE-629: Merge add support for updating connection parameters of in-progress connections. 2018-09-26 08:47:32 -04:00
Nick Couchman
2d6ce1a5fd GUACAMOLE-632: Merge dynamic JPEG/WebP quality scaling. 2018-09-26 08:45:32 -04:00
Nick Couchman
43db1965ef GUACAMOLE-623: Merge support for terminals of containers in Kubernetes pods. 2018-09-26 08:43:30 -04:00
Michael Jumper
61df2956b3 GUACAMOLE-623: Clean up logging (libwebsockets adds newline characters). 2018-09-25 21:30:52 -07:00
Michael Jumper
83a531bc89 GUACAMOLE-623: Add support for SSL. 2018-09-25 21:30:52 -07:00
Michael Jumper
2e50573531 GUACAMOLE-623: Move I/O-related functions into separate files. 2018-09-25 21:30:52 -07:00
Michael Jumper
5e3aec6df2 GUACAMOLE-623: Add missing documentation for URL character test. 2018-09-25 21:30:51 -07:00
Michael Jumper
371eed1f93 GUACAMOLE-623: Add missin includes. Remove unnecessary includes. 2018-09-25 21:30:51 -07:00
Michael Jumper
77a866129b GUACAMOLE-623: Add warning when Kubernetes support will not be built. Fix summary output from configure. 2018-09-25 21:30:51 -07:00
Michael Jumper
c5f67a31dc GUACAMOLE-623: Add configure test for LWS_CALLBACK_CLIENT_CLOSED (only defined in recent libwebsockets and required if present). 2018-09-25 21:30:51 -07:00
Michael Jumper
ed56093888 GUACAMOLE-623: Generate Kubernetes API endpoint dynamically. 2018-09-25 21:30:51 -07:00
Michael Jumper
34f8f8b30d GUACAMOLE-623: Redirect libwebsockets logging to guacd's debug level log. 2018-09-25 21:30:51 -07:00
Michael Jumper
fe7edce569 GUACAMOLE-623: Add support for terminal resize. Redraw Kubernetes container upon connect. 2018-09-25 21:30:51 -07:00
Michael Jumper
b7c938c239 GUACAMOLE-623: Send typed data to Kubernetes via the STDIN channel. 2018-09-25 21:30:51 -07:00
Michael Jumper
f35517b3ff GUACAMOLE-623: Add outbound message buffer. 2018-09-25 21:30:51 -07:00
Michael Jumper
cbe593503f GUACAMOLE-623: Do not return -1 from libwebsockets callback. Doing so results in automatic cleanup of part of the context, resulting in a segfault when lws_context_destroy() is invoked. 2018-09-25 21:30:51 -07:00
Michael Jumper
f72877bf0d GUACAMOLE-623: Handle data received from Kubernetes. 2018-09-25 21:30:51 -07:00
Michael Jumper
7165fa949d GUACAMOLE-623: Stub out implementation of WebSocket client for Kubernetes. 2018-09-25 21:30:51 -07:00
Michael Jumper
519c90a887 GUACAMOLE-623: Default to unencrypted Kubernetes connections. 2018-09-25 21:30:51 -07:00
Michael Jumper
5bae422b29 GUACAMOLE-623: libwebsockets requires an integer port number. 2018-09-25 21:30:51 -07:00
Michael Jumper
b8bd0e4c6a GUACAMOLE-623: Add base skeleton for Kubernetes protocol support. 2018-09-25 21:30:51 -07:00
Michael Jumper
45e8503ead GUACAMOLE-632: Dynamically scale JPEG/WebP quality depending on measured processing lag. 2018-09-25 13:28:21 -07:00
Michael Jumper
8456c050ea GUACAMOLE-629: Add support for updating connection parameters of in-progress connections. 2018-09-25 11:40:08 -07:00
Nick Couchman
54fda21366 GUACAMOLE-622: Merge withold first terminal frame until connection is verified. 2018-09-21 20:26:47 -04:00
Nick Couchman
d7cfff324e GUACAMOLE-628: Merge correct RDP scancode mapping for right control key. 2018-09-21 20:13:30 -04:00
Michael Jumper
622a849bae GUACAMOLE-628: Correct RDP scancode mapping for right control key. 2018-09-21 16:25:11 -07:00
Michael Jumper
462d494ed8 GUACAMOLE-622: Match each line against all regexes. 2018-09-21 14:29:01 -07:00
Michael Jumper
442b1d5cc2 GUACAMOLE-622: Start terminal for telnet only after login status is known (if login success/failure detection enabled). 2018-09-21 14:29:01 -07:00
netromnetrom
5f8c6470ff
Update Makefile.am
Danish keyboard layout
2018-09-11 13:44:29 +02:00
netromnetrom
948d1bcac8
Create dk_dk_qwerty.keymap
Danish keyboard layout
2018-09-11 13:40:25 +02:00
Michael Jumper
1178b475da GUACAMOLE-622: Do not allow STDIN to be redirected if the terminal is not yet started. 2018-09-02 23:04:14 -07:00
Michael Jumper
286cbf32a7 GUACAMOLE-622: Ensure connection to guacd is kept alive even if the SSH daemon is taking its time responding. Lengthy connect times due to DNS verification, PAM, etc. are not uncommon. 2018-09-02 23:04:14 -07:00
Michael Jumper
4606607309 GUACAMOLE-622: Start terminal for SSH only after SSH connection succeeds. 2018-09-02 23:04:14 -07:00
Michael Jumper
0b39b0fc5f GUACAMOLE-622: Implicitly invoke guac_terminal_start() if prompting is required. 2018-09-02 23:04:14 -07:00
Michael Jumper
61a51df1b2 GUACAMOLE-622: Require guac_terminal_start() to be invoked before the terminal will render frames or accept user input. 2018-09-02 23:04:14 -07:00
Nick Couchman
332e187813 Merge 1.0.0 changes back to master. 2018-08-24 12:17:20 -04:00
Nick Couchman
a1ba91b01d GUACAMOLE-470: Merge support named colors in color-scheme configuration. 2018-08-24 12:15:58 -04:00
Jim Chen
eb5aa14a6f GUACAMOLE-470: Support named colors in color-scheme configuration.
When parsing named colors, treat semi-colons as string terminators, so
we can properly parse named colors within the color-scheme
configuration.
2018-08-24 10:42:24 -04:00
Nick Couchman
911e60cf5c GUACAMOLE-610: Merge add support for changing scrollback buffer size. 2018-08-19 14:49:26 -04:00
Michael Jumper
994cb95893 GUACAMOLE-610: Add console code for altering scrollback size on the fly. 2018-08-18 11:26:12 -07:00
Michael Jumper
0e6d549a40 GUACAMOLE-610: Allow scrollback size to be specified for SSH and telnet. 2018-08-18 11:12:55 -07:00
Michael Jumper
6a576f0121 GUACAMOLE-610: Limit terminal width/height to 1024 characters. 2018-08-18 11:12:50 -07:00
Nick Couchman
0062f61d67 Merge 1.0.0 changes back to master. 2018-07-31 08:12:30 -04:00
Nick Couchman
427c4c8b44 GUACAMOLE-559: Merge fix race condition in receipt of clipboard data by terminal. 2018-07-31 08:10:47 -04:00
Michael Jumper
4f25410aa9 GUACAMOLE-559: Guarantee ordered modification to the clipboard. Do not allow modification of clipboard while clipboard contents are being sent. 2018-07-30 23:53:03 -07:00
Michael Jumper
860a5fca8f GUACAMOLE-559: Maintain terminal clipboard at client level such that it is guaranteed to exist immediately after user connects. 2018-07-30 23:53:03 -07:00
Nick Couchman
d8cb2218ee GUACAMOLE-597: Merge add optional flags to OSC for controlling redirected terminal output. 2018-07-27 22:08:20 -04:00
Michael Jumper
e66178ff9a GUACAMOLE-597: Add flag for forcing automatic flushing of pipe stream. 2018-07-27 14:23:50 -07:00
Michael Jumper
99b17b0ac4 GUACAMOLE-597: Add flag which sends terminal output to both the user's display and the open pipe stream. 2018-07-27 14:23:44 -07:00
Michael Jumper
e02df8d550 GUACAMOLE-597: Additionally parse integer flags which may affect pipe stream contents. 2018-07-27 14:23:33 -07:00
James Muehlner
79ce5ad8b0 GUACAMOLE-573: Merge scrollback buffer check to fix text selection. 2018-07-17 22:06:20 -07:00
Michael Jumper
b0b0b186f5 GUACAMOLE-573: Ensure scrollback buffer bounds cannot be exceeded. Remove incorrect bounds checks. 2018-07-17 21:55:46 -07:00
Michael Jumper
f5b5ac7183 Merge 1.0.0 changes back to master. 2018-07-05 22:54:36 -07:00
Michael Jumper
71f993b25d GUACAMOLE-446: Merge changes adding support for overriding default RDP virtual drive name. 2018-07-05 22:53:29 -07:00
Michael Jumper
83f8dd50df Merge 1.0.0 changes back to master. 2018-07-05 14:42:15 -07:00
Michael Jumper
f980d4b926 GUACAMOLE-587: Merge changes allowing up to 128 elements per Guacamole instruction. 2018-07-05 14:40:00 -07:00
Nick Couchman
adcdb080cb GUACAMOLE-587: Increase max number of elements per instruction. 2018-07-05 16:42:33 -04:00
Nick Couchman
5e942c9a67 GUACAMOLE-446: Valid default value for the filesystem name. 2018-07-03 23:23:38 -04:00
Nick Couchman
958fb4c8e0 GUACAMOLE-446: Pass through drive name to RDPDR stream. 2018-07-03 23:20:11 -04:00
Nick Couchman
cfcfe8866c GUACAMOLE-446: Add settings for drive name. 2018-07-03 22:59:30 -04:00
Michael Jumper
35237a4f88 Merge 1.0.0 changes back to master. 2018-07-03 19:32:36 -07:00
Michael Jumper
da1e078242 GUACAMOLE-445: Merge support for defining the RDP printer name. 2018-07-03 19:24:07 -07:00
Nick Couchman
a1ec5d9ad7 GUACAMOLE-445: Implement per-device announce stream, set it up with device initalization, and collect them all during the annonuce process. 2018-07-03 22:13:11 -04:00
Nick Couchman
e68fe81938 GUACAMOLE-445: Pass printer name from settings to RDP session. 2018-07-03 22:12:30 -04:00
Nick Couchman
b21f00c29d GUACAMOLE-445: Add settings for printer name. 2018-06-26 19:23:52 -04:00
Michael Jumper
67680bd2d5 Merge 1.0.0 changes back to master. 2018-06-25 17:27:10 -07:00
Michael Jumper
addb473148 GUACAMOLE-527: Merge support for SSH host key checking. 2018-06-25 17:22:09 -07:00
Nick Couchman
fe44fd7c3b GUACAMOLE-527: Remove unused error message length variable. 2018-06-25 20:04:26 -04:00
Nick Couchman
7bc6a62365 GUACAMOLE-527: Do not call a remote host key a fingerprint. 2018-06-25 13:57:01 -04:00
Nick Couchman
ba684962b6 GUACAMOLE-527: Plug some memory leaks before returning NULL. 2018-06-25 13:50:19 -04:00
Nick Couchman
f9379dc6bb GUACAMOLE-527: Get full error message when key verification fails. 2018-06-25 08:37:34 -04:00
Nick Couchman
7e254955e8 GUACAMOLE-527: Slight tweak to error message. 2018-06-25 08:31:37 -04:00
Nick Couchman
ebbb7492e7 GUACAMOLE-527: Add warning if no known host keys are provided. 2018-06-25 08:31:37 -04:00
Nick Couchman
27c977adb2 GUACAMOLE-527: Make sure ssh_known_hosts exists before trying to load. 2018-06-25 08:31:37 -04:00
Nick Couchman
428243bb78 GUACAMOLE-527: Move host key checking to a separate function. 2018-06-25 08:31:37 -04:00
Nick Couchman
ac2b4f8d12 GUACAMOLE-527: Check either provided key or key file, if it exists. 2018-06-25 08:31:37 -04:00
Nick Couchman
aec2be6da2 GUACAMOLE-527: Remove unnecessary includes. 2018-06-25 08:31:37 -04:00
Nick Couchman
2bebb96804 GUACAMOLE-527: Fix host key options in the protocol settings. 2018-06-25 08:31:37 -04:00
Nick Couchman
551598e0a4 GUACAMOLE-527: Use libssh2_knownhost_readline and remove host key type. 2018-06-25 08:31:37 -04:00
Nick Couchman
42044e4279 GUACAMOLE-527: Clean up memory and logging. 2018-06-25 08:31:37 -04:00
Nick Couchman
ec4315dfbe GUACAMOLE-527: Correct names of parameters coming from client. 2018-06-25 08:31:37 -04:00
Nick Couchman
5bb616832e GUACAMOLE-527: Order SSH handshake correctly, and remove unnecessary logging. 2018-06-25 08:31:37 -04:00
Nick Couchman
c080569cac GUACAMOLE-527: Fix issue with null host_key variable. 2018-06-25 08:31:37 -04:00
Nick Couchman
2f0c6dcfa3 GUACAMOLE-527: Add error logging for known host checks. 2018-06-25 08:31:37 -04:00
Nick Couchman
9112c4f32f GUACAMOLE-527: Enable host key setting for SFTP connections. 2018-06-25 08:31:37 -04:00
Nick Couchman
0d82cd1e6c GUACAMOLE-527: Add host key and type settings. 2018-06-25 08:31:37 -04:00
Nick Couchman
171bae1f5c GUACAMOLE-527: Add basic check for known hosts file for SSH connections. 2018-06-25 08:31:37 -04:00
Nick Couchman
c120aa0274 GUACAMOLE-574: Merge allow SSH/Telnet input from STDIN pipe. 2018-06-18 20:17:42 -04:00
Michael Jumper
b650bef139 GUACAMOLE-574: Redirect STDIN from pipe stream named "STDIN" for SSH and telnet. 2018-06-18 14:31:09 -07:00
Michael Jumper
97593958e4 GUACAMOLE-574: Add support for reading STDIN from a pipe stream. 2018-06-18 14:31:09 -07:00
Nick Couchman
f3d9c2f610 GUACAMOLE-573: Merge allow selection of text while scrolling. 2018-06-18 09:32:18 -04:00
Nick Couchman
7bfd3e1c6a GUACAMOLE-572: Merge fix typo in README. 2018-06-18 06:26:30 -04:00
Liron Newman
da2e8220f3
GUACAMOLE-572: Fix typo from "test-based protocol" to "text-based protocol" 2018-06-17 17:40:59 +01:00
Michael Jumper
ecda5c1df9 GUACAMOLE-573: Read selection only within bounds of terminal/scrollback. 2018-06-17 00:01:47 -07:00
Michael Jumper
1756c01522 GUACAMOLE-573: Update selected region when terminal scrolls. 2018-06-17 00:01:47 -07:00
Michael Jumper
6f08ef2a07 GUACAMOLE-573: Allow text selection to be expanded using Shift (fixes GUACAMOLE-191). 2018-06-17 00:01:47 -07:00
Michael Jumper
c0d323828e GUACAMOLE-573: Copy terminal data directly into clipboard. Do not assume selected region will be strictly visible. 2018-06-16 23:58:38 -07:00
Michael Jumper
f87af06ad6 GUACAMOLE-573: Move terminal text selection code into own file. 2018-06-16 23:58:34 -07:00
Nick Couchman
30e90b2425 Merge 1.0.0 changes back to master. 2018-06-07 04:35:11 -04:00
Nick Couchman
334849e2a6 GUACAMOLE-570: Bump version number to 1.0.0. 2018-06-07 04:34:05 -04:00
Michael Jumper
107fdda1f0 GUACAMOLE-570: Update libtool version info for libguac (interfaces added and removed). 2018-06-05 21:48:39 -07:00
Michael Jumper
6850fd40fe GUACAMOLE-570: Bump version number to 1.0.0. 2018-06-05 21:47:40 -07:00
Michael Jumper
21f54b9e12 GUACAMOLE-470: Merge changes addressing broken build / GCC warning. 2018-05-27 21:13:25 -07:00
Jim Chen
9c10ddae3b GUACAMOLE-470: Fix incompatible pointer type warning under older GCC.
Older versions of GCC (prior to 5.1) emits an "incompatible pointer
type" warning when passing `foo(*)[]` as `const foo(*)[]`. This was
changed in GCC 5.1, and this patch adds explicit casts to remove the
warning under older GCC.
2018-05-27 23:46:16 -04:00
Michael Jumper
526152b9c6 GUACAMOLE-564: Merge changes ignoring APC sequences within Guacamole's terminal emulator. 2018-05-27 09:31:35 -07:00
Michael Jumper
81bba1b587 GUACAMOLE-470: Merge support for fully configurable terminal color palette. 2018-05-27 08:49:18 -07:00
Nick Couchman
4eae5d2e6d GUACAMOLE-565: Merge add terminal-type parameter for SSH and telnet. 2018-05-27 07:18:46 -04:00
Jim Chen
87df97317f GUACAMOLE-565: Add terminal-type parameter for SSH and Telnet.
Add a terminal-type parameter for SSH and Telnet connections, to specify
the terminal emulator type that is passed to programs. If not specified,
the default type of "linux" is used in keep with existing behavior.
2018-05-26 23:30:22 -04:00
Jim Chen
b96afce222 GUACAMOLE-564: Hide APC escape sequence.
An APC escape sequence contains an arbitrary string command between
(ESC _) and (ESC \) sequences. While we don't support any APC commands, we
should ignore any commands that we do encounter.
2018-05-26 23:25:56 -04:00
Jim Chen
6da9236ffd GUACAMOLE-470: Reset character attributes on terminal reset.
The character attributes such as foreground/background colors should be
reset as well when performing a terminal reset.
2018-05-26 23:18:27 -04:00
Jim Chen
03d9c51b5d GUACAMOLE-470: Fix crash when X11 color is not found.
Fix a crash when an X11 color name is not found. The variable to
null-check should be `found`, not `color`.
2018-05-26 23:18:27 -04:00
Jim Chen
7e68901ceb GUACAMOLE-470: Set palette index for parsed RGB colors.
Parsed RGB colors do not correspond to any palette entry, so set the
palette index to -1.
2018-05-26 23:18:27 -04:00
Jim Chen
1bd537c350 GUACAMOLE-470: Support configurable colors in color-scheme parameter.
Add support for configuring individual colors in the color-scheme
parameter, by parsing the parameter content into name-value pairs.
Backward compatibility is preserved by translating previously supported
values into corresponding new values.
2018-05-26 23:18:27 -04:00
Jim Chen
f8b35078fc GUACAMOLE-470: Add support for configurable default palette.
Add support for configuring a default palette for a terminal display.
When the default palette is specified during display creation, that
palette is used instead of GUAC_TERMINAL_INITIAL_PALETTE when resetting
the display palette.
2018-05-15 22:05:59 -04:00
Nick Couchman
b61a6ab758 GUACAMOLE-482: Merge allow encoding to proceed despite invalid instructions. 2018-04-13 14:46:01 -04:00
Michael Jumper
8d43c4344d GUACAMOLE-482: Ignore invalid instructions within guacenc. Log failure at debug level. 2018-04-12 15:07:45 -07:00
Nick Couchman
325c8061ea GUACAMOLE-407: Merge refactor guacd Docker to debian:stable base. 2018-04-04 17:00:30 -04:00
Nick Couchman
6d8319e1bd GUACAMOLE-533: Merge process cleanup following disconnect. 2018-04-02 18:17:36 -04:00
Michael Jumper
70b2b8a1bf GUACAMOLE-269: Merge support for overriding the character sequence sent for backspace for SSH/telnet. 2018-04-02 12:19:02 -07:00
Nick Couchman
dc1918b217 GUACAMOLE-269: Don't abort on ttymode issue, just log a warning. 2018-04-02 15:05:56 -04:00
Nick Couchman
7453bc8f44 GUACAMOLE-269: Clean up logging and comments, and simplify code. 2018-04-02 15:04:03 -04:00
Nick Couchman
b441181c18 GUACAMOLE-269: Remove unnecessary data structure and array size, and update comments. 2018-04-02 10:43:57 -04:00
Nick Couchman
ea946f2492 GUACAMOLE-269: Changes to initializing opcode array. 2018-04-02 09:10:11 -04:00
Nick Couchman
c898f35959 GUACAMOLE-269: Clean up terminal backspace initialization. 2018-04-02 07:47:49 -04:00
Michael Jumper
d6a5695f8a GUACAMOLE-533: Wait at most 5 seconds for connection processes to terminate following disconnect. 2018-04-01 23:35:17 -07:00
Michael Jumper
0126880dad GUACAMOLE-407: As the Docker base image lacks the "en_US" locale, we must instead use "C.UTF-8" to ensure characters render correctly. 2018-04-01 22:05:06 -07:00
Michael Jumper
b3c1471180 GUACAMOLE-407: Explicitly set LD_LIBRARY_PATH such that linker can find guacd's protocol plugins. 2018-04-01 21:50:41 -07:00
Michael Jumper
1f60526ab8 GUACAMOLE-407: Do not build guaclog within guacd Docker image. The guacd image should contain only guacd. 2018-04-01 21:36:59 -07:00
Michael Jumper
14389326b4 GUACAMOLE-407: Remove unnecessary setting of LC_ALL within build (only needed at runtime). 2018-04-01 21:31:44 -07:00
Michael Jumper
eb282e49d9 GUACAMOLE-407: Use Debian (stable) instead of Ubuntu. 2018-04-01 21:26:30 -07:00
Michael Jumper
2e4fb5b91c GUACAMOLE-407: Upgrade Docker image to Ubuntu 17.10. 2018-04-01 21:16:38 -07:00
Michael Jumper
d6510360d0 GUACAMOLE-407: Dynamically derive runtime dependencies. 2018-04-01 21:16:38 -07:00
Michael Jumper
554d3209db GUACAMOLE-407: Restrict runtime dependencies to only those libraries which are actually linked. 2018-04-01 21:16:38 -07:00
Michael Jumper
72638aa03e GUACAMOLE-407: Update Docker image to use more recent packages by switching to Ubuntu. 2018-04-01 21:16:38 -07:00
Michael Jumper
3516704b82 GUACAMOLE-42: Merge changes adding support for specifying the guacd log level for the Docker image. 2018-03-31 10:53:39 -07:00
Nick Couchman
a9d01af104 GUACAMOLE-42: Run CMD so that ENV can be used. 2018-03-29 04:32:06 -04:00
Nick Couchman
1cfba83164 GUACAMOLE-42: Configure log level in docker. 2018-03-28 19:55:56 -04:00
Nick Couchman
e16bfd7837 GAUCAMOLE-269: Memory effeciency updates. 2018-03-24 15:50:11 -04:00
Nick Couchman
11136f7d7b GUACAMOLE-269: More documentation updates. 2018-03-24 15:09:34 -04:00
Nick Couchman
112ce5299e GUACAMOLE-269: Remove unnecessary dynamic allocation. 2018-03-24 14:54:27 -04:00
Nick Couchman
86dde85b2d GUACAMOLE-269: Comment and spelling updates. 2018-03-24 14:53:22 -04:00
Michael Jumper
e2feb41605 GUACAMOLE-30: Merge support for systemd. 2018-03-16 23:18:18 -07:00
Nick Couchman
fef819fbb9 GUACAMOLE-30: Add license to file and want network.target. 2018-03-16 17:02:53 -04:00
Nick Couchman
f75579de7e GUACAMOLE-30: Change from script to data. 2018-03-15 07:30:55 -04:00
Nick Couchman
77cac3b30d GUACAMOLE-30: Implement systemd script for guacd 2018-03-15 06:52:41 -04:00
Michael Jumper
344ed4f42e GUACAMOLE-523: Merge changes registering RDPDR devices using the configured RDP client name. 2018-03-08 11:14:37 -08:00
Nick Couchman
a27757682a GUACAMOLE-523: Add default value for client name. 2018-03-08 12:21:04 -05:00
Nick Couchman
b72bcafecd GUACAMOLE-523: Pass configured client name through for redirect messages. 2018-03-08 12:16:31 -05:00
Nick Couchman
45b832bfdc GUACAMOLE-269: Remove all dynamic allocation and simplify implementation. 2018-03-08 11:36:15 -05:00
Nick Couchman
dd7522bd9f GUACAMOLE-269: Get rid of dynamic allocation and properly free up data structures. 2018-03-08 10:48:22 -05:00
Nick Couchman
c3e1b2afef GUACAMOLE-269: Fix minor style issues and update comments. 2018-03-08 10:48:22 -05:00
Nick Couchman
64ca77f3a5 GUACAMOLE-269: Change struct to struct pointer. 2018-03-08 10:48:22 -05:00
Nick Couchman
33cca46346 GUACAMOLE-269: Remove debug code. 2018-03-08 10:48:22 -05:00
Nick Couchman
dd78d230ea GUACAMOLE-269: Backspace key should send null-terminated string. 2018-03-08 10:48:22 -05:00
Nick Couchman
c286668b79 GUACAMOLE-269: Name functions per Guacamole standards. 2018-03-08 10:48:22 -05:00
Nick Couchman
9bd28321e5 GUACAMOLE-269: Fix up style in comments. 2018-03-08 10:48:21 -05:00
Nick Couchman
fd58d31eea GUACAMOLE-269: Use backspace config to set up tty modes. 2018-03-08 10:48:21 -05:00
Nick Couchman
46e908c06e GUACAMOLE-269: Allow backspace key to be configured. 2018-03-08 10:48:21 -05:00
Nick Couchman
2ace9385a2 GUACAMOLE-269: Add documentation for the defines and variables. 2018-03-08 10:48:21 -05:00
Nick Couchman
5583748b54 GUACAMOLE-269: Move constant declaration to ttymode.c 2018-03-08 10:48:21 -05:00
Nick Couchman
f1bf70a4a2 GUACAMOLE-269: Add basic support for sending TTY mode encoding. 2018-03-08 10:48:21 -05:00
Nick Couchman
bc1e2f5276 GUACAMOLE-517: Merge add definition for "Print Screen" key to base RDP keymap. 2018-03-06 15:20:02 -05:00
Michael Jumper
5d37530687 GUACAMOLE-517: Add definition for "Print Screen" key to base RDP keymap. 2018-03-06 12:01:50 -08:00
Michael Jumper
bc5b01d4d8 GUACAMOLE-448: Merge support for configuring the level of caching used by RDP. 2018-02-22 00:39:31 -08:00
Nick Couchman
d239207f0f GUACAMOLE-448: Add support for configuring glyph caching. 2018-02-20 15:35:50 -05:00
Nick Couchman
3187a641cf GUACAMOLE-471: Merge update copyright year in NOTICE to 2018 2018-02-07 22:38:16 -05:00
Nick Couchman
329cc9ee48 GUACAMOLE-351: Merge add "-v" parameter 2018-02-07 22:35:42 -05:00
Michael Jumper
3b327378eb GUACAMOLE-351: Add "-v" option which causes guacd to print its version information and exit. 2018-02-07 13:45:13 -08:00
Michael Jumper
f4f5b4e65a GUACAMOLE-351: Separate guac_config structure into own header file, independent of how that config is loaded. 2018-02-07 13:33:52 -08:00
Michael Jumper
5f27616f32 GUACAMOLE-471: Update copyright year in NOTICE to 2018. 2018-02-07 12:48:02 -08:00
James Muehlner
05f54d098c GUACAMOLE-502: Merge cessastion of name instruction in RDP/VNC to avoid incorreclty updating window title. 2018-02-06 22:43:46 -08:00
James Muehlner
599ca960aa GUACAMOLE-500: Merge buffer size compilation warning fix. 2018-02-06 22:30:07 -08:00
Michael Jumper
cd0e48234a GUACAMOLE-500: Explicitly guarantee typescript filename cannot exceed buffer size. 2018-02-06 22:13:55 -08:00
James Muehlner
5b58c7e15b GUACAMOLE-324: Merge buffer write bug fix. 2018-02-06 21:38:27 -08:00
James Muehlner
9ed3baf004 GUACAMOLE-482: Merge encoding error handling improvements. 2018-02-06 21:30:30 -08:00
Michael Jumper
9705b39c2b GUACAMOLE-324: Continuously write chunks of data until entire buffer has been sent. 2018-02-06 21:29:31 -08:00
Michael Jumper
19b5050fbf GUACAMOLE-482: Fail overall encoding process if any instruction handler reports failure. 2018-02-06 21:19:24 -08:00
Michael Jumper
b0c14bd59f GUACAMOLE-482: Report video encoding failure if frame flush fails. 2018-02-06 21:18:39 -08:00
James Muehlner
1cf86e12a1 GUACAMOLE-485: Merge terminal emulator build fix. 2018-02-06 20:54:56 -08:00
Michael Jumper
d75a18e603 GUACAMOLE-485: Disable build of terminal emulator if Pango was manually disabled. 2018-02-06 20:21:14 -08:00
Michael Jumper
02cd424d18 GUACAMOLE-502: Do not send connection name / hostname (which may be internal information). 2018-02-06 20:12:53 -08:00
Nick Couchman
4d7191147c GUACAMOLE-313: Merge add support for including key events within session recordings. 2018-02-02 16:16:42 -05:00
Nick Couchman
ebc6b9429f GUACAMOLE-492: Merge remove guaclog binary erroneously added to source tree. 2018-01-31 22:42:48 -05:00
Michael Jumper
139251ea73 GUACAMOLE-492: Remove guaclog binary erroneously added to source tree. 2018-01-31 16:45:09 -08:00
Nick Couchman
3f6acb6378 GUACAMOLE-313: Merge remove handling of Unicode codepoints which cannot actually be represented by an X11 keysym. 2018-01-30 19:06:01 -05:00
Nick Couchman
b1d050285a GUACAMOLE-313: Merge ensure keydef structure is freed in all cases. 2018-01-30 19:04:22 -05:00
Nick Couchman
8ca6ff3a94 GUACAMOLE-313: Merge exclude built guaclog.1 mangpage from git. 2018-01-30 18:41:28 -05:00
Nick Couchman
35eebe8553 GUACAMOLE-313: Merge properly initialize modifier flag for all keydefs. 2018-01-30 18:39:41 -05:00
Michael Jumper
7f9e61a1f2 GUACAMOLE-313: Exclude built guaclog.1 manpage from git. 2018-01-30 15:28:15 -08:00
Michael Jumper
555126441e GUACAMOLE-313: Remove code handling Unicode codepoints which cannot be represented by X11 keysyms. 2018-01-30 15:26:25 -08:00
Michael Jumper
cfd69cd122 GUACAMOLE-313: Clarify logic testing for Unicode keysyms. 2018-01-30 15:26:05 -08:00
Michael Jumper
5f547fb118 GUACAMOLE-313: Ensure keydef structure is freed in all cases. 2018-01-30 15:16:56 -08:00
Michael Jumper
575ff91369 GUACAMOLE-313: Properly initialize modifier flag for all keydefs. 2018-01-30 15:11:23 -08:00
Nick Couchman
5f5b4ea8eb GUACAMOLE-313: Merge add "guaclog" utility for producing human-readable interpreatations of keys pressed in session recordings. 2018-01-30 14:07:35 -05:00
Nick Couchman
08f854ffef GUACAMOLE-313: Merge add support for logging mouse cursor information. 2018-01-30 14:05:39 -05:00
Nick Couchman
c543adddb2 GUACAMOLE-352: Merge clean up keymap lookup/update logic for the sake of verifiability. 2018-01-29 12:13:21 -05:00
Michael Jumper
053d9d420c GUACAMOLE-352: Clean up keymap lookup/update logic for sake of verifiability. 2018-01-28 23:09:50 -08:00
Nick Couchman
4e5a7e97ad GUACAMOLE-352: Merge add support for typing using dead keys within RDP. 2018-01-28 07:59:22 -05:00
Michael Jumper
9a5b5574a8 GUACAMOLE-352: Type using dead keys when necessary and possible. 2018-01-28 01:32:58 -08:00
Michael Jumper
5d56985479 GUACAMOLE-352: Add utility function for checking whether a keysym exists within the current RDP keyboard layout. 2018-01-28 00:56:24 -08:00
Nick Couchman
e37fb1dad9 GUACAMOLE-489: Merge lock both wrapped sockets when performing operations through a tee socket. 2018-01-27 17:20:28 -05:00
Nick Couchman
57428a95aa GUACAMOLE-490: Merge take channel mask into account when rendering image streams to buffers. 2018-01-27 17:17:24 -05:00
Michael Jumper
4fb17d5610 GUACAMOLE-313: Add flags for controlling the contents of session recordings. 2018-01-26 16:42:24 -08:00
Michael Jumper
876516a1fb GUACAMOLE-313: Add support for including key states within session recordings. 2018-01-26 16:42:14 -08:00
Michael Jumper
b21aef565b GUACAMOLE-313: Add function for sending "key" instructions. 2018-01-26 16:42:14 -08:00
Michael Jumper
fdd17e3042 GUACAMOLE-313: Note that guacenc/guaclog are related. 2018-01-26 16:24:45 -08:00
Michael Jumper
c0b2871b31 GUACAMOLE-313: Document log format. 2018-01-26 16:24:45 -08:00
Michael Jumper
b7257d9ae4 GUACAMOLE-313: Include unknown keys within log. 2018-01-26 16:24:45 -08:00
Michael Jumper
5e5f1fcb3e GUACAMOLE-313: Add missing keysyms. Track modifier keys only. 2018-01-26 16:24:45 -08:00
Michael Jumper
5b612b856a GUACAMOLE-313: Refactor guaclog to produce simpler, greppable output. 2018-01-26 16:24:45 -08:00
Michael Jumper
86b09c8cf7 GUACAMOLE-313: Add remaining key names. Use Unicode where possible. 2018-01-26 16:24:45 -08:00
Michael Jumper
3633af5e41 GUACAMOLE-313: Use binary search to find human-readable names for known keys. 2018-01-26 16:24:45 -08:00
Michael Jumper
df29735c83 GUACAMOLE-313: Separate naming logic for keysyms. Align previously-pressed keys. 2018-01-26 16:24:43 -08:00
Michael Jumper
d39757b4dc GUACAMOLE-313: Continuously track key press/release. 2018-01-26 16:24:14 -08:00
Michael Jumper
ebc731aaf3 GUACAMOLE-313: Add guaclog utility with stubbed interpretation of key events. 2018-01-26 16:24:04 -08:00
Michael Jumper
81a0e66d9f GUACAMOLE-313: Include current button state within mouse update for completeness. 2018-01-26 16:21:53 -08:00
Michael Jumper
7eb4e22515 GUACAMOLE-313: Use mouse timestamps for frames as well as sync. 2018-01-26 16:21:51 -08:00
Michael Jumper
a74d6a2aaf GUACAMOLE-313: Include timestamp with mouse position reporting. 2018-01-26 16:21:49 -08:00
Michael Jumper
e2455d6f26 GUACAMOLE-313: Do not render cursor unless mouse has actually moved. 2018-01-26 16:21:47 -08:00
Michael Jumper
cafcd90f9f GUACAMOLE-313: Add support for the "mouse" instruction to guacenc. 2018-01-26 16:21:45 -08:00
Michael Jumper
a14832c4da GUACAMOLE-313: Implement the "cursor" instruction to guacenc. 2018-01-26 16:21:43 -08:00
Michael Jumper
df770ae4ea GUACAMOLE-313: Add support for including mouse location within session recordings. 2018-01-26 16:21:28 -08:00
Michael Jumper
b37e73488f GUACAMOLE-313: Provide reference to in-progress screen recording. 2018-01-26 16:21:24 -08:00
Michael Jumper
dc5245025e GUACAMOLE-489: Lock both wrapped sockets when performing operations through a tee socket. 2018-01-26 16:17:45 -08:00
Michael Jumper
dcaf7b2c21 GUACAMOLE-490: Take channel mask into account when rendering image streams to buffers. 2018-01-26 16:08:51 -08:00
Michael Jumper
db85163e20 GUACAMOLE-384: Merge fix for potential segfault if SSH connection is closed while output is still being written to the terminal. 2018-01-23 14:44:47 -08:00
Nick Couchman
8c844e6eab GUACAMOLE-484: Merge ensure disconnect reason code is checked for orderly RDP disconnect. 2018-01-22 15:29:26 -05:00
Michael Jumper
822a6c6b9d GUACAMOLE-484: Do not flush frame if connection closed mid-frame. 2018-01-22 12:24:07 -08:00
Michael Jumper
61c16a89d2 GUACAMOLE-484: Always clean up after orderly disconnect. 2018-01-22 12:23:39 -08:00
Michael Jumper
d562cb7648 GUACAMOLE-484: Ensure disconnect reason code is checked for orderly RDP disconnect. 2018-01-22 12:16:09 -08:00
Michael Jumper
0f78b01e81 GUACAMOLE-456: Merge multi-stage Docker build changes. 2018-01-19 13:37:01 -08:00
Michael Jumper
11605ff5ed GUACAMOLE-481: Merge Turkish keymap for RDP. 2018-01-09 19:12:05 -08:00
csenel
93b3eebc5d
GUACAMOLE-481: Add Turkish Q keymap for RDP 2018-01-09 10:53:05 +03:00
Nick Couchman
66ffda24f0 GUACAMOLE-448: Add support for configuring bitmap caching. 2018-01-02 18:26:29 -05:00
Nick Couchman
5295886f68 Merge 0.9.14 changes back to master. 2018-01-01 16:27:03 -05:00
Nick Couchman
7c191d7be0 GUACAMOLE-423: Merge bump version number to 0.9.14. 2018-01-01 16:23:37 -05:00
Nick Couchman
f72de10328 GUACAMOLE-307: Merge the size instruction can also apply to buffers. 2017-12-09 12:55:19 -05:00
Michael Jumper
ff6c4b04f4 GUACAMOLE-307: The "size" instruction can also apply to buffers, not just layers. 2017-12-08 14:54:15 -08:00
Michael Jumper
1b81549c97 GUACAMOLE-423: Update libtool version info for libguac (interfaces added, none changed/removed). 2017-12-07 19:10:45 -08:00
Michael Jumper
37236207a0 GUACAMOLE-423: Bump version number to 0.9.14. 2017-12-07 19:10:45 -08:00
Michael Jumper
76a6e41031 GUACAMOLE-423: Automatically populate package version within manpages. 2017-12-07 19:10:45 -08:00
Nick Couchman
e3d8c3fa12 Merge 0.9.14 changes back to master. 2017-12-06 10:04:34 -05:00
Nick Couchman
6322874d3a GUACAMOLE-436: Merge remove incubator prefixes and DISCLAIMER. 2017-12-06 10:02:44 -05:00
Carl Harris
e4f4761c87 GUACAMOLE-456: use Docker multi-stage build 2017-12-06 07:57:12 -05:00
Michael Jumper
798ba1e5be GUACAMOLE-423: Automatically populate package version within Doxyfile. 2017-12-06 01:13:39 -08:00
Michael Jumper
89912dc657 GUACAMOLE-436: Remove old references to pre-Incubator project. 2017-12-06 00:54:21 -08:00
Michael Jumper
a514f03fd4 GUACAMOLE-436: Remove incubator prefix from repositories and URLs. 2017-12-06 00:54:21 -08:00
Michael Jumper
d201344443 GUACAMOLE-436: Remove Incubator DISCLAIMER file. 2017-12-06 00:54:21 -08:00
Michael Jumper
2c12c12850 GUACAMOLE-424: Merge changes addressing potential NULL-pointer dereference in VNC user leave handler. 2017-11-15 07:05:21 -08:00
itsankoff
aa6d81d6f9 GUACAMOLE-424: Update doc comments 2017-11-15 15:02:08 +02:00
Michael Jumper
a75bca1e95 GUACAMOLE-273: Merge RDP support for Portuguese Brazilian keyboard. 2017-11-14 17:17:34 -08:00
Frode Langelo
fc599d2aec GUACAMOLE-273: Remove Mac remapping of €. 2017-11-14 20:04:49 +00:00
Michael Jumper
493fa4df16 GUACAMOLE-233: Merge RDP support for Spanish keyboards. 2017-11-14 10:56:28 -08:00
Michael Jumper
c4c32264bf GUACAMOLE-434: Merge RDP support for UK English keyboards. 2017-11-14 10:55:53 -08:00
Frode Langelo
fc15850288 GUACAMOLE-233: Add Spanish keymap for RDP. 2017-11-13 22:57:21 +00:00
Frode Langelo
a8174eeac9 GUACAMOLE-273: Fix comment for remapping of €. 2017-11-13 22:52:39 +00:00
Frode Langelo
ed8a32f98b GUACAMOLE-273: Add Brazillian ABNT2 keymap for RDP. 2017-11-13 22:43:42 +00:00
Frode Langelo
625eee0caa GUACAMOLE-434: Add UK English keymap for RDP. 2017-11-13 22:26:29 +00:00
itsankoff
e139b20d12 GUACAMOLE-424: Remove check against NULL for display cursor 2017-11-13 14:51:31 +02:00
itsankoff
f7990af6d0 GUACAMOLE-424: Return NULL if guac_common_display allocation fails 2017-11-13 14:50:44 +02:00
itsankoff
da0fc1a6d8 GUACAMOLE-424: Add doc comment for guac_common_cursor_alloc 2017-11-13 14:49:44 +02:00
Michael Jumper
025fc0525f Merge 0.9.14-incubating changes back to master. 2017-11-06 11:29:37 -08:00
Michael Jumper
233f5e27e2 GUACAMOLE-296: Merge changes reverting explicit linking of libwinpr-utils. 2017-11-06 11:24:39 -08:00
Nick Couchman
b9f8e13d80 GUACAMOLE-296: Revert manual addition of winpr-utils library. 2017-11-06 12:20:56 -05:00
itsankoff
bbafa00df0 GUACAMOLE-424: Prevent null pointer dereference for vnc client display and cursor 2017-11-02 19:53:17 +02:00
sanhex
d33bd8deff GUACAMOLE-384: fixing segfault during ssh disconnect
Root Cause:
See the core dump and Valgrind report posted on Jira. guacd was reading a ssh terminal which had been freed. When a ssh connection is terminated, guac_ssh_client_free_handler() will be called from guacd_exec_proc() -> guac_client_free() with pointer client->free_handler. In guac_ssh_client_free_handler(), when ssh_client->term is freed, ssh_client->client_thread may still be using the ssh_client->term. It causes the crash reported in this bug.

The stack trace exposing the problem can be found by running guacd under Valgrind with a ssh test script. The test script repeats doing ssh login and logout for 5000 times.

Solution:
In guac_ssh_client_free_handler(), before calling guac_terminal_free(ssh_client->term), close the stdin pipe of the terminal to stop reading the pipe with guac_terminal_read_stdin() in ssh_input_thread(). So that ssh_input_thread() can be terminated in this case. Call pthread_join() to wait for ssh_client_thread() terminating before freeing the terminal.

Add a new function guac_terminal_stop() to close the pipe and set the fds to invalid (-1). Call it in guac_ssh_client_free_handler() and guac_terminal_free().

Checking the client running state in ssh_input_thread() and ssh_client_thread() to make sure they can be terminated when the client is stopped in guacd_exec_proc() by another thread.

Test:
- Confirmed ssh connection works normally.
- Observed the child process of guacd exits when ssh connection is terminated.
- Reran the ssh test script. Observed no crash.
2017-10-29 18:11:15 -07:00
itsankoff
15f6c4f3dc GUACAMOLE-424: Fix null pointer dereference for vnc client display 2017-10-24 20:21:03 +03:00
Michael Jumper
95be88be19 GUACAMOLE-296: Merge fix for linking issues with FreeRDP 1.1 and guacai (audio input). 2017-10-14 23:45:35 -07:00
Michael Jumper
012a3497eb GUACAMOLE-411: Merge changes fully initializing CMSG buffer prior to use. 2017-10-14 17:50:47 -07:00
Nick Couchman
caedf26a06 GUACAMOLE-296: Break out WINPR libs into their own variable. 2017-10-13 21:25:32 -04:00
Nick Couchman
9487eb2dc9 GUACAMOLE-296: Fix linking issue that causes audio issues with FreeRDP 1.1 2017-10-13 21:04:13 -04:00
Nick Couchman
c49c57ef30 GUACAMOLE-402: Merge fix out-of-tree build 2017-10-12 12:35:46 -04:00
David Fort
bb527f30f8 GUACAMOLE-402: fix out-of-tree build
Use $(srcdir) in places were it's needed, so that an out-of-tree build works.
2017-10-12 15:11:27 +02:00
Jukka-Pekka Virtanen
c8eaa91ad3 GUACAMOLE-411: Fixed using uninitialized values in guacd_send_fd 2017-10-10 12:41:19 +03:00
Michael Jumper
d35cc7a83e GUACAMOLE-400: Merge changes correcting segfault when an SSH private key cannot be imported. 2017-09-29 12:05:56 -07:00
sanhex
3c7a09f52b GUACAMOLE-400: Fix guacd crash when ssh key fails
Root Cause:
In the ssh library of guacd, function ssh_client_thread(), when guac_ssh_get_user() fails to load private key for ssh authentication, it will return NULL. In this case, the subsequent call to guac_common_ssh_create_session() with parameter 'user=0x0' will cause guacd crash in function guac_common_ssh_authenticate() by accessing 'user->username'.

Solution:
- Update the comment of function guac_ssh_get_user() to document that NULL will be returned if fails to import key for the user.
- In function ssh_client_thread(), verify the return of guac_ssh_get_user(). If ssh_client->user is NULL, return NULL.

Test:
- Configured a ssh app with an encrypted private key and a wrong passphrase.
- Ran the ssh app from web portal and observed guacd crash.
- Applied the fix and reran the ssh app. Observed no crash.
2017-09-29 11:04:48 -07:00
Michael Jumper
1d0e63b251 GUACAMOLE-398: Merge fix for address info memory leak. 2017-09-27 10:27:22 -07:00
Nick Couchman
9200bc789f GUACAMOLE-398: Use freeaddrinfo() instead of free() on the linked list. 2017-09-27 13:24:58 -04:00
Nick Couchman
e4dd8de4f1 GUACAMOLE-398: Fix memory leak identified by Coverity in common ssh code. 2017-09-27 13:02:41 -04:00
Michael Jumper
afb554a014 GUACAMOLE-396: Merge support for connecting to IPv6 hosts via SSH. 2017-09-26 19:46:17 -07:00
James
f559701645 GUACAMOLE-396: Fixing ssh socket for IPv6 address
Root Cause:
In the ssh library of guacd, the TCP socket for connecting to ssh server is created with AF_INET. So it does not support IPv6 address.

Solution:
When guacd creates the socket for ssh in guac_common_ssh_create_session(), stop using hard coded AF_INET for socket() call, use the address family which is returned from getaddrinfo().

Test:
- Connected successfully via ssh connections with IPv4 and IPv6 hosts.
- No connection error in guacd logs.
- Simulated a connection failure with specifying a ssh server which does not exist. guacd worked well in this case.
2017-09-26 17:19:18 -07:00
Nick Couchman
4e80960933 GUACAMOLE-391: Merge resolve low-impact memory leak. 2017-09-24 08:42:46 -04:00
Ilya Shipitsin
d2102e5705 GUACAMOLE-391: resolve low impact memory leak 2017-09-24 13:42:59 +05:00
Michael Jumper
c5f674340a GUACAMOLE-383: Merge fix for low-impact memory leaks identified by cppcheck. 2017-09-23 13:31:01 -07:00
Ilya Shipitsin
fc071fd1af GUACAMOLE-383: resolve issues identified by cppcheck
[src/guacd/conf-file.c:206]: (error) Memory leak: conf
[src/protocols/rdp/rdp_cliprdr.c:205]: (error) Memory leak: output
[src/terminal/display.c:283]: (error) Memory leak: display
[src/terminal/display.c:290]: (error) Memory leak: display
2017-09-20 22:55:58 +05:00
448 changed files with 35088 additions and 13301 deletions

View File

@ -1,3 +1,5 @@
# Docker build spec
Dockerfile
# Git repository metadata # Git repository metadata
.git .git
@ -54,5 +56,5 @@ tests/test_*
!tests/test_*.[ch] !tests/test_*.[ch]
# Generated docs # Generated docs
doc/doxygen-output doc/*/doxygen-output

24
.gitignore vendored
View File

@ -10,6 +10,10 @@
*.gcov *.gcov
*.gcno *.gcno
# Test suite output
*.log
*.trs
# Backup files # Backup files
*~ *~
@ -23,32 +27,24 @@
.deps/ .deps/
.dirstamp .dirstamp
.libs/ .libs/
Doxyfile
Makefile Makefile
Makefile.in Makefile.in
aclocal.m4 aclocal.m4
autom4te.cache/ autom4te.cache/
build-aux/
libtool
m4/* m4/*
!README !README
compile
config.guess
config.h config.h
config.h.in config.h.in
config.log config.log
config.status config.status
config.sub
configure configure
depcomp
install-sh
libtool
ltmain.sh
missing
stamp-h1 stamp-h1
test-driver
# Test binaries
tests/test_*
!tests/test_*.[ch]
# Generated docs # Generated docs
doc/doxygen-output doc/*/doxygen-output
# IDE metadata
nbproject/

View File

@ -24,10 +24,10 @@ the review process.
The Guacamole source is maintained in git repositories hosted on GitHub: The Guacamole source is maintained in git repositories hosted on GitHub:
https://github.com/apache/incubator-guacamole-client https://github.com/apache/guacamole-client
https://github.com/apache/incubator-guacamole-manual https://github.com/apache/guacamole-manual
https://github.com/apache/incubator-guacamole-server https://github.com/apache/guacamole-server
https://github.com/apache/incubator-guacamole-website https://github.com/apache/guacamole-website
To make your changes, fork the applicable repositories and make commits To make your changes, fork the applicable repositories and make commits
to a topic branch in your fork. Commits should be made in logical units to a topic branch in your fork. Commits should be made in logical units

View File

@ -1,18 +0,0 @@
2013-08-26 Michael Jumper <mike.jumper@guac-dev.org>
* Experimental sound support for VNC (ticket #369)
* Improved handling of frame flush (ticket #380)
* SSL transport for guacd (ticket #371)
* Fix segfault in RDP disconnect (ticket #385)
* Add security options to RDP (ticket #190)
2013-07-02 Michael Jumper <mike.jumper@guac-dev.org>
* Optional threadsafety in guac_socket
* Printing support in for RDP (ticket #110)
* Fix ENABLE_OGG bug (ticket #355)
2013-06-06 Michael Jumper <mike.jumper@guac-dev.org>
* Created new repository layout

View File

@ -1,7 +0,0 @@
Apache Guacamole is an effort undergoing incubation at The Apache Software
Foundation (ASF). Incubation is required of all newly accepted projects until a
further review indicates that the infrastructure, communications, and decision
making process have stabilized in a manner consistent with other successful ASF
projects. While incubation status is not necessarily a reflection of the
completeness or stability of the code, it does indicate that the project has
yet to be fully endorsed by the ASF.

View File

@ -21,68 +21,181 @@
# Dockerfile for guacamole-server # Dockerfile for guacamole-server
# #
# Start from CentOS base image # The Alpine Linux image that should be used as the basis for the guacd image
FROM centos:centos7 ARG ALPINE_BASE_IMAGE=latest
FROM alpine:${ALPINE_BASE_IMAGE} AS builder
# Environment variables # Install build dependencies
ENV \ RUN apk add --no-cache \
BUILD_DIR=/tmp/guacd-docker-BUILD \
LC_ALL=en_US.UTF-8 \
RUNTIME_DEPENDENCIES=" \
cairo \
dejavu-sans-mono-fonts \
freerdp \
freerdp-plugins \
ghostscript \
libjpeg-turbo \
libssh2 \
liberation-mono-fonts \
libtelnet \
libvorbis \
libvncserver \
libwebp \
pango \
pulseaudio-libs \
terminus-fonts \
uuid" \
BUILD_DEPENDENCIES=" \
autoconf \ autoconf \
automake \ automake \
cairo-devel \ build-base \
freerdp-devel \ cairo-dev \
gcc \ cmake \
libjpeg-turbo-devel \ git \
libssh2-devel \ grep \
libjpeg-turbo-dev \
libpng-dev \
libtool \ libtool \
libtelnet-devel \ libwebp-dev \
libvorbis-devel \
libvncserver-devel \
libwebp-devel \
make \ make \
pango-devel \ openssl-dev \
pulseaudio-libs-devel \ pango-dev \
uuid-devel" pulseaudio-dev \
util-linux-dev
# Bring environment up-to-date and install guacamole-server dependencies
RUN yum -y update && \
yum -y install epel-release && \
yum -y install $RUNTIME_DEPENDENCIES && \
yum clean all
# Add configuration scripts
COPY src/guacd-docker/bin /opt/guacd/bin/
# Copy source to container for sake of build # Copy source to container for sake of build
COPY . "$BUILD_DIR" ARG BUILD_DIR=/tmp/guacamole-server
COPY . ${BUILD_DIR}
# Build guacamole-server from local source #
RUN yum -y install $BUILD_DEPENDENCIES && \ # Base directory for installed build artifacts.
/opt/guacd/bin/build-guacd.sh "$BUILD_DIR" && \ #
rm -Rf "$BUILD_DIR" && \ # NOTE: Due to limitations of the Docker image build process, this value is
yum -y autoremove $BUILD_DEPENDENCIES && \ # duplicated in an ARG in the second stage of the build.
yum clean all #
ARG PREFIX_DIR=/opt/guacamole
#
# Automatically select the latest versions of each core protocol support
# library (these can be overridden at build time if a specific version is
# needed)
#
ARG WITH_FREERDP='2(\.\d+)+'
ARG WITH_LIBSSH2='libssh2-\d+(\.\d+)+'
ARG WITH_LIBTELNET='\d+(\.\d+)+'
ARG WITH_LIBVNCCLIENT='LibVNCServer-\d+(\.\d+)+'
ARG WITH_LIBWEBSOCKETS='v\d+(\.\d+)+'
#
# Default build options for each core protocol support library, as well as
# guacamole-server itself (these can be overridden at build time if different
# options are needed)
#
ARG FREERDP_OPTS="\
-DBUILTIN_CHANNELS=OFF \
-DCHANNEL_URBDRC=OFF \
-DWITH_ALSA=OFF \
-DWITH_CAIRO=ON \
-DWITH_CHANNELS=ON \
-DWITH_CLIENT=ON \
-DWITH_CUPS=OFF \
-DWITH_DIRECTFB=OFF \
-DWITH_FFMPEG=OFF \
-DWITH_GSM=OFF \
-DWITH_GSSAPI=OFF \
-DWITH_IPP=OFF \
-DWITH_JPEG=ON \
-DWITH_LIBSYSTEMD=OFF \
-DWITH_MANPAGES=OFF \
-DWITH_OPENH264=OFF \
-DWITH_OPENSSL=ON \
-DWITH_OSS=OFF \
-DWITH_PCSC=OFF \
-DWITH_PULSE=OFF \
-DWITH_SERVER=OFF \
-DWITH_SERVER_INTERFACE=OFF \
-DWITH_SHADOW_MAC=OFF \
-DWITH_SHADOW_X11=OFF \
-DWITH_SSE2=ON \
-DWITH_WAYLAND=OFF \
-DWITH_X11=OFF \
-DWITH_X264=OFF \
-DWITH_XCURSOR=ON \
-DWITH_XEXT=ON \
-DWITH_XI=OFF \
-DWITH_XINERAMA=OFF \
-DWITH_XKBFILE=ON \
-DWITH_XRENDER=OFF \
-DWITH_XTEST=OFF \
-DWITH_XV=OFF \
-DWITH_ZLIB=ON"
ARG GUACAMOLE_SERVER_OPTS="\
--disable-guaclog"
ARG LIBSSH2_OPTS="\
-DBUILD_EXAMPLES=OFF \
-DBUILD_SHARED_LIBS=ON"
ARG LIBTELNET_OPTS="\
--disable-static \
--disable-util"
ARG LIBVNCCLIENT_OPTS=""
ARG LIBWEBSOCKETS_OPTS="\
-DDISABLE_WERROR=ON \
-DLWS_WITHOUT_SERVER=ON \
-DLWS_WITHOUT_TESTAPPS=ON \
-DLWS_WITHOUT_TEST_CLIENT=ON \
-DLWS_WITHOUT_TEST_PING=ON \
-DLWS_WITHOUT_TEST_SERVER=ON \
-DLWS_WITHOUT_TEST_SERVER_EXTPOLL=ON \
-DLWS_WITH_STATIC=OFF"
# Build guacamole-server and its core protocol library dependencies
RUN ${BUILD_DIR}/src/guacd-docker/bin/build-all.sh
# Record the packages of all runtime library dependencies
RUN ${BUILD_DIR}/src/guacd-docker/bin/list-dependencies.sh \
${PREFIX_DIR}/sbin/guacd \
${PREFIX_DIR}/lib/libguac-client-*.so \
${PREFIX_DIR}/lib/freerdp2/*guac*.so \
> ${PREFIX_DIR}/DEPENDENCIES
# Use same Alpine version as the base for the runtime image
FROM alpine:${ALPINE_BASE_IMAGE}
#
# Base directory for installed build artifacts. See also the
# CMD directive at the end of this build stage.
#
# NOTE: Due to limitations of the Docker image build process, this value is
# duplicated in an ARG in the first stage of the build.
#
ARG PREFIX_DIR=/opt/guacamole
# Runtime environment
ENV LC_ALL=C.UTF-8
ENV LD_LIBRARY_PATH=${PREFIX_DIR}/lib
ENV GUACD_LOG_LEVEL=info
# Copy build artifacts into this stage
COPY --from=builder ${PREFIX_DIR} ${PREFIX_DIR}
# Bring runtime environment up to date and install runtime dependencies
RUN apk add --no-cache \
ca-certificates \
ghostscript \
netcat-openbsd \
shadow \
terminus-font \
ttf-dejavu \
ttf-liberation \
util-linux-login && \
xargs apk add --no-cache < ${PREFIX_DIR}/DEPENDENCIES
# Checks the operating status every 5 minutes with a timeout of 5 seconds
HEALTHCHECK --interval=5m --timeout=5s CMD nc -z 127.0.0.1 4822 || exit 1
# Create a new user guacd
ARG UID=1000
ARG GID=1000
RUN groupadd --gid $GID guacd
RUN useradd --system --create-home --shell /sbin/nologin --uid $UID --gid $GID guacd
# Run with user guacd
USER guacd
# Expose the default listener port
EXPOSE 4822
# Start guacd, listening on port 0.0.0.0:4822 # Start guacd, listening on port 0.0.0.0:4822
EXPOSE 4822 #
CMD [ "/usr/local/sbin/guacd", "-b", "0.0.0.0", "-f" ] # Note the path here MUST correspond to the value specified in the
# PREFIX_DIR build argument.
#
CMD /opt/guacamole/sbin/guacd -b 0.0.0.0 -L $GUACD_LOG_LEVEL -f

View File

@ -16,28 +16,34 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
# #
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
# Subprojects # Subprojects
DIST_SUBDIRS = \ DIST_SUBDIRS = \
src/libguac \ src/libguac \
src/common \ src/common \
src/common-ssh \ src/common-ssh \
src/terminal \ src/terminal \
src/guacd \ src/guacd \
src/guacenc \ src/guacenc \
src/pulse \ src/guaclog \
src/protocols/rdp \ src/pulse \
src/protocols/ssh \ src/protocols/kubernetes \
src/protocols/telnet \ src/protocols/rdp \
src/protocols/vnc \ src/protocols/ssh \
tests src/protocols/telnet \
src/protocols/vnc
SUBDIRS = \ SUBDIRS = \
src/libguac \ src/libguac \
src/common \ src/common
tests
if ENABLE_COMMON_SSH if ENABLE_COMMON_SSH
SUBDIRS += src/common-ssh SUBDIRS += src/common-ssh
@ -51,6 +57,10 @@ if ENABLE_PULSE
SUBDIRS += src/pulse SUBDIRS += src/pulse
endif endif
if ENABLE_KUBERNETES
SUBDIRS += src/protocols/kubernetes
endif
if ENABLE_RDP if ENABLE_RDP
SUBDIRS += src/protocols/rdp SUBDIRS += src/protocols/rdp
endif endif
@ -75,14 +85,19 @@ if ENABLE_GUACENC
SUBDIRS += src/guacenc SUBDIRS += src/guacenc
endif endif
EXTRA_DIST = \ if ENABLE_GUACLOG
.dockerignore \ SUBDIRS += src/guaclog
CONTRIBUTING \ endif
DISCLAIMER \
Dockerfile \ EXTRA_DIST = \
LICENSE \ .dockerignore \
NOTICE \ CONTRIBUTING \
bin/guacctl \ Dockerfile \
doc/Doxyfile \ LICENSE \
src/guacd-docker NOTICE \
bin/guacctl \
doc/libguac/Doxyfile.in \
doc/libguac-terminal/Doxyfile.in \
src/guacd-docker \
util/generate-test-runner.pl

2
NOTICE
View File

@ -1,5 +1,5 @@
Apache Guacamole Apache Guacamole
Copyright 2017 The Apache Software Foundation Copyright 2020 The Apache Software Foundation
This product includes software developed at This product includes software developed at
The Apache Software Foundation (http://www.apache.org/). The Apache Software Foundation (http://www.apache.org/).

6
README
View File

@ -8,11 +8,11 @@ technical users intending to compile parts of Apache Guacamole themselves.
Source archives are available from the downloads section of the project website: Source archives are available from the downloads section of the project website:
http://guacamole.incubator.apache.org/ http://guacamole.apache.org/
A full manual is available as well: A full manual is available as well:
http://guacamole.incubator.apache.org/doc/gug/ http://guacamole.apache.org/doc/gug/
------------------------------------------------------------ ------------------------------------------------------------
@ -25,7 +25,7 @@ libraries.
guacd is the Guacamole proxy daemon used by the Guacamole web application and guacd is the Guacamole proxy daemon used by the Guacamole web application and
framework. As JavaScript cannot handle binary protocols (like VNC and remote framework. As JavaScript cannot handle binary protocols (like VNC and remote
desktop) efficiently, a new test-based protocol was developed which would desktop) efficiently, a new text-based protocol was developed which would
contain a common superset of the operations needed for efficient remote desktop contain a common superset of the operations needed for efficient remote desktop
access, but would be easy for JavaScript programs to process. guacd is the access, but would be easy for JavaScript programs to process. guacd is the
proxy which translates between arbitrary protocols and the Guacamole protocol. proxy which translates between arbitrary protocols and the Guacamole protocol.

89
README-unit-testing.md Normal file
View File

@ -0,0 +1,89 @@
Unit testing and guacamole-server
=================================
Unit tests within guacamole-server are implemented using the following:
* automake, which allows arbitrary tests to be declared within `Makefile.am`
and uses `make check` to run those tests.
* CUnit (libcunit), a unit testing framework.
* `util/generate-test-runner.pl`, a Perl script which generates a test runner
written in C which leverages CUnit, running the unit tests declared in each
of the given `.c` files. The generated test runner produces output in [TAP
format](https://testanything.org/) which is consumed by the TAP test driver
provided by automake.
Writing unit tests
------------------
All unit tests should be within reasonably-isolated C source files, with each
logical test having its own function of the form:
void test_SUITENAME__TESTNAME() {
...
}
where `TESTNAME` is the arbitrary name of the test and `SUITENAME` is the
arbitrary name of the test suite that this test belongs to.
**This naming convention is required by `generate-test-runner.pl`.** Absolutely
all tests MUST follow the above convention if they are to be picked up and
organized by the test runner generation script. Functions which are not tests
MUST NOT follow the above convention so that they are _not_ picked up mistakenly
by the test runner generator as if they were tests.
The `Makefile.am` for a subproject which contains such tests is typically
modified to contain a sections like the following:
#
# Unit tests for myproj
#
check_PROGRAMS = test_myproj
TESTS = $(check_PROGRAMS)
test_myproj_SOURCES = \
...all source files...
test_myproj_CFLAGS = \
-Werror -Wall -pedantic \
...other flags...
test_myproj_LDADD = \
...libraries...
#
# Autogenerate test runner
#
GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
CLEANFILES = _generated_runner.c
_generated_runner.c: $(test_myproj_SOURCES)
$(AM_V_GEN) $(GEN_RUNNER) $(test_myproj_SOURCES) > $@
nodist_test_libguac_SOURCES = \
_generated_runner.c
# Use automake's TAP test driver for running any tests
LOG_DRIVER = \
env AM_TAP_AWK='$(AWK)' \
$(SHELL) $(top_srcdir)/build-aux/tap-driver.sh
The above declares ...
* ... that a binary, `test_myproj` should be built from the given sources.
Note that `test_myproj_SOURCES` contains only the source which was actually
written by hand while `nodist_test_myproj_SOURCES` contains only the source
which was generated by `generate-test-runner.pl`.
* ... that this `test_myproj` binary should be run to test this project when
`make check` is run, and that automake's TAP driver should be used to
consume its output.
* ... that the `_generated_runner.c` source file is generated dynamically
(through running `generate-test-runner.pl` on all non-generated test source)
and should not be distributed as part of the source archive.
With tests following the above naming convention in place, and with the
necessary changes made to the applicable `Makefile.am`, all tests will be
run automatically when `make check` is run.

View File

@ -90,6 +90,18 @@ send_close_pipe_stream() {
printf "\033]482203;\007" printf "\033]482203;\007"
} }
##
## Sends the Guacamole-specific console code for resizing the scrollback
## buffer.
##
## @param ROWS
## The number of rows that the scrollback buffer should contain.
##
send_resize_scrollback() {
ROWS="$1"
printf "\033]482204;%s\007" "$ROWS"
}
## ##
## Prints the given error text to STDERR. ## Prints the given error text to STDERR.
## ##
@ -105,7 +117,7 @@ error() {
## ##
usage() { usage() {
cat >&2 <<END cat >&2 <<END
guacctl 0.9.11-incubating, Guacamole terminal session control utility. guacctl 1.5.0, Apache Guacamole terminal session control utility.
Usage: guacctl [OPTION] [FILE or NAME]... Usage: guacctl [OPTION] [FILE or NAME]...
-d, --download download each of the files listed. -d, --download download each of the files listed.
@ -115,6 +127,8 @@ Usage: guacctl [OPTION] [FILE or NAME]...
name. name.
-c, --close-pipe close any existing pipe stream and redirect output -c, --close-pipe close any existing pipe stream and redirect output
back to the terminal emulator. back to the terminal emulator.
-S, --scrollback request that the scrollback buffer be limited to the
given number of rows.
END END
} }
@ -243,6 +257,39 @@ close_pipe_stream() {
} }
##
## Resizes the scrollback buffer to the given number of rows.
##
## @param ...
## The number of rows that should be contained within the scrollback
## buffer, as provided to guacctl.
##
resize_scrollback() {
#
# Validate arguments
#
if [ $# -lt 1 ]; then
error "No row count specified."
return;
fi
if [ $# -gt 1 ]; then
error "Only one row count may be given."
return;
fi
#
# Send code for resizing scrollback
#
ROWS="$1"
send_resize_scrollback "$ROWS"
}
# #
# Get script name # Get script name
# #
@ -300,6 +347,15 @@ case "$1" in
close_pipe_stream "$@" close_pipe_stream "$@"
;; ;;
#
# Resize scrollback
#
"--scrollback"|"-S")
shift
resize_scrollback "$@"
;;
# #
# Show usage info if options are invalid # Show usage info if options are invalid
# #

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
#
# Project name / version
#
PROJECT_NAME = libguac-terminal
PROJECT_NUMBER = @PACKAGE_VERSION@
#
# Warn about undocumented parameters and return values, but do not fill output
# with verbose progress info.
#
QUIET = YES
WARN_NO_PARAMDOC = YES
#
# Output format
#
ALPHABETICAL_INDEX = YES
GENERATE_HTML = YES
GENERATE_LATEX = NO
OPTIMIZE_OUTPUT_FOR_C = YES
OUTPUT_DIRECTORY = doxygen-output
RECURSIVE = YES
SHOW_INCLUDE_FILES = NO
#
# Input format
#
CASE_SENSE_NAMES = YES
FILE_PATTERNS = *.h
STRIP_FROM_PATH = ../../src/terminal
INPUT = ../../src/terminal/terminal/terminal.h
JAVADOC_AUTOBRIEF = YES
TAB_SIZE = 4
TYPEDEF_HIDES_STRUCT = YES

View File

@ -22,7 +22,7 @@
# #
PROJECT_NAME = libguac PROJECT_NAME = libguac
PROJECT_NUMBER = 0.9.13-incubating PROJECT_NUMBER = @PACKAGE_VERSION@
# #
# Warn about undocumented parameters and return values, but do not fill output # Warn about undocumented parameters and return values, but do not fill output
@ -52,9 +52,9 @@ SHOW_INCLUDE_FILES = NO
CASE_SENSE_NAMES = YES CASE_SENSE_NAMES = YES
EXCLUDE_SYMBOLS = __* guac_palette* EXCLUDE_SYMBOLS = __* guac_palette*
FILE_PATTERNS = *.h FILE_PATTERNS = *.h
INPUT = ../src/libguac/guacamole INPUT = ../../src/libguac/guacamole
JAVADOC_AUTOBRIEF = YES JAVADOC_AUTOBRIEF = YES
STRIP_FROM_PATH = ../src/libguac STRIP_FROM_PATH = ../../src/libguac
TAB_SIZE = 4 TAB_SIZE = 4
TYPEDEF_HIDES_STRUCT = YES TYPEDEF_HIDES_STRUCT = YES

5
src/common-ssh/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Auto-generated test runner and binary
_generated_runner.c
test_common_ssh

View File

@ -16,16 +16,21 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
# #
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
noinst_LTLIBRARIES = libguac_common_ssh.la noinst_LTLIBRARIES = libguac_common_ssh.la
SUBDIRS = . tests
libguac_common_ssh_la_SOURCES = \ libguac_common_ssh_la_SOURCES = \
buffer.c \ buffer.c \
dsa-compat.c \
rsa-compat.c \
sftp.c \ sftp.c \
ssh.c \ ssh.c \
key.c \ key.c \
@ -33,8 +38,6 @@ libguac_common_ssh_la_SOURCES = \
noinst_HEADERS = \ noinst_HEADERS = \
common-ssh/buffer.h \ common-ssh/buffer.h \
common-ssh/dsa-compat.h \
common-ssh/rsa-compat.h \
common-ssh/key.h \ common-ssh/key.h \
common-ssh/sftp.h \ common-ssh/sftp.h \
common-ssh/ssh.h \ common-ssh/ssh.h \

View File

@ -1,61 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef GUAC_COMMON_SSH_DSA_COMPAT_H
#define GUAC_COMMON_SSH_DSA_COMPAT_H
#include "config.h"
#include <openssl/bn.h>
#include <openssl/dsa.h>
#ifndef HAVE_DSA_GET0_PQG
/**
* DSA_get0_pqg() implementation for versions of OpenSSL which lack this
* function (pre 1.1).
*
* See: https://www.openssl.org/docs/man1.1.0/crypto/DSA_get0_pqg.html
*/
void DSA_get0_pqg(const DSA* dsa_key, const BIGNUM** p,
const BIGNUM** q, const BIGNUM** g);
#endif
#ifndef HAVE_DSA_GET0_KEY
/**
* DSA_get0_key() implementation for versions of OpenSSL which lack this
* function (pre 1.1).
*
* See: https://www.openssl.org/docs/man1.1.0/crypto/DSA_get0_key.html
*/
void DSA_get0_key(const DSA* dsa_key, const BIGNUM** pub_key,
const BIGNUM** priv_key);
#endif
#ifndef HAVE_DSA_SIG_GET0
/**
* DSA_SIG_get0() implementation for versions of OpenSSL which lack this
* function (pre 1.1).
*
* See: https://www.openssl.org/docs/man1.1.0/crypto/DSA_SIG_get0.html
*/
void DSA_SIG_get0(const DSA_SIG* dsa_sig, const BIGNUM** r, const BIGNUM** s);
#endif
#endif

View File

@ -22,75 +22,30 @@
#include "config.h" #include "config.h"
#include <openssl/ossl_typ.h> #include <guacamole/client.h>
#include <libssh2.h>
/** /**
* The expected header of RSA private keys. * OpenSSH v1 private keys are PEM-wrapped base64-encoded blobs. The encoded data begins with:
* "openssh-key-v1\0"
*/ */
#define SSH_RSA_KEY_HEADER "-----BEGIN RSA PRIVATE KEY-----" #define OPENSSH_V1_KEY_HEADER "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEA"
/** /**
* The expected header of DSA private keys. * The base64-encoded prefix indicating an OpenSSH v1 private key is NOT protected by a
* passphrase. Specifically, it is the following data fields and values:
* pascal string: cipher name ("none")
* pascal string: kdf name ("none")
* pascal string: kdf params (NULL)
* 32-bit int: number of keys (1)
*/ */
#define SSH_DSA_KEY_HEADER "-----BEGIN DSA PRIVATE KEY-----" #define OPENSSH_V1_UNENCRYPTED_KEY "AAAABG5vbmUAAAAEbm9uZQAAAAAAAAAB"
/**
* The size of single number within a DSA signature, in bytes.
*/
#define DSA_SIG_NUMBER_SIZE 20
/**
* The size of a DSA signature, in bytes.
*/
#define DSA_SIG_SIZE DSA_SIG_NUMBER_SIZE*2
/**
* The type of an SSH key.
*/
typedef enum guac_common_ssh_key_type {
/**
* RSA key.
*/
SSH_KEY_RSA,
/**
* DSA key.
*/
SSH_KEY_DSA
} guac_common_ssh_key_type;
/** /**
* Abstraction of a key used for SSH authentication. * Abstraction of a key used for SSH authentication.
*/ */
typedef struct guac_common_ssh_key { typedef struct guac_common_ssh_key {
/**
* The type of this key.
*/
guac_common_ssh_key_type type;
/**
* Underlying RSA private key, if any.
*/
RSA* rsa;
/**
* Underlying DSA private key, if any.
*/
DSA* dsa;
/**
* The associated public key, encoded as necessary for SSH.
*/
char* public_key;
/**
* The length of the public key, in bytes.
*/
int public_key_length;
/** /**
* The private key, encoded as necessary for SSH. * The private key, encoded as necessary for SSH.
*/ */
@ -101,6 +56,11 @@ typedef struct guac_common_ssh_key {
*/ */
int private_key_length; int private_key_length;
/**
* The private key's passphrase, if any.
*/
char *passphrase;
} guac_common_ssh_key; } guac_common_ssh_key;
/** /**
@ -142,29 +102,51 @@ const char* guac_common_ssh_key_error();
void guac_common_ssh_key_free(guac_common_ssh_key* key); void guac_common_ssh_key_free(guac_common_ssh_key* key);
/** /**
* Signs the given data using the given key, returning the length of the * Verifies the host key for the given hostname/port combination against
* signature in bytes, or a value less than zero on error. * one or more known_hosts entries. The known_host entries can either be a
* single host_key, provided by the client, or a set of known_hosts entries
* provided in the /etc/guacamole/ssh_known_hosts file. Failure to correctly
* load the known_hosts entries will result in a connection abort and a returned
* error code. A return code of zero indiciates that either no known_hosts entries
* were provided, or that the verification succeeded (match). Negative values
* indicate internal libssh2 error codes; positive values indicate a failure
* during verification of the host key against the known hosts.
* *
* @param key * @param session
* The key to use when signing the given data. * A pointer to the LIBSSH2_SESSION structure of the SSH connection already
* in progress.
* *
* @param data * @param client
* The arbitrary data to sign. * The current guac_client instance for which the known_hosts checking is
* being performed.
* *
* @param length * @param host_key
* The length of the arbitrary data being signed, in bytes. * The known host entry provided by the client. If this is non-null and not
* empty, it will be the only host key loaded and used for verification. If
* this is null or empty an attempt will be made to read the
* /etc/guacamole/ssh_known_hosts file and load entries from it.
* *
* @param sig * @param hostname
* The buffer into which the signature should be written. The buffer must * The hostname or IP of the server that is being verified.
* be at least DSA_SIG_SIZE for DSA keys. For RSA keys, the signature size *
* is dependent only on key size, and is equal to the length of the * @param port
* modulus, in bytes. * The port number of the server being verified.
*
* @param remote_hostkey
* The host key of the remote system being verified.
*
* @param remote_hostkey_len
* The length of the remote host key being verified
* *
* @return * @return
* The number of bytes in the resulting signature. * The status of the known_hosts check. This will be zero if no entries
* are provided or if the match succeeds, negative to indicate internal
* libssh2 errors, or positive to indicate failures during host key
* checking.
*/ */
int guac_common_ssh_key_sign(guac_common_ssh_key* key, const char* data, int guac_common_ssh_verify_host_key(LIBSSH2_SESSION* session, guac_client* client,
int length, unsigned char* sig); const char* host_key, const char* hostname, int port, const char* remote_hostkey,
const size_t remote_hostkey_len);
#endif #endif

View File

@ -70,6 +70,16 @@ typedef struct guac_common_ssh_sftp_filesystem {
*/ */
char upload_path[GUAC_COMMON_SSH_SFTP_MAX_PATH]; char upload_path[GUAC_COMMON_SSH_SFTP_MAX_PATH];
/**
* If downloads from SFTP to the local browser should be disabled.
*/
int disable_download;
/**
* If uploads from the local browser to SFTP should be disabled.
*/
int disable_upload;
} guac_common_ssh_sftp_filesystem; } guac_common_ssh_sftp_filesystem;
/** /**
@ -123,12 +133,19 @@ typedef struct guac_common_ssh_sftp_ls_state {
* to a user, or NULL to automatically generate a name from the provided * to a user, or NULL to automatically generate a name from the provided
* root_path. * root_path.
* *
* @param disable_download
* Whether downloads from the SFTP share to the local browser should be
* disabled.
*
* @param disable_upload
* Whether uploads from the local browser to SFTP should be disabled.
*
* @return * @return
* A new SFTP filesystem object, not yet exposed to users. * A new SFTP filesystem object, not yet exposed to users.
*/ */
guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem( guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem(
guac_common_ssh_session* session, const char* root_path, guac_common_ssh_session* session, const char* root_path,
const char* name); const char* name, int disable_download, int disable_upload);
/** /**
* Destroys the given filesystem object, disconnecting from SFTP and freeing * Destroys the given filesystem object, disconnecting from SFTP and freeing
@ -255,5 +272,30 @@ int guac_common_ssh_sftp_handle_file_stream(
void guac_common_ssh_sftp_set_upload_path( void guac_common_ssh_sftp_set_upload_path(
guac_common_ssh_sftp_filesystem* filesystem, const char* path); guac_common_ssh_sftp_filesystem* filesystem, const char* path);
/**
* Given an arbitrary absolute path, which may contain "..", ".", and
* backslashes, creates an equivalent absolute path which does NOT contain
* relative path components (".." or "."), backslashes, or empty path
* components. With the exception of paths referring to the root directory, the
* resulting path is guaranteed to not contain trailing slashes.
*
* Normalization will fail if the given path is not absolute, is too long, or
* contains more than GUAC_COMMON_SSH_SFTP_MAX_DEPTH path components.
*
* @param fullpath
* The buffer to populate with the normalized path. The normalized path
* will not contain relative path components like ".." or ".", nor will it
* contain backslashes. This buffer MUST be at least
* GUAC_COMMON_SSH_SFTP_MAX_PATH bytes in size.
*
* @param path
* The absolute path to normalize.
*
* @return
* Non-zero if normalization succeeded, zero otherwise.
*/
int guac_common_ssh_sftp_normalize_path(char* fullpath,
const char* path);
#endif #endif

View File

@ -25,6 +25,23 @@
#include <guacamole/client.h> #include <guacamole/client.h>
#include <libssh2.h> #include <libssh2.h>
/**
* Handler for retrieving additional credentials.
*
* @param client
* The Guacamole Client associated with this need for additional
* credentials.
*
* @param cred_name
* The name of the credential being requested, which will be shared
* with the client in order to generate a meaningful prompt.
*
* @return
* A newly-allocated string containing the credentials provided by
* the user, which must be freed by a call to free().
*/
typedef char* guac_ssh_credential_handler(guac_client* client, char* cred_name);
/** /**
* An SSH session, backed by libssh2 and associated with a particular * An SSH session, backed by libssh2 and associated with a particular
* Guacamole client. * Guacamole client.
@ -51,6 +68,11 @@ typedef struct guac_common_ssh_session {
*/ */
int fd; int fd;
/**
* Callback function to retrieve credentials.
*/
guac_ssh_credential_handler* credential_handler;
} guac_common_ssh_session; } guac_common_ssh_session;
/** /**
@ -93,12 +115,31 @@ void guac_common_ssh_uninit();
* @param user * @param user
* The user to authenticate as, once connected. * The user to authenticate as, once connected.
* *
* @param keepalive
* How frequently the connection should send keepalive packets, in
* seconds. Zero disables keepalive packets, and 2 is the minimum
* configurable value.
*
* @param host_key
* The known public host key of the server, as provided by the client. If
* provided the identity of the server will be checked against this key,
* and a mis-match between this and the server identity will cause the
* connection to fail. If not provided, no checks will be done and the
* connection will proceed.
*
* @param credential_handler
* The handler function for retrieving additional credentials from the user
* as required by the SSH server, or NULL if the user will not be asked
* for additional credentials.
*
* @return * @return
* A new SSH session if the connection and authentication succeed, or NULL * A new SSH session if the connection and authentication succeed, or NULL
* if the connection or authentication were not successful. * if the connection or authentication were not successful.
*/ */
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive); const char* hostname, const char* port, guac_common_ssh_user* user,
int keepalive, const char* host_key,
guac_ssh_credential_handler* credential_handler);
/** /**
* Disconnects and destroys the given SSH session, freeing all associated * Disconnects and destroys the given SSH session, freeing all associated

View File

@ -1,59 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "config.h"
#include <openssl/bn.h>
#include <openssl/dsa.h>
#include <stdlib.h>
#ifndef HAVE_DSA_GET0_PQG
void DSA_get0_pqg(const DSA* dsa_key, const BIGNUM** p,
const BIGNUM** q, const BIGNUM** g) {
/* Retrieve all requested internal values */
if (p != NULL) *p = dsa_key->p;
if (q != NULL) *q = dsa_key->q;
if (g != NULL) *g = dsa_key->g;
}
#endif
#ifndef HAVE_DSA_GET0_KEY
void DSA_get0_key(const DSA* dsa_key, const BIGNUM** pub_key,
const BIGNUM** priv_key) {
/* Retrieve all requested internal values */
if (pub_key != NULL) *pub_key = dsa_key->pub_key;
if (priv_key != NULL) *priv_key = dsa_key->priv_key;
}
#endif
#ifndef HAVE_DSA_SIG_GET0
void DSA_SIG_get0(const DSA_SIG* dsa_sig, const BIGNUM** r, const BIGNUM** s) {
/* Retrieve all requested internal values */
if (r != NULL) *r = dsa_sig->r;
if (s != NULL) *s = dsa_sig->s;
}
#endif

View File

@ -20,9 +20,9 @@
#include "config.h" #include "config.h"
#include "common-ssh/buffer.h" #include "common-ssh/buffer.h"
#include "common-ssh/dsa-compat.h"
#include "common-ssh/key.h" #include "common-ssh/key.h"
#include "common-ssh/rsa-compat.h"
#include <guacamole/string.h>
#include <openssl/bio.h> #include <openssl/bio.h>
#include <openssl/bn.h> #include <openssl/bn.h>
@ -33,118 +33,118 @@
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
/**
* Check for a PKCS#1/PKCS#8 ENCRYPTED marker.
*
* @param data
* The buffer to scan.
* @param length
* The length of the buffer.
*
* @return
* True if the buffer contains the marker, false otherwise.
*/
static bool is_pkcs_encrypted_key(char* data, int length) {
return guac_strnstr(data, "ENCRYPTED", length) != NULL;
}
/**
* Check for a PEM header & initial base64-encoded data indicating this is an
* OpenSSH v1 key.
*
* @param data
* The buffer to scan.
* @param length
* The length of the buffer.
*
* @return
* True if the buffer contains a private key, false otherwise.
*/
static bool is_ssh_private_key(char* data, int length) {
if (length < sizeof(OPENSSH_V1_KEY_HEADER) - 1) {
return false;
}
return !strncmp(data, OPENSSH_V1_KEY_HEADER, sizeof(OPENSSH_V1_KEY_HEADER) - 1);
}
/**
* Assuming an offset into a key past the header, check for the base64-encoded
* data indicating this key is not protected by a passphrase.
*
* @param data
* The buffer to scan.
* @param length
* The length of the buffer.
*
* @return
* True if the buffer contains an unencrypted key, false otherwise.
*/
static bool is_ssh_key_unencrypted(char* data, int length) {
if (length < sizeof(OPENSSH_V1_UNENCRYPTED_KEY) - 1) {
return false;
}
return !strncmp(data, OPENSSH_V1_UNENCRYPTED_KEY, sizeof(OPENSSH_V1_UNENCRYPTED_KEY) - 1);
}
/**
* A passphrase is needed if the key is an encrypted PKCS#1/PKCS#8 key OR if
* the key is both an OpenSSH v1 key AND there isn't a marker indicating the
* key is unprotected.
*
* @param data
* The buffer to scan.
* @param length
* The length of the buffer.
*
* @return
* True if the buffer contains a key needing a passphrase, false otherwise.
*/
static bool is_passphrase_needed(char* data, int length) {
/* Is this an encrypted PKCS#1/PKCS#8 key? */
if (is_pkcs_encrypted_key(data, length)) {
return true;
}
/* Is this an OpenSSH v1 key? */
if (is_ssh_private_key(data, length)) {
/* This is safe due to the check in is_ssh_private_key. */
data += sizeof(OPENSSH_V1_KEY_HEADER) - 1;
length -= sizeof(OPENSSH_V1_KEY_HEADER) - 1;
/* If this is NOT unprotected, we need a passphrase. */
if (!is_ssh_key_unencrypted(data, length)) {
return true;
}
}
return false;
}
guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length, guac_common_ssh_key* guac_common_ssh_key_alloc(char* data, int length,
char* passphrase) { char* passphrase) {
guac_common_ssh_key* key; /* Because libssh2 will do the actual key parsing (to let it deal with
BIO* key_bio; * different key algorithms) we need to perform a heuristic here to check
* if a passphrase is needed. This could allow junk keys through that
* would never be able to auth. libssh2 should display errors to help
* admins track down malformed keys and delete or replace them.
*/
char* public_key; if (is_passphrase_needed(data, length) && (passphrase == NULL || *passphrase == '\0'))
char* pos;
/* Create BIO for reading key from memory */
key_bio = BIO_new_mem_buf(data, length);
/* If RSA key, load RSA */
if (length > sizeof(SSH_RSA_KEY_HEADER)-1
&& memcmp(SSH_RSA_KEY_HEADER, data,
sizeof(SSH_RSA_KEY_HEADER)-1) == 0) {
RSA* rsa_key;
const BIGNUM* key_e;
const BIGNUM* key_n;
/* Read key */
rsa_key = PEM_read_bio_RSAPrivateKey(key_bio, NULL, NULL, passphrase);
if (rsa_key == NULL)
return NULL;
/* Allocate key */
key = malloc(sizeof(guac_common_ssh_key));
key->rsa = rsa_key;
/* Set type */
key->type = SSH_KEY_RSA;
/* Allocate space for public key */
public_key = malloc(4096);
pos = public_key;
/* Retrieve public key */
RSA_get0_key(rsa_key, &key_n, &key_e, NULL);
/* Send public key formatted for SSH */
guac_common_ssh_buffer_write_string(&pos, "ssh-rsa", sizeof("ssh-rsa")-1);
guac_common_ssh_buffer_write_bignum(&pos, key_e);
guac_common_ssh_buffer_write_bignum(&pos, key_n);
/* Save public key to structure */
key->public_key = public_key;
key->public_key_length = pos - public_key;
}
/* If DSA key, load DSA */
else if (length > sizeof(SSH_DSA_KEY_HEADER)-1
&& memcmp(SSH_DSA_KEY_HEADER, data,
sizeof(SSH_DSA_KEY_HEADER)-1) == 0) {
DSA* dsa_key;
const BIGNUM* key_p;
const BIGNUM* key_q;
const BIGNUM* key_g;
const BIGNUM* pub_key;
/* Read key */
dsa_key = PEM_read_bio_DSAPrivateKey(key_bio, NULL, NULL, passphrase);
if (dsa_key == NULL)
return NULL;
/* Allocate key */
key = malloc(sizeof(guac_common_ssh_key));
key->dsa = dsa_key;
/* Set type */
key->type = SSH_KEY_DSA;
/* Allocate space for public key */
public_key = malloc(4096);
pos = public_key;
/* Retrieve public key */
DSA_get0_pqg(dsa_key, &key_p, &key_q, &key_g);
DSA_get0_key(dsa_key, &pub_key, NULL);
/* Send public key formatted for SSH */
guac_common_ssh_buffer_write_string(&pos, "ssh-dss", sizeof("ssh-dss")-1);
guac_common_ssh_buffer_write_bignum(&pos, key_p);
guac_common_ssh_buffer_write_bignum(&pos, key_q);
guac_common_ssh_buffer_write_bignum(&pos, key_g);
guac_common_ssh_buffer_write_bignum(&pos, pub_key);
/* Save public key to structure */
key->public_key = public_key;
key->public_key_length = pos - public_key;
}
/* Otherwise, unsupported type */
else {
BIO_free(key_bio);
return NULL; return NULL;
}
guac_common_ssh_key* key = malloc(sizeof(guac_common_ssh_key));
/* Copy private key to structure */ /* Copy private key to structure */
key->private_key_length = length; key->private_key_length = length;
key->private_key = malloc(length); key->private_key = malloc(length);
memcpy(key->private_key, data, length); memcpy(key->private_key, data, length);
key->passphrase = strdup(passphrase);
BIO_free(key_bio);
return key; return key;
} }
@ -158,90 +158,91 @@ const char* guac_common_ssh_key_error() {
void guac_common_ssh_key_free(guac_common_ssh_key* key) { void guac_common_ssh_key_free(guac_common_ssh_key* key) {
/* Free key-specific data */
if (key->type == SSH_KEY_RSA)
RSA_free(key->rsa);
else if (key->type == SSH_KEY_DSA)
DSA_free(key->dsa);
free(key->private_key); free(key->private_key);
free(key->public_key); free(key->passphrase);
free(key); free(key);
} }
int guac_common_ssh_key_sign(guac_common_ssh_key* key, const char* data, int guac_common_ssh_verify_host_key(LIBSSH2_SESSION* session, guac_client* client,
int length, unsigned char* sig) { const char* host_key, const char* hostname, int port, const char* remote_hostkey,
const size_t remote_hostkey_len) {
const EVP_MD* md; LIBSSH2_KNOWNHOSTS* ssh_known_hosts = libssh2_knownhost_init(session);
int known_hosts = 0;
unsigned char digest[EVP_MAX_MD_SIZE]; /* Add host key provided from settings */
unsigned int dlen, len; if (host_key && strcmp(host_key, "") != 0) {
/* Get SHA1 digest */ known_hosts = libssh2_knownhost_readline(ssh_known_hosts, host_key, strlen(host_key),
if ((md = EVP_get_digestbynid(NID_sha1)) == NULL) LIBSSH2_KNOWNHOST_FILE_OPENSSH);
return -1;
/* Allocate digest context */ /* readline function returns 0 on success, so we increment to indicate a valid entry */
EVP_MD_CTX* md_ctx = EVP_MD_CTX_create(); if (known_hosts == 0)
if (md_ctx == NULL) known_hosts++;
return -1;
/* Digest data */
EVP_DigestInit(md_ctx, md);
EVP_DigestUpdate(md_ctx, data, length);
EVP_DigestFinal(md_ctx, digest, &dlen);
/* Digest context no longer needed */
EVP_MD_CTX_destroy(md_ctx);
/* Sign with key */
switch (key->type) {
case SSH_KEY_RSA:
if (RSA_sign(NID_sha1, digest, dlen, sig, &len, key->rsa) == 1)
return len;
break;
case SSH_KEY_DSA: {
DSA_SIG* dsa_sig = DSA_do_sign(digest, dlen, key->dsa);
if (dsa_sig != NULL) {
const BIGNUM* sig_r;
const BIGNUM* sig_s;
/* Retrieve DSA signature values */
DSA_SIG_get0(dsa_sig, &sig_r, &sig_s);
/* Compute size of each half of signature */
int rlen = BN_num_bytes(sig_r);
int slen = BN_num_bytes(sig_s);
/* Ensure each number is within the required size */
if (rlen > DSA_SIG_NUMBER_SIZE || slen > DSA_SIG_NUMBER_SIZE)
return -1;
/* Init to all zeroes */
memset(sig, 0, DSA_SIG_SIZE);
/* Add R at the end of the first block of the signature */
BN_bn2bin(sig_r, sig + DSA_SIG_SIZE
- DSA_SIG_NUMBER_SIZE - rlen);
/* Add S at the end of the second block of the signature */
BN_bn2bin(sig_s, sig + DSA_SIG_SIZE - slen);
/* Done */
DSA_SIG_free(dsa_sig);
return DSA_SIG_SIZE;
}
}
} }
return -1; /* Otherwise, we look for a ssh_known_hosts file within GUACAMOLE_HOME and read that in. */
else {
const char *guac_known_hosts = "/etc/guacamole/ssh_known_hosts";
if (access(guac_known_hosts, F_OK) != -1)
known_hosts = libssh2_knownhost_readfile(ssh_known_hosts, guac_known_hosts, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
}
/* If there's an error provided, abort connection and return that. */
if (known_hosts < 0) {
char* errmsg;
int errval = libssh2_session_last_error(session, &errmsg, NULL, 0);
guac_client_log(client, GUAC_LOG_ERROR,
"Error %d trying to load SSH host keys: %s", errval, errmsg);
libssh2_knownhost_free(ssh_known_hosts);
return known_hosts;
}
/* No host keys were loaded, so we bail out checking and continue the connection. */
else if (known_hosts == 0) {
guac_client_log(client, GUAC_LOG_WARNING,
"No known host keys provided, host identity will not be verified.");
libssh2_knownhost_free(ssh_known_hosts);
return known_hosts;
}
/* Check remote host key against known hosts */
int kh_check = libssh2_knownhost_checkp(ssh_known_hosts, hostname, port,
remote_hostkey, remote_hostkey_len,
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
LIBSSH2_KNOWNHOST_KEYENC_RAW,
NULL);
/* Deal with the return of the host key check */
switch (kh_check) {
case LIBSSH2_KNOWNHOST_CHECK_MATCH:
guac_client_log(client, GUAC_LOG_DEBUG,
"Host key match found for %s", hostname);
break;
case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
guac_client_log(client, GUAC_LOG_ERROR,
"Host key not found for %s.", hostname);
break;
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
guac_client_log(client, GUAC_LOG_ERROR,
"Host key does not match known hosts entry for %s", hostname);
break;
case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
default:
guac_client_log(client, GUAC_LOG_ERROR,
"Host %s could not be checked against known hosts.",
hostname);
}
/* Return the check value */
libssh2_knownhost_free(ssh_known_hosts);
return kh_check;
} }

View File

@ -24,6 +24,7 @@
#include <guacamole/object.h> #include <guacamole/object.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/socket.h> #include <guacamole/socket.h>
#include <guacamole/string.h>
#include <guacamole/user.h> #include <guacamole/user.h>
#include <libssh2.h> #include <libssh2.h>
@ -32,107 +33,70 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/** int guac_common_ssh_sftp_normalize_path(char* fullpath,
* Given an arbitrary absolute path, which may contain "..", ".", and
* backslashes, creates an equivalent absolute path which does NOT contain
* relative path components (".." or "."), backslashes, or empty path
* components. With the exception of paths referring to the root directory, the
* resulting path is guaranteed to not contain trailing slashes.
*
* Normalization will fail if the given path is not absolute, is too long, or
* contains more than GUAC_COMMON_SSH_SFTP_MAX_DEPTH path components.
*
* @param fullpath
* The buffer to populate with the normalized path. The normalized path
* will not contain relative path components like ".." or ".", nor will it
* contain backslashes. This buffer MUST be at least
* GUAC_COMMON_SSH_SFTP_MAX_PATH bytes in size.
*
* @param path
* The absolute path to normalize.
*
* @return
* Non-zero if normalization succeeded, zero otherwise.
*/
static int guac_common_ssh_sftp_normalize_path(char* fullpath,
const char* path) { const char* path) {
int i;
int path_depth = 0; int path_depth = 0;
char path_component_data[GUAC_COMMON_SSH_SFTP_MAX_PATH];
const char* path_components[GUAC_COMMON_SSH_SFTP_MAX_DEPTH]; const char* path_components[GUAC_COMMON_SSH_SFTP_MAX_DEPTH];
const char** current_path_component = &(path_components[0]);
const char* current_path_component_data = &(path_component_data[0]);
/* If original path is not absolute, normalization fails */ /* If original path is not absolute, normalization fails */
if (path[0] != '\\' && path[0] != '/') if (path[0] != '\\' && path[0] != '/')
return 1; return 0;
/* Skip past leading slash */ /* Create scratch copy of path excluding leading slash (we will be
path++; * replacing path separators with null terminators and referencing those
* substrings directly as path components) */
char path_scratch[GUAC_COMMON_SSH_SFTP_MAX_PATH - 1];
int length = guac_strlcpy(path_scratch, path + 1,
sizeof(path_scratch));
/* Copy path into component data for parsing */ /* Fail if provided path is too long */
strncpy(path_component_data, path, sizeof(path_component_data) - 1); if (length >= sizeof(path_scratch))
return 0;
/* Find path components within path */ /* Locate all path components within path */
for (i = 0; i < sizeof(path_component_data) - 1; i++) { const char* current_path_component = &(path_scratch[0]);
for (int i = 0; i <= length; i++) {
/* If current character is a path separator, parse as component */ /* If current character is a path separator, parse as component */
char c = path_component_data[i]; char c = path_scratch[i];
if (c == '/' || c == '\\' || c == '\0') { if (c == '/' || c == '\\' || c == '\0') {
/* Terminate current component */ /* Terminate current component */
path_component_data[i] = '\0'; path_scratch[i] = '\0';
/* If component refers to parent, just move up in depth */ /* If component refers to parent, just move up in depth */
if (strcmp(current_path_component_data, "..") == 0) { if (strcmp(current_path_component, "..") == 0) {
if (path_depth > 0) if (path_depth > 0)
path_depth--; path_depth--;
} }
/* Otherwise, if component not current directory, add to list */ /* Otherwise, if component not current directory, add to list */
else if (strcmp(current_path_component_data, ".") != 0 else if (strcmp(current_path_component, ".") != 0
&& strcmp(current_path_component_data, "") != 0) && strcmp(current_path_component, "") != 0) {
path_components[path_depth++] = current_path_component_data;
/* If end of string, stop */ /* Fail normalization if path is too deep */
if (c == '\0') if (path_depth >= GUAC_COMMON_SSH_SFTP_MAX_DEPTH)
break; return 0;
path_components[path_depth++] = current_path_component;
}
/* Update start of next component */ /* Update start of next component */
current_path_component_data = &(path_component_data[i+1]); current_path_component = &(path_scratch[i+1]);
} /* end if separator */ } /* end if separator */
} /* end for each character */ } /* end for each character */
/* If no components, the path is simply root */ /* Add leading slash for resulting absolute path */
if (path_depth == 0) { fullpath[0] = '/';
strcpy(fullpath, "/");
return 1;
}
/* Ensure last component is null-terminated */ /* Append normalized components to path, separated by slashes */
path_component_data[i] = 0; guac_strljoin(fullpath + 1, path_components, path_depth,
"/", GUAC_COMMON_SSH_SFTP_MAX_PATH - 1);
/* Convert components back into path */
for (; path_depth > 0; path_depth--) {
const char* filename = *(current_path_component++);
/* Add separator */
*(fullpath++) = '/';
/* Copy string */
while (*filename != 0)
*(fullpath++) = *(filename++);
}
/* Terminate absolute path */
*(fullpath++) = 0;
return 1; return 1;
} }
@ -229,7 +193,7 @@ static guac_protocol_status guac_sftp_get_status(
static int guac_ssh_append_filename(char* fullpath, const char* path, static int guac_ssh_append_filename(char* fullpath, const char* path,
const char* filename) { const char* filename) {
int i; int length;
/* Disallow "." as a filename */ /* Disallow "." as a filename */
if (strcmp(filename, ".") == 0) if (strcmp(filename, ".") == 0)
@ -239,49 +203,29 @@ static int guac_ssh_append_filename(char* fullpath, const char* path,
if (strcmp(filename, "..") == 0) if (strcmp(filename, "..") == 0)
return 0; return 0;
/* Copy path, append trailing slash */ /* Filenames may not contain slashes */
for (i=0; i<GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) { if (strchr(filename, '/') != NULL)
/*
* Append trailing slash only if:
* 1) Trailing slash is not already present
* 2) Path is non-empty
*/
char c = path[i];
if (c == '\0') {
if (i > 0 && path[i-1] != '/')
fullpath[i++] = '/';
break;
}
/* Copy character if not end of string */
fullpath[i] = c;
}
/* Append filename */
for (; i<GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) {
char c = *(filename++);
if (c == '\0')
break;
/* Filenames may not contain slashes */
if (c == '\\' || c == '/')
return 0;
/* Append each character within filename */
fullpath[i] = c;
}
/* Verify path length is within maximum */
if (i == GUAC_COMMON_SSH_SFTP_MAX_PATH)
return 0; return 0;
/* Terminate path string */ /* Copy base path */
fullpath[i] = '\0'; length = guac_strlcpy(fullpath, path, GUAC_COMMON_SSH_SFTP_MAX_PATH);
/*
* Append trailing slash only if:
* 1) Trailing slash is not already present
* 2) Path is non-empty
*/
if (length > 0 && fullpath[length - 1] != '/')
length += guac_strlcpy(fullpath + length, "/",
GUAC_COMMON_SSH_SFTP_MAX_PATH - length);
/* Append filename */
length += guac_strlcpy(fullpath + length, filename,
GUAC_COMMON_SSH_SFTP_MAX_PATH - length);
/* Verify path length is within maximum */
if (length >= GUAC_COMMON_SSH_SFTP_MAX_PATH)
return 0;
/* Append was successful */ /* Append was successful */
return 1; return 1;
@ -310,46 +254,30 @@ static int guac_ssh_append_filename(char* fullpath, const char* path,
static int guac_ssh_append_path(char* fullpath, const char* path_a, static int guac_ssh_append_path(char* fullpath, const char* path_a,
const char* path_b) { const char* path_b) {
int i; int length;
/* Copy path, appending a trailing slash */ /* Copy first half of path */
for (i = 0; i < GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) { length = guac_strlcpy(fullpath, path_a, GUAC_COMMON_SSH_SFTP_MAX_PATH);
if (length >= GUAC_COMMON_SSH_SFTP_MAX_PATH)
return 0;
char c = path_a[i]; /* Ensure path ends with trailing slash */
if (c == '\0') { if (length == 0 || fullpath[length - 1] != '/')
if (i > 0 && path_a[i-1] != '/') length += guac_strlcpy(fullpath + length, "/",
fullpath[i++] = '/'; GUAC_COMMON_SSH_SFTP_MAX_PATH - length);
break;
}
/* Copy character if not end of string */
fullpath[i] = c;
}
/* Skip past leading slashes in second path */ /* Skip past leading slashes in second path */
while (*path_b == '/') while (*path_b == '/')
path_b++; path_b++;
/* Append path */ /* Append final half of path */
for (; i < GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) { length += guac_strlcpy(fullpath + length, path_b,
GUAC_COMMON_SSH_SFTP_MAX_PATH - length);
char c = *(path_b++);
if (c == '\0')
break;
/* Append each character within path */
fullpath[i] = c;
}
/* Verify path length is within maximum */ /* Verify path length is within maximum */
if (i == GUAC_COMMON_SSH_SFTP_MAX_PATH) if (length >= GUAC_COMMON_SSH_SFTP_MAX_PATH)
return 0; return 0;
/* Terminate path string */
fullpath[i] = '\0';
/* Append was successful */ /* Append was successful */
return 1; return 1;
@ -448,6 +376,18 @@ int guac_common_ssh_sftp_handle_file_stream(
char fullpath[GUAC_COMMON_SSH_SFTP_MAX_PATH]; char fullpath[GUAC_COMMON_SSH_SFTP_MAX_PATH];
LIBSSH2_SFTP_HANDLE* file; LIBSSH2_SFTP_HANDLE* file;
/* Ignore upload if uploads have been disabled */
if (filesystem->disable_upload) {
guac_user_log(user, GUAC_LOG_WARNING, "A upload attempt has "
"been blocked due to uploads being disabled, however it "
"should have been blocked at a higher level. This is likely "
"a bug.");
guac_protocol_send_ack(user->socket, stream, "SFTP: Upload disabled",
GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
guac_socket_flush(user->socket);
return 0;
}
/* Concatenate filename with path */ /* Concatenate filename with path */
if (!guac_ssh_append_filename(fullpath, filesystem->upload_path, if (!guac_ssh_append_filename(fullpath, filesystem->upload_path,
filename)) { filename)) {
@ -501,7 +441,7 @@ int guac_common_ssh_sftp_handle_file_stream(
/** /**
* Handler for ack messages which continue an outbound SFTP data transfer * Handler for ack messages which continue an outbound SFTP data transfer
* (download), signalling the current status and requesting additional data. * (download), signaling the current status and requesting additional data.
* The data associated with the given stream is expected to be a pointer to an * The data associated with the given stream is expected to be a pointer to an
* open LIBSSH2_SFTP_HANDLE for the file from which the data is to be read. * open LIBSSH2_SFTP_HANDLE for the file from which the data is to be read.
* *
@ -588,6 +528,15 @@ guac_stream* guac_common_ssh_sftp_download_file(
guac_stream* stream; guac_stream* stream;
LIBSSH2_SFTP_HANDLE* file; LIBSSH2_SFTP_HANDLE* file;
/* Ignore download if downloads have been disabled */
if (filesystem->disable_download) {
guac_user_log(user, GUAC_LOG_WARNING, "A download attempt has "
"been blocked due to downloads being disabled, however it "
"should have been blocked at a higher level. This is likely "
"a bug.");
return NULL;
}
/* Attempt to open file for reading */ /* Attempt to open file for reading */
file = libssh2_sftp_open(filesystem->sftp_session, filename, file = libssh2_sftp_open(filesystem->sftp_session, filename,
LIBSSH2_FXF_READ, 0); LIBSSH2_FXF_READ, 0);
@ -658,7 +607,6 @@ static int guac_common_ssh_sftp_ls_ack_handler(guac_user* user,
guac_stream* stream, char* message, guac_protocol_status status) { guac_stream* stream, char* message, guac_protocol_status status) {
int bytes_read; int bytes_read;
int blob_written = 0;
char filename[GUAC_COMMON_SSH_SFTP_MAX_PATH]; char filename[GUAC_COMMON_SSH_SFTP_MAX_PATH];
LIBSSH2_SFTP_ATTRIBUTES attributes; LIBSSH2_SFTP_ATTRIBUTES attributes;
@ -680,8 +628,7 @@ static int guac_common_ssh_sftp_ls_ack_handler(guac_user* user,
/* While directory entries remain */ /* While directory entries remain */
while ((bytes_read = libssh2_sftp_readdir(list_state->directory, while ((bytes_read = libssh2_sftp_readdir(list_state->directory,
filename, sizeof(filename), &attributes)) > 0 filename, sizeof(filename), &attributes)) > 0) {
&& !blob_written) {
char absolute_path[GUAC_COMMON_SSH_SFTP_MAX_PATH]; char absolute_path[GUAC_COMMON_SSH_SFTP_MAX_PATH];
@ -711,9 +658,10 @@ static int guac_common_ssh_sftp_ls_ack_handler(guac_user* user,
else else
mimetype = "application/octet-stream"; mimetype = "application/octet-stream";
/* Write entry */ /* Write entry, waiting for next ack if a blob is written */
blob_written |= guac_common_json_write_property(user, stream, if (guac_common_json_write_property(user, stream,
&list_state->json_state, absolute_path, mimetype); &list_state->json_state, absolute_path, mimetype))
break;
} }
@ -830,8 +778,17 @@ static int guac_common_ssh_sftp_get_handler(guac_user* user,
list_state->directory = dir; list_state->directory = dir;
list_state->filesystem = filesystem; list_state->filesystem = filesystem;
strncpy(list_state->directory_name, name,
sizeof(list_state->directory_name) - 1); int length = guac_strlcpy(list_state->directory_name, name,
sizeof(list_state->directory_name));
/* Bail out if directory name is too long to store */
if (length >= sizeof(list_state->directory_name)) {
guac_user_log(user, GUAC_LOG_INFO, "Unable to read directory "
"\"%s\": Path too long", fullpath);
free(list_state);
return 0;
}
/* Allocate stream for body */ /* Allocate stream for body */
guac_stream* stream = guac_user_alloc_stream(user); guac_stream* stream = guac_user_alloc_stream(user);
@ -850,6 +807,14 @@ static int guac_common_ssh_sftp_get_handler(guac_user* user,
/* Otherwise, send file contents */ /* Otherwise, send file contents */
else { else {
/* If downloads are disabled, log and return. */
if (filesystem->disable_download) {
guac_user_log(user, GUAC_LOG_INFO,
"Unable to download file \"%s\", "
"file downloads have been disabled.", fullpath);
return 0;
}
/* Open as normal file */ /* Open as normal file */
LIBSSH2_SFTP_HANDLE* file = libssh2_sftp_open(sftp, fullpath, LIBSSH2_SFTP_HANDLE* file = libssh2_sftp_open(sftp, fullpath,
LIBSSH2_FXF_READ, 0); LIBSSH2_FXF_READ, 0);
@ -906,6 +871,18 @@ static int guac_common_ssh_sftp_put_handler(guac_user* user,
guac_common_ssh_sftp_filesystem* filesystem = guac_common_ssh_sftp_filesystem* filesystem =
(guac_common_ssh_sftp_filesystem*) object->data; (guac_common_ssh_sftp_filesystem*) object->data;
/* Ignore upload if uploads have been disabled */
if (filesystem->disable_upload) {
guac_user_log(user, GUAC_LOG_WARNING, "A upload attempt has "
"been blocked due to uploads being disabled, however it "
"should have been blocked at a higher level. This is likely "
"a bug.");
guac_protocol_send_ack(user->socket, stream, "SFTP: Upload disabled",
GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN);
guac_socket_flush(user->socket);
return 0;
}
LIBSSH2_SFTP* sftp = filesystem->sftp_session; LIBSSH2_SFTP* sftp = filesystem->sftp_session;
/* Translate stream name into filesystem path */ /* Translate stream name into filesystem path */
@ -966,7 +943,11 @@ guac_object* guac_common_ssh_alloc_sftp_filesystem_object(
/* Init filesystem */ /* Init filesystem */
guac_object* fs_object = guac_user_alloc_object(user); guac_object* fs_object = guac_user_alloc_object(user);
fs_object->get_handler = guac_common_ssh_sftp_get_handler; fs_object->get_handler = guac_common_ssh_sftp_get_handler;
fs_object->put_handler = guac_common_ssh_sftp_put_handler;
/* Only handle uploads if not disabled. */
if (!filesystem->disable_upload)
fs_object->put_handler = guac_common_ssh_sftp_put_handler;
fs_object->data = filesystem; fs_object->data = filesystem;
/* Send filesystem to user */ /* Send filesystem to user */
@ -979,7 +960,7 @@ guac_object* guac_common_ssh_alloc_sftp_filesystem_object(
guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem( guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem(
guac_common_ssh_session* session, const char* root_path, guac_common_ssh_session* session, const char* root_path,
const char* name) { const char* name, int disable_download, int disable_upload) {
/* Request SFTP */ /* Request SFTP */
LIBSSH2_SFTP* sftp_session = libssh2_sftp_init(session->session); LIBSSH2_SFTP* sftp_session = libssh2_sftp_init(session->session);
@ -994,6 +975,10 @@ guac_common_ssh_sftp_filesystem* guac_common_ssh_create_sftp_filesystem(
filesystem->ssh_session = session; filesystem->ssh_session = session;
filesystem->sftp_session = sftp_session; filesystem->sftp_session = sftp_session;
/* Copy over disable flags */
filesystem->disable_download = disable_download;
filesystem->disable_upload = disable_upload;
/* Normalize and store the provided root path */ /* Normalize and store the provided root path */
if (!guac_common_ssh_sftp_normalize_path(filesystem->root_path, if (!guac_common_ssh_sftp_normalize_path(filesystem->root_path,
root_path)) { root_path)) {

View File

@ -22,6 +22,7 @@
#include "common-ssh/user.h" #include "common-ssh/user.h"
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/fips.h>
#include <libssh2.h> #include <libssh2.h>
#ifdef LIBSSH2_USES_GCRYPT #ifdef LIBSSH2_USES_GCRYPT
@ -35,6 +36,7 @@
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <pthread.h> #include <pthread.h>
#include <pwd.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -45,6 +47,20 @@
GCRY_THREAD_OPTION_PTHREAD_IMPL; GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif #endif
/**
* A list of all key exchange algorithms that are both FIPS-compliant, and
* OpenSSL-supported. Note that "ext-info-c" is also included. While not a key
* exchange algorithm per se, it must be in the list to ensure that the server
* will send a SSH_MSG_EXT_INFO response, which is required to perform RSA key
* upgrades.
*/
#define FIPS_COMPLIANT_KEX_ALGORITHMS "diffie-hellman-group-exchange-sha256,ext-info-c"
/**
* A list of ciphers that are both FIPS-compliant, and OpenSSL-supported.
*/
#define FIPS_COMPLIANT_CIPHERS "aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,aes192-cbc,aes256-cbc"
#ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS #ifdef OPENSSL_REQUIRES_THREADING_CALLBACKS
/** /**
* Array of mutexes, used by OpenSSL. * Array of mutexes, used by OpenSSL.
@ -139,11 +155,21 @@ static void guac_common_ssh_openssl_free_locks(int count) {
int guac_common_ssh_init(guac_client* client) { int guac_common_ssh_init(guac_client* client) {
#ifdef LIBSSH2_USES_GCRYPT #ifdef LIBSSH2_USES_GCRYPT
/* Init threadsafety in libgcrypt */
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) {
if (!gcry_check_version(GCRYPT_VERSION)) {
guac_client_log(client, GUAC_LOG_ERROR, "libgcrypt version mismatch."); /* Init threadsafety in libgcrypt */
return 1; gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
/* Initialize GCrypt */
if (!gcry_check_version(GCRYPT_VERSION)) {
guac_client_log(client, GUAC_LOG_ERROR, "libgcrypt version mismatch.");
return 1;
}
/* Mark initialization as completed. */
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
} }
#endif #endif
@ -154,9 +180,11 @@ int guac_common_ssh_init(guac_client* client) {
CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback); CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback);
#endif #endif
/* Init OpenSSL */ #if OPENSSL_VERSION_NUMBER < 0x10100000L
/* Init OpenSSL - only required for OpenSSL Versions < 1.1.0 */
SSL_library_init(); SSL_library_init();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
#endif
/* Init libssh2 */ /* Init libssh2 */
libssh2_init(0); libssh2_init(0);
@ -172,55 +200,6 @@ void guac_common_ssh_uninit() {
#endif #endif
} }
/**
* Callback invoked by libssh2 when libssh2_userauth_publickkey() is invoked.
* This callback must sign the given data, returning the signature as newly-
* allocated buffer space.
*
* @param session
* The SSH session for which the signature is being generated.
*
* @param sig
* A pointer to the buffer space containing the signature. This callback
* MUST allocate and assign this space.
*
* @param sig_len
* The length of the signature within the allocated buffer space, in bytes.
* This value must be set to the size of the signature after the signing
* operation completes.
*
* @param data
* The arbitrary data that must be signed.
*
* @param data_len
* The length of the arbitrary data to be signed, in bytes.
*
* @param abstract
* The value of the abstract parameter provided with the corresponding call
* to libssh2_userauth_publickey().
*
* @return
* Zero on success, non-zero if the signing operation failed.
*/
static int guac_common_ssh_sign_callback(LIBSSH2_SESSION* session,
unsigned char** sig, size_t* sig_len,
const unsigned char* data, size_t data_len, void **abstract) {
guac_common_ssh_key* key = (guac_common_ssh_key*) abstract;
int length;
/* Allocate space for signature */
*sig = malloc(4096);
/* Sign with key */
length = guac_common_ssh_key_sign(key, (const char*) data, data_len, *sig);
if (length < 0)
return 1;
*sig_len = length;
return 0;
}
/** /**
* Callback for the keyboard-interactive authentication method. Currently * Callback for the keyboard-interactive authentication method. Currently
* supports just one prompt for the password. This callback is invoked as * supports just one prompt for the password. This callback is invoked as
@ -303,20 +282,27 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
LIBSSH2_SESSION* session = common_session->session; LIBSSH2_SESSION* session = common_session->session;
/* Get user credentials */ /* Get user credentials */
char* username = user->username;
char* password = user->password;
guac_common_ssh_key* key = user->private_key; guac_common_ssh_key* key = user->private_key;
/* Validate username provided */ /* Validate username provided */
if (username == NULL) { if (user->username == NULL) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED, guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_UNAUTHORIZED,
"SSH authentication requires a username."); "SSH authentication requires a username.");
return 1; return 1;
} }
/* Get list of supported authentication methods */ /* Get list of supported authentication methods */
char* user_authlist = libssh2_userauth_list(session, username, size_t username_len = strlen(user->username);
strlen(username)); char* user_authlist = libssh2_userauth_list(session, user->username,
username_len);
/* If auth list is NULL, then authentication has succeeded with NONE */
if (user_authlist == NULL) {
guac_client_log(client, GUAC_LOG_DEBUG,
"SSH NONE authentication succeeded.");
return 0;
}
guac_client_log(client, GUAC_LOG_DEBUG, guac_client_log(client, GUAC_LOG_DEBUG,
"Supported authentication methods: %s", user_authlist); "Supported authentication methods: %s", user_authlist);
@ -332,9 +318,9 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
} }
/* Attempt public key auth */ /* Attempt public key auth */
if (libssh2_userauth_publickey(session, username, if (libssh2_userauth_publickey_frommemory(session, user->username,
(unsigned char*) key->public_key, key->public_key_length, username_len, NULL, 0, key->private_key,
guac_common_ssh_sign_callback, (void**) key)) { key->private_key_length, key->passphrase)) {
/* Abort on failure */ /* Abort on failure */
char* error_message; char* error_message;
@ -351,14 +337,18 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
} }
/* Attempt authentication with username + password. */
if (user->password == NULL && common_session->credential_handler)
user->password = common_session->credential_handler(client, "Password: ");
/* Authenticate with password, if provided */ /* Authenticate with password, if provided */
else if (password != NULL) { if (user->password != NULL) {
/* Check if password auth is supported on the server */ /* Check if password auth is supported on the server */
if (strstr(user_authlist, "password") != NULL) { if (strstr(user_authlist, "password") != NULL) {
/* Attempt password authentication */ /* Attempt password authentication */
if (libssh2_userauth_password(session, username, password)) { if (libssh2_userauth_password(session, user->username, user->password)) {
/* Abort on failure */ /* Abort on failure */
char* error_message; char* error_message;
@ -379,7 +369,7 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
if (strstr(user_authlist, "keyboard-interactive") != NULL) { if (strstr(user_authlist, "keyboard-interactive") != NULL) {
/* Attempt keyboard-interactive auth using provided password */ /* Attempt keyboard-interactive auth using provided password */
if (libssh2_userauth_keyboard_interactive(session, username, if (libssh2_userauth_keyboard_interactive(session, user->username,
&guac_common_ssh_kbd_callback)) { &guac_common_ssh_kbd_callback)) {
/* Abort on failure */ /* Abort on failure */
@ -414,7 +404,9 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
} }
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive) { const char* hostname, const char* port, guac_common_ssh_user* user,
int keepalive, const char* host_key,
guac_ssh_credential_handler* credential_handler) {
int retval; int retval;
@ -431,20 +423,11 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
.ai_protocol = IPPROTO_TCP .ai_protocol = IPPROTO_TCP
}; };
/* Get socket */
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Unable to create socket: %s", strerror(errno));
return NULL;
}
/* Get addresses connection */ /* Get addresses connection */
if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) { if ((retval = getaddrinfo(hostname, port, &hints, &addresses))) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Error parsing given address or port: %s", "Error parsing given address or port: %s",
gai_strerror(retval)); gai_strerror(retval));
close(fd);
return NULL; return NULL;
} }
@ -461,6 +444,15 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
guac_client_log(client, GUAC_LOG_DEBUG, guac_client_log(client, GUAC_LOG_DEBUG,
"Unable to resolve host: %s", gai_strerror(retval)); "Unable to resolve host: %s", gai_strerror(retval));
/* Get socket */
fd = socket(current_address->ai_family, SOCK_STREAM, 0);
if (fd < 0) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Unable to create socket: %s", strerror(errno));
freeaddrinfo(addresses);
return NULL;
}
/* Connect */ /* Connect */
if (connect(fd, current_address->ai_addr, if (connect(fd, current_address->ai_addr,
current_address->ai_addrlen) == 0) { current_address->ai_addrlen) == 0) {
@ -475,11 +467,11 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
} }
/* Otherwise log information regarding bind failure */ /* Otherwise log information regarding bind failure */
else guac_client_log(client, GUAC_LOG_DEBUG, "Unable to connect to "
guac_client_log(client, GUAC_LOG_DEBUG, "Unable to connect to " "host %s, port %s: %s",
"host %s, port %s: %s", connected_address, connected_port, strerror(errno));
connected_address, connected_port, strerror(errno));
close(fd);
current_address = current_address->ai_next; current_address = current_address->ai_next;
} }
@ -491,7 +483,6 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
if (current_address == NULL) { if (current_address == NULL) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND, guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
"Unable to connect to any addresses."); "Unable to connect to any addresses.");
close(fd);
return NULL; return NULL;
} }
@ -510,6 +501,17 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
return NULL; return NULL;
} }
/*
* If FIPS mode is enabled, prefer only FIPS-compatible algorithms and
* ciphers that are also supported by libssh2. For more info, see:
* https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp2906.pdf
*/
if (guac_fips_enabled()) {
libssh2_session_method_pref(session, LIBSSH2_METHOD_KEX, FIPS_COMPLIANT_KEX_ALGORITHMS);
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_CS, FIPS_COMPLIANT_CIPHERS);
libssh2_session_method_pref(session, LIBSSH2_METHOD_CRYPT_SC, FIPS_COMPLIANT_CIPHERS);
}
/* Perform handshake */ /* Perform handshake */
if (libssh2_session_handshake(session, fd)) { if (libssh2_session_handshake(session, fd)) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR,
@ -519,11 +521,48 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
return NULL; return NULL;
} }
/* Get host key of remote system we're connecting to */
size_t remote_hostkey_len;
const char *remote_hostkey = libssh2_session_hostkey(session, &remote_hostkey_len, NULL);
/* Failure to retrieve a host key means we should abort */
if (!remote_hostkey) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Failed to get host key for %s", hostname);
free(common_session);
close(fd);
return NULL;
}
/* SSH known host key checking. */
int known_host_check = guac_common_ssh_verify_host_key(session, client, host_key,
hostname, atoi(port), remote_hostkey,
remote_hostkey_len);
/* Abort on any error codes */
if (known_host_check != 0) {
char* err_msg;
libssh2_session_last_error(session, &err_msg, NULL, 0);
if (known_host_check < 0)
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Error occurred attempting to check host key: %s", err_msg);
if (known_host_check > 0)
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Host key did not match any provided known host keys. %s", err_msg);
free(common_session);
close(fd);
return NULL;
}
/* Store basic session data */ /* Store basic session data */
common_session->client = client; common_session->client = client;
common_session->user = user; common_session->user = user;
common_session->session = session; common_session->session = session;
common_session->fd = fd; common_session->fd = fd;
common_session->credential_handler = credential_handler;
/* Attempt authentication */ /* Attempt authentication */
if (guac_common_ssh_authenticate(common_session)) { if (guac_common_ssh_authenticate(common_session)) {
@ -561,4 +600,3 @@ void guac_common_ssh_destroy_session(guac_common_ssh_session* session) {
free(session); free(session);
} }

View File

@ -0,0 +1,67 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
#
# Unit tests for common SSH support
#
check_PROGRAMS = test_common_ssh
TESTS = $(check_PROGRAMS)
test_common_ssh_SOURCES = \
sftp/normalize_path.c
test_common_ssh_CFLAGS = \
-Werror -Wall -pedantic \
@COMMON_INCLUDE@ \
@COMMON_SSH_INCLUDE@ \
@LIBGUAC_INCLUDE@
test_common_ssh_LDADD = \
@CUNIT_LIBS@ \
@COMMON_SSH_LTLIB@ \
@COMMON_LTLIB@
#
# Autogenerate test runner
#
GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
CLEANFILES = _generated_runner.c
_generated_runner.c: $(test_common_ssh_SOURCES)
$(AM_V_GEN) $(GEN_RUNNER) $(test_common_ssh_SOURCES) > $@
nodist_test_common_ssh_SOURCES = \
_generated_runner.c
# Use automake's TAP test driver for running any tests
LOG_DRIVER = \
env AM_TAP_AWK='$(AWK)' \
$(SHELL) $(top_srcdir)/build-aux/tap-driver.sh

View File

@ -0,0 +1,263 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common-ssh/sftp.h"
#include <CUnit/CUnit.h>
#include <stdlib.h>
/**
* Test which verifies absolute Windows-style paths are correctly normalized to
* absolute paths with UNIX separators and no relative components.
*/
void test_sftp__normalize_absolute_windows() {
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\baz\\"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\..\\baz\\a\\..\\b"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\.\\bar\\baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\..\\..\\..\\..\\..\\baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized));
}
/**
* Test which verifies absolute UNIX-style paths are correctly normalized to
* absolute paths with UNIX separators and no relative components.
*/
void test_sftp__normalize_absolute_unix() {
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../baz/"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../../baz/a/../b"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/./bar/baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../../../../../../baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized));
}
/**
* Test which verifies absolute paths consisting of mixed Windows and UNIX path
* separators are correctly normalized to absolute paths with UNIX separators
* and no relative components.
*/
void test_sftp__normalize_absolute_mixed() {
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo\\bar/..\\baz/"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\../../baz\\a\\..\\b"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\.\\bar/baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized));
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\../..\\..\\..\\../..\\baz"), 0);
CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized));
}
/**
* Test which verifies relative Windows-style paths are always rejected.
*/
void test_sftp__normalize_relative_windows() {
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ""), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "."), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".."), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "..\\foo"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo\\bar\\baz"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo\\bar\\baz"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "..\\foo\\bar\\baz"), 0);
}
/**
* Test which verifies relative UNIX-style paths are always rejected.
*/
void test_sftp__normalize_relative_unix() {
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ""), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "."), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".."), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "./foo"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo/bar/baz"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "./foo/bar/baz"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo/bar/baz"), 0);
}
/**
* Test which verifies relative paths consisting of mixed Windows and UNIX path
* separators are always rejected.
*/
void test_sftp__normalize_relative_mixed() {
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo\\bar/baz"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo/bar/baz"), 0);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo\\bar\\baz"), 0);
}
/**
* Generates a dynamically-allocated path having the given number of bytes, not
* counting the null-terminator. The path will contain only UNIX-style path
* separators. The returned path must eventually be freed with a call to
* free().
*
* @param length
* The number of bytes to include in the generated path, not counting the
* null-terminator. If -1, the length of the path will be automatically
* determined from the provided max_depth.
*
* @param max_depth
* The maximum number of path components to include within the generated
* path.
*
* @return
* A dynamically-allocated path containing the given number of bytes, not
* counting the null-terminator. This path must eventually be freed with a
* call to free().
*/
static char* generate_path(int length, int max_depth) {
/* If no length given, calculate space required from max_depth */
if (length == -1)
length = max_depth * 2;
int i;
char* input = malloc(length + 1);
/* Fill path with /x/x/x/x/x/x/x/x/x/x/.../xxxxxxxxx... */
for (i = 0; i < length; i++) {
if (max_depth > 0 && i % 2 == 0) {
input[i] = '/';
max_depth--;
}
else
input[i] = 'x';
}
/* Add null terminator */
input[length] = '\0';
return input;
}
/**
* Test which verifies that paths exceeding the maximum path length are
* rejected.
*/
void test_sftp__normalize_long() {
char* input;
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
/* Exceeds maximum length by a factor of 2 */
input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH * 2, GUAC_COMMON_SSH_SFTP_MAX_DEPTH);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
free(input);
/* Exceeds maximum length by one byte */
input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH, GUAC_COMMON_SSH_SFTP_MAX_DEPTH);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
free(input);
/* Exactly maximum length */
input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH - 1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH);
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
free(input);
}
/**
* Test which verifies that paths exceeding the maximum path depth are
* rejected.
*/
void test_sftp__normalize_deep() {
char* input;
char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH];
/* Exceeds maximum depth by a factor of 2 */
input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH * 2);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
free(input);
/* Exceeds maximum depth by one component */
input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH + 1);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
free(input);
/* Exactly maximum depth (should still be rejected as SFTP depth limits are
* set such that a path with the maximum depth will exceed the maximum
* length) */
input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH);
CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
free(input);
/* Less than maximum depth */
input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH - 1);
CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0);
free(input);
}

5
src/common/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Auto-generated test runner and binary
_generated_runner.c
test_common

View File

@ -16,17 +16,25 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
# #
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
noinst_LTLIBRARIES = libguac_common.la noinst_LTLIBRARIES = libguac_common.la
SUBDIRS = . tests
noinst_HEADERS = \ noinst_HEADERS = \
common/io.h \ common/io.h \
common/blank_cursor.h \ common/blank_cursor.h \
common/clipboard.h \ common/clipboard.h \
common/cursor.h \ common/cursor.h \
common/defaults.h \
common/display.h \ common/display.h \
common/dot_cursor.h \ common/dot_cursor.h \
common/ibar_cursor.h \ common/ibar_cursor.h \
@ -34,7 +42,6 @@ noinst_HEADERS = \
common/json.h \ common/json.h \
common/list.h \ common/list.h \
common/pointer_cursor.h \ common/pointer_cursor.h \
common/recording.h \
common/rect.h \ common/rect.h \
common/string.h \ common/string.h \
common/surface.h common/surface.h
@ -51,7 +58,6 @@ libguac_common_la_SOURCES = \
json.c \ json.c \
list.c \ list.c \
pointer_cursor.c \ pointer_cursor.c \
recording.c \
rect.c \ rect.c \
string.c \ string.c \
surface.c surface.c

View File

@ -23,26 +23,37 @@
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/stream.h> #include <guacamole/stream.h>
#include <guacamole/string.h>
#include <guacamole/user.h> #include <guacamole/user.h>
#include <pthread.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
guac_common_clipboard* guac_common_clipboard_alloc(int size) { guac_common_clipboard* guac_common_clipboard_alloc() {
guac_common_clipboard* clipboard = malloc(sizeof(guac_common_clipboard)); guac_common_clipboard* clipboard = malloc(sizeof(guac_common_clipboard));
/* Init clipboard */ /* Init clipboard */
clipboard->mimetype[0] = '\0'; clipboard->mimetype[0] = '\0';
clipboard->buffer = malloc(size); clipboard->buffer = malloc(GUAC_COMMON_CLIPBOARD_MAX_LENGTH);
clipboard->available = GUAC_COMMON_CLIPBOARD_MAX_LENGTH;
clipboard->length = 0; clipboard->length = 0;
clipboard->available = size;
pthread_mutex_init(&(clipboard->lock), NULL);
return clipboard; return clipboard;
} }
void guac_common_clipboard_free(guac_common_clipboard* clipboard) { void guac_common_clipboard_free(guac_common_clipboard* clipboard) {
/* Destroy lock */
pthread_mutex_destroy(&(clipboard->lock));
/* Free buffer */
free(clipboard->buffer); free(clipboard->buffer);
/* Free base structure */
free(clipboard); free(clipboard);
} }
@ -108,18 +119,36 @@ static void* __send_user_clipboard(guac_user* user, void* data) {
} }
void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* client) { void guac_common_clipboard_send(guac_common_clipboard* clipboard, guac_client* client) {
pthread_mutex_lock(&(clipboard->lock));
guac_client_log(client, GUAC_LOG_DEBUG, "Broadcasting clipboard to all connected users."); guac_client_log(client, GUAC_LOG_DEBUG, "Broadcasting clipboard to all connected users.");
guac_client_foreach_user(client, __send_user_clipboard, clipboard); guac_client_foreach_user(client, __send_user_clipboard, clipboard);
guac_client_log(client, GUAC_LOG_DEBUG, "Broadcast of clipboard complete."); guac_client_log(client, GUAC_LOG_DEBUG, "Broadcast of clipboard complete.");
pthread_mutex_unlock(&(clipboard->lock));
} }
void guac_common_clipboard_reset(guac_common_clipboard* clipboard, const char* mimetype) { void guac_common_clipboard_reset(guac_common_clipboard* clipboard,
const char* mimetype) {
pthread_mutex_lock(&(clipboard->lock));
/* Clear clipboard contents */
clipboard->length = 0; clipboard->length = 0;
strncpy(clipboard->mimetype, mimetype, sizeof(clipboard->mimetype)-1);
/* Assign given mimetype */
guac_strlcpy(clipboard->mimetype, mimetype, sizeof(clipboard->mimetype));
pthread_mutex_unlock(&(clipboard->lock));
} }
void guac_common_clipboard_append(guac_common_clipboard* clipboard, const char* data, int length) { void guac_common_clipboard_append(guac_common_clipboard* clipboard, const char* data, int length) {
pthread_mutex_lock(&(clipboard->lock));
/* Truncate data to available length */ /* Truncate data to available length */
int remaining = clipboard->available - clipboard->length; int remaining = clipboard->available - clipboard->length;
if (remaining < length) if (remaining < length)
@ -131,5 +160,7 @@ void guac_common_clipboard_append(guac_common_clipboard* clipboard, const char*
/* Update length */ /* Update length */
clipboard->length += length; clipboard->length += length;
pthread_mutex_unlock(&(clipboard->lock));
} }

View File

@ -23,6 +23,7 @@
#include "config.h" #include "config.h"
#include <guacamole/client.h> #include <guacamole/client.h>
#include <pthread.h>
/** /**
* The maximum number of bytes to send in an individual blob when * The maximum number of bytes to send in an individual blob when
@ -30,11 +31,23 @@
*/ */
#define GUAC_COMMON_CLIPBOARD_BLOCK_SIZE 4096 #define GUAC_COMMON_CLIPBOARD_BLOCK_SIZE 4096
/**
* The maximum number of bytes to allow within the clipboard.
*/
#define GUAC_COMMON_CLIPBOARD_MAX_LENGTH 262144
/** /**
* Generic clipboard structure. * Generic clipboard structure.
*/ */
typedef struct guac_common_clipboard { typedef struct guac_common_clipboard {
/**
* Lock which restricts simultaneous access to the clipboard, guaranteeing
* ordered modifications to the clipboard and that changes to the clipboard
* are not allowed while the clipboard is being broadcast to all users.
*/
pthread_mutex_t lock;
/** /**
* The mimetype of the contained clipboard data. * The mimetype of the contained clipboard data.
*/ */
@ -58,12 +71,9 @@ typedef struct guac_common_clipboard {
} guac_common_clipboard; } guac_common_clipboard;
/** /**
* Creates a new clipboard having the given initial size. * Creates a new clipboard.
*
* @param size The maximum number of bytes to allow within the clipboard.
* @return A newly-allocated clipboard.
*/ */
guac_common_clipboard* guac_common_clipboard_alloc(int size); guac_common_clipboard* guac_common_clipboard_alloc();
/** /**
* Frees the given clipboard. * Frees the given clipboard.

View File

@ -102,6 +102,27 @@ typedef struct guac_common_cursor {
*/ */
int y; int y;
/**
* An integer value representing the current state of each button, where
* the Nth bit within the integer is set to 1 if and only if the Nth mouse
* button is currently pressed. The lowest-order bit is the left mouse
* button, followed by the middle button, right button, and finally the up
* and down buttons of the scroll wheel.
*
* @see GUAC_CLIENT_MOUSE_LEFT
* @see GUAC_CLIENT_MOUSE_MIDDLE
* @see GUAC_CLIENT_MOUSE_RIGHT
* @see GUAC_CLIENT_MOUSE_SCROLL_UP
* @see GUAC_CLIENT_MOUSE_SCROLL_DOWN
*/
int button_mask;
/**
* The server timestamp representing the point in time when the mousr
* location was last updated.
*/
guac_timestamp timestamp;
} guac_common_cursor; } guac_common_cursor;
/** /**
@ -142,12 +163,12 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
guac_socket* socket); guac_socket* socket);
/** /**
* Moves the mouse cursor, marking the given user as the most recent user of * Updates the current position and button state of the mouse cursor, marking
* the mouse. The remote mouse cursor will be hidden for this user and shown * the given user as the most recent user of the mouse. The remote mouse cursor
* for all others. * will be hidden for this user and shown for all others.
* *
* @param cursor * @param cursor
* The cursor being moved. * The cursor being updated.
* *
* @param user * @param user
* The user that moved the cursor. * The user that moved the cursor.
@ -157,9 +178,22 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
* *
* @param y * @param y
* The new Y coordinate of the cursor. * The new Y coordinate of the cursor.
*
* @param button_mask
* An integer value representing the current state of each button, where
* the Nth bit within the integer is set to 1 if and only if the Nth mouse
* button is currently pressed. The lowest-order bit is the left mouse
* button, followed by the middle button, right button, and finally the up
* and down buttons of the scroll wheel.
*
* @see GUAC_CLIENT_MOUSE_LEFT
* @see GUAC_CLIENT_MOUSE_MIDDLE
* @see GUAC_CLIENT_MOUSE_RIGHT
* @see GUAC_CLIENT_MOUSE_SCROLL_UP
* @see GUAC_CLIENT_MOUSE_SCROLL_DOWN
*/ */
void guac_common_cursor_move(guac_common_cursor* cursor, guac_user* user, void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user,
int x, int y); int x, int y, int button_mask);
/** /**
* Sets the cursor image to the given raw image data. This raw image data must * Sets the cursor image to the given raw image data. This raw image data must

View File

@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef GUAC_COMMON_DEFAULTS_H
#define GUAC_COMMON_DEFAULTS_H
/**
* The default number of seconds to wait after sending the Wake-on-LAN packet
* for the destination host to start responding.
*/
#define GUAC_WOL_DEFAULT_BOOT_WAIT_TIME 0
#endif /* GUAC_COMMON_DEFAULTS_H */

View File

@ -99,6 +99,13 @@ typedef struct guac_common_display {
*/ */
guac_common_display_layer* buffers; guac_common_display_layer* buffers;
/**
* Non-zero if all graphical updates for this display should use lossless
* compression, 0 otherwise. By default, newly-created displays will use
* lossy compression when heuristics determine it is appropriate.
*/
int lossless;
/** /**
* Mutex which is locked internally when access to the display must be * Mutex which is locked internally when access to the display must be
* synchronized. All public functions of guac_common_display should be * synchronized. All public functions of guac_common_display should be
@ -228,5 +235,27 @@ void guac_common_display_free_layer(guac_common_display* display,
void guac_common_display_free_buffer(guac_common_display* display, void guac_common_display_free_buffer(guac_common_display* display,
guac_common_display_layer* display_buffer); guac_common_display_layer* display_buffer);
/**
* Sets the overall lossless compression policy of the given display to the
* given value, affecting all current and future layers/buffers maintained by
* the display. By default, newly-created displays will use lossy compression
* for graphical updates when heuristics determine that doing so is
* appropriate. Specifying a non-zero value here will force all graphical
* updates to always use lossless compression, whereas specifying zero will
* restore the default policy.
*
* Note that this can also be adjusted on a per-layer / per-buffer basis with
* guac_common_surface_set_lossless().
*
* @param display
* The display to modify.
*
* @param lossless
* Non-zero if all graphical updates for this display should use lossless
* compression, 0 otherwise.
*/
void guac_common_display_set_lossless(guac_common_display* display,
int lossless);
#endif #endif

View File

@ -76,6 +76,30 @@ guac_iconv_read GUAC_READ_CP1252;
*/ */
guac_iconv_read GUAC_READ_ISO8859_1; guac_iconv_read GUAC_READ_ISO8859_1;
/**
* Read function for UTF-8 which normalizes newline character sequences like
* "\r\n" to Unix-style newlines ('\n').
*/
guac_iconv_read GUAC_READ_UTF8_NORMALIZED;
/**
* Read function for UTF-16 which normalizes newline character sequences like
* "\r\n" to Unix-style newlines ('\n').
*/
guac_iconv_read GUAC_READ_UTF16_NORMALIZED;
/**
* Read function for CP-1252 which normalizes newline character sequences like
* "\r\n" to Unix-style newlines ('\n').
*/
guac_iconv_read GUAC_READ_CP1252_NORMALIZED;
/**
* Read function for ISO 8859-1 which normalizes newline character sequences
* like "\r\n" to Unix-style newlines ('\n').
*/
guac_iconv_read GUAC_READ_ISO8859_1_NORMALIZED;
/** /**
* Write function for UTF8. * Write function for UTF8.
*/ */
@ -96,5 +120,29 @@ guac_iconv_write GUAC_WRITE_CP1252;
*/ */
guac_iconv_write GUAC_WRITE_ISO8859_1; guac_iconv_write GUAC_WRITE_ISO8859_1;
/**
* Write function for UTF-8 which writes newline characters ('\n') as
* Windows-style newlines ("\r\n").
*/
guac_iconv_write GUAC_WRITE_UTF8_CRLF;
/**
* Write function for UTF-16 which writes newline characters ('\n') as
* Windows-style newlines ("\r\n").
*/
guac_iconv_write GUAC_WRITE_UTF16_CRLF;
/**
* Write function for CP-1252 which writes newline characters ('\n') as
* Windows-style newlines ("\r\n").
*/
guac_iconv_write GUAC_WRITE_CP1252_CRLF;
/**
* Write function for ISO 8859-1 which writes newline characters ('\n') as
* Windows-style newlines ("\r\n").
*/
guac_iconv_write GUAC_WRITE_ISO8859_1_CRLF;
#endif #endif

View File

@ -1,78 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef GUAC_COMMON_RECORDING_H
#define GUAC_COMMON_RECORDING_H
#include <guacamole/client.h>
/**
* The maximum numeric value allowed for the .1, .2, .3, etc. suffix appended
* to the end of the session recording filename if a recording having the
* requested name already exists.
*/
#define GUAC_COMMON_RECORDING_MAX_SUFFIX 255
/**
* The maximum length of the string containing a sequential numeric suffix
* between 1 and GUAC_COMMON_RECORDING_MAX_SUFFIX inclusive, in bytes,
* including NULL terminator.
*/
#define GUAC_COMMON_RECORDING_MAX_SUFFIX_LENGTH 4
/**
* The maximum overall length of the full path to the session recording file,
* including any additional suffix and NULL terminator, in bytes.
*/
#define GUAC_COMMON_RECORDING_MAX_NAME_LENGTH 2048
/**
* Replaces the socket of the given client such that all further Guacamole
* protocol output will be copied into a file within the given path and having
* the given name. If the create_path flag is non-zero, the given path will be
* created if it does not yet exist. If creation of the recording file or path
* fails, error messages will automatically be logged, and no recording will be
* written. The recording will automatically be closed once the client is
* freed.
*
* @param client
* The client whose output should be copied to a recording file.
*
* @param path
* The full absolute path to a directory in which the recording file should
* be created.
*
* @param name
* The base name to use for the recording file created within the specified
* path.
*
* @param create_path
* Zero if the specified path MUST exist for the recording file to be
* written, or non-zero if the path should be created if it does not yet
* exist.
*
* @return
* Zero if the recording file has been successfully created and a recording
* will be written, non-zero otherwise.
*/
int guac_common_recording_create(guac_client* client, const char* path,
const char* name, int create_path);
#endif

View File

@ -120,6 +120,19 @@ typedef struct guac_common_surface {
*/ */
guac_socket* socket; guac_socket* socket;
/**
* The number of simultaneous touches that this surface can accept, where 0
* indicates that the surface does not support touch events at all.
*/
int touches;
/**
* Non-zero if all graphical updates for this surface should use lossless
* compression, 0 otherwise. By default, newly-created surfaces will use
* lossy compression when heuristics determine it is appropriate.
*/
int lossless;
/** /**
* The X coordinate of the upper-left corner of this layer, in pixels, * The X coordinate of the upper-left corner of this layer, in pixels,
* relative to its parent layer. This is only applicable to visible * relative to its parent layer. This is only applicable to visible
@ -486,5 +499,41 @@ void guac_common_surface_flush(guac_common_surface* surface);
void guac_common_surface_dup(guac_common_surface* surface, guac_user* user, void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
guac_socket* socket); guac_socket* socket);
/**
* Declares that the given surface should receive touch events. By default,
* surfaces are assumed to not expect touch events. This value is advisory, and
* the client is not required to honor the declared level of touch support.
* Implementations are expected to safely handle or ignore any received touch
* events, regardless of the level of touch support declared. regardless of
* the level of touch support declared.
*
* @param surface
* The surface to modify.
*
* @param touches
* The number of simultaneous touches that this surface can accept, where 0
* indicates that the surface does not support touch events at all.
*/
void guac_common_surface_set_multitouch(guac_common_surface* surface,
int touches);
/**
* Sets the lossless compression policy of the given surface to the given
* value. By default, newly-created surfaces will use lossy compression for
* graphical updates when heuristics determine that doing so is appropriate.
* Specifying a non-zero value here will force all graphical updates to always
* use lossless compression, whereas specifying zero will restore the default
* policy.
*
* @param surface
* The surface to modify.
*
* @param lossless
* Non-zero if all graphical updates for this surface should use lossless
* compression, 0 otherwise.
*/
void guac_common_surface_set_lossless(guac_common_surface* surface,
int lossless);
#endif #endif

View File

@ -28,12 +28,23 @@
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/socket.h> #include <guacamole/socket.h>
#include <guacamole/timestamp.h>
#include <guacamole/user.h> #include <guacamole/user.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/**
* Allocates a cursor as well as an image buffer where the cursor is rendered.
*
* @param client
* The client owning the cursor.
*
* @return
* The newly-allocated cursor or NULL if cursor cannot be allocated.
*/
guac_common_cursor* guac_common_cursor_alloc(guac_client* client) { guac_common_cursor* guac_common_cursor_alloc(guac_client* client) {
guac_common_cursor* cursor = malloc(sizeof(guac_common_cursor)); guac_common_cursor* cursor = malloc(sizeof(guac_common_cursor));
@ -57,6 +68,7 @@ guac_common_cursor* guac_common_cursor_alloc(guac_client* client) {
/* No user has moved the mouse yet */ /* No user has moved the mouse yet */
cursor->user = NULL; cursor->user = NULL;
cursor->timestamp = guac_timestamp_current();
/* Start cursor in upper-left */ /* Start cursor in upper-left */
cursor->x = 0; cursor->x = 0;
@ -91,7 +103,8 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
guac_socket* socket) { guac_socket* socket) {
/* Synchronize location */ /* Synchronize location */
guac_protocol_send_mouse(socket, cursor->x, cursor->y); guac_protocol_send_mouse(socket, cursor->x, cursor->y, cursor->button_mask,
cursor->timestamp);
/* Synchronize cursor image */ /* Synchronize cursor image */
if (cursor->surface != NULL) { if (cursor->surface != NULL) {
@ -112,23 +125,25 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user,
/** /**
* Callback for guac_client_foreach_user() which sends the current cursor * Callback for guac_client_foreach_user() which sends the current cursor
* position to any given user except the user that moved the cursor last. * position and button state to any given user except the user that moved the
* cursor last.
* *
* @param data * @param data
* A pointer to the guac_common_cursor whose position should be broadcast * A pointer to the guac_common_cursor whose state should be broadcast to
* to all users except the user that moved the cursor last. * all users except the user that moved the cursor last.
* *
* @return * @return
* Always NULL. * Always NULL.
*/ */
static void* guac_common_cursor_broadcast_position(guac_user* user, static void* guac_common_cursor_broadcast_state(guac_user* user,
void* data) { void* data) {
guac_common_cursor* cursor = (guac_common_cursor*) data; guac_common_cursor* cursor = (guac_common_cursor*) data;
/* Send cursor position only if the user is not moving the cursor */ /* Send cursor state only if the user is not moving the cursor */
if (user != cursor->user) { if (user != cursor->user) {
guac_protocol_send_mouse(user->socket, cursor->x, cursor->y); guac_protocol_send_mouse(user->socket, cursor->x, cursor->y,
cursor->button_mask, cursor->timestamp);
guac_socket_flush(user->socket); guac_socket_flush(user->socket);
} }
@ -136,19 +151,23 @@ static void* guac_common_cursor_broadcast_position(guac_user* user,
} }
void guac_common_cursor_move(guac_common_cursor* cursor, guac_user* user, void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user,
int x, int y) { int x, int y, int button_mask) {
/* Update current user of cursor */ /* Update current user of cursor */
cursor->user = user; cursor->user = user;
/* Update cursor position */ /* Update cursor state */
cursor->x = x; cursor->x = x;
cursor->y = y; cursor->y = y;
cursor->button_mask = button_mask;
/* Notify all other users of change in cursor position */ /* Store time at which cursor was updated */
cursor->timestamp = guac_timestamp_current();
/* Notify all other users of change in cursor state */
guac_client_foreach_user(cursor->client, guac_client_foreach_user(cursor->client,
guac_common_cursor_broadcast_position, cursor); guac_common_cursor_broadcast_state, cursor);
} }

View File

@ -99,6 +99,22 @@ static void guac_common_display_free_layers(guac_common_display_layer* layers,
} }
/**
* Allocates a display and a cursor which are used to represent the remote
* display and cursor.
*
* @param client
* The client owning the cursor.
*
* @param width
* The desired width of the display.
*
* @param height
* The desired height of the display.
*
* @return
* The newly-allocated display or NULL if display cannot be allocated.
*/
guac_common_display* guac_common_display_alloc(guac_client* client, guac_common_display* guac_common_display_alloc(guac_client* client,
int width, int height) { int width, int height) {
@ -107,14 +123,18 @@ guac_common_display* guac_common_display_alloc(guac_client* client,
if (display == NULL) if (display == NULL)
return NULL; return NULL;
/* Allocate shared cursor */
display->cursor = guac_common_cursor_alloc(client);
if (display->cursor == NULL) {
free(display);
return NULL;
}
pthread_mutex_init(&display->_lock, NULL); pthread_mutex_init(&display->_lock, NULL);
/* Associate display with given client */ /* Associate display with given client */
display->client = client; display->client = client;
/* Allocate shared cursor */
display->cursor = guac_common_cursor_alloc(client);
display->default_surface = guac_common_surface_alloc(client, display->default_surface = guac_common_surface_alloc(client,
client->socket, GUAC_DEFAULT_LAYER, width, height); client->socket, GUAC_DEFAULT_LAYER, width, height);
@ -146,6 +166,8 @@ void guac_common_display_free(guac_common_display* display) {
void guac_common_display_dup(guac_common_display* display, guac_user* user, void guac_common_display_dup(guac_common_display* display, guac_user* user,
guac_socket* socket) { guac_socket* socket) {
guac_client* client = user->client;
pthread_mutex_lock(&display->_lock); pthread_mutex_lock(&display->_lock);
/* Sunchronize shared cursor */ /* Sunchronize shared cursor */
@ -158,6 +180,33 @@ void guac_common_display_dup(guac_common_display* display, guac_user* user,
guac_common_display_dup_layers(display->layers, user, socket); guac_common_display_dup_layers(display->layers, user, socket);
guac_common_display_dup_layers(display->buffers, user, socket); guac_common_display_dup_layers(display->buffers, user, socket);
/* Sends a sync instruction to mark the boundary of the first frame */
guac_protocol_send_sync(socket, client->last_sent_timestamp, 1);
pthread_mutex_unlock(&display->_lock);
}
void guac_common_display_set_lossless(guac_common_display* display,
int lossless) {
pthread_mutex_lock(&display->_lock);
/* Update lossless setting to be applied to all newly-allocated
* layers/buffers */
display->lossless = lossless;
/* Update losslessness of all allocated layers/buffers */
guac_common_display_layer* current = display->layers;
while (current != NULL) {
guac_common_surface_set_lossless(current->surface, lossless);
current = current->next;
}
/* Update losslessness of default display layer (not included within layers
* list) */
guac_common_surface_set_lossless(display->default_surface, lossless);
pthread_mutex_unlock(&display->_lock); pthread_mutex_unlock(&display->_lock);
} }
@ -267,6 +316,9 @@ guac_common_display_layer* guac_common_display_alloc_layer(
guac_common_surface* surface = guac_common_surface_alloc(display->client, guac_common_surface* surface = guac_common_surface_alloc(display->client,
display->client->socket, layer, width, height); display->client->socket, layer, width, height);
/* Apply current display losslessness */
guac_common_surface_set_lossless(surface, display->lossless);
/* Add layer and surface to list */ /* Add layer and surface to list */
guac_common_display_layer* display_layer = guac_common_display_layer* display_layer =
guac_common_display_add_layer(&display->layers, layer, surface); guac_common_display_add_layer(&display->layers, layer, surface);
@ -288,6 +340,9 @@ guac_common_display_layer* guac_common_display_alloc_buffer(
guac_common_surface* surface = guac_common_surface_alloc(display->client, guac_common_surface* surface = guac_common_surface_alloc(display->client,
display->client->socket, buffer, width, height); display->client->socket, buffer, width, height);
/* Apply current display losslessness */
guac_common_surface_set_lossless(surface, display->lossless);
/* Add buffer and surface to list */ /* Add buffer and surface to list */
guac_common_display_layer* display_layer = guac_common_display_layer* display_layer =
guac_common_display_add_layer(&display->buffers, buffer, surface); guac_common_display_add_layer(&display->buffers, buffer, surface);
@ -334,4 +389,3 @@ void guac_common_display_free_buffer(guac_common_display* display,
pthread_mutex_unlock(&display->_lock); pthread_mutex_unlock(&display->_lock);
} }

View File

@ -138,6 +138,70 @@ int GUAC_READ_ISO8859_1(const char** input, int remaining) {
} }
/**
* Invokes the given reader function, automatically normalizing newline
* sequences as Unix-style newline characters ('\n'). All other charaters are
* read verbatim.
*
* @param reader
* The reader to use to read the given character.
*
* @param input
* Pointer to the location within the input buffer that the next character
* should be read from.
*
* @param remaining
* The number of bytes remaining in the input buffer.
*
* @return
* The codepoint that was read, or zero if the end of the input string has
* been reached.
*/
static int guac_iconv_read_normalized(guac_iconv_read* reader,
const char** input, int remaining) {
/* Read requested character */
const char* input_start = *input;
int value = reader(input, remaining);
/* Automatically translate CRLF pairs to simple newlines */
if (value == '\r') {
/* Peek ahead by one character, adjusting remaining bytes relative to
* last read */
int peek_remaining = remaining - (*input - input_start);
const char* peek_input = *input;
int peek_value = reader(&peek_input, peek_remaining);
/* Consider read value to be a newline if we have encountered a "\r\n"
* (CRLF) pair */
if (peek_value == '\n') {
value = '\n';
*input = peek_input;
}
}
return value;
}
int GUAC_READ_UTF8_NORMALIZED(const char** input, int remaining) {
return guac_iconv_read_normalized(GUAC_READ_UTF8, input, remaining);
}
int GUAC_READ_UTF16_NORMALIZED(const char** input, int remaining) {
return guac_iconv_read_normalized(GUAC_READ_UTF16, input, remaining);
}
int GUAC_READ_CP1252_NORMALIZED(const char** input, int remaining) {
return guac_iconv_read_normalized(GUAC_READ_CP1252, input, remaining);
}
int GUAC_READ_ISO8859_1_NORMALIZED(const char** input, int remaining) {
return guac_iconv_read_normalized(GUAC_READ_ISO8859_1, input, remaining);
}
void GUAC_WRITE_UTF8(char** output, int remaining, int value) { void GUAC_WRITE_UTF8(char** output, int remaining, int value) {
*output += guac_utf8_write(value, *output, remaining); *output += guac_utf8_write(value, *output, remaining);
} }
@ -190,3 +254,53 @@ void GUAC_WRITE_ISO8859_1(char** output, int remaining, int value) {
(*output)++; (*output)++;
} }
/**
* Invokes the given writer function, automatically writing newline characters
* ('\n') as CRLF ("\r\n"). All other charaters are written verbatim.
*
* @param writer
* The writer to use to write the given character.
*
* @param output
* Pointer to the location within the output buffer that the next character
* should be written.
*
* @param remaining
* The number of bytes remaining in the output buffer.
*
* @param value
* The codepoint of the character to write.
*/
static void guac_iconv_write_crlf(guac_iconv_write* writer, char** output,
int remaining, int value) {
if (value != '\n') {
writer(output, remaining, value);
return;
}
char* output_start = *output;
writer(output, remaining, '\r');
remaining -= *output - output_start;
if (remaining > 0)
writer(output, remaining, '\n');
}
void GUAC_WRITE_UTF8_CRLF(char** output, int remaining, int value) {
guac_iconv_write_crlf(GUAC_WRITE_UTF8, output, remaining, value);
}
void GUAC_WRITE_UTF16_CRLF(char** output, int remaining, int value) {
guac_iconv_write_crlf(GUAC_WRITE_UTF16, output, remaining, value);
}
void GUAC_WRITE_CP1252_CRLF(char** output, int remaining, int value) {
guac_iconv_write_crlf(GUAC_WRITE_CP1252, output, remaining, value);
}
void GUAC_WRITE_ISO8859_1_CRLF(char** output, int remaining, int value) {
guac_iconv_write_crlf(GUAC_WRITE_ISO8859_1, output, remaining, value);
}

View File

@ -97,15 +97,15 @@ int guac_common_json_write_string(guac_user* user,
const char* current = str; const char* current = str;
for (; *current != '\0'; current++) { for (; *current != '\0'; current++) {
/* Escape all quotes */ /* Escape all quotes and back-slashes */
if (*current == '"') { if (*current == '"' || *current == '\\') {
/* Write any string content up to current character */ /* Write any string content up to current character */
if (current != str) if (current != str)
blob_written |= guac_common_json_write(user, stream, blob_written |= guac_common_json_write(user, stream,
json_state, str, current - str); json_state, str, current - str);
/* Escape the quote that was just read */ /* Escape the character that was just read */
blob_written |= guac_common_json_write(user, stream, blob_written |= guac_common_json_write(user, stream,
json_state, "\\", 1); json_state, "\\", 1);

View File

@ -78,13 +78,6 @@
#define cairo_format_stride_for_width(format, width) (width*4) #define cairo_format_stride_for_width(format, width) (width*4)
#endif #endif
/**
* The JPEG image quality ('quantization') setting to use. Range 0-100 where
* 100 is the highest quality/largest file size, and 0 is the lowest
* quality/smallest file size.
*/
#define GUAC_SURFACE_JPEG_IMAGE_QUALITY 90
/** /**
* The framerate which, if exceeded, indicates that JPEG is preferred. * The framerate which, if exceeded, indicates that JPEG is preferred.
*/ */
@ -96,13 +89,6 @@
*/ */
#define GUAC_SURFACE_JPEG_MIN_BITMAP_SIZE 4096 #define GUAC_SURFACE_JPEG_MIN_BITMAP_SIZE 4096
/**
* The WebP image quality ('quantization') setting to use. Range 0-100 where
* 100 is the highest quality/largest file size, and 0 is the lowest
* quality/smallest file size.
*/
#define GUAC_SURFACE_WEBP_IMAGE_QUALITY 90
/** /**
* The JPEG compression min block size. This defines the optimal rectangle block * The JPEG compression min block size. This defines the optimal rectangle block
* size factor for JPEG compression. Usually 8x8 would suffice, but use 16 to * size factor for JPEG compression. Usually 8x8 would suffice, but use 16 to
@ -117,6 +103,28 @@
*/ */
#define GUAC_SURFACE_WEBP_BLOCK_SIZE 8 #define GUAC_SURFACE_WEBP_BLOCK_SIZE 8
void guac_common_surface_set_multitouch(guac_common_surface* surface,
int touches) {
pthread_mutex_lock(&surface->_lock);
surface->touches = touches;
guac_protocol_send_set_int(surface->socket, surface->layer,
GUAC_PROTOCOL_LAYER_PARAMETER_MULTI_TOUCH, touches);
pthread_mutex_unlock(&surface->_lock);
}
void guac_common_surface_set_lossless(guac_common_surface* surface,
int lossless) {
pthread_mutex_lock(&surface->_lock);
surface->lossless = lossless;
pthread_mutex_unlock(&surface->_lock);
}
void guac_common_surface_move(guac_common_surface* surface, int x, int y) { void guac_common_surface_move(guac_common_surface* surface, int x, int y) {
pthread_mutex_lock(&surface->_lock); pthread_mutex_lock(&surface->_lock);
@ -274,18 +282,31 @@ static int __guac_common_surface_is_opaque(guac_common_surface* surface,
/** /**
* Returns whether the given rectangle should be combined into the existing * Returns whether the given rectangle should be combined into the existing
* dirty rectangle, to be eventually flushed as a "png" instruction. * dirty rectangle, to be eventually flushed as image data, or would be best
* kept independent of the current rectangle.
* *
* @param surface The surface to be queried. * @param surface
* @param rect The update rectangle. * The surface being updated.
* @param rect_only Non-zero if this update, by its nature, contains only *
* metainformation about the update's rectangle, zero if * @param rect
* the update also contains image data. * The bounding rectangle of the update being made to the surface.
* @return Non-zero if the update should be combined with any existing update, *
* zero otherwise. * @param rect_only
* Non-zero if this update, by its nature, contains only metainformation
* about the update's bounding rectangle, zero if the update also contains
* image data.
*
* @return
* Non-zero if the update should be combined with any existing update, zero
* otherwise.
*/ */
static int __guac_common_should_combine(guac_common_surface* surface, const guac_common_rect* rect, int rect_only) { static int __guac_common_should_combine(guac_common_surface* surface, const guac_common_rect* rect, int rect_only) {
/* Always favor combining updates if surface is currently a purely
* server-side scratch area */
if (!surface->realized)
return 1;
if (surface->dirty) { if (surface->dirty) {
int combined_cost, dirty_cost, update_cost; int combined_cost, dirty_cost, update_cost;
@ -522,6 +543,10 @@ static int __guac_common_surface_png_optimality(guac_common_surface* surface,
static int __guac_common_surface_should_use_jpeg(guac_common_surface* surface, static int __guac_common_surface_should_use_jpeg(guac_common_surface* surface,
const guac_common_rect* rect) { const guac_common_rect* rect) {
/* Do not use JPEG if lossless quality is required */
if (surface->lossless)
return 0;
/* Calculate the average framerate for the given rect */ /* Calculate the average framerate for the given rect */
int framerate = __guac_common_surface_calculate_framerate(surface, rect); int framerate = __guac_common_surface_calculate_framerate(surface, rect);
@ -1666,6 +1691,36 @@ static void __guac_common_surface_flush_to_png(guac_common_surface* surface,
} }
/**
* Returns an appropriate quality between 0 and 100 for lossy encoding
* depending on the current processing lag calculated for the given client.
*
* @param client
* The client for which the lossy quality is being calculated.
*
* @return
* A value between 0 and 100 inclusive which seems appropriate for the
* client based on lag measurements.
*/
static int guac_common_surface_suggest_quality(guac_client* client) {
int lag = guac_client_get_processing_lag(client);
/* Scale quality linearly from 90 to 30 as lag varies from 20ms to 80ms */
int quality = 90 - (lag - 20);
/* Do not exceed 90 for quality */
if (quality > 90)
return 90;
/* Do not go below 30 for quality */
if (quality < 30)
return 30;
return quality;
}
/** /**
* Flushes the bitmap update currently described by the dirty rectangle within * Flushes the bitmap update currently described by the dirty rectangle within
* the given surface directly via an "img" instruction as JPEG data. The * the given surface directly via an "img" instruction as JPEG data. The
@ -1702,7 +1757,7 @@ static void __guac_common_surface_flush_to_jpeg(guac_common_surface* surface) {
/* Send JPEG for rect */ /* Send JPEG for rect */
guac_client_stream_jpeg(surface->client, socket, GUAC_COMP_OVER, layer, guac_client_stream_jpeg(surface->client, socket, GUAC_COMP_OVER, layer,
surface->dirty_rect.x, surface->dirty_rect.y, rect, surface->dirty_rect.x, surface->dirty_rect.y, rect,
GUAC_SURFACE_JPEG_IMAGE_QUALITY); guac_common_surface_suggest_quality(surface->client));
cairo_surface_destroy(rect); cairo_surface_destroy(rect);
surface->realized = 1; surface->realized = 1;
@ -1764,7 +1819,8 @@ static void __guac_common_surface_flush_to_webp(guac_common_surface* surface,
/* Send WebP for rect */ /* Send WebP for rect */
guac_client_stream_webp(surface->client, socket, GUAC_COMP_OVER, layer, guac_client_stream_webp(surface->client, socket, GUAC_COMP_OVER, layer,
surface->dirty_rect.x, surface->dirty_rect.y, rect, surface->dirty_rect.x, surface->dirty_rect.y, rect,
GUAC_SURFACE_WEBP_IMAGE_QUALITY, 0); guac_common_surface_suggest_quality(surface->client),
surface->lossless ? 1 : 0);
cairo_surface_destroy(rect); cairo_surface_destroy(rect);
surface->realized = 1; surface->realized = 1;
@ -1952,6 +2008,11 @@ void guac_common_surface_dup(guac_common_surface* surface, guac_user* user,
guac_protocol_send_move(socket, surface->layer, guac_protocol_send_move(socket, surface->layer,
surface->parent, surface->x, surface->y, surface->z); surface->parent, surface->x, surface->y, surface->z);
/* Synchronize multi-touch support level */
guac_protocol_send_set_int(surface->socket, surface->layer,
GUAC_PROTOCOL_LAYER_PARAMETER_MULTI_TOUCH,
surface->touches);
} }
/* Sync size to new socket */ /* Sync size to new socket */

View File

@ -0,0 +1,76 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
#
# Unit tests for libguac_common
#
check_PROGRAMS = test_common
TESTS = $(check_PROGRAMS)
noinst_HEADERS = \
iconv/convert-test-data.h
test_common_SOURCES = \
iconv/convert.c \
iconv/convert-test-data.c \
rect/clip_and_split.c \
rect/constrain.c \
rect/expand_to_grid.c \
rect/extend.c \
rect/init.c \
rect/intersects.c \
string/count_occurrences.c \
string/split.c
test_common_CFLAGS = \
-Werror -Wall -pedantic \
@COMMON_INCLUDE@
test_common_LDADD = \
@COMMON_LTLIB@ \
@CUNIT_LIBS@
#
# Autogenerate test runner
#
GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
CLEANFILES = _generated_runner.c
_generated_runner.c: $(test_common_SOURCES)
$(AM_V_GEN) $(GEN_RUNNER) $(test_common_SOURCES) > $@
nodist_test_common_SOURCES = \
_generated_runner.c
# Use automake's TAP test driver for running any tests
LOG_DRIVER = \
env AM_TAP_AWK='$(AWK)' \
$(SHELL) $(top_srcdir)/build-aux/tap-driver.sh

View File

@ -0,0 +1,153 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common/iconv.h"
#include "convert-test-data.h"
encoding_test_parameters test_params[NUM_SUPPORTED_ENCODINGS] = {
/*
* UTF-8
*/
{
"UTF-8",
GUAC_READ_UTF8, GUAC_READ_UTF8_NORMALIZED,
GUAC_WRITE_UTF8, GUAC_WRITE_UTF8_CRLF,
.test_mixed = TEST_STRING(
"pap\xC3\xA0 \xC3\xA8 bello\n"
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
"pap\xC3\xA0 \xC3\xA8 bello\n"
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
"pap\xC3\xA0 \xC3\xA8 bello"
),
.test_unix = TEST_STRING(
"pap\xC3\xA0 \xC3\xA8 bello\n"
"pap\xC3\xA0 \xC3\xA8 bello\n"
"pap\xC3\xA0 \xC3\xA8 bello\n"
"pap\xC3\xA0 \xC3\xA8 bello\n"
"pap\xC3\xA0 \xC3\xA8 bello"
),
.test_windows = TEST_STRING(
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
"pap\xC3\xA0 \xC3\xA8 bello\r\n"
"pap\xC3\xA0 \xC3\xA8 bello"
)
},
/*
* UTF-16
*/
{
"UTF-16",
GUAC_READ_UTF16, GUAC_READ_UTF16_NORMALIZED,
GUAC_WRITE_UTF16, GUAC_WRITE_UTF16_CRLF,
.test_mixed = TEST_STRING(
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00"
"\x00"
),
.test_unix = TEST_STRING(
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00"
"\x00"
),
.test_windows = TEST_STRING(
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00" "\r\x00" "\n\x00"
"p\x00" "a\x00" "p\x00" "\xE0\x00" " \x00" "\xE8\x00" " \x00" "b\x00" "e\x00" "l\x00" "l\x00" "o\x00"
"\x00"
)
},
/*
* ISO 8859-1
*/
{
"ISO 8859-1",
GUAC_READ_ISO8859_1, GUAC_READ_ISO8859_1_NORMALIZED,
GUAC_WRITE_ISO8859_1, GUAC_WRITE_ISO8859_1_CRLF,
.test_mixed = TEST_STRING(
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello"
),
.test_unix = TEST_STRING(
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello"
),
.test_windows = TEST_STRING(
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello"
)
},
/*
* CP-1252
*/
{
"CP-1252",
GUAC_READ_CP1252, GUAC_READ_CP1252_NORMALIZED,
GUAC_WRITE_CP1252, GUAC_WRITE_CP1252_CRLF,
.test_mixed = TEST_STRING(
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello"
),
.test_unix = TEST_STRING(
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello\n"
"pap\xE0 \xE8 bello"
),
.test_windows = TEST_STRING(
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello\r\n"
"pap\xE0 \xE8 bello"
)
}
};

View File

@ -0,0 +1,121 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common/iconv.h"
/**
* Representation of test string data and its length in bytes.
*/
typedef struct test_string {
/**
* The raw content of the test string.
*/
unsigned char* buffer;
/**
* The number of bytes within the test string, including null terminator.
*/
int size;
} test_string;
/**
* Convenience macro which statically-initializes a test_string with the given
* string value, automatically calculating its size in bytes.
*
* @param value
* The string value.
*/
#define TEST_STRING(value) { \
.buffer = (unsigned char*) (value), \
.size = sizeof(value) \
}
/**
* The parameters applicable to a unit test for a particular encoding supported
* by guac_iconv().
*/
typedef struct encoding_test_parameters {
/**
* The human-readable name of this encoding. This will be logged to the
* test suite log to assist with debugging test failures.
*/
const char* name;
/**
* Reader function which reads using this encoding and does not perform any
* transformation on newline characters.
*/
guac_iconv_read* reader;
/**
* Reader function which reads using this encoding and automatically
* normalizes newline sequences to Unix-style newline characters.
*/
guac_iconv_read* reader_normalized;
/**
* Writer function which writes using this encoding and does not perform
* any transformation on newline characters.
*/
guac_iconv_write* writer;
/**
* Writer function which writes using this encoding, but writes newline
* characters as CRLF sequences.
*/
guac_iconv_write* writer_crlf;
/**
* A test string having both Windows- and Unix-style line endings. Except
* for the line endings, the characters represented within this test string
* must be identical to all other test strings.
*/
test_string test_mixed;
/**
* A test string having only Unix-style line endings. Except for the line
* endings, the characters represented within this test string must be
* identical to all other test strings.
*/
test_string test_unix;
/**
* A test string having only Windows-style line endings. Except for the
* line endings, the characters represented within this test string must be
* identical to all other test strings.
*/
test_string test_windows;
} encoding_test_parameters;
/**
* The total number of encodings supported by guac_iconv().
*/
#define NUM_SUPPORTED_ENCODINGS 4
/**
* Test parameters for each supported encoding. The test strings included each
* consist of five repeated lines of "papà è bello", omitting the line ending
* of the final line.
*/
extern encoding_test_parameters test_params[NUM_SUPPORTED_ENCODINGS];

View File

@ -0,0 +1,129 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common/iconv.h"
#include "convert-test-data.h"
#include <CUnit/CUnit.h>
#include <stdio.h>
/**
* Tests that conversion between character sets using the given guac_iconv_read
* and guac_iconv_write implementations matches expectations.
*
* @param reader
* The guac_iconv_read implementation to use to read the input string.
*
* @param in_string
* A pointer to the test_string structure describing the input string being
* tested.
*
* @param writer
* The guac_iconv_write implementation to use to write the output string
* (the converted input string).
*
* @param out_string
* A pointer to the test_string structure describing the expected result of
* the conversion.
*/
static void verify_conversion(
guac_iconv_read* reader, test_string* in_string,
guac_iconv_write* writer, test_string* out_string) {
char output[4096];
char input[4096];
const char* current_input = input;
char* current_output = output;
memcpy(input, in_string->buffer, in_string->size);
guac_iconv(reader, &current_input, sizeof(input),
writer, &current_output, sizeof(output));
/* Verify output length */
CU_ASSERT_EQUAL(out_string->size, current_output - output);
/* Verify entire input read */
CU_ASSERT_EQUAL(in_string->size, current_input - input);
/* Verify output content */
CU_ASSERT_EQUAL(0, memcmp(output, out_string->buffer, out_string->size));
}
/**
* Test which verifies that every supported encoding can be correctly converted
* to every other supported encoding, with all line endings preserved verbatim
* (not normalized).
*/
void test_iconv__preserve() {
for (int i = 0; i < NUM_SUPPORTED_ENCODINGS; i++) {
for (int j = 0; j < NUM_SUPPORTED_ENCODINGS; j++) {
encoding_test_parameters* from = &test_params[i];
encoding_test_parameters* to = &test_params[j];
printf("# \"%s\" -> \"%s\" ...\n", from->name, to->name);
verify_conversion(from->reader, &from->test_mixed,
to->writer, &to->test_mixed);
}
}
}
/**
* Test which verifies that every supported encoding can be correctly converted
* to every other supported encoding, normalizing all line endings to
* Unix-style line endings.
*/
void test_iconv__normalize_unix() {
for (int i = 0; i < NUM_SUPPORTED_ENCODINGS; i++) {
for (int j = 0; j < NUM_SUPPORTED_ENCODINGS; j++) {
encoding_test_parameters* from = &test_params[i];
encoding_test_parameters* to = &test_params[j];
printf("# \"%s\" -> \"%s\" ...\n", from->name, to->name);
verify_conversion(from->reader_normalized, &from->test_mixed,
to->writer, &to->test_unix);
}
}
}
/**
* Test which verifies that every supported encoding can be correctly converted
* to every other supported encoding, normalizing all line endings to
* Windows-style line endings.
*/
void test_iconv__normalize_crlf() {
for (int i = 0; i < NUM_SUPPORTED_ENCODINGS; i++) {
for (int j = 0; j < NUM_SUPPORTED_ENCODINGS; j++) {
encoding_test_parameters* from = &test_params[i];
encoding_test_parameters* to = &test_params[j];
printf("# \"%s\" -> \"%s\" ...\n", from->name, to->name);
verify_conversion(from->reader_normalized, &from->test_mixed,
to->writer_crlf, &to->test_windows);
}
}
}

View File

@ -0,0 +1,156 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common/rect.h"
#include <CUnit/CUnit.h>
/**
* Test which verifies that guac_common_rect_clip_and_split() divides a
* rectangle into subrectangles after removing a "hole" rectangle.
*/
void test_rect__clip_and_split() {
int res;
guac_common_rect cut;
guac_common_rect min;
guac_common_rect rect;
guac_common_rect_init(&min, 10, 10, 10, 10);
/* Clip top */
guac_common_rect_init(&rect, 10, 5, 10, 10);
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(1, res);
CU_ASSERT_EQUAL(10, cut.x);
CU_ASSERT_EQUAL(5, cut.y);
CU_ASSERT_EQUAL(10, cut.width);
CU_ASSERT_EQUAL(5, cut.height);
CU_ASSERT_EQUAL(10, rect.x);
CU_ASSERT_EQUAL(10, rect.y);
CU_ASSERT_EQUAL(10, rect.width);
CU_ASSERT_EQUAL(5, rect.height);
/* Clip bottom */
guac_common_rect_init(&rect, 10, 15, 10, 10);
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(1, res);
CU_ASSERT_EQUAL(10, cut.x);
CU_ASSERT_EQUAL(20, cut.y);
CU_ASSERT_EQUAL(10, cut.width);
CU_ASSERT_EQUAL(5, cut.height);
CU_ASSERT_EQUAL(10, rect.x);
CU_ASSERT_EQUAL(15, rect.y);
CU_ASSERT_EQUAL(10, rect.width);
CU_ASSERT_EQUAL(5, rect.height);
/* Clip left */
guac_common_rect_init(&rect, 5, 10, 10, 10);
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(1, res);
CU_ASSERT_EQUAL(5, cut.x);
CU_ASSERT_EQUAL(10, cut.y);
CU_ASSERT_EQUAL(5, cut.width);
CU_ASSERT_EQUAL(10, cut.height);
CU_ASSERT_EQUAL(10, rect.x);
CU_ASSERT_EQUAL(10, rect.y);
CU_ASSERT_EQUAL(5, rect.width);
CU_ASSERT_EQUAL(10, rect.height);
/* Clip right */
guac_common_rect_init(&rect, 15, 10, 10, 10);
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(1, res);
CU_ASSERT_EQUAL(20, cut.x);
CU_ASSERT_EQUAL(10, cut.y);
CU_ASSERT_EQUAL(5, cut.width);
CU_ASSERT_EQUAL(10, cut.height);
CU_ASSERT_EQUAL(15, rect.x);
CU_ASSERT_EQUAL(10, rect.y);
CU_ASSERT_EQUAL(5, rect.width);
CU_ASSERT_EQUAL(10, rect.height);
/*
* Test a rectangle which completely covers the hole.
* Clip and split until done.
*/
guac_common_rect_init(&rect, 5, 5, 20, 20);
/* Clip top */
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(1, res);
CU_ASSERT_EQUAL(5, cut.x);
CU_ASSERT_EQUAL(5, cut.y);
CU_ASSERT_EQUAL(20, cut.width);
CU_ASSERT_EQUAL(5, cut.height);
CU_ASSERT_EQUAL(5, rect.x);
CU_ASSERT_EQUAL(10, rect.y);
CU_ASSERT_EQUAL(20, rect.width);
CU_ASSERT_EQUAL(15, rect.height);
/* Clip left */
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(1, res);
CU_ASSERT_EQUAL(5, cut.x);
CU_ASSERT_EQUAL(10, cut.y);
CU_ASSERT_EQUAL(5, cut.width);
CU_ASSERT_EQUAL(15, cut.height);
CU_ASSERT_EQUAL(10, rect.x);
CU_ASSERT_EQUAL(10, rect.y);
CU_ASSERT_EQUAL(15, rect.width);
CU_ASSERT_EQUAL(15, rect.height);
/* Clip bottom */
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(1, res);
CU_ASSERT_EQUAL(10, cut.x);
CU_ASSERT_EQUAL(20, cut.y);
CU_ASSERT_EQUAL(15, cut.width);
CU_ASSERT_EQUAL(5, cut.height);
CU_ASSERT_EQUAL(10, rect.x);
CU_ASSERT_EQUAL(10, rect.y);
CU_ASSERT_EQUAL(15, rect.width);
CU_ASSERT_EQUAL(10, rect.height);
/* Clip right */
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(20, cut.x);
CU_ASSERT_EQUAL(10, cut.y);
CU_ASSERT_EQUAL(5, cut.width);
CU_ASSERT_EQUAL(10, cut.height);
CU_ASSERT_EQUAL(10, rect.x);
CU_ASSERT_EQUAL(10, rect.y);
CU_ASSERT_EQUAL(10, rect.width);
CU_ASSERT_EQUAL(10, rect.height);
/* Make sure nothing is left to do */
res = guac_common_rect_clip_and_split(&rect, &min, &cut);
CU_ASSERT_EQUAL(0, res);
}

View File

@ -17,31 +17,27 @@
* under the License. * under the License.
*/ */
#include "config.h" #include "common/rect.h"
#include "client/client_suite.h" #include <CUnit/CUnit.h>
#include "common/common_suite.h"
#include "protocol/suite.h"
#include "util/util_suite.h"
#include <CUnit/Basic.h> /**
* Test which verifies that guac_common_rect_constrain() restricts a given
* rectangle to arbitrary bounds.
*/
void test_rect__constrain() {
int main() { guac_common_rect max;
guac_common_rect rect;
/* Init registry */ guac_common_rect_init(&rect, -10, -10, 110, 110);
if (CU_initialize_registry() != CUE_SUCCESS) guac_common_rect_init(&max, 0, 0, 100, 100);
return CU_get_error(); guac_common_rect_constrain(&rect, &max);
/* Register suites */ CU_ASSERT_EQUAL(0, rect.x);
register_protocol_suite(); CU_ASSERT_EQUAL(0, rect.y);
register_client_suite(); CU_ASSERT_EQUAL(100, rect.width);
register_util_suite(); CU_ASSERT_EQUAL(100, rect.height);
/* Run tests */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return CU_get_error();
} }

View File

@ -0,0 +1,71 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common/rect.h"
#include <CUnit/CUnit.h>
/**
* Test which verifies guac_common_rect_expand_to_grid() properly shifts and
* resizes rectangles to fit an NxN grid.
*/
void test_rect__expand_to_grid() {
int cell_size = 16;
guac_common_rect max;
guac_common_rect rect;
/* Simple adjustment */
guac_common_rect_init(&rect, 0, 0, 25, 25);
guac_common_rect_init(&max, 0, 0, 100, 100);
guac_common_rect_expand_to_grid(cell_size, &rect, &max);
CU_ASSERT_EQUAL(0, rect.x);
CU_ASSERT_EQUAL(0, rect.y);
CU_ASSERT_EQUAL(32, rect.width);
CU_ASSERT_EQUAL(32, rect.height);
/* Adjustment with moving of rect */
guac_common_rect_init(&rect, 75, 75, 25, 25);
guac_common_rect_init(&max, 0, 0, 100, 100);
guac_common_rect_expand_to_grid(cell_size, &rect, &max);
CU_ASSERT_EQUAL(max.width - 32, rect.x);
CU_ASSERT_EQUAL(max.height - 32, rect.y);
CU_ASSERT_EQUAL(32, rect.width);
CU_ASSERT_EQUAL(32, rect.height);
guac_common_rect_init(&rect, -5, -5, 25, 25);
guac_common_rect_init(&max, 0, 0, 100, 100);
guac_common_rect_expand_to_grid(cell_size, &rect, &max);
CU_ASSERT_EQUAL(0, rect.x);
CU_ASSERT_EQUAL(0, rect.y);
CU_ASSERT_EQUAL(32, rect.width);
CU_ASSERT_EQUAL(32, rect.height);
/* Adjustment with moving and clamping of rect */
guac_common_rect_init(&rect, 0, 0, 25, 15);
guac_common_rect_init(&max, 0, 5, 32, 15);
guac_common_rect_expand_to_grid(cell_size, &rect, &max);
CU_ASSERT_EQUAL(max.x, rect.x);
CU_ASSERT_EQUAL(max.y, rect.y);
CU_ASSERT_EQUAL(max.width, rect.width);
CU_ASSERT_EQUAL(max.height, rect.height);
}

View File

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common/rect.h"
#include <CUnit/CUnit.h>
/**
* Test which verifies that guac_common_rect_extend() expands the given
* rectangle as necessary to contain at least the given bounds.
*/
void test_rect__extend() {
guac_common_rect max;
guac_common_rect rect;
guac_common_rect_init(&rect, 10, 10, 90, 90);
guac_common_rect_init(&max, 0, 0, 100, 100);
guac_common_rect_extend(&rect, &max);
CU_ASSERT_EQUAL(0, rect.x);
CU_ASSERT_EQUAL(0, rect.y);
CU_ASSERT_EQUAL(100, rect.width);
CU_ASSERT_EQUAL(100, rect.height);
}

View File

@ -17,22 +17,23 @@
* under the License. * under the License.
*/ */
#include "config.h" #include "common/rect.h"
#include <openssl/bn.h> #include <CUnit/CUnit.h>
#include <openssl/rsa.h>
#include <stdlib.h> /**
* Test which verifies rectangle initialization via guac_common_rect_init().
*/
void test_rect__init() {
#ifndef HAVE_RSA_GET0_KEY guac_common_rect max;
void RSA_get0_key(const RSA* rsa_key, const BIGNUM** n,
const BIGNUM** e, const BIGNUM**d) {
/* Retrieve all requested internal values */ guac_common_rect_init(&max, 0, 0, 100, 100);
if (n != NULL) *n = rsa_key->n;
if (e != NULL) *e = rsa_key->e; CU_ASSERT_EQUAL(0, max.x);
if (d != NULL) *d = rsa_key->d; CU_ASSERT_EQUAL(0, max.y);
CU_ASSERT_EQUAL(100, max.width);
CU_ASSERT_EQUAL(100, max.height);
} }
#endif

View File

@ -0,0 +1,91 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common/rect.h"
#include <CUnit/CUnit.h>
/**
* Test which verifies intersection testing via guac_common_rect_intersects().
*/
void test_rect__intersects() {
int res;
guac_common_rect min;
guac_common_rect rect;
guac_common_rect_init(&min, 10, 10, 10, 10);
/* Rectangle intersection - empty
* rectangle is outside */
guac_common_rect_init(&rect, 25, 25, 5, 5);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(0, res);
/* Rectangle intersection - complete
* rectangle is completely inside */
guac_common_rect_init(&rect, 11, 11, 5, 5);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(2, res);
/* Rectangle intersection - partial
* rectangle intersects UL */
guac_common_rect_init(&rect, 8, 8, 5, 5);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(1, res);
/* Rectangle intersection - partial
* rectangle intersects LR */
guac_common_rect_init(&rect, 18, 18, 5, 5);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(1, res);
/* Rectangle intersection - complete
* rect intersects along UL but inside */
guac_common_rect_init(&rect, 10, 10, 5, 5);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(2, res);
/* Rectangle intersection - partial
* rectangle intersects along L but outside */
guac_common_rect_init(&rect, 5, 10, 5, 5);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(1, res);
/* Rectangle intersection - complete
* rectangle intersects along LR but rest is inside */
guac_common_rect_init(&rect, 15, 15, 5, 5);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(2, res);
/* Rectangle intersection - partial
* rectangle intersects along R but rest is outside */
guac_common_rect_init(&rect, 20, 10, 5, 5);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(1, res);
/* Rectangle intersection - partial
* rectangle encloses min; which is a partial intersection */
guac_common_rect_init(&rect, 5, 5, 20, 20);
res = guac_common_rect_intersects(&rect, &min);
CU_ASSERT_EQUAL(1, res);
}

View File

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "common/string.h"
#include <CUnit/CUnit.h>
/**
* Test which verifies that guac_count_occurrences() counts the number of
* occurrences of an arbitrary character within a given string.
*/
void test_string__guac_count_occurrences() {
CU_ASSERT_EQUAL(4, guac_count_occurrences("this is a test string", 's'));
CU_ASSERT_EQUAL(3, guac_count_occurrences("this is a test string", 'i'));
CU_ASSERT_EQUAL(0, guac_count_occurrences("", 's'));
}

View File

@ -17,26 +17,20 @@
* under the License. * under the License.
*/ */
#include "config.h"
#include "common_suite.h"
#include "common/string.h" #include "common/string.h"
#include <CUnit/CUnit.h>
#include <stdlib.h> #include <stdlib.h>
#include <CUnit/Basic.h>
void test_guac_string() { /**
* Test which verifies that guac_split() splits a string on occurrences of a
char** tokens; * given character.
*/
/* Test occurrence counting */ void test_string__split() {
CU_ASSERT_EQUAL(4, guac_count_occurrences("this is a test string", 's'));
CU_ASSERT_EQUAL(3, guac_count_occurrences("this is a test string", 'i'));
CU_ASSERT_EQUAL(0, guac_count_occurrences("", 's'));
/* Split test string */ /* Split test string */
tokens = guac_split("this is a test string", ' '); char** tokens = guac_split("this is a test string", ' ');
CU_ASSERT_PTR_NOT_NULL(tokens); CU_ASSERT_PTR_NOT_NULL(tokens);
/* Check resulting tokens */ /* Check resulting tokens */
@ -57,7 +51,6 @@ void test_guac_string() {
CU_ASSERT_PTR_NULL(tokens[5]); CU_ASSERT_PTR_NULL(tokens[5]);
/* Clean up */ /* Clean up */
free(tokens[0]); free(tokens[0]);
free(tokens[1]); free(tokens[1]);

View File

@ -1,11 +1,11 @@
What is guacd? What is guacd?
============== ==============
[guacd](https://github.com/apache/incubator/guacamole-server/) is the native [guacd](https://github.com/apache/guacamole-server/) is the native
server-side proxy used by the [Apache Guacamole web server-side proxy used by the [Apache Guacamole web
application](http://guacamole.incubator.apache.org/). If you wish to deploy application](http://guacamole.apache.org/). If you wish to deploy
Guacamole, or an application using the [Guacamole core Guacamole, or an application using the [Guacamole core
APIs](http://guacamole.incubator.apache.org/api-documentation), you will need a APIs](http://guacamole.apache.org/api-documentation), you will need a
copy of guacd running. copy of guacd running.
How to use this image How to use this image

115
src/guacd-docker/bin/build-all.sh Executable file
View File

@ -0,0 +1,115 @@
#!/bin/sh -e
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
##
## @fn build-all.sh
##
## Builds the source of guacamole-server and its various core protocol library
## dependencies.
##
# Pre-populate build control variables such that the custom build prefix is
# used for C headers, locating libraries, etc.
export CFLAGS="-I${PREFIX_DIR}/include"
export LDFLAGS="-L${PREFIX_DIR}/lib"
export PKG_CONFIG_PATH="${PREFIX_DIR}/lib/pkgconfig"
# Ensure thread stack size will be 8 MB (glibc's default on Linux) rather than
# 128 KB (musl's default)
export LDFLAGS="$LDFLAGS -Wl,-z,stack-size=8388608"
##
## Builds and installs the source at the given git repository, automatically
## switching to the version of the source at the tag/commit that matches the
## given pattern.
##
## @param URL
## The URL of the git repository that the source should be downloaded from.
##
## @param PATTERN
## The Perl-compatible regular expression that the tag must match. If no
## tag matches the regular expression, the pattern is assumed to be an
## exact reference to a commit, branch, etc. acceptable by git checkout.
##
## @param ...
## Any additional command-line options that should be provided to CMake or
## the configure script.
##
install_from_git() {
URL="$1"
PATTERN="$2"
shift 2
# Calculate top-level directory name of resulting repository from the
# provided URL
REPO_DIR="$(basename "$URL" .git)"
# Allow dependencies to be manually omitted with the tag/commit pattern "NO"
if [ "$PATTERN" = "NO" ]; then
echo "NOT building $REPO_DIR (explicitly skipped)"
return
fi
# Clone repository and change to top-level directory of source
cd /tmp
git clone "$URL"
cd $REPO_DIR/
# Locate tag/commit based on provided pattern
VERSION="$(git tag -l --sort=-v:refname | grep -Px -m1 "$PATTERN" \
|| echo "$PATTERN")"
# Switch to desired version of source
echo "Building $REPO_DIR @ $VERSION ..."
git -c advice.detachedHead=false checkout "$VERSION"
# Configure build using CMake or GNU Autotools, whichever happens to be
# used by the library being built
if [ -e CMakeLists.txt ]; then
cmake -DCMAKE_INSTALL_PREFIX:PATH="$PREFIX_DIR" "$@" .
else
[ -e configure ] || autoreconf -fi
./configure --prefix="$PREFIX_DIR" "$@"
fi
# Build and install
make && make install
}
#
# Build and install core protocol library dependencies
#
install_from_git "https://github.com/FreeRDP/FreeRDP" "$WITH_FREERDP" $FREERDP_OPTS
install_from_git "https://github.com/libssh2/libssh2" "$WITH_LIBSSH2" $LIBSSH2_OPTS
install_from_git "https://github.com/seanmiddleditch/libtelnet" "$WITH_LIBTELNET" $LIBTELNET_OPTS
install_from_git "https://github.com/LibVNC/libvncserver" "$WITH_LIBVNCCLIENT" $LIBVNCCLIENT_OPTS
install_from_git "https://libwebsockets.org/repo/libwebsockets" "$WITH_LIBWEBSOCKETS" $LIBWEBSOCKETS_OPTS
#
# Build guacamole-server
#
cd "$BUILD_DIR"
autoreconf -fi && ./configure --prefix="$PREFIX_DIR" $GUACAMOLE_SERVER_OPTS
make && make install

View File

@ -1,62 +0,0 @@
#!/bin/sh -e
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
##
## @fn build-guacd.sh
##
## Builds the source of guacamole-server, automatically creating any required
## symbolic links for the proper loading of FreeRDP plugins.
##
## @param BUILD_DIR
## The directory which currently contains the guacamole-server source and
## in which the build should be performed.
##
BUILD_DIR="$1"
##
## Locates the directory in which the FreeRDP libraries (.so files) are
## located, printing the result to STDOUT.
##
where_is_freerdp() {
dirname `rpm -ql freerdp-libs | grep 'libfreerdp.*\.so' | head -n1`
}
#
# Build guacamole-server
#
cd "$BUILD_DIR"
autoreconf -fi
./configure
make
make install
ldconfig
#
# Add FreeRDP plugins to proper path
#
FREERDP_DIR=`where_is_freerdp`
FREERDP_PLUGIN_DIR="$FREERDP_DIR/freerdp"
mkdir -p "$FREERDP_PLUGIN_DIR"
ln -s /usr/local/lib/freerdp/*.so "$FREERDP_PLUGIN_DIR"

View File

@ -0,0 +1,51 @@
#!/bin/sh -e
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
##
## @fn list-dependencies.sh
##
## Lists the Alpine Linux package names for all library dependencies of the
## given binaries. Each package is only listed once, even if multiple binaries
## provided by the same package are given.
##
## @param ...
## The full paths to all binaries being checked.
##
while [ -n "$1" ]; do
# For all non-Guacamole library dependencies
ldd "$1" | grep -v 'libguac' | awk '/=>/{print $(NF-1)}' \
| while read LIBRARY; do
# List the package providing that library, if any
apk info -W "$LIBRARY" 2> /dev/null \
| grep 'is owned by' | grep -o '[^ ]*$' || true
done
# Next binary
shift
# Strip the "-VERSION" suffix from each package name, listing each resulting
# package uniquely ("apk add" cannot handle package names that include the
# version number)
done | sed 's/\(.*\)-[0-9]\+\..*$/\1/' | sort -u

40
src/guacd/.gitignore vendored
View File

@ -2,42 +2,14 @@
# Compiled init script # Compiled init script
init.d/guacd init.d/guacd
# Compiled systemd unit
systemd/guacd.service
# Compiled proxy # Compiled proxy
guacd guacd
guacd.exe guacd.exe
# Object code # Documentation (built from .in files)
*.o man/guacd.8
*.so man/guacd.conf.5
*.lo
*.la
# Backup files
*~
# Release files
*.tar.gz
# Files currently being edited by vim or vi
*.swp
# automake/autoconf
.deps/
.libs/
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
m4/
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
libtool
ltmain.sh
missing

View File

@ -16,6 +16,12 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
# #
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
@ -26,6 +32,7 @@ man_MANS = \
man/guacd.conf.5 man/guacd.conf.5
noinst_HEADERS = \ noinst_HEADERS = \
conf.h \
conf-args.h \ conf-args.h \
conf-file.h \ conf-file.h \
conf-parse.h \ conf-parse.h \
@ -59,12 +66,13 @@ guacd_LDFLAGS = \
@PTHREAD_LIBS@ \ @PTHREAD_LIBS@ \
@SSL_LIBS@ @SSL_LIBS@
EXTRA_DIST = \ EXTRA_DIST = \
init.d/guacd.in \ init.d/guacd.in \
man/guacd.8 \ systemd/guacd.service.in \
man/guacd.conf.5 man/guacd.8.in \
man/guacd.conf.5.in
CLEANFILES = $(init_SCRIPTS) CLEANFILES = $(init_SCRIPTS) $(systemd_UNITS)
# Init script # Init script
if ENABLE_INIT if ENABLE_INIT
@ -76,3 +84,12 @@ init.d/guacd: init.d/guacd.in
chmod +x init.d/guacd chmod +x init.d/guacd
endif endif
# Systemd service
if ENABLE_SYSTEMD
systemddir = @systemd_dir@
systemd_DATA = systemd/guacd.service
systemd/guacd.service: systemd/guacd.service.in
sed -e 's,[@]sbindir[@],$(sbindir),g' < systemd/guacd.service.in > systemd/guacd.service
endif

View File

@ -19,8 +19,8 @@
#include "config.h" #include "config.h"
#include "conf.h"
#include "conf-args.h" #include "conf-args.h"
#include "conf-file.h"
#include "conf-parse.h" #include "conf-parse.h"
#include <getopt.h> #include <getopt.h>
@ -32,7 +32,7 @@ int guacd_conf_parse_args(guacd_config* config, int argc, char** argv) {
/* Parse arguments */ /* Parse arguments */
int opt; int opt;
while ((opt = getopt(argc, argv, "l:b:p:L:C:K:f")) != -1) { while ((opt = getopt(argc, argv, "l:b:p:L:C:K:fv")) != -1) {
/* -l: Bind port */ /* -l: Bind port */
if (opt == 'l') { if (opt == 'l') {
@ -51,6 +51,11 @@ int guacd_conf_parse_args(guacd_config* config, int argc, char** argv) {
config->foreground = 1; config->foreground = 1;
} }
/* -v: Print version and exit */
else if (opt == 'v') {
config->print_version = 1;
}
/* -p: PID file */ /* -p: PID file */
else if (opt == 'p') { else if (opt == 'p') {
free(config->pidfile); free(config->pidfile);
@ -105,7 +110,8 @@ int guacd_conf_parse_args(guacd_config* config, int argc, char** argv) {
" [-C CERTIFICATE_FILE]" " [-C CERTIFICATE_FILE]"
" [-K PEM_FILE]" " [-K PEM_FILE]"
#endif #endif
" [-f]\n", argv[0]); " [-f]"
" [-v]\n", argv[0]);
return 1; return 1;
} }

View File

@ -22,7 +22,7 @@
#include "config.h" #include "config.h"
#include "conf-file.h" #include "conf.h"
/** /**
* Parses the given arguments into the given configuration. Zero is returned on * Parses the given arguments into the given configuration. Zero is returned on

View File

@ -19,6 +19,7 @@
#include "config.h" #include "config.h"
#include "conf.h"
#include "conf-file.h" #include "conf-file.h"
#include "conf-parse.h" #include "conf-parse.h"
@ -175,10 +176,11 @@ guacd_config* guacd_conf_load() {
return NULL; return NULL;
/* Load defaults */ /* Load defaults */
conf->bind_host = NULL; conf->bind_host = strdup(GUACD_DEFAULT_BIND_HOST);
conf->bind_port = strdup("4822"); conf->bind_port = strdup(GUACD_DEFAULT_BIND_PORT);
conf->pidfile = NULL; conf->pidfile = NULL;
conf->foreground = 0; conf->foreground = 0;
conf->print_version = 0;
conf->max_log_level = GUAC_LOG_INFO; conf->max_log_level = GUAC_LOG_INFO;
#ifdef ENABLE_SSL #ifdef ENABLE_SSL
@ -195,6 +197,7 @@ guacd_config* guacd_conf_load() {
if (retval != 0) { if (retval != 0) {
fprintf(stderr, "Unable to parse \"" GUACD_CONF_FILE "\".\n"); fprintf(stderr, "Unable to parse \"" GUACD_CONF_FILE "\".\n");
free(conf);
return NULL; return NULL;
} }
@ -203,6 +206,7 @@ guacd_config* guacd_conf_load() {
/* Notify of errors preventing reading */ /* Notify of errors preventing reading */
else if (errno != ENOENT) { else if (errno != ENOENT) {
fprintf(stderr, "Unable to open \"" GUACD_CONF_FILE "\": %s\n", strerror(errno)); fprintf(stderr, "Unable to open \"" GUACD_CONF_FILE "\": %s\n", strerror(errno));
free(conf);
return NULL; return NULL;
} }

View File

@ -22,51 +22,7 @@
#include "config.h" #include "config.h"
#include <guacamole/client.h> #include "conf.h"
/**
* The contents of a guacd configuration file.
*/
typedef struct guacd_config {
/**
* The host to bind on.
*/
char* bind_host;
/**
* The port to bind on.
*/
char* bind_port;
/**
* The file to write the PID in, if any.
*/
char* pidfile;
/**
* Whether guacd should run in the foreground.
*/
int foreground;
#ifdef ENABLE_SSL
/**
* SSL certificate file.
*/
char* cert_file;
/**
* SSL private key file.
*/
char* key_file;
#endif
/**
* The maximum log level to be logged by guacd.
*/
guac_client_log_level max_log_level;
} guacd_config;
/** /**
* Reads the given file descriptor, parsing its contents into the guacd_config. * Reads the given file descriptor, parsing its contents into the guacd_config.

View File

@ -19,6 +19,7 @@
#include "config.h" #include "config.h"
#include "conf.h"
#include "conf-parse.h" #include "conf-parse.h"
#include <guacamole/client.h> #include <guacamole/client.h>

89
src/guacd/conf.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef GUACD_CONF_H
#define GUACD_CONF_H
#include "config.h"
#include <guacamole/client.h>
/**
* The default host that guacd should bind to, if no other host is explicitly
* specified.
*/
#define GUACD_DEFAULT_BIND_HOST "localhost"
/**
* The default port that guacd should bind to, if no other port is explicitly
* specified.
*/
#define GUACD_DEFAULT_BIND_PORT "4822"
/**
* The contents of a guacd configuration file.
*/
typedef struct guacd_config {
/**
* The host to bind on.
*/
char* bind_host;
/**
* The port to bind on.
*/
char* bind_port;
/**
* The file to write the PID in, if any.
*/
char* pidfile;
/**
* Whether guacd should run in the foreground.
*/
int foreground;
/**
* Whether guacd should simply print its version information and exit.
*/
int print_version;
#ifdef ENABLE_SSL
/**
* SSL certificate file.
*/
char* cert_file;
/**
* SSL private key file.
*/
char* key_file;
#endif
/**
* The maximum log level to be logged by guacd.
*/
guac_client_log_level max_log_level;
} guacd_config;
#endif

View File

@ -278,10 +278,13 @@ static int guacd_route_connection(guacd_proc_map* map, guac_socket* socket) {
proc = guacd_proc_map_retrieve(map, identifier); proc = guacd_proc_map_retrieve(map, identifier);
new_process = 0; new_process = 0;
/* Warn if requested connection does not exist */ /* Warn and ward off client if requested connection does not exist */
if (proc == NULL) if (proc == NULL) {
guacd_log(GUAC_LOG_INFO, "Connection \"%s\" does not exist.", guacd_log(GUAC_LOG_INFO, "Connection \"%s\" does not exist", identifier);
identifier); guac_protocol_send_error(socket, "No such connection.",
GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
}
else else
guacd_log(GUAC_LOG_INFO, "Joining existing connection \"%s\"", guacd_log(GUAC_LOG_INFO, "Joining existing connection \"%s\"",
identifier); identifier);

View File

@ -19,9 +19,10 @@
#include "config.h" #include "config.h"
#include "connection.h" #include "conf.h"
#include "conf-args.h" #include "conf-args.h"
#include "conf-file.h" #include "conf-file.h"
#include "connection.h"
#include "log.h" #include "log.h"
#include "proc-map.h" #include "proc-map.h"
@ -279,6 +280,13 @@ int main(int argc, char* argv[]) {
if (config == NULL || guacd_conf_parse_args(config, argc, argv)) if (config == NULL || guacd_conf_parse_args(config, argc, argv))
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
/* If requested, simply print version and exit, without initializing the
* logging system, etc. */
if (config->print_version) {
printf("Guacamole proxy daemon (guacd) version " VERSION "\n");
exit(EXIT_SUCCESS);
}
/* Init logging as early as possible */ /* Init logging as early as possible */
guacd_log_level = config->max_log_level; guacd_log_level = config->max_log_level;
openlog(GUACD_LOG_NAME, LOG_PID, LOG_DAEMON); openlog(GUACD_LOG_NAME, LOG_PID, LOG_DAEMON);
@ -296,20 +304,6 @@ int main(int argc, char* argv[]) {
} }
/* Get socket */
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0) {
guacd_log(GUAC_LOG_ERROR, "Error opening socket: %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Allow socket reuse */
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,
(void*) &opt_on, sizeof(opt_on))) {
guacd_log(GUAC_LOG_WARNING, "Unable to set socket options for reuse: %s",
strerror(errno));
}
/* Attempt binding of each address until success */ /* Attempt binding of each address until success */
current_address = addresses; current_address = addresses;
while (current_address != NULL) { while (current_address != NULL) {
@ -325,27 +319,47 @@ int main(int argc, char* argv[]) {
guacd_log(GUAC_LOG_ERROR, "Unable to resolve host: %s", guacd_log(GUAC_LOG_ERROR, "Unable to resolve host: %s",
gai_strerror(retval)); gai_strerror(retval));
/* Get socket */
socket_fd = socket(current_address->ai_family, SOCK_STREAM, 0);
if (socket_fd < 0) {
guacd_log(GUAC_LOG_ERROR, "Error opening socket: %s", strerror(errno));
/* Unable to get a socket for the resolved address family, try next */
current_address = current_address->ai_next;
continue;
}
/* Allow socket reuse */
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,
(void*) &opt_on, sizeof(opt_on))) {
guacd_log(GUAC_LOG_WARNING, "Unable to set socket options for reuse: %s",
strerror(errno));
}
/* Attempt to bind socket to address */ /* Attempt to bind socket to address */
if (bind(socket_fd, if (bind(socket_fd,
current_address->ai_addr, current_address->ai_addr,
current_address->ai_addrlen) == 0) { current_address->ai_addrlen) == 0) {
guacd_log(GUAC_LOG_DEBUG, "Successfully bound socket to " guacd_log(GUAC_LOG_DEBUG, "Successfully bound "
"host %s, port %s", bound_address, bound_port); "%s socket to host %s, port %s",
(current_address->ai_family == AF_INET) ? "AF_INET" : "AF_INET6",
bound_address, bound_port);
/* Done if successful bind */ /* Done if successful bind */
break; break;
} }
/* Otherwise log information regarding bind failure */ /* Otherwise log information regarding bind failure */
else close(socket_fd);
guacd_log(GUAC_LOG_DEBUG, "Unable to bind socket to " socket_fd = -1;
"host %s, port %s: %s", guacd_log(GUAC_LOG_DEBUG, "Unable to bind %s socket to "
bound_address, bound_port, strerror(errno)); "host %s, port %s: %s",
(current_address->ai_family == AF_INET) ? "AF_INET" : "AF_INET6",
bound_address, bound_port, strerror(errno));
/* Try next address */
current_address = current_address->ai_next; current_address = current_address->ai_next;
} }
/* If unable to bind to anything, fail */ /* If unable to bind to anything, fail */
@ -367,10 +381,15 @@ int main(int argc, char* argv[]) {
CRYPTO_set_locking_callback(guacd_openssl_locking_callback); CRYPTO_set_locking_callback(guacd_openssl_locking_callback);
#endif #endif
/* Init SSL */ #if OPENSSL_VERSION_NUMBER < 0x10100000L
/* Init OpenSSL for OpenSSL Versions < 1.1.0 */
SSL_library_init(); SSL_library_init();
SSL_load_error_strings(); SSL_load_error_strings();
ssl_context = SSL_CTX_new(SSLv23_server_method()); ssl_context = SSL_CTX_new(SSLv23_server_method());
#else
/* Set up OpenSSL for OpenSSL Versions >= 1.1.0 */
ssl_context = SSL_CTX_new(TLS_server_method());
#endif
/* Load key */ /* Load key */
if (config->key_file != NULL) { if (config->key_file != NULL) {

View File

@ -133,7 +133,7 @@ void guacd_log_guac_error(guac_client_log_level level, const char* message) {
void guacd_log_handshake_failure() { void guacd_log_handshake_failure() {
if (guac_error == GUAC_STATUS_CLOSED) if (guac_error == GUAC_STATUS_CLOSED)
guacd_log(GUAC_LOG_INFO, guacd_log(GUAC_LOG_DEBUG,
"Guacamole connection closed during handshake"); "Guacamole connection closed during handshake");
else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR) else if (guac_error == GUAC_STATUS_PROTOCOL_ERROR)
guacd_log(GUAC_LOG_ERROR, guacd_log(GUAC_LOG_ERROR,

View File

@ -16,7 +16,7 @@
.\" specific language governing permissions and limitations .\" specific language governing permissions and limitations
.\" under the License. .\" under the License.
.\" .\"
.TH guacd 8 "1 Jun 2017" "version 0.9.13-incubating" "Guacamole" .TH guacd 8 "1 Jun 2017" "version @PACKAGE_VERSION@" "Apache Guacamole"
. .
.SH NAME .SH NAME
guacd \- Guacamole proxy daemon guacd \- Guacamole proxy daemon
@ -30,6 +30,7 @@ guacd \- Guacamole proxy daemon
[\fB-C\fR \fICERTIFICATE FILE\fR] [\fB-C\fR \fICERTIFICATE FILE\fR]
[\fB-K\fR \fIKEY FILE\fR] [\fB-K\fR \fIKEY FILE\fR]
[\fB-f\fR] [\fB-f\fR]
[\fB-v\fR]
. .
.SH DESCRIPTION .SH DESCRIPTION
.B guacd .B guacd
@ -80,6 +81,11 @@ Causes
.B guacd .B guacd
to run in the foreground, rather than automatically forking into the to run in the foreground, rather than automatically forking into the
background. background.
.TP
\fB\-v\fR
Causes
.B guacd
to simply print its version information and exit.
. .
.SH SSL/TLS OPTIONS .SH SSL/TLS OPTIONS
If libssl was present at the time If libssl was present at the time
@ -113,6 +119,3 @@ this option is not given, communication with guacd must be unencrypted.
. .
.SH SEE ALSO .SH SEE ALSO
.BR guacd.conf (5) .BR guacd.conf (5)
.
.SH AUTHOR
Written by Michael Jumper <mike.jumper@guac-dev.org>

View File

@ -16,7 +16,7 @@
.\" specific language governing permissions and limitations .\" specific language governing permissions and limitations
.\" under the License. .\" under the License.
.\" .\"
.TH guacd.conf 5 "1 Jun 2017" "version 0.9.13-incubating" "Guacamole" .TH guacd.conf 5 "1 Jun 2017" "version @PACKAGE_VERSION@" "Apache Guacamole"
. .
.SH NAME .SH NAME
/etc/guacamole/guacd.conf \- Configuration file for guacd /etc/guacamole/guacd.conf \- Configuration file for guacd
@ -176,6 +176,3 @@ server_certificate = /etc/ssl/certs/guacd.crt
server_key = /etc/ssl/private/guacd.key server_key = /etc/ssl/private/guacd.key
.RE .RE
.fi .fi
.
.SH AUTHOR
Written by Michael Jumper <mike.jumper@guac-dev.org>

View File

@ -44,7 +44,7 @@ int guacd_send_fd(int sock, int fd) {
message.msg_iovlen = 1; message.msg_iovlen = 1;
/* Assign ancillary data buffer */ /* Assign ancillary data buffer */
char buffer[CMSG_SPACE(sizeof(fd))]; char buffer[CMSG_SPACE(sizeof(fd))] = {0};
message.msg_control = buffer; message.msg_control = buffer;
message.msg_controllen = sizeof(buffer); message.msg_controllen = sizeof(buffer);

View File

@ -33,11 +33,15 @@
#include <guacamole/user.h> #include <guacamole/user.h>
#include <errno.h> #include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h>
/** /**
* Parameters for the user thread. * Parameters for the user thread.
@ -138,6 +142,151 @@ static void guacd_proc_add_user(guacd_proc* proc, int fd, int owner) {
} }
/**
* Forcibly kills all processes within the current process group, including the
* current process and all child processes. This function is only safe to call
* if the process group ID has been correctly set. Calling this function within
* a process which does not have a PGID separate from the main guacd process
* can result in guacd itself being terminated.
*/
static void guacd_kill_current_proc_group() {
/* Forcibly kill all children within process group */
if (kill(0, SIGKILL))
guacd_log(GUAC_LOG_WARNING, "Unable to forcibly terminate "
"client process: %s ", strerror(errno));
}
/**
* The current status of a background attempt to free a guac_client instance.
*/
typedef struct guacd_client_free {
/**
* The guac_client instance being freed.
*/
guac_client* client;
/**
* The condition which is signalled whenever changes are made to the
* completed flag. The completed flag only changes from zero (not yet
* freed) to non-zero (successfully freed).
*/
pthread_cond_t completed_cond;
/**
* Mutex which must be acquired before any changes are made to the
* completed flag.
*/
pthread_mutex_t completed_mutex;
/**
* Whether the guac_client has been successfully freed. Initially, this
* will be zero, indicating that the free operation has not yet been
* attempted. If the client is eventually successfully freed, this will be
* set to a non-zero value. Changes to this flag are signalled through
* the completed_cond condition.
*/
int completed;
} guacd_client_free;
/**
* Thread which frees a given guac_client instance in the background. If the
* free operation succeeds, a flag is set on the provided structure, and the
* change in that flag is signalled with a pthread condition.
*
* At the time this function is provided to a pthread_create() call, the
* completed flag of the associated guacd_client_free structure MUST be
* initialized to zero, the pthread mutex and condition MUST both be
* initialized, and the client pointer must point to the guac_client being
* freed.
*
* @param data
* A pointer to a guacd_client_free structure describing the free
* operation.
*
* @return
* Always NULL.
*/
static void* guacd_client_free_thread(void* data) {
guacd_client_free* free_operation = (guacd_client_free*) data;
/* Attempt to free client (this may never return if the client is
* malfunctioning) */
guac_client_free(free_operation->client);
/* Signal that the client was successfully freed */
pthread_mutex_lock(&free_operation->completed_mutex);
free_operation->completed = 1;
pthread_cond_broadcast(&free_operation->completed_cond);
pthread_mutex_unlock(&free_operation->completed_mutex);
return NULL;
}
/**
* Attempts to free the given guac_client, restricting the time taken by the
* free handler of the guac_client to a finite number of seconds. If the free
* handler does not complete within the time alotted, this function returns
* and the intended free operation is left in an undefined state.
*
* @param client
* The guac_client instance to free.
*
* @param timeout
* The maximum amount of time to wait for the guac_client to be freed,
* in seconds.
*
* @return
* Zero if the guac_client was successfully freed within the time alotted,
* non-zero otherwise.
*/
static int guacd_timed_client_free(guac_client* client, int timeout) {
pthread_t client_free_thread;
guacd_client_free free_operation = {
.client = client,
.completed_cond = PTHREAD_COND_INITIALIZER,
.completed_mutex = PTHREAD_MUTEX_INITIALIZER,
.completed = 0
};
/* Get current time */
struct timeval current_time;
if (gettimeofday(&current_time, NULL))
return 1;
/* Calculate exact time that the free operation MUST complete by */
struct timespec deadline = {
.tv_sec = current_time.tv_sec + timeout,
.tv_nsec = current_time.tv_usec * 1000
};
/* The mutex associated with the pthread conditional and flag MUST be
* acquired before attempting to wait for the condition */
if (pthread_mutex_lock(&free_operation.completed_mutex))
return 1;
/* Free the client in a separate thread, so we can time the free operation */
if (!pthread_create(&client_free_thread, NULL,
guacd_client_free_thread, &free_operation)) {
/* Wait a finite amount of time for the free operation to finish */
(void) pthread_cond_timedwait(&free_operation.completed_cond,
&free_operation.completed_mutex, &deadline);
}
(void) pthread_mutex_unlock(&free_operation.completed_mutex);
/* Return status of free operation */
return !free_operation.completed;
}
/** /**
* Starts protocol-specific handling on the given process by loading the client * Starts protocol-specific handling on the given process by loading the client
* plugin for that protocol. This function does NOT return. It initializes the * plugin for that protocol. This function does NOT return. It initializes the
@ -154,8 +303,18 @@ static void guacd_proc_add_user(guacd_proc* proc, int fd, int owner) {
*/ */
static void guacd_exec_proc(guacd_proc* proc, const char* protocol) { static void guacd_exec_proc(guacd_proc* proc, const char* protocol) {
int result = 1;
/* Set process group ID to match PID */
if (setpgid(0, 0)) {
guacd_log(GUAC_LOG_ERROR, "Cannot set PGID for connection process: %s",
strerror(errno));
goto cleanup_process;
}
/* Init client for selected protocol */ /* Init client for selected protocol */
if (guac_client_load_plugin(proc->client, protocol)) { guac_client* client = proc->client;
if (guac_client_load_plugin(client, protocol)) {
/* Log error */ /* Log error */
if (guac_error == GUAC_STATUS_NOT_FOUND) if (guac_error == GUAC_STATUS_NOT_FOUND)
@ -165,15 +324,15 @@ static void guacd_exec_proc(guacd_proc* proc, const char* protocol) {
guacd_log_guac_error(GUAC_LOG_ERROR, guacd_log_guac_error(GUAC_LOG_ERROR,
"Unable to load client plugin"); "Unable to load client plugin");
guac_client_free(proc->client); goto cleanup_client;
close(proc->fd_socket);
free(proc);
exit(1);
} }
/* The first file descriptor is the owner */ /* The first file descriptor is the owner */
int owner = 1; int owner = 1;
/* Enable keep alive on the broadcast socket */
guac_socket_require_keep_alive(client->socket);
/* Add each received file descriptor as a new user */ /* Add each received file descriptor as a new user */
int received_fd; int received_fd;
while ((received_fd = guacd_recv_fd(proc->fd_socket)) != -1) { while ((received_fd = guacd_recv_fd(proc->fd_socket)) != -1) {
@ -185,14 +344,47 @@ static void guacd_exec_proc(guacd_proc* proc, const char* protocol) {
} }
/* Stop and free client */ cleanup_client:
guac_client_stop(proc->client);
guac_client_free(proc->client);
/* Child is finished */ /* Request client to stop/disconnect */
guac_client_stop(client);
/* Attempt to free client cleanly */
guacd_log(GUAC_LOG_DEBUG, "Requesting termination of client...");
result = guacd_timed_client_free(client, GUACD_CLIENT_FREE_TIMEOUT);
/* If client was unable to be freed, warn and forcibly kill */
if (result) {
guacd_log(GUAC_LOG_WARNING, "Client did not terminate in a timely "
"manner. Forcibly terminating client and any child "
"processes.");
guacd_kill_current_proc_group();
}
else
guacd_log(GUAC_LOG_DEBUG, "Client terminated successfully.");
/* Verify whether children were all properly reaped */
pid_t child_pid;
while ((child_pid = waitpid(0, NULL, WNOHANG)) > 0) {
guacd_log(GUAC_LOG_DEBUG, "Automatically reaped unreaped "
"(zombie) child process with PID %i.", child_pid);
}
/* If running children remain, warn and forcibly kill */
if (child_pid == 0) {
guacd_log(GUAC_LOG_WARNING, "Client reported successful termination, "
"but child processes remain. Forcibly terminating client and "
"child processes.");
guacd_kill_current_proc_group();
}
cleanup_process:
/* Free up all internal resources outside the client */
close(proc->fd_socket); close(proc->fd_socket);
free(proc); free(proc);
exit(0);
exit(result);
} }

View File

@ -40,6 +40,14 @@
*/ */
#define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000) #define GUACD_USEC_TIMEOUT (GUACD_TIMEOUT*1000)
/**
* The number of seconds to wait for any particular guac_client instance
* to be freed following disconnect. If the free operation does not complete
* within this period of time, the associated process will be forcibly
* terminated.
*/
#define GUACD_CLIENT_FREE_TIMEOUT 5
/** /**
* Process information of the internal remote desktop client. * Process information of the internal remote desktop client.
*/ */

View File

@ -0,0 +1,29 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
[Unit]
Description=Guacamole Server
Documentation=man:guacd(8)
After=network.target
[Service]
User=daemon
ExecStart=@sbindir@/guacd -f
Restart=on-abnormal
[Install]
WantedBy=multi-user.target

View File

@ -3,3 +3,6 @@
guacenc guacenc
guacenc.exe guacenc.exe
# Documentation (built from .in files)
man/guacenc.1

View File

@ -16,6 +16,12 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
# #
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
@ -26,6 +32,7 @@ man_MANS = \
noinst_HEADERS = \ noinst_HEADERS = \
buffer.h \ buffer.h \
cursor.h \
display.h \ display.h \
encode.h \ encode.h \
ffmpeg-compat.h \ ffmpeg-compat.h \
@ -41,6 +48,7 @@ noinst_HEADERS = \
guacenc_SOURCES = \ guacenc_SOURCES = \
buffer.c \ buffer.c \
cursor.c \
display.c \ display.c \
display-buffers.c \ display-buffers.c \
display-image-streams.c \ display-image-streams.c \
@ -59,6 +67,7 @@ guacenc_SOURCES = \
instruction-dispose.c \ instruction-dispose.c \
instruction-end.c \ instruction-end.c \
instruction-img.c \ instruction-img.c \
instruction-mouse.c \
instruction-move.c \ instruction-move.c \
instruction-rect.c \ instruction-rect.c \
instruction-shade.c \ instruction-shade.c \
@ -81,6 +90,7 @@ endif
guacenc_CFLAGS = \ guacenc_CFLAGS = \
-Werror -Wall \ -Werror -Wall \
@AVCODEC_CFLAGS@ \ @AVCODEC_CFLAGS@ \
@AVFORMAT_CFLAGS@ \
@AVUTIL_CFLAGS@ \ @AVUTIL_CFLAGS@ \
@LIBGUAC_INCLUDE@ \ @LIBGUAC_INCLUDE@ \
@SWSCALE_CFLAGS@ @SWSCALE_CFLAGS@
@ -88,14 +98,15 @@ guacenc_CFLAGS = \
guacenc_LDADD = \ guacenc_LDADD = \
@LIBGUAC_LTLIB@ @LIBGUAC_LTLIB@
guacenc_LDFLAGS = \ guacenc_LDFLAGS = \
@AVCODEC_LIBS@ \ @AVCODEC_LIBS@ \
@AVUTIL_LIBS@ \ @AVFORMAT_LIBS@ \
@CAIRO_LIBS@ \ @AVUTIL_LIBS@ \
@JPEG_LIBS@ \ @CAIRO_LIBS@ \
@SWSCALE_LIBS@ \ @JPEG_LIBS@ \
@SWSCALE_LIBS@ \
@WEBP_LIBS@ @WEBP_LIBS@
EXTRA_DIST = \ EXTRA_DIST = \
man/guacenc.1 man/guacenc.1.in

View File

@ -18,40 +18,42 @@
*/ */
#include "config.h" #include "config.h"
#include "buffer.h"
#include "cursor.h"
#include "common_suite.h" #include <stdlib.h>
#include <CUnit/Basic.h> guacenc_cursor* guacenc_cursor_alloc() {
int common_suite_init() { /* Allocate new cursor */
return 0; guacenc_cursor* cursor = (guacenc_cursor*) malloc(sizeof(guacenc_cursor));
} if (cursor == NULL)
return NULL;
int common_suite_cleanup() { /* Allocate associated buffer (image) */
return 0; cursor->buffer = guacenc_buffer_alloc();
} if (cursor->buffer == NULL) {
free(cursor);
int register_common_suite() { return NULL;
/* Add common test suite */
CU_pSuite suite = CU_add_suite("common",
common_suite_init, common_suite_cleanup);
if (suite == NULL) {
CU_cleanup_registry();
return CU_get_error();
} }
/* Add tests */ /* Do not initially render cursor, unless it moves */
if ( cursor->x = cursor->y = -1;
CU_add_test(suite, "guac-iconv", test_guac_iconv) == NULL
|| CU_add_test(suite, "guac-string", test_guac_string) == NULL
|| CU_add_test(suite, "guac-rect", test_guac_rect) == NULL
) {
CU_cleanup_registry();
return CU_get_error();
}
return 0; return cursor;
}
void guacenc_cursor_free(guacenc_cursor* cursor) {
/* Ignore NULL cursors */
if (cursor == NULL)
return;
/* Free underlying buffer */
guacenc_buffer_free(cursor->buffer);
free(cursor);
} }

87
src/guacenc/cursor.h Normal file
View File

@ -0,0 +1,87 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifndef GUACENC_CURSOR_H
#define GUACENC_CURSOR_H
#include "config.h"
#include "buffer.h"
#include <guacamole/protocol.h>
#include <guacamole/timestamp.h>
/**
* A mouse cursor, having a current location, hostspot, and associated cursor
* image.
*/
typedef struct guacenc_cursor {
/**
* The current X coordinate of the mouse cursor, in pixels. Valid values
* are non-negative. Negative values indicate that the cursor should not
* be rendered.
*/
int x;
/**
* The current Y coordinate of the mouse cursor, in pixels. Valid values
* are non-negative. Negative values indicate that the cursor should not
* be rendered.
*/
int y;
/**
* The X coordinate of the mouse cursor hotspot within the cursor image,
* in pixels.
*/
int hotspot_x;
/**
* The Y coordinate of the mouse cursor hotspot within the cursor image,
* in pixels.
*/
int hotspot_y;
/**
* The current mouse cursor image.
*/
guacenc_buffer* buffer;
} guacenc_cursor;
/**
* Allocates and initializes a new cursor object.
*
* @return
* A newly-allocated and initialized guacenc_cursor, or NULL if allocation
* fails.
*/
guacenc_cursor* guacenc_cursor_alloc();
/**
* Frees all memory associated with the given cursor object. If the cursor
* provided is NULL, this function has no effect.
*
* @param cursor
* The cursor to free, which may be NULL.
*/
void guacenc_cursor_free(guacenc_cursor* cursor);
#endif

View File

@ -20,9 +20,12 @@
#include "config.h" #include "config.h"
#include "display.h" #include "display.h"
#include "layer.h" #include "layer.h"
#include "log.h"
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <guacamole/client.h>
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -75,6 +78,50 @@ static int guacenc_display_layer_comparator(const void* a, const void* b) {
} }
/**
* Renders the mouse cursor on top of the frame buffer of the default layer of
* the given display.
*
* @param display
* The display whose mouse cursor should be rendered to the frame buffer
* of its default layer.
*
* @return
* Zero if rendering succeeds, non-zero otherwise.
*/
static int guacenc_display_render_cursor(guacenc_display* display) {
guacenc_cursor* cursor = display->cursor;
/* Do not render cursor if coordinates are negative */
if (cursor->x < 0 || cursor->y < 0)
return 0;
/* Retrieve default layer (guaranteed to not be NULL) */
guacenc_layer* def_layer = guacenc_display_get_layer(display, 0);
assert(def_layer != NULL);
/* Get source and destination buffers */
guacenc_buffer* src = cursor->buffer;
guacenc_buffer* dst = def_layer->frame;
/* Render cursor to layer */
if (src->width > 0 && src->height > 0) {
cairo_set_source_surface(dst->cairo, src->surface,
cursor->x - cursor->hotspot_x,
cursor->y - cursor->hotspot_y);
cairo_rectangle(dst->cairo,
cursor->x - cursor->hotspot_x,
cursor->y - cursor->hotspot_y,
src->width, src->height);
cairo_fill(dst->cairo);
}
/* Always succeeds */
return 0;
}
int guacenc_display_flatten(guacenc_display* display) { int guacenc_display_flatten(guacenc_display* display) {
int i; int i;
@ -151,7 +198,8 @@ int guacenc_display_flatten(guacenc_display* display) {
} }
return 0; /* Render cursor on top of everything else */
return guacenc_display_render_cursor(display);
} }

View File

@ -18,6 +18,7 @@
*/ */
#include "config.h" #include "config.h"
#include "cursor.h"
#include "display.h" #include "display.h"
#include "video.h" #include "video.h"
@ -97,6 +98,9 @@ guacenc_display* guacenc_display_alloc(const char* path, const char* codec,
/* Associate display with video output */ /* Associate display with video output */
display->output = video; display->output = video;
/* Allocate special-purpose cursor layer */
display->cursor = guacenc_cursor_alloc();
return display; return display;
} }
@ -124,6 +128,9 @@ int guacenc_display_free(guacenc_display* display) {
for (i = 0; i < GUACENC_DISPLAY_MAX_STREAMS; i++) for (i = 0; i < GUACENC_DISPLAY_MAX_STREAMS; i++)
guacenc_image_stream_free(display->image_streams[i]); guacenc_image_stream_free(display->image_streams[i]);
/* Free cursor */
guacenc_cursor_free(display->cursor);
free(display); free(display);
return retval; return retval;

View File

@ -22,10 +22,12 @@
#include "config.h" #include "config.h"
#include "buffer.h" #include "buffer.h"
#include "cursor.h"
#include "image-stream.h" #include "image-stream.h"
#include "layer.h" #include "layer.h"
#include "video.h" #include "video.h"
#include <cairo/cairo.h>
#include <guacamole/protocol.h> #include <guacamole/protocol.h>
#include <guacamole/timestamp.h> #include <guacamole/timestamp.h>
@ -52,6 +54,11 @@
*/ */
typedef struct guacenc_display { typedef struct guacenc_display {
/**
* The current mouse cursor state.
*/
guacenc_cursor* cursor;
/** /**
* All currently-allocated buffers. The index of the buffer corresponds to * All currently-allocated buffers. The index of the buffer corresponds to
* its position within this array, where -1 is the 0th entry. If a buffer * its position within this array, where -1 is the 0th entry. If a buffer

View File

@ -63,8 +63,11 @@ static int guacenc_read_instructions(guacenc_display* display,
/* Continuously read and handle all instructions */ /* Continuously read and handle all instructions */
while (!guac_parser_read(parser, socket, -1)) { while (!guac_parser_read(parser, socket, -1)) {
guacenc_handle_instruction(display, parser->opcode, if (guacenc_handle_instruction(display, parser->opcode,
parser->argc, parser->argv); parser->argc, parser->argv)) {
guacenc_log(GUAC_LOG_DEBUG, "Handling of \"%s\" instruction "
"failed.", parser->opcode);
}
} }
/* Fail on read/parse error */ /* Fail on read/parse error */

View File

@ -51,8 +51,41 @@
*/ */
static int guacenc_write_packet(guacenc_video* video, void* data, int size) { static int guacenc_write_packet(guacenc_video* video, void* data, int size) {
/* Write data, logging any errors */ int ret;
if (fwrite(data, 1, size, video->output) == 0) {
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54,1,0)
AVPacket pkt;
/* Have to create a packet around the encoded data we have */
av_init_packet(&pkt);
if (video->context->coded_frame->pts != AV_NOPTS_VALUE) {
pkt.pts = av_rescale_q(video->context->coded_frame->pts,
video->context->time_base,
video->output_stream->time_base);
}
if (video->context->coded_frame->key_frame) {
pkt->flags |= AV_PKT_FLAG_KEY;
}
pkt.data = data;
pkt.size = size;
pkt.stream_index = video->output_stream->index;
ret = av_interleaved_write_frame(video->container_format_context, &pkt);
#else
/* We know data is already a packet if we're using a newer libavcodec */
AVPacket* pkt = (AVPacket*) data;
av_packet_rescale_ts(pkt, video->context->time_base, video->output_stream->time_base);
pkt->stream_index = video->output_stream->index;
ret = av_interleaved_write_frame(video->container_format_context, pkt);
#endif
if (ret != 0) {
guacenc_log(GUAC_LOG_ERROR, "Unable to write frame " guacenc_log(GUAC_LOG_ERROR, "Unable to write frame "
"#%" PRId64 ": %s", video->next_pts, strerror(errno)); "#%" PRId64 ": %s", video->next_pts, strerror(errno));
return -1; return -1;
@ -62,8 +95,7 @@ static int guacenc_write_packet(guacenc_video* video, void* data, int size) {
guacenc_log(GUAC_LOG_DEBUG, "Frame #%08" PRId64 ": wrote %i bytes", guacenc_log(GUAC_LOG_DEBUG, "Frame #%08" PRId64 ": wrote %i bytes",
video->next_pts, size); video->next_pts, size);
return 0; return ret;
} }
int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) { int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
@ -103,6 +135,15 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
#else #else
/* For libavcodec < 57.37.100: input/output was not decoupled and static
* allocation of AVPacket was supported.
*
* NOTE: Since dynamic allocation of AVPacket was added before this point (in
* 57.12.100) and static allocation was deprecated later (in 58.133.100), it is
* convenient to tie static vs. dynamic allocation to the old vs. new I/O
* mechanism and avoid further complicating the version comparison logic. */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 37, 100)
/* Init video packet */ /* Init video packet */
AVPacket packet; AVPacket packet;
av_init_packet(&packet); av_init_packet(&packet);
@ -111,8 +152,6 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
packet.data = NULL; packet.data = NULL;
packet.size = 0; packet.size = 0;
/* For libavcodec < 57.37.100: input/output was not decoupled */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57,37,100)
/* Write frame to video */ /* Write frame to video */
int got_data; int got_data;
if (avcodec_encode_video2(video->context, &packet, frame, &got_data) < 0) { if (avcodec_encode_video2(video->context, &packet, frame, &got_data) < 0) {
@ -123,10 +162,12 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
/* Write corresponding data to file */ /* Write corresponding data to file */
if (got_data) { if (got_data) {
guacenc_write_packet(video, packet.data, packet.size); guacenc_write_packet(video, (void*) &packet, packet.size);
av_packet_unref(&packet); av_packet_unref(&packet);
} }
#else #else
/* Write frame to video */ /* Write frame to video */
int result = avcodec_send_frame(video->context, frame); int result = avcodec_send_frame(video->context, frame);
@ -141,18 +182,25 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
return -1; return -1;
} }
AVPacket* packet = av_packet_alloc();
if (packet == NULL)
return -1;
/* Flush all available packets */ /* Flush all available packets */
int got_data = 0; int got_data = 0;
while (avcodec_receive_packet(video->context, &packet) == 0) { while (avcodec_receive_packet(video->context, packet) == 0) {
/* Data was received */ /* Data was received */
got_data = 1; got_data = 1;
/* Attempt to write data to output file */ /* Attempt to write data to output file */
guacenc_write_packet(video, packet.data, packet.size); guacenc_write_packet(video, (void*) packet, packet->size);
av_packet_unref(&packet); av_packet_unref(packet);
} }
av_packet_free(&packet);
#endif #endif
/* Frame may have been queued for later writing / reordering */ /* Frame may have been queued for later writing / reordering */
@ -165,3 +213,54 @@ int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame) {
#endif #endif
} }
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec,
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
int pix_fmt, AVRational time_base) {
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 33, 100)
stream->codec->bit_rate = bitrate;
stream->codec->width = width;
stream->codec->height = height;
stream->codec->gop_size = gop_size;
stream->codec->qmax = qmax;
stream->codec->qmin = qmin;
stream->codec->pix_fmt = pix_fmt;
stream->codec->time_base = time_base;
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 44, 100)
stream->time_base = time_base;
#endif
return stream->codec;
#else
AVCodecContext* context = avcodec_alloc_context3(codec);
if (context) {
context->bit_rate = bitrate;
context->width = width;
context->height = height;
context->gop_size = gop_size;
context->qmax = qmax;
context->qmin = qmin;
context->pix_fmt = pix_fmt;
context->time_base = time_base;
stream->time_base = time_base;
}
return context;
#endif
}
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
const AVCodec *codec, AVDictionary **options,
AVStream* stream) {
int ret = avcodec_open2(avcodec_context, codec, options);
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100)
/* Copy stream parameters to the muxer */
int codecpar_ret = avcodec_parameters_from_context(stream->codecpar, avcodec_context);
if (codecpar_ret < 0)
return codecpar_ret;
#endif
return ret;
}

View File

@ -52,6 +52,16 @@
#define av_packet_unref av_free_packet #define av_packet_unref av_free_packet
#endif #endif
/* For libavcodec <= 56.41.100: Global header flag didn't have AV_ prefix.
* Guacenc defines its own flag here to avoid conflicts with libavcodec
* macros.
*/
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(56,41,100)
#define GUACENC_FLAG_GLOBAL_HEADER CODEC_FLAG_GLOBAL_HEADER
#else
#define GUACENC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER
#endif
/* For libavutil < 51.42.0: AV_PIX_FMT_* was PIX_FMT_* */ /* For libavutil < 51.42.0: AV_PIX_FMT_* was PIX_FMT_* */
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51,42,0) #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51,42,0)
#define AV_PIX_FMT_RGB32 PIX_FMT_RGB32 #define AV_PIX_FMT_RGB32 PIX_FMT_RGB32
@ -78,5 +88,78 @@
*/ */
int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame); int guacenc_avcodec_encode_video(guacenc_video* video, AVFrame* frame);
/**
* Creates and sets up the AVCodecContext for the appropriate version of
* libavformat installed. The AVCodecContext will be built, but the AVStream
* will also be affected by having its time_base field set to the value passed
* into this function.
*
* @param stream
* The open AVStream.
*
* @param codec
* The codec used on the AVStream.
*
* @param bitrate
* The target bitrate for the encoded video
*
* @param width
* The target width for the encoded video.
*
* @param height
* The target height for the encoded video.
*
* @param gop_size
* The size of the Group of Pictures.
*
* @param qmax
* The max value of the quantizer.
*
* @param qmin
* The min value of the quantizer.
*
* @param pix_fmt
* The target pixel format for the encoded video.
*
* @param time_base
* The target time base for the encoded video.
*
* @return
* The pointer to the configured AVCodecContext.
*
*/
AVCodecContext* guacenc_build_avcodeccontext(AVStream* stream, const AVCodec* codec,
int bitrate, int width, int height, int gop_size, int qmax, int qmin,
int pix_fmt, AVRational time_base);
/**
* A wrapper for avcodec_open2(). Because libavformat ver 57.33.100 and greater
* use stream->codecpar rather than stream->codec to handle information to the
* codec, there needs to be an additional step in that version. So this
* wrapper handles that. Otherwise, it's the same as avcodec_open2().
*
* @param avcodec_context
* The context to initialize.
*
* @param codec
* The codec to open this context for. If a non-NULL codec has been
* previously passed to avcodec_alloc_context3() or for this context, then
* this parameter MUST be either NULL or equal to the previously passed
* codec.
*
* @param options
* A dictionary filled with AVCodecContext and codec-private options. On
* return this object will be filled with options that were not found.
*
* @param stream
* The stream for the codec context.
*
* @return
* Zero on success, a negative value on error.
*/
int guacenc_open_avcodec(AVCodecContext *avcodec_context,
const AVCodec *codec, AVDictionary **options,
AVStream* stream);
#endif #endif

View File

@ -25,6 +25,7 @@
#include "parse.h" #include "parse.h"
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <getopt.h> #include <getopt.h>
#include <stdbool.h> #include <stdbool.h>
@ -75,8 +76,14 @@ int main(int argc, char* argv[]) {
guacenc_log(GUAC_LOG_INFO, "Guacamole video encoder (guacenc) " guacenc_log(GUAC_LOG_INFO, "Guacamole video encoder (guacenc) "
"version " VERSION); "version " VERSION);
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
/* Prepare libavcodec */ /* Prepare libavcodec */
avcodec_register_all(); avcodec_register_all();
#endif
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
av_register_all();
#endif
/* Track number of overall failures */ /* Track number of overall failures */
int total_files = argc - optind; int total_files = argc - optind;

View File

@ -18,6 +18,7 @@
*/ */
#include "config.h" #include "config.h"
#include "display.h"
#include "image-stream.h" #include "image-stream.h"
#include "jpeg.h" #include "jpeg.h"
#include "log.h" #include "log.h"
@ -139,6 +140,7 @@ int guacenc_image_stream_end(guacenc_image_stream* stream,
/* Draw surface to buffer */ /* Draw surface to buffer */
if (buffer->cairo != NULL) { if (buffer->cairo != NULL) {
cairo_set_operator(buffer->cairo, guacenc_display_cairo_operator(stream->mask));
cairo_set_source_surface(buffer->cairo, surface, stream->x, stream->y); cairo_set_source_surface(buffer->cairo, surface, stream->x, stream->y);
cairo_rectangle(buffer->cairo, stream->x, stream->y, width, height); cairo_rectangle(buffer->cairo, stream->x, stream->y, width, height);
cairo_fill(buffer->cairo); cairo_fill(buffer->cairo);

View File

@ -18,6 +18,8 @@
*/ */
#include "config.h" #include "config.h"
#include "buffer.h"
#include "cursor.h"
#include "display.h" #include "display.h"
#include "log.h" #include "log.h"
@ -36,16 +38,32 @@ int guacenc_handle_cursor(guacenc_display* display, int argc, char** argv) {
/* Parse arguments */ /* Parse arguments */
int hotspot_x = atoi(argv[0]); int hotspot_x = atoi(argv[0]);
int hotspot_y = atoi(argv[1]); int hotspot_y = atoi(argv[1]);
int src_index = atoi(argv[2]); int sindex = atoi(argv[2]);
int src_x = atoi(argv[3]); int sx = atoi(argv[3]);
int src_y = atoi(argv[4]); int sy = atoi(argv[4]);
int src_w = atoi(argv[5]); int width = atoi(argv[5]);
int src_h = atoi(argv[6]); int height = atoi(argv[6]);
/* Nothing to do with cursor (yet) */ /* Pull buffer of source layer/buffer */
guacenc_log(GUAC_LOG_DEBUG, "Ignoring cursor: hotspot (%i, %i) " guacenc_buffer* src = guacenc_display_get_related_buffer(display, sindex);
"src_layer=%i (%i, %i) %ix%i", hotspot_x, hotspot_y, if (src == NULL)
src_index, src_x, src_y, src_w, src_h); return 1;
/* Update cursor hotspot */
guacenc_cursor* cursor = display->cursor;
cursor->hotspot_x = hotspot_x;
cursor->hotspot_y = hotspot_y;
/* Resize cursor to exactly fit */
guacenc_buffer_resize(cursor->buffer, width, height);
/* Copy rectangle from source to cursor */
guacenc_buffer* dst = cursor->buffer;
if (src->surface != NULL && dst->cairo != NULL) {
cairo_set_operator(dst->cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface(dst->cairo, src->surface, sx, sy);
cairo_paint(dst->cairo);
}
return 0; return 0;

View File

@ -17,42 +17,40 @@
* under the License. * under the License.
*/ */
#ifndef __GUAC_RDP_RDP_RAIL_H
#define __GUAC_RDP_RDP_RAIL_H
#include "config.h" #include "config.h"
#include "cursor.h"
#include "display.h"
#include "log.h"
#include "parse.h"
#include <guacamole/client.h> #include <guacamole/client.h>
#ifdef ENABLE_WINPR #include <stdlib.h>
#include <winpr/stream.h>
#else
#include "compat/winpr-stream.h"
#endif
/** int guacenc_handle_mouse(guacenc_display* display, int argc, char** argv) {
* Dispatches a given RAIL event to the appropriate handler.
*
* @param client
* The guac_client associated with the current RDP session.
*
* @param event
* The RAIL event to process.
*/
void guac_rdp_process_rail_event(guac_client* client, wMessage* event);
/** /* Verify argument count */
* Handles the event sent when updating system parameters. The event given if (argc < 2) {
* MUST be a SYSPARAM event. guacenc_log(GUAC_LOG_WARNING, "\"mouse\" instruction incomplete");
* return 1;
* @param client }
* The guac_client associated with the current RDP session.
*
* @param event
* The system parameter event to process.
*/
void guac_rdp_process_rail_get_sysparam(guac_client* client, wMessage* event);
#endif /* Parse arguments */
int x = atoi(argv[0]);
int y = atoi(argv[1]);
/* Update cursor properties */
guacenc_cursor* cursor = display->cursor;
cursor->x = x;
cursor->y = y;
/* If no timestamp provided, nothing further to do */
if (argc < 4)
return 0;
/* Leverage timestamp to render frame */
guac_timestamp timestamp = guacenc_parse_timestamp(argv[3]);
return guacenc_display_sync(display, timestamp);
}

View File

@ -38,13 +38,13 @@ int guacenc_handle_size(guacenc_display* display, int argc, char** argv) {
int width = atoi(argv[1]); int width = atoi(argv[1]);
int height = atoi(argv[2]); int height = atoi(argv[2]);
/* Retrieve requested layer */ /* Retrieve requested layer/buffer */
guacenc_layer* layer = guacenc_display_get_layer(display, index); guacenc_buffer* buffer = guacenc_display_get_related_buffer(display, index);
if (layer == NULL) if (buffer == NULL)
return 1; return 1;
/* Resize layer */ /* Resize layer/buffer */
return guacenc_buffer_resize(layer->buffer, width, height); return guacenc_buffer_resize(buffer, width, height);
} }

View File

@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "display.h" #include "display.h"
#include "log.h" #include "log.h"
#include "parse.h"
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/timestamp.h> #include <guacamole/timestamp.h>
@ -27,40 +28,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
/**
* Parses a guac_timestamp from the given string. The string is assumed to
* consist solely of decimal digits with an optional leading minus sign. If the
* given string contains other characters, the behavior of this function is
* undefined.
*
* @param str
* The string to parse, which must contain only decimal digits and an
* optional leading minus sign.
*
* @return
* A guac_timestamp having the same value as the provided string.
*/
static guac_timestamp guacenc_parse_timestamp(const char* str) {
int sign = 1;
int64_t num = 0;
for (; *str != '\0'; str++) {
/* Flip sign for each '-' encountered */
if (*str == '-')
sign = -sign;
/* If not '-', assume the character is a digit */
else
num = num * 10 + (*str - '0');
}
return (guac_timestamp) (num * sign);
}
int guacenc_handle_sync(guacenc_display* display, int argc, char** argv) { int guacenc_handle_sync(guacenc_display* display, int argc, char** argv) {
/* Verify argument count */ /* Verify argument count */

View File

@ -30,6 +30,7 @@ guacenc_instruction_handler_mapping guacenc_instruction_handler_map[] = {
{"blob", guacenc_handle_blob}, {"blob", guacenc_handle_blob},
{"img", guacenc_handle_img}, {"img", guacenc_handle_img},
{"end", guacenc_handle_end}, {"end", guacenc_handle_end},
{"mouse", guacenc_handle_mouse},
{"sync", guacenc_handle_sync}, {"sync", guacenc_handle_sync},
{"cursor", guacenc_handle_cursor}, {"cursor", guacenc_handle_cursor},
{"copy", guacenc_handle_copy}, {"copy", guacenc_handle_copy},

View File

@ -114,6 +114,11 @@ guacenc_instruction_handler guacenc_handle_img;
*/ */
guacenc_instruction_handler guacenc_handle_end; guacenc_instruction_handler guacenc_handle_end;
/**
* Handler for the Guacamole "mouse" instruction.
*/
guacenc_instruction_handler guacenc_handle_mouse;
/** /**
* Handler for the Guacamole "sync" instruction. * Handler for the Guacamole "sync" instruction.
*/ */

View File

@ -16,7 +16,7 @@
.\" specific language governing permissions and limitations .\" specific language governing permissions and limitations
.\" under the License. .\" under the License.
.\" .\"
.TH guacenc 1 "1 Jun 2017" "version 0.9.13-incubating" "Guacamole" .TH guacenc 1 "26 Jan 2018" "version @PACKAGE_VERSION@" "Apache Guacamole"
. .
.SH NAME .SH NAME
guacenc \- Guacamole video encoder guacenc \- Guacamole video encoder
@ -38,7 +38,7 @@ is essentially an implementation of a Guacamole client which accepts
its input from files instead of a network connection, and renders directly to its input from files instead of a network connection, and renders directly to
video instead of to the user's screen. video instead of to the user's screen.
.P .P
Each \fIFILE\fR specified will be encoded as a raw MPEG-4 video stream to a new Each \fIFILE\fR specified will be encoded as MPEG-4 video to a new
file named \fIFILE\fR.m4v, encoded according to the other options specified. By file named \fIFILE\fR.m4v, encoded according to the other options specified. By
default, the output video will be \fI640\fRx\fI480\fR pixels, and will be saved default, the output video will be \fI640\fRx\fI480\fR pixels, and will be saved
with a bitrate of \fI2000000\fR bits per second (2 Mbps). These defaults can be with a bitrate of \fI2000000\fR bits per second (2 Mbps). These defaults can be
@ -76,5 +76,5 @@ Overrides the default behavior of
such that input files will be encoded even if they appear to be recordings of such that input files will be encoded even if they appear to be recordings of
in-progress Guacamole sessions. in-progress Guacamole sessions.
. .
.SH AUTHOR .SH SEE ALSO
Written by Michael Jumper <mike.jumper@guac-dev.org> .BR guaclog (1)

View File

@ -19,6 +19,8 @@
#include "config.h" #include "config.h"
#include <guacamole/timestamp.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
@ -67,3 +69,24 @@ int guacenc_parse_dimensions(char* arg, int* width, int* height) {
} }
guac_timestamp guacenc_parse_timestamp(const char* str) {
int sign = 1;
int64_t num = 0;
for (; *str != '\0'; str++) {
/* Flip sign for each '-' encountered */
if (*str == '-')
sign = -sign;
/* If not '-', assume the character is a digit */
else
num = num * 10 + (*str - '0');
}
return (guac_timestamp) (num * sign);
}

View File

@ -22,6 +22,8 @@
#include "config.h" #include "config.h"
#include <guacamole/timestamp.h>
/** /**
* Parses a string into a single integer. Only positive integers are accepted. * Parses a string into a single integer. Only positive integers are accepted.
* The input string may be modified during parsing. A value will be stored in * The input string may be modified during parsing. A value will be stored in
@ -63,6 +65,21 @@ int guacenc_parse_int(char* arg, int* i);
*/ */
int guacenc_parse_dimensions(char* arg, int* width, int* height); int guacenc_parse_dimensions(char* arg, int* width, int* height);
/**
* Parses a guac_timestamp from the given string. The string is assumed to
* consist solely of decimal digits with an optional leading minus sign. If the
* given string contains other characters, the behavior of this function is
* undefined.
*
* @param str
* The string to parse, which must contain only decimal digits and an
* optional leading minus sign.
*
* @return
* A guac_timestamp having the same value as the provided string.
*/
guac_timestamp guacenc_parse_timestamp(const char* str);
#endif #endif

View File

@ -25,6 +25,9 @@
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#ifndef AVFORMAT_AVFORMAT_H
#include <libavformat/avformat.h>
#endif
#include <libavutil/common.h> #include <libavutil/common.h>
#include <libavutil/imgutils.h> #include <libavutil/imgutils.h>
#include <libswscale/swscale.h> #include <libswscale/swscale.h>
@ -34,42 +37,68 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name, guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
int width, int height, int bitrate) { int width, int height, int bitrate) {
const AVOutputFormat *container_format;
AVFormatContext *container_format_context;
AVStream *video_stream;
int ret;
int failed_header = 0;
/* allocate the output media context */
avformat_alloc_output_context2(&container_format_context, NULL, NULL, path);
if (container_format_context == NULL) {
guacenc_log(GUAC_LOG_ERROR, "Failed to determine container from output file name");
goto fail_codec;
}
container_format = container_format_context->oformat;
/* Pull codec based on name */ /* Pull codec based on name */
AVCodec* codec = avcodec_find_encoder_by_name(codec_name); const AVCodec* codec = avcodec_find_encoder_by_name(codec_name);
if (codec == NULL) { if (codec == NULL) {
guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".", guacenc_log(GUAC_LOG_ERROR, "Failed to locate codec \"%s\".",
codec_name); codec_name);
goto fail_codec; goto fail_codec;
} }
/* create stream */
video_stream = NULL;
video_stream = avformat_new_stream(container_format_context, codec);
if (video_stream == NULL) {
guacenc_log(GUAC_LOG_ERROR, "Could not allocate encoder stream. Cannot continue.");
goto fail_format_context;
}
video_stream->id = container_format_context->nb_streams - 1;
/* Retrieve encoding context */ /* Retrieve encoding context */
AVCodecContext* context = avcodec_alloc_context3(codec); AVCodecContext* avcodec_context =
if (context == NULL) { guacenc_build_avcodeccontext(video_stream, codec, bitrate, width,
height, /*gop size*/ 10, /*qmax*/ 31, /*qmin*/ 2,
/*pix fmt*/ AV_PIX_FMT_YUV420P,
/*time base*/ (AVRational) { 1, GUACENC_VIDEO_FRAMERATE });
if (avcodec_context == NULL) {
guacenc_log(GUAC_LOG_ERROR, "Failed to allocate context for " guacenc_log(GUAC_LOG_ERROR, "Failed to allocate context for "
"codec \"%s\".", codec_name); "codec \"%s\".", codec_name);
goto fail_context; goto fail_context;
} }
/* Init context with encoding parameters */ /* If format needs global headers, write them */
context->bit_rate = bitrate; if (container_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
context->width = width; avcodec_context->flags |= GUACENC_FLAG_GLOBAL_HEADER;
context->height = height; }
context->time_base = (AVRational) { 1, GUACENC_VIDEO_FRAMERATE };
context->gop_size = 10;
context->max_b_frames = 1;
context->pix_fmt = AV_PIX_FMT_YUV420P;
/* Open codec for use */ /* Open codec for use */
if (avcodec_open2(context, codec, NULL) < 0) { if (guacenc_open_avcodec(avcodec_context, codec, NULL, video_stream) < 0) {
guacenc_log(GUAC_LOG_ERROR, "Failed to open codec \"%s\".", codec_name); guacenc_log(GUAC_LOG_ERROR, "Failed to open codec \"%s\".", codec_name);
goto fail_codec_open; goto fail_codec_open;
} }
@ -81,9 +110,9 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
} }
/* Copy necessary data for frame from context */ /* Copy necessary data for frame from context */
frame->format = context->pix_fmt; frame->format = avcodec_context->pix_fmt;
frame->width = context->width; frame->width = avcodec_context->width;
frame->height = context->height; frame->height = avcodec_context->height;
/* Allocate actual backing data for frame */ /* Allocate actual backing data for frame */
if (av_image_alloc(frame->data, frame->linesize, frame->width, if (av_image_alloc(frame->data, frame->linesize, frame->width,
@ -91,31 +120,32 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
goto fail_frame_data; goto fail_frame_data;
} }
/* Open output file */ /* Open output file, if the container needs it */
int fd = open(path, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); if (!(container_format->flags & AVFMT_NOFILE)) {
if (fd == -1) { ret = avio_open(&container_format_context->pb, path, AVIO_FLAG_WRITE);
guacenc_log(GUAC_LOG_ERROR, "Failed to open output file \"%s\": %s", if (ret < 0) {
path, strerror(errno)); guacenc_log(GUAC_LOG_ERROR, "Error occurred while opening output file.");
goto fail_output_fd; goto fail_output_avio;
}
} }
/* Create stream for output file */ /* write the stream header, if needed */
FILE* output = fdopen(fd, "wb"); ret = avformat_write_header(container_format_context, NULL);
if (output == NULL) { if (ret < 0) {
guacenc_log(GUAC_LOG_ERROR, "Failed to allocate stream for output " guacenc_log(GUAC_LOG_ERROR, "Error occurred while writing output file header.");
"file \"%s\": %s", path, strerror(errno)); failed_header = true;
goto fail_output_file; goto fail_output_file;
} }
/* Allocate video structure */ /* Allocate video structure */
guacenc_video* video = malloc(sizeof(guacenc_video)); guacenc_video* video = malloc(sizeof(guacenc_video));
if (video == NULL) { if (video == NULL)
goto fail_video; goto fail_alloc_video;
}
/* Init properties of video */ /* Init properties of video */
video->output = output; video->output_stream = video_stream;
video->context = context; video->context = avcodec_context;
video->container_format_context = container_format_context;
video->next_frame = frame; video->next_frame = frame;
video->width = width; video->width = width;
video->height = height; video->height = height;
@ -128,13 +158,16 @@ guacenc_video* guacenc_video_alloc(const char* path, const char* codec_name,
return video; return video;
/* Free all allocated data in case of failure */ /* Free all allocated data in case of failure */
fail_video: fail_alloc_video:
fclose(output);
fail_output_file: fail_output_file:
close(fd); avio_close(container_format_context->pb);
fail_output_fd: /* Delete the file that was created if it was actually created */
if (unlink(path) == -1 && errno != ENOENT)
guacenc_log(GUAC_LOG_WARNING, "Failed output file \"%s\" could not "
"be automatically deleted: %s", path, strerror(errno));
fail_output_avio:
av_freep(&frame->data[0]); av_freep(&frame->data[0]);
fail_frame_data: fail_frame_data:
@ -142,7 +175,13 @@ fail_frame_data:
fail_frame: fail_frame:
fail_codec_open: fail_codec_open:
avcodec_free_context(&context); avcodec_free_context(&avcodec_context);
fail_format_context:
/* failing to write the container implicitly frees the context */
if (!failed_header) {
avformat_free_context(container_format_context);
}
fail_context: fail_context:
fail_codec: fail_codec:
@ -228,7 +267,11 @@ int guacenc_video_advance_timeline(guacenc_video* video,
/* Flush frames to bring timeline in sync, duplicating if necessary */ /* Flush frames to bring timeline in sync, duplicating if necessary */
do { do {
guacenc_video_flush_frame(video); if (guacenc_video_flush_frame(video)) {
guacenc_log(GUAC_LOG_ERROR, "Unable to flush frame to video "
"stream.");
return 1;
}
} while (--elapsed != 0); } while (--elapsed != 0);
} }
@ -431,26 +474,34 @@ int guacenc_video_free(guacenc_video* video) {
/* Write final frame */ /* Write final frame */
guacenc_video_flush_frame(video); guacenc_video_flush_frame(video);
/* Init video packet for final flush of encoded data */
AVPacket packet;
av_init_packet(&packet);
/* Flush any unwritten frames */ /* Flush any unwritten frames */
int retval; int retval;
do { do {
retval = guacenc_video_write_frame(video, NULL); retval = guacenc_video_write_frame(video, NULL);
} while (retval > 0); } while (retval > 0);
/* write trailer, if needed */
if (video->container_format_context != NULL &&
video->output_stream != NULL) {
guacenc_log(GUAC_LOG_DEBUG, "Writing trailer: %s",
av_write_trailer(video->container_format_context) == 0 ?
"success" : "failure");
}
/* File is now completely written */ /* File is now completely written */
fclose(video->output); if (video->container_format_context != NULL) {
avio_close(video->container_format_context->pb);
}
/* Free frame encoding data */ /* Free frame encoding data */
av_freep(&video->next_frame->data[0]); av_freep(&video->next_frame->data[0]);
av_frame_free(&video->next_frame); av_frame_free(&video->next_frame);
/* Clean up encoding context */ /* Clean up encoding context */
avcodec_close(video->context); if (video->context != NULL) {
avcodec_free_context(&(video->context)); avcodec_close(video->context);
avcodec_free_context(&(video->context));
}
free(video); free(video);
return 0; return 0;

View File

@ -26,6 +26,14 @@
#include <guacamole/timestamp.h> #include <guacamole/timestamp.h>
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#ifndef AVCODEC_AVCODEC_H
#include <libavcodec/avcodec.h>
#endif
#ifndef AVFORMAT_AVFORMAT_H
#include <libavformat/avformat.h>
#endif
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -42,9 +50,11 @@
typedef struct guacenc_video { typedef struct guacenc_video {
/** /**
* Output file stream. * AVStream for video output.
* Frames sent to this stream are written into
* the output file in the specified container format.
*/ */
FILE* output; AVStream* output_stream;
/** /**
* The open encoding context from libavcodec, created for the codec * The open encoding context from libavcodec, created for the codec
@ -52,6 +62,12 @@ typedef struct guacenc_video {
*/ */
AVCodecContext* context; AVCodecContext* context;
/**
* The open format context from libavformat, created for the file
* container specified when this guacenc_video was created.
*/
AVFormatContext* container_format_context;
/** /**
* The width of the video, in pixels. * The width of the video, in pixels.
*/ */

8
src/guaclog/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Compiled guaclog
guaclog
guaclog.exe
# Documentation (built from .in files)
man/guaclog.1

59
src/guaclog/Makefile.am Normal file
View File

@ -0,0 +1,59 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
#
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = guaclog
man_MANS = \
man/guaclog.1
noinst_HEADERS = \
guaclog.h \
instructions.h \
interpret.h \
keydef.h \
log.h \
state.h
guaclog_SOURCES = \
guaclog.c \
instructions.c \
instruction-key.c \
interpret.c \
keydef.c \
log.c \
state.c
guaclog_CFLAGS = \
-Werror -Wall \
@LIBGUAC_INCLUDE@
guaclog_LDADD = \
@LIBGUAC_LTLIB@
EXTRA_DIST = \
man/guaclog.1.in

119
src/guaclog/guaclog.c Normal file
View File

@ -0,0 +1,119 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#include "config.h"
#include "guaclog.h"
#include "interpret.h"
#include "log.h"
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
int i;
/* Load defaults */
bool force = false;
/* Parse arguments */
int opt;
while ((opt = getopt(argc, argv, "s:r:f")) != -1) {
/* -f: Force */
if (opt == 'f')
force = true;
/* Invalid option */
else {
goto invalid_options;
}
}
/* Log start */
guaclog_log(GUAC_LOG_INFO, "Guacamole input log interpreter (guaclog) "
"version " VERSION);
/* Track number of overall failures */
int total_files = argc - optind;
int failures = 0;
/* Abort if no files given */
if (total_files <= 0) {
guaclog_log(GUAC_LOG_INFO, "No input files specified. Nothing to do.");
return 0;
}
guaclog_log(GUAC_LOG_INFO, "%i input file(s) provided.", total_files);
/* Interpret all input files */
for (i = optind; i < argc; i++) {
/* Get current filename */
const char* path = argv[i];
/* Generate output filename */
char out_path[4096];
int len = snprintf(out_path, sizeof(out_path), "%s.txt", path);
/* Do not write if filename exceeds maximum length */
if (len >= sizeof(out_path)) {
guaclog_log(GUAC_LOG_ERROR, "Cannot write output file for \"%s\": "
"Name too long", path);
continue;
}
/* Attempt interpreting, log granular success/failure at debug level */
if (guaclog_interpret(path, out_path, force)) {
failures++;
guaclog_log(GUAC_LOG_DEBUG,
"%s was NOT successfully interpreted.", path);
}
else
guaclog_log(GUAC_LOG_DEBUG, "%s was successfully "
"interpreted.", path);
}
/* Warn if at least one file failed */
if (failures != 0)
guaclog_log(GUAC_LOG_WARNING, "Interpreting failed for %i of %i "
"file(s).", failures, total_files);
/* Notify of success */
else
guaclog_log(GUAC_LOG_INFO, "All files interpreted successfully.");
/* Interpreting complete */
return 0;
/* Display usage and exit with error if options are invalid */
invalid_options:
fprintf(stderr, "USAGE: %s"
" [-f]"
" [FILE]...\n", argv[0]);
return 1;
}

Some files were not shown because too many files have changed in this diff Show More