normalize_path.c (9706B)
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 "fs.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 Windows separators and no relative components. 30 */ 31void test_fs__normalize_absolute_windows() { 32 33 char normalized[GUAC_RDP_FS_MAX_PATH]; 34 35 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\", normalized), 0) 36 CU_ASSERT_NSTRING_EQUAL(normalized, "\\", sizeof(normalized)); 37 38 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\bar\\baz", normalized), 0) 39 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized)); 40 41 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\bar\\..\\baz\\", normalized), 0) 42 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\baz", sizeof(normalized)); 43 44 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\bar\\..\\..\\baz\\a\\..\\b", normalized), 0) 45 CU_ASSERT_NSTRING_EQUAL(normalized, "\\baz\\b", sizeof(normalized)); 46 47 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\.\\bar\\baz", normalized), 0) 48 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized)); 49 50 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\bar\\..\\..\\..\\..\\..\\..\\baz", normalized), 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 Windows separators and no relative components. 58 */ 59void test_fs__normalize_absolute_unix() { 60 61 char normalized[GUAC_RDP_FS_MAX_PATH]; 62 63 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/", normalized), 0) 64 CU_ASSERT_NSTRING_EQUAL(normalized, "\\", sizeof(normalized)); 65 66 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/bar/baz", normalized), 0) 67 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized)); 68 69 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/bar/../baz/", normalized), 0) 70 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\baz", sizeof(normalized)); 71 72 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/bar/../../baz/a/../b", normalized), 0) 73 CU_ASSERT_NSTRING_EQUAL(normalized, "\\baz\\b", sizeof(normalized)); 74 75 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/./bar/baz", normalized), 0) 76 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized)); 77 78 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo/bar/../../../../../../baz", normalized), 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 Windows 86 * separators and no relative components. 87 */ 88void test_fs__normalize_absolute_mixed() { 89 90 char normalized[GUAC_RDP_FS_MAX_PATH]; 91 92 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo/bar\\baz", normalized), 0) 93 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized)); 94 95 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("/foo\\bar/..\\baz/", normalized), 0) 96 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\baz", sizeof(normalized)); 97 98 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo/bar\\../../baz\\a\\..\\b", normalized), 0) 99 CU_ASSERT_NSTRING_EQUAL(normalized, "\\baz\\b", sizeof(normalized)); 100 101 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo\\.\\bar/baz", normalized), 0) 102 CU_ASSERT_NSTRING_EQUAL(normalized, "\\foo\\bar\\baz", sizeof(normalized)); 103 104 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path("\\foo/bar\\../..\\..\\..\\../..\\baz", normalized), 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_fs__normalize_relative_windows() { 113 114 char normalized[GUAC_RDP_FS_MAX_PATH]; 115 116 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("", normalized), 0) 117 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".", normalized), 0) 118 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("..", normalized), 0) 119 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo", normalized), 0) 120 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".\\foo", normalized), 0) 121 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("..\\foo", normalized), 0) 122 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo\\bar\\baz", normalized), 0) 123 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".\\foo\\bar\\baz", normalized), 0) 124 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("..\\foo\\bar\\baz", normalized), 0) 125 126} 127 128/** 129 * Test which verifies relative UNIX-style paths are always rejected. 130 */ 131void test_fs__normalize_relative_unix() { 132 133 char normalized[GUAC_RDP_FS_MAX_PATH]; 134 135 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("", normalized), 0) 136 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".", normalized), 0) 137 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("..", normalized), 0) 138 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo", normalized), 0) 139 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("./foo", normalized), 0) 140 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("../foo", normalized), 0) 141 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo/bar/baz", normalized), 0) 142 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("./foo/bar/baz", normalized), 0) 143 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("../foo/bar/baz", normalized), 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_fs__normalize_relative_mixed() { 152 153 char normalized[GUAC_RDP_FS_MAX_PATH]; 154 155 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("foo\\bar/baz", normalized), 0) 156 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(".\\foo/bar/baz", normalized), 0) 157 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path("../foo\\bar\\baz", normalized), 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 Windows-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 = 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_fs__normalize_long() { 212 213 char* input; 214 char normalized[GUAC_RDP_FS_MAX_PATH]; 215 216 /* Exceeds maximum length by a factor of 2 */ 217 input = generate_path(GUAC_RDP_FS_MAX_PATH * 2, GUAC_RDP_MAX_PATH_DEPTH); 218 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); 219 guac_mem_free(input); 220 221 /* Exceeds maximum length by one byte */ 222 input = generate_path(GUAC_RDP_FS_MAX_PATH, GUAC_RDP_MAX_PATH_DEPTH); 223 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); 224 guac_mem_free(input); 225 226 /* Exactly maximum length */ 227 input = generate_path(GUAC_RDP_FS_MAX_PATH - 1, GUAC_RDP_MAX_PATH_DEPTH); 228 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 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_fs__normalize_deep() { 238 239 char* input; 240 char normalized[GUAC_RDP_FS_MAX_PATH]; 241 242 /* Exceeds maximum depth by a factor of 2 */ 243 input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH * 2); 244 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); 245 guac_mem_free(input); 246 247 /* Exceeds maximum depth by one component */ 248 input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH + 1); 249 CU_ASSERT_NOT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); 250 guac_mem_free(input); 251 252 /* Exactly maximum depth */ 253 input = generate_path(-1, GUAC_RDP_MAX_PATH_DEPTH); 254 CU_ASSERT_EQUAL(guac_rdp_fs_normalize_path(input, normalized), 0); 255 guac_mem_free(input); 256 257} 258