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.
23 #define _CPP_OSXSIGNING
26 #include <Security/osxsigning.h>
28 #include <sys/types.h>
32 #include <CoreFoundation/CFBundle.h>
42 // Enumerate a single file on disk.
44 void OSXCode::scanFile(const char *pathname
, Signer::State
&state
)
46 // open the file (well, try)
47 int fd
= open(pathname
, O_RDONLY
);
57 #if defined(LIMITED_SIGNING)
58 if (st
.st_size
>= 0x4000)
63 void *p
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_FILE
, fd
, 0);
64 close(fd
); // done with this either way
69 debug("codesign", "scanning file %s (%ld bytes)", pathname
, long(st
.st_size
));
70 state
.enumerateContents(p
, st
.st_size
);
72 // unmap it (ignore error)
73 munmap(p
, st
.st_size
);
78 // Use prefix encoding for externalizing OSXCode objects
80 OSXCode
*OSXCode::decode(const char *extForm
)
82 if (!extForm
|| !extForm
[0] || extForm
[1] != ':')
86 return new ExecutableTool(extForm
+2);
88 return new GenericBundle(extForm
+2);
96 // Produce a Signable for the currently running application
98 OSXCode
*OSXCode::main()
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());
109 // too weird; assume this is a single-file "tool" executable
110 return new ExecutableTool(getPath(CFBundleCopyExecutableURL(mainBundle
)).c_str());
112 // CF gives no error indications...
113 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
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
120 extern "C" CFStringRef
CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator
,
121 CFURLRef anURL
, CFURLPathStyle fsType
, Boolean resolveAgainstBase
);
123 string
OSXCode::getPath(CFURLRef url
)
126 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
); // source CF call failed
128 CFRef
<CFStringRef
> str(CFURLCreateStringWithFileSystemPath(NULL
,
129 url
, kCFURLPOSIXPathStyle
, true));
133 if (CFStringGetCString(str
, path
, PATH_MAX
, kCFStringEncodingUTF8
))
136 // no error indications from CF...
137 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
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.
146 OSXCode
*OSXCode::at(const char *path
)
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
);
162 void ExecutableTool::scanContents(Signer::State
&state
) const
164 scanFile(mPath
.c_str(), state
);
167 string
ExecutableTool::encode() const
172 string
ExecutableTool::canonicalPath() const
181 GenericBundle::GenericBundle(const char *path
) : mPath(path
)
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
);
189 GenericBundle::~GenericBundle()
195 void GenericBundle::scanContents(Signer::State
&state
) const
197 scanFile(executablePath().c_str(), state
);
200 string
GenericBundle::encode() const
205 void *GenericBundle::lookupSymbol(const char *name
)
207 CFRef
<CFStringRef
> cfName(CFStringCreateWithCString(NULL
, name
,
208 kCFStringEncodingMacRoman
));
210 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT
);
211 void *function
= CFBundleGetFunctionPointerForName(mBundle
, cfName
);
212 if (function
== NULL
)
213 CssmError::throwMe(CSSM_ERRCODE_UNKNOWN_FORMAT
);
217 string
GenericBundle::canonicalPath() const
224 // Load management for a loadable bundle
226 void LoadableBundle::load()
228 if (!CFBundleLoadExecutable(mBundle
))
229 CssmError::throwMe(CSSMERR_CSSM_ADDIN_LOAD_FAILED
);
230 IFDEBUG(debug("bundle", "%p (%s) loaded", this, path().c_str()));
233 void LoadableBundle::unload()
235 IFDEBUG(debug("bundle", "%p (%s) unloaded", this, path().c_str()));
236 CFBundleUnloadExecutable(mBundle
);
239 bool LoadableBundle::isLoaded() const
241 return CFBundleIsExecutableLoaded(mBundle
);
245 }; // end namespace CodeSigning
247 } // end namespace Security