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 debug("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
);
150 } else { // not directory - assume tool
151 return new ExecutableTool(path
);
159 void ExecutableTool::scanContents(Signer::State
&state
) const
161 scanFile(mPath
.c_str(), state
);
164 string
ExecutableTool::encode() const
169 string
ExecutableTool::canonicalPath() const
178 GenericBundle::GenericBundle(const char *path
) : mPath(path
)
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
);
186 GenericBundle::~GenericBundle()
192 void GenericBundle::scanContents(Signer::State
&state
) const
194 scanFile(executablePath().c_str(), state
);
197 string
GenericBundle::encode() const
202 void *GenericBundle::lookupSymbol(const char *name
)
204 CFRef
<CFStringRef
> cfName(CFStringCreateWithCString(NULL
, name
,
205 kCFStringEncodingMacRoman
));
207 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT
);
208 void *function
= CFBundleGetFunctionPointerForName(mBundle
, cfName
);
209 if (function
== NULL
)
210 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT
);
214 string
GenericBundle::canonicalPath() const
221 // Load management for a loadable bundle
223 void LoadableBundle::load()
225 if (!CFBundleLoadExecutable(mBundle
))
226 CssmError::throwMe(CSSMERR_CSSM_ADDIN_LOAD_FAILED
);
227 IFDEBUG(debug("bundle", "%p (%s) loaded", this, path().c_str()));
230 void LoadableBundle::unload()
232 IFDEBUG(debug("bundle", "%p (%s) unloaded", this, path().c_str()));
233 CFBundleUnloadExecutable(mBundle
);
236 bool LoadableBundle::isLoaded() const
238 return CFBundleIsExecutableLoaded(mBundle
);
242 }; // end namespace CodeSigning
244 } // end namespace Security