2 * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
30 This file incorporates code from securityd_files.c (iOS) and iOSforOSX.c (OSX).
33 #include <TargetConditionals.h>
34 #include <AssertMacros.h>
35 #include <CoreFoundation/CFPriv.h>
36 #include <CoreFoundation/CFString.h>
37 #include <CoreFoundation/CFURL.h>
38 #include <CoreFoundation/CFUtilities.h>
39 #include <utilities/SecCFWrappers.h>
40 #include <utilities/SecCFRelease.h>
42 #include <sys/param.h>
43 #include <sys/errno.h>
44 #include <uuid/uuid.h>
48 #include "SecFileLocations.h"
50 static CFURLRef sCustomHomeURL
= NULL
;
52 CFURLRef
SecCopyHomeURL(void)
54 // This returns a CFURLRef so that it can be passed as the second parameter
55 // to CFURLCreateCopyAppendingPathComponent
57 CFURLRef homeURL
= sCustomHomeURL
;
61 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
62 // We would use CFCopyHomeDirectoryURL but it doesn't exist on MACOS.
63 // This does the same.
64 homeURL
= CFCopyHomeDirectoryURLForUser(NULL
);
66 homeURL
= CFCopyHomeDirectoryURL();
73 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
74 static const char * get_host_uuid()
76 static uuid_string_t hostuuid
= {};
77 static dispatch_once_t onceToken
;
78 dispatch_once(&onceToken
, ^{
79 struct timespec timeout
= {30, 0};
81 if (gethostuuid(uuid
, &timeout
) == 0) {
82 uuid_unparse(uuid
, hostuuid
);
84 secerror("failed to get host uuid");
91 static CFStringRef
copy_keychain_uuid_path(CFURLRef keyChainBaseURL
)
93 CFStringRef baseURLString
= NULL
;
94 CFStringRef uuid_path
= NULL
;
96 require(keyChainBaseURL
, done
);
98 baseURLString
= CFURLCopyFileSystemPath(keyChainBaseURL
, kCFURLPOSIXPathStyle
);
99 require(baseURLString
, done
);
101 uuid_path
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%s"), baseURLString
, get_host_uuid());
104 CFReleaseSafe(baseURLString
);
108 // See _kb_verify_create_path in securityd
109 static bool keychain_verify_create_path(const char *keychainBasePath
)
111 bool created
= false;
112 struct stat st_info
= {};
113 char new_path
[PATH_MAX
] = {};
114 char kb_path
[PATH_MAX
] = {};
115 snprintf(kb_path
, sizeof(kb_path
), "%s", keychainBasePath
);
116 if (lstat(kb_path
, &st_info
) == 0) {
117 if (S_ISDIR(st_info
.st_mode
)) {
120 secerror("invalid directory at '%s' moving aside", kb_path
);
121 snprintf(new_path
, sizeof(new_path
), "%s-invalid", kb_path
);
123 if (rename(kb_path
, new_path
) != 0) {
124 secerror("failed to rename file: %s (%s)", kb_path
, strerror(errno
));
130 require_action(mkpath_np(kb_path
, 0700) == 0, done
, secerror("could not create path: %s (%s)", kb_path
, strerror(errno
)));
137 #endif /*(TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
139 static CFURLRef
SecCopyBaseFilesURL()
141 CFURLRef baseURL
= sCustomHomeURL
;
145 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED))
146 baseURL
= SecCopyHomeURL();
148 baseURL
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/"), kCFURLPOSIXPathStyle
, true);
154 static CFURLRef
SecCopyURLForFileInBaseDirectory(CFStringRef directoryPath
, CFStringRef fileName
)
156 CFURLRef fileURL
= NULL
;
157 CFStringRef suffix
= NULL
;
158 CFURLRef homeURL
= SecCopyBaseFilesURL();
161 suffix
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%@"), directoryPath
, fileName
);
164 suffix
= CFStringCreateCopy(kCFAllocatorDefault
, directoryPath
);
166 if (homeURL
&& suffix
)
167 fileURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault
, homeURL
, suffix
, false);
168 CFReleaseSafe(suffix
);
169 CFReleaseSafe(homeURL
);
173 CFURLRef
SecCopyURLForFileInKeychainDirectory(CFStringRef fileName
)
175 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
176 // need to tack on uuid here
177 Boolean isDirectory
= (fileName
== NULL
);
178 CFURLRef resultURL
= NULL
;
179 CFStringRef resultStr
= NULL
;
180 __block
bool directoryExists
= false;
182 CFURLRef keyChainBaseURL
= SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), NULL
);
183 CFStringRef uuid_path
= copy_keychain_uuid_path(keyChainBaseURL
);
184 CFStringPerformWithCString(uuid_path
, ^(const char *utf8Str
) {
185 directoryExists
= keychain_verify_create_path(utf8Str
);
187 require(directoryExists
, done
);
189 resultStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%@"), uuid_path
, fileName
);
191 resultStr
= CFStringCreateCopy(kCFAllocatorDefault
, uuid_path
);
194 CFReleaseSafe(uuid_path
);
195 CFReleaseSafe(keyChainBaseURL
);
198 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, resultStr
, kCFURLPOSIXPathStyle
, isDirectory
);
199 CFRelease(resultStr
);
203 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), fileName
);
207 CFURLRef
SecCopyURLForFileInUserCacheDirectory(CFStringRef fileName
)
210 Boolean isDirectory
= (fileName
== NULL
);
211 CFURLRef resultURL
= NULL
;
212 CFStringRef cacheDirStr
= NULL
;
213 char strBuffer
[PATH_MAX
+ 1];
214 size_t result
= confstr(_CS_DARWIN_USER_CACHE_DIR
, strBuffer
, sizeof(strBuffer
));
216 syslog(LOG_CRIT
, "SecCopyURLForFileInUserCacheDirectory: confstr on _CS_DARWIN_USER_CACHE_DIR failed: %d", errno
);
219 cacheDirStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s/%@"), strBuffer
, fileName
);
221 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, cacheDirStr
, kCFURLPOSIXPathStyle
, isDirectory
);
223 CFReleaseSafe(cacheDirStr
);
226 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Caches"), fileName
);
230 CFURLRef
SecCopyURLForFileInPreferencesDirectory(CFStringRef fileName
)
232 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Preferences"), fileName
);
235 CFURLRef
SecCopyURLForFileInManagedPreferencesDirectory(CFStringRef fileName
)
237 CFURLRef resultURL
= NULL
;
239 CFStringRef userName
;
240 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
241 userName
= CFCopyUserName();
243 userName
= CFStringCreateWithCString(kCFAllocatorDefault
, "mobile", kCFStringEncodingASCII
);
247 CFStringRef path
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("/Library/Managed Preferences/%@/%@"), userName
, fileName
);
249 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path
, kCFURLPOSIXPathStyle
, false);
252 CFReleaseSafe(userName
);
258 CFURLRef
SecCopyURLForFileInRevocationInfoDirectory(CFStringRef fileName
)
260 CFURLRef resultURL
= NULL
;
261 CFStringRef path
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("/Library/Keychains/crls/%@"), fileName
);
263 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path
, kCFURLPOSIXPathStyle
, false);
269 static void WithPathInDirectory(CFURLRef fileURL
, void(^operation
)(const char *utf8String
))
271 /* Ownership of fileURL is taken by this function and so we release it. */
273 UInt8 buffer
[PATH_MAX
];
274 CFURLGetFileSystemRepresentation(fileURL
, false, buffer
, sizeof(buffer
));
276 operation((const char*)buffer
);
281 void WithPathInRevocationInfoDirectory(CFStringRef fileName
, void(^operation
)(const char *utf8String
))
283 WithPathInDirectory(SecCopyURLForFileInRevocationInfoDirectory(fileName
), operation
);
286 void WithPathInKeychainDirectory(CFStringRef fileName
, void(^operation
)(const char *utf8String
))
288 WithPathInDirectory(SecCopyURLForFileInKeychainDirectory(fileName
), operation
);
291 void WithPathInUserCacheDirectory(CFStringRef fileName
, void(^operation
)(const char *utf8String
))
293 WithPathInDirectory(SecCopyURLForFileInUserCacheDirectory(fileName
), operation
);
296 void SetCustomHomeURL(CFURLRef url
)
298 sCustomHomeURL
= CFRetainSafe(url
);
302 void SetCustomHomeURLString(CFStringRef home_path
)
304 CFReleaseNull(sCustomHomeURL
);
306 sCustomHomeURL
= CFURLCreateWithFileSystemPath(NULL
, home_path
, kCFURLPOSIXPathStyle
, true);
310 void SetCustomHomePath(const char* path
)
313 CFStringRef path_cf
= CFStringCreateWithCStringNoCopy(NULL
, path
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
314 SetCustomHomeURLString(path_cf
);
315 CFReleaseSafe(path_cf
);
317 SetCustomHomeURLString(NULL
);