]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/osxsigning.cpp
Security-179.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / osxsigning.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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 // osxsigning - MacOS X's standard signable objects.
21 //
22 #include <Security/osxsigning.h>
23 #include <Security/cfutilities.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
31
32 namespace Security
33 {
34
35 namespace CodeSigning
36 {
37
38 //
39 // Enumerate a single file on disk.
40 //
41 void OSXCode::scanFile(const char *pathname, Signer::State &state)
42 {
43 // open the file (well, try)
44 int fd = open(pathname, O_RDONLY);
45 if (fd < 0)
46 UnixError::throwMe();
47
48 // how big is it?
49 struct stat st;
50 if (fstat(fd, &st)) {
51 close(fd);
52 UnixError::throwMe();
53 }
54 #if defined(LIMITED_SIGNING)
55 if (st.st_size >= 0x4000)
56 st.st_size = 0x4000;
57 #endif
58
59 // map it
60 void *p = mmap(NULL, st.st_size, PROT_READ, MAP_FILE, fd, 0);
61 close(fd); // done with this either way
62 if (p == MAP_FAILED)
63 UnixError::throwMe();
64
65 // scan it
66 secdebug("codesign", "scanning file %s (%ld bytes)", pathname, long(st.st_size));
67 state.enumerateContents(p, st.st_size);
68
69 // unmap it (ignore error)
70 munmap(p, st.st_size);
71 }
72
73
74 //
75 // Use prefix encoding for externalizing OSXCode objects
76 //
77 OSXCode *OSXCode::decode(const char *extForm)
78 {
79 if (!extForm || !extForm[0] || extForm[1] != ':')
80 return NULL;
81 switch (extForm[0]) {
82 case 't':
83 return new ExecutableTool(extForm+2);
84 case 'b':
85 return new GenericBundle(extForm+2);
86 default:
87 return NULL;
88 }
89 }
90
91
92 //
93 // Produce a Signable for the currently running application
94 //
95 OSXCode *OSXCode::main()
96 {
97 //@@@ cache the main bundle?
98 if (CFBundleRef mainBundle = CFBundleGetMainBundle()) {
99 CFRef<CFURLRef> base = CFBundleCopyBundleURL(mainBundle);
100 CFRef<CFURLRef> resources(CFBundleCopyResourcesDirectoryURL(mainBundle));
101 if (base && resources && !CFEqual(resources, base)) {
102 // assume this is a real bundle
103 return new ApplicationBundle(getPath(CFBundleCopyBundleURL(mainBundle)).c_str());
104 }
105
106 // too weird; assume this is a single-file "tool" executable
107 return new ExecutableTool(getPath(CFBundleCopyExecutableURL(mainBundle)).c_str());
108 }
109 // CF gives no error indications...
110 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
111 }
112
113
114 // Note: The public CFURLCopyFileSystemPath fails to resolve relative URLs as
115 // produced by CFURL methods. We need to call an internal(!) method of CF to get
116 // the full path.
117 extern "C" CFStringRef CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator,
118 CFURLRef anURL, CFURLPathStyle fsType, Boolean resolveAgainstBase);
119
120 string OSXCode::getPath(CFURLRef url)
121 {
122 if (url == NULL)
123 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); // source CF call failed
124
125 CFRef<CFStringRef> str(CFURLCreateStringWithFileSystemPath(NULL,
126 url, kCFURLPOSIXPathStyle, true));
127 CFRelease(url);
128 if (str) {
129 char path[PATH_MAX];
130 if (CFStringGetCString(str, path, PATH_MAX, kCFStringEncodingUTF8))
131 return path;
132 }
133 // no error indications from CF...
134 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
135 }
136
137
138 //
139 // Produce a Signable for whatever is at a given path.
140 // This tries to guess at the type of Signable to be used.
141 // If you *know*, just create the suitable subclass directly.
142 //
143 OSXCode *OSXCode::at(const char *path)
144 {
145 struct stat st;
146 if (stat(path, &st))
147 UnixError::throwMe();
148 if ((st.st_mode & S_IFMT) == S_IFDIR) { // directory - assume bundle
149 return new GenericBundle(path);
150 } else {
151 // look for .../Contents/MacOS/<base>
152 if (const char *slash = strrchr(path, '/'))
153 if (const char *contents = strstr(path, "/Contents/MacOS/"))
154 if (contents + 15 == slash)
155 return new GenericBundle(string(path).substr(0, contents-path).c_str());
156 // assume tool (single executable)
157 return new ExecutableTool(path);
158 }
159 }
160
161
162 //
163 // Executable Tools
164 //
165 void ExecutableTool::scanContents(Signer::State &state) const
166 {
167 scanFile(mPath.c_str(), state);
168 }
169
170 string ExecutableTool::encode() const
171 {
172 return "t:" + mPath;
173 }
174
175 string ExecutableTool::canonicalPath() const
176 {
177 return path();
178 }
179
180
181 //
182 // Generic Bundles
183 //
184 GenericBundle::GenericBundle(const char *path) : mPath(path)
185 {
186 CFRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(NULL,
187 (const UInt8 *)path, strlen(path), true));
188 if (!url || !(mBundle = CFBundleCreate(NULL, url)))
189 CssmError::throwMe(CSSMERR_CSSM_ADDIN_LOAD_FAILED);
190 }
191
192 GenericBundle::~GenericBundle()
193 {
194 CFRelease(mBundle);
195 }
196
197
198 void GenericBundle::scanContents(Signer::State &state) const
199 {
200 scanFile(executablePath().c_str(), state);
201 }
202
203 string GenericBundle::encode() const
204 {
205 return "b:" + mPath;
206 }
207
208 void *GenericBundle::lookupSymbol(const char *name)
209 {
210 CFRef<CFStringRef> cfName(CFStringCreateWithCString(NULL, name,
211 kCFStringEncodingMacRoman));
212 if (!cfName)
213 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT);
214 void *function = CFBundleGetFunctionPointerForName(mBundle, cfName);
215 if (function == NULL)
216 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT);
217 return function;
218 }
219
220 string GenericBundle::canonicalPath() const
221 {
222 return path();
223 }
224
225
226 //
227 // Load management for a loadable bundle
228 //
229 void LoadableBundle::load()
230 {
231 if (!CFBundleLoadExecutable(mBundle))
232 CssmError::throwMe(CSSMERR_CSSM_ADDIN_LOAD_FAILED);
233 secdebug("bundle", "%p (%s) loaded", this, path().c_str());
234 }
235
236 void LoadableBundle::unload()
237 {
238 secdebug("bundle", "%p (%s) unloaded", this, path().c_str());
239 CFBundleUnloadExecutable(mBundle);
240 }
241
242 bool LoadableBundle::isLoaded() const
243 {
244 return CFBundleIsExecutableLoaded(mBundle);
245 }
246
247
248 }; // end namespace CodeSigning
249
250 } // end namespace Security