]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/filediskrep.cpp
2 * Copyright (c) 2006-2007,2011 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 #include "filediskrep.h"
24 #include "StaticCode.h"
25 #include <security_utilities/macho++.h>
30 namespace CodeSigning
{
32 using namespace UnixPlusPlus
;
36 // Everything's lazy in here
38 FileDiskRep::FileDiskRep(const char *path
)
41 CODESIGN_DISKREP_CREATE_FILE(this, (char*)path
);
46 // Produce an extended attribute name from a canonical slot name
48 string
FileDiskRep::attrName(const char *name
)
50 static const char prefix
[] = "com.apple.cs.";
51 return string(prefix
) + name
;
56 // Retrieve an extended attribute by name
58 CFDataRef
FileDiskRep::getAttribute(const char *name
)
60 string aname
= attrName(name
);
62 ssize_t length
= fd().getAttrLength(aname
);
64 return NULL
; // no such attribute
65 CFMallocData
buffer(length
);
66 fd().getAttr(aname
, buffer
, length
);
68 } catch (const UnixError
&err
) {
69 // recover some errors that happen in (relatively) benign circumstances
71 case ENOTSUP
: // no extended attributes on this filesystem
72 case EPERM
: // filesystem objects to name(?)
82 // Extract and return a component by slot number.
83 // If we have a Mach-O binary, use embedded components.
84 // Otherwise, look for and return the extended attribute, if any.
86 CFDataRef
FileDiskRep::component(CodeDirectory::SpecialSlot slot
)
88 if (const char *name
= CodeDirectory::canonicalSlotName(slot
))
89 return getAttribute(name
);
96 // Generate a suggested set of internal requirements.
97 // We don't really have to say much. However, if we encounter a file that
98 // starts with the magic "#!" script marker, we do suggest that this should
99 // be a valid host if we can reasonably make out what that is.
101 const Requirements
*FileDiskRep::defaultRequirements(const Architecture
*, const SigningContext
&ctx
)
103 // read start of file
105 size_t length
= fd().read(buffer
, sizeof(buffer
), 0);
106 if (length
> 3 && buffer
[0] == '#' && buffer
[1] == '!' && buffer
[2] == '/') {
107 // isolate (full) path element in #!/full/path -some -other -stuff
108 if (length
== sizeof(buffer
))
110 buffer
[length
] = '\0';
111 char *cmd
= buffer
+ 2;
112 cmd
[strcspn(cmd
, " \t\n\r\f")] = '\0';
113 secinfo("filediskrep", "looks like a script for %s", cmd
);
116 // find path on disk, get designated requirement (if signed)
117 string path
= ctx
.sdkPath(cmd
);
118 if (RefPointer
<DiskRep
> rep
= DiskRep::bestFileGuess(path
))
119 if (SecPointer
<SecStaticCode
> code
= new SecStaticCode(rep
))
120 if (const Requirement
*req
= code
->designatedRequirement()) {
121 CODESIGN_SIGN_DEP_INTERP(this, (char*)cmd
, (void*)req
);
122 // package up as host requirement and return that
123 Requirements::Maker maker
;
124 maker
.add(kSecHostRequirementType
, req
->clone());
128 secinfo("filediskrep", "exception getting host requirement (ignored)");
135 string
FileDiskRep::format()
141 // FileDiskRep::Writers
143 DiskRep::Writer
*FileDiskRep::writer()
145 return new Writer(this);
150 // Write a component.
151 // Note that this isn't concerned with Mach-O writing; this is handled at
152 // a much higher level. If we're called, it's extended attribute time.
154 void FileDiskRep::Writer::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
157 std::string name
= attrName(CodeDirectory::canonicalSlotName(slot
));
158 fd().setAttr(name
, CFDataGetBytePtr(data
), CFDataGetLength(data
));
159 mWrittenAttributes
.insert(name
);
160 } catch (const UnixError
&error
) {
161 if (error
.error
== ERANGE
)
162 MacOSError::throwMe(errSecCSCMSTooLarge
);
168 void FileDiskRep::Writer::flush()
170 size_t size
= fd().listAttr(NULL
, 0);
171 std::vector
<char> buffer(size
);
172 char *s
= &buffer
[0];
173 char *end
= &buffer
[size
];
174 fd().listAttr(s
, size
);
176 std::string name
= s
;
177 s
+= strlen(s
) + 1; // skip to next
178 if (name
.compare(0, 13, "com.apple.cs.") == 0) // one of ours
179 if (mWrittenAttributes
.find(name
) == mWrittenAttributes
.end()) { // not written by this signing operation
180 fd().removeAttr(name
);
187 // Clear all signing data
189 void FileDiskRep::Writer::remove()
191 for (CodeDirectory::SpecialSlot slot
= 0; slot
< cdSlotCount
; slot
++)
192 if (const char *name
= CodeDirectory::canonicalSlotName(slot
))
193 fd().removeAttr(attrName(name
));
194 fd().removeAttr(attrName(kSecCS_SIGNATUREFILE
));
199 // We are NOT the preferred store for components because our approach
200 // (extended attributes) suffers from some serious limitations.
202 bool FileDiskRep::Writer::preferredStore()
208 } // end namespace CodeSigning
209 } // end namespace Security