1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr.h" 18251875Speter#include "apr_private.h" 19251875Speter#include "apr_arch_file_io.h" 20251875Speter#include "apr_file_io.h" 21251875Speter#include "apr_strings.h" 22251875Speter#define APR_WANT_STRFUNC 23251875Speter#include "apr_want.h" 24251875Speter#if APR_HAVE_UNISTD_H 25251875Speter#include <unistd.h> 26251875Speter#endif 27251875Speter 28251875Speter/* Win32 malpropism that can go away once everyone believes this 29251875Speter * code is golden, and I'm not testing it anymore :-) 30251875Speter */ 31251875Speter#if APR_HAVE_DIRENT_H 32251875Speter#include <dirent.h> 33251875Speter#endif 34251875Speter 35251875Speter/* Any OS that requires/refuses trailing slashes should be dealt with here. 36251875Speter */ 37251875SpeterAPR_DECLARE(apr_status_t) apr_filepath_get(char **defpath, apr_int32_t flags, 38251875Speter apr_pool_t *p) 39251875Speter{ 40251875Speter char path[APR_PATH_MAX]; 41251875Speter 42251875Speter if (!getcwd(path, sizeof(path))) { 43251875Speter if (errno == ERANGE) 44251875Speter return APR_ENAMETOOLONG; 45251875Speter else 46251875Speter return errno; 47251875Speter } 48251875Speter *defpath = apr_pstrdup(p, path); 49251875Speter 50251875Speter return APR_SUCCESS; 51251875Speter} 52251875Speter 53251875Speter 54251875Speter/* Any OS that requires/refuses trailing slashes should be dealt with here 55251875Speter */ 56251875SpeterAPR_DECLARE(apr_status_t) apr_filepath_set(const char *path, apr_pool_t *p) 57251875Speter{ 58251875Speter if (chdir(path) != 0) 59251875Speter return errno; 60251875Speter 61251875Speter return APR_SUCCESS; 62251875Speter} 63251875Speter 64251875SpeterAPR_DECLARE(apr_status_t) apr_filepath_root(const char **rootpath, 65251875Speter const char **inpath, 66251875Speter apr_int32_t flags, 67251875Speter apr_pool_t *p) 68251875Speter{ 69251875Speter if (**inpath == '/') { 70251875Speter *rootpath = apr_pstrdup(p, "/"); 71251875Speter do { 72251875Speter ++(*inpath); 73251875Speter } while (**inpath == '/'); 74251875Speter 75251875Speter return APR_SUCCESS; 76251875Speter } 77251875Speter 78251875Speter return APR_ERELATIVE; 79251875Speter} 80251875Speter 81251875SpeterAPR_DECLARE(apr_status_t) apr_filepath_merge(char **newpath, 82251875Speter const char *rootpath, 83251875Speter const char *addpath, 84251875Speter apr_int32_t flags, 85251875Speter apr_pool_t *p) 86251875Speter{ 87251875Speter char *path; 88251875Speter apr_size_t rootlen; /* is the length of the src rootpath */ 89251875Speter apr_size_t maxlen; /* maximum total path length */ 90251875Speter apr_size_t keptlen; /* is the length of the retained rootpath */ 91251875Speter apr_size_t pathlen; /* is the length of the result path */ 92251875Speter apr_size_t seglen; /* is the end of the current segment */ 93251875Speter apr_status_t rv; 94251875Speter 95251875Speter /* Treat null as an empty path. 96251875Speter */ 97251875Speter if (!addpath) 98251875Speter addpath = ""; 99251875Speter 100251875Speter if (addpath[0] == '/') { 101251875Speter /* If addpath is rooted, then rootpath is unused. 102251875Speter * Ths violates any APR_FILEPATH_SECUREROOTTEST and 103251875Speter * APR_FILEPATH_NOTABSOLUTE flags specified. 104251875Speter */ 105251875Speter if (flags & APR_FILEPATH_SECUREROOTTEST) 106251875Speter return APR_EABOVEROOT; 107251875Speter if (flags & APR_FILEPATH_NOTABSOLUTE) 108251875Speter return APR_EABSOLUTE; 109251875Speter 110251875Speter /* If APR_FILEPATH_NOTABOVEROOT wasn't specified, 111251875Speter * we won't test the root again, it's ignored. 112251875Speter * Waste no CPU retrieving the working path. 113251875Speter */ 114251875Speter if (!rootpath && !(flags & APR_FILEPATH_NOTABOVEROOT)) 115251875Speter rootpath = ""; 116251875Speter } 117251875Speter else { 118251875Speter /* If APR_FILEPATH_NOTABSOLUTE is specified, the caller 119251875Speter * requires a relative result. If the rootpath is 120251875Speter * ommitted, we do not retrieve the working path, 121251875Speter * if rootpath was supplied as absolute then fail. 122251875Speter */ 123251875Speter if (flags & APR_FILEPATH_NOTABSOLUTE) { 124251875Speter if (!rootpath) 125251875Speter rootpath = ""; 126251875Speter else if (rootpath[0] == '/') 127251875Speter return APR_EABSOLUTE; 128251875Speter } 129251875Speter } 130251875Speter 131251875Speter if (!rootpath) { 132251875Speter /* Start with the current working path. This is bass akwards, 133251875Speter * but required since the compiler (at least vc) doesn't like 134251875Speter * passing the address of a char const* for a char** arg. 135251875Speter */ 136251875Speter char *getpath; 137251875Speter rv = apr_filepath_get(&getpath, flags, p); 138251875Speter rootpath = getpath; 139251875Speter if (rv != APR_SUCCESS) 140251875Speter return errno; 141251875Speter 142251875Speter /* XXX: Any kernel subject to goofy, uncanonical results 143251875Speter * must run the rootpath against the user's given flags. 144251875Speter * Simplest would be a recursive call to apr_filepath_merge 145251875Speter * with an empty (not null) rootpath and addpath of the cwd. 146251875Speter */ 147251875Speter } 148251875Speter 149251875Speter rootlen = strlen(rootpath); 150251875Speter maxlen = rootlen + strlen(addpath) + 4; /* 4 for slashes at start, after 151251875Speter * root, and at end, plus trailing 152251875Speter * null */ 153251875Speter if (maxlen > APR_PATH_MAX) { 154251875Speter return APR_ENAMETOOLONG; 155251875Speter } 156251875Speter path = (char *)apr_palloc(p, maxlen); 157251875Speter 158251875Speter if (addpath[0] == '/') { 159251875Speter /* Ignore the given root path, strip off leading 160251875Speter * '/'s to a single leading '/' from the addpath, 161251875Speter * and leave addpath at the first non-'/' character. 162251875Speter */ 163251875Speter keptlen = 0; 164251875Speter while (addpath[0] == '/') 165251875Speter ++addpath; 166251875Speter path[0] = '/'; 167251875Speter pathlen = 1; 168251875Speter } 169251875Speter else { 170251875Speter /* If both paths are relative, fail early 171251875Speter */ 172251875Speter if (rootpath[0] != '/' && (flags & APR_FILEPATH_NOTRELATIVE)) 173251875Speter return APR_ERELATIVE; 174251875Speter 175251875Speter /* Base the result path on the rootpath 176251875Speter */ 177251875Speter keptlen = rootlen; 178251875Speter memcpy(path, rootpath, rootlen); 179251875Speter 180251875Speter /* Always '/' terminate the given root path 181251875Speter */ 182251875Speter if (keptlen && path[keptlen - 1] != '/') { 183251875Speter path[keptlen++] = '/'; 184251875Speter } 185251875Speter pathlen = keptlen; 186251875Speter } 187251875Speter 188251875Speter while (*addpath) { 189251875Speter /* Parse each segment, find the closing '/' 190251875Speter */ 191251875Speter const char *next = addpath; 192251875Speter while (*next && (*next != '/')) { 193251875Speter ++next; 194251875Speter } 195251875Speter seglen = next - addpath; 196251875Speter 197251875Speter if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) { 198251875Speter /* noop segment (/ or ./) so skip it 199251875Speter */ 200251875Speter } 201251875Speter else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') { 202251875Speter /* backpath (../) */ 203251875Speter if (pathlen == 1 && path[0] == '/') { 204251875Speter /* Attempt to move above root. Always die if the 205251875Speter * APR_FILEPATH_SECUREROOTTEST flag is specified. 206251875Speter */ 207251875Speter if (flags & APR_FILEPATH_SECUREROOTTEST) { 208251875Speter return APR_EABOVEROOT; 209251875Speter } 210251875Speter 211251875Speter /* Otherwise this is simply a noop, above root is root. 212251875Speter * Flag that rootpath was entirely replaced. 213251875Speter */ 214251875Speter keptlen = 0; 215251875Speter } 216251875Speter else if (pathlen == 0 217251875Speter || (pathlen == 3 218251875Speter && !memcmp(path + pathlen - 3, "../", 3)) 219251875Speter || (pathlen > 3 220251875Speter && !memcmp(path + pathlen - 4, "/../", 4))) { 221251875Speter /* Path is already backpathed or empty, if the 222251875Speter * APR_FILEPATH_SECUREROOTTEST.was given die now. 223251875Speter */ 224251875Speter if (flags & APR_FILEPATH_SECUREROOTTEST) { 225251875Speter return APR_EABOVEROOT; 226251875Speter } 227251875Speter 228251875Speter /* Otherwise append another backpath, including 229251875Speter * trailing slash if present. 230251875Speter */ 231251875Speter memcpy(path + pathlen, "../", *next ? 3 : 2); 232251875Speter pathlen += *next ? 3 : 2; 233251875Speter } 234251875Speter else { 235251875Speter /* otherwise crop the prior segment 236251875Speter */ 237251875Speter do { 238251875Speter --pathlen; 239251875Speter } while (pathlen && path[pathlen - 1] != '/'); 240251875Speter } 241251875Speter 242251875Speter /* Now test if we are above where we started and back up 243251875Speter * the keptlen offset to reflect the added/altered path. 244251875Speter */ 245251875Speter if (pathlen < keptlen) { 246251875Speter if (flags & APR_FILEPATH_SECUREROOTTEST) { 247251875Speter return APR_EABOVEROOT; 248251875Speter } 249251875Speter keptlen = pathlen; 250251875Speter } 251251875Speter } 252251875Speter else { 253251875Speter /* An actual segment, append it to the destination path 254251875Speter */ 255251875Speter if (*next) { 256251875Speter seglen++; 257251875Speter } 258251875Speter memcpy(path + pathlen, addpath, seglen); 259251875Speter pathlen += seglen; 260251875Speter } 261251875Speter 262251875Speter /* Skip over trailing slash to the next segment 263251875Speter */ 264251875Speter if (*next) { 265251875Speter ++next; 266251875Speter } 267251875Speter 268251875Speter addpath = next; 269251875Speter } 270251875Speter path[pathlen] = '\0'; 271251875Speter 272251875Speter /* keptlen will be the rootlen unless the addpath contained 273251875Speter * backpath elements. If so, and APR_FILEPATH_NOTABOVEROOT 274251875Speter * is specified (APR_FILEPATH_SECUREROOTTEST was caught above), 275251875Speter * compare the original root to assure the result path is 276251875Speter * still within given root path. 277251875Speter */ 278251875Speter if ((flags & APR_FILEPATH_NOTABOVEROOT) && keptlen < rootlen) { 279251875Speter if (strncmp(rootpath, path, rootlen)) { 280251875Speter return APR_EABOVEROOT; 281251875Speter } 282251875Speter if (rootpath[rootlen - 1] != '/' 283251875Speter && path[rootlen] && path[rootlen] != '/') { 284251875Speter return APR_EABOVEROOT; 285251875Speter } 286251875Speter } 287251875Speter 288251875Speter *newpath = path; 289251875Speter return APR_SUCCESS; 290251875Speter} 291251875Speter 292251875SpeterAPR_DECLARE(apr_status_t) apr_filepath_list_split(apr_array_header_t **pathelts, 293251875Speter const char *liststr, 294251875Speter apr_pool_t *p) 295251875Speter{ 296251875Speter return apr_filepath_list_split_impl(pathelts, liststr, ':', p); 297251875Speter} 298251875Speter 299251875SpeterAPR_DECLARE(apr_status_t) apr_filepath_list_merge(char **liststr, 300251875Speter apr_array_header_t *pathelts, 301251875Speter apr_pool_t *p) 302251875Speter{ 303251875Speter return apr_filepath_list_merge_impl(liststr, pathelts, ':', p); 304251875Speter} 305251875Speter 306251875SpeterAPR_DECLARE(apr_status_t) apr_filepath_encoding(int *style, apr_pool_t *p) 307251875Speter{ 308251875Speter#if defined(DARWIN) 309251875Speter *style = APR_FILEPATH_ENCODING_UTF8; 310251875Speter#else 311251875Speter *style = APR_FILEPATH_ENCODING_LOCALE; 312251875Speter#endif 313251875Speter return APR_SUCCESS; 314251875Speter} 315