#include "muscle++.h"
#include <security_utilities/debugging.h>
namespace Security {
namespace Muscle {
Error::Error(MSC_RV err) : error(err)
{
SECURITY_EXCEPTION_THROW_OTHER(this, err, (char *)"muscle");
}
const char *Error::what() const throw ()
{
return msc_error(error);
}
void Error::throwMe(MSC_RV err)
{
throw Error(err);
}
OSStatus Error::osStatus() const
{
return -1; }
int Error::unixError() const
{
return EINVAL; }
Connection::Connection()
: mIsOpen(false), mCurrentTransaction(NULL)
{
}
Connection::~Connection()
{
assert(!mCurrentTransaction);
close();
}
void Connection::open(const PCSC::ReaderState &reader, unsigned share)
{
MSCTokenInfo info;
strncpy(info.slotName, reader.name(), MAX_READERNAME);
assert(reader.length() <= MAX_ATR_SIZE);
memcpy(info.tokenId, reader.data(), reader.length());
info.tokenIdLength = (MSCULong32)reader.length();
Error::check(::MSCEstablishConnection(&info, share, NULL, 0, this));
mIsOpen = true;
secdebug("muscle", "%p opened %s", this, info.slotName);
updateStatus();
}
void Connection::close()
{
if (mIsOpen) {
secdebug("muscle", "%p closing", this);
Error::check(::MSCReleaseConnection(this, SCARD_LEAVE_CARD));
mIsOpen = false;
}
}
void Connection::begin(Transaction *trans)
{
assert(!mCurrentTransaction);
Error::check(::MSCBeginTransaction(this));
secdebug("muscle", "%p start transaction %p", this, trans);
mCurrentTransaction = trans;
}
void Connection::end(Transaction *trans)
{
assert(trans == mCurrentTransaction);
secdebug("muscle", "%p end transaction %p", this, trans);
Error::check(::MSCEndTransaction(this, SCARD_LEAVE_CARD));
mCurrentTransaction = NULL;
}
void Connection::updateStatus()
{
Error::check(::MSCGetStatus(this, this));
}
template <class Info, class Item, MSC_RV (*list)(MSCTokenConnection *, MSCUChar8, Info *)>
static void get(Connection *conn, Connection::ItemSet &items)
{
Info info;
MSCUChar8 seq = MSC_SEQUENCE_RESET;
for (;;) {
switch (MSC_RV rc = list(conn, seq, &info)) {
case MSC_SEQUENCE_END:
return;
case MSC_SUCCESS:
items.insert(new Item(info));
seq = MSC_SEQUENCE_NEXT;
break;
default:
Error::throwMe(rc);
}
}
}
void Connection::getItems(ItemSet &result, bool getKeys, bool getOthers)
{
ItemSet items;
if (getKeys)
get<MSCKeyInfo, Key, MSCListKeys>(this, items);
if (getOthers)
get<MSCObjectInfo, Object, MSCListObjects>(this, items);
items.swap(result);
}
Transaction::Transaction(Connection &con)
: connection(con)
{
connection.begin(this);
}
Transaction::~Transaction()
{
connection.end(this);
}
static void aclForm(string &s, MSCUShort16 acl, int offset, char c)
{
for (int n = 0; n < 5; n++) {
char p = '-';
switch (acl) {
case MSC_AUT_ALL: p = c; break;
case MSC_AUT_NONE: break;
default: if (acl & (MSC_AUT_PIN_0 << n)) p = c; break;
}
s[3 * n + offset] = p;
}
}
string ACL::form(char ue) const
{
string r = "---------------";
aclForm(r, mRead, 0, 'r');
aclForm(r, mWrite, 1, 'w');
aclForm(r, mErase, 2, ue);
return r;
}
CardItem::~CardItem()
{ }
Key::Key(const MSCKeyInfo &info)
: MSCKeyInfo(info)
{
snprintf(mKeyName, sizeof(mKeyName), "K%d", id());
}
const ACL &Key::acl() const { return reinterpret_cast<const ACL &>(keyACL); }
ACL &Key::acl() { return reinterpret_cast<ACL &>(keyACL); }
const char *Key::name() const { return mKeyName; }
unsigned Key::size() const { return keySize; }
void Key::debugDump()
{
printf("Key %d type %d size %d mode=0x%x dir=0x%x ACL %s\n",
keyNum, keyType, keySize, mode(), operations(), acl().form('u').c_str());
}
const char *Object::name() const { return objectID; }
unsigned Object::size() const { return objectSize; }
const ACL &Object::acl() const { return reinterpret_cast<const ACL &>(objectACL); }
ACL &Object::acl() { return reinterpret_cast<ACL &>(objectACL); }
void Object::debugDump()
{
printf("Object %s size %d ACL %s\n",
objectID, objectSize, acl().form('e').c_str());
}
} }