GUACAMOLE-637: Merge migration to new libguac string functions.
This commit is contained in:
commit
dd4c3968d1
4
.gitignore
vendored
4
.gitignore
vendored
@ -10,6 +10,10 @@
|
||||
*.gcov
|
||||
*.gcno
|
||||
|
||||
# Test suite output
|
||||
*.log
|
||||
*.trs
|
||||
|
||||
# Backup files
|
||||
*~
|
||||
|
||||
|
@ -60,7 +60,7 @@ modified to contain a sections like the following:
|
||||
CLEANFILES = _generated_runner.c
|
||||
|
||||
_generated_runner.c: $(test_myproj_SOURCES)
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $^ > $@
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $(test_myproj_SOURCES) > $@
|
||||
|
||||
nodist_test_libguac_SOURCES = \
|
||||
_generated_runner.c
|
||||
|
17
configure.ac
17
configure.ac
@ -42,6 +42,7 @@ AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/socket.h time.h sys/time.h syslo
|
||||
|
||||
# Source characteristics
|
||||
AC_DEFINE([_XOPEN_SOURCE], [700], [Uses X/Open and POSIX APIs])
|
||||
AC_DEFINE([__BSD_VISIBLE], [1], [Uses BSD-specific APIs (if available)])
|
||||
|
||||
# Check for whether math library is required
|
||||
AC_CHECK_LIB([m], [cos],
|
||||
@ -120,6 +121,16 @@ AC_CHECK_DECL([poll],
|
||||
[Whether poll() is defined])],,
|
||||
[#include <poll.h>])
|
||||
|
||||
AC_CHECK_DECL([strlcpy],
|
||||
[AC_DEFINE([HAVE_STRLCPY],,
|
||||
[Whether strlcpy() is defined])],,
|
||||
[#include <string.h>])
|
||||
|
||||
AC_CHECK_DECL([strlcat],
|
||||
[AC_DEFINE([HAVE_STRLCAT],,
|
||||
[Whether strlcat() is defined])],,
|
||||
[#include <string.h>])
|
||||
|
||||
# Typedefs
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
@ -140,6 +151,10 @@ AC_SUBST([PULSE_INCLUDE], '-I$(top_srcdir)/src/pulse')
|
||||
AC_SUBST([COMMON_SSH_LTLIB], '$(top_builddir)/src/common-ssh/libguac_common_ssh.la')
|
||||
AC_SUBST([COMMON_SSH_INCLUDE], '-I$(top_srcdir)/src/common-ssh')
|
||||
|
||||
# RDP support
|
||||
AC_SUBST([LIBGUAC_CLIENT_RDP_LTLIB], '$(top_builddir)/src/protocols/rdp/libguac-client-rdp.la')
|
||||
AC_SUBST([LIBGUAC_CLIENT_RDP_INCLUDE], '-I$(top_srcdir)/src/protocols/rdp')
|
||||
|
||||
# Terminal emulator
|
||||
AC_SUBST([TERMINAL_LTLIB], '$(top_builddir)/src/terminal/libguac_terminal.la')
|
||||
AC_SUBST([TERMINAL_INCLUDE], '-I$(top_srcdir)/src/terminal $(PANGO_CFLAGS) $(PANGOCAIRO_CFLAGS) $(COMMON_INCLUDE)')
|
||||
@ -1306,6 +1321,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/common/Makefile
|
||||
src/common/tests/Makefile
|
||||
src/common-ssh/Makefile
|
||||
src/common-ssh/tests/Makefile
|
||||
src/terminal/Makefile
|
||||
src/libguac/Makefile
|
||||
src/libguac/tests/Makefile
|
||||
@ -1319,6 +1335,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/pulse/Makefile
|
||||
src/protocols/kubernetes/Makefile
|
||||
src/protocols/rdp/Makefile
|
||||
src/protocols/rdp/tests/Makefile
|
||||
src/protocols/ssh/Makefile
|
||||
src/protocols/telnet/Makefile
|
||||
src/protocols/vnc/Makefile])
|
||||
|
5
src/common-ssh/.gitignore
vendored
Normal file
5
src/common-ssh/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
# Auto-generated test runner and binary
|
||||
_generated_runner.c
|
||||
test_common_ssh
|
||||
|
@ -27,6 +27,7 @@ AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
noinst_LTLIBRARIES = libguac_common_ssh.la
|
||||
SUBDIRS = . tests
|
||||
|
||||
libguac_common_ssh_la_SOURCES = \
|
||||
buffer.c \
|
||||
|
@ -255,5 +255,30 @@ int guac_common_ssh_sftp_handle_file_stream(
|
||||
void guac_common_ssh_sftp_set_upload_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
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <guacamole/object.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <libssh2.h>
|
||||
|
||||
@ -32,107 +33,70 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* 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,
|
||||
int guac_common_ssh_sftp_normalize_path(char* fullpath,
|
||||
const char* path) {
|
||||
|
||||
int i;
|
||||
|
||||
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** 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 (path[0] != '\\' && path[0] != '/')
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
/* Skip past leading slash */
|
||||
path++;
|
||||
/* Create scratch copy of path excluding leading slash (we will be
|
||||
* 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 */
|
||||
strncpy(path_component_data, path, sizeof(path_component_data) - 1);
|
||||
/* Fail if provided path is too long */
|
||||
if (length >= sizeof(path_scratch))
|
||||
return 0;
|
||||
|
||||
/* Find path components within path */
|
||||
for (i = 0; i < sizeof(path_component_data) - 1; i++) {
|
||||
/* Locate all path components within path */
|
||||
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 */
|
||||
char c = path_component_data[i];
|
||||
char c = path_scratch[i];
|
||||
if (c == '/' || c == '\\' || c == '\0') {
|
||||
|
||||
/* Terminate current component */
|
||||
path_component_data[i] = '\0';
|
||||
path_scratch[i] = '\0';
|
||||
|
||||
/* 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)
|
||||
path_depth--;
|
||||
}
|
||||
|
||||
/* Otherwise, if component not current directory, add to list */
|
||||
else if (strcmp(current_path_component_data, ".") != 0
|
||||
&& strcmp(current_path_component_data, "") != 0)
|
||||
path_components[path_depth++] = current_path_component_data;
|
||||
else if (strcmp(current_path_component, ".") != 0
|
||||
&& strcmp(current_path_component, "") != 0) {
|
||||
|
||||
/* If end of string, stop */
|
||||
if (c == '\0')
|
||||
break;
|
||||
/* Fail normalization if path is too deep */
|
||||
if (path_depth >= GUAC_COMMON_SSH_SFTP_MAX_DEPTH)
|
||||
return 0;
|
||||
|
||||
path_components[path_depth++] = current_path_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 for each character */
|
||||
|
||||
/* If no components, the path is simply root */
|
||||
if (path_depth == 0) {
|
||||
strcpy(fullpath, "/");
|
||||
return 1;
|
||||
}
|
||||
/* Add leading slash for resulting absolute path */
|
||||
fullpath[0] = '/';
|
||||
|
||||
/* Ensure last component is null-terminated */
|
||||
path_component_data[i] = 0;
|
||||
/* Append normalized components to path, separated by slashes */
|
||||
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;
|
||||
|
||||
}
|
||||
@ -229,7 +193,7 @@ static guac_protocol_status guac_sftp_get_status(
|
||||
static int guac_ssh_append_filename(char* fullpath, const char* path,
|
||||
const char* filename) {
|
||||
|
||||
int i;
|
||||
int length;
|
||||
|
||||
/* Disallow "." as a filename */
|
||||
if (strcmp(filename, ".") == 0)
|
||||
@ -239,49 +203,29 @@ static int guac_ssh_append_filename(char* fullpath, const char* path,
|
||||
if (strcmp(filename, "..") == 0)
|
||||
return 0;
|
||||
|
||||
/* Copy path, append trailing slash */
|
||||
for (i=0; i<GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) {
|
||||
|
||||
/*
|
||||
* 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)
|
||||
/* Filenames may not contain slashes */
|
||||
if (strchr(filename, '/') != NULL)
|
||||
return 0;
|
||||
|
||||
/* Terminate path string */
|
||||
fullpath[i] = '\0';
|
||||
/* Copy base path */
|
||||
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 */
|
||||
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,
|
||||
const char* path_b) {
|
||||
|
||||
int i;
|
||||
int length;
|
||||
|
||||
/* Copy path, appending a trailing slash */
|
||||
for (i = 0; i < GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) {
|
||||
/* Copy first half of path */
|
||||
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];
|
||||
if (c == '\0') {
|
||||
if (i > 0 && path_a[i-1] != '/')
|
||||
fullpath[i++] = '/';
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy character if not end of string */
|
||||
fullpath[i] = c;
|
||||
|
||||
}
|
||||
/* Ensure path ends with trailing slash */
|
||||
if (length == 0 || fullpath[length - 1] != '/')
|
||||
length += guac_strlcpy(fullpath + length, "/",
|
||||
GUAC_COMMON_SSH_SFTP_MAX_PATH - length);
|
||||
|
||||
/* Skip past leading slashes in second path */
|
||||
while (*path_b == '/')
|
||||
path_b++;
|
||||
|
||||
/* Append path */
|
||||
for (; i < GUAC_COMMON_SSH_SFTP_MAX_PATH; i++) {
|
||||
|
||||
char c = *(path_b++);
|
||||
if (c == '\0')
|
||||
break;
|
||||
|
||||
/* Append each character within path */
|
||||
fullpath[i] = c;
|
||||
|
||||
}
|
||||
/* Append final half of path */
|
||||
length += guac_strlcpy(fullpath + length, path_b,
|
||||
GUAC_COMMON_SSH_SFTP_MAX_PATH - length);
|
||||
|
||||
/* Verify path length is within maximum */
|
||||
if (i == GUAC_COMMON_SSH_SFTP_MAX_PATH)
|
||||
if (length >= GUAC_COMMON_SSH_SFTP_MAX_PATH)
|
||||
return 0;
|
||||
|
||||
/* Terminate path string */
|
||||
fullpath[i] = '\0';
|
||||
|
||||
/* Append was successful */
|
||||
return 1;
|
||||
|
||||
@ -830,8 +758,17 @@ static int guac_common_ssh_sftp_get_handler(guac_user* user,
|
||||
|
||||
list_state->directory = dir;
|
||||
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 */
|
||||
guac_stream* stream = guac_user_alloc_stream(user);
|
||||
|
66
src/common-ssh/tests/Makefile.am
Normal file
66
src/common-ssh/tests/Makefile.am
Normal file
@ -0,0 +1,66 @@
|
||||
#
|
||||
# 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@
|
||||
|
||||
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
|
||||
|
263
src/common-ssh/tests/sftp/normalize_path.c
Normal file
263
src/common-ssh/tests/sftp/normalize_path.c
Normal 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);
|
||||
|
||||
}
|
||||
|
4
src/common/.gitignore
vendored
4
src/common/.gitignore
vendored
@ -3,7 +3,3 @@
|
||||
_generated_runner.c
|
||||
test_common
|
||||
|
||||
# Test suite output
|
||||
*.log
|
||||
*.trs
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <guacamole/user.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
@ -131,8 +132,7 @@ void guac_common_clipboard_reset(guac_common_clipboard* clipboard,
|
||||
clipboard->length = 0;
|
||||
|
||||
/* Assign given mimetype */
|
||||
strncpy(clipboard->mimetype, mimetype, sizeof(clipboard->mimetype) - 1);
|
||||
clipboard->mimetype[sizeof(clipboard->mimetype) - 1] = '\0';
|
||||
guac_strlcpy(clipboard->mimetype, mimetype, sizeof(clipboard->mimetype));
|
||||
|
||||
pthread_mutex_unlock(&(clipboard->lock));
|
||||
|
||||
|
@ -60,7 +60,7 @@ GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
|
||||
CLEANFILES = _generated_runner.c
|
||||
|
||||
_generated_runner.c: $(test_common_SOURCES)
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $^ > $@
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $(test_common_SOURCES) > $@
|
||||
|
||||
nodist_test_common_SOURCES = \
|
||||
_generated_runner.c
|
||||
|
35
src/guacd/.gitignore
vendored
35
src/guacd/.gitignore
vendored
@ -13,38 +13,3 @@ guacd.exe
|
||||
man/guacd.8
|
||||
man/guacd.conf.5
|
||||
|
||||
# Object code
|
||||
*.o
|
||||
*.so
|
||||
*.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
|
||||
|
||||
|
||||
|
4
src/libguac/.gitignore
vendored
4
src/libguac/.gitignore
vendored
@ -3,7 +3,3 @@
|
||||
_generated_runner.c
|
||||
test_libguac
|
||||
|
||||
# Test suite output
|
||||
*.log
|
||||
*.trs
|
||||
|
||||
|
@ -61,6 +61,7 @@ libguacinc_HEADERS = \
|
||||
guacamole/socket-types.h \
|
||||
guacamole/stream.h \
|
||||
guacamole/stream-types.h \
|
||||
guacamole/string.h \
|
||||
guacamole/timestamp.h \
|
||||
guacamole/timestamp-types.h \
|
||||
guacamole/unicode.h \
|
||||
@ -96,6 +97,7 @@ libguac_la_SOURCES = \
|
||||
socket-fd.c \
|
||||
socket-nest.c \
|
||||
socket-tee.c \
|
||||
string.c \
|
||||
timestamp.c \
|
||||
unicode.c \
|
||||
user.c \
|
||||
@ -122,7 +124,7 @@ libguacinc_HEADERS += guacamole/socket-wsa.h
|
||||
endif
|
||||
|
||||
libguac_la_CFLAGS = \
|
||||
-Werror -Wall -pedantic -I$(srcdir)/guacamole
|
||||
-Werror -Wall -pedantic
|
||||
|
||||
libguac_la_LDFLAGS = \
|
||||
-version-info 17:0:0 \
|
||||
|
@ -19,14 +19,13 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "guacamole/audio.h"
|
||||
#include "guacamole/client.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "guacamole/user.h"
|
||||
#include "raw_encoder.h"
|
||||
|
||||
#include <guacamole/audio.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -19,20 +19,21 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "encode-jpeg.h"
|
||||
#include "encode-png.h"
|
||||
#include "encode-webp.h"
|
||||
#include "error.h"
|
||||
#include "guacamole/client.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/layer.h"
|
||||
#include "guacamole/plugin.h"
|
||||
#include "guacamole/pool.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "guacamole/string.h"
|
||||
#include "guacamole/timestamp.h"
|
||||
#include "guacamole/user.h"
|
||||
#include "id.h"
|
||||
#include "layer.h"
|
||||
#include "pool.h"
|
||||
#include "plugin.h"
|
||||
#include "protocol.h"
|
||||
#include "socket.h"
|
||||
#include "stream.h"
|
||||
#include "timestamp.h"
|
||||
#include "user.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <inttypes.h>
|
||||
@ -441,8 +442,13 @@ int guac_client_load_plugin(guac_client* client, const char* protocol) {
|
||||
} alias;
|
||||
|
||||
/* Add protocol and .so suffix to protocol_lib */
|
||||
strncat(protocol_lib, protocol, GUAC_PROTOCOL_NAME_LIMIT-1);
|
||||
strcat(protocol_lib, GUAC_PROTOCOL_LIBRARY_SUFFIX);
|
||||
guac_strlcat(protocol_lib, protocol, sizeof(protocol_lib));
|
||||
if (guac_strlcat(protocol_lib, GUAC_PROTOCOL_LIBRARY_SUFFIX,
|
||||
sizeof(protocol_lib)) >= sizeof(protocol_lib)) {
|
||||
guac_error = GUAC_STATUS_NO_MEMORY;
|
||||
guac_error_message = "Protocol name is too long";
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load client plugin */
|
||||
client_plugin_handle = dlopen(protocol_lib, RTLD_LAZY);
|
||||
|
@ -20,10 +20,10 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "encode-jpeg.h"
|
||||
#include "error.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "palette.h"
|
||||
#include "protocol.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <jpeglib.h>
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "stream.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/stream.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
|
@ -20,10 +20,10 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "encode-png.h"
|
||||
#include "error.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "palette.h"
|
||||
#include "protocol.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include <png.h>
|
||||
#include <cairo/cairo.h>
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "stream.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/stream.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
|
@ -20,10 +20,10 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "encode-webp.h"
|
||||
#include "error.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "palette.h"
|
||||
#include "protocol.h"
|
||||
#include "stream.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <webp/encode.h>
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "stream.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/stream.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "guacamole/error.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
161
src/libguac/guacamole/string.h
Normal file
161
src/libguac/guacamole/string.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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_STRING_H
|
||||
#define GUAC_STRING_H
|
||||
|
||||
/**
|
||||
* Provides convenience functions for manipulating strings.
|
||||
*
|
||||
* @file string.h
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Copies a limited number of bytes from the given source string to the given
|
||||
* destination buffer. The resulting buffer will always be null-terminated,
|
||||
* even if doing so means that the intended string is truncated, unless the
|
||||
* destination buffer has no space available at all. As this function always
|
||||
* returns the length of the string it tried to create (the length of the
|
||||
* source string), whether truncation has occurred can be detected by comparing
|
||||
* the return value against the size of the destination buffer. If the value
|
||||
* returned is greater than or equal to the size of the destination buffer, then
|
||||
* the string has been truncated.
|
||||
*
|
||||
* The source and destination buffers MAY NOT overlap.
|
||||
*
|
||||
* @param dest
|
||||
* The buffer which should receive the contents of the source string. This
|
||||
* buffer will always be null terminated unless zero bytes are available
|
||||
* within the buffer.
|
||||
*
|
||||
* @param src
|
||||
* The source string to copy into the destination buffer. This string MUST
|
||||
* be null terminated.
|
||||
*
|
||||
* @param n
|
||||
* The number of bytes available within the destination buffer. If this
|
||||
* value is zero, no bytes will be written to the destination buffer, and
|
||||
* the destination buffer may not be null terminated. In all other cases,
|
||||
* the destination buffer will always be null terminated, even if doing
|
||||
* so means that the copied data from the source string will be truncated.
|
||||
*
|
||||
* @return
|
||||
* The length of the copied string (the source string) in bytes, excluding
|
||||
* the null terminator.
|
||||
*/
|
||||
size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n);
|
||||
|
||||
/**
|
||||
* Appends the given source string after the end of the given destination
|
||||
* string, writing at most the given number of bytes. Both the source and
|
||||
* destination strings MUST be null-terminated. The resulting buffer will
|
||||
* always be null-terminated, even if doing so means that the intended string
|
||||
* is truncated, unless the destination buffer has no space available at all.
|
||||
* As this function always returns the length of the string it tried to create
|
||||
* (the length of destination and source strings added together), whether
|
||||
* truncation has occurred can be detected by comparing the return value
|
||||
* against the size of the destination buffer. If the value returned is greater
|
||||
* than or equal to the size of the destination buffer, then the string has
|
||||
* been truncated.
|
||||
*
|
||||
* The source and destination buffers MAY NOT overlap.
|
||||
*
|
||||
* @param dest
|
||||
* The buffer which should be appended with the contents of the source
|
||||
* string. This buffer MUST already be null-terminated and will always be
|
||||
* null-terminated unless zero bytes are available within the buffer.
|
||||
*
|
||||
* As a safeguard against incorrectly-written code, in the event that the
|
||||
* destination buffer is not null-terminated, this function will still stop
|
||||
* before overrunning the buffer, instead behaving as if the length of the
|
||||
* string in the buffer is exactly the size of the buffer. The destination
|
||||
* buffer will remain untouched (and unterminated) in this case.
|
||||
*
|
||||
* @param src
|
||||
* The source string to append to the the destination buffer. This string
|
||||
* MUST be null-terminated.
|
||||
*
|
||||
* @param n
|
||||
* The number of bytes available within the destination buffer. If this
|
||||
* value is not greater than zero, no bytes will be written to the
|
||||
* destination buffer, and the destination buffer may not be
|
||||
* null-terminated. In all other cases, the destination buffer will always
|
||||
* be null-terminated, even if doing so means that the copied data from the
|
||||
* source string will be truncated.
|
||||
*
|
||||
* @return
|
||||
* The length of the string this function tried to create (the lengths of
|
||||
* the source and destination strings added together) in bytes, excluding
|
||||
* the null terminator.
|
||||
*/
|
||||
size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n);
|
||||
|
||||
/**
|
||||
* Concatenates each of the given strings, separated by the given delimiter,
|
||||
* storing the result within a destination buffer. The number of bytes written
|
||||
* will be no more than the given number of bytes, and the destination buffer
|
||||
* is guaranteed to be null-terminated, even if doing so means that one or more
|
||||
* of the intended strings are truncated or omitted from the end of the result,
|
||||
* unless the destination buffer has no space available at all. As this
|
||||
* function always returns the length of the string it tried to create (the
|
||||
* length of all source strings and all delimiters added together), whether
|
||||
* truncation has occurred can be detected by comparing the return value
|
||||
* against the size of the destination buffer. If the value returned is greater
|
||||
* than or equal to the size of the destination buffer, then the string has
|
||||
* been truncated.
|
||||
*
|
||||
* The source strings, delimiter string, and destination buffer MAY NOT
|
||||
* overlap.
|
||||
*
|
||||
* @param dest
|
||||
* The buffer which should receive the result of joining the given strings.
|
||||
* This buffer will always be null terminated unless zero bytes are
|
||||
* available within the buffer.
|
||||
*
|
||||
* @param elements
|
||||
* The elements to concatenate together, separated by the given delimiter.
|
||||
* Each element MUST be null-terminated.
|
||||
*
|
||||
* @param nmemb
|
||||
* The number of elements within the elements array.
|
||||
*
|
||||
* @param delim
|
||||
* The delimiter to include between each pair of elements.
|
||||
*
|
||||
* @param n
|
||||
* The number of bytes available within the destination buffer. If this
|
||||
* value is not greater than zero, no bytes will be written to the
|
||||
* destination buffer, and the destination buffer may not be null
|
||||
* terminated. In all other cases, the destination buffer will always be
|
||||
* null terminated, even if doing so means that the result will be
|
||||
* truncated.
|
||||
*
|
||||
* @return
|
||||
* The length of the string this function tried to create (the length of
|
||||
* all source strings and all delimiters added together) in bytes,
|
||||
* excluding the null terminator.
|
||||
*/
|
||||
size_t guac_strljoin(char* restrict dest, const char* restrict const* elements,
|
||||
int nmemb, const char* restrict delim, size_t n);
|
||||
|
||||
#endif
|
||||
|
@ -19,8 +19,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "guacamole/error.h"
|
||||
#include "id.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifdef HAVE_OSSP_UUID_H
|
||||
#include <ossp/uuid.h>
|
||||
|
@ -19,10 +19,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "parser.h"
|
||||
#include "socket.h"
|
||||
#include "unicode.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/parser.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/unicode.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pool.h"
|
||||
#include "guacamole/pool.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -19,14 +19,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "layer.h"
|
||||
#include "object.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/layer.h"
|
||||
#include "guacamole/object.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "guacamole/unicode.h"
|
||||
#include "palette.h"
|
||||
#include "protocol.h"
|
||||
#include "socket.h"
|
||||
#include "stream.h"
|
||||
#include "unicode.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
|
@ -19,15 +19,13 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "audio.h"
|
||||
#include "guacamole/audio.h"
|
||||
#include "guacamole/client.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/user.h"
|
||||
#include "raw_encoder.h"
|
||||
|
||||
#include <guacamole/audio.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "audio.h"
|
||||
#include "guacamole/audio.h"
|
||||
|
||||
/**
|
||||
* The number of bytes to send in each audio blob.
|
||||
|
@ -19,10 +19,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "error.h"
|
||||
#include "socket.h"
|
||||
#include "user.h"
|
||||
#include "guacamole/client.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/user.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -19,8 +19,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "socket.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "wait-fd.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "protocol.h"
|
||||
#include "socket.h"
|
||||
#include "unicode.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/unicode.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "socket-ssl.h"
|
||||
#include "socket.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/socket-ssl.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "wait-fd.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "guacamole/socket.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
#include "socket.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/socket.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stddef.h>
|
||||
|
@ -19,10 +19,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "error.h"
|
||||
#include "protocol.h"
|
||||
#include "socket.h"
|
||||
#include "timestamp.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/timestamp.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
|
107
src/libguac/string.c
Normal file
107
src/libguac/string.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Returns the space remaining in a buffer assuming that the given number of
|
||||
* bytes have already been written. If the number of bytes exceeds the size
|
||||
* of the buffer, zero is returned.
|
||||
*
|
||||
* @param n
|
||||
* The size of the buffer in bytes.
|
||||
*
|
||||
* @param length
|
||||
* The number of bytes which have been written to the buffer so far. If
|
||||
* the routine writing the bytes will automatically truncate its writes,
|
||||
* this value may exceed the size of the buffer.
|
||||
*
|
||||
* @return
|
||||
* The number of bytes remaining in the buffer. This value will always
|
||||
* be non-negative. If the number of bytes written already exceeds the
|
||||
* size of the buffer, zero will be returned.
|
||||
*/
|
||||
#define REMAINING(n, length) (((n) < (length)) ? 0 : ((n) - (length)))
|
||||
|
||||
size_t guac_strlcpy(char* restrict dest, const char* restrict src, size_t n) {
|
||||
|
||||
#ifdef HAVE_STRLCPY
|
||||
return strlcpy(dest, src, n);
|
||||
#else
|
||||
/* Calculate actual length of desired string */
|
||||
size_t length = strlen(src);
|
||||
|
||||
/* Copy nothing if there is no space */
|
||||
if (n == 0)
|
||||
return length;
|
||||
|
||||
/* Calculate length of the string which will be copied */
|
||||
size_t copy_length = length;
|
||||
if (copy_length >= n)
|
||||
copy_length = n - 1;
|
||||
|
||||
/* Copy only as much of string as possible, manually adding a null
|
||||
* terminator */
|
||||
memcpy(dest, src, copy_length);
|
||||
dest[copy_length] = '\0';
|
||||
|
||||
/* Return the overall length of the desired string */
|
||||
return length;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
size_t guac_strlcat(char* restrict dest, const char* restrict src, size_t n) {
|
||||
|
||||
#ifdef HAVE_STRLCPY
|
||||
return strlcat(dest, src, n);
|
||||
#else
|
||||
size_t length = strnlen(dest, n);
|
||||
return length + guac_strlcpy(dest + length, src, REMAINING(n, length));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
size_t guac_strljoin(char* restrict dest, const char* restrict const* elements,
|
||||
int nmemb, const char* restrict delim, size_t n) {
|
||||
|
||||
size_t length = 0;
|
||||
const char* restrict const* current = elements;
|
||||
|
||||
/* If no elements are provided, nothing to do but ensure the destination
|
||||
* buffer is null terminated */
|
||||
if (nmemb <= 0)
|
||||
return guac_strlcpy(dest, "", n);
|
||||
|
||||
/* Initialize destination buffer with first element */
|
||||
length += guac_strlcpy(dest, *current, n);
|
||||
|
||||
/* Copy all remaining elements, separated by delimiter */
|
||||
for (current++; nmemb > 1; current++, nmemb--) {
|
||||
length += guac_strlcat(dest + length, delim, REMAINING(n, length));
|
||||
length += guac_strlcat(dest + length, *current, REMAINING(n, length));
|
||||
}
|
||||
|
||||
return length;
|
||||
|
||||
}
|
||||
|
@ -42,6 +42,9 @@ test_libguac_SOURCES = \
|
||||
protocol/base64_decode.c \
|
||||
socket/fd_send_instruction.c \
|
||||
socket/nested_send_instruction.c \
|
||||
string/strlcat.c \
|
||||
string/strlcpy.c \
|
||||
string/strljoin.c \
|
||||
unicode/charsize.c \
|
||||
unicode/read.c \
|
||||
unicode/strlen.c \
|
||||
@ -64,7 +67,7 @@ GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
|
||||
CLEANFILES = _generated_runner.c
|
||||
|
||||
_generated_runner.c: $(test_libguac_SOURCES)
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $^ > $@
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $(test_libguac_SOURCES) > $@
|
||||
|
||||
nodist_test_libguac_SOURCES = \
|
||||
_generated_runner.c
|
||||
|
153
src/libguac/tests/string/strlcat.c
Normal file
153
src/libguac/tests/string/strlcat.c
Normal 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 <CUnit/CUnit.h>
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Verify guac_strlcat() behavior when the string fits the buffer without
|
||||
* truncation. The return value of each call should be the length of the
|
||||
* resulting string. Each resulting string should contain the full result of
|
||||
* the concatenation, including null terminator.
|
||||
*/
|
||||
void test_string__strlcat() {
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
strcpy(buffer, "Apache ");
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "Guacamole", sizeof(buffer)), 16);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "Apache Guacamole");
|
||||
CU_ASSERT_EQUAL(buffer[17], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
strcpy(buffer, "");
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "This is a test", sizeof(buffer)), 14);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "This is a test");
|
||||
CU_ASSERT_EQUAL(buffer[15], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
strcpy(buffer, "AB");
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "X", sizeof(buffer)), 3);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "ABX");
|
||||
CU_ASSERT_EQUAL(buffer[4], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
strcpy(buffer, "X");
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "", sizeof(buffer)), 1);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "X");
|
||||
CU_ASSERT_EQUAL(buffer[2], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
strcpy(buffer, "");
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "", sizeof(buffer)), 0);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "");
|
||||
CU_ASSERT_EQUAL(buffer[1], '\xFF');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify guac_strlcat() behavior when the string must be truncated to fit the
|
||||
* buffer. The return value of each call should be the length that would result
|
||||
* from concatenating the strings given an infinite buffer, however only as
|
||||
* many characters as can fit should be appended to the string within the
|
||||
* buffer, and the buffer should be null-terminated.
|
||||
*/
|
||||
void test_string__strlcat_truncate() {
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
strcpy(buffer, "Apache ");
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "Guacamole", 9), 16);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "Apache G");
|
||||
CU_ASSERT_EQUAL(buffer[9], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
strcpy(buffer, "");
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "This is a test", 10), 14);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "This is a");
|
||||
CU_ASSERT_EQUAL(buffer[10], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
strcpy(buffer, "This ");
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "is ANOTHER test", 6), 20);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "This ");
|
||||
CU_ASSERT_EQUAL(buffer[6], '\xFF');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify guac_strlcat() behavior with zero buffer sizes. The return value of
|
||||
* each call should be the size of the input string, while the buffer remains
|
||||
* untouched.
|
||||
*/
|
||||
void test_string__strlcat_nospace() {
|
||||
|
||||
/* 0-byte buffer plus 1 guard byte (to test overrun) */
|
||||
char buffer[1] = { '\xFF' };
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "Guacamole", 0), 9);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "This is a test", 0), 14);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "X", 0), 1);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "", 0), 0);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify guac_strlcat() behavior with unterminated buffers. With respect to
|
||||
* the return value, the length of the string in the buffer should be
|
||||
* considered equal to the size of the buffer, however the resulting buffer
|
||||
* should not be null-terminated.
|
||||
*/
|
||||
void test_string__strlcat_nonull() {
|
||||
|
||||
char expected[1024];
|
||||
memset(expected, 0xFF, sizeof(expected));
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "Guacamole", 256), 265);
|
||||
CU_ASSERT_NSTRING_EQUAL(buffer, expected, sizeof(expected));
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "This is a test", 37), 51);
|
||||
CU_ASSERT_NSTRING_EQUAL(buffer, expected, sizeof(expected));
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "X", 12), 13);
|
||||
CU_ASSERT_NSTRING_EQUAL(buffer, expected, sizeof(expected));
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcat(buffer, "", 100), 100);
|
||||
CU_ASSERT_NSTRING_EQUAL(buffer, expected, sizeof(expected));
|
||||
|
||||
}
|
||||
|
102
src/libguac/tests/string/strlcpy.c
Normal file
102
src/libguac/tests/string/strlcpy.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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 <CUnit/CUnit.h>
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Verify guac_strlcpy() behavior when the string fits the buffer without
|
||||
* truncation.
|
||||
*/
|
||||
void test_string__strlcpy() {
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "Guacamole", sizeof(buffer)), 9);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "Guacamole");
|
||||
CU_ASSERT_EQUAL(buffer[10], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "This is a test", sizeof(buffer)), 14);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "This is a test");
|
||||
CU_ASSERT_EQUAL(buffer[15], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "X", sizeof(buffer)), 1);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "X");
|
||||
CU_ASSERT_EQUAL(buffer[2], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "", sizeof(buffer)), 0);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "");
|
||||
CU_ASSERT_EQUAL(buffer[1], '\xFF');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify guac_strlcpy() behavior when the string must be truncated to fit the
|
||||
* buffer.
|
||||
*/
|
||||
void test_string__strlcpy_truncate() {
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "Guacamole", 6), 9);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "Guaca");
|
||||
CU_ASSERT_EQUAL(buffer[6], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "This is a test", 10), 14);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "This is a");
|
||||
CU_ASSERT_EQUAL(buffer[10], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "This is ANOTHER test", 2), 20);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "T");
|
||||
CU_ASSERT_EQUAL(buffer[2], '\xFF');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify guac_strlcpy() behavior with zero buffer sizes.
|
||||
*/
|
||||
void test_string__strlcpy_nospace() {
|
||||
|
||||
/* 0-byte buffer plus 1 guard byte (to test overrun) */
|
||||
char buffer[1] = { '\xFF' };
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "Guacamole", 0), 9);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "This is a test", 0), 14);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "X", 0), 1);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strlcpy(buffer, "", 0), 0);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
}
|
||||
|
148
src/libguac/tests/string/strljoin.c
Normal file
148
src/libguac/tests/string/strljoin.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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 <CUnit/CUnit.h>
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Array of test elements containing the strings "Apache" and "Guacamole".
|
||||
*/
|
||||
const char* const apache_guacamole[] = { "Apache", "Guacamole" };
|
||||
|
||||
/**
|
||||
* Array of test elements containing the strings "This", "is", "a", and "test".
|
||||
*/
|
||||
const char* const this_is_a_test[] = { "This", "is", "a", "test" };
|
||||
|
||||
/**
|
||||
* Array of four test elements containing the strings "A" and "B", each
|
||||
* preceded by an empty string ("").
|
||||
*/
|
||||
const char* const empty_a_empty_b[] = { "", "A", "", "B" };
|
||||
|
||||
/**
|
||||
* Array of test elements containing ten empty strings.
|
||||
*/
|
||||
const char* const empty_x10[] = { "", "", "", "", "", "", "", "", "", "" };
|
||||
|
||||
/**
|
||||
* Verify guac_strljoin() behavior when the string fits the buffer without
|
||||
* truncation. The return value of each call should be the length of the
|
||||
* resulting string. Each resulting string should contain the full result of
|
||||
* the join operation, including null terminator.
|
||||
*/
|
||||
void test_string__strljoin() {
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, apache_guacamole, 2, " ", sizeof(buffer)), 16);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "Apache Guacamole");
|
||||
CU_ASSERT_EQUAL(buffer[17], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, this_is_a_test, 4, "", sizeof(buffer)), 11);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "Thisisatest");
|
||||
CU_ASSERT_EQUAL(buffer[12], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, this_is_a_test, 4, "-/-", sizeof(buffer)), 20);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "This-/-is-/-a-/-test");
|
||||
CU_ASSERT_EQUAL(buffer[21], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, empty_a_empty_b, 4, "/", sizeof(buffer)), 5);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "/A//B");
|
||||
CU_ASSERT_EQUAL(buffer[6], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, empty_x10, 10, "/", sizeof(buffer)), 9);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "/////////");
|
||||
CU_ASSERT_EQUAL(buffer[10], '\xFF');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify guac_strljoin() behavior when the string must be truncated to fit the
|
||||
* buffer. The return value of each call should be the length that would result
|
||||
* from joining the strings given an infinite buffer, however only as many
|
||||
* characters as can fit should be appended to the string within the buffer,
|
||||
* and the buffer should be null-terminated.
|
||||
*/
|
||||
void test_string__strljoin_truncate() {
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, apache_guacamole, 2, " ", 9), 16);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "Apache G");
|
||||
CU_ASSERT_EQUAL(buffer[9], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, this_is_a_test, 4, "", 8), 11);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "Thisisa");
|
||||
CU_ASSERT_EQUAL(buffer[8], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, this_is_a_test, 4, "-/-", 12), 20);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "This-/-is-/");
|
||||
CU_ASSERT_EQUAL(buffer[12], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, empty_a_empty_b, 4, "/", 2), 5);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "/");
|
||||
CU_ASSERT_EQUAL(buffer[2], '\xFF');
|
||||
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, empty_x10, 10, "/", 7), 9);
|
||||
CU_ASSERT_STRING_EQUAL(buffer, "//////");
|
||||
CU_ASSERT_EQUAL(buffer[7], '\xFF');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify guac_strljoin() behavior with zero buffer sizes. The return value of
|
||||
* each call should be the size of the input string, while the buffer remains
|
||||
* untouched.
|
||||
*/
|
||||
void test_string__strljoin_nospace() {
|
||||
|
||||
/* 0-byte buffer plus 1 guard byte (to test overrun) */
|
||||
char buffer[1] = { '\xFF' };
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, apache_guacamole, 2, " ", 0), 16);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, this_is_a_test, 4, "", 0), 11);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, this_is_a_test, 4, "-/-", 0), 20);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, empty_a_empty_b, 4, "/", 0), 5);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
CU_ASSERT_EQUAL(guac_strljoin(buffer, empty_x10, 10, "/", 0), 9);
|
||||
CU_ASSERT_EQUAL(buffer[0], '\xFF');
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "timestamp.h"
|
||||
#include "guacamole/timestamp.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "unicode.h"
|
||||
#include "guacamole/unicode.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "object.h"
|
||||
#include "protocol.h"
|
||||
#include "stream.h"
|
||||
#include "timestamp.h"
|
||||
#include "user.h"
|
||||
#include "guacamole/client.h"
|
||||
#include "guacamole/object.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "guacamole/timestamp.h"
|
||||
#include "guacamole/user.h"
|
||||
#include "user-handlers.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
@ -31,8 +31,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "timestamp.h"
|
||||
#include "guacamole/client.h"
|
||||
#include "guacamole/timestamp.h"
|
||||
|
||||
/**
|
||||
* Internal handler for Guacamole instructions. Instruction handlers will be
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "error.h"
|
||||
#include "parser.h"
|
||||
#include "protocol.h"
|
||||
#include "socket.h"
|
||||
#include "user.h"
|
||||
#include "guacamole/client.h"
|
||||
#include "guacamole/error.h"
|
||||
#include "guacamole/parser.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/user.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -19,18 +19,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "encode-jpeg.h"
|
||||
#include "encode-png.h"
|
||||
#include "encode-webp.h"
|
||||
#include "guacamole/client.h"
|
||||
#include "guacamole/object.h"
|
||||
#include "guacamole/pool.h"
|
||||
#include "guacamole/protocol.h"
|
||||
#include "guacamole/socket.h"
|
||||
#include "guacamole/stream.h"
|
||||
#include "guacamole/timestamp.h"
|
||||
#include "guacamole/user.h"
|
||||
#include "id.h"
|
||||
#include "object.h"
|
||||
#include "pool.h"
|
||||
#include "protocol.h"
|
||||
#include "socket.h"
|
||||
#include "stream.h"
|
||||
#include "timestamp.h"
|
||||
#include "user.h"
|
||||
#include "user-handlers.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
37
src/protocols/rdp/.gitignore
vendored
37
src/protocols/rdp/.gitignore
vendored
@ -1,38 +1,7 @@
|
||||
|
||||
# Object code
|
||||
*.o
|
||||
*.so
|
||||
*.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/*
|
||||
!README
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
# Auto-generated test runner and binary
|
||||
_generated_runner.c
|
||||
test_rdp
|
||||
|
||||
# Autogenerated sources
|
||||
_generated_keymaps.c
|
||||
|
@ -27,6 +27,7 @@ AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
lib_LTLIBRARIES = libguac-client-rdp.la
|
||||
SUBDIRS = . tests
|
||||
|
||||
nodist_libguac_client_rdp_la_SOURCES = \
|
||||
_generated_keymaps.c
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#ifdef ENABLE_WINPR
|
||||
#include <winpr/stream.h>
|
||||
@ -53,7 +54,7 @@ int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) {
|
||||
guac_rdp_svc* svc = (guac_rdp_svc*) entry_points_ex->pExtendedData;
|
||||
|
||||
/* Init channel def */
|
||||
strncpy(svc_plugin->plugin.channel_def.name, svc->name,
|
||||
guac_strlcpy(svc_plugin->plugin.channel_def.name, svc->name,
|
||||
GUAC_RDP_SVC_MAX_LENGTH);
|
||||
svc_plugin->plugin.channel_def.options =
|
||||
CHANNEL_OPTION_INITIALIZED
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/perl
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <guacamole/object.h>
|
||||
#include <guacamole/pool.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path,
|
||||
@ -606,51 +607,55 @@ const char* guac_rdp_fs_read_dir(guac_rdp_fs* fs, int file_id) {
|
||||
|
||||
int guac_rdp_fs_normalize_path(const char* path, char* abs_path) {
|
||||
|
||||
int i;
|
||||
int path_depth = 0;
|
||||
char path_component_data[GUAC_RDP_FS_MAX_PATH];
|
||||
const char* path_components[64];
|
||||
|
||||
const char** current_path_component = &(path_components[0]);
|
||||
const char* current_path_component_data = &(path_component_data[0]);
|
||||
const char* path_components[GUAC_RDP_MAX_PATH_DEPTH];
|
||||
|
||||
/* If original path is not absolute, normalization fails */
|
||||
if (path[0] != '\\' && path[0] != '/')
|
||||
return 1;
|
||||
|
||||
/* Skip past leading slash */
|
||||
path++;
|
||||
/* Create scratch copy of path excluding leading slash (we will be
|
||||
* replacing path separators with null terminators and referencing those
|
||||
* substrings directly as path components) */
|
||||
char path_scratch[GUAC_RDP_FS_MAX_PATH - 1];
|
||||
int length = guac_strlcpy(path_scratch, path + 1,
|
||||
sizeof(path_scratch));
|
||||
|
||||
/* Copy path into component data for parsing */
|
||||
strncpy(path_component_data, path, sizeof(path_component_data) - 1);
|
||||
/* Fail if provided path is too long */
|
||||
if (length >= sizeof(path_scratch))
|
||||
return 1;
|
||||
|
||||
/* Find path components within path */
|
||||
for (i = 0; i < sizeof(path_component_data) - 1; i++) {
|
||||
/* Locate all path components within path */
|
||||
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 */
|
||||
char c = path_component_data[i];
|
||||
if (c == '/' || c == '\\' || c == 0) {
|
||||
char c = path_scratch[i];
|
||||
if (c == '/' || c == '\\' || c == '\0') {
|
||||
|
||||
/* Terminate current component */
|
||||
path_component_data[i] = 0;
|
||||
path_scratch[i] = '\0';
|
||||
|
||||
/* 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)
|
||||
path_depth--;
|
||||
}
|
||||
|
||||
/* Otherwise, if component not current directory, add to list */
|
||||
else if (strcmp(current_path_component_data, ".") != 0
|
||||
&& strcmp(current_path_component_data, "") != 0)
|
||||
path_components[path_depth++] = current_path_component_data;
|
||||
else if (strcmp(current_path_component, ".") != 0
|
||||
&& strcmp(current_path_component, "") != 0) {
|
||||
|
||||
/* If end of string, stop */
|
||||
if (c == 0)
|
||||
break;
|
||||
/* Fail normalization if path is too deep */
|
||||
if (path_depth >= GUAC_RDP_MAX_PATH_DEPTH)
|
||||
return 1;
|
||||
|
||||
path_components[path_depth++] = current_path_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 */
|
||||
|
||||
@ -660,57 +665,32 @@ int guac_rdp_fs_normalize_path(const char* path, char* abs_path) {
|
||||
|
||||
} /* end for each character */
|
||||
|
||||
/* If no components, the path is simply root */
|
||||
if (path_depth == 0) {
|
||||
strcpy(abs_path, "\\");
|
||||
return 0;
|
||||
}
|
||||
/* Add leading slash for resulting absolute path */
|
||||
abs_path[0] = '\\';
|
||||
|
||||
/* Ensure last component is null-terminated */
|
||||
path_component_data[i] = 0;
|
||||
/* Append normalized components to path, separated by slashes */
|
||||
guac_strljoin(abs_path + 1, path_components, path_depth,
|
||||
"\\", GUAC_RDP_FS_MAX_PATH - 1);
|
||||
|
||||
/* Convert components back into path */
|
||||
for (; path_depth > 0; path_depth--) {
|
||||
|
||||
const char* filename = *(current_path_component++);
|
||||
|
||||
/* Add separator */
|
||||
*(abs_path++) = '\\';
|
||||
|
||||
/* Copy string */
|
||||
while (*filename != 0)
|
||||
*(abs_path++) = *(filename++);
|
||||
|
||||
}
|
||||
|
||||
/* Terminate absolute path */
|
||||
*(abs_path++) = 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int guac_rdp_fs_convert_path(const char* parent, const char* rel_path, char* abs_path) {
|
||||
|
||||
int i;
|
||||
int length;
|
||||
char combined_path[GUAC_RDP_FS_MAX_PATH];
|
||||
char* current = combined_path;
|
||||
|
||||
/* Copy parent path */
|
||||
for (i=0; i<GUAC_RDP_FS_MAX_PATH; i++) {
|
||||
|
||||
char c = *(parent++);
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
*(current++) = c;
|
||||
|
||||
}
|
||||
length = guac_strlcpy(combined_path, parent, sizeof(combined_path));
|
||||
|
||||
/* Add trailing slash */
|
||||
*(current++) = '\\';
|
||||
length += guac_strlcpy(combined_path + length, "\\",
|
||||
sizeof(combined_path) - length);
|
||||
|
||||
/* Copy remaining path */
|
||||
strncpy(current, rel_path, GUAC_RDP_FS_MAX_PATH-i-2);
|
||||
length += guac_strlcpy(combined_path + length, rel_path,
|
||||
sizeof(combined_path) - length);
|
||||
|
||||
/* Normalize into provided buffer */
|
||||
return guac_rdp_fs_normalize_path(combined_path, abs_path);
|
||||
|
@ -50,6 +50,11 @@
|
||||
*/
|
||||
#define GUAC_RDP_FS_MAX_PATH 4096
|
||||
|
||||
/**
|
||||
* The maximum number of directories a path may contain.
|
||||
*/
|
||||
#define GUAC_RDP_MAX_PATH_DEPTH 64
|
||||
|
||||
/**
|
||||
* Error code returned when no more file IDs can be allocated.
|
||||
*/
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/settings.h>
|
||||
#include <guacamole/string.h>
|
||||
#include <guacamole/user.h>
|
||||
|
||||
#ifdef ENABLE_WINPR
|
||||
@ -1242,11 +1243,11 @@ void guac_rdp_push_settings(guac_client* client,
|
||||
/* Client name */
|
||||
if (guac_settings->client_name != NULL) {
|
||||
#ifdef LEGACY_RDPSETTINGS
|
||||
strncpy(rdp_settings->client_hostname, guac_settings->client_name,
|
||||
RDP_CLIENT_HOSTNAME_SIZE - 1);
|
||||
guac_strlcpy(rdp_settings->client_hostname, guac_settings->client_name,
|
||||
RDP_CLIENT_HOSTNAME_SIZE);
|
||||
#else
|
||||
strncpy(rdp_settings->ClientHostname, guac_settings->client_name,
|
||||
RDP_CLIENT_HOSTNAME_SIZE - 1);
|
||||
guac_strlcpy(rdp_settings->ClientHostname, guac_settings->client_name,
|
||||
RDP_CLIENT_HOSTNAME_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <guacamole/protocol.h>
|
||||
#include <guacamole/socket.h>
|
||||
#include <guacamole/stream.h>
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#ifdef HAVE_FREERDP_CLIENT_CLIPRDR_H
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
@ -504,8 +505,8 @@ int guac_rdp_download_get_handler(guac_user* user, guac_object* object,
|
||||
rdp_stream->type = GUAC_RDP_LS_STREAM;
|
||||
rdp_stream->ls_status.fs = fs;
|
||||
rdp_stream->ls_status.file_id = file_id;
|
||||
strncpy(rdp_stream->ls_status.directory_name, name,
|
||||
sizeof(rdp_stream->ls_status.directory_name) - 1);
|
||||
guac_strlcpy(rdp_stream->ls_status.directory_name, name,
|
||||
sizeof(rdp_stream->ls_status.directory_name));
|
||||
|
||||
/* Allocate stream for body */
|
||||
guac_stream* stream = guac_user_alloc_stream(user);
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <guacamole/client.h>
|
||||
#include <guacamole/string.h>
|
||||
|
||||
#ifdef ENABLE_WINPR
|
||||
#include <winpr/stream.h>
|
||||
@ -33,7 +34,6 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
guac_rdp_svc* guac_rdp_alloc_svc(guac_client* client, char* name) {
|
||||
|
||||
@ -44,16 +44,14 @@ guac_rdp_svc* guac_rdp_alloc_svc(guac_client* client, char* name) {
|
||||
svc->plugin = NULL;
|
||||
svc->output_pipe = NULL;
|
||||
|
||||
/* Init name */
|
||||
int name_length = guac_strlcpy(svc->name, name, GUAC_RDP_SVC_MAX_LENGTH);
|
||||
|
||||
/* Warn about name length */
|
||||
if (strnlen(name, GUAC_RDP_SVC_MAX_LENGTH+1) > GUAC_RDP_SVC_MAX_LENGTH)
|
||||
if (name_length >= GUAC_RDP_SVC_MAX_LENGTH)
|
||||
guac_client_log(client, GUAC_LOG_INFO,
|
||||
"Static channel name \"%s\" exceeds maximum of %i characters "
|
||||
"and will be truncated",
|
||||
name, GUAC_RDP_SVC_MAX_LENGTH);
|
||||
|
||||
/* Init name */
|
||||
strncpy(svc->name, name, GUAC_RDP_SVC_MAX_LENGTH);
|
||||
svc->name[GUAC_RDP_SVC_MAX_LENGTH] = '\0';
|
||||
"and will be truncated", name, GUAC_RDP_SVC_MAX_LENGTH - 1);
|
||||
|
||||
return svc;
|
||||
}
|
||||
|
@ -27,9 +27,10 @@
|
||||
#include <guacamole/stream.h>
|
||||
|
||||
/**
|
||||
* The maximum number of characters to allow for each channel name.
|
||||
* The maximum number of bytes to allow within each channel name, including
|
||||
* null terminator.
|
||||
*/
|
||||
#define GUAC_RDP_SVC_MAX_LENGTH 7
|
||||
#define GUAC_RDP_SVC_MAX_LENGTH 8
|
||||
|
||||
/**
|
||||
* Structure describing a static virtual channel, and the corresponding
|
||||
@ -50,7 +51,7 @@ typedef struct guac_rdp_svc {
|
||||
/**
|
||||
* The name of the RDP channel in use, and the name to use for each pipe.
|
||||
*/
|
||||
char name[GUAC_RDP_SVC_MAX_LENGTH+1];
|
||||
char name[GUAC_RDP_SVC_MAX_LENGTH];
|
||||
|
||||
/**
|
||||
* The output pipe, opened when the RDP server receives a connection to
|
||||
|
64
src/protocols/rdp/tests/Makefile.am
Normal file
64
src/protocols/rdp/tests/Makefile.am
Normal file
@ -0,0 +1,64 @@
|
||||
#
|
||||
# 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 RDP support
|
||||
#
|
||||
|
||||
check_PROGRAMS = test_rdp
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
test_rdp_SOURCES = \
|
||||
fs/normalize_path.c
|
||||
|
||||
test_rdp_CFLAGS = \
|
||||
-Werror -Wall -pedantic \
|
||||
@LIBGUAC_CLIENT_RDP_INCLUDE@
|
||||
|
||||
test_rdp_LDADD = \
|
||||
@CUNIT_LIBS@ \
|
||||
@LIBGUAC_CLIENT_RDP_LTLIB@
|
||||
|
||||
#
|
||||
# Autogenerate test runner
|
||||
#
|
||||
|
||||
GEN_RUNNER = $(top_srcdir)/util/generate-test-runner.pl
|
||||
CLEANFILES = _generated_runner.c
|
||||
|
||||
_generated_runner.c: $(test_rdp_SOURCES)
|
||||
$(AM_V_GEN) $(GEN_RUNNER) $(test_rdp_SOURCES) > $@
|
||||
|
||||
nodist_test_rdp_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
|
||||
|
256
src/protocols/rdp/tests/fs/normalize_path.c
Normal file
256
src/protocols/rdp/tests/fs/normalize_path.c
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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 "rdp_fs.h"
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Test which verifies absolute Windows-style paths are correctly normalized to
|
||||
* absolute paths with Windows separators and no relative components.
|
||||
*/
|
||||
void test_fs__normalize_absolute_windows() {
|
||||
|
||||
char normalized[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\bar\\baz", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\bar\\..\\baz\\", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\bar\\..\\..\\baz\\a\\..\\b", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\baz\\b", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\.\\bar\\baz", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\bar\\..\\..\\..\\..\\..\\..\\baz", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\baz", sizeof(normalized));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies absolute UNIX-style paths are correctly normalized to
|
||||
* absolute paths with Windows separators and no relative components.
|
||||
*/
|
||||
void test_fs__normalize_absolute_unix() {
|
||||
|
||||
char normalized[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/bar/baz", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/bar/../baz/", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/bar/../../baz/a/../b", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\baz\\b", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/./bar/baz", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/bar/../../../../../../baz", normalized), 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 Windows
|
||||
* separators and no relative components.
|
||||
*/
|
||||
void test_fs__normalize_absolute_mixed() {
|
||||
|
||||
char normalized[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo/bar\\baz", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo\\bar/..\\baz/", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo/bar\\../../baz\\a\\..\\b", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\baz\\b", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\.\\bar/baz", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized));
|
||||
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo/bar\\../..\\..\\..\\../..\\baz", normalized), 0)
|
||||
CU_ASSERT_NSTRING_EQUAL(normalized, "\\baz", sizeof(normalized));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies relative Windows-style paths are always rejected.
|
||||
*/
|
||||
void test_fs__normalize_relative_windows() {
|
||||
|
||||
char normalized[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("..", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".\\foo", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("..\\foo", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo\\bar\\baz", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".\\foo\\bar\\baz", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("..\\foo\\bar\\baz", normalized), 0)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies relative UNIX-style paths are always rejected.
|
||||
*/
|
||||
void test_fs__normalize_relative_unix() {
|
||||
|
||||
char normalized[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("..", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("./foo", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("../foo", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo/bar/baz", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("./foo/bar/baz", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("../foo/bar/baz", normalized), 0)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies relative paths consisting of mixed Windows and UNIX path
|
||||
* separators are always rejected.
|
||||
*/
|
||||
void test_fs__normalize_relative_mixed() {
|
||||
|
||||
char normalized[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo\\bar/baz", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".\\foo/bar/baz", normalized), 0)
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("../foo\\bar\\baz", normalized), 0)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a dynamically-allocated path having the given number of bytes, not
|
||||
* counting the null-terminator. The path will contain only Windows-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_fs__normalize_long() {
|
||||
|
||||
char* input;
|
||||
char normalized[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
/* Exceeds maximum length by a factor of 2 */
|
||||
input = generate_path(GUAC_RDP_FS_MAX_PATH * 2, GUAC_RDP_MAX_PATH_DEPTH);
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0);
|
||||
free(input);
|
||||
|
||||
/* Exceeds maximum length by one byte */
|
||||
input = generate_path(GUAC_RDP_FS_MAX_PATH, GUAC_RDP_MAX_PATH_DEPTH);
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0);
|
||||
free(input);
|
||||
|
||||
/* Exactly maximum length */
|
||||
input = generate_path(GUAC_RDP_FS_MAX_PATH - 1, GUAC_RDP_MAX_PATH_DEPTH);
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0);
|
||||
free(input);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test which verifies that paths exceeding the maximum path depth are
|
||||
* rejected.
|
||||
*/
|
||||
void test_fs__normalize_deep() {
|
||||
|
||||
char* input;
|
||||
char normalized[GUAC_RDP_FS_MAX_PATH];
|
||||
|
||||
/* Exceeds maximum depth by a factor of 2 */
|
||||
input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH * 2);
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0);
|
||||
free(input);
|
||||
|
||||
/* Exceeds maximum depth by one component */
|
||||
input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH + 1);
|
||||
CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0);
|
||||
free(input);
|
||||
|
||||
/* Exactly maximum depth */
|
||||
input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH);
|
||||
CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0);
|
||||
free(input);
|
||||
|
||||
}
|
||||
|
36
src/protocols/ssh/.gitignore
vendored
36
src/protocols/ssh/.gitignore
vendored
@ -1,36 +0,0 @@
|
||||
|
||||
# Object code
|
||||
*.o
|
||||
*.so
|
||||
*.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/*
|
||||
!README
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
|
36
src/protocols/telnet/.gitignore
vendored
36
src/protocols/telnet/.gitignore
vendored
@ -1,36 +0,0 @@
|
||||
|
||||
# Object code
|
||||
*.o
|
||||
*.so
|
||||
*.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/*
|
||||
!README
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
|
36
src/protocols/vnc/.gitignore
vendored
36
src/protocols/vnc/.gitignore
vendored
@ -1,36 +0,0 @@
|
||||
|
||||
# Object code
|
||||
*.o
|
||||
*.so
|
||||
*.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/*
|
||||
!README
|
||||
config.guess
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/perl
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
|
Loading…
Reference in New Issue
Block a user