From 3feb20c0f5ae8476957d3a45f51addd7ea3de698 Mon Sep 17 00:00:00 2001 From: eugen-keeper Date: Tue, 18 Aug 2026 13:59:31 -0400 Subject: [PATCH] GUACAMOLE-2319: Fix SFTP symlink dirs shown as files when root is not system root. --- src/common-ssh/common-ssh/sftp.h | 10 +++++++++- src/common-ssh/sftp.c | 11 +++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/common-ssh/common-ssh/sftp.h b/src/common-ssh/common-ssh/sftp.h index a3784ea249..73bc0d80b3 100644 --- a/src/common-ssh/common-ssh/sftp.h +++ b/src/common-ssh/common-ssh/sftp.h @@ -99,10 +99,18 @@ typedef struct guac_common_ssh_sftp_ls_state { LIBSSH2_SFTP_HANDLE* directory; /** - * The absolute path of the directory being listed. + * The absolute path of the directory being listed, as exposed to the + * client via the Guacamole protocol stream name. */ char directory_name[GUAC_COMMON_SSH_SFTP_MAX_PATH]; + /** + * The real, server-side filesystem path of the directory being listed, + * including any configured SFTP root prefix. Used to resolve symlinks + * during listing when the SFTP root is not "/". + */ + char directory_real_path[GUAC_COMMON_SSH_SFTP_MAX_PATH]; + /** * The current state of the JSON directory object being written. */ diff --git a/src/common-ssh/sftp.c b/src/common-ssh/sftp.c index 4a6f7716ab..38b8e7e22d 100644 --- a/src/common-ssh/sftp.c +++ b/src/common-ssh/sftp.c @@ -649,8 +649,12 @@ static int guac_common_ssh_sftp_ls_ack_handler(guac_user* user, } /* Stat explicitly if symbolic link (might point to directory) */ - if (LIBSSH2_SFTP_S_ISLNK(attributes.permissions)) - libssh2_sftp_stat(sftp, absolute_path, &attributes); + if (LIBSSH2_SFTP_S_ISLNK(attributes.permissions)) { + char real_path[GUAC_COMMON_SSH_SFTP_MAX_PATH]; + if (guac_ssh_append_filename(real_path, + list_state->directory_real_path, filename)) + libssh2_sftp_stat(sftp, real_path, &attributes); + } /* Determine mimetype */ const char* mimetype; @@ -791,6 +795,9 @@ static int guac_common_ssh_sftp_get_handler(guac_user* user, return 0; } + guac_strlcpy(list_state->directory_real_path, fullpath, + sizeof(list_state->directory_real_path)); + /* Allocate stream for body */ guac_stream* stream = guac_user_alloc_stream(user); stream->ack_handler = guac_common_ssh_sftp_ls_ack_handler;