]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/src/SecFileLocations.c
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / utilities / src / 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 <uuid/uuid.h>
43 #include <copyfile.h>
44 #include <syslog.h>
45
46 #include "SecFileLocations.h"
47
48 static CFURLRef sCustomHomeURL = NULL;
49
50 static CFURLRef SecCopyHomeURL(void)
51 {
52 // This returns a CFURLRef so that it can be passed as the second parameter
53 // to CFURLCreateCopyAppendingPathComponent
54
55 CFURLRef homeURL = sCustomHomeURL;
56 if (homeURL) {
57 CFRetain(homeURL);
58 } else {
59 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
60 // We would use CFCopyHomeDirectoryURL but it doesn't exist on MACOS.
61 // This does the same.
62 homeURL = CFCopyHomeDirectoryURLForUser(NULL);
63 #else
64 homeURL = CFCopyHomeDirectoryURL();
65 #endif
66 }
67
68 return homeURL;
69 }
70
71 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
72 static const char * get_host_uuid()
73 {
74 static uuid_string_t hostuuid = {};
75 static dispatch_once_t onceToken;
76 dispatch_once(&onceToken, ^{
77 struct timespec timeout = {30, 0};
78 uuid_t uuid = {};
79 if (gethostuuid(uuid, &timeout) == 0) {
80 uuid_unparse(uuid, hostuuid);
81 } else {
82 secerror("failed to get host uuid");
83 }
84 });
85
86 return hostuuid;
87 }
88
89 static CFStringRef copy_keychain_uuid_path(CFURLRef keyChainBaseURL)
90 {
91 CFStringRef baseURLString = NULL;
92 CFStringRef uuid_path = NULL;
93
94 require(keyChainBaseURL, done);
95
96 baseURLString = CFURLCopyFileSystemPath(keyChainBaseURL, kCFURLPOSIXPathStyle);
97 require(baseURLString, done);
98
99 uuid_path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%s"), baseURLString, get_host_uuid());
100
101 done:
102 CFReleaseSafe(baseURLString);
103 return uuid_path;
104 }
105
106 // See _kb_verify_create_path in securityd
107 static bool keychain_verify_create_path(const char *keychainBasePath)
108 {
109 bool created = false;
110 struct stat st_info = {};
111 char new_path[PATH_MAX] = {};
112 char kb_path[PATH_MAX] = {};
113 snprintf(kb_path, sizeof(kb_path), "%s", keychainBasePath);
114 if (lstat(kb_path, &st_info) == 0) {
115 if (S_ISDIR(st_info.st_mode)) {
116 created = true;
117 } else {
118 secerror("invalid directory at '%s' moving aside", kb_path);
119 snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path);
120 unlink(new_path);
121 if (rename(kb_path, new_path) != 0) {
122 secerror("failed to rename file: %s (%s)", kb_path, strerror(errno));
123 goto done;
124 }
125 }
126 }
127 if (!created) {
128 require_action(mkpath_np(kb_path, 0700) == 0, done, secerror("could not create path: %s (%s)", kb_path, strerror(errno)));
129 created = true;
130 }
131
132 done:
133 return created;
134 }
135 #endif /*(TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
136
137 static CFURLRef SecCopyBaseFilesURL()
138 {
139 CFURLRef baseURL = sCustomHomeURL;
140 if (baseURL) {
141 CFRetain(baseURL);
142 } else {
143 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED))
144 baseURL = SecCopyHomeURL();
145 #else
146 baseURL = CFURLCreateWithFileSystemPath(NULL, CFSTR("/"), kCFURLPOSIXPathStyle, true);
147 #endif
148 }
149 return baseURL;
150 }
151
152 static CFURLRef SecCopyURLForFileInBaseDirectory(CFStringRef directoryPath, CFStringRef fileName)
153 {
154 CFURLRef fileURL = NULL;
155 CFStringRef suffix = NULL;
156 CFURLRef homeURL = SecCopyBaseFilesURL();
157
158 if (fileName)
159 suffix = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%@"), directoryPath, fileName);
160 else
161 if (directoryPath)
162 suffix = CFStringCreateCopy(kCFAllocatorDefault, directoryPath);
163
164 if (homeURL && suffix)
165 fileURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, homeURL, suffix, false);
166 CFReleaseSafe(suffix);
167 CFReleaseSafe(homeURL);
168 return fileURL;
169 }
170
171 CFURLRef SecCopyURLForFileInKeychainDirectory(CFStringRef fileName)
172 {
173 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
174 // need to tack on uuid here
175 Boolean isDirectory = (fileName == NULL);
176 CFURLRef resultURL = NULL;
177 CFStringRef resultStr = NULL;
178 __block bool directoryExists = false;
179
180 CFURLRef keyChainBaseURL = SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), NULL);
181 CFStringRef uuid_path = copy_keychain_uuid_path(keyChainBaseURL);
182 CFStringPerformWithCString(uuid_path, ^(const char *utf8Str) {
183 directoryExists = keychain_verify_create_path(utf8Str);
184 });
185 require(directoryExists, done);
186 if (fileName)
187 resultStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%@"), uuid_path, fileName);
188 else
189 resultStr = CFStringCreateCopy(kCFAllocatorDefault, uuid_path);
190
191 done:
192 CFReleaseSafe(uuid_path);
193 CFReleaseSafe(keyChainBaseURL);
194 if (resultStr)
195 {
196 resultURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, resultStr, kCFURLPOSIXPathStyle, isDirectory);
197 CFRelease(resultStr);
198 }
199 return resultURL;
200 #else
201 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), fileName);
202 #endif
203 }
204
205 CFURLRef SecCopyURLForFileInUserCacheDirectory(CFStringRef fileName)
206 {
207 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
208 Boolean isDirectory = (fileName == NULL);
209 CFURLRef resultURL = NULL;
210 CFStringRef cacheDirStr = NULL;
211 char strBuffer[PATH_MAX + 1];
212 size_t result = confstr(_CS_DARWIN_USER_CACHE_DIR, strBuffer, sizeof(strBuffer));
213 if (result == 0) {
214 syslog(LOG_CRIT, "SecOCSPCacheCopyPath: confstr on _CS_DARWIN_USER_CACHE_DIR failed");
215 return resultURL;
216 }
217 cacheDirStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s/%@"), strBuffer, fileName);
218 if (cacheDirStr) {
219 resultURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cacheDirStr, kCFURLPOSIXPathStyle, isDirectory);
220 }
221 CFReleaseSafe(cacheDirStr);
222 return resultURL;
223 #else
224 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Caches"), fileName);
225 #endif
226 }
227
228 CFURLRef SecCopyURLForFileInPreferencesDirectory(CFStringRef fileName)
229 {
230 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Preferences"), fileName);
231 }
232
233 CFURLRef SecCopyURLForFileInManagedPreferencesDirectory(CFStringRef fileName)
234 {
235 CFURLRef resultURL = NULL;
236
237 CFStringRef userName;
238 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
239 userName = CFCopyUserName();
240 #else
241 userName = CFStringCreateWithCString(kCFAllocatorDefault, "mobile", kCFStringEncodingASCII);
242 #endif
243
244 if (userName) {
245 CFStringRef path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/Library/Managed Preferences/%@/%@"), userName, fileName);
246 if (path) {
247 resultURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false);
248 CFReleaseSafe(path);
249 }
250 CFReleaseSafe(userName);
251 }
252
253 return resultURL;
254 }
255
256 void WithPathInKeychainDirectory(CFStringRef fileName, void(^operation)(const char *utf8String))
257 {
258 CFURLRef fileURL = SecCopyURLForFileInKeychainDirectory(fileName);
259 if (fileURL) {
260 UInt8 buffer[MAXPATHLEN];
261 CFURLGetFileSystemRepresentation(fileURL, false, buffer, sizeof(buffer));
262
263 operation((const char*)buffer);
264 CFRelease(fileURL);
265 }
266 }
267
268 void SetCustomHomeURLString(CFStringRef home_path)
269 {
270 CFReleaseNull(sCustomHomeURL);
271 if (home_path) {
272 sCustomHomeURL = CFURLCreateWithFileSystemPath(NULL, home_path, kCFURLPOSIXPathStyle, true);
273 }
274 }
275
276 void SetCustomHomeURL(const char* path)
277 {
278 if (path) {
279 CFStringRef path_cf = CFStringCreateWithCStringNoCopy(NULL, path, kCFStringEncodingUTF8, kCFAllocatorNull);
280 SetCustomHomeURLString(path_cf);
281 CFReleaseSafe(path_cf);
282 } else {
283 SetCustomHomeURLString(NULL);
284 }
285 }
286
287