X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_codesigning/lib/filediskrep.cpp diff --git a/libsecurity_codesigning/lib/filediskrep.cpp b/libsecurity_codesigning/lib/filediskrep.cpp new file mode 100644 index 00000000..7a098c22 --- /dev/null +++ b/libsecurity_codesigning/lib/filediskrep.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The 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. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#include "filediskrep.h" +#include "StaticCode.h" +#include +#include + + +namespace Security { +namespace CodeSigning { + +using namespace UnixPlusPlus; + + +// +// Everything's lazy in here +// +FileDiskRep::FileDiskRep(const char *path) + : SingleDiskRep(path) +{ + CODESIGN_DISKREP_CREATE_FILE(this, (char*)path); +} + + +// +// Produce an extended attribute name from a canonical slot name +// +string FileDiskRep::attrName(const char *name) +{ + static const char prefix[] = "com.apple.cs."; + return string(prefix) + name; +} + + +// +// Retrieve an extended attribute by name +// +CFDataRef FileDiskRep::getAttribute(const char *name) +{ + string aname = attrName(name); + try { + ssize_t length = fd().getAttrLength(aname); + if (length < 0) + return NULL; // no such attribute + CFMallocData buffer(length); + fd().getAttr(aname, buffer, length); + return buffer; + } catch (const UnixError &err) { + // recover some errors that happen in (relatively) benign circumstances + switch (err.error) { + case ENOTSUP: // no extended attributes on this filesystem + case EPERM: // filesystem objects to name(?) + return NULL; + default: + throw; + } + } +} + + +// +// Extract and return a component by slot number. +// If we have a Mach-O binary, use embedded components. +// Otherwise, look for and return the extended attribute, if any. +// +CFDataRef FileDiskRep::component(CodeDirectory::SpecialSlot slot) +{ + if (const char *name = CodeDirectory::canonicalSlotName(slot)) + return getAttribute(name); + else + return NULL; +} + + +// +// Generate a suggested set of internal requirements. +// We don't really have to say much. However, if we encounter a file that +// starts with the magic "#!" script marker, we do suggest that this should +// be a valid host if we can reasonably make out what that is. +// +const Requirements *FileDiskRep::defaultRequirements(const Architecture *, const SigningContext &ctx) +{ + // read start of file + char buffer[256]; + size_t length = fd().read(buffer, sizeof(buffer), 0); + if (length > 3 && buffer[0] == '#' && buffer[1] == '!' && buffer[2] == '/') { + // isolate (full) path element in #!/full/path -some -other -stuff + if (length == sizeof(buffer)) + length--; + buffer[length] = '\0'; + char *cmd = buffer + 2; + cmd[strcspn(cmd, " \t\n\r\f")] = '\0'; + secdebug("filediskrep", "looks like a script for %s", cmd); + if (cmd[1]) + try { + // find path on disk, get designated requirement (if signed) + string path = ctx.sdkPath(cmd); + if (RefPointer rep = DiskRep::bestFileGuess(path)) + if (SecPointer code = new SecStaticCode(rep)) + if (const Requirement *req = code->designatedRequirement()) { + CODESIGN_SIGN_DEP_INTERP(this, (char*)cmd, (void*)req); + // package up as host requirement and return that + Requirements::Maker maker; + maker.add(kSecHostRequirementType, req->clone()); + return maker.make(); + } + } catch (...) { + secdebug("filediskrep", "exception getting host requirement (ignored)"); + } + } + return NULL; +} + + +string FileDiskRep::format() +{ + return "generic"; +} + + +// +// FileDiskRep::Writers +// +DiskRep::Writer *FileDiskRep::writer() +{ + return new Writer(this); +} + + +// +// Write a component. +// Note that this isn't concerned with Mach-O writing; this is handled at +// a much higher level. If we're called, it's extended attribute time. +// +void FileDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data) +{ + try { + fd().setAttr(attrName(CodeDirectory::canonicalSlotName(slot)), + CFDataGetBytePtr(data), CFDataGetLength(data)); + } catch (const UnixError &error) { + if (error.error == ERANGE) + MacOSError::throwMe(errSecCSCMSTooLarge); + throw; + } +} + + +// +// Clear all signing data +// +void FileDiskRep::Writer::remove() +{ + for (CodeDirectory::SpecialSlot slot = 0; slot < cdSlotCount; slot++) + if (const char *name = CodeDirectory::canonicalSlotName(slot)) + fd().removeAttr(attrName(name)); + fd().removeAttr(attrName(kSecCS_SIGNATUREFILE)); +} + + +// +// We are NOT the preferred store for components because our approach +// (extended attributes) suffers from some serious limitations. +// +bool FileDiskRep::Writer::preferredStore() +{ + return false; +} + + +} // end namespace CodeSigning +} // end namespace Security