]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/osxcode.cpp
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / osxcode.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // osxcode - MacOS X's standard code objects
21 //
22 #include <security_utilities/osxcode.h>
23 #include <security_utilities/unix++.h>
24 #include <fcntl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <errno.h>
29 #include <CoreFoundation/CFBundle.h>
30 #include <CoreFoundation/CFBundlePriv.h>
31
32
33 namespace Security {
34
35
36 //
37 // Produce an OSXCode for the currently running application.
38 //
39 // Note that we don't build the CFBundleRef here; we defer this to when we
40 // really need it for something more interesting than the base or executable paths.
41 // This is important because OSXCode::main() is called from various initialization
42 // scenarios (out of the securityd client layer), and CFBundle calls into some
43 // bizarrely high-level APIs to complete CFBundleGetMainBundle. Until that is fixed
44 // (if it ever is), this particular instance of laziness is mandatory.
45 //
46 RefPointer<OSXCode> OSXCode::main()
47 {
48 // return a code signing-aware OSXCode subclass if possible
49 CFRef<SecCodeRef> me;
50 if (!SecCodeCopySelf(kSecCSDefaultFlags, &me.aref()))
51 return new OSXCodeWrap(me);
52
53 // otherwise, follow the legacy path precisely - no point in messing with this, is there?
54 Boolean isRealBundle;
55 string path = cfStringRelease(_CFBundleCopyMainBundleExecutableURL(&isRealBundle));
56 if (isRealBundle) {
57 const char *cpath = path.c_str();
58 if (const char *slash = strrchr(cpath, '/'))
59 if (const char *contents = strstr(cpath, "/Contents/MacOS/"))
60 if (contents + 15 == slash)
61 return new Bundle(path.substr(0, contents-cpath).c_str());
62 secinfo("bundle", "OSXCode::main(%s) not recognized as bundle (treating as tool)", cpath);
63 }
64 return new ExecutableTool(path.c_str());
65 }
66
67
68 SecStaticCodeRef OSXCode::codeRef() const
69 {
70 SecStaticCodeRef code;
71 MacOSError::check(SecStaticCodeCreateWithPath(CFTempURL(this->canonicalPath()), kSecCSDefaultFlags, &code));
72 return code;
73 }
74
75
76 //
77 // Produce an OSXCode for whatever is at a given path.
78 // This tries to guess at the type of OSXCode to be used.
79 // If you *know*, just create the suitable subclass directly.
80 //
81 RefPointer<OSXCode> OSXCode::at(const char *path)
82 {
83 CFRef<SecStaticCodeRef> code;
84 if (!SecStaticCodeCreateWithPath(CFTempURL(path), kSecCSDefaultFlags, &code.aref()))
85 return new OSXCodeWrap(code);
86
87 struct stat st;
88 // otherwise, follow the legacy path precisely - no point in messing with this, is there?
89 if (stat(path, &st))
90 UnixError::throwMe();
91 if ((st.st_mode & S_IFMT) == S_IFDIR) { // directory - assume bundle
92 return new Bundle(path);
93 } else {
94 // look for .../Contents/MacOS/<base>
95 if (const char *slash = strrchr(path, '/'))
96 if (const char *contents = strstr(path, "/Contents/MacOS/"))
97 if (contents + 15 == slash)
98 return new Bundle(string(path).substr(0, contents-path).c_str(), path);
99 // assume tool (single executable)
100 return new ExecutableTool(path);
101 }
102 }
103
104
105 //
106 // Executable Tools
107 //
108 string ExecutableTool::canonicalPath() const
109 {
110 return path();
111 }
112
113 string ExecutableTool::executablePath() const
114 {
115 return path();
116 }
117
118
119 //
120 // Generic Bundles
121 //
122 Bundle::Bundle(const char *path, const char *execPath /* = NULL */)
123 : mPath(path), mBundle(NULL)
124 {
125 if (execPath) // caller knows that one; set it
126 mExecutablePath = execPath;
127 secinfo("bundle", "%p Bundle from path %s(%s)", this, path, executablePath().c_str());
128 }
129
130 Bundle::Bundle(CFBundleRef bundle, const char *root /* = NULL */)
131 : mBundle(bundle)
132 {
133 assert(bundle);
134 CFRetain(bundle);
135 mPath = root ? root : cfStringRelease(CFBundleCopyBundleURL(mBundle));
136 secinfo("bundle", "%p Bundle from bundle %p(%s)", this, bundle, mPath.c_str());
137 }
138
139
140 Bundle::~Bundle()
141 {
142 if (mBundle)
143 CFRelease(mBundle);
144 }
145
146
147 string Bundle::executablePath() const
148 {
149 if (mExecutablePath.empty())
150 return mExecutablePath = cfStringRelease(CFBundleCopyExecutableURL(cfBundle()));
151 else
152 return mExecutablePath;
153 }
154
155
156 CFBundleRef Bundle::cfBundle() const
157 {
158 if (!mBundle) {
159 secinfo("bundle", "instantiating CFBundle for %s", mPath.c_str());
160 CFRef<CFURLRef> url = CFURLCreateFromFileSystemRepresentation(NULL,
161 (const UInt8 *)mPath.c_str(), mPath.length(), true);
162 if (!url || !(mBundle = CFBundleCreate(NULL, url)))
163 CFError::throwMe();
164 }
165 return mBundle;
166 }
167
168
169 CFTypeRef Bundle::infoPlistItem(const char *name) const
170 {
171 return CFBundleGetValueForInfoDictionaryKey(cfBundle(), CFTempString(name));
172 }
173
174
175 void *Bundle::lookupSymbol(const char *name)
176 {
177 CFRef<CFStringRef> cfName(CFStringCreateWithCString(NULL, name,
178 kCFStringEncodingMacRoman));
179 if (!cfName)
180 UnixError::throwMe(EBADEXEC); // sort of
181 void *function = CFBundleGetFunctionPointerForName(cfBundle(), cfName);
182 if (function == NULL)
183 UnixError::throwMe(EBADEXEC); // sort of
184 return function;
185 }
186
187 string Bundle::canonicalPath() const
188 {
189 return path();
190 }
191
192
193 string Bundle::resource(const char *name, const char *type, const char *subdir)
194 {
195 return cfStringRelease(CFBundleCopyResourceURL(cfBundle(),
196 CFTempString(name), CFTempString(type), CFTempString(subdir)));
197 }
198
199 void Bundle::resources(vector<string> &paths, const char *type, const char *subdir)
200 {
201 CFRef<CFArrayRef> cfList = CFBundleCopyResourceURLsOfType(cfBundle(),
202 CFTempString(type), CFTempString(subdir));
203 CFIndex size = CFArrayGetCount(cfList);
204 paths.reserve(size);
205 for (CFIndex n = 0; n < size; n++)
206 paths.push_back(cfString(CFURLRef(CFArrayGetValueAtIndex(cfList, n))));
207 }
208
209
210 //
211 // Load management for a loadable bundle
212 //
213 void LoadableBundle::load()
214 {
215 if (!CFBundleLoadExecutable(cfBundle()))
216 CFError::throwMe();
217 secinfo("bundle", "%p (%s) loaded", this, path().c_str());
218 }
219
220 void LoadableBundle::unload()
221 {
222 secinfo("bundle", "%p (%s) unloaded", this, path().c_str());
223 CFBundleUnloadExecutable(cfBundle());
224 }
225
226 bool LoadableBundle::isLoaded() const
227 {
228 return CFBundleIsExecutableLoaded(cfBundle());
229 }
230
231
232 //
233 // OSXCodeWrap
234 //
235 string OSXCodeWrap::canonicalPath() const
236 {
237 CFURLRef path;
238 MacOSError::check(SecCodeCopyPath(mCode, kSecCSDefaultFlags, &path));
239 return cfStringRelease(path);
240 }
241
242
243 //
244 // The executable path is a bit annoying to get, but not quite
245 // annoying enough to cache the result.
246 //
247 string OSXCodeWrap::executablePath() const
248 {
249 CFRef<CFDictionaryRef> info;
250 MacOSError::check(SecCodeCopySigningInformation(mCode, kSecCSDefaultFlags, &info.aref()));
251 return cfString(CFURLRef(CFDictionaryGetValue(info, kSecCodeInfoMainExecutable)));
252 }
253
254 SecStaticCodeRef OSXCodeWrap::codeRef() const
255 {
256 return mCode.retain();
257 }
258
259
260 } // end namespace Security