2  * Copyright (c) 2006-2007,2011,2013-2014 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@ 
  25 // diskrep - disk representations of code 
  29 #include <CoreFoundation/CFBundlePriv.h> 
  31 // specific disk representations created by the bestGuess() function 
  32 #include "filediskrep.h" 
  33 #include "bundlediskrep.h" 
  38 namespace CodeSigning 
{ 
  40 using namespace UnixPlusPlus
; 
  52         CODESIGN_DISKREP_DESTROY(this); 
  57 // Normal DiskReps are their own base. 
  59 DiskRep 
*DiskRep::base() 
  66 // By default, DiskReps are read-only. 
  68 DiskRep::Writer 
*DiskRep::writer() 
  70         MacOSError::throwMe(errSecCSUnimplemented
); 
  74 void DiskRep::Writer::addDiscretionary(CodeDirectory::Builder 
&) 
  81 // Given a file system path, come up with the most likely correct 
  82 // disk representation for what's there. 
  83 // This is, strictly speaking, a heuristic that could be fooled - there's 
  84 // no fool-proof rule for figuring this out. But we'd expect this to work 
  85 // fine in ordinary use. If you happen to know what you're looking at 
  86 // (say, a bundle), then just create the suitable subclass of DiskRep directly. 
  87 // That's quite legal. 
  88 // The optional context argument can provide additional information that guides the guess. 
  90 DiskRep 
*DiskRep::bestGuess(const char *path
, const Context 
*ctx
) 
  93                 if (!(ctx 
&& ctx
->fileOnly
)) { 
  95                         if (::stat(path
, &st
)) 
  98                         // if it's a directory, assume it's a bundle 
  99                         if ((st
.st_mode 
& S_IFMT
) == S_IFDIR
)   // directory - assume bundle 
 100                                 return new BundleDiskRep(path
, ctx
); 
 102                         // see if it's the main executable of a recognized bundle 
 103                         if (CFRef
<CFURLRef
> pathURL 
= makeCFURL(path
)) 
 104                                 if (CFRef
<CFBundleRef
> bundle 
= _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL
, pathURL
)) 
 105                                                 return new BundleDiskRep(bundle
, ctx
); 
 108                 // try the various single-file representations 
 109                 AutoFileDesc 
fd(path
, O_RDONLY
); 
 110                 if (MachORep::candidate(fd
)) 
 111                         return new MachORep(path
, ctx
); 
 112                 if (DYLDCacheRep::candidate(fd
)) 
 113                         return new DYLDCacheRep(path
); 
 115                 // ultimate fallback - the generic file representation 
 116                 return new FileDiskRep(path
); 
 118         } catch (const CommonError 
&error
) { 
 119                 switch (error
.unixError()) { 
 121                         MacOSError::throwMe(errSecCSStaticCodeNotFound
); 
 129 DiskRep 
*DiskRep::bestFileGuess(const char *path
, const Context 
*ctx
) 
 134         dctx
.fileOnly 
= true; 
 135         return bestGuess(path
, &dctx
); 
 140 // Given a main executable known to be a Mach-O binary, and an offset into 
 141 // the file of the actual architecture desired (of a Universal file), 
 142 // produce a suitable MachORep. 
 143 // This function does not consider non-MachO binaries. It does however handle 
 144 // bundles with Mach-O main executables correctly. 
 146 DiskRep 
*DiskRep::bestGuess(const char *path
, size_t archOffset
) 
 149                 // is it the main executable of a bundle? 
 150                 if (CFRef
<CFURLRef
> pathURL 
= makeCFURL(path
)) 
 151                         if (CFRef
<CFBundleRef
> bundle 
= _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL
, pathURL
)) { 
 152                                 Context ctx
; ctx
.offset 
= archOffset
; 
 153                                 return new BundleDiskRep(bundle
, &ctx
); // ask bundle to make bundle-with-MachO-at-offset 
 155                 // else, must be a Mach-O binary 
 156                 Context ctx
; ctx
.offset 
= archOffset
; 
 157                 return new MachORep(path
, &ctx
); 
 158         } catch (const CommonError 
&error
) { 
 159                 switch (error
.unixError()) { 
 161                         MacOSError::throwMe(errSecCSStaticCodeNotFound
); 
 170 // Default behaviors of DiskRep 
 172 string 
DiskRep::resourcesRootPath() 
 174         return "";              // has no resources directory 
 177 void DiskRep::adjustResources(ResourceBuilder 
&builder
) 
 182 Universal 
*DiskRep::mainExecutableImage() 
 184         return NULL
;    // no Mach-O executable 
 187 size_t DiskRep::signingBase() 
 189         return 0;               // whole file (start at beginning) 
 192 CFArrayRef 
DiskRep::modifiedFiles() 
 194         // by default, claim (just) the main executable modified 
 195         CFRef
<CFURLRef
> mainURL 
= makeCFURL(mainExecutablePath()); 
 196         return makeCFArray(1, mainURL
.get()); 
 199 void DiskRep::flush() 
 205 CFDictionaryRef 
DiskRep::defaultResourceRules(const SigningContext 
&) 
 210 const Requirements 
*DiskRep::defaultRequirements(const Architecture 
*, const SigningContext 
&) 
 215 size_t DiskRep::pageSize(const SigningContext 
&) 
 217         return monolithicPageSize
;      // unpaged (monolithic) 
 221 void DiskRep::strictValidate(const CodeDirectory
*, const ToleratedErrors
&) 
 226 CFArrayRef 
DiskRep::allowedResourceOmissions() 
 233 // Given some string (usually a pathname), derive a suggested signing identifier 
 234 // in a canonical way (so there's some consistency). 
 236 // This is a heuristic. First we lop off any leading directories and final (non-numeric) 
 237 // extension. Then we walk backwards, eliminating numeric extensions except the first one. 
 238 // Thus, libfrotz7.3.5.dylib becomes libfrotz7, mumble.77.plugin becomes mumble.77, 
 239 // and rumble.rb becomes rumble. This isn't perfect, but it ought to handle 98%+ of 
 240 // the common varieties out there. Specify an explicit identifier for the oddballs. 
 242 // This is called by the various recommendedIdentifier() methods, who are 
 243 // free to modify or override it. 
 245 // Note: We use strchr("...") instead of is*() here because we do not 
 246 // wish to be influenced by locale settings. 
 248 std::string 
DiskRep::canonicalIdentifier(const std::string 
&name
) 
 253         // lop off any directory prefixes 
 254         if ((p 
= s
.rfind('/')) != string::npos
) 
 257         // remove any final extension (last dot) unless it's numeric 
 258         if ((p 
= s
.rfind('.')) != string::npos 
&& !strchr("0123456789", s
[p
+1])) 
 261         // eat numeric suffixes except the first one; roughly: 
 262         // foo.2.3.4 => foo.2, foo2.3 => foo2, foo.9 => foo.9, foo => foo 
 263         if (strchr("0123456789.", s
[0]))                        // starts with digit or . 
 264                 return s
;                                                               // ... so don't mess with it 
 266         // foo3.5^, foo.3.5^, foo3^, foo.3^, foo^ 
 267         while (strchr("0123456789.", s
[p
])) 
 269         // fo^o3.5, fo^o.3.5, fo^o3, fo^o.3, fo^o 
 271         // foo^3.5, foo^.3.5, foo^3, foo^.3, foo^ 
 274         // foo^3.5, foo.^3.5, foo^3, foo.^3, foo^ 
 275         while (p 
< s
.size() && strchr("0123456789", s
[p
])) 
 277         // foo3^.5, foo.3^.5, foo3^, foo.3^, foo^ 
 278         return s
.substr(0, p
); 
 285 DiskRep::Writer::Writer(uint32_t attrs
) 
 286         : mArch(CPU_TYPE_ANY
), mAttributes(attrs
) 
 290 DiskRep::Writer::~Writer() 
 293 uint32_t DiskRep::Writer::attributes() const 
 294 { return mAttributes
; } 
 296 void DiskRep::Writer::flush() 
 299 void DiskRep::Writer::remove() 
 301         MacOSError::throwMe(errSecCSNotSupported
); 
 305 } // end namespace CodeSigning 
 306 } // end namespace Security