]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/SecFileLocations.c
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / utilities / SecFileLocations.c
1 /*
2 * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // SecFileLocations.c
26 // utilities
27 //
28
29 /*
30 This file incorporates code from securityd_files.c (iOS) and iOSforOSX.c (OSX).
31 */
32
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>
41 #include <sys/stat.h>
42 #include <sys/param.h>
43 #include <sys/errno.h>
44 #include <uuid/uuid.h>
45 #include <copyfile.h>
46 #include <syslog.h>
47
48 #include "SecFileLocations.h"
49
50 static CFURLRef sCustomHomeURL = NULL;
51
52 CFURLRef SecCopyHomeURL(void)
53 {
54 // This returns a CFURLRef so that it can be passed as the second parameter
55 // to CFURLCreateCopyAppendingPathComponent
56
57 CFURLRef homeURL = sCustomHomeURL;
58 if (homeURL) {
59 CFRetain(homeURL);
60 } else {
61 homeURL = CFCopyHomeDirectoryURL();
62 }
63
64 return homeURL;
65 }
66
67 #if TARGET_OS_OSX
68 static const char * get_host_uuid()
69 {
70 static uuid_string_t hostuuid = {};
71 static dispatch_once_t onceToken;
72 dispatch_once(&onceToken, ^{
73 struct timespec timeout = {30, 0};
74 uuid_t uuid = {};
75 if (gethostuuid(uuid, &timeout) == 0) {
76 uuid_unparse(uuid, hostuuid);
77 } else {
78 secerror("failed to get host uuid");
79 }
80 });
81
82 return hostuuid;
83 }
84
85 static CFStringRef copy_keychain_uuid_path(CFURLRef keyChainBaseURL)
86 {
87 CFStringRef baseURLString = NULL;
88 CFStringRef uuid_path = NULL;
89
90 require(keyChainBaseURL, done);
91
92 baseURLString = CFURLCopyFileSystemPath(keyChainBaseURL, kCFURLPOSIXPathStyle);
93 require(baseURLString, done);
94
95 uuid_path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%s"), baseURLString, get_host_uuid());
96
97 done:
98 CFReleaseSafe(baseURLString);
99 return uuid_path;
100 }
101
102 // See _kb_verify_create_path in securityd
103 static bool keychain_verify_create_path(const char *keychainBasePath)
104 {
105 bool created = false;
106 struct stat st_info = {};
107 char new_path[PATH_MAX] = {};
108 char kb_path[PATH_MAX] = {};
109 snprintf(kb_path, sizeof(kb_path), "%s", keychainBasePath);
110 if (lstat(kb_path, &st_info) == 0) {
111 if (S_ISDIR(st_info.st_mode)) {
112 created = true;
113 } else {
114 secerror("invalid directory at '%s' moving aside", kb_path);
115 snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path);
116 unlink(new_path);
117 if (rename(kb_path, new_path) != 0) {
118 secerror("failed to rename file: %s (%s)", kb_path, strerror(errno));
119 goto done;
120 }
121 }
122 }
123 if (!created) {
124 errno_t err = mkpath_np(kb_path, 0700);
125 require_action(err == 0 || err == EEXIST, done, secerror("could not create path: %s (%s)", kb_path, strerror(err)));
126 created = true;
127 }
128
129 done:
130 return created;
131 }
132 #endif /* TARGET_OS_OSX */
133
134 static CFURLRef SecCopyBaseFilesURL(bool system)
135 {
136 CFURLRef baseURL = sCustomHomeURL;
137 if (baseURL) {
138 CFRetain(baseURL);
139 } else {
140 #if TARGET_OS_OSX
141 if (system) {
142 baseURL = CFURLCreateWithFileSystemPath(NULL, CFSTR("/"), kCFURLPOSIXPathStyle, true);
143 } else {
144 baseURL = SecCopyHomeURL();
145 }
146 #elif TARGET_OS_SIMULATOR
147 baseURL = SecCopyHomeURL();
148 #else
149 baseURL = CFURLCreateWithFileSystemPath(NULL, CFSTR("/"), kCFURLPOSIXPathStyle, true);
150 #endif
151 }
152 return baseURL;
153 }
154
155 static CFURLRef SecCopyURLForFileInBaseDirectory(bool system, CFStringRef directoryPath, CFStringRef fileName)
156 {
157 CFURLRef fileURL = NULL;
158 CFStringRef suffix = NULL;
159 CFURLRef homeURL = SecCopyBaseFilesURL(system);
160
161 if (fileName)
162 suffix = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%@"), directoryPath, fileName);
163 else
164 if (directoryPath)
165 suffix = CFStringCreateCopy(kCFAllocatorDefault, directoryPath);
166
167 if (homeURL && suffix)
168 fileURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, homeURL, suffix, false);
169 CFReleaseSafe(suffix);
170 CFReleaseSafe(homeURL);
171 return fileURL;
172 }
173
174 CFURLRef SecCopyURLForFileInKeychainDirectory(CFStringRef fileName)
175 {
176 #if TARGET_OS_OSX
177 // need to tack on uuid here
178 Boolean isDirectory = (fileName == NULL);
179 CFURLRef resultURL = NULL;
180 CFStringRef resultStr = NULL;
181 __block bool directoryExists = false;
182
183 CFURLRef keyChainBaseURL = SecCopyURLForFileInBaseDirectory(false, CFSTR("Library/Keychains"), NULL);
184 CFStringRef uuid_path = copy_keychain_uuid_path(keyChainBaseURL);
185 CFStringPerformWithCString(uuid_path, ^(const char *utf8Str) {
186 directoryExists = keychain_verify_create_path(utf8Str);
187 });
188 require(directoryExists, done);
189 if (fileName)
190 resultStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%@"), uuid_path, fileName);
191 else
192 resultStr = CFStringCreateCopy(kCFAllocatorDefault, uuid_path);
193
194 done:
195 CFReleaseSafe(uuid_path);
196 CFReleaseSafe(keyChainBaseURL);
197 if (resultStr)
198 {
199 resultURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, resultStr, kCFURLPOSIXPathStyle, isDirectory);
200 CFRelease(resultStr);
201 }
202 return resultURL;
203 #else /* !TARGET_OS_OSX */
204 return SecCopyURLForFileInBaseDirectory(true, CFSTR("Library/Keychains"), fileName);
205 #endif
206 }
207
208 CFURLRef SecCopyURLForFileInSystemKeychainDirectory(CFStringRef fileName) {
209 return SecCopyURLForFileInBaseDirectory(true, CFSTR("Library/Keychains"), fileName);
210 }
211
212 CFURLRef SecCopyURLForFileInUserCacheDirectory(CFStringRef fileName)
213 {
214 #if TARGET_OS_OSX
215 Boolean isDirectory = (fileName == NULL);
216 CFURLRef resultURL = NULL;
217 CFStringRef cacheDirStr = NULL;
218 char strBuffer[PATH_MAX + 1];
219 size_t result = confstr(_CS_DARWIN_USER_CACHE_DIR, strBuffer, sizeof(strBuffer));
220 if (result == 0) {
221 syslog(LOG_CRIT, "SecCopyURLForFileInUserCacheDirectory: confstr on _CS_DARWIN_USER_CACHE_DIR failed: %d", errno);
222 return resultURL;
223 }
224 cacheDirStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s/%@"), strBuffer, fileName);
225 if (cacheDirStr) {
226 resultURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cacheDirStr, kCFURLPOSIXPathStyle, isDirectory);
227 }
228 CFReleaseSafe(cacheDirStr);
229 return resultURL;
230 #else
231 return SecCopyURLForFileInBaseDirectory(true, CFSTR("Library/Caches"), fileName);
232 #endif
233 }
234
235 CFURLRef SecCopyURLForFileInPreferencesDirectory(CFStringRef fileName)
236 {
237 return SecCopyURLForFileInBaseDirectory(false, CFSTR("Library/Preferences"), fileName);
238 }
239
240 CFURLRef SecCopyURLForFileInManagedPreferencesDirectory(CFStringRef fileName)
241 {
242 CFURLRef resultURL = NULL;
243
244 CFStringRef userName;
245 #if TARGET_OS_OSX
246 userName = CFCopyUserName();
247 #else
248 userName = CFStringCreateWithCString(kCFAllocatorDefault, "mobile", kCFStringEncodingASCII);
249 #endif
250
251 if (userName) {
252 CFStringRef path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/Library/Managed Preferences/%@/%@"), userName, fileName);
253 if (path) {
254 resultURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false);
255 CFReleaseSafe(path);
256 }
257 CFReleaseSafe(userName);
258 }
259
260 return resultURL;
261 }
262
263 CFURLRef SecCopyURLForFileInRevocationInfoDirectory(CFStringRef fileName)
264 {
265 #if TARGET_OS_OSX
266 return SecCopyURLForFileInBaseDirectory(true, CFSTR("private/var/protected/trustd/"), fileName);
267 #else
268 return SecCopyURLForFileInBaseDirectory(true, CFSTR("Library/Keychains/crls/"), fileName);
269 #endif
270 }
271
272 CFURLRef SecCopyURLForFileInProtectedDirectory(CFStringRef fileName)
273 {
274 return SecCopyURLForFileInBaseDirectory(true, CFSTR("private/var/protected/"), fileName);
275 }
276
277 static void WithPathInDirectory(CFURLRef fileURL, void(^operation)(const char *utf8String))
278 {
279 /* Ownership of fileURL is taken by this function and so we release it. */
280 if (fileURL) {
281 UInt8 buffer[PATH_MAX];
282 CFURLGetFileSystemRepresentation(fileURL, false, buffer, sizeof(buffer));
283
284 operation((const char*)buffer);
285 CFRelease(fileURL);
286 }
287 }
288
289 void WithPathInRevocationInfoDirectory(CFStringRef fileName, void(^operation)(const char *utf8String))
290 {
291 WithPathInDirectory(SecCopyURLForFileInRevocationInfoDirectory(fileName), operation);
292 }
293
294 void WithPathInKeychainDirectory(CFStringRef fileName, void(^operation)(const char *utf8String))
295 {
296 WithPathInDirectory(SecCopyURLForFileInKeychainDirectory(fileName), operation);
297 }
298
299 void WithPathInUserCacheDirectory(CFStringRef fileName, void(^operation)(const char *utf8String))
300 {
301 WithPathInDirectory(SecCopyURLForFileInUserCacheDirectory(fileName), operation);
302 }
303
304 void WithPathInProtectedDirectory(CFStringRef fileName, void(^operation)(const char *utf8String))
305 {
306 WithPathInDirectory(SecCopyURLForFileInProtectedDirectory(fileName), operation);
307 }
308
309 void SetCustomHomeURL(CFURLRef url)
310 {
311 sCustomHomeURL = CFRetainSafe(url);
312 }
313
314
315 void SetCustomHomeURLString(CFStringRef home_path)
316 {
317 CFReleaseNull(sCustomHomeURL);
318 if (home_path) {
319 sCustomHomeURL = CFURLCreateWithFileSystemPath(NULL, home_path, kCFURLPOSIXPathStyle, true);
320 }
321 }
322
323 void SetCustomHomePath(const char* path)
324 {
325 if (path) {
326 CFStringRef path_cf = CFStringCreateWithCStringNoCopy(NULL, path, kCFStringEncodingUTF8, kCFAllocatorNull);
327 SetCustomHomeURLString(path_cf);
328 CFReleaseSafe(path_cf);
329 } else {
330 SetCustomHomeURLString(NULL);
331 }
332 }
333
334