2 * Copyright (c) 2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
28 #include <sys/types.h>
29 #include <sys/sysctl.h>
32 #define __APPLE_API_PRIVATE
33 #include <quarantine.h>
34 #undef __APPLE_API_PRIVATE
36 #include <security_utilities/logging.h>
37 #include <security_utilities/unix++.h>
38 #include <security_utilities/cfutilities.h>
40 #include "SecTranslocateUtilities.hpp"
42 #define APP_TRANSLOCATION_DIR "/AppTranslocation/"
46 using namespace Security::UnixPlusPlus
;
48 namespace SecTranslocate
{
52 /* store the real path and fstatfs for the file descriptor. This throws if either fail */
53 void ExtendedAutoFileDesc::init()
55 char absPath
[MAXPATHLEN
];
58 UnixError::check(fstatfs(fd(), &fsInfo
));
59 fcntl(F_GETPATH
, absPath
);
63 quarantineFetched
= false; //only fetch quarantine info when we need it
67 bool ExtendedAutoFileDesc::isFileSystemType(const string
&fsType
) const
69 notOpen(); //Throws if not Open
71 return fsType
== fsInfo
.f_fstypename
;
74 bool ExtendedAutoFileDesc::pathIsAbsolute() const
76 notOpen(); //Throws if not Open
78 return originalPath
== realPath
;
81 bool ExtendedAutoFileDesc::isMountPoint() const
83 notOpen(); //Throws if not Open
84 return realPath
== fsInfo
.f_mntonname
;
86 bool ExtendedAutoFileDesc::isInPrefixDir(const string
&prefixDir
) const
88 notOpen(); //Throws if not Open
90 return strncmp(realPath
.c_str(), prefixDir
.c_str(), prefixDir
.length()) == 0;
93 string
ExtendedAutoFileDesc::getFsType() const
95 notOpen(); //Throws if not Open
97 return fsInfo
.f_fstypename
;
100 string
ExtendedAutoFileDesc::getMountPoint() const
102 notOpen(); //Throws if not Open
104 return fsInfo
.f_mntonname
;
107 string
ExtendedAutoFileDesc::getMountFromPath() const
109 notOpen(); //Throws if not Open
111 return fsInfo
.f_mntfromname
;
114 const string
& ExtendedAutoFileDesc::getRealPath() const
116 notOpen(); //Throws if not Open
121 fsid_t
const ExtendedAutoFileDesc::getFsid() const
123 notOpen(); //Throws if not Open
125 return fsInfo
.f_fsid
;
128 void ExtendedAutoFileDesc::fetchQuarantine()
130 if(!quarantineFetched
)
134 qtn_file_t qf
= qtn_file_alloc();
138 if(0 == qtn_file_init_with_fd(qf
, fd()))
141 qtn_flags
= qtn_file_get_flags(qf
);
144 quarantineFetched
= true;
148 Syslog::error("SecTranslocate: failed to allocate memory for quarantine struct");
149 UnixError::throwMe();
154 bool ExtendedAutoFileDesc::isQuarantined()
162 bool ExtendedAutoFileDesc::isUserApproved()
167 return ((qtn_flags
& QTN_FLAG_USER_APPROVED
) == QTN_FLAG_USER_APPROVED
);
170 bool ExtendedAutoFileDesc::shouldTranslocate()
175 return ((qtn_flags
& (QTN_FLAG_TRANSLOCATE
| QTN_FLAG_DO_NOT_TRANSLOCATE
)) == QTN_FLAG_TRANSLOCATE
);
178 /* Take an absolute path and split it into a vector of path components */
179 vector
<string
> splitPath(const string
&path
)
186 if(path
.empty() || path
.front() != '/')
188 Syslog::error("SecTranslocate::splitPath: asked to split a non-absolute or empty path: %s",path
.c_str());
189 UnixError::throwMe(EINVAL
);
192 while(end
!= string::npos
)
194 end
= path
.find('/', start
);
195 len
= (end
== string::npos
) ? end
: (end
- start
);
196 string temp
= path
.substr(start
,len
);
208 /* Take a vector of path components and turn it into an absolute path */
209 string
joinPath(vector
<string
>& path
)
219 string
joinPathUpTo(vector
<string
> &path
, size_t index
)
221 if (path
.size() == 0 || index
> path
.size()-1)
223 Syslog::error("SecTranslocate::joinPathUpTo invalid index %lu (size %lu)",index
, path
.size()-1);
224 UnixError::throwMe(EINVAL
);
228 for (size_t i
= 0; i
<= index
; i
++)
230 out
+= "/" + path
[i
];
236 /* Fully resolve the path provided */
237 string
getRealPath(const string
&path
)
239 char absPath
[MAXPATHLEN
];
240 AutoFileDesc
fd(path
);
241 fd
.fcntl(F_GETPATH
, absPath
);
245 /* Create a UUID string */
248 CFRef
<CFUUIDRef
> newUUID
= CFUUIDCreate(NULL
);
251 UnixError::throwMe(ENOMEM
);
254 CFRef
<CFStringRef
> str
= CFUUIDCreateString(NULL
, newUUID
.get());
257 UnixError::throwMe(ENOMEM
);
260 return cfString(str
);
263 void* checkedDlopen(const char* path
, int mode
)
265 void* handle
= dlopen(path
, mode
);
269 Syslog::critical("SecTranslocate: failed to load library %s: %s", path
, dlerror());
270 UnixError::throwMe();
276 void* checkedDlsym(void* handle
, const char* symbol
)
278 void* result
= dlsym(handle
, symbol
);
282 Syslog::critical("SecTranslocate: failed to load symbol %s: %s", symbol
, dlerror());
283 UnixError::throwMe();
288 /* Calculate the app translocation directory for the user inside the user's temp directory */
289 string
translocationDirForUser()
291 char userTempPath
[MAXPATHLEN
];
293 if(confstr(_CS_DARWIN_USER_TEMP_DIR
, userTempPath
, sizeof(userTempPath
)) == 0)
295 Syslog::error("SecTranslocate: Failed to get temp dir for user %d (error:%d)",
298 UnixError::throwMe();
301 // confstr returns a path with a symlink, we want the resolved path */
302 return getRealPath(userTempPath
)+APP_TRANSLOCATION_DIR
;
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.
308 int getFDForDirectory(const string
&directoryPath
, bool *owned
)
310 FileDesc
fd(directoryPath
, O_RDONLY
, FileDesc::modeMissingOk
);
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. */