]>
Commit | Line | Data |
---|---|---|
fa7225c8 A |
1 | /* |
2 | * Copyright (c) 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 | #include <string> | |
25 | #include <vector> | |
26 | ||
27 | #include <unistd.h> | |
28 | #include <sys/types.h> | |
29 | #include <sys/sysctl.h> | |
30 | #include <dlfcn.h> | |
31 | ||
32 | #define __APPLE_API_PRIVATE | |
33 | #include <quarantine.h> | |
34 | #undef __APPLE_API_PRIVATE | |
35 | ||
36 | #include <security_utilities/logging.h> | |
37 | #include <security_utilities/unix++.h> | |
38 | #include <security_utilities/cfutilities.h> | |
39 | ||
40 | #include "SecTranslocateUtilities.hpp" | |
41 | ||
42 | #define APP_TRANSLOCATION_DIR "/AppTranslocation/" | |
43 | ||
44 | namespace Security { | |
45 | ||
46 | using namespace Security::UnixPlusPlus; | |
47 | ||
48 | namespace SecTranslocate { | |
49 | ||
50 | using namespace std; | |
51 | ||
52 | /* store the real path and fstatfs for the file descriptor. This throws if either fail */ | |
53 | void ExtendedAutoFileDesc::init() | |
54 | { | |
55 | char absPath[MAXPATHLEN]; | |
56 | if(isOpen()) | |
57 | { | |
58 | UnixError::check(fstatfs(fd(), &fsInfo)); | |
59 | fcntl(F_GETPATH, absPath); | |
60 | realPath = absPath; | |
61 | quarantined = false; | |
62 | qtn_flags = 0; | |
63 | quarantineFetched = false; //only fetch quarantine info when we need it | |
64 | } | |
65 | } | |
66 | ||
67 | bool ExtendedAutoFileDesc::isFileSystemType(const string &fsType) const | |
68 | { | |
69 | notOpen(); //Throws if not Open | |
70 | ||
71 | return fsType == fsInfo.f_fstypename; | |
72 | } | |
73 | ||
74 | bool ExtendedAutoFileDesc::pathIsAbsolute() const | |
75 | { | |
76 | notOpen(); //Throws if not Open | |
77 | ||
78 | return originalPath == realPath; | |
79 | } | |
80 | ||
81 | bool ExtendedAutoFileDesc::isMountPoint() const | |
82 | { | |
83 | notOpen(); //Throws if not Open | |
84 | return realPath == fsInfo.f_mntonname; | |
85 | } | |
86 | bool ExtendedAutoFileDesc::isInPrefixDir(const string &prefixDir) const | |
87 | { | |
88 | notOpen(); //Throws if not Open | |
89 | ||
90 | return strncmp(realPath.c_str(), prefixDir.c_str(), prefixDir.length()) == 0; | |
91 | } | |
92 | ||
93 | string ExtendedAutoFileDesc::getFsType() const | |
94 | { | |
95 | notOpen(); //Throws if not Open | |
96 | ||
97 | return fsInfo.f_fstypename; | |
98 | } | |
99 | ||
100 | string ExtendedAutoFileDesc::getMountPoint() const | |
101 | { | |
102 | notOpen(); //Throws if not Open | |
103 | ||
104 | return fsInfo.f_mntonname; | |
105 | } | |
106 | ||
107 | string ExtendedAutoFileDesc::getMountFromPath() const | |
108 | { | |
109 | notOpen(); //Throws if not Open | |
110 | ||
111 | return fsInfo.f_mntfromname; | |
112 | } | |
113 | ||
114 | const string& ExtendedAutoFileDesc::getRealPath() const | |
115 | { | |
116 | notOpen(); //Throws if not Open | |
117 | ||
118 | return realPath; | |
119 | } | |
120 | ||
121 | fsid_t const ExtendedAutoFileDesc::getFsid() const | |
122 | { | |
123 | notOpen(); //Throws if not Open | |
124 | ||
125 | return fsInfo.f_fsid; | |
126 | } | |
127 | ||
128 | void ExtendedAutoFileDesc::fetchQuarantine() | |
129 | { | |
130 | if(!quarantineFetched) | |
131 | { | |
132 | notOpen(); | |
133 | ||
134 | qtn_file_t qf = qtn_file_alloc(); | |
135 | ||
136 | if(qf) | |
137 | { | |
138 | if(0 == qtn_file_init_with_fd(qf, fd())) | |
139 | { | |
140 | quarantined = true; | |
141 | qtn_flags = qtn_file_get_flags(qf); | |
142 | } | |
143 | qtn_file_free(qf); | |
144 | quarantineFetched = true; | |
145 | } | |
146 | else | |
147 | { | |
148 | Syslog::error("SecTranslocate: failed to allocate memory for quarantine struct"); | |
149 | UnixError::throwMe(); | |
150 | } | |
151 | } | |
152 | } | |
153 | ||
154 | bool ExtendedAutoFileDesc::isQuarantined() | |
155 | { | |
156 | notOpen(); | |
157 | fetchQuarantine(); | |
158 | ||
159 | return quarantined; | |
160 | } | |
161 | ||
162 | bool ExtendedAutoFileDesc::isUserApproved() | |
163 | { | |
164 | notOpen(); | |
165 | fetchQuarantine(); | |
166 | ||
167 | return ((qtn_flags & QTN_FLAG_USER_APPROVED) == QTN_FLAG_USER_APPROVED); | |
168 | } | |
169 | ||
170 | bool ExtendedAutoFileDesc::shouldTranslocate() | |
171 | { | |
172 | notOpen(); | |
173 | fetchQuarantine(); | |
174 | ||
175 | return ((qtn_flags & (QTN_FLAG_TRANSLOCATE | QTN_FLAG_DO_NOT_TRANSLOCATE)) == QTN_FLAG_TRANSLOCATE); | |
176 | } | |
177 | ||
178 | /* Take an absolute path and split it into a vector of path components */ | |
179 | vector<string> splitPath(const string &path) | |
180 | { | |
181 | vector<string> out; | |
182 | size_t start = 0; | |
183 | size_t end = 0; | |
184 | size_t len = 0; | |
185 | ||
186 | if(path.empty() || path.front() != '/') | |
187 | { | |
188 | Syslog::error("SecTranslocate::splitPath: asked to split a non-absolute or empty path: %s",path.c_str()); | |
189 | UnixError::throwMe(EINVAL); | |
190 | } | |
191 | ||
192 | while(end != string::npos) | |
193 | { | |
194 | end = path.find('/', start); | |
195 | len = (end == string::npos) ? end : (end - start); | |
196 | string temp = path.substr(start,len); | |
197 | ||
198 | if(!temp.empty()) | |
199 | { | |
200 | out.push_back(temp); | |
201 | } | |
202 | start = end + 1; | |
203 | } | |
204 | ||
205 | return out; | |
206 | } | |
207 | ||
208 | /* Take a vector of path components and turn it into an absolute path */ | |
209 | string joinPath(vector<string>& path) | |
210 | { | |
211 | string out = ""; | |
212 | for(auto &i : path) | |
213 | { | |
214 | out += "/"+i; | |
215 | } | |
216 | return out; | |
217 | } | |
218 | ||
219 | string joinPathUpTo(vector<string> &path, size_t index) | |
220 | { | |
221 | if (path.size() == 0 || index > path.size()-1) | |
222 | { | |
223 | Syslog::error("SecTranslocate::joinPathUpTo invalid index %lu (size %lu)",index, path.size()-1); | |
224 | UnixError::throwMe(EINVAL); | |
225 | } | |
226 | ||
227 | string out = ""; | |
228 | for (size_t i = 0; i <= index; i++) | |
229 | { | |
230 | out += "/" + path[i]; | |
231 | } | |
232 | ||
233 | return out; | |
234 | } | |
235 | ||
236 | /* Fully resolve the path provided */ | |
237 | string getRealPath(const string &path) | |
238 | { | |
239 | char absPath[MAXPATHLEN]; | |
240 | AutoFileDesc fd(path); | |
241 | fd.fcntl(F_GETPATH, absPath); | |
242 | return absPath; | |
243 | } | |
244 | ||
245 | /* Create a UUID string */ | |
246 | string makeUUID() | |
247 | { | |
248 | CFRef<CFUUIDRef> newUUID = CFUUIDCreate(NULL); | |
249 | if (!newUUID) | |
250 | { | |
251 | UnixError::throwMe(ENOMEM); | |
252 | } | |
253 | ||
254 | CFRef<CFStringRef> str = CFUUIDCreateString(NULL, newUUID.get()); | |
255 | if (!str) | |
256 | { | |
257 | UnixError::throwMe(ENOMEM); | |
258 | } | |
259 | ||
260 | return cfString(str); | |
261 | } | |
262 | ||
263 | void* checkedDlopen(const char* path, int mode) | |
264 | { | |
265 | void* handle = dlopen(path, mode); | |
266 | ||
267 | if(handle == NULL) | |
268 | { | |
269 | Syslog::critical("SecTranslocate: failed to load library %s: %s", path, dlerror()); | |
270 | UnixError::throwMe(); | |
271 | } | |
272 | ||
273 | return handle; | |
274 | } | |
275 | ||
276 | void* checkedDlsym(void* handle, const char* symbol) | |
277 | { | |
278 | void* result = dlsym(handle, symbol); | |
279 | ||
280 | if(result == NULL) | |
281 | { | |
282 | Syslog::critical("SecTranslocate: failed to load symbol %s: %s", symbol, dlerror()); | |
283 | UnixError::throwMe(); | |
284 | } | |
285 | return result; | |
286 | } | |
287 | ||
288 | /* Calculate the app translocation directory for the user inside the user's temp directory */ | |
289 | string translocationDirForUser() | |
290 | { | |
291 | char userTempPath[MAXPATHLEN]; | |
292 | ||
293 | if(confstr(_CS_DARWIN_USER_TEMP_DIR, userTempPath, sizeof(userTempPath)) == 0) | |
294 | { | |
295 | Syslog::error("SecTranslocate: Failed to get temp dir for user %d (error:%d)", | |
296 | getuid(), | |
297 | errno); | |
298 | UnixError::throwMe(); | |
299 | } | |
300 | ||
301 | // confstr returns a path with a symlink, we want the resolved path */ | |
302 | return getRealPath(userTempPath)+APP_TRANSLOCATION_DIR; | |
303 | } | |
304 | ||
305 | /* Get a file descriptor for the provided path. if the last component of the provided path doesn't | |
306 | exist, create it and then re-attempt to get the file descriptor. | |
307 | */ | |
308 | int getFDForDirectory(const string &directoryPath, bool *owned) | |
309 | { | |
310 | FileDesc fd(directoryPath, O_RDONLY, FileDesc::modeMissingOk); | |
311 | if(!fd) | |
312 | { | |
313 | UnixError::check(mkdir(directoryPath.c_str(),0755)); | |
314 | fd.open(directoryPath); | |
315 | /* owned means that the library created the directory rather than it being pre-existent. | |
316 | We just made a directory that didn't exist before, so set owned to true. */ | |
317 | if(owned) | |
318 | { | |
319 | *owned = true; | |
320 | } | |
321 | } | |
322 | else if (owned) | |
323 | { | |
324 | *owned = false; | |
325 | } | |
326 | ||
327 | return fd; | |
328 | } | |
329 | } | |
330 | } |