]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_translocate/lib/SecTranslocateUtilities.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_translocate / lib / SecTranslocateUtilities.cpp
CommitLineData
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
44namespace Security {
45
46using namespace Security::UnixPlusPlus;
47
48namespace SecTranslocate {
49
50using namespace std;
51
52/* store the real path and fstatfs for the file descriptor. This throws if either fail */
53void 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
67bool ExtendedAutoFileDesc::isFileSystemType(const string &fsType) const
68{
69 notOpen(); //Throws if not Open
70
71 return fsType == fsInfo.f_fstypename;
72}
73
74bool ExtendedAutoFileDesc::pathIsAbsolute() const
75{
76 notOpen(); //Throws if not Open
77
78 return originalPath == realPath;
79}
80
81bool ExtendedAutoFileDesc::isMountPoint() const
82{
83 notOpen(); //Throws if not Open
84 return realPath == fsInfo.f_mntonname;
85}
86bool 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
93string ExtendedAutoFileDesc::getFsType() const
94{
95 notOpen(); //Throws if not Open
96
97 return fsInfo.f_fstypename;
98}
99
100string ExtendedAutoFileDesc::getMountPoint() const
101{
102 notOpen(); //Throws if not Open
103
104 return fsInfo.f_mntonname;
105}
106
107string ExtendedAutoFileDesc::getMountFromPath() const
108{
109 notOpen(); //Throws if not Open
110
111 return fsInfo.f_mntfromname;
112}
113
114const string& ExtendedAutoFileDesc::getRealPath() const
115{
116 notOpen(); //Throws if not Open
117
118 return realPath;
119}
120
121fsid_t const ExtendedAutoFileDesc::getFsid() const
122{
123 notOpen(); //Throws if not Open
124
125 return fsInfo.f_fsid;
126}
127
128void 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
154bool ExtendedAutoFileDesc::isQuarantined()
155{
156 notOpen();
157 fetchQuarantine();
158
159 return quarantined;
160}
161
162bool ExtendedAutoFileDesc::isUserApproved()
163{
164 notOpen();
165 fetchQuarantine();
166
167 return ((qtn_flags & QTN_FLAG_USER_APPROVED) == QTN_FLAG_USER_APPROVED);
168}
169
170bool 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 */
179vector<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 */
209string joinPath(vector<string>& path)
210{
211 string out = "";
212 for(auto &i : path)
213 {
214 out += "/"+i;
215 }
216 return out;
217}
218
219string 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 */
237string 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 */
246string 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
263void* 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
276void* 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 */
289string 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 */
308int 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}