2 * Copyright (c) 2013 SURFnet bv
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 /*****************************************************************************
30 This class represents object records in a database
31 *****************************************************************************/
35 #include "OSPathSep.h"
37 #include "OSAttributes.h"
40 #include <sys/types.h>
46 // Create an object that can access a record, but don't do anything yet.
47 DBObject::DBObject(DB::Connection *connection, ObjectStoreToken *token)
48 : _mutex(MutexFactory::i()->getMutex()), _connection(connection), _token(token), _objectId(0), _transaction(NULL)
53 DBObject::DBObject(DB::Connection *connection, ObjectStoreToken *token, long long objectId)
54 : _mutex(MutexFactory::i()->getMutex()), _connection(connection), _token(token), _objectId(objectId), _transaction(NULL)
61 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _attributes.begin(); it!=_attributes.end(); ++it) {
67 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
73 MutexFactory::i()->recycleMutex(_mutex);
76 void DBObject::dropConnection()
78 MutexLocker lock(_mutex);
83 // create tables to support storage of attributes for the DBObject
84 bool DBObject::createTables()
86 MutexLocker lock(_mutex);
88 if (_connection == NULL)
90 ERROR_MSG("Object is not connected to the database.");
94 // Create the tables inside the database
95 DB::Statement cr_object = _connection->prepare("create table object (id integer primary key autoincrement);");
96 if (!_connection->execute(cr_object))
98 ERROR_MSG("Failed to create \"object\" table");
103 DB::Statement cr_attr_text = _connection->prepare(
104 "create table attribute_text ("
107 "object_id integer references object(id) on delete cascade,"
108 "id integer primary key autoincrement)"
110 if (!_connection->execute(cr_attr_text))
112 ERROR_MSG("Failed to create \"attribute_text\" table");
117 DB::Statement cr_attr_integer = _connection->prepare(
118 "create table attribute_integer ("
121 "object_id integer references object(id) on delete cascade,"
122 "id integer primary key autoincrement)"
124 if (!_connection->execute(cr_attr_integer))
126 ERROR_MSG("Failed to create \"attribute_integer\" table");
131 DB::Statement cr_attr_binary = _connection->prepare(
132 "create table attribute_binary ("
135 "object_id integer references object(id) on delete cascade,"
136 "id integer primary key autoincrement)"
138 if (!_connection->execute(cr_attr_binary))
140 ERROR_MSG("Failed to create \"attribute_binary\" table");
145 DB::Statement cr_attr_array = _connection->prepare(
146 "create table attribute_array ("
149 "object_id integer references object(id) on delete cascade,"
150 "id integer primary key autoincrement)"
152 if (!_connection->execute(cr_attr_array))
154 ERROR_MSG("Failed to create \"attribute_array\" table");
159 DB::Statement cr_attr_boolean = _connection->prepare(
160 "create table attribute_boolean ("
163 "object_id integer references object(id) on delete cascade,"
164 "id integer primary key autoincrement)"
166 if (!_connection->execute(cr_attr_boolean))
168 ERROR_MSG("Failed to create \"attribute_boolean\" table");
172 // attribute_datetime
173 DB::Statement cr_attr_datetime = _connection->prepare(
174 "create table attribute_datetime ("
177 "object_id integer references object(id) on delete cascade,"
178 "id integer primary key autoincrement)"
180 if (!_connection->execute(cr_attr_datetime))
182 ERROR_MSG("Failed to create \"attribute_datetime\" table");
187 DB::Statement cr_attr_real = _connection->prepare(
188 "create table attribute_real ("
191 "object_id integer references object(id) on delete cascade,"
192 "id integer primary key autoincrement)"
194 if (!_connection->execute(cr_attr_real))
196 ERROR_MSG("Failed to create \"attribute_real\" table");
203 bool DBObject::dropTables()
205 MutexLocker lock(_mutex);
207 if (_connection == NULL)
209 ERROR_MSG("Object is not connected to the database.");
213 // Create the tables inside the database
214 DB::Statement dr_object = _connection->prepare("drop table object");
215 if (!_connection->execute(dr_object))
217 ERROR_MSG("Failed to drop \"object\" table");
222 DB::Statement dr_attr_text = _connection->prepare("drop table attribute_text");
223 if (!_connection->execute(dr_attr_text))
225 ERROR_MSG("Failed to drop \"attribute_text\" table");
230 DB::Statement dr_attr_integer = _connection->prepare("drop table attribute_integer");
231 if (!_connection->execute(dr_attr_integer))
233 ERROR_MSG("Failed to drop \"attribute_integer\" table");
238 DB::Statement dr_attr_binary = _connection->prepare("drop table attribute_binary");
239 if (!_connection->execute(dr_attr_binary))
241 ERROR_MSG("Failed to drop \"attribute_binary\" table");
246 DB::Statement dr_attr_array = _connection->prepare("drop table attribute_array");
247 if (!_connection->execute(dr_attr_array))
249 ERROR_MSG("Failed to drop \"attribute_array\" table");
254 DB::Statement dr_attr_boolean = _connection->prepare("drop table attribute_boolean");
255 if (!_connection->execute(dr_attr_boolean))
257 ERROR_MSG("Failed to drop \"attribute_boolean\" table");
261 // attribute_datetime
262 DB::Statement dr_attr_datetime = _connection->prepare("drop table attribute_datetime");
263 if (!_connection->execute(dr_attr_datetime))
265 ERROR_MSG("Failed to drop \"attribute_datetime\" table");
270 DB::Statement dr_attr_real = _connection->prepare("drop table attribute_real");
271 if (!_connection->execute(dr_attr_real))
273 ERROR_MSG("Failed to drop \"attribute_real\" table");
280 bool DBObject::find(long long objectId)
282 MutexLocker lock(_mutex);
284 if (_connection == NULL)
286 ERROR_MSG("Object is not connected to the database.");
291 ERROR_MSG("Invalid object_id 0 passed to find");
295 // find the object in the database for the given object_id
296 DB::Statement statement = _connection->prepare(
297 "select id from object where id=%lld",
299 if (!statement.isValid()) {
300 ERROR_MSG("Preparing object selection statement failed");
304 DB::Result result = _connection->perform(statement);
305 if (result.getLongLong(1) != objectId) {
306 ERROR_MSG("Failed to find object with id %lld",objectId);
310 _objectId = objectId;
314 bool DBObject::insert()
316 MutexLocker lock(_mutex);
318 if (_connection == NULL)
320 ERROR_MSG("Object is not connected to the database.");
324 DB::Statement statement = _connection->prepare("insert into object default values");
326 if (!_connection->execute(statement)) {
327 ERROR_MSG("Failed to insert a new object");
331 _objectId = _connection->lastInsertRowId();
332 return _objectId != 0;
335 bool DBObject::remove()
337 MutexLocker lock(_mutex);
339 if (_connection == NULL)
341 ERROR_MSG("Object is not connected to the database.");
345 DB::Statement statement = _connection->prepare("delete from object where id=%lld",_objectId);
347 if (!_connection->execute(statement)) {
348 ERROR_MSG("Failed to remove an existing object");
356 long long DBObject::objectId()
358 MutexLocker lock(_mutex);
363 static bool isModifiable(CK_ATTRIBUTE_TYPE type)
370 case CKA_SERIAL_NUMBER:
377 case CKA_VERIFY_RECOVER:
382 case CKA_SIGN_RECOVER:
384 case CKA_EXTRACTABLE:
385 case CKA_OS_TOKENFLAGS:
403 static AttributeKind attributeKind(CK_ATTRIBUTE_TYPE type)
406 case CKA_CLASS: return akInteger;
407 case CKA_TOKEN: return akBoolean;
408 case CKA_PRIVATE: return akBoolean;
409 case CKA_LABEL: return akBinary;
410 case CKA_APPLICATION: return akBinary;
411 case CKA_VALUE: return akBinary;
412 case CKA_OBJECT_ID: return akBinary;
413 case CKA_CERTIFICATE_TYPE: return akInteger;
414 case CKA_ISSUER: return akBinary;
415 case CKA_SERIAL_NUMBER: return akBinary;
416 case CKA_AC_ISSUER: return akBinary;
417 case CKA_OWNER: return akBinary;
418 case CKA_ATTR_TYPES: return akBinary;
419 case CKA_TRUSTED: return akBoolean;
420 case CKA_CERTIFICATE_CATEGORY: return akInteger;
421 case CKA_JAVA_MIDP_SECURITY_DOMAIN: return akInteger;
422 case CKA_URL: return akBinary;
423 case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: return akBinary;
424 case CKA_HASH_OF_ISSUER_PUBLIC_KEY: return akBinary;
425 case CKA_NAME_HASH_ALGORITHM: return akInteger;
426 case CKA_CHECK_VALUE: return akBinary;
427 case CKA_KEY_TYPE: return akInteger;
428 case CKA_SUBJECT: return akBinary;
429 case CKA_ID: return akBinary;
430 case CKA_SENSITIVE: return akBoolean;
431 case CKA_ENCRYPT: return akBoolean;
432 case CKA_DECRYPT: return akBoolean;
433 case CKA_WRAP: return akBoolean;
434 case CKA_UNWRAP: return akBoolean;
435 case CKA_SIGN: return akBoolean;
436 case CKA_SIGN_RECOVER: return akBoolean;
437 case CKA_VERIFY: return akBoolean;
438 case CKA_VERIFY_RECOVER: return akBoolean;
439 case CKA_DERIVE: return akBoolean;
440 case CKA_START_DATE: return akBinary;
441 case CKA_END_DATE: return akBinary;
442 case CKA_MODULUS: return akBinary;
443 case CKA_MODULUS_BITS: return akInteger;
444 case CKA_PUBLIC_EXPONENT: return akBinary;
445 case CKA_PRIVATE_EXPONENT: return akBinary;
446 case CKA_PRIME_1: return akBinary;
447 case CKA_PRIME_2: return akBinary;
448 case CKA_EXPONENT_1: return akBinary;
449 case CKA_EXPONENT_2: return akBinary;
450 case CKA_COEFFICIENT: return akBinary;
451 case CKA_PRIME: return akBinary;
452 case CKA_SUBPRIME: return akBinary;
453 case CKA_BASE: return akBinary;
454 case CKA_PRIME_BITS: return akInteger;
455 case CKA_SUBPRIME_BITS: return akInteger;
456 case CKA_VALUE_BITS: return akInteger;
457 case CKA_VALUE_LEN: return akInteger;
458 case CKA_EXTRACTABLE: return akBoolean;
459 case CKA_LOCAL: return akBoolean;
460 case CKA_NEVER_EXTRACTABLE: return akBoolean;
461 case CKA_ALWAYS_SENSITIVE: return akBoolean;
462 case CKA_KEY_GEN_MECHANISM: return akInteger;
463 case CKA_MODIFIABLE: return akBoolean;
464 case CKA_COPYABLE: return akBoolean;
465 case CKA_ECDSA_PARAMS: return akBinary;
466 case CKA_EC_POINT: return akBinary;
467 case CKA_SECONDARY_AUTH: return akBoolean;
468 case CKA_AUTH_PIN_FLAGS: return akInteger;
469 case CKA_ALWAYS_AUTHENTICATE: return akBoolean;
470 case CKA_WRAP_WITH_TRUSTED: return akBoolean;
474 case CKA_OTP_TIME_INTERVAL:
475 case CKA_OTP_USER_FRIENDLY_MODE:
476 case CKA_OTP_CHALLENGE_REQUIREMENT:
477 case CKA_OTP_TIME_REQUIREMENT:
478 case CKA_OTP_COUNTER_REQUIREMENT:
479 case CKA_OTP_PIN_REQUIREMENT:
480 case CKA_OTP_COUNTER:
482 case CKA_OTP_USER_IDENTIFIER:
483 case CKA_OTP_SERVICE_IDENTIFIER:
484 case CKA_OTP_SERVICE_LOGO:
485 case CKA_OTP_SERVICE_LOGO_TYPE:
487 case CKA_GOSTR3410_PARAMS: return akBinary;
488 case CKA_GOSTR3411_PARAMS: return akBinary;
489 case CKA_GOST28147_PARAMS: return akBinary;
491 case CKA_HW_FEATURE_TYPE:
492 case CKA_RESET_ON_INIT:
498 case CKA_CHAR_COLUMNS:
500 case CKA_BITS_PER_PIXEL:
502 case CKA_ENCODING_METHODS:
504 case CKA_MECHANISM_TYPE:
505 case CKA_REQUIRED_CMS_ATTRIBUTES:
506 case CKA_DEFAULT_CMS_ATTRIBUTES:
507 case CKA_SUPPORTED_CMS_ATTRIBUTES:
509 case CKA_WRAP_TEMPLATE: return akAttrMap;
510 case CKA_UNWRAP_TEMPLATE: return akAttrMap;
511 case CKA_DERIVE_TEMPLATE: return akAttrMap;
512 case CKA_ALLOWED_MECHANISMS: return akMechSet;
514 case CKA_OS_TOKENLABEL: return akBinary;
515 case CKA_OS_TOKENSERIAL: return akBinary;
516 case CKA_OS_TOKENFLAGS: return akInteger;
517 case CKA_OS_SOPIN: return akBinary;
518 case CKA_OS_USERPIN: return akBinary;
520 default: return akUnknown;
524 static bool decodeMechanismTypeSet(std::set<CK_MECHANISM_TYPE>& set, const unsigned char *binary, size_t size)
526 for (size_t pos = 0; pos < size; )
529 if (pos == size) break;
531 CK_MECHANISM_TYPE mechType;
532 if (pos + sizeof(mechType) > size)
534 ERROR_MSG("mechanism type set overrun");
538 memcpy(&mechType, binary + pos, sizeof(mechType));
539 pos += sizeof(mechType);
541 set.insert(mechType);
547 static void encodeMechanismTypeSet(ByteString& value, const std::set<CK_MECHANISM_TYPE>& set)
549 for (std::set<CK_MECHANISM_TYPE>::const_iterator i = set.begin(); i != set.end(); ++i)
551 CK_MECHANISM_TYPE mechType = *i;
552 value += ByteString((unsigned char *) &mechType, sizeof(mechType));
556 static bool decodeAttributeMap(std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& map, const unsigned char *binary, size_t size)
558 for (size_t pos = 0; pos < size; )
561 if (pos == size) break;
563 CK_ATTRIBUTE_TYPE attrType;
564 if (pos + sizeof(attrType) > size)
568 memcpy(&attrType, binary + pos, sizeof(attrType));
569 pos += sizeof(attrType);
571 AttributeKind attrKind;
572 if (pos + sizeof(AttributeKind) > size)
576 memcpy(&attrKind, binary + pos, sizeof(attrKind));
577 pos += sizeof(attrKind);
579 // Verify using attributeKind()?
586 if (pos + sizeof(value) > size)
590 memcpy(&value, binary + pos, sizeof(value));
591 pos += sizeof(value);
593 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
600 if (pos + sizeof(value) > size)
604 memcpy(&value, binary + pos, sizeof(value));
605 pos += sizeof(value);
607 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
615 if (pos + sizeof(len) > size)
619 memcpy(&len, binary + pos, sizeof(len));
622 if (pos + len > size)
627 memcpy(&value[0], binary + pos, len);
630 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
637 if (pos + sizeof(len) > size)
641 memcpy(&len, binary + pos, sizeof(len));
644 if (pos + len > size)
649 std::set<CK_MECHANISM_TYPE> value;
650 if (!decodeMechanismTypeSet(value, binary + pos, len)) {
655 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
660 ERROR_MSG("unsupported attribute kind in attribute map");
669 ERROR_MSG("attribute map template overrun");
674 static bool encodeAttributeMap(ByteString& value, const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& attributes)
676 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator i = attributes.begin(); i != attributes.end(); ++i)
678 CK_ATTRIBUTE_TYPE attrType = i->first;
679 value += ByteString((unsigned char*) &attrType, sizeof(attrType));
681 OSAttribute attr = i->second;
682 if (attr.isBooleanAttribute())
684 AttributeKind attrKind = akBoolean;
685 value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
687 bool val = attr.getBooleanValue();
688 value += ByteString((unsigned char*) &val, sizeof(val));
690 else if (attr.isUnsignedLongAttribute())
692 AttributeKind attrKind = akInteger;
693 value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
695 unsigned long val = attr.getUnsignedLongValue();
696 value += ByteString((unsigned char*) &val, sizeof(val));
698 else if (attr.isByteStringAttribute())
700 AttributeKind attrKind = akBinary;
701 value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
703 ByteString val = attr.getByteStringValue();
704 unsigned long len = val.size();
705 value += ByteString((unsigned char*) &len, sizeof(len));
708 else if (attr.isMechanismTypeSetAttribute())
710 AttributeKind attrKind = akMechSet;
711 value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
714 encodeMechanismTypeSet(val, attr.getMechanismTypeSetValue());
716 unsigned long len = val.size();
717 value += ByteString((unsigned char*) &len, sizeof(len));
722 ERROR_MSG("unsupported attribute kind for attribute map");
731 OSAttribute *DBObject::accessAttribute(CK_ATTRIBUTE_TYPE type)
733 switch (attributeKind(type))
739 // try to find the attribute in the boolean attribute table
740 DB::Statement statement = _connection->prepare(
741 "select value from attribute_boolean where type=%lu and object_id=%lld",
744 if (!statement.isValid())
748 DB::Result result = _connection->perform(statement);
749 if (!result.isValid())
753 // Store the attribute in the transaction when it is active.
754 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
756 attrs = _transaction;
758 bool value = result.getInt(1) != 0;
759 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
761 if (it != attrs->end())
763 if (it->second != NULL)
768 it->second = new OSAttribute(value);
773 attr = new OSAttribute(value);
774 (*attrs)[type] = attr;
780 // try to find the attribute in the integer attribute table
781 DB::Statement statement = _connection->prepare(
782 "select value from attribute_integer where type=%lu and object_id=%lld",
785 if (!statement.isValid())
789 DB::Result result = _connection->perform(statement);
790 if (!result.isValid())
794 // Store the attribute in the transaction when it is active.
795 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
797 attrs = _transaction;
799 unsigned long value = result.getULongLong(1);
800 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
802 if (it != attrs->end())
804 if (it->second != NULL)
809 it->second = new OSAttribute(value);
814 attr = new OSAttribute(value);
815 (*attrs)[type] = attr;
821 // try to find the attribute in the binary attribute table
822 DB::Statement statement = _connection->prepare(
823 "select value from attribute_binary where type=%lu and object_id=%lld",
826 if (!statement.isValid())
830 DB::Result result = _connection->perform(statement);
831 if (!result.isValid())
835 // Store the attribute in the transaction when it is active.
836 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
838 attrs = _transaction;
840 const unsigned char *value = result.getBinary(1);
841 size_t size = result.getFieldLength(1);
842 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
844 if (it != attrs->end())
846 if (it->second != NULL)
851 it->second = new OSAttribute(ByteString(value,size));
856 attr = new OSAttribute(ByteString(value,size));
857 (*attrs)[type] = attr;
864 // try to find the attribute in the binary attribute table
865 DB::Statement statement = _connection->prepare(
866 "select value from attribute_binary where type=%lu and object_id=%lld",
869 if (!statement.isValid())
873 DB::Result result = _connection->perform(statement);
874 if (!result.isValid())
878 // Store the attribute in the transaction when it is active.
879 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
881 attrs = _transaction;
883 const unsigned char *value = result.getBinary(1);
884 size_t size = result.getFieldLength(1);
886 std::set<CK_MECHANISM_TYPE> set;
887 if (!decodeMechanismTypeSet(set, value, size))
893 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
894 if (it != attrs->end())
896 if (it->second != NULL)
901 it->second = new OSAttribute(set);
906 attr = new OSAttribute(set);
907 (*attrs)[type] = attr;
914 // try to find the attribute in the array attribute table
915 DB::Statement statement = _connection->prepare(
916 "select value from attribute_array where type=%lu and object_id=%lld",
919 if (!statement.isValid())
923 DB::Result result = _connection->perform(statement);
924 if (!result.isValid())
928 // Store the attribute in the transaction when it is active.
929 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
931 attrs = _transaction;
933 const unsigned char *binary = result.getBinary(1);
934 size_t size = result.getFieldLength(1);
935 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
937 if (it != attrs->end())
939 std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
940 if (!decodeAttributeMap(value,binary,size))
945 if (it->second != NULL)
950 it->second = new OSAttribute(value);
955 std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
956 if (!decodeAttributeMap(value,binary,size))
960 attr = new OSAttribute(value);
961 (*attrs)[type] = attr;
971 // Retrieve the specified attribute for internal use
972 // Calling function must lock the mutex
973 OSAttribute* DBObject::getAttributeDB(CK_ATTRIBUTE_TYPE type)
975 if (_connection == NULL)
977 ERROR_MSG("Object is not connected to the database.");
983 ERROR_MSG("Cannot read from invalid object.");
987 // If a transaction is in progress, we can just return the attribute from the transaction.
990 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->find(type);
991 if (it != _transaction->end())
995 // If the attribute exists and is non-modifiable then return a previously retrieved attribute value.
996 if (!isModifiable(type))
998 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _attributes.find(type);
999 if (it != _attributes.end())
1005 return accessAttribute(type);
1008 // Check if the specified attribute exists
1009 bool DBObject::attributeExists(CK_ATTRIBUTE_TYPE type)
1011 MutexLocker lock(_mutex);
1013 return getAttributeDB(type) != NULL;
1016 // Retrieve the specified attribute
1017 OSAttribute DBObject::getAttribute(CK_ATTRIBUTE_TYPE type)
1019 MutexLocker lock(_mutex);
1021 OSAttribute* attr = getAttributeDB(type);
1022 if (attr == NULL) return OSAttribute((unsigned long)0);
1027 bool DBObject::getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val)
1029 MutexLocker lock(_mutex);
1031 OSAttribute* attr = getAttributeDB(type);
1032 if (attr == NULL) return val;
1034 if (attr->isBooleanAttribute())
1036 return attr->getBooleanValue();
1040 ERROR_MSG("The attribute is not a boolean: 0x%08X", type);
1045 unsigned long DBObject::getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val)
1047 MutexLocker lock(_mutex);
1049 OSAttribute* attr = getAttributeDB(type);
1050 if (attr == NULL) return val;
1052 if (attr->isUnsignedLongAttribute())
1054 return attr->getUnsignedLongValue();
1058 ERROR_MSG("The attribute is not an unsigned long: 0x%08X", type);
1063 ByteString DBObject::getByteStringValue(CK_ATTRIBUTE_TYPE type)
1065 MutexLocker lock(_mutex);
1069 OSAttribute* attr = getAttributeDB(type);
1070 if (attr == NULL) return val;
1072 if (attr->isByteStringAttribute())
1074 return attr->getByteStringValue();
1078 ERROR_MSG("The attribute is not a byte string: 0x%08X", type);
1083 CK_ATTRIBUTE_TYPE DBObject::nextAttributeType(CK_ATTRIBUTE_TYPE)
1085 MutexLocker lock(_mutex);
1087 if (_connection == NULL)
1089 ERROR_MSG("Object is not connected to the database.");
1094 ERROR_MSG("Cannot get next attribute for invalid object.");
1098 // FIXME: implement for C_CopyObject
1102 // Set the specified attribute
1103 bool DBObject::setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute)
1105 MutexLocker lock(_mutex);
1107 if (_connection == NULL)
1109 ERROR_MSG("Object is not connected to the database.");
1114 ERROR_MSG("Cannot update invalid object.");
1118 // Retrieve and existing attribute if it exists or NULL if it doesn't
1119 OSAttribute *attr = getAttributeDB(type);
1121 // Update an existing attribute...
1124 DB::Statement statement;
1125 if (attr->isBooleanAttribute())
1127 // update boolean attribute
1128 statement = _connection->prepare(
1129 "update attribute_boolean set value=%d where type=%lu and object_id=%lld",
1130 attribute.getBooleanValue() ? 1 : 0,
1134 else if (attr->isUnsignedLongAttribute())
1136 // update integer attribute
1137 statement = _connection->prepare(
1138 "update attribute_integer set value=%lld where type=%lu and object_id=%lld",
1139 static_cast<long long>(attribute.getUnsignedLongValue()),
1143 else if (attr->isByteStringAttribute())
1145 // update binary attribute
1146 statement = _connection->prepare(
1147 "update attribute_binary set value=? where type=%lu and object_id=%lld",
1150 DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
1152 else if (attr->isMechanismTypeSetAttribute())
1154 // update binary attribute
1156 encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
1158 statement = _connection->prepare(
1159 "update attribute_binary set value=? where type=%lu and object_id=%lld",
1162 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1164 else if (attr->isAttributeMapAttribute())
1166 // update attribute map attribute
1168 if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
1173 statement = _connection->prepare(
1174 "update attribute_array set value=? where type=%lu and object_id=%lld",
1177 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1180 // Statement is valid when a prepared statement has been attached to it.
1181 if (statement.isValid())
1183 if (!_connection->execute(statement))
1185 ERROR_MSG("Failed to update attribute %lu for object %lld",type,_objectId);
1191 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->find(type);
1192 if (it != _transaction->end())
1193 *it->second = attribute;
1195 (*_transaction)[type] = new OSAttribute(attribute);
1202 DB::Statement statement;
1204 // Insert the attribute, because it is currently unknown
1205 if (attribute.isBooleanAttribute())
1207 // Could not update it, so we need to insert it.
1208 statement = _connection->prepare(
1209 "insert into attribute_boolean (value,type,object_id) values (%d,%lu,%lld)",
1210 attribute.getBooleanValue() ? 1 : 0,
1215 else if (attribute.isUnsignedLongAttribute())
1217 // Could not update it, so we need to insert it.
1218 statement = _connection->prepare(
1219 "insert into attribute_integer (value,type,object_id) values (%lld,%lu,%lld)",
1220 static_cast<long long>(attribute.getUnsignedLongValue()),
1224 else if (attribute.isByteStringAttribute())
1226 // Could not update it, so we need to insert it.
1227 statement = _connection->prepare(
1228 "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
1232 DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
1234 else if (attribute.isMechanismTypeSetAttribute())
1236 // Could not update it, so we need to insert it.
1238 encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
1240 statement = _connection->prepare(
1241 "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
1244 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1246 else if (attribute.isAttributeMapAttribute())
1248 // Could not update it, so we need to insert it.
1250 if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
1255 statement = _connection->prepare(
1256 "insert into attribute_array (value,type,object_id) values (?,%lu,%lld)",
1259 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1262 // Statement is valid when a prepared statement has been attached to it.
1263 if (statement.isValid())
1265 if (!_connection->execute(statement))
1267 ERROR_MSG("Failed to insert attribute %lu for object %lld",type,_objectId);
1272 (*_transaction)[type] = new OSAttribute(attribute);
1274 _attributes[type] = new OSAttribute(attribute);
1281 // Set the specified attribute
1282 bool DBObject::deleteAttribute(CK_ATTRIBUTE_TYPE type)
1284 MutexLocker lock(_mutex);
1286 if (_connection == NULL)
1288 ERROR_MSG("Object is not connected to the database.");
1293 ERROR_MSG("Cannot update invalid object.");
1297 // Retrieve and existing attribute if it exists or NULL if it doesn't
1298 OSAttribute *attr = getAttributeDB(type);
1301 ERROR_MSG("Cannot delete an attribute that doesn't exist.");
1305 DB::Statement statement;
1306 if (attr->isBooleanAttribute())
1308 // delete boolean attribute
1309 statement = _connection->prepare(
1310 "delete from attribute_boolean where type=%lu and object_id=%lld",
1314 else if (attr->isUnsignedLongAttribute())
1316 // delete integer attribute
1317 statement = _connection->prepare(
1318 "delete from attribute_integer where type=%lu and object_id=%lld",
1322 else if (attr->isByteStringAttribute() || attr -> isMechanismTypeSetAttribute())
1324 // delete binary attribute
1325 statement = _connection->prepare(
1326 "delete from attribute_binary where type=%lu and object_id=%lld",
1330 else if (attr->isAttributeMapAttribute())
1332 // delete attribute map attribute
1333 statement = _connection->prepare(
1334 "delete from attribute_array where type=%lu and object_id=%lld",
1339 // Statement is valid when a prepared statement has been attached to it.
1340 if (statement.isValid())
1342 if (!_connection->execute(statement))
1344 ERROR_MSG("Failed to delete attribute %lu for object %lld",type,_objectId);
1350 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->find(type);
1351 if (it != _transaction->end())
1364 // The validity state of the object
1365 bool DBObject::isValid()
1367 MutexLocker lock(_mutex);
1369 return _objectId != 0 && _connection != NULL;
1372 // Start an attribute set transaction; this method is used when - for
1373 // example - a key is generated and all its attributes need to be
1374 // persisted in one go.
1376 // N.B.: Starting a transaction locks the object!
1377 bool DBObject::startTransaction(Access access)
1379 MutexLocker lock(_mutex);
1381 if (_connection == NULL)
1383 ERROR_MSG("Object is not connected to the database.");
1389 ERROR_MSG("Transaction is already active.");
1393 _transaction = new std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>;
1394 if (_transaction == NULL)
1396 ERROR_MSG("Not enough memory to start transaction.");
1400 if (_connection->inTransaction())
1402 ERROR_MSG("Transaction in database is already active.");
1406 // Ask the connection to start the transaction.
1407 if (access == ReadWrite)
1408 return _connection->beginTransactionRW();
1410 return _connection->beginTransactionRO();
1413 // Commit an attribute transaction
1414 bool DBObject::commitTransaction()
1416 MutexLocker lock(_mutex);
1418 if (_connection == NULL)
1420 ERROR_MSG("Object is not connected to the database.");
1424 if (_transaction == NULL)
1426 ERROR_MSG("No transaction active.");
1430 if (!_connection->commitTransaction())
1435 // Copy the values from the internally stored transaction to the _attributes field.
1436 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
1437 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator attr_it = _attributes.find(it->first);
1438 if (attr_it == _attributes.end())
1440 _attributes[it->first] = it->second;
1444 *attr_it->second = *it->second;
1449 delete _transaction;
1450 _transaction = NULL;
1454 // Abort an attribute transaction; loads back the previous version of the object from disk
1455 bool DBObject::abortTransaction()
1457 MutexLocker lock(_mutex);
1459 if (_connection == NULL)
1461 ERROR_MSG("Object is not connected to the database.");
1465 // Forget the atributes that were set during the transaction.
1468 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
1472 delete _transaction;
1473 _transaction = NULL;
1476 return _connection->rollbackTransaction();
1479 // Destroy the object; WARNING: pointers to the object become invalid after this call
1480 bool DBObject::destroyObject()
1482 // NOTE: Do not lock _mutex, because _token will call us back and cause a deadlock.
1483 // There is no need to lock anyway as _token is a non-mutable pointer, so no race
1484 // conditions possible.
1488 ERROR_MSG("Cannot destroy an object that is not associated with a token");
1492 return _token->deleteObject(this);