+++ /dev/null
-/*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
- *
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-//
-// osxcode - MacOS X's standard code objects
-//
-#include <security_utilities/osxcode.h>
-#include <security_utilities/unix++.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <CoreFoundation/CFBundle.h>
-#include <CoreFoundation/CFBundlePriv.h>
-
-
-namespace Security {
-
-
-//
-// Produce an OSXCode for the currently running application.
-//
-// Note that we don't build the CFBundleRef here; we defer this to when we
-// really need it for something more interesting than the base or executable paths.
-// This is important because OSXCode::main() is called from various initialization
-// scenarios (out of the securityd client layer), and CFBundle calls into some
-// bizarrely high-level APIs to complete CFBundleGetMainBundle. Until that is fixed
-// (if it ever is), this particular instance of laziness is mandatory.
-//
-RefPointer<OSXCode> OSXCode::main()
-{
- // return a code signing-aware OSXCode subclass if possible
- CFRef<SecCodeRef> me;
- if (!SecCodeCopySelf(kSecCSDefaultFlags, &me.aref()))
- return new OSXCodeWrap(me);
-
- // otherwise, follow the legacy path precisely - no point in messing with this, is there?
- Boolean isRealBundle;
- string path = cfStringRelease(_CFBundleCopyMainBundleExecutableURL(&isRealBundle));
- if (isRealBundle) {
- const char *cpath = path.c_str();
- if (const char *slash = strrchr(cpath, '/'))
- if (const char *contents = strstr(cpath, "/Contents/MacOS/"))
- if (contents + 15 == slash)
- return new Bundle(path.substr(0, contents-cpath).c_str());
- secdebug("bundle", "OSXCode::main(%s) not recognized as bundle (treating as tool)", cpath);
- }
- return new ExecutableTool(path.c_str());
-}
-
-
-SecStaticCodeRef OSXCode::codeRef() const
-{
- SecStaticCodeRef code;
- MacOSError::check(SecStaticCodeCreateWithPath(CFTempURL(this->canonicalPath()), kSecCSDefaultFlags, &code));
- return code;
-}
-
-
-//
-// Produce an OSXCode for whatever is at a given path.
-// This tries to guess at the type of OSXCode to be used.
-// If you *know*, just create the suitable subclass directly.
-//
-RefPointer<OSXCode> OSXCode::at(const char *path)
-{
- CFRef<SecStaticCodeRef> code;
- if (!SecStaticCodeCreateWithPath(CFTempURL(path), kSecCSDefaultFlags, &code.aref()))
- return new OSXCodeWrap(code);
-
- struct stat st;
- // otherwise, follow the legacy path precisely - no point in messing with this, is there?
- if (stat(path, &st))
- UnixError::throwMe();
- if ((st.st_mode & S_IFMT) == S_IFDIR) { // directory - assume bundle
- return new Bundle(path);
- } else {
- // look for .../Contents/MacOS/<base>
- if (const char *slash = strrchr(path, '/'))
- if (const char *contents = strstr(path, "/Contents/MacOS/"))
- if (contents + 15 == slash)
- return new Bundle(string(path).substr(0, contents-path).c_str(), path);
- // assume tool (single executable)
- return new ExecutableTool(path);
- }
-}
-
-
-//
-// Executable Tools
-//
-string ExecutableTool::canonicalPath() const
-{
- return path();
-}
-
-string ExecutableTool::executablePath() const
-{
- return path();
-}
-
-
-//
-// Generic Bundles
-//
-Bundle::Bundle(const char *path, const char *execPath /* = NULL */)
- : mPath(path), mBundle(NULL)
-{
- if (execPath) // caller knows that one; set it
- mExecutablePath = execPath;
- secdebug("bundle", "%p Bundle from path %s(%s)", this, path, executablePath().c_str());
-}
-
-Bundle::Bundle(CFBundleRef bundle, const char *root /* = NULL */)
- : mBundle(bundle)
-{
- assert(bundle);
- CFRetain(bundle);
- mPath = root ? root : cfStringRelease(CFBundleCopyBundleURL(mBundle));
- secdebug("bundle", "%p Bundle from bundle %p(%s)", this, bundle, mPath.c_str());
-}
-
-
-Bundle::~Bundle()
-{
- if (mBundle)
- CFRelease(mBundle);
-}
-
-
-string Bundle::executablePath() const
-{
- if (mExecutablePath.empty())
- return mExecutablePath = cfStringRelease(CFBundleCopyExecutableURL(cfBundle()));
- else
- return mExecutablePath;
-}
-
-
-CFBundleRef Bundle::cfBundle() const
-{
- if (!mBundle) {
- secdebug("bundle", "instantiating CFBundle for %s", mPath.c_str());
- CFRef<CFURLRef> url = CFURLCreateFromFileSystemRepresentation(NULL,
- (const UInt8 *)mPath.c_str(), mPath.length(), true);
- if (!url || !(mBundle = CFBundleCreate(NULL, url)))
- CFError::throwMe();
- }
- return mBundle;
-}
-
-
-CFTypeRef Bundle::infoPlistItem(const char *name) const
-{
- return CFBundleGetValueForInfoDictionaryKey(cfBundle(), CFTempString(name));
-}
-
-
-void *Bundle::lookupSymbol(const char *name)
-{
- CFRef<CFStringRef> cfName(CFStringCreateWithCString(NULL, name,
- kCFStringEncodingMacRoman));
- if (!cfName)
- UnixError::throwMe(EBADEXEC); // sort of
- void *function = CFBundleGetFunctionPointerForName(cfBundle(), cfName);
- if (function == NULL)
- UnixError::throwMe(EBADEXEC); // sort of
- return function;
-}
-
-string Bundle::canonicalPath() const
-{
- return path();
-}
-
-
-string Bundle::resource(const char *name, const char *type, const char *subdir)
-{
- return cfStringRelease(CFBundleCopyResourceURL(cfBundle(),
- CFTempString(name), CFTempString(type), CFTempString(subdir)));
-}
-
-void Bundle::resources(vector<string> &paths, const char *type, const char *subdir)
-{
- CFRef<CFArrayRef> cfList = CFBundleCopyResourceURLsOfType(cfBundle(),
- CFTempString(type), CFTempString(subdir));
- UInt32 size = CFArrayGetCount(cfList);
- paths.reserve(size);
- for (UInt32 n = 0; n < size; n++)
- paths.push_back(cfString(CFURLRef(CFArrayGetValueAtIndex(cfList, n))));
-}
-
-
-//
-// Load management for a loadable bundle
-//
-void LoadableBundle::load()
-{
- if (!CFBundleLoadExecutable(cfBundle()))
- CFError::throwMe();
- secdebug("bundle", "%p (%s) loaded", this, path().c_str());
-}
-
-void LoadableBundle::unload()
-{
- secdebug("bundle", "%p (%s) unloaded", this, path().c_str());
- CFBundleUnloadExecutable(cfBundle());
-}
-
-bool LoadableBundle::isLoaded() const
-{
- return CFBundleIsExecutableLoaded(cfBundle());
-}
-
-
-//
-// OSXCodeWrap
-//
-string OSXCodeWrap::canonicalPath() const
-{
- CFURLRef path;
- MacOSError::check(SecCodeCopyPath(mCode, kSecCSDefaultFlags, &path));
- return cfStringRelease(path);
-}
-
-
-//
-// The executable path is a bit annoying to get, but not quite
-// annoying enough to cache the result.
-//
-string OSXCodeWrap::executablePath() const
-{
- CFRef<CFDictionaryRef> info;
- MacOSError::check(SecCodeCopySigningInformation(mCode, kSecCSDefaultFlags, &info.aref()));
- return cfString(CFURLRef(CFDictionaryGetValue(info, kSecCodeInfoMainExecutable)));
-}
-
-SecStaticCodeRef OSXCodeWrap::codeRef() const
-{
- return mCode.retain();
-}
-
-
-} // end namespace Security