]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_translocate/lib/SecTranslocateUtilities.cpp
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_translocate / lib / SecTranslocateUtilities.cpp
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 }