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 <uuid/uuid.h>
46 #include "SecFileLocations.h"
48 static CFURLRef sCustomHomeURL
= NULL
;
50 static CFURLRef
SecCopyHomeURL(void)
52 // This returns a CFURLRef so that it can be passed as the second parameter
53 // to CFURLCreateCopyAppendingPathComponent
55 CFURLRef homeURL
= sCustomHomeURL
;
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
);
64 homeURL
= CFCopyHomeDirectoryURL();
71 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
72 static const char * get_host_uuid()
74 static uuid_string_t hostuuid
= {};
75 static dispatch_once_t onceToken
;
76 dispatch_once(&onceToken
, ^{
77 struct timespec timeout
= {30, 0};
79 if (gethostuuid(uuid
, &timeout
) == 0) {
80 uuid_unparse(uuid
, hostuuid
);
82 secerror("failed to get host uuid");
89 static CFStringRef
copy_keychain_uuid_path(CFURLRef keyChainBaseURL
)
91 CFStringRef baseURLString
= NULL
;
92 CFStringRef uuid_path
= NULL
;
94 require(keyChainBaseURL
, done
);
96 baseURLString
= CFURLCopyFileSystemPath(keyChainBaseURL
, kCFURLPOSIXPathStyle
);
97 require(baseURLString
, done
);
99 uuid_path
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%s"), baseURLString
, get_host_uuid());
102 CFReleaseSafe(baseURLString
);
106 // See _kb_verify_create_path in securityd
107 static bool keychain_verify_create_path(const char *keychainBasePath
)
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
)) {
118 secerror("invalid directory at '%s' moving aside", kb_path
);
119 snprintf(new_path
, sizeof(new_path
), "%s-invalid", kb_path
);
121 if (rename(kb_path
, new_path
) != 0) {
122 secerror("failed to rename file: %s (%s)", kb_path
, strerror(errno
));
128 require_action(mkpath_np(kb_path
, 0700) == 0, done
, secerror("could not create path: %s (%s)", kb_path
, strerror(errno
)));
135 #endif /*(TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
137 static CFURLRef
SecCopyBaseFilesURL()
139 CFURLRef baseURL
= sCustomHomeURL
;
143 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED))
144 baseURL
= SecCopyHomeURL();
146 baseURL
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/"), kCFURLPOSIXPathStyle
, true);
152 static CFURLRef
SecCopyURLForFileInBaseDirectory(CFStringRef directoryPath
, CFStringRef fileName
)
154 CFURLRef fileURL
= NULL
;
155 CFStringRef suffix
= NULL
;
156 CFURLRef homeURL
= SecCopyBaseFilesURL();
159 suffix
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%@"), directoryPath
, fileName
);
162 suffix
= CFStringCreateCopy(kCFAllocatorDefault
, directoryPath
);
164 if (homeURL
&& suffix
)
165 fileURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault
, homeURL
, suffix
, false);
166 CFReleaseSafe(suffix
);
167 CFReleaseSafe(homeURL
);
171 CFURLRef
SecCopyURLForFileInKeychainDirectory(CFStringRef fileName
)
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;
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
);
185 require(directoryExists
, done
);
187 resultStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%@"), uuid_path
, fileName
);
189 resultStr
= CFStringCreateCopy(kCFAllocatorDefault
, uuid_path
);
192 CFReleaseSafe(uuid_path
);
193 CFReleaseSafe(keyChainBaseURL
);
196 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, resultStr
, kCFURLPOSIXPathStyle
, isDirectory
);
197 CFRelease(resultStr
);
201 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), fileName
);
205 CFURLRef
SecCopyURLForFileInUserCacheDirectory(CFStringRef fileName
)
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
));
214 syslog(LOG_CRIT
, "SecOCSPCacheCopyPath: confstr on _CS_DARWIN_USER_CACHE_DIR failed");
217 cacheDirStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s/%@"), strBuffer
, fileName
);
219 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, cacheDirStr
, kCFURLPOSIXPathStyle
, isDirectory
);
221 CFReleaseSafe(cacheDirStr
);
224 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Caches"), fileName
);
228 CFURLRef
SecCopyURLForFileInPreferencesDirectory(CFStringRef fileName
)
230 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Preferences"), fileName
);
233 CFURLRef
SecCopyURLForFileInManagedPreferencesDirectory(CFStringRef fileName
)
235 CFURLRef resultURL
= NULL
;
237 CFStringRef userName
;
238 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
239 userName
= CFCopyUserName();
241 userName
= CFStringCreateWithCString(kCFAllocatorDefault
, "mobile", kCFStringEncodingASCII
);
245 CFStringRef path
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("/Library/Managed Preferences/%@/%@"), userName
, fileName
);
247 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path
, kCFURLPOSIXPathStyle
, false);
250 CFReleaseSafe(userName
);
256 void WithPathInKeychainDirectory(CFStringRef fileName
, void(^operation
)(const char *utf8String
))
258 CFURLRef fileURL
= SecCopyURLForFileInKeychainDirectory(fileName
);
260 UInt8 buffer
[MAXPATHLEN
];
261 CFURLGetFileSystemRepresentation(fileURL
, false, buffer
, sizeof(buffer
));
263 operation((const char*)buffer
);
268 void SetCustomHomeURLString(CFStringRef home_path
)
270 CFReleaseNull(sCustomHomeURL
);
272 sCustomHomeURL
= CFURLCreateWithFileSystemPath(NULL
, home_path
, kCFURLPOSIXPathStyle
, true);
276 void SetCustomHomeURL(const char* path
)
279 CFStringRef path_cf
= CFStringCreateWithCStringNoCopy(NULL
, path
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
280 SetCustomHomeURLString(path_cf
);
281 CFReleaseSafe(path_cf
);
283 SetCustomHomeURLString(NULL
);