2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // osxsigning - MacOS X's standard signable objects.
22 #include <Security/osxsigning.h>
23 #include <Security/cfutilities.h>
25 #include <sys/types.h>
29 #include <CoreFoundation/CFBundle.h>
39 // Enumerate a single file on disk.
41 void OSXCode::scanFile(const char *pathname
, Signer::State
&state
)
43 // open the file (well, try)
44 int fd
= open(pathname
, O_RDONLY
);
54 #if defined(LIMITED_SIGNING)
55 if (st
.st_size
>= 0x4000)
60 void *p
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_FILE
, fd
, 0);
61 close(fd
); // done with this either way
66 secdebug("codesign", "scanning file %s (%ld bytes)", pathname
, long(st
.st_size
));
67 state
.enumerateContents(p
, st
.st_size
);
69 // unmap it (ignore error)
70 munmap(p
, st
.st_size
);
75 // Use prefix encoding for externalizing OSXCode objects
77 OSXCode
*OSXCode::decode(const char *extForm
)
79 if (!extForm
|| !extForm
[0] || extForm
[1] != ':')
83 return new ExecutableTool(extForm
+2);
85 return new GenericBundle(extForm
+2);
93 // Produce a Signable for the currently running application
95 OSXCode
*OSXCode::main()
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());
106 // too weird; assume this is a single-file "tool" executable
107 return new ExecutableTool(getPath(CFBundleCopyExecutableURL(mainBundle
)).c_str());
109 // CF gives no error indications...
110 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
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
117 extern "C" CFStringRef
CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator
,
118 CFURLRef anURL
, CFURLPathStyle fsType
, Boolean resolveAgainstBase
);
120 string
OSXCode::getPath(CFURLRef url
)
123 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); // source CF call failed
125 CFRef
<CFStringRef
> str(CFURLCreateStringWithFileSystemPath(NULL
,
126 url
, kCFURLPOSIXPathStyle
, true));
130 if (CFStringGetCString(str
, path
, PATH_MAX
, kCFStringEncodingUTF8
))
133 // no error indications from CF...
134 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
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.
143 OSXCode
*OSXCode::at(const char *path
)
147 UnixError::throwMe();
148 if ((st
.st_mode
& S_IFMT
) == S_IFDIR
) { // directory - assume bundle
149 return new GenericBundle(path
);
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
);
165 void ExecutableTool::scanContents(Signer::State
&state
) const
167 scanFile(mPath
.c_str(), state
);
170 string
ExecutableTool::encode() const
175 string
ExecutableTool::canonicalPath() const
184 GenericBundle::GenericBundle(const char *path
) : mPath(path
)
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
);
192 GenericBundle::~GenericBundle()
198 void GenericBundle::scanContents(Signer::State
&state
) const
200 scanFile(executablePath().c_str(), state
);
203 string
GenericBundle::encode() const
208 void *GenericBundle::lookupSymbol(const char *name
)
210 CFRef
<CFStringRef
> cfName(CFStringCreateWithCString(NULL
, name
,
211 kCFStringEncodingMacRoman
));
213 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT
);
214 void *function
= CFBundleGetFunctionPointerForName(mBundle
, cfName
);
215 if (function
== NULL
)
216 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT
);
220 string
GenericBundle::canonicalPath() const
227 // Load management for a loadable bundle
229 void LoadableBundle::load()
231 if (!CFBundleLoadExecutable(mBundle
))
232 CssmError::throwMe(CSSMERR_CSSM_ADDIN_LOAD_FAILED
);
233 secdebug("bundle", "%p (%s) loaded", this, path().c_str());
236 void LoadableBundle::unload()
238 secdebug("bundle", "%p (%s) unloaded", this, path().c_str());
239 CFBundleUnloadExecutable(mBundle
);
242 bool LoadableBundle::isLoaded() const
244 return CFBundleIsExecutableLoaded(mBundle
);
248 }; // end namespace CodeSigning
250 } // end namespace Security