]> git.saurik.com Git - apple/security.git/blob - utilities/src/SecFileLocations.c
Security-55471.14.tar.gz
[apple/security.git] / utilities / src / SecFileLocations.c
1 /*
2 * Copyright (c) 2012-2013 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
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