2 * Copyright (c) 2012-2014 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>
45 #include "SecFileLocations.h"
47 static CFURLRef sCustomHomeURL
= NULL
;
49 static CFURLRef
SecCopyHomeURL(void)
51 // This returns a CFURLRef so that it can be passed as the second parameter
52 // to CFURLCreateCopyAppendingPathComponent
54 CFURLRef homeURL
= sCustomHomeURL
;
58 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
59 // We would use CFCopyHomeDirectoryURL but it doesn't exist on MACOS.
60 // This does the same.
61 homeURL
= CFCopyHomeDirectoryURLForUser(NULL
);
63 homeURL
= CFCopyHomeDirectoryURL();
70 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
71 static const char * get_host_uuid()
73 static uuid_string_t hostuuid
= {};
74 static dispatch_once_t onceToken
;
75 dispatch_once(&onceToken
, ^{
76 struct timespec timeout
= {30, 0};
78 if (gethostuuid(uuid
, &timeout
) == 0) {
79 uuid_unparse(uuid
, hostuuid
);
81 secerror("failed to get host uuid");
88 static CFStringRef
copy_keychain_uuid_path(CFURLRef keyChainBaseURL
)
90 CFStringRef baseURLString
= NULL
;
91 CFStringRef uuid_path
= NULL
;
93 require(keyChainBaseURL
, done
);
95 baseURLString
= CFURLCopyFileSystemPath(keyChainBaseURL
, kCFURLPOSIXPathStyle
);
96 require(baseURLString
, done
);
98 uuid_path
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%s"), baseURLString
, get_host_uuid());
101 CFReleaseSafe(baseURLString
);
105 // See _kb_verify_create_path in securityd
106 static bool keychain_verify_create_path(const char *keychainBasePath
)
108 bool created
= false;
109 struct stat st_info
= {};
110 char new_path
[PATH_MAX
] = {};
111 char kb_path
[PATH_MAX
] = {};
112 snprintf(kb_path
, sizeof(kb_path
), "%s", keychainBasePath
);
113 if (lstat(kb_path
, &st_info
) == 0) {
114 if (S_ISDIR(st_info
.st_mode
)) {
117 secerror("invalid directory at '%s' moving aside", kb_path
);
118 snprintf(new_path
, sizeof(new_path
), "%s-invalid", kb_path
);
120 if (rename(kb_path
, new_path
) != 0) {
121 secerror("failed to rename file: %s (%s)", kb_path
, strerror(errno
));
127 require_action(mkpath_np(kb_path
, 0700) == 0, done
, secerror("could not create path: %s (%s)", kb_path
, strerror(errno
)));
134 #endif /*(TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
136 static CFURLRef
SecCopyBaseFilesURL()
138 CFURLRef baseURL
= sCustomHomeURL
;
142 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED))
143 baseURL
= SecCopyHomeURL();
145 baseURL
= CFURLCreateWithFileSystemPath(NULL
, CFSTR("/"), kCFURLPOSIXPathStyle
, true);
151 static CFURLRef
SecCopyURLForFileInBaseDirectory(CFStringRef directoryPath
, CFStringRef fileName
)
153 CFURLRef fileURL
= NULL
;
154 CFStringRef suffix
= NULL
;
155 CFURLRef homeURL
= SecCopyBaseFilesURL();
158 suffix
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%@"), directoryPath
, fileName
);
161 suffix
= CFStringCreateCopy(kCFAllocatorDefault
, directoryPath
);
163 if (homeURL
&& suffix
)
164 fileURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault
, homeURL
, suffix
, false);
165 CFReleaseSafe(suffix
);
166 CFReleaseSafe(homeURL
);
170 CFURLRef
SecCopyURLForFileInKeychainDirectory(CFStringRef fileName
)
172 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
173 // need to tack on uuid here
174 Boolean isDirectory
= (fileName
== NULL
);
175 CFURLRef resultURL
= NULL
;
176 CFStringRef resultStr
= NULL
;
177 __block
bool directoryExists
= false;
179 CFURLRef keyChainBaseURL
= SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), NULL
);
180 CFStringRef uuid_path
= copy_keychain_uuid_path(keyChainBaseURL
);
181 CFStringPerformWithCString(uuid_path
, ^(const char *utf8Str
) {
182 directoryExists
= keychain_verify_create_path(utf8Str
);
184 require(directoryExists
, done
);
186 resultStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@/%@"), uuid_path
, fileName
);
188 resultStr
= CFStringCreateCopy(kCFAllocatorDefault
, uuid_path
);
191 CFReleaseSafe(uuid_path
);
192 CFReleaseSafe(keyChainBaseURL
);
195 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, resultStr
, kCFURLPOSIXPathStyle
, isDirectory
);
196 CFRelease(resultStr
);
200 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), fileName
);
204 CFURLRef
SecCopyURLForFileInPreferencesDirectory(CFStringRef fileName
)
206 return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Preferences"), fileName
);
209 CFURLRef
SecCopyURLForFileInManagedPreferencesDirectory(CFStringRef fileName
)
211 CFURLRef resultURL
= NULL
;
213 CFStringRef userName
;
214 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
215 userName
= CFCopyUserName();
217 userName
= CFStringCreateWithCString(kCFAllocatorDefault
, "mobile", kCFStringEncodingASCII
);
221 CFStringRef path
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("/Library/Managed Preferences/%@/%@"), userName
, fileName
);
223 resultURL
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path
, kCFURLPOSIXPathStyle
, false);
226 CFReleaseSafe(userName
);
232 void WithPathInKeychainDirectory(CFStringRef fileName
, void(^operation
)(const char *utf8String
))
234 CFURLRef fileURL
= SecCopyURLForFileInKeychainDirectory(fileName
);
236 UInt8 buffer
[MAXPATHLEN
];
237 CFURLGetFileSystemRepresentation(fileURL
, false, buffer
, sizeof(buffer
));
239 operation((const char*)buffer
);
244 void SetCustomHomeURLString(CFStringRef home_path
)
246 CFReleaseNull(sCustomHomeURL
);
248 sCustomHomeURL
= CFURLCreateWithFileSystemPath(NULL
, home_path
, kCFURLPOSIXPathStyle
, true);
252 void SetCustomHomeURL(const char* path
)
255 CFStringRef path_cf
= CFStringCreateWithCStringNoCopy(NULL
, path
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
256 SetCustomHomeURLString(path_cf
);
257 CFReleaseSafe(path_cf
);
259 SetCustomHomeURLString(NULL
);