Use GCDWebServerNormalizePath() on all relative paths passed to GCDWebServer

This commit is contained in:
Pierre-Olivier Latour
2019-01-04 18:59:57 -08:00
parent ec800b43d5
commit 87745c0fde
3 changed files with 30 additions and 57 deletions

View File

@ -77,7 +77,7 @@ NS_ASSUME_NONNULL_END
- (instancetype)initWithUploadDirectory:(NSString*)path { - (instancetype)initWithUploadDirectory:(NSString*)path {
if ((self = [super init])) { if ((self = [super init])) {
_uploadDirectory = [[path stringByStandardizingPath] copy]; _uploadDirectory = [path copy];
GCDWebDAVServer* __unsafe_unretained server = self; GCDWebDAVServer* __unsafe_unretained server = self;
// 9.1 PROPFIND method // 9.1 PROPFIND method
@ -157,11 +157,6 @@ NS_ASSUME_NONNULL_END
@implementation GCDWebDAVServer (Methods) @implementation GCDWebDAVServer (Methods)
// Must match implementation in GCDWebUploader
- (BOOL)_checkSandboxedPath:(NSString*)path {
return [[path stringByStandardizingPath] hasPrefix:_uploadDirectory];
}
- (BOOL)_checkFileExtension:(NSString*)fileName { - (BOOL)_checkFileExtension:(NSString*)fileName {
if (_allowedFileExtensions && ![_allowedFileExtensions containsObject:[[fileName pathExtension] lowercaseString]]) { if (_allowedFileExtensions && ![_allowedFileExtensions containsObject:[[fileName pathExtension] lowercaseString]]) {
return NO; return NO;
@ -186,9 +181,9 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) {
- (GCDWebServerResponse*)performGET:(GCDWebServerRequest*)request { - (GCDWebServerResponse*)performGET:(GCDWebServerRequest*)request {
NSString* relativePath = request.path; NSString* relativePath = request.path;
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
} }
@ -221,10 +216,7 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) {
} }
NSString* relativePath = request.path; NSString* relativePath = request.path;
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
if (![self _checkSandboxedPath:absolutePath]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
}
BOOL isDirectory; BOOL isDirectory;
if (![[NSFileManager defaultManager] fileExistsAtPath:[absolutePath stringByDeletingLastPathComponent] isDirectory:&isDirectory] || !isDirectory) { if (![[NSFileManager defaultManager] fileExistsAtPath:[absolutePath stringByDeletingLastPathComponent] isDirectory:&isDirectory] || !isDirectory) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Conflict message:@"Missing intermediate collection(s) for \"%@\"", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Conflict message:@"Missing intermediate collection(s) for \"%@\"", relativePath];
@ -265,9 +257,9 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) {
} }
NSString* relativePath = request.path; NSString* relativePath = request.path;
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
} }
@ -299,10 +291,7 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) {
} }
NSString* relativePath = request.path; NSString* relativePath = request.path;
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
if (![self _checkSandboxedPath:absolutePath]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
}
BOOL isDirectory; BOOL isDirectory;
if (![[NSFileManager defaultManager] fileExistsAtPath:[absolutePath stringByDeletingLastPathComponent] isDirectory:&isDirectory] || !isDirectory) { if (![[NSFileManager defaultManager] fileExistsAtPath:[absolutePath stringByDeletingLastPathComponent] isDirectory:&isDirectory] || !isDirectory) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Conflict message:@"Missing intermediate collection(s) for \"%@\"", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Conflict message:@"Missing intermediate collection(s) for \"%@\"", relativePath];
@ -348,10 +337,7 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) {
} }
NSString* srcRelativePath = request.path; NSString* srcRelativePath = request.path;
NSString* srcAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:srcRelativePath]; NSString* srcAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(srcRelativePath)];
if (![self _checkSandboxedPath:srcAbsolutePath]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", srcRelativePath];
}
NSString* dstRelativePath = [request.headers objectForKey:@"Destination"]; NSString* dstRelativePath = [request.headers objectForKey:@"Destination"];
NSRange range = [dstRelativePath rangeOfString:(NSString*)[request.headers objectForKey:@"Host"]]; NSRange range = [dstRelativePath rangeOfString:(NSString*)[request.headers objectForKey:@"Host"]];
@ -362,8 +348,8 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) {
#pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdeprecated-declarations"
dstRelativePath = [[dstRelativePath substringFromIndex:(range.location + range.length)] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; dstRelativePath = [[dstRelativePath substringFromIndex:(range.location + range.length)] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
#pragma clang diagnostic pop #pragma clang diagnostic pop
NSString* dstAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:dstRelativePath]; NSString* dstAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(dstRelativePath)];
if (![self _checkSandboxedPath:dstAbsolutePath]) { if (!dstAbsolutePath) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", srcRelativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", srcRelativePath];
} }
@ -532,9 +518,9 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
} }
NSString* relativePath = request.path; NSString* relativePath = request.path;
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
} }
@ -582,9 +568,9 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
} }
NSString* relativePath = request.path; NSString* relativePath = request.path;
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
} }
@ -679,9 +665,9 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
} }
NSString* relativePath = request.path; NSString* relativePath = request.path;
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
} }

