X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/utilities/src/SecFileLocations.c diff --git a/Security/utilities/src/SecFileLocations.c b/Security/utilities/src/SecFileLocations.c new file mode 100644 index 00000000..349549b8 --- /dev/null +++ b/Security/utilities/src/SecFileLocations.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +// +// SecFileLocations.c +// utilities +// + +/* + This file incorporates code from securityd_files.c (iOS) and iOSforOSX.c (OSX). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SecFileLocations.h" + +static CFURLRef sCustomHomeURL = NULL; + +static CFURLRef SecCopyHomeURL(void) +{ + // This returns a CFURLRef so that it can be passed as the second parameter + // to CFURLCreateCopyAppendingPathComponent + + CFURLRef homeURL = sCustomHomeURL; + if (homeURL) { + CFRetain(homeURL); + } else { +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) + // We would use CFCopyHomeDirectoryURL but it doesn't exist on MACOS. + // This does the same. + homeURL = CFCopyHomeDirectoryURLForUser(NULL); +#else + homeURL = CFCopyHomeDirectoryURL(); +#endif + } + + return homeURL; +} + +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) +static const char * get_host_uuid() +{ + static uuid_string_t hostuuid = {}; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + struct timespec timeout = {30, 0}; + uuid_t uuid = {}; + if (gethostuuid(uuid, &timeout) == 0) { + uuid_unparse(uuid, hostuuid); + } else { + secerror("failed to get host uuid"); + } + }); + + return hostuuid; +} + +static CFStringRef copy_keychain_uuid_path(CFURLRef keyChainBaseURL) +{ + CFStringRef baseURLString = NULL; + CFStringRef uuid_path = NULL; + + require(keyChainBaseURL, done); + + baseURLString = CFURLCopyFileSystemPath(keyChainBaseURL, kCFURLPOSIXPathStyle); + require(baseURLString, done); + + uuid_path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%s"), baseURLString, get_host_uuid()); + +done: + CFReleaseSafe(baseURLString); + return uuid_path; +} + +// See _kb_verify_create_path in securityd +static bool keychain_verify_create_path(const char *keychainBasePath) +{ + bool created = false; + struct stat st_info = {}; + char new_path[PATH_MAX] = {}; + char kb_path[PATH_MAX] = {}; + snprintf(kb_path, sizeof(kb_path), "%s", keychainBasePath); + if (lstat(kb_path, &st_info) == 0) { + if (S_ISDIR(st_info.st_mode)) { + created = true; + } else { + secerror("invalid directory at '%s' moving aside", kb_path); + snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path); + unlink(new_path); + if (rename(kb_path, new_path) != 0) { + secerror("failed to rename file: %s (%s)", kb_path, strerror(errno)); + goto done; + } + } + } + if (!created) { + require_action(mkpath_np(kb_path, 0700) == 0, done, secerror("could not create path: %s (%s)", kb_path, strerror(errno))); + created = true; + } + +done: + return created; +} +#endif /*(TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ + +static CFURLRef SecCopyBaseFilesURL() +{ + CFURLRef baseURL = sCustomHomeURL; + if (baseURL) { + CFRetain(baseURL); + } else { +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED)) + baseURL = SecCopyHomeURL(); +#else + baseURL = CFURLCreateWithFileSystemPath(NULL, CFSTR("/"), kCFURLPOSIXPathStyle, true); +#endif + } + return baseURL; +} + +static CFURLRef SecCopyURLForFileInBaseDirectory(CFStringRef directoryPath, CFStringRef fileName) +{ + CFURLRef fileURL = NULL; + CFStringRef suffix = NULL; + CFURLRef homeURL = SecCopyBaseFilesURL(); + + if (fileName) + suffix = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%@"), directoryPath, fileName); + else + if (directoryPath) + suffix = CFStringCreateCopy(kCFAllocatorDefault, directoryPath); + + if (homeURL && suffix) + fileURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, homeURL, suffix, false); + CFReleaseSafe(suffix); + CFReleaseSafe(homeURL); + return fileURL; +} + +CFURLRef SecCopyURLForFileInKeychainDirectory(CFStringRef fileName) +{ +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) + // need to tack on uuid here + Boolean isDirectory = (fileName == NULL); + CFURLRef resultURL = NULL; + CFStringRef resultStr = NULL; + __block bool directoryExists = false; + + CFURLRef keyChainBaseURL = SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), NULL); + CFStringRef uuid_path = copy_keychain_uuid_path(keyChainBaseURL); + CFStringPerformWithCString(uuid_path, ^(const char *utf8Str) { + directoryExists = keychain_verify_create_path(utf8Str); + }); + require(directoryExists, done); + if (fileName) + resultStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%@"), uuid_path, fileName); + else + resultStr = CFStringCreateCopy(kCFAllocatorDefault, uuid_path); + +done: + CFReleaseSafe(uuid_path); + CFReleaseSafe(keyChainBaseURL); + if (resultStr) + { + resultURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, resultStr, kCFURLPOSIXPathStyle, isDirectory); + CFRelease(resultStr); + } + return resultURL; +#else + return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), fileName); +#endif +} + +CFURLRef SecCopyURLForFileInPreferencesDirectory(CFStringRef fileName) +{ + return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Preferences"), fileName); +} + +void WithPathInKeychainDirectory(CFStringRef fileName, void(^operation)(const char *utf8String)) +{ + CFURLRef fileURL = SecCopyURLForFileInKeychainDirectory(fileName); + UInt8 buffer[MAXPATHLEN]; + CFURLGetFileSystemRepresentation(fileURL, false, buffer, sizeof(buffer)); + + operation((const char*)buffer); + CFRelease(fileURL); +} + +void SetCustomHomeURLString(CFStringRef home_path) +{ + CFReleaseNull(sCustomHomeURL); + if (home_path) { + sCustomHomeURL = CFURLCreateWithFileSystemPath(NULL, home_path, kCFURLPOSIXPathStyle, true); + } +} + +void SetCustomHomeURL(const char* path) +{ + if (path) { + CFStringRef path_cf = CFStringCreateWithCStringNoCopy(NULL, path, kCFStringEncodingUTF8, kCFAllocatorNull); + SetCustomHomeURLString(path_cf); + CFReleaseSafe(path_cf); + } else { + SetCustomHomeURLString(NULL); + } +} + +