normalize_path.c (10611B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "common-ssh/sftp.h" 21 22#include <guacamole/mem.h> 23 24#include <CUnit/CUnit.h> 25#include <stdlib.h> 26 27/** 28 * Test which verifies absolute Windows-style paths are correctly normalized to 29 * absolute paths with UNIX separators and no relative components. 30 */ 31void test_sftp__normalize_absolute_windows() { 32 33 char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH]; 34 35 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\"), 0); 36 CU_ASSERT_NSTRING_EQUAL(normalized, "/", sizeof(normalized)); 37 38 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\baz"), 0); 39 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized)); 40 41 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\baz\\"), 0); 42 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized)); 43 44 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\..\\baz\\a\\..\\b"), 0); 45 CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized)); 46 47 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\.\\bar\\baz"), 0); 48 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized)); 49 50 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\bar\\..\\..\\..\\..\\..\\..\\baz"), 0); 51 CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized)); 52 53} 54 55/** 56 * Test which verifies absolute UNIX-style paths are correctly normalized to 57 * absolute paths with UNIX separators and no relative components. 58 */ 59void test_sftp__normalize_absolute_unix() { 60 61 char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH]; 62 63 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/"), 0); 64 CU_ASSERT_NSTRING_EQUAL(normalized, "/", sizeof(normalized)); 65 66 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/baz"), 0); 67 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized)); 68 69 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../baz/"), 0); 70 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized)); 71 72 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../../baz/a/../b"), 0); 73 CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized)); 74 75 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/./bar/baz"), 0); 76 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized)); 77 78 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo/bar/../../../../../../baz"), 0); 79 CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized)); 80 81} 82 83/** 84 * Test which verifies absolute paths consisting of mixed Windows and UNIX path 85 * separators are correctly normalized to absolute paths with UNIX separators 86 * and no relative components. 87 */ 88void test_sftp__normalize_absolute_mixed() { 89 90 char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH]; 91 92 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\baz"), 0); 93 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized)); 94 95 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "/foo\\bar/..\\baz/"), 0); 96 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/baz", sizeof(normalized)); 97 98 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\../../baz\\a\\..\\b"), 0); 99 CU_ASSERT_NSTRING_EQUAL(normalized, "/baz/b", sizeof(normalized)); 100 101 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo\\.\\bar/baz"), 0); 102 CU_ASSERT_NSTRING_EQUAL(normalized, "/foo/bar/baz", sizeof(normalized)); 103 104 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "\\foo/bar\\../..\\..\\..\\../..\\baz"), 0); 105 CU_ASSERT_NSTRING_EQUAL(normalized, "/baz", sizeof(normalized)); 106 107} 108 109/** 110 * Test which verifies relative Windows-style paths are always rejected. 111 */ 112void test_sftp__normalize_relative_windows() { 113 114 char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH]; 115 116 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ""), 0); 117 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "."), 0); 118 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".."), 0); 119 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo"), 0); 120 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo"), 0); 121 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "..\\foo"), 0); 122 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo\\bar\\baz"), 0); 123 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo\\bar\\baz"), 0); 124 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "..\\foo\\bar\\baz"), 0); 125 126} 127 128/** 129 * Test which verifies relative UNIX-style paths are always rejected. 130 */ 131void test_sftp__normalize_relative_unix() { 132 133 char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH]; 134 135 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ""), 0); 136 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "."), 0); 137 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".."), 0); 138 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo"), 0); 139 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "./foo"), 0); 140 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo"), 0); 141 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo/bar/baz"), 0); 142 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "./foo/bar/baz"), 0); 143 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo/bar/baz"), 0); 144 145} 146 147/** 148 * Test which verifies relative paths consisting of mixed Windows and UNIX path 149 * separators are always rejected. 150 */ 151void test_sftp__normalize_relative_mixed() { 152 153 char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH]; 154 155 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "foo\\bar/baz"), 0); 156 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, ".\\foo/bar/baz"), 0); 157 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, "../foo\\bar\\baz"), 0); 158 159} 160 161/** 162 * Generates a dynamically-allocated path having the given number of bytes, not 163 * counting the null-terminator. The path will contain only UNIX-style path 164 * separators. The returned path must eventually be freed with a call to 165 * guac_mem_free(). 166 * 167 * @param length 168 * The number of bytes to include in the generated path, not counting the 169 * null-terminator. If -1, the length of the path will be automatically 170 * determined from the provided max_depth. 171 * 172 * @param max_depth 173 * The maximum number of path components to include within the generated 174 * path. 175 * 176 * @return 177 * A dynamically-allocated path containing the given number of bytes, not 178 * counting the null-terminator. This path must eventually be freed with a 179 * call to guac_mem_free(). 180 */ 181static char* generate_path(int length, int max_depth) { 182 183 /* If no length given, calculate space required from max_depth */ 184 if (length == -1) 185 length = guac_mem_ckd_mul_or_die(max_depth, 2); 186 187 int i; 188 char* input = guac_mem_alloc(guac_mem_ckd_add_or_die(length, 1)); 189 190 /* Fill path with /x/x/x/x/x/x/x/x/x/x/.../xxxxxxxxx... */ 191 for (i = 0; i < length; i++) { 192 if (max_depth > 0 && i % 2 == 0) { 193 input[i] = '/'; 194 max_depth--; 195 } 196 else 197 input[i] = 'x'; 198 } 199 200 /* Add null terminator */ 201 input[length] = '\0'; 202 203 return input; 204 205} 206 207/** 208 * Test which verifies that paths exceeding the maximum path length are 209 * rejected. 210 */ 211void test_sftp__normalize_long() { 212 213 char* input; 214 char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH]; 215 216 /* Exceeds maximum length by a factor of 2 */ 217 input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH * 2, GUAC_COMMON_SSH_SFTP_MAX_DEPTH); 218 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); 219 guac_mem_free(input); 220 221 /* Exceeds maximum length by one byte */ 222 input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH, GUAC_COMMON_SSH_SFTP_MAX_DEPTH); 223 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); 224 guac_mem_free(input); 225 226 /* Exactly maximum length */ 227 input = generate_path(GUAC_COMMON_SSH_SFTP_MAX_PATH - 1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH); 228 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); 229 guac_mem_free(input); 230 231} 232 233/** 234 * Test which verifies that paths exceeding the maximum path depth are 235 * rejected. 236 */ 237void test_sftp__normalize_deep() { 238 239 char* input; 240 char normalized[GUAC_COMMON_SSH_SFTP_MAX_PATH]; 241 242 /* Exceeds maximum depth by a factor of 2 */ 243 input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH * 2); 244 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); 245 guac_mem_free(input); 246 247 /* Exceeds maximum depth by one component */ 248 input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH + 1); 249 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); 250 guac_mem_free(input); 251 252 /* Exactly maximum depth (should still be rejected as SFTP depth limits are 253 * set such that a path with the maximum depth will exceed the maximum 254 * length) */ 255 input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH); 256 CU_ASSERT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); 257 guac_mem_free(input); 258 259 /* Less than maximum depth */ 260 input = generate_path(-1, GUAC_COMMON_SSH_SFTP_MAX_DEPTH - 1); 261 CU_ASSERT_NOT_EQUAL(guac_common_ssh_sftp_normalize_path(normalized, input), 0); 262 guac_mem_free(input); 263 264} 265