]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2006-2007 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 | secdebug("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 | secdebug("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 | // | |
142 | // FileDiskRep::Writers | |
143 | // | |
144 | DiskRep::Writer *FileDiskRep::writer() | |
145 | { | |
146 | return new Writer(this); | |
147 | } | |
148 | ||
149 | ||
150 | // | |
151 | // Write a component. | |
152 | // Note that this isn't concerned with Mach-O writing; this is handled at | |
153 | // a much higher level. If we're called, it's extended attribute time. | |
154 | // | |
155 | void FileDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data) | |
156 | { | |
157 | try { | |
158 | fd().setAttr(attrName(CodeDirectory::canonicalSlotName(slot)), | |
159 | CFDataGetBytePtr(data), CFDataGetLength(data)); | |
160 | } catch (const UnixError &error) { | |
161 | if (error.error == ERANGE) | |
162 | MacOSError::throwMe(errSecCSCMSTooLarge); | |
163 | throw; | |
164 | } | |
165 | } | |
166 | ||
167 | ||
168 | // | |
169 | // Clear all signing data | |
170 | // | |
171 | void FileDiskRep::Writer::remove() | |
172 | { | |
173 | for (CodeDirectory::SpecialSlot slot = 0; slot < cdSlotCount; slot++) | |
174 | if (const char *name = CodeDirectory::canonicalSlotName(slot)) | |
175 | fd().removeAttr(attrName(name)); | |
176 | fd().removeAttr(attrName(kSecCS_SIGNATUREFILE)); | |
177 | } | |
178 | ||
179 | ||
180 | // | |
181 | // We are NOT the preferred store for components because our approach | |
182 | // (extended attributes) suffers from some serious limitations. | |
183 | // | |
184 | bool FileDiskRep::Writer::preferredStore() | |
185 | { | |
186 | return false; | |
187 | } | |
188 | ||
189 | ||
190 | } // end namespace CodeSigning | |
191 | } // end namespace Security |