Skip to content

Commit 0f9fd29

Browse files
committed
Adds Application::entitlements()
1 parent c8e3460 commit 0f9fd29

4 files changed

Lines changed: 198 additions & 0 deletions

File tree

AltSign/Application.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99
#include "Application.hpp"
1010

1111
#include "Error.hpp"
12+
#include "ldid.hpp"
1213

1314
#include <fstream>
1415
#include <filesystem>
16+
#include <WinSock2.h>
17+
18+
#define odslog(msg) { std::stringstream ss; ss << msg << std::endl; OutputDebugStringA(ss.str().c_str()); }
1519

1620
extern std::vector<unsigned char> readFile(const char* filename);
1721

@@ -23,6 +27,37 @@ Application::Application()
2327

2428
Application::~Application()
2529
{
30+
for (auto& pair : _entitlements)
31+
{
32+
plist_free(pair.second);
33+
}
34+
}
35+
36+
Application::Application(const Application& app)
37+
{
38+
_name = app.name();
39+
_bundleIdentifier = app.bundleIdentifier();
40+
_version = app.version();
41+
_path = app.path();
42+
43+
// Don't assign _entitlementsString or _entitlements,
44+
// since each copy will create its own entitlements lazily.
45+
// Otherwise there might be duplicate frees in deconstructor.
46+
}
47+
48+
Application& Application::operator=(const Application& app)
49+
{
50+
if (this == &app)
51+
{
52+
return *this;
53+
}
54+
55+
_name = app.name();
56+
_bundleIdentifier = app.bundleIdentifier();
57+
_version = app.version();
58+
_path = app.path();
59+
60+
return *this;
2661
}
2762

2863
Application::Application(std::string appBundlePath)
@@ -136,4 +171,57 @@ std::vector<std::shared_ptr<Application>> Application::appExtensions() const
136171
}
137172

138173
return appExtensions;
174+
}
175+
176+
std::string Application::entitlementsString()
177+
{
178+
if (_entitlementsString == "")
179+
{
180+
_entitlementsString = ldid::Entitlements(this->path());
181+
}
182+
183+
return _entitlementsString;
184+
}
185+
186+
std::map<std::string, plist_t> Application::entitlements()
187+
{
188+
if (_entitlements.size() == 0)
189+
{
190+
auto rawEntitlements = this->entitlementsString();
191+
192+
plist_t plist = nullptr;
193+
plist_from_memory((const char*)rawEntitlements.data(), (int)rawEntitlements.size(), &plist);
194+
195+
if (plist != nullptr)
196+
{
197+
std::map<std::string, plist_t> entitlements;
198+
char* key = NULL;
199+
plist_t node = NULL;
200+
201+
plist_dict_iter it = NULL;
202+
plist_dict_new_iter(plist, &it);
203+
plist_dict_next_item(plist, it, &key, &node);
204+
205+
while (node != nullptr)
206+
{
207+
entitlements[key] = plist_copy(node);
208+
209+
node = NULL;
210+
free(key);
211+
key = NULL;
212+
plist_dict_next_item(plist, it, &key, &node);
213+
}
214+
215+
free(it);
216+
plist_free(plist);
217+
218+
_entitlements = entitlements;
219+
}
220+
else
221+
{
222+
odslog("Error parsing entitlements:\n" << rawEntitlements);
223+
}
224+
}
225+
226+
return _entitlements;
139227
}

AltSign/Application.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <optional>
1616
#include <string>
1717
#include <memory>
18+
#include <map>
1819

1920
#include <plist/plist.h>
2021

@@ -27,6 +28,9 @@ class Application
2728
~Application();
2829

2930
Application(std::string appBundlePath) /* throws */;
31+
32+
Application(const Application& app);
33+
Application& operator=(const Application& app);
3034

3135
std::string name() const;
3236
std::string bundleIdentifier() const;
@@ -35,6 +39,8 @@ class Application
3539

3640
std::shared_ptr<ProvisioningProfile> provisioningProfile();
3741
std::vector<std::shared_ptr<Application>> appExtensions() const;
42+
43+
std::map<std::string, plist_t> entitlements();
3844

3945
friend std::ostream& operator<<(std::ostream& os, const Application& app);
4046

@@ -45,6 +51,11 @@ class Application
4551
std::string _path;
4652

