#include "filediskrep.h"
#include "StaticCode.h"
#include "macho++.h" // may perhaps move into security_utilities...
#include <cstring>
namespace Security {
namespace CodeSigning {
using namespace UnixPlusPlus;
FileDiskRep::FileDiskRep(const char *path)
: SingleDiskRep(path)
{
}
string FileDiskRep::attrName(const char *name)
{
static const char prefix[] = "com.apple.cs.";
return string(prefix) + name;
}
CFDataRef FileDiskRep::getAttribute(const char *name)
{
string aname = attrName(name);
ssize_t length = fd().getAttrLength(aname);
if (length < 0)
return NULL; CFMallocData buffer(length);
fd().getAttr(aname, buffer, length);
return buffer;
}
CFDataRef FileDiskRep::component(CodeDirectory::SpecialSlot slot)
{
if (const char *name = CodeDirectory::canonicalSlotName(slot))
return getAttribute(name);
else
return NULL;
}
const Requirements *FileDiskRep::defaultRequirements(const Architecture *)
{
char buffer[256];
size_t length = fd().read(buffer, sizeof(buffer), 0);
if (length > 3 && buffer[0] == '#' && buffer[1] == '!' && buffer[2] == '/') {
if (length == sizeof(buffer))
length--;
buffer[length] = '\0';
char *path = buffer + 2;
path[strcspn(path, " \t\n\r\f")] = '\0';
secdebug("filediskrep", "looks like a script for %s", path);
if (path[1])
try {
if (RefPointer<DiskRep> rep = DiskRep::bestFileGuess(path))
if (SecPointer<SecStaticCode> code = new SecStaticCode(rep))
if (const Requirement *req = code->designatedRequirement()) {
Requirements::Maker maker;
maker.add(kSecHostRequirementType, req->clone());
secdebug("filediskrep", "made a scripting host requirement");
return maker.make();
}
} catch (...) {
secdebug("filediskrep", "exception getting host requirement (ignored)");
}
}
return NULL;
}
string FileDiskRep::format()
{
return "generic";
}
DiskRep::Writer *FileDiskRep::writer()
{
return new Writer(this);
}
void FileDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
{
try {
fd().setAttr(attrName(CodeDirectory::canonicalSlotName(slot)),
CFDataGetBytePtr(data), CFDataGetLength(data));
} catch (const UnixError &error) {
if (error.error == ERANGE)
MacOSError::throwMe(errSecCSCMSTooLarge);
throw;
}
}
bool FileDiskRep::Writer::preferredStore()
{
return false;
}
} }