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