]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_codesigning/lib/filediskrep.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_codesigning / lib / filediskrep.cpp
diff --git a/Security/libsecurity_codesigning/lib/filediskrep.cpp b/Security/libsecurity_codesigning/lib/filediskrep.cpp
new file mode 100644 (file)
index 0000000..d0e294d
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2006-2007,2011 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 <security_utilities/macho++.h>
+#include <cstring>
+
+
+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<DiskRep> rep = DiskRep::bestFileGuess(path))
+                                       if (SecPointer<SecStaticCode> 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