]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/osxsigning.cpp
Security-54.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 #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 debug("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 { // not directory - assume tool
151 return new ExecutableTool(path);
152 }
153 }
154
155
156 //
157 // Executable Tools
158 //
159 void ExecutableTool::scanContents(Signer::State &state) const
160 {
161 scanFile(mPath.c_str(), state);
162 }
163
164 string ExecutableTool::encode() const
165 {
166 return "t:" + mPath;
167 }
168
169 string ExecutableTool::canonicalPath() const
170 {
171 return path();
172 }
173
174
175 //
176 // Generic Bundles
177 //
178 GenericBundle::GenericBundle(const char *path) : mPath(path)
179 {
180 CFRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(NULL,
181 (const UInt8 *)path, strlen(path), true));
182 if (!url || !(mBundle = CFBundleCreate(NULL, url)))
183 CssmError::throwMe(CSSMERR_CSSM_ADDIN_LOAD_FAILED);
184 }
185
186 GenericBundle::~GenericBundle()
187 {
188 CFRelease(mBundle);
189 }
190
191
192 void GenericBundle::scanContents(Signer::State &state) const
193 {
194 scanFile(executablePath().c_str(), state);
195 }
196
197 string GenericBundle::encode() const
198 {
199 return "b:" + mPath;
200 }
201
202 void *GenericBundle::lookupSymbol(const char *name)
203 {
204 CFRef<CFStringRef> cfName(CFStringCreateWithCString(NULL, name,
205 kCFStringEncodingMacRoman));
206 if (!cfName)
207 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT);
208 void *function = CFBundleGetFunctionPointerForName(mBundle, cfName);
209 if (function == NULL)
210 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT);
211 return function;
212 }
213
214 string GenericBundle::canonicalPath() const
215 {
216 return path();
217 }
218
219
220 //
221 // Load management for a loadable bundle
222 //
223 void LoadableBundle::load()
224 {
225 if (!CFBundleLoadExecutable(mBundle))
226 CssmError::throwMe(CSSMERR_CSSM_ADDIN_LOAD_FAILED);
227 IFDEBUG(debug("bundle", "%p (%s) loaded", this, path().c_str()));
228 }
229
230 void LoadableBundle::unload()
231 {
232 IFDEBUG(debug("bundle", "%p (%s) unloaded", this, path().c_str()));
233 CFBundleUnloadExecutable(mBundle);
234 }
235
236 bool LoadableBundle::isLoaded() const
237 {
238 return CFBundleIsExecutableLoaded(mBundle);
239 }
240
241
242 }; // end namespace CodeSigning
243
244 } // end namespace Security