1 /* ldid - (Mach-O) Link-Loader Identity Editor 
   2  * Copyright (C) 2007-2015  Jay Freeman (saurik) 
   5 /* GNU Affero General Public License, Version 3 {{{ */ 
   7  * This program is free software: you can redistribute it and/or modify 
   8  * it under the terms of the GNU Affero General Public License as published by 
   9  * the Free Software Foundation, either version 3 of the License, or 
  10  * (at your option) any later version. 
  12  * This program is distributed in the hope that it will be useful, 
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  * GNU Affero General Public License for more details. 
  17  * You should have received a copy of the GNU Affero General Public License 
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  43 #include <sys/types.h> 
  46 #include <openssl/err.h> 
  47 #include <openssl/pem.h> 
  48 #include <openssl/pkcs7.h> 
  49 #include <openssl/pkcs12.h> 
  53 #include <CommonCrypto/CommonDigest.h> 
  55 #define LDID_SHA1_DIGEST_LENGTH CC_SHA1_DIGEST_LENGTH 
  56 #define LDID_SHA1 CC_SHA1 
  57 #define LDID_SHA1_CTX CC_SHA1_CTX 
  58 #define LDID_SHA1_Init CC_SHA1_Init 
  59 #define LDID_SHA1_Update CC_SHA1_Update 
  60 #define LDID_SHA1_Final CC_SHA1_Final 
  62 #define LDID_SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH 
  63 #define LDID_SHA256 CC_SHA256 
  64 #define LDID_SHA256_CTX CC_SHA256_CTX 
  65 #define LDID_SHA256_Init CC_SHA256_Init 
  66 #define LDID_SHA256_Update CC_SHA256_Update 
  67 #define LDID_SHA256_Final CC_SHA256_Final 
  69 #include <openssl/sha.h> 
  71 #define LDID_SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH 
  72 #define LDID_SHA1 SHA1 
  73 #define LDID_SHA1_CTX SHA_CTX 
  74 #define LDID_SHA1_Init SHA1_Init 
  75 #define LDID_SHA1_Update SHA1_Update 
  76 #define LDID_SHA1_Final SHA1_Final 
  78 #define LDID_SHA256_DIGEST_LENGTH SHA256_DIGEST_LENGTH 
  79 #define LDID_SHA256 SHA256 
  80 #define LDID_SHA256_CTX SHA256_CTX 
  81 #define LDID_SHA256_Init SHA256_Init 
  82 #define LDID_SHA256_Update SHA256_Update 
  83 #define LDID_SHA256_Final SHA256_Final 
  87 #include <plist/plist.h> 
  92 #define _assert___(line) \ 
  94 #define _assert__(line) \ 
  98 #define _assert_(expr, format, ...) \ 
 100         fprintf(stderr, "%s(%u): _assert(): " format "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ 
 101         throw __FILE__ "(" _assert__(__LINE__) "): _assert(" #expr ")"; \ 
 104 // XXX: this is not acceptable 
 105 #define _assert_(expr, format, ...) \ 
 107         fprintf(stderr, "%s(%u): _assert(): " format "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ 
 112 #define _assert(expr) \ 
 113     _assert_(expr, "%s", #expr) 
 115 #define _syscall(expr, ...) [&] { for (;;) { \ 
 117     if ((long) _value != -1) \ 
 120     if (error == EINTR) \ 
 122     /* XXX: EINTR is included in this list to fix g++ */ \ 
 123     for (auto success : (long[]) {EINTR, __VA_ARGS__}) \ 
 124         if (error == success) \ 
 125             return (decltype(expr)) -success; \ 
 126     _assert_(false, "errno=%u", error); \ 
 130     fprintf(stderr, "_trace(%s:%u): %s\n", __FILE__, __LINE__, __FUNCTION__) 
 136     __attribute__((packed)) 
 138 template <typename Type_
> 
 140     typedef typename 
Type_::const_iterator Result
; 
 143 #define _foreach(item, list) \ 
 144     for (bool _stop(true); _stop; ) \ 
 145         for (const __typeof__(list) &_list = (list); _stop; _stop = false) \ 
 146             for (Iterator_<__typeof__(list)>::Result _item = _list.begin(); _item != _list.end(); ++_item) \ 
 147                 for (bool _suck(true); _suck; _suck = false) \ 
 148                     for (const __typeof__(*_item) &item = *_item; _suck; _suck = false) 
 153 template <typename Function_
> 
 161     Scope(const Function_ 
&function
) : 
 171 template <typename Function_
> 
 172 Scope
<Function_
> _scope(const Function_ 
&function
) { 
 173     return Scope
<Function_
>(function
); 
 176 #define _scope__(counter, function) \ 
 177     __attribute__((__unused__)) \ 
 178     const _Scope &_scope ## counter(_scope([&]function)) 
 179 #define _scope_(counter, function) \ 
 180     _scope__(counter, function) 
 181 #define _scope(function) \ 
 182     _scope_(__COUNTER__, function) 
 184 #define CPU_ARCH_MASK  uint32_t(0xff000000) 
 185 #define CPU_ARCH_ABI64 uint32_t(0x01000000) 
 187 #define CPU_TYPE_ANY     uint32_t(-1) 
 188 #define CPU_TYPE_VAX     uint32_t( 1) 
 189 #define CPU_TYPE_MC680x0 uint32_t( 6) 
 190 #define CPU_TYPE_X86     uint32_t( 7) 
 191 #define CPU_TYPE_MC98000 uint32_t(10) 
 192 #define CPU_TYPE_HPPA    uint32_t(11) 
 193 #define CPU_TYPE_ARM     uint32_t(12) 
 194 #define CPU_TYPE_MC88000 uint32_t(13) 
 195 #define CPU_TYPE_SPARC   uint32_t(14) 
 196 #define CPU_TYPE_I860    uint32_t(15) 
 197 #define CPU_TYPE_POWERPC uint32_t(18) 
 199 #define CPU_TYPE_I386 CPU_TYPE_X86 
 201 #define CPU_TYPE_ARM64     (CPU_ARCH_ABI64 | CPU_TYPE_ARM) 
 202 #define CPU_TYPE_POWERPC64 (CPU_ARCH_ABI64 | CPU_TYPE_POWERPC) 
 203 #define CPU_TYPE_X86_64    (CPU_ARCH_ABI64 | CPU_TYPE_X86) 
 210 #define FAT_MAGIC 0xcafebabe 
 211 #define FAT_CIGAM 0xbebafeca 
 231 #define MH_MAGIC 0xfeedface 
 232 #define MH_CIGAM 0xcefaedfe 
 234 #define MH_MAGIC_64 0xfeedfacf 
 235 #define MH_CIGAM_64 0xcffaedfe 
 237 #define MH_DYLDLINK   0x4 
 239 #define MH_OBJECT     0x1 
 240 #define MH_EXECUTE    0x2 
 242 #define MH_BUNDLE     0x8 
 243 #define MH_DYLIB_STUB 0x9 
 245 struct load_command 
{ 
 250 #define LC_REQ_DYLD           uint32_t(0x80000000) 
 252 #define LC_SEGMENT            uint32_t(0x01) 
 253 #define LC_SYMTAB             uint32_t(0x02) 
 254 #define LC_DYSYMTAB           uint32_t(0x0b) 
 255 #define LC_LOAD_DYLIB         uint32_t(0x0c) 
 256 #define LC_ID_DYLIB           uint32_t(0x0d) 
 257 #define LC_SEGMENT_64         uint32_t(0x19) 
 258 #define LC_UUID               uint32_t(0x1b) 
 259 #define LC_CODE_SIGNATURE     uint32_t(0x1d) 
 260 #define LC_SEGMENT_SPLIT_INFO uint32_t(0x1e) 
 261 #define LC_REEXPORT_DYLIB     uint32_t(0x1f | LC_REQ_DYLD) 
 262 #define LC_ENCRYPTION_INFO    uint32_t(0x21) 
 263 #define LC_DYLD_INFO          uint32_t(0x22) 
 264 #define LC_DYLD_INFO_ONLY     uint32_t(0x22 | LC_REQ_DYLD) 
 265 #define LC_ENCRYPTION_INFO_64 uint32_t(0x2c) 
 280     uint32_t current_version
; 
 281     uint32_t compatibility_version
; 
 284 struct dylib_command 
{ 
 290 struct uuid_command 
{ 
 296 struct symtab_command 
{ 
 305 struct dyld_info_command 
{ 
 309     uint32_t rebase_size
; 
 312     uint32_t weak_bind_off
; 
 313     uint32_t weak_bind_size
; 
 314     uint32_t lazy_bind_off
; 
 315     uint32_t lazy_bind_size
; 
 317     uint32_t export_size
; 
 320 struct dysymtab_command 
{ 
 333     uint32_t extrefsymoff
; 
 334     uint32_t nextrefsyms
; 
 335     uint32_t indirectsymoff
; 
 336     uint32_t nindirectsyms
; 
 343 struct dylib_table_of_contents 
{ 
 344     uint32_t symbol_index
; 
 345     uint32_t module_index
; 
 348 struct dylib_module 
{ 
 349     uint32_t module_name
; 
 358     uint32_t iinit_iterm
; 
 359     uint32_t ninit_nterm
; 
 360     uint32_t objc_module_info_addr
; 
 361     uint32_t objc_module_info_size
; 
 364 struct dylib_reference 
{ 
 369 struct relocation_info 
{ 
 371     uint32_t r_symbolnum
:24; 
 390 struct segment_command 
{ 
 404 struct segment_command_64 
{ 
 447 struct linkedit_data_command 
{ 
 454 struct encryption_info_command 
{ 
 462 #define BIND_OPCODE_MASK                             0xf0 
 463 #define BIND_IMMEDIATE_MASK                          0x0f 
 464 #define BIND_OPCODE_DONE                             0x00 
 465 #define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM            0x10 
 466 #define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB           0x20 
 467 #define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM            0x30 
 468 #define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM    0x40 
 469 #define BIND_OPCODE_SET_TYPE_IMM                     0x50 
 470 #define BIND_OPCODE_SET_ADDEND_SLEB                  0x60 
 471 #define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB      0x70 
 472 #define BIND_OPCODE_ADD_ADDR_ULEB                    0x80 
 473 #define BIND_OPCODE_DO_BIND                          0x90 
 474 #define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB            0xa0 
 475 #define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED      0xb0 
 476 #define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xc0 
 478 static std::streamsize 
read(std::streambuf 
&stream
, void *data
, size_t size
) { 
 479     auto writ(stream
.sgetn(static_cast<char *>(data
), size
)); 
 484 static inline void get(std::streambuf 
&stream
, void *data
, size_t size
) { 
 485     _assert(read(stream
, data
, size
) == size
); 
 488 static inline void put(std::streambuf 
&stream
, const void *data
, size_t size
) { 
 489     _assert(stream
.sputn(static_cast<const char *>(data
), size
) == size
); 
 492 static size_t most(std::streambuf 
&stream
, void *data
, size_t size
) { 
 495         if (auto writ 
= read(stream
, data
, size
)) 
 501 static inline void pad(std::streambuf 
&stream
, size_t size
) { 
 503     memset(padding
, 0, size
); 
 504     put(stream
, padding
, size
); 
 507 template <typename Type_
> 
 508 Type_ 
Align(Type_ value
, size_t align
) { 
 515 static const uint8_t PageShift_(0x0c); 
 516 static const uint32_t PageSize_(1 << PageShift_
); 
 518 static inline uint16_t Swap_(uint16_t value
) { 
 520         ((value 
>>  8) & 0x00ff) | 
 521         ((value 
<<  8) & 0xff00); 
 524 static inline uint32_t Swap_(uint32_t value
) { 
 525     value 
= ((value 
>>  8) & 0x00ff00ff) | 
 526             ((value 
<<  8) & 0xff00ff00); 
 527     value 
= ((value 
>> 16) & 0x0000ffff) | 
 528             ((value 
<< 16) & 0xffff0000); 
 532 static inline uint64_t Swap_(uint64_t value
) { 
 533     value 
= (value 
& 0x00000000ffffffff) << 32 | (value 
& 0xffffffff00000000) >> 32; 
 534     value 
= (value 
& 0x0000ffff0000ffff) << 16 | (value 
& 0xffff0000ffff0000) >> 16; 
 535     value 
= (value 
& 0x00ff00ff00ff00ff) << 8  | (value 
& 0xff00ff00ff00ff00) >> 8; 
 539 static inline int16_t Swap_(int16_t value
) { 
 540     return Swap_(static_cast<uint16_t>(value
)); 
 543 static inline int32_t Swap_(int32_t value
) { 
 544     return Swap_(static_cast<uint32_t>(value
)); 
 547 static inline int64_t Swap_(int64_t value
) { 
 548     return Swap_(static_cast<uint64_t>(value
)); 
 551 static bool little_(true); 
 553 static inline uint16_t Swap(uint16_t value
) { 
 554     return little_ 
? Swap_(value
) : value
; 
 557 static inline uint32_t Swap(uint32_t value
) { 
 558     return little_ 
? Swap_(value
) : value
; 
 561 static inline uint64_t Swap(uint64_t value
) { 
 562     return little_ 
? Swap_(value
) : value
; 
 565 static inline int16_t Swap(int16_t value
) { 
 566     return Swap(static_cast<uint16_t>(value
)); 
 569 static inline int32_t Swap(int32_t value
) { 
 570     return Swap(static_cast<uint32_t>(value
)); 
 573 static inline int64_t Swap(int64_t value
) { 
 574     return Swap(static_cast<uint64_t>(value
)); 
 587     Swapped(bool swapped
) : 
 592     template <typename Type_
> 
 593     Type_ 
Swap(Type_ value
) const { 
 594         return swapped_ 
? Swap_(value
) : value
; 
 606     Data(void *base
, size_t size
) : 
 612     void *GetBase() const { 
 616     size_t GetSize() const { 
 627     struct mach_header 
*mach_header_
; 
 628     struct load_command 
*load_command_
; 
 631     MachHeader(void *base
, size_t size
) : 
 634         mach_header_ 
= (mach_header 
*) base
; 
 636         switch (Swap(mach_header_
->magic
)) { 
 638                 swapped_ 
= !swapped_
; 
 644                 swapped_ 
= !swapped_
; 
 653         void *post 
= mach_header_ 
+ 1; 
 655             post 
= (uint32_t *) post 
+ 1; 
 656         load_command_ 
= (struct load_command 
*) post
; 
 659             Swap(mach_header_
->filetype
) == MH_EXECUTE 
|| 
 660             Swap(mach_header_
->filetype
) == MH_DYLIB 
|| 
 661             Swap(mach_header_
->filetype
) == MH_BUNDLE
 
 665     bool Bits64() const { 
 669     struct mach_header 
*operator ->() const { 
 673     operator struct mach_header 
*() const { 
 677     uint32_t GetCPUType() const { 
 678         return Swap(mach_header_
->cputype
); 
 681     uint32_t GetCPUSubtype() const { 
 682         return Swap(mach_header_
->cpusubtype
) & 0xff; 
 685     struct load_command 
*GetLoadCommand() const { 
 686         return load_command_
; 
 689     std::vector
<struct load_command 
*> GetLoadCommands() const { 
 690         std::vector
<struct load_command 
*> load_commands
; 
 692         struct load_command 
*load_command 
= load_command_
; 
 693         for (uint32_t cmd 
= 0; cmd 
!= Swap(mach_header_
->ncmds
); ++cmd
) { 
 694             load_commands
.push_back(load_command
); 
 695             load_command 
= (struct load_command 
*) ((uint8_t *) load_command 
+ Swap(load_command
->cmdsize
)); 
 698         return load_commands
; 
 701     void ForSection(const ldid::Functor
<void (const char *, const char *, void *, size_t)> &code
) const { 
 702         _foreach (load_command
, GetLoadCommands()) 
 703             switch (Swap(load_command
->cmd
)) { 
 705                     auto segment(reinterpret_cast<struct segment_command 
*>(load_command
)); 
 706                     code(segment
->segname
, NULL
, GetOffset
<void>(segment
->fileoff
), segment
->filesize
); 
 707                     auto section(reinterpret_cast<struct section 
*>(segment 
+ 1)); 
 708                     for (uint32_t i(0), e(Swap(segment
->nsects
)); i 
!= e
; ++i
, ++section
) 
 709                         code(segment
->segname
, section
->sectname
, GetOffset
<void>(segment
->fileoff 
+ section
->offset
), section
->size
); 
 712                 case LC_SEGMENT_64
: { 
 713                     auto segment(reinterpret_cast<struct segment_command_64 
*>(load_command
)); 
 714                     code(segment
->segname
, NULL
, GetOffset
<void>(segment
->fileoff
), segment
->filesize
); 
 715                     auto section(reinterpret_cast<struct section_64 
*>(segment 
+ 1)); 
 716                     for (uint32_t i(0), e(Swap(segment
->nsects
)); i 
!= e
; ++i
, ++section
) 
 717                         code(segment
->segname
, section
->sectname
, GetOffset
<void>(segment
->fileoff 
+ section
->offset
), section
->size
); 
 722     template <typename Target_
> 
 723     Target_ 
*GetOffset(uint32_t offset
) const { 
 724         return reinterpret_cast<Target_ 
*>(offset 
+ (uint8_t *) mach_header_
); 
 728 class FatMachHeader 
: 
 735     FatMachHeader(void *base
, size_t size
, fat_arch 
*fat_arch
) : 
 736         MachHeader(base
, size
), 
 741     fat_arch 
*GetFatArch() const { 
 750     fat_header 
*fat_header_
; 
 751     std::vector
<FatMachHeader
> mach_headers_
; 
 754     FatHeader(void *base
, size_t size
) : 
 757         fat_header_ 
= reinterpret_cast<struct fat_header 
*>(base
); 
 759         if (Swap(fat_header_
->magic
) == FAT_CIGAM
) { 
 760             swapped_ 
= !swapped_
; 
 762         } else if (Swap(fat_header_
->magic
) != FAT_MAGIC
) { 
 764             mach_headers_
.push_back(FatMachHeader(base
, size
, NULL
)); 
 766             size_t fat_narch 
= Swap(fat_header_
->nfat_arch
); 
 767             fat_arch 
*fat_arch 
= reinterpret_cast<struct fat_arch 
*>(fat_header_ 
+ 1); 
 769             for (arch 
= 0; arch 
!= fat_narch
; ++arch
) { 
 770                 uint32_t arch_offset 
= Swap(fat_arch
->offset
); 
 771                 uint32_t arch_size 
= Swap(fat_arch
->size
); 
 772                 mach_headers_
.push_back(FatMachHeader((uint8_t *) base 
+ arch_offset
, arch_size
, fat_arch
)); 
 778     std::vector
<FatMachHeader
> &GetMachHeaders() { 
 779         return mach_headers_
; 
 783         return fat_header_ 
!= NULL
; 
 786     struct fat_header 
*operator ->() const { 
 790     operator struct fat_header 
*() const { 
 795 #define CSMAGIC_REQUIREMENT            uint32_t(0xfade0c00) 
 796 #define CSMAGIC_REQUIREMENTS           uint32_t(0xfade0c01) 
 797 #define CSMAGIC_CODEDIRECTORY          uint32_t(0xfade0c02) 
 798 #define CSMAGIC_EMBEDDED_SIGNATURE     uint32_t(0xfade0cc0) 
 799 #define CSMAGIC_EMBEDDED_SIGNATURE_OLD uint32_t(0xfade0b02) 
 800 #define CSMAGIC_EMBEDDED_ENTITLEMENTS  uint32_t(0xfade7171) 
 801 #define CSMAGIC_DETACHED_SIGNATURE     uint32_t(0xfade0cc1) 
 802 #define CSMAGIC_BLOBWRAPPER            uint32_t(0xfade0b01) 
 804 #define CSSLOT_CODEDIRECTORY uint32_t(0x00000) 
 805 #define CSSLOT_INFOSLOT      uint32_t(0x00001) 
 806 #define CSSLOT_REQUIREMENTS  uint32_t(0x00002) 
 807 #define CSSLOT_RESOURCEDIR   uint32_t(0x00003) 
 808 #define CSSLOT_APPLICATION   uint32_t(0x00004) 
 809 #define CSSLOT_ENTITLEMENTS  uint32_t(0x00005) 
 811 #define CSSLOT_SIGNATURESLOT uint32_t(0x10000) 
 813 #define CS_HASHTYPE_SHA1 1 
 828     struct BlobIndex index
[]; 
 831 struct CodeDirectory 
{ 
 835     uint32_t identOffset
; 
 836     uint32_t nSpecialSlots
; 
 844     uint32_t scatterOffset
; 
 845     uint32_t teamIDOffset
; 
 847     uint64_t codeLimit64
; 
 851 extern "C" uint32_t hash(uint8_t *k
, uint32_t length
, uint32_t initval
); 
 854 static void sha1(uint8_t *hash
, const void *data
, size_t size
) { 
 855     LDID_SHA1(static_cast<const uint8_t *>(data
), size
, hash
); 
 858 static void sha1(std::vector
<char> &hash
, const void *data
, size_t size
) { 
 859     hash
.resize(LDID_SHA1_DIGEST_LENGTH
); 
 860     sha1(reinterpret_cast<uint8_t *>(hash
.data()), data
, size
); 
 863 struct CodesignAllocation 
{ 
 864     FatMachHeader mach_header_
; 
 871     CodesignAllocation(FatMachHeader mach_header
, size_t offset
, size_t size
, size_t limit
, size_t alloc
, size_t align
) : 
 872         mach_header_(mach_header
), 
 895             _syscall(close(file_
)); 
 898     void open(const char *path
, int flags
) { 
 899         _assert(file_ 
== -1); 
 900         file_ 
= _syscall(::open(path
, flags
)); 
 917         _syscall(munmap(data_
, size_
)); 
 929     Map(const std::string 
&path
, int oflag
, int pflag
, int mflag
) : 
 932         open(path
, oflag
, pflag
, mflag
); 
 935     Map(const std::string 
&path
, bool edit
) : 
 946         return data_ 
== NULL
; 
 949     void open(const std::string 
&path
, int oflag
, int pflag
, int mflag
) { 
 952         file_
.open(path
.c_str(), oflag
); 
 953         int file(file_
.file()); 
 956         _syscall(fstat(file
, &stat
)); 
 957         size_ 
= stat
.st_size
; 
 959         data_ 
= _syscall(mmap(NULL
, size_
, pflag
, mflag
, file
, 0)); 
 962     void open(const std::string 
&path
, bool edit
) { 
 964             open(path
, O_RDWR
, PROT_READ 
| PROT_WRITE
, MAP_SHARED
); 
 966             open(path
, O_RDONLY
, PROT_READ
, MAP_PRIVATE
); 
 973     size_t size() const { 
 977     operator std::string() const { 
 978         return std::string(static_cast<char *>(data_
), size_
); 
 985 static void Allocate(const void *idata
, size_t isize
, std::streambuf 
&output
, const Functor
<size_t (const MachHeader 
&, size_t)> &allocate
, const Functor
<size_t (const MachHeader 
&, std::streambuf 
&output
, size_t, const std::string 
&, const char *)> &save
) { 
 986     FatHeader 
source(const_cast<void *>(idata
), isize
); 
 990         offset 
+= sizeof(fat_header
) + sizeof(fat_arch
) * source
.Swap(source
->nfat_arch
); 
 992     std::vector
<CodesignAllocation
> allocations
; 
 993     _foreach (mach_header
, source
.GetMachHeaders()) { 
 994         struct linkedit_data_command 
*signature(NULL
); 
 995         struct symtab_command 
*symtab(NULL
); 
 997         _foreach (load_command
, mach_header
.GetLoadCommands()) { 
 998             uint32_t cmd(mach_header
.Swap(load_command
->cmd
)); 
1000             else if (cmd 
== LC_CODE_SIGNATURE
) 
1001                 signature 
= reinterpret_cast<struct linkedit_data_command 
*>(load_command
); 
1002             else if (cmd 
== LC_SYMTAB
) 
1003                 symtab 
= reinterpret_cast<struct symtab_command 
*>(load_command
); 
1007         if (signature 
== NULL
) 
1008             size 
= mach_header
.GetSize(); 
1010             size 
= mach_header
.Swap(signature
->dataoff
); 
1011             _assert(size 
<= mach_header
.GetSize()); 
1014         if (symtab 
!= NULL
) { 
1015             auto end(mach_header
.Swap(symtab
->stroff
) + mach_header
.Swap(symtab
->strsize
)); 
1016             _assert(end 
<= size
); 
1017             _assert(end 
>= size 
- 0x10); 
1021         size_t alloc(allocate(mach_header
, size
)); 
1023         auto *fat_arch(mach_header
.GetFatArch()); 
1026         if (fat_arch 
!= NULL
) 
1027             align 
= source
.Swap(fat_arch
->align
); 
1028         else switch (mach_header
.GetCPUType()) { 
1029             case CPU_TYPE_POWERPC
: 
1030             case CPU_TYPE_POWERPC64
: 
1032             case CPU_TYPE_X86_64
: 
1036             case CPU_TYPE_ARM64
: 
1044         offset 
= Align(offset
, 1 << align
); 
1046         uint32_t limit(size
); 
1048             limit 
= Align(limit
, 0x10); 
1050         allocations
.push_back(CodesignAllocation(mach_header
, offset
, size
, limit
, alloc
, align
)); 
1051         offset 
+= size 
+ alloc
; 
1052         offset 
= Align(offset
, 0x10); 
1057     if (source
.IsFat()) { 
1058         fat_header fat_header
; 
1059         fat_header
.magic 
= Swap(FAT_MAGIC
); 
1060         fat_header
.nfat_arch 
= Swap(uint32_t(allocations
.size())); 
1061         put(output
, &fat_header
, sizeof(fat_header
)); 
1062         position 
+= sizeof(fat_header
); 
1064         _foreach (allocation
, allocations
) { 
1065             auto &mach_header(allocation
.mach_header_
); 
1068             fat_arch
.cputype 
= Swap(mach_header
->cputype
); 
1069             fat_arch
.cpusubtype 
= Swap(mach_header
->cpusubtype
); 
1070             fat_arch
.offset 
= Swap(allocation
.offset_
); 
1071             fat_arch
.size 
= Swap(allocation
.limit_ 
+ allocation
.alloc_
); 
1072             fat_arch
.align 
= Swap(allocation
.align_
); 
1073             put(output
, &fat_arch
, sizeof(fat_arch
)); 
1074             position 
+= sizeof(fat_arch
); 
1078     _foreach (allocation
, allocations
) { 
1079         auto &mach_header(allocation
.mach_header_
); 
1081         pad(output
, allocation
.offset_ 
- position
); 
1082         position 
= allocation
.offset_
; 
1084         std::vector
<std::string
> commands
; 
1086         _foreach (load_command
, mach_header
.GetLoadCommands()) { 
1087             std::string 
copy(reinterpret_cast<const char *>(load_command
), load_command
->cmdsize
); 
1089             switch (mach_header
.Swap(load_command
->cmd
)) { 
1090                 case LC_CODE_SIGNATURE
: 
1095                     auto segment_command(reinterpret_cast<struct segment_command 
*>(©
[0])); 
1096                     if (strncmp(segment_command
->segname
, "__LINKEDIT", 16) != 0) 
1098                     size_t size(mach_header
.Swap(allocation
.limit_ 
+ allocation
.alloc_ 
- mach_header
.Swap(segment_command
->fileoff
))); 
1099                     segment_command
->filesize 
= size
; 
1100                     segment_command
->vmsize 
= Align(size
, 1 << allocation
.align_
); 
1103                 case LC_SEGMENT_64
: { 
1104                     auto segment_command(reinterpret_cast<struct segment_command_64 
*>(©
[0])); 
1105                     if (strncmp(segment_command
->segname
, "__LINKEDIT", 16) != 0) 
1107                     size_t size(mach_header
.Swap(allocation
.limit_ 
+ allocation
.alloc_ 
- mach_header
.Swap(segment_command
->fileoff
))); 
1108                     segment_command
->filesize 
= size
; 
1109                     segment_command
->vmsize 
= Align(size
, 1 << allocation
.align_
); 
1113             commands
.push_back(copy
); 
1116         if (allocation
.alloc_ 
!= 0) { 
1117             linkedit_data_command signature
; 
1118             signature
.cmd 
= mach_header
.Swap(LC_CODE_SIGNATURE
); 
1119             signature
.cmdsize 
= mach_header
.Swap(uint32_t(sizeof(signature
))); 
1120             signature
.dataoff 
= mach_header
.Swap(allocation
.limit_
); 
1121             signature
.datasize 
= mach_header
.Swap(allocation
.alloc_
); 
1122             commands
.push_back(std::string(reinterpret_cast<const char *>(&signature
), sizeof(signature
))); 
1125         size_t begin(position
); 
1128         _foreach(command
, commands
) 
1129             after 
+= command
.size(); 
1131         std::stringbuf altern
; 
1133         struct mach_header 
header(*mach_header
); 
1134         header
.ncmds 
= mach_header
.Swap(uint32_t(commands
.size())); 
1135         header
.sizeofcmds 
= mach_header
.Swap(after
); 
1136         put(output
, &header
, sizeof(header
)); 
1137         put(altern
, &header
, sizeof(header
)); 
1138         position 
+= sizeof(header
); 
1140         if (mach_header
.Bits64()) { 
1141             auto pad(mach_header
.Swap(uint32_t(0))); 
1142             put(output
, &pad
, sizeof(pad
)); 
1143             put(altern
, &pad
, sizeof(pad
)); 
1144             position 
+= sizeof(pad
); 
1147         _foreach(command
, commands
) { 
1148             put(output
, command
.data(), command
.size()); 
1149             put(altern
, command
.data(), command
.size()); 
1150             position 
+= command
.size(); 
1153         uint32_t before(mach_header
.Swap(mach_header
->sizeofcmds
)); 
1154         if (before 
> after
) { 
1155             pad(output
, before 
- after
); 
1156             pad(altern
, before 
- after
); 
1157             position 
+= before 
- after
; 
1160         auto top(reinterpret_cast<char *>(mach_header
.GetBase())); 
1162         std::string 
overlap(altern
.str()); 
1163         overlap
.append(top 
+ overlap
.size(), Align(overlap
.size(), 0x1000) - overlap
.size()); 
1165         put(output
, top 
+ (position 
- begin
), allocation
.size_ 
- (position 
- begin
)); 
1166         position 
= begin 
+ allocation
.size_
; 
1168         pad(output
, allocation
.limit_ 
- allocation
.size_
); 
1169         position 
+= allocation
.limit_ 
- allocation
.size_
; 
1171         size_t saved(save(mach_header
, output
, allocation
.limit_
, overlap
, top
)); 
1172         if (allocation
.alloc_ 
> saved
) 
1173             pad(output
, allocation
.alloc_ 
- saved
); 
1174         position 
+= allocation
.alloc_
; 
1180 typedef std::map
<uint32_t, std::string
> Blobs
; 
1182 static void insert(Blobs 
&blobs
, uint32_t slot
, const std::stringbuf 
&buffer
) { 
1183     auto value(buffer
.str()); 
1184     std::swap(blobs
[slot
], value
); 
1187 static const std::string 
&insert(Blobs 
&blobs
, uint32_t slot
, uint32_t magic
, const std::stringbuf 
&buffer
) { 
1188     auto value(buffer
.str()); 
1190     blob
.magic 
= Swap(magic
); 
1191     blob
.length 
= Swap(uint32_t(sizeof(blob
) + value
.size())); 
1192     value
.insert(0, reinterpret_cast<char *>(&blob
), sizeof(blob
)); 
1193     auto &save(blobs
[slot
]); 
1194     std::swap(save
, value
); 
1198 static size_t put(std::streambuf 
&output
, uint32_t magic
, const Blobs 
&blobs
) { 
1200     _foreach (blob
, blobs
) 
1201         total 
+= blob
.second
.size(); 
1203     struct SuperBlob super
; 
1204     super
.blob
.magic 
= Swap(magic
); 
1205     super
.blob
.length 
= Swap(uint32_t(sizeof(SuperBlob
) + blobs
.size() * sizeof(BlobIndex
) + total
)); 
1206     super
.count 
= Swap(uint32_t(blobs
.size())); 
1207     put(output
, &super
, sizeof(super
)); 
1209     size_t offset(sizeof(SuperBlob
) + sizeof(BlobIndex
) * blobs
.size()); 
1211     _foreach (blob
, blobs
) { 
1213         index
.type 
= Swap(blob
.first
); 
1214         index
.offset 
= Swap(uint32_t(offset
)); 
1215         put(output
, &index
, sizeof(index
)); 
1216         offset 
+= blob
.second
.size(); 
1219     _foreach (blob
, blobs
) 
1220         put(output
, blob
.second
.data(), blob
.second
.size()); 
1225 #ifndef LDID_NOSMIME 
1234         _assert(bio_ 
!= NULL
); 
1238         bio_(BIO_new(BIO_s_mem())) 
1242     Buffer(const char *data
, size_t size
) : 
1243         Buffer(BIO_new_mem_buf(const_cast<char *>(data
), size
)) 
1247     Buffer(const std::string 
&data
) : 
1248         Buffer(data
.data(), data
.size()) 
1252     Buffer(PKCS7 
*pkcs
) : 
1255         _assert(i2d_PKCS7_bio(bio_
, pkcs
) != 0); 
1262     operator BIO 
*() const { 
1266     explicit operator std::string() const { 
1268         auto size(BIO_get_mem_data(bio_
, &data
)); 
1269         return std::string(data
, size
); 
1278     STACK_OF(X509
) *ca_
; 
1282         value_(d2i_PKCS12_bio(bio
, NULL
)), 
1285         _assert(value_ 
!= NULL
); 
1286         _assert(PKCS12_parse(value_
, "", &key_
, &cert_
, &ca_
) != 0); 
1287         _assert(key_ 
!= NULL
); 
1288         _assert(cert_ 
!= NULL
); 
1291     Stuff(const std::string 
&data
) : 
1297         sk_X509_pop_free(ca_
, X509_free
); 
1299         EVP_PKEY_free(key_
); 
1300         PKCS12_free(value_
); 
1303     operator PKCS12 
*() const { 
1307     operator EVP_PKEY 
*() const { 
1311     operator X509 
*() const { 
1315     operator STACK_OF(X509
) *() const { 
1325     Signature(const Stuff 
&stuff
, const Buffer 
&data
) : 
1326         value_(PKCS7_sign(stuff
, stuff
, stuff
, data
, PKCS7_BINARY 
| PKCS7_DETACHED
)) 
1328         _assert(value_ 
!= NULL
); 
1335     operator PKCS7 
*() const { 
1342     public std::streambuf
 
1345     virtual std::streamsize 
xsputn(const char_type 
*data
, std::streamsize size
) { 
1349     virtual int_type 
overflow(int_type next
) { 
1356     char sha1_
[LDID_SHA1_DIGEST_LENGTH
]; 
1357     char sha256_
[LDID_SHA256_DIGEST_LENGTH
]; 
1359     operator std::vector
<char>() const { 
1360         return {sha1_
, sha1_ 
+ sizeof(sha1_
)}; 
1365     public std::streambuf
 
1370     LDID_SHA1_CTX sha1_
; 
1371     LDID_SHA256_CTX sha256_
; 
1374     HashBuffer(Hash 
&hash
) : 
1377         LDID_SHA1_Init(&sha1_
); 
1378         LDID_SHA256_Init(&sha256_
); 
1382         LDID_SHA1_Final(reinterpret_cast<uint8_t *>(hash_
.sha1_
), &sha1_
); 
1383         LDID_SHA256_Final(reinterpret_cast<uint8_t *>(hash_
.sha256_
), &sha256_
); 
1386     virtual std::streamsize 
xsputn(const char_type 
*data
, std::streamsize size
) { 
1387         LDID_SHA1_Update(&sha1_
, data
, size
); 
1388         LDID_SHA256_Update(&sha256_
, data
, size
); 
1392     virtual int_type 
overflow(int_type next
) { 
1393         if (next 
== traits_type::eof()) 
1405     std::streambuf 
&buffer_
; 
1408     HashProxy(Hash 
&hash
, std::streambuf 
&buffer
) : 
1414     virtual std::streamsize 
xsputn(const char_type 
*data
, std::streamsize size
) { 
1415         _assert(HashBuffer::xsputn(data
, size
) == size
); 
1416         return buffer_
.sputn(data
, size
); 
1420 #ifndef LDID_NOTOOLS 
1421 static bool Starts(const std::string 
&lhs
, const std::string 
&rhs
) { 
1422     return lhs
.size() >= rhs
.size() && lhs
.compare(0, rhs
.size(), rhs
) == 0; 
1430     Split(const std::string 
&path
) { 
1431         size_t slash(path
.rfind('/')); 
1432         if (slash 
== std::string::npos
) 
1435             dir 
= path
.substr(0, slash 
+ 1); 
1436             base 
= path
.substr(slash 
+ 1); 
1441 static void mkdir_p(const std::string 
&path
) { 
1445     if (_syscall(mkdir(path
.c_str()), EEXIST
) == -EEXIST
) 
1448     if (_syscall(mkdir(path
.c_str(), 0755), EEXIST
) == -EEXIST
) 
1451     auto slash(path
.rfind('/', path
.size() - 1)); 
1452     if (slash 
== std::string::npos
) 
1454     mkdir_p(path
.substr(0, slash
)); 
1457 static std::string 
Temporary(std::filebuf 
&file
, const Split 
&split
) { 
1458     std::string 
temp(split
.dir 
+ ".ldid." + split
.base
); 
1460     _assert_(file
.open(temp
.c_str(), std::ios::out 
| std::ios::trunc 
| std::ios::binary
) == &file
, "open(): %s", temp
.c_str()); 
1464 static void Commit(const std::string 
&path
, const std::string 
&temp
) { 
1466     if (_syscall(stat(path
.c_str(), &info
), ENOENT
) == 0) { 
1468         _syscall(chown(temp
.c_str(), info
.st_uid
, info
.st_gid
)); 
1470         _syscall(chmod(temp
.c_str(), info
.st_mode
)); 
1473     _syscall(rename(temp
.c_str(), path
.c_str())); 
1479 std::vector
<char> Sign(const void *idata
, size_t isize
, std::streambuf 
&output
, const std::string 
&identifier
, const std::string 
&entitlements
, const std::string 
&requirement
, const std::string 
&key
, const Slots 
&slots
) { 
1480     std::vector
<char> hash(LDID_SHA1_DIGEST_LENGTH
); 
1484 #ifndef LDID_NOSMIME 
1487         auto name(X509_get_subject_name(stuff
)); 
1488         _assert(name 
!= NULL
); 
1489         auto index(X509_NAME_get_index_by_NID(name
, NID_organizationalUnitName
, -1)); 
1490         _assert(index 
>= 0); 
1491         auto next(X509_NAME_get_index_by_NID(name
, NID_organizationalUnitName
, index
)); 
1492         _assert(next 
== -1); 
1493         auto entry(X509_NAME_get_entry(name
, index
)); 
1494         _assert(entry 
!= NULL
); 
1495         auto asn(X509_NAME_ENTRY_get_data(entry
)); 
1496         _assert(asn 
!= NULL
); 
1497         team
.assign(reinterpret_cast<char *>(ASN1_STRING_data(asn
)), ASN1_STRING_length(asn
)); 
1501     Allocate(idata
, isize
, output
, fun([&](const MachHeader 
&mach_header
, size_t size
) -> size_t { 
1502         size_t alloc(sizeof(struct SuperBlob
)); 
1504         uint32_t special(0); 
1506         special 
= std::max(special
, CSSLOT_REQUIREMENTS
); 
1507         alloc 
+= sizeof(struct BlobIndex
); 
1508         if (requirement
.empty()) 
1511             alloc 
+= requirement
.size(); 
1513         if (!entitlements
.empty()) { 
1514             special 
= std::max(special
, CSSLOT_ENTITLEMENTS
); 
1515             alloc 
+= sizeof(struct BlobIndex
); 
1516             alloc 
+= sizeof(struct Blob
); 
1517             alloc 
+= entitlements
.size(); 
1520         special 
= std::max(special
, CSSLOT_CODEDIRECTORY
); 
1521         alloc 
+= sizeof(struct BlobIndex
); 
1522         alloc 
+= sizeof(struct Blob
); 
1523         alloc 
+= sizeof(struct CodeDirectory
); 
1524         alloc 
+= identifier
.size() + 1; 
1527             alloc 
+= team
.size() + 1; 
1530             alloc 
+= sizeof(struct BlobIndex
); 
1531             alloc 
+= sizeof(struct Blob
); 
1532             // XXX: this is just a "sufficiently large number" 
1536         _foreach (slot
, slots
) 
1537             special 
= std::max(special
, slot
.first
); 
1539         mach_header
.ForSection(fun([&](const char *segment
, const char *section
, void *data
, size_t size
) { 
1540             if (strcmp(segment
, "__TEXT") == 0 && section 
!= NULL 
&& strcmp(section
, "__info_plist") == 0) 
1541                 special 
= std::max(special
, CSSLOT_INFOSLOT
); 
1544         uint32_t normal((size 
+ PageSize_ 
- 1) / PageSize_
); 
1545         alloc 
= Align(alloc 
+ (special 
+ normal
) * LDID_SHA1_DIGEST_LENGTH
, 16); 
1547     }), fun([&](const MachHeader 
&mach_header
, std::streambuf 
&output
, size_t limit
, const std::string 
&overlap
, const char *top
) -> size_t { 
1551             std::stringbuf data
; 
1553             if (requirement
.empty()) { 
1555                 put(data
, CSMAGIC_REQUIREMENTS
, requirements
); 
1557                 put(data
, requirement
.data(), requirement
.size()); 
1560             insert(blobs
, CSSLOT_REQUIREMENTS
, data
); 
1563         if (!entitlements
.empty()) { 
1564             std::stringbuf data
; 
1565             put(data
, entitlements
.data(), entitlements
.size()); 
1566             insert(blobs
, CSSLOT_ENTITLEMENTS
, CSMAGIC_EMBEDDED_ENTITLEMENTS
, data
); 
1570             std::stringbuf data
; 
1574             mach_header
.ForSection(fun([&](const char *segment
, const char *section
, void *data
, size_t size
) { 
1575                 if (strcmp(segment
, "__TEXT") == 0 && section 
!= NULL 
&& strcmp(section
, "__info_plist") == 0) 
1576                     sha1(posts
[CSSLOT_INFOSLOT
], data
, size
); 
1579             uint32_t special(0); 
1580             _foreach (blob
, blobs
) 
1581                 special 
= std::max(special
, blob
.first
); 
1582             _foreach (slot
, posts
) 
1583                 special 
= std::max(special
, slot
.first
); 
1584             uint32_t normal((limit 
+ PageSize_ 
- 1) / PageSize_
); 
1586             CodeDirectory directory
; 
1587             directory
.version 
= Swap(uint32_t(0x00020200)); 
1588             directory
.flags 
= Swap(uint32_t(0)); 
1589             directory
.nSpecialSlots 
= Swap(special
); 
1590             directory
.codeLimit 
= Swap(uint32_t(limit
)); 
1591             directory
.nCodeSlots 
= Swap(normal
); 
1592             directory
.hashSize 
= LDID_SHA1_DIGEST_LENGTH
; 
1593             directory
.hashType 
= CS_HASHTYPE_SHA1
; 
1594             directory
.spare1 
= 0x00; 
1595             directory
.pageSize 
= PageShift_
; 
1596             directory
.spare2 
= Swap(uint32_t(0)); 
1597             directory
.scatterOffset 
= Swap(uint32_t(0)); 
1598             directory
.spare3 
= Swap(uint32_t(0)); 
1599             directory
.codeLimit64 
= Swap(uint64_t(0)); 
1601             uint32_t offset(sizeof(Blob
) + sizeof(CodeDirectory
)); 
1603             directory
.identOffset 
= Swap(uint32_t(offset
)); 
1604             offset 
+= identifier
.size() + 1; 
1607                 directory
.teamIDOffset 
= Swap(uint32_t(0)); 
1609                 directory
.teamIDOffset 
= Swap(uint32_t(offset
)); 
1610                 offset 
+= team
.size() + 1; 
1613             offset 
+= LDID_SHA1_DIGEST_LENGTH 
* special
; 
1614             directory
.hashOffset 
= Swap(uint32_t(offset
)); 
1615             offset 
+= LDID_SHA1_DIGEST_LENGTH 
* normal
; 
1617             put(data
, &directory
, sizeof(directory
)); 
1619             put(data
, identifier
.c_str(), identifier
.size() + 1); 
1620             put(data
, team
.c_str(), team
.size() + 1); 
1622             uint8_t storage
[special 
+ normal
][LDID_SHA1_DIGEST_LENGTH
]; 
1623             uint8_t (*hashes
)[LDID_SHA1_DIGEST_LENGTH
] = storage 
+ special
; 
1625             memset(storage
, 0, sizeof(*storage
) * special
); 
1627             _foreach (blob
, blobs
) { 
1628                 auto local(reinterpret_cast<const Blob 
*>(&blob
.second
[0])); 
1629                 sha1((uint8_t *) (hashes 
- blob
.first
), local
, Swap(local
->length
)); 
1632             _foreach (slot
, posts
) { 
1633                 _assert(sizeof(*hashes
) == slot
.second
.size()); 
1634                 memcpy(hashes 
- slot
.first
, slot
.second
.data(), slot
.second
.size()); 
1638                 for (size_t i 
= 0; i 
!= normal 
- 1; ++i
) 
1639                     sha1(hashes
[i
], (PageSize_ 
* i 
< overlap
.size() ? overlap
.data() : top
) + PageSize_ 
* i
, PageSize_
); 
1641                 sha1(hashes
[normal 
- 1], top 
+ PageSize_ 
* (normal 
- 1), ((limit 
- 1) % PageSize_
) + 1); 
1643             put(data
, storage
, sizeof(storage
)); 
1645             const auto &save(insert(blobs
, CSSLOT_CODEDIRECTORY
, CSMAGIC_CODEDIRECTORY
, data
)); 
1646             sha1(hash
, save
.data(), save
.size()); 
1649 #ifndef LDID_NOSMIME 
1651             std::stringbuf data
; 
1652             const std::string 
&sign(blobs
[CSSLOT_CODEDIRECTORY
]); 
1657             Signature 
signature(stuff
, sign
); 
1658             Buffer 
result(signature
); 
1659             std::string 
value(result
); 
1660             put(data
, value
.data(), value
.size()); 
1662             insert(blobs
, CSSLOT_SIGNATURESLOT
, CSMAGIC_BLOBWRAPPER
, data
); 
1666         return put(output
, CSMAGIC_EMBEDDED_SIGNATURE
, blobs
); 
1672 #ifndef LDID_NOTOOLS 
1673 static void Unsign(void *idata
, size_t isize
, std::streambuf 
&output
) { 
1674     Allocate(idata
, isize
, output
, fun([](const MachHeader 
&mach_header
, size_t size
) -> size_t { 
1676     }), fun([](const MachHeader 
&mach_header
, std::streambuf 
&output
, size_t limit
, const std::string 
&overlap
, const char *top
) -> size_t { 
1681 std::string 
DiskFolder::Path(const std::string 
&path
) { 
1682     return path_ 
+ "/" + path
; 
1685 DiskFolder::DiskFolder(const std::string 
&path
) : 
1690 DiskFolder::~DiskFolder() { 
1691     if (!std::uncaught_exception()) 
1692         for (const auto &commit 
: commit_
) 
1693             Commit(commit
.first
, commit
.second
); 
1697 std::string 
readlink(const std::string 
&path
) { 
1698     for (size_t size(1024); ; size 
*= 2) { 
1702         int writ(_syscall(::readlink(path
.c_str(), &data
[0], data
.size()))); 
1703         if (size_t(writ
) >= size
) 
1712 void DiskFolder::Find(const std::string 
&root
, const std::string 
&base
, const Functor
<void (const std::string 
&, const Functor
<void (const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &)> &)> &code
, const Functor
<void (const std::string 
&, const Functor
<std::string ()> &)> &link
) { 
1713     std::string 
path(Path(root
) + base
); 
1715     DIR *dir(opendir(path
.c_str())); 
1716     _assert(dir 
!= NULL
); 
1717     _scope({ _syscall(closedir(dir
)); }); 
1719     while (auto child 
= readdir(dir
)) { 
1720         std::string 
name(child
->d_name
); 
1721         if (name 
== "." || name 
== "..") 
1723         if (Starts(name
, ".ldid.")) 
1730         _syscall(stat((path 
+ name
).c_str(), &info
)); 
1732         else if (S_ISDIR(info
.st_mode
)) 
1734         else if (S_ISREG(info
.st_mode
)) 
1737             _assert_(false, "st_mode=%x", info
.st_mode
); 
1739         switch (child
->d_type
) { 
1747                 link(base 
+ name
, fun([&]() { return readlink(path 
+ name
); })); 
1750                 _assert_(false, "d_type=%u", child
->d_type
); 
1755             Find(root
, base 
+ name 
+ "/", code
, link
); 
1757             code(base 
+ name
, fun([&](const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &code
) { 
1758                 std::string 
access(root 
+ base 
+ name
); 
1759                 Open(access
, fun([&](std::streambuf 
&data
, const void *flag
) { 
1760                     auto from(path 
+ name
); 
1762                     commit_
[from
] = Temporary(save
, from
); 
1769 void DiskFolder::Save(const std::string 
&path
, const void *flag
, const Functor
<void (std::streambuf 
&)> &code
) { 
1771     auto from(Path(path
)); 
1772     commit_
[from
] = Temporary(save
, from
); 
1776 bool DiskFolder::Look(const std::string 
&path
) { 
1777     return _syscall(access(Path(path
).c_str(), R_OK
), ENOENT
) == 0; 
1780 void DiskFolder::Open(const std::string 
&path
, const Functor
<void (std::streambuf 
&, const void *)> &code
) { 
1782     auto result(data
.open(Path(path
).c_str(), std::ios::binary 
| std::ios::in
)); 
1783     _assert_(result 
== &data
, "DiskFolder::Open(%s)", path
.c_str()); 
1787 void DiskFolder::Find(const std::string 
&path
, const Functor
<void (const std::string 
&, const Functor
<void (const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &)> &)> &code
, const Functor
<void (const std::string 
&, const Functor
<std::string ()> &)> &link
) { 
1788     Find(path
, "", code
, link
); 
1792 SubFolder::SubFolder(Folder 
&parent
, const std::string 
&path
) : 
1798 void SubFolder::Save(const std::string 
&path
, const void *flag
, const Functor
<void (std::streambuf 
&)> &code
) { 
1799     return parent_
.Save(path_ 
+ path
, flag
, code
); 
1802 bool SubFolder::Look(const std::string 
&path
) { 
1803     return parent_
.Look(path_ 
+ path
); 
1806 void SubFolder::Open(const std::string 
&path
, const Functor
<void (std::streambuf 
&, const void *)> &code
) { 
1807     return parent_
.Open(path_ 
+ path
, code
); 
1810 void SubFolder::Find(const std::string 
&path
, const Functor
<void (const std::string 
&, const Functor
<void (const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &)> &)> &code
, const Functor
<void (const std::string 
&, const Functor
<std::string ()> &)> &link
) { 
1811     return parent_
.Find(path_ 
+ path
, code
, link
); 
1814 std::string 
UnionFolder::Map(const std::string 
&path
) { 
1815     auto remap(remaps_
.find(path
)); 
1816     if (remap 
== remaps_
.end()) 
1818     return remap
->second
; 
1821 void UnionFolder::Map(const std::string 
&path
, const Functor
<void (const std::string 
&, const Functor
<void (const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &)> &)> &code
, const std::string 
&file
, const Functor
<void (const Functor
<void (std::streambuf 
&, const void *)> &)> &save
) { 
1822     if (file
.size() >= path
.size() && file
.substr(0, path
.size()) == path
) 
1823         code(file
.substr(path
.size()), fun([&](const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &code
) { 
1824             save(fun([&](std::streambuf 
&data
, const void *flag
) { 
1825                 parent_
.Save(file
, flag
, fun([&](std::streambuf 
&save
) { 
1832 UnionFolder::UnionFolder(Folder 
&parent
) : 
1837 void UnionFolder::Save(const std::string 
&path
, const void *flag
, const Functor
<void (std::streambuf 
&)> &code
) { 
1838     return parent_
.Save(Map(path
), flag
, code
); 
1841 bool UnionFolder::Look(const std::string 
&path
) { 
1842     auto file(resets_
.find(path
)); 
1843     if (file 
!= resets_
.end()) 
1845     return parent_
.Look(Map(path
)); 
1848 void UnionFolder::Open(const std::string 
&path
, const Functor
<void (std::streambuf 
&, const void *)> &code
) { 
1849     auto file(resets_
.find(path
)); 
1850     if (file 
== resets_
.end()) 
1851         return parent_
.Open(Map(path
), code
); 
1852     auto &entry(file
->second
); 
1854     auto &data(entry
.first
); 
1855     data
.pubseekpos(0, std::ios::in
); 
1856     code(data
, entry
.second
); 
1859 void UnionFolder::Find(const std::string 
&path
, const Functor
<void (const std::string 
&, const Functor
<void (const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &)> &)> &code
, const Functor
<void (const std::string 
&, const Functor
<std::string ()> &)> &link
) { 
1860     parent_
.Find(path
, fun([&](const std::string 
&name
, const Functor
<void (const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &)> &save
) { 
1861         if (deletes_
.find(path 
+ name
) == deletes_
.end()) 
1863     }), fun([&](const std::string 
&name
, const Functor
<std::string ()> &read
) { 
1864         if (deletes_
.find(path 
+ name
) == deletes_
.end()) 
1868     for (auto &reset 
: resets_
) 
1869         Map(path
, code
, reset
.first
, fun([&](const Functor
<void (std::streambuf 
&, const void *)> &code
) { 
1870             auto &entry(reset
.second
); 
1871             entry
.first
.pubseekpos(0, std::ios::in
); 
1872             code(entry
.first
, entry
.second
); 
1875     for (auto &remap 
: remaps_
) 
1876         Map(path
, code
, remap
.first
, fun([&](const Functor
<void (std::streambuf 
&, const void *)> &code
) { 
1877             parent_
.Open(remap
.second
, fun([&](std::streambuf 
&data
, const void *flag
) { 
1883 #ifndef LDID_NOTOOLS 
1884 static size_t copy(std::streambuf 
&source
, std::streambuf 
&target
) { 
1888         size_t writ(source
.sgetn(data
, sizeof(data
))); 
1891         _assert(target
.sputn(data
, writ
) == writ
); 
1897 #ifndef LDID_NOPLIST 
1898 static plist_t 
plist(const std::string 
&data
) { 
1899     plist_t 
plist(NULL
); 
1900     if (Starts(data
, "bplist00")) 
1901         plist_from_bin(data
.data(), data
.size(), &plist
); 
1903         plist_from_xml(data
.data(), data
.size(), &plist
); 
1904     _assert(plist 
!= NULL
); 
1908 static void plist_d(std::streambuf 
&buffer
, const Functor
<void (plist_t
)> &code
) { 
1909     std::stringbuf data
; 
1911     auto node(plist(data
.str())); 
1912     _scope({ plist_free(node
); }); 
1913     _assert(plist_get_node_type(node
) == PLIST_DICT
); 
1917 static std::string 
plist_s(plist_t node
) { 
1918     _assert(node 
!= NULL
); 
1919     _assert(plist_get_node_type(node
) == PLIST_STRING
); 
1921     plist_get_string_val(node
, &data
); 
1922     _scope({ free(data
); }); 
1938     std::vector
<std::string
> matches_
; 
1941     Expression(const std::string 
&code
) { 
1942         _assert_(regcomp(®ex_
, code
.c_str(), REG_EXTENDED
) == 0, "regcomp()"); 
1943         matches_
.resize(regex_
.re_nsub 
+ 1); 
1950     bool operator ()(const std::string 
&data
) { 
1951         regmatch_t matches
[matches_
.size()]; 
1952         auto value(regexec(®ex_
, data
.c_str(), matches_
.size(), matches
, 0)); 
1953         if (value 
== REG_NOMATCH
) 
1955         _assert_(value 
== 0, "regexec()"); 
1956         for (size_t i(0); i 
!= matches_
.size(); ++i
) 
1957             matches_
[i
].assign(data
.data() + matches
[i
].rm_so
, matches
[i
].rm_eo 
- matches
[i
].rm_so
); 
1961     const std::string 
&operator [](size_t index
) const { 
1962         return matches_
[index
]; 
1971     mutable std::auto_ptr
<Expression
> regex_
; 
1973     Rule(unsigned weight
, Mode mode
, const std::string 
&code
) : 
1980     Rule(const Rule 
&rhs
) : 
1981         weight_(rhs
.weight_
), 
1987     void Compile() const { 
1988         regex_
.reset(new Expression(code_
)); 
1991     bool operator ()(const std::string 
&data
) const { 
1992         _assert(regex_
.get() != NULL
); 
1993         return (*regex_
)(data
); 
1996     bool operator <(const Rule 
&rhs
) const { 
1997         if (weight_ 
> rhs
.weight_
) 
1999         if (weight_ 
< rhs
.weight_
) 
2001         return mode_ 
> rhs
.mode_
; 
2006     bool operator ()(const Rule 
*lhs
, const Rule 
*rhs
) const { 
2007         return lhs
->code_ 
< rhs
->code_
; 
2011 #ifndef LDID_NOPLIST 
2012 static std::vector
<char> Sign(const uint8_t *prefix
, size_t size
, std::streambuf 
&buffer
, Hash 
&hash
, std::streambuf 
&save
, const std::string 
&identifier
, const std::string 
&entitlements
, const std::string 
&requirement
, const std::string 
&key
, const Slots 
&slots
) { 
2013     // XXX: this is a miserable fail 
2014     std::stringbuf temp
; 
2015     put(temp
, prefix
, size
); 
2017     auto data(temp
.str()); 
2019     HashProxy 
proxy(hash
, save
); 
2020     return Sign(data
.data(), data
.size(), proxy
, identifier
, entitlements
, requirement
, key
, slots
); 
2023 Bundle 
Sign(const std::string 
&root
, Folder 
&folder
, const std::string 
&key
, std::map
<std::string
, Hash
> &remote
, const std::string 
&entitlements
, const std::string 
&requirement
) { 
2024     std::string executable
; 
2025     std::string identifier
; 
2029     std::string 
info("Info.plist"); 
2030     if (!folder
.Look(info
) && folder
.Look("Resources/" + info
)) { 
2032         info 
= "Resources/" + info
; 
2035     folder
.Open(info
, fun([&](std::streambuf 
&buffer
, const void *flag
) { 
2036         plist_d(buffer
, fun([&](plist_t node
) { 
2037             executable 
= plist_s(plist_dict_get_item(node
, "CFBundleExecutable")); 
2038             identifier 
= plist_s(plist_dict_get_item(node
, "CFBundleIdentifier")); 
2042     if (!mac 
&& folder
.Look("MacOS/" + executable
)) { 
2043         executable 
= "MacOS/" + executable
; 
2047     static const std::string 
directory("_CodeSignature/"); 
2048     static const std::string 
signature(directory 
+ "CodeResources"); 
2050     std::map
<std::string
, std::multiset
<Rule
>> versions
; 
2052     auto &rules1(versions
[""]); 
2053     auto &rules2(versions
["2"]); 
2055     const std::string 
resources(mac 
? "Resources/" : ""); 
2058         rules1
.insert(Rule
{1, NoMode
, "^" + resources
}); 
2059         if (!mac
) rules1
.insert(Rule
{10000, OmitMode
, "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/|())SC_Info/[^/]+\\.(sinf|supf|supp)$"}); 
2060         rules1
.insert(Rule
{1000, OptionalMode
, "^" + resources 
+ ".*\\.lproj/"}); 
2061         rules1
.insert(Rule
{1100, OmitMode
, "^" + resources 
+ ".*\\.lproj/locversion.plist$"}); 
2062         if (!mac
) rules1
.insert(Rule
{10000, OmitMode
, "^Watch/[^/]+\\.app/(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/)SC_Info/[^/]+\\.(sinf|supf|supp)$"}); 
2063         rules1
.insert(Rule
{1, NoMode
, "^version.plist$"}); 
2067         rules2
.insert(Rule
{11, NoMode
, ".*\\.dSYM($|/)"}); 
2068         rules2
.insert(Rule
{20, NoMode
, "^" + resources
}); 
2069         rules2
.insert(Rule
{2000, OmitMode
, "^(.*/)?\\.DS_Store$"}); 
2070         if (!mac
) rules2
.insert(Rule
{10000, OmitMode
, "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/|())SC_Info/[^/]+\\.(sinf|supf|supp)$"}); 
2071         rules2
.insert(Rule
{10, NestedMode
, "^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/"}); 
2072         rules2
.insert(Rule
{1, NoMode
, "^.*"}); 
2073         rules2
.insert(Rule
{1000, OptionalMode
, "^" + resources 
+ ".*\\.lproj/"}); 
2074         rules2
.insert(Rule
{1100, OmitMode
, "^" + resources 
+ ".*\\.lproj/locversion.plist$"}); 
2075         rules2
.insert(Rule
{20, OmitMode
, "^Info\\.plist$"}); 
2076         rules2
.insert(Rule
{20, OmitMode
, "^PkgInfo$"}); 
2077         if (!mac
) rules2
.insert(Rule
{10000, OmitMode
, "^Watch/[^/]+\\.app/(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/)SC_Info/[^/]+\\.(sinf|supf|supp)$"}); 
2078         rules2
.insert(Rule
{10, NestedMode
, "^[^/]+$"}); 
2079         rules2
.insert(Rule
{20, NoMode
, "^embedded\\.provisionprofile$"}); 
2080         rules2
.insert(Rule
{20, NoMode
, "^version\\.plist$"}); 
2083     std::map
<std::string
, Hash
> local
; 
2085     std::string 
failure(mac 
? "Contents/|Versions/[^/]*/Resources/" : ""); 
2086     Expression 
nested("^(Frameworks/[^/]*\\.framework|PlugIns/[^/]*\\.appex(()|/[^/]*.app))/(" + failure 
+ ")Info\\.plist$"); 
2087     std::map
<std::string
, Bundle
> bundles
; 
2089     folder
.Find("", fun([&](const std::string 
&name
, const Functor
<void (const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &)> &code
) { 
2092         auto bundle(root 
+ Split(name
).dir
); 
2093         bundle
.resize(bundle
.size() - resources
.size()); 
2094         SubFolder 
subfolder(folder
, bundle
); 
2095         bundles
[nested
[1]] = Sign(bundle
, subfolder
, key
, local
, "", ""); 
2096     }), fun([&](const std::string 
&name
, const Functor
<std::string ()> &read
) { 
2099     std::set
<std::string
> excludes
; 
2101     auto exclude([&](const std::string 
&name
) { 
2102         // BundleDiskRep::adjustResources -> builder.addExclusion 
2103         if (name 
== executable 
|| Starts(name
, directory
) || Starts(name
, "_MASReceipt/") || name 
== "CodeResources") 
2106         for (const auto &bundle 
: bundles
) 
2107             if (Starts(name
, bundle
.first 
+ "/")) { 
2108                 excludes
.insert(name
); 
2115     std::map
<std::string
, std::string
> links
; 
2117     folder
.Find("", fun([&](const std::string 
&name
, const Functor
<void (const Functor
<void (std::streambuf 
&, std::streambuf 
&)> &)> &code
) { 
2121         if (local
.find(name
) != local
.end()) 
2123         auto &hash(local
[name
]); 
2125         code(fun([&](std::streambuf 
&data
, std::streambuf 
&save
) { 
2135             auto size(most(data
, &header
.bytes
, sizeof(header
.bytes
))); 
2137             if (name 
!= "_WatchKitStub/WK" && size 
== sizeof(header
.bytes
)) 
2138                 switch (Swap(header
.magic
)) { 
2140                         // Java class file format 
2141                         if (Swap(header
.count
) >= 40) 
2144                     case MH_MAGIC
: case MH_MAGIC_64
: 
2145                     case MH_CIGAM
: case MH_CIGAM_64
: 
2147                         Sign(header
.bytes
, size
, data
, hash
, save
, identifier
, "", "", key
, slots
); 
2151             HashProxy 
proxy(hash
, save
); 
2152             put(proxy
, header
.bytes
, size
); 
2155     }), fun([&](const std::string 
&name
, const Functor
<std::string ()> &read
) { 
2159         links
[name
] = read(); 
2162     auto plist(plist_new_dict()); 
2163     _scope({ plist_free(plist
); }); 
2165     for (const auto &version 
: versions
) { 
2166         auto files(plist_new_dict()); 
2167         plist_dict_set_item(plist
, ("files" + version
.first
).c_str(), files
); 
2169         for (const auto &rule 
: version
.second
) 
2172         bool old(&version
.second 
== &rules1
); 
2174         for (const auto &hash 
: local
) 
2175             for (const auto &rule 
: version
.second
) 
2176                 if (rule(hash
.first
)) { 
2177                     if (!old 
&& mac 
&& excludes
.find(hash
.first
) != excludes
.end()); 
2178                     else if (old 
&& rule
.mode_ 
== NoMode
) 
2179                         plist_dict_set_item(files
, hash
.first
.c_str(), plist_new_data(hash
.second
.sha1_
, sizeof(hash
.second
.sha1_
))); 
2180                     else if (rule
.mode_ 
!= OmitMode
) { 
2181                         auto entry(plist_new_dict()); 
2182                         plist_dict_set_item(entry
, "hash", plist_new_data(hash
.second
.sha1_
, sizeof(hash
.second
.sha1_
))); 
2184                             plist_dict_set_item(entry
, "hash2", plist_new_data(hash
.second
.sha256_
, sizeof(hash
.second
.sha256_
))); 
2185                         if (rule
.mode_ 
== OptionalMode
) 
2186                             plist_dict_set_item(entry
, "optional", plist_new_bool(true)); 
2187                         plist_dict_set_item(files
, hash
.first
.c_str(), entry
); 
2193         for (const auto &link 
: links
) 
2194             for (const auto &rule 
: version
.second
) 
2195                 if (rule(link
.first
)) { 
2196                     if (rule
.mode_ 
!= OmitMode
) { 
2197                         auto entry(plist_new_dict()); 
2198                         plist_dict_set_item(entry
, "symlink", plist_new_string(link
.second
.c_str())); 
2199                         if (rule
.mode_ 
== OptionalMode
) 
2200                             plist_dict_set_item(entry
, "optional", plist_new_bool(true)); 
2201                         plist_dict_set_item(files
, link
.first
.c_str(), entry
); 
2208             for (const auto &bundle 
: bundles
) { 
2209                 auto entry(plist_new_dict()); 
2210                 plist_dict_set_item(entry
, "cdhash", plist_new_data(bundle
.second
.hash
.data(), bundle
.second
.hash
.size())); 
2211                 plist_dict_set_item(entry
, "requirement", plist_new_string("anchor apple generic")); 
2212                 plist_dict_set_item(files
, bundle
.first
.c_str(), entry
); 
2216     for (const auto &version 
: versions
) { 
2217         auto rules(plist_new_dict()); 
2218         plist_dict_set_item(plist
, ("rules" + version
.first
).c_str(), rules
); 
2220         std::multiset
<const Rule 
*, RuleCode
> ordered
; 
2221         for (const auto &rule 
: version
.second
) 
2222             ordered
.insert(&rule
); 
2224         for (const auto &rule 
: ordered
) 
2225             if (rule
->weight_ 
== 1 && rule
->mode_ 
== NoMode
) 
2226                 plist_dict_set_item(rules
, rule
->code_
.c_str(), plist_new_bool(true)); 
2228                 auto entry(plist_new_dict()); 
2229                 plist_dict_set_item(rules
, rule
->code_
.c_str(), entry
); 
2231                 switch (rule
->mode_
) { 
2235                         plist_dict_set_item(entry
, "omit", plist_new_bool(true)); 
2238                         plist_dict_set_item(entry
, "optional", plist_new_bool(true)); 
2241                         plist_dict_set_item(entry
, "nested", plist_new_bool(true)); 
2244                         plist_dict_set_item(entry
, "top", plist_new_bool(true)); 
2248                 if (rule
->weight_ 
>= 10000) 
2249                     plist_dict_set_item(entry
, "weight", plist_new_uint(rule
->weight_
)); 
2250                 else if (rule
->weight_ 
!= 1) 
2251                     plist_dict_set_item(entry
, "weight", plist_new_real(rule
->weight_
)); 
2255     folder
.Save(signature
, NULL
, fun([&](std::streambuf 
&save
) { 
2256         HashProxy 
proxy(local
[signature
], save
); 
2259         plist_to_xml(plist
, &xml
, &size
); 
2260         _scope({ free(xml
); }); 
2261         put(proxy
, xml
, size
); 
2265     bundle
.path 
= executable
; 
2267     folder
.Open(executable
, fun([&](std::streambuf 
&buffer
, const void *flag
) { 
2268         folder
.Save(executable
, flag
, fun([&](std::streambuf 
&save
) { 
2270             slots
[1] = local
.at(info
); 
2271             slots
[3] = local
.at(signature
); 
2272             bundle
.hash 
= Sign(NULL
, 0, buffer
, local
[executable
], save
, identifier
, entitlements
, requirement
, key
, slots
); 
2276     for (const auto &entry 
: local
) 
2277         remote
[root 
+ entry
.first
] = entry
.second
; 
2282 Bundle 
Sign(const std::string 
&root
, Folder 
&folder
, const std::string 
&key
, const std::string 
&entitlements
, const std::string 
&requirement
) { 
2283     std::map
<std::string
, Hash
> local
; 
2284     return Sign(root
, folder
, key
, local
, entitlements
, requirement
); 
2291 #ifndef LDID_NOTOOLS 
2292 int main(int argc
, char *argv
[]) { 
2293 #ifndef LDID_NOSMIME 
2294     OpenSSL_add_all_algorithms(); 
2302     little_ 
= endian
.byte
[0]; 
2308 #ifndef LDID_NOFLAGT 
2322     uint32_t flag_CPUType(_not(uint32_t)); 
2323     uint32_t flag_CPUSubtype(_not(uint32_t)); 
2325     const char *flag_I(NULL
); 
2327 #ifndef LDID_NOFLAGT 
2337     std::vector
<std::string
> files
; 
2340         fprintf(stderr
, "usage: %s -S[entitlements.xml] <binary>\n", argv
[0]); 
2341         fprintf(stderr
, "   %s -e MobileSafari\n", argv
[0]); 
2342         fprintf(stderr
, "   %s -S cat\n", argv
[0]); 
2343         fprintf(stderr
, "   %s -Stfp.xml gdb\n", argv
[0]); 
2347     for (int argi(1); argi 
!= argc
; ++argi
) 
2348         if (argv
[argi
][0] != '-') 
2349             files
.push_back(argv
[argi
]); 
2350         else switch (argv
[argi
][1]) { 
2357             case 'e': flag_e 
= true; break; 
2360                 const char *slot 
= argv
[argi
] + 2; 
2361                 const char *colon 
= strchr(slot
, ':'); 
2362                 _assert(colon 
!= NULL
); 
2363                 Map 
file(colon 
+ 1, O_RDONLY
, PROT_READ
, MAP_PRIVATE
); 
2365                 unsigned number(strtoul(slot
, &arge
, 0)); 
2366                 _assert(arge 
== colon
); 
2367                 sha1(slots
[number
], file
.data(), file
.size()); 
2370             case 'q': flag_q 
= true; break; 
2373                 const char *xml 
= argv
[argi
] + 2; 
2374                 requirement
.open(xml
, O_RDONLY
, PROT_READ
, MAP_PRIVATE
); 
2377             case 'D': flag_D 
= true; break; 
2379             case 'a': flag_a 
= true; break; 
2384                 if (argv
[argi
][2] != '\0') { 
2385                     const char *cpu 
= argv
[argi
] + 2; 
2386                     const char *colon 
= strchr(cpu
, ':'); 
2387                     _assert(colon 
!= NULL
); 
2389                     flag_CPUType 
= strtoul(cpu
, &arge
, 0); 
2390                     _assert(arge 
== colon
); 
2391                     flag_CPUSubtype 
= strtoul(colon 
+ 1, &arge
, 0); 
2392                     _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
2406                 if (argv
[argi
][2] != '\0') { 
2407                     const char *xml 
= argv
[argi
] + 2; 
2408                     entitlements
.open(xml
, O_RDONLY
, PROT_READ
, MAP_PRIVATE
); 
2413                 if (argv
[argi
][2] != '\0') 
2414                     key
.open(argv
[argi
] + 2, O_RDONLY
, PROT_READ
, MAP_PRIVATE
); 
2417 #ifndef LDID_NOFLAGT 
2420                 if (argv
[argi
][2] == '-') 
2424                     timev 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
2425                     _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
2435                 flag_I 
= argv
[argi
] + 2; 
2443     _assert(flag_S 
|| key
.empty()); 
2444     _assert(flag_S 
|| flag_I 
== NULL
); 
2446     if (files
.empty()) usage
: { 
2450     size_t filei(0), filee(0); 
2451     _foreach (file
, files
) try { 
2452         std::string 
path(file
); 
2455         _syscall(stat(path
.c_str(), &info
)); 
2457         if (S_ISDIR(info
.st_mode
)) { 
2458 #ifndef LDID_NOPLIST 
2460             ldid::DiskFolder 
folder(path
); 
2461             path 
+= "/" + Sign("", folder
, key
, entitlements
, requirement
).path
; 
2465         } else if (flag_S 
|| flag_r
) { 
2466             Map 
input(path
, O_RDONLY
, PROT_READ
, MAP_PRIVATE
); 
2468             std::filebuf output
; 
2470             auto temp(Temporary(output
, split
)); 
2473                 ldid::Unsign(input
.data(), input
.size(), output
); 
2475                 std::string 
identifier(flag_I 
?: split
.base
.c_str()); 
2476                 ldid::Sign(input
.data(), input
.size(), output
, identifier
, entitlements
, requirement
, key
, slots
); 
2483 #ifndef LDID_NOFLAGT 
2490         Map 
mapping(path
, modify
); 
2491         FatHeader 
fat_header(mapping
.data(), mapping
.size()); 
2493         _foreach (mach_header
, fat_header
.GetMachHeaders()) { 
2494             struct linkedit_data_command 
*signature(NULL
); 
2495             struct encryption_info_command 
*encryption(NULL
); 
2498                 if (mach_header
.GetCPUType() != flag_CPUType
) 
2500                 if (mach_header
.GetCPUSubtype() != flag_CPUSubtype
) 
2505                 printf("cpu=0x%x:0x%x\n", mach_header
.GetCPUType(), mach_header
.GetCPUSubtype()); 
2507             _foreach (load_command
, mach_header
.GetLoadCommands()) { 
2508                 uint32_t cmd(mach_header
.Swap(load_command
->cmd
)); 
2511                 else if (cmd 
== LC_CODE_SIGNATURE
) 
2512                     signature 
= reinterpret_cast<struct linkedit_data_command 
*>(load_command
); 
2513                 else if (cmd 
== LC_ENCRYPTION_INFO 
|| cmd 
== LC_ENCRYPTION_INFO_64
) 
2514                     encryption 
= reinterpret_cast<struct encryption_info_command 
*>(load_command
); 
2515                 else if (cmd 
== LC_LOAD_DYLIB
) { 
2516                     volatile struct dylib_command 
*dylib_command(reinterpret_cast<struct dylib_command 
*>(load_command
)); 
2517                     const char *name(reinterpret_cast<const char *>(load_command
) + mach_header
.Swap(dylib_command
->dylib
.name
)); 
2519                     if (strcmp(name
, "/System/Library/Frameworks/UIKit.framework/UIKit") == 0) { 
2522                             version
.value 
= mach_header
.Swap(dylib_command
->dylib
.current_version
); 
2523                             printf("uikit=%u.%u.%u\n", version
.major
, version
.minor
, version
.patch
); 
2527 #ifndef LDID_NOFLAGT 
2528                 else if (cmd 
== LC_ID_DYLIB
) { 
2529                     volatile struct dylib_command 
*dylib_command(reinterpret_cast<struct dylib_command 
*>(load_command
)); 
2537                             dylib_command
->dylib
.timestamp 
= 0; 
2538                             timed 
= hash(reinterpret_cast<uint8_t *>(mach_header
.GetBase()), mach_header
.GetSize(), timev
); 
2541                         dylib_command
->dylib
.timestamp 
= mach_header
.Swap(timed
); 
2548                 _assert(encryption 
!= NULL
); 
2549                 encryption
->cryptid 
= mach_header
.Swap(0); 
2553                 _assert(signature 
!= NULL
); 
2555                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
2557                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
2558                 uint8_t *blob 
= top 
+ data
; 
2559                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
2561                 for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
2562                     if (Swap(super
->index
[index
].type
) == CSSLOT_ENTITLEMENTS
) { 
2563                         uint32_t begin 
= Swap(super
->index
[index
].offset
); 
2564                         struct Blob 
*entitlements 
= reinterpret_cast<struct Blob 
*>(blob 
+ begin
); 
2565                         fwrite(entitlements 
+ 1, 1, Swap(entitlements
->length
) - sizeof(*entitlements
), stdout
); 
2570                 _assert(signature 
!= NULL
); 
2572                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
2574                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
2575                 uint8_t *blob 
= top 
+ data
; 
2576                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
2578                 for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
2579                     if (Swap(super
->index
[index
].type
) == CSSLOT_REQUIREMENTS
) { 
2580                         uint32_t begin 
= Swap(super
->index
[index
].offset
); 
2581                         struct Blob 
*requirement 
= reinterpret_cast<struct Blob 
*>(blob 
+ begin
); 
2582                         fwrite(requirement
, 1, Swap(requirement
->length
), stdout
); 
2587                 _assert(signature 
!= NULL
); 
2589                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
2591                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
2592                 uint8_t *blob 
= top 
+ data
; 
2593                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
2595                 for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
2596                     if (Swap(super
->index
[index
].type
) == CSSLOT_CODEDIRECTORY
) { 
2597                         uint32_t begin 
= Swap(super
->index
[index
].offset
); 
2598                         struct CodeDirectory 
*directory 
= reinterpret_cast<struct CodeDirectory 
*>(blob 
+ begin 
+ sizeof(Blob
)); 
2600                         uint8_t (*hashes
)[LDID_SHA1_DIGEST_LENGTH
] = reinterpret_cast<uint8_t (*)[LDID_SHA1_DIGEST_LENGTH
]>(blob 
+ begin 
+ Swap(directory
->hashOffset
)); 
2601                         uint32_t pages 
= Swap(directory
->nCodeSlots
); 
2604                             for (size_t i 
= 0; i 
!= pages 
- 1; ++i
) 
2605                                 sha1(hashes
[i
], top 
+ PageSize_ 
* i
, PageSize_
); 
2607                             sha1(hashes
[pages 
- 1], top 
+ PageSize_ 
* (pages 
- 1), ((data 
- 1) % PageSize_
) + 1); 
2613     } catch (const char *) {