#include "filediskrep.h"
#include "StaticCode.h"
#include <security_utilities/macho++.h>
#include <cstring>
namespace Security {
namespace CodeSigning {
using namespace UnixPlusPlus;
FileDiskRep::FileDiskRep(const char *path)
: SingleDiskRep(path)
{
CODESIGN_DISKREP_CREATE_FILE(this, (char*)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);
try {
ssize_t length = fd().getAttrLength(aname);
if (length < 0)
return NULL; CFMallocData buffer(length);
fd().getAttr(aname, buffer, length);
return buffer;
} catch (const UnixError &err) {
switch (err.error) {
case ENOTSUP: case EPERM: return NULL;
default:
throw;
}
}
}
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 *, const SigningContext &ctx)
{
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 *cmd = buffer + 2;
cmd[strcspn(cmd, " \t\n\r\f")] = '\0';
secdebug("filediskrep", "looks like a script for %s", cmd);
if (cmd[1])
try {
string path = ctx.sdkPath(cmd);
if (RefPointer<DiskRep> rep = DiskRep::bestFileGuess(path))
if (SecPointer<SecStaticCode> code = new SecStaticCode(rep))
if (const Requirement *req = code->designatedRequirement()) {
CODESIGN_SIGN_DEP_INTERP(this, (char*)cmd, (void*)req);
Requirements::Maker maker;
maker.add(kSecHostRequirementType, req->clone());
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;
}
}
void FileDiskRep::Writer::remove()
{
for (CodeDirectory::SpecialSlot slot = 0; slot < cdSlotCount; slot++)
if (const char *name = CodeDirectory::canonicalSlotName(slot))
fd().removeAttr(attrName(name));
fd().removeAttr(attrName(kSecCS_SIGNATUREFILE));
}
bool FileDiskRep::Writer::preferredStore()
{
return false;
}
} }