]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/filediskrep.cpp
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / filediskrep.cpp
1 /*
2 * Copyright (c) 2006-2007,2011 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include "filediskrep.h"
24 #include "StaticCode.h"
25 #include <security_utilities/macho++.h>
26 #include <cstring>
27
28
29 namespace Security {
30 namespace CodeSigning {
31
32 using namespace UnixPlusPlus;
33
34
35 //
36 // Everything's lazy in here
37 //
38 FileDiskRep::FileDiskRep(const char *path)
39 : SingleDiskRep(path)
40 {
41 CODESIGN_DISKREP_CREATE_FILE(this, (char*)path);
42 }
43
44
45 //
46 // Produce an extended attribute name from a canonical slot name
47 //
48 string FileDiskRep::attrName(const char *name)
49 {
50 static const char prefix[] = "com.apple.cs.";
51 return string(prefix) + name;
52 }
53
54
55 //
56 // Retrieve an extended attribute by name
57 //
58 CFDataRef FileDiskRep::getAttribute(const char *name)
59 {
60 string aname = attrName(name);
61 try {
62 ssize_t length = fd().getAttrLength(aname);
63 if (length < 0)
64 return NULL; // no such attribute
65 CFMallocData buffer(length);
66 fd().getAttr(aname, buffer, length);
67 return buffer;
68 } catch (const UnixError &err) {
69 // recover some errors that happen in (relatively) benign circumstances
70 switch (err.error) {
71 case ENOTSUP: // no extended attributes on this filesystem
72 case EPERM: // filesystem objects to name(?)
73 return NULL;
74 default:
75 throw;
76 }
77 }
78 }
79
80
81 //
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.
85 //
86 CFDataRef FileDiskRep::component(CodeDirectory::SpecialSlot slot)
87 {
88 if (const char *name = CodeDirectory::canonicalSlotName(slot))
89 return getAttribute(name);
90 else
91 return NULL;
92 }
93
94
95 //
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.
100 //
101 const Requirements *FileDiskRep::defaultRequirements(const Architecture *, const SigningContext &ctx)
102 {
103 // read start of file
104 char buffer[256];
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))
109 length--;
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);
114 if (cmd[1])
115 try {
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());
125 return maker.make();
126 }
127 } catch (...) {
128 secinfo("filediskrep", "exception getting host requirement (ignored)");
129 }
130 }
131 return NULL;
132 }
133
134
135 string FileDiskRep::format()
136 {
137 return "generic";
138 }
139
140 //
141 // FileDiskRep::Writers
142 //
143 DiskRep::Writer *FileDiskRep::writer()
144 {
145 return new Writer(this);
146 }
147
148
149 //
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.
153 //
154 void FileDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
155 {
156 try {
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);
163 throw;
164 }
165 }
166
167
168 void FileDiskRep::Writer::flush()
169 {
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);
175 while (s < end) {
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);
181 }
182 }
183 }
184
185
186 //
187 // Clear all signing data
188 //
189 void FileDiskRep::Writer::remove()
190 {
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));
195 }
196
197
198 //
199 // We are NOT the preferred store for components because our approach
200 // (extended attributes) suffers from some serious limitations.
201 //
202 bool FileDiskRep::Writer::preferredStore()
203 {
204 return false;
205 }
206
207
208 } // end namespace CodeSigning
209 } // end namespace Security