View File

@ -1026,7 +1026,7 @@ static inline NSString* _EncodeBase64(NSString* string) {
} }
processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) { processBlock:^GCDWebServerResponse*(GCDWebServerRequest* request) {
GCDWebServerResponse* response = nil; GCDWebServerResponse* response = nil;
NSString* filePath = [directoryPath stringByAppendingPathComponent:[request.path substringFromIndex:basePath.length]]; NSString* filePath = [directoryPath stringByAppendingPathComponent:GCDWebServerNormalizePath([request.path substringFromIndex:basePath.length])];
NSString* fileType = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL] fileType]; NSString* fileType = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL] fileType];
if (fileType) { if (fileType) {
if ([fileType isEqualToString:NSFileTypeDirectory]) { if ([fileType isEqualToString:NSFileTypeDirectory]) {

View File

@ -37,6 +37,7 @@
#endif #endif
#import "GCDWebUploader.h" #import "GCDWebUploader.h"
#import "GCDWebServerFunctions.h"
#import "GCDWebServerDataRequest.h" #import "GCDWebServerDataRequest.h"
#import "GCDWebServerMultiPartFormRequest.h" #import "GCDWebServerMultiPartFormRequest.h"
@ -73,7 +74,7 @@ NS_ASSUME_NONNULL_END
if (siteBundle == nil) { if (siteBundle == nil) {
return nil; return nil;
} }
_uploadDirectory = [[path stringByStandardizingPath] copy]; _uploadDirectory = [path copy];
GCDWebUploader* __unsafe_unretained server = self; GCDWebUploader* __unsafe_unretained server = self;
// Resource files // Resource files
@ -192,11 +193,6 @@ NS_ASSUME_NONNULL_END
@implementation GCDWebUploader (Methods) @implementation GCDWebUploader (Methods)
// Must match implementation in GCDWebDAVServer
- (BOOL)_checkSandboxedPath:(NSString*)path {
return [[path stringByStandardizingPath] hasPrefix:_uploadDirectory];
}
- (BOOL)_checkFileExtension:(NSString*)fileName { - (BOOL)_checkFileExtension:(NSString*)fileName {
if (_allowedFileExtensions && ![_allowedFileExtensions containsObject:[[fileName pathExtension] lowercaseString]]) { if (_allowedFileExtensions && ![_allowedFileExtensions containsObject:[[fileName pathExtension] lowercaseString]]) {
return NO; return NO;
@ -224,9 +220,9 @@ NS_ASSUME_NONNULL_END
- (GCDWebServerResponse*)listDirectory:(GCDWebServerRequest*)request { - (GCDWebServerResponse*)listDirectory:(GCDWebServerRequest*)request {
NSString* relativePath = [[request query] objectForKey:@"path"]; NSString* relativePath = [[request query] objectForKey:@"path"];
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { if (!absolutePath || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
} }
if (!isDirectory) { if (!isDirectory) {
@ -268,9 +264,9 @@ NS_ASSUME_NONNULL_END
- (GCDWebServerResponse*)downloadFile:(GCDWebServerRequest*)request { - (GCDWebServerResponse*)downloadFile:(GCDWebServerRequest*)request {
NSString* relativePath = [[request query] objectForKey:@"path"]; NSString* relativePath = [[request query] objectForKey:@"path"];
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
} }
if (isDirectory) { if (isDirectory) {
@ -299,10 +295,7 @@ NS_ASSUME_NONNULL_END
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploaded file name \"%@\" is not allowed", file.fileName]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploaded file name \"%@\" is not allowed", file.fileName];
} }
NSString* relativePath = [[request firstArgumentForControlName:@"path"] string]; NSString* relativePath = [[request firstArgumentForControlName:@"path"] string];
NSString* absolutePath = [self _uniquePathForPath:[[_uploadDirectory stringByAppendingPathComponent:relativePath] stringByAppendingPathComponent:file.fileName]]; NSString* absolutePath = [self _uniquePathForPath:[[_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)] stringByAppendingPathComponent:file.fileName]];
if (![self _checkSandboxedPath:absolutePath]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
}
if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) { if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploading file \"%@\" to \"%@\" is not permitted", file.fileName, relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploading file \"%@\" to \"%@\" is not permitted", file.fileName, relativePath];
@ -323,17 +316,14 @@ NS_ASSUME_NONNULL_END
- (GCDWebServerResponse*)moveItem:(GCDWebServerURLEncodedFormRequest*)request { - (GCDWebServerResponse*)moveItem:(GCDWebServerURLEncodedFormRequest*)request {
NSString* oldRelativePath = [request.arguments objectForKey:@"oldPath"]; NSString* oldRelativePath = [request.arguments objectForKey:@"oldPath"];
NSString* oldAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:oldRelativePath]; NSString* oldAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(oldRelativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:oldAbsolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:oldAbsolutePath isDirectory:&isDirectory]) { if (![[NSFileManager defaultManager] fileExistsAtPath:oldAbsolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", oldRelativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", oldRelativePath];
} }
NSString* newRelativePath = [request.arguments objectForKey:@"newPath"]; NSString* newRelativePath = [request.arguments objectForKey:@"newPath"];
NSString* newAbsolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:newRelativePath]]; NSString* newAbsolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(newRelativePath)]];
if (![self _checkSandboxedPath:newAbsolutePath]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", newRelativePath];
}
NSString* itemName = [newAbsolutePath lastPathComponent]; NSString* itemName = [newAbsolutePath lastPathComponent];
if ((!_allowHiddenItems && [itemName hasPrefix:@"."]) || (!isDirectory && ![self _checkFileExtension:itemName])) { if ((!_allowHiddenItems && [itemName hasPrefix:@"."]) || (!isDirectory && ![self _checkFileExtension:itemName])) {
@ -359,9 +349,9 @@ NS_ASSUME_NONNULL_END
- (GCDWebServerResponse*)deleteItem:(GCDWebServerURLEncodedFormRequest*)request { - (GCDWebServerResponse*)deleteItem:(GCDWebServerURLEncodedFormRequest*)request {
NSString* relativePath = [request.arguments objectForKey:@"path"]; NSString* relativePath = [request.arguments objectForKey:@"path"];
NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath]; NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)];
BOOL isDirectory = NO; BOOL isDirectory = NO;
if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) { if (![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath]; return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
} }
@ -389,10 +379,7 @@ NS_ASSUME_NONNULL_END
- (GCDWebServerResponse*)createDirectory:(GCDWebServerURLEncodedFormRequest*)request { - (GCDWebServerResponse*)createDirectory:(GCDWebServerURLEncodedFormRequest*)request {
NSString* relativePath = [request.arguments objectForKey:@"path"]; NSString* relativePath = [request.arguments objectForKey:@"path"];
NSString* absolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:relativePath]]; NSString* absolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:GCDWebServerNormalizePath(relativePath)]];
if (![self _checkSandboxedPath:absolutePath]) {
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
}
NSString* directoryName = [absolutePath lastPathComponent]; NSString* directoryName = [absolutePath lastPathComponent];
if (!_allowHiddenItems && [directoryName hasPrefix:@"."]) { if (!_allowHiddenItems && [directoryName hasPrefix:@"."]) {