]>
Commit | Line | Data |
---|---|---|
427c49bc | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. |
427c49bc A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
d8f41ccd | 5 | * |
427c49bc A |
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. | |
d8f41ccd | 12 | * |
427c49bc A |
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. | |
d8f41ccd | 20 | * |
427c49bc A |
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 | ||
45 | #include "SecFileLocations.h" | |
46 | ||
47 | static CFURLRef sCustomHomeURL = NULL; | |
48 | ||
49 | static CFURLRef SecCopyHomeURL(void) | |
50 | { | |
51 | // This returns a CFURLRef so that it can be passed as the second parameter | |
52 | // to CFURLCreateCopyAppendingPathComponent | |
53 | ||
54 | CFURLRef homeURL = sCustomHomeURL; | |
55 | if (homeURL) { | |
56 | CFRetain(homeURL); | |
57 | } else { | |
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); | |
62 | #else | |
63 | homeURL = CFCopyHomeDirectoryURL(); | |
64 | #endif | |
65 | } | |
66 | ||
67 | return homeURL; | |
68 | } | |
69 | ||
70 | #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | |
71 | static const char * get_host_uuid() | |
72 | { | |
73 | static uuid_string_t hostuuid = {}; | |
74 | static dispatch_once_t onceToken; | |
75 | dispatch_once(&onceToken, ^{ | |
76 | struct timespec timeout = {30, 0}; | |
77 | uuid_t uuid = {}; | |
78 | if (gethostuuid(uuid, &timeout) == 0) { | |
79 | uuid_unparse(uuid, hostuuid); | |
80 | } else { | |
81 | secerror("failed to get host uuid"); | |
82 | } | |
83 | }); | |
84 | ||
85 | return hostuuid; | |
86 | } | |
87 | ||
88 | static CFStringRef copy_keychain_uuid_path(CFURLRef keyChainBaseURL) | |
89 | { | |
90 | CFStringRef baseURLString = NULL; | |
91 | CFStringRef uuid_path = NULL; | |
92 | ||
93 | require(keyChainBaseURL, done); | |
94 | ||
95 | baseURLString = CFURLCopyFileSystemPath(keyChainBaseURL, kCFURLPOSIXPathStyle); | |
96 | require(baseURLString, done); | |
97 | ||
98 | uuid_path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%s"), baseURLString, get_host_uuid()); | |
99 | ||
100 | done: | |
101 | CFReleaseSafe(baseURLString); | |
102 | return uuid_path; | |
103 | } | |
104 | ||
105 | // See _kb_verify_create_path in securityd | |
106 | static bool keychain_verify_create_path(const char *keychainBasePath) | |
107 | { | |
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)) { | |
115 | created = true; | |
116 | } else { | |
117 | secerror("invalid directory at '%s' moving aside", kb_path); | |
118 | snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path); | |
119 | unlink(new_path); | |
120 | if (rename(kb_path, new_path) != 0) { | |
121 | secerror("failed to rename file: %s (%s)", kb_path, strerror(errno)); | |
122 | goto done; | |
123 | } | |
124 | } | |
125 | } | |
126 | if (!created) { | |
127 | require_action(mkpath_np(kb_path, 0700) == 0, done, secerror("could not create path: %s (%s)", kb_path, strerror(errno))); | |
128 | created = true; | |
129 | } | |
130 | ||
131 | done: | |
132 | return created; | |
133 | } | |
134 | #endif /*(TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ | |
135 | ||
136 | static CFURLRef SecCopyBaseFilesURL() | |
137 | { | |
138 | CFURLRef baseURL = sCustomHomeURL; | |
139 | if (baseURL) { | |
140 | CFRetain(baseURL); | |
141 | } else { | |
142 | #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED)) | |
143 | baseURL = SecCopyHomeURL(); | |
144 | #else | |
145 | baseURL = CFURLCreateWithFileSystemPath(NULL, CFSTR("/"), kCFURLPOSIXPathStyle, true); | |
146 | #endif | |
147 | } | |
148 | return baseURL; | |
149 | } | |
150 | ||
151 | static CFURLRef SecCopyURLForFileInBaseDirectory(CFStringRef directoryPath, CFStringRef fileName) | |
152 | { | |
153 | CFURLRef fileURL = NULL; | |
154 | CFStringRef suffix = NULL; | |
155 | CFURLRef homeURL = SecCopyBaseFilesURL(); | |
156 | ||
157 | if (fileName) | |
158 | suffix = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%@"), directoryPath, fileName); | |
159 | else | |
160 | if (directoryPath) | |
161 | suffix = CFStringCreateCopy(kCFAllocatorDefault, directoryPath); | |
162 | ||
163 | if (homeURL && suffix) | |
164 | fileURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, homeURL, suffix, false); | |
165 | CFReleaseSafe(suffix); | |
166 | CFReleaseSafe(homeURL); | |
167 | return fileURL; | |
168 | } | |
169 | ||
170 | CFURLRef SecCopyURLForFileInKeychainDirectory(CFStringRef fileName) | |
171 | { | |
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; | |
178 | ||
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); | |
183 | }); | |
184 | require(directoryExists, done); | |
185 | if (fileName) | |
186 | resultStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@/%@"), uuid_path, fileName); | |
187 | else | |
188 | resultStr = CFStringCreateCopy(kCFAllocatorDefault, uuid_path); | |
189 | ||
190 | done: | |
191 | CFReleaseSafe(uuid_path); | |
192 | CFReleaseSafe(keyChainBaseURL); | |
193 | if (resultStr) | |
194 | { | |
195 | resultURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, resultStr, kCFURLPOSIXPathStyle, isDirectory); | |
196 | CFRelease(resultStr); | |
197 | } | |
198 | return resultURL; | |
199 | #else | |
200 | return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Keychains"), fileName); | |
201 | #endif | |
202 | } | |
203 | ||
204 | CFURLRef SecCopyURLForFileInPreferencesDirectory(CFStringRef fileName) | |
205 | { | |
206 | return SecCopyURLForFileInBaseDirectory(CFSTR("Library/Preferences"), fileName); | |
207 | } | |
208 | ||
209 | void WithPathInKeychainDirectory(CFStringRef fileName, void(^operation)(const char *utf8String)) | |
210 | { | |
211 | CFURLRef fileURL = SecCopyURLForFileInKeychainDirectory(fileName); | |
212 | UInt8 buffer[MAXPATHLEN]; | |
213 | CFURLGetFileSystemRepresentation(fileURL, false, buffer, sizeof(buffer)); | |
214 | ||
215 | operation((const char*)buffer); | |
216 | CFRelease(fileURL); | |
217 | } | |
218 | ||
219 | void SetCustomHomeURLString(CFStringRef home_path) | |
220 | { | |
221 | CFReleaseNull(sCustomHomeURL); | |
222 | if (home_path) { | |
223 | sCustomHomeURL = CFURLCreateWithFileSystemPath(NULL, home_path, kCFURLPOSIXPathStyle, true); | |
224 | } | |
225 | } | |
226 | ||
227 | void SetCustomHomeURL(const char* path) | |
228 | { | |
229 | if (path) { | |
230 | CFStringRef path_cf = CFStringCreateWithCStringNoCopy(NULL, path, kCFStringEncodingUTF8, kCFAllocatorNull); | |
231 | SetCustomHomeURLString(path_cf); | |
232 | CFReleaseSafe(path_cf); | |
233 | } else { | |
234 | SetCustomHomeURLString(NULL); | |
235 | } | |
236 | } | |
237 | ||
238 |