4753
std::shared_ptr<ProvisioningProfile> _provisioningProfile;
54+
55+
std::string _entitlementsString;
56+
std::map<std::string, plist_t> _entitlements;
57+
58+
std::string entitlementsString();
4859
};
4960

5061
#pragma GCC visibility pop

ldid/ldid.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2504,6 +2504,104 @@ namespace ldid {
25042504
}
25052505
#endif
25062506

2507+
// Based heavily on ldid::Sign executable locating logic.
2508+
std::string ExecutablePath(std::string bundlePath)
2509+
{
2510+
auto folder = ldid::DiskFolder(bundlePath);
2511+
2512+
std::string executable;
2513+
2514+
bool mac(false);
2515+
2516+
std::string info("Info.plist");
2517+
if (!folder.Look(info) && folder.Look("Resources/" + info)) {
2518+
mac = true;
2519+
info = "Resources/" + info;
2520+
}
2521+
2522+
folder.Open(info, fun([&](std::streambuf& buffer, size_t length, const void* flag) {
2523+
plist_d(buffer, length, fun([&](plist_t node) {
2524+
executable = plist_s(plist_dict_get_item(node, "CFBundleExecutable"));
2525+
}));
2526+
}));
2527+
2528+
if (!mac && folder.Look("MacOS/" + executable)) {
2529+
executable = "MacOS/" + executable;
2530+
mac = true;
2531+
}
2532+
2533+
return executable;
2534+
}
2535+
2536+
// Based heavily on ldid's -e argument logic.
2537+
std::string Entitlements(std::string path)
2538+
{
2539+
struct stat info;
2540+
_syscall(stat(path.c_str(), &info));
2541+
2542+
if (S_ISDIR(info.st_mode))
2543+
{
2544+
path += "/" + ExecutablePath(path);
2545+
}
2546+
2547+
std::stringstream stringstream;
2548+
2549+
Map mapping(path, false);
2550+
FatHeader fat_header(mapping.data(), mapping.size());
2551+
2552+
_foreach(mach_header, fat_header.GetMachHeaders())
2553+
{
2554+
struct linkedit_data_command* signature(NULL);
2555+
2556+
_foreach(load_command, mach_header.GetLoadCommands())
2557+
{
2558+
uint32_t cmd(mach_header.Swap(load_command->cmd));
2559+
if (cmd == LC_CODE_SIGNATURE)
2560+
{
2561+
signature = reinterpret_cast<struct linkedit_data_command*>(load_command);
2562+
}
2563+
}
2564+
2565+
if (signature != NULL)
2566+
{
2567+
uint32_t data = mach_header.Swap(signature->dataoff);
2568+
2569+
uint8_t* top = reinterpret_cast<uint8_t*>(mach_header.GetBase());
2570+
uint8_t* blob = top + data;
2571+
struct SuperBlob* super = reinterpret_cast<struct SuperBlob*>(blob);
2572+
2573+
for (size_t index(0); index != Swap(super->count); ++index)
2574+
{
2575+
if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS)
2576+
{
2577+
uint32_t begin = Swap(super->index[index].offset);
2578+
struct Blob* entitlements = reinterpret_cast<struct Blob*>(blob + begin);
2579+
2580+
char* bytes = (char*)(entitlements + 1);
2581+
int size = Swap(entitlements->length) - sizeof(*entitlements);
2582+
2583+
for (int i = 0; i < size; i++)
2584+
{
2585+
char byte = bytes[i];
2586+
stringstream << byte;
2587+
}
2588+
2589+
if (size > 0)
2590+
{
2591+
auto entitlementsString = stringstream.str();
2592+
2593+
// One valid mach_header is all we need to retrieve entitlements, so return to stop iterating over the next ones.
2594+
return entitlementsString;
2595+
}
2596+
}
2597+
}
2598+
}
2599+
}
2600+
2601+
// No entitlements found in any mach_header, so return empty string.
2602+
return "";
2603+
}
2604+
25072605
#endif
25082606
}
25092607

ldid/ldid.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ typedef std::map<uint32_t, Hash> Slots;
154154

155155
Hash 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, const Functor<void (double)> &percent);
156156

157+
__declspec(dllexport) std::string Entitlements(std::string path);
157158
}
158159

159160
#endif//LDID_HPP

0 commit comments

Comments
 (0)