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:
388 case CKA_OS_PRIVATE_HANDLE:
404 static AttributeKind attributeKind(CK_ATTRIBUTE_TYPE type)
407 case CKA_CLASS: return akInteger;
408 case CKA_TOKEN: return akBoolean;
409 case CKA_PRIVATE: return akBoolean;
410 case CKA_LABEL: return akBinary;
411 case CKA_APPLICATION: return akBinary;
412 case CKA_VALUE: return akBinary;
413 case CKA_OBJECT_ID: return akBinary;
414 case CKA_CERTIFICATE_TYPE: return akInteger;
415 case CKA_ISSUER: return akBinary;
416 case CKA_SERIAL_NUMBER: return akBinary;
417 case CKA_AC_ISSUER: return akBinary;
418 case CKA_OWNER: return akBinary;
419 case CKA_ATTR_TYPES: return akBinary;
420 case CKA_TRUSTED: return akBoolean;
421 case CKA_CERTIFICATE_CATEGORY: return akInteger;
422 case CKA_JAVA_MIDP_SECURITY_DOMAIN: return akInteger;
423 case CKA_URL: return akBinary;
424 case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: return akBinary;
425 case CKA_HASH_OF_ISSUER_PUBLIC_KEY: return akBinary;
426 case CKA_NAME_HASH_ALGORITHM: return akInteger;
427 case CKA_CHECK_VALUE: return akBinary;
428 case CKA_KEY_TYPE: return akInteger;
429 case CKA_SUBJECT: return akBinary;
430 case CKA_ID: return akBinary;
431 case CKA_SENSITIVE: return akBoolean;
432 case CKA_ENCRYPT: return akBoolean;
433 case CKA_DECRYPT: return akBoolean;
434 case CKA_WRAP: return akBoolean;
435 case CKA_UNWRAP: return akBoolean;
436 case CKA_SIGN: return akBoolean;
437 case CKA_SIGN_RECOVER: return akBoolean;
438 case CKA_VERIFY: return akBoolean;
439 case CKA_VERIFY_RECOVER: return akBoolean;
440 case CKA_DERIVE: return akBoolean;
441 case CKA_START_DATE: return akBinary;
442 case CKA_END_DATE: return akBinary;
443 case CKA_MODULUS: return akBinary;
444 case CKA_MODULUS_BITS: return akInteger;
445 case CKA_PUBLIC_EXPONENT: return akBinary;
446 case CKA_PRIVATE_EXPONENT: return akBinary;
447 case CKA_PRIME_1: return akBinary;
448 case CKA_PRIME_2: return akBinary;
449 case CKA_EXPONENT_1: return akBinary;
450 case CKA_EXPONENT_2: return akBinary;
451 case CKA_COEFFICIENT: return akBinary;
452 case CKA_PRIME: return akBinary;
453 case CKA_SUBPRIME: return akBinary;
454 case CKA_BASE: return akBinary;
455 case CKA_PRIME_BITS: return akInteger;
456 case CKA_SUBPRIME_BITS: return akInteger;
457 case CKA_VALUE_BITS: return akInteger;
458 case CKA_VALUE_LEN: return akInteger;
459 case CKA_EXTRACTABLE: return akBoolean;
460 case CKA_LOCAL: return akBoolean;
461 case CKA_NEVER_EXTRACTABLE: return akBoolean;
462 case CKA_ALWAYS_SENSITIVE: return akBoolean;
463 case CKA_KEY_GEN_MECHANISM: return akInteger;
464 case CKA_MODIFIABLE: return akBoolean;
465 case CKA_COPYABLE: return akBoolean;
466 case CKA_ECDSA_PARAMS: return akBinary;
467 case CKA_EC_POINT: return akBinary;
468 case CKA_SECONDARY_AUTH: return akBoolean;
469 case CKA_AUTH_PIN_FLAGS: return akInteger;
470 case CKA_ALWAYS_AUTHENTICATE: return akBoolean;
471 case CKA_WRAP_WITH_TRUSTED: return akBoolean;
475 case CKA_OTP_TIME_INTERVAL:
476 case CKA_OTP_USER_FRIENDLY_MODE:
477 case CKA_OTP_CHALLENGE_REQUIREMENT:
478 case CKA_OTP_TIME_REQUIREMENT:
479 case CKA_OTP_COUNTER_REQUIREMENT:
480 case CKA_OTP_PIN_REQUIREMENT:
481 case CKA_OTP_COUNTER:
483 case CKA_OTP_USER_IDENTIFIER:
484 case CKA_OTP_SERVICE_IDENTIFIER:
485 case CKA_OTP_SERVICE_LOGO:
486 case CKA_OTP_SERVICE_LOGO_TYPE:
488 case CKA_GOSTR3410_PARAMS: return akBinary;
489 case CKA_GOSTR3411_PARAMS: return akBinary;
490 case CKA_GOST28147_PARAMS: return akBinary;
492 case CKA_HW_FEATURE_TYPE:
493 case CKA_RESET_ON_INIT:
499 case CKA_CHAR_COLUMNS:
501 case CKA_BITS_PER_PIXEL:
503 case CKA_ENCODING_METHODS:
505 case CKA_MECHANISM_TYPE:
506 case CKA_REQUIRED_CMS_ATTRIBUTES:
507 case CKA_DEFAULT_CMS_ATTRIBUTES:
508 case CKA_SUPPORTED_CMS_ATTRIBUTES:
510 case CKA_WRAP_TEMPLATE: return akAttrMap;
511 case CKA_UNWRAP_TEMPLATE: return akAttrMap;
512 case CKA_DERIVE_TEMPLATE: return akAttrMap;
513 case CKA_ALLOWED_MECHANISMS: return akMechSet;
515 case CKA_OS_TOKENLABEL: return akBinary;
516 case CKA_OS_TOKENSERIAL: return akBinary;
517 case CKA_OS_TOKENFLAGS: return akInteger;
518 case CKA_OS_SOPIN: return akBinary;
519 case CKA_OS_USERPIN: return akBinary;
520 case CKA_OS_PRIVATE_HANDLE: return akInteger;
522 default: return akUnknown;
526 static bool decodeMechanismTypeSet(std::set<CK_MECHANISM_TYPE>& set, const unsigned char *binary, size_t size)
528 for (size_t pos = 0; pos < size; )
531 if (pos == size) break;
533 CK_MECHANISM_TYPE mechType;
534 if (pos + sizeof(mechType) > size)
536 ERROR_MSG("mechanism type set overrun");
540 memcpy(&mechType, binary + pos, sizeof(mechType));
541 pos += sizeof(mechType);
543 set.insert(mechType);
549 static void encodeMechanismTypeSet(ByteString& value, const std::set<CK_MECHANISM_TYPE>& set)
551 for (std::set<CK_MECHANISM_TYPE>::const_iterator i = set.begin(); i != set.end(); ++i)
553 CK_MECHANISM_TYPE mechType = *i;
554 value += ByteString((unsigned char *) &mechType, sizeof(mechType));
558 static bool decodeAttributeMap(std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& map, const unsigned char *binary, size_t size)
560 for (size_t pos = 0; pos < size; )
563 if (pos == size) break;
565 CK_ATTRIBUTE_TYPE attrType;
566 if (pos + sizeof(attrType) > size)
570 memcpy(&attrType, binary + pos, sizeof(attrType));
571 pos += sizeof(attrType);
573 AttributeKind attrKind;
574 if (pos + sizeof(AttributeKind) > size)
578 memcpy(&attrKind, binary + pos, sizeof(attrKind));
579 pos += sizeof(attrKind);
581 // Verify using attributeKind()?
588 if (pos + sizeof(value) > size)
592 memcpy(&value, binary + pos, sizeof(value));
593 pos += sizeof(value);
595 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
602 if (pos + sizeof(value) > size)
606 memcpy(&value, binary + pos, sizeof(value));
607 pos += sizeof(value);
609 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
617 if (pos + sizeof(len) > size)
621 memcpy(&len, binary + pos, sizeof(len));
624 if (pos + len > size)
629 memcpy(&value[0], binary + pos, len);
632 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
639 if (pos + sizeof(len) > size)
643 memcpy(&len, binary + pos, sizeof(len));
646 if (pos + len > size)
651 std::set<CK_MECHANISM_TYPE> value;
652 if (!decodeMechanismTypeSet(value, binary + pos, len)) {
657 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
662 ERROR_MSG("unsupported attribute kind in attribute map");
671 ERROR_MSG("attribute map template overrun");
676 static bool encodeAttributeMap(ByteString& value, const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& attributes)
678 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator i = attributes.begin(); i != attributes.end(); ++i)
680 CK_ATTRIBUTE_TYPE attrType = i->first;
681 value += ByteString((unsigned char*) &attrType, sizeof(attrType));
683 OSAttribute attr = i->second;
684 if (attr.isBooleanAttribute())
686 AttributeKind attrKind = akBoolean;
687 value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
689 bool val = attr.getBooleanValue();
690 value += ByteString((unsigned char*) &val, sizeof(val));
692 else if (attr.isUnsignedLongAttribute())
694 AttributeKind attrKind = akInteger;
695 value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
697 unsigned long val = attr.getUnsignedLongValue();
698 value += ByteString((unsigned char*) &val, sizeof(val));
700 else if (attr.isByteStringAttribute())
702 AttributeKind attrKind = akBinary;
703 value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
705 ByteString val = attr.getByteStringValue();
706 unsigned long len = val.size();
707 value += ByteString((unsigned char*) &len, sizeof(len));
710 else if (attr.isMechanismTypeSetAttribute())
712 AttributeKind attrKind = akMechSet;
713 value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
716 encodeMechanismTypeSet(val, attr.getMechanismTypeSetValue());
718 unsigned long len = val.size();
719 value += ByteString((unsigned char*) &len, sizeof(len));
724 ERROR_MSG("unsupported attribute kind for attribute map");
733 OSAttribute *DBObject::accessAttribute(CK_ATTRIBUTE_TYPE type)
735 switch (attributeKind(type))
741 // try to find the attribute in the boolean attribute table
742 DB::Statement statement = _connection->prepare(
743 "select value from attribute_boolean where type=%lu and object_id=%lld",
746 if (!statement.isValid())
750 DB::Result result = _connection->perform(statement);
751 if (!result.isValid())
755 // Store the attribute in the transaction when it is active.
756 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
758 attrs = _transaction;
760 bool value = result.getInt(1) != 0;
761 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
763 if (it != attrs->end())
765 if (it->second != NULL)
770 it->second = new OSAttribute(value);
775 attr = new OSAttribute(value);
776 (*attrs)[type] = attr;
782 // try to find the attribute in the integer attribute table
783 DB::Statement statement = _connection->prepare(
784 "select value from attribute_integer where type=%lu and object_id=%lld",
787 if (!statement.isValid())
791 DB::Result result = _connection->perform(statement);
792 if (!result.isValid())
796 // Store the attribute in the transaction when it is active.
797 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
799 attrs = _transaction;
801 unsigned long value = result.getULongLong(1);
802 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
804 if (it != attrs->end())
806 if (it->second != NULL)
811 it->second = new OSAttribute(value);
816 attr = new OSAttribute(value);
817 (*attrs)[type] = attr;
823 // try to find the attribute in the binary attribute table
824 DB::Statement statement = _connection->prepare(
825 "select value from attribute_binary where type=%lu and object_id=%lld",
828 if (!statement.isValid())
832 DB::Result result = _connection->perform(statement);
833 if (!result.isValid())
837 // Store the attribute in the transaction when it is active.
838 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
840 attrs = _transaction;
842 const unsigned char *value = result.getBinary(1);
843 size_t size = result.getFieldLength(1);
844 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
846 if (it != attrs->end())
848 if (it->second != NULL)
853 it->second = new OSAttribute(ByteString(value,size));
858 attr = new OSAttribute(ByteString(value,size));
859 (*attrs)[type] = attr;
866 // try to find the attribute in the binary attribute table
867 DB::Statement statement = _connection->prepare(
868 "select value from attribute_binary where type=%lu and object_id=%lld",
871 if (!statement.isValid())
875 DB::Result result = _connection->perform(statement);
876 if (!result.isValid())
880 // Store the attribute in the transaction when it is active.
881 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
883 attrs = _transaction;
885 const unsigned char *value = result.getBinary(1);
886 size_t size = result.getFieldLength(1);
888 std::set<CK_MECHANISM_TYPE> set;
889 if (!decodeMechanismTypeSet(set, value, size))
895 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
896 if (it != attrs->end())
898 if (it->second != NULL)
903 it->second = new OSAttribute(set);
908 attr = new OSAttribute(set);
909 (*attrs)[type] = attr;
916 // try to find the attribute in the array attribute table
917 DB::Statement statement = _connection->prepare(
918 "select value from attribute_array where type=%lu and object_id=%lld",
921 if (!statement.isValid())
925 DB::Result result = _connection->perform(statement);
926 if (!result.isValid())
930 // Store the attribute in the transaction when it is active.
931 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
933 attrs = _transaction;
935 const unsigned char *binary = result.getBinary(1);
936 size_t size = result.getFieldLength(1);
937 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = attrs->find(type);
939 if (it != attrs->end())
941 std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
942 if (!decodeAttributeMap(value,binary,size))
947 if (it->second != NULL)
952 it->second = new OSAttribute(value);
957 std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
958 if (!decodeAttributeMap(value,binary,size))
962 attr = new OSAttribute(value);
963 (*attrs)[type] = attr;
973 // Retrieve the specified attribute for internal use
974 // Calling function must lock the mutex
975 OSAttribute* DBObject::getAttributeDB(CK_ATTRIBUTE_TYPE type)
977 if (_connection == NULL)
979 ERROR_MSG("Object is not connected to the database.");
985 ERROR_MSG("Cannot read from invalid object.");
989 // If a transaction is in progress, we can just return the attribute from the transaction.
992 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->find(type);
993 if (it != _transaction->end())
997 // If the attribute exists and is non-modifiable then return a previously retrieved attribute value.
998 if (!isModifiable(type))
1000 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _attributes.find(type);
1001 if (it != _attributes.end())
1007 return accessAttribute(type);
1010 // Check if the specified attribute exists
1011 bool DBObject::attributeExists(CK_ATTRIBUTE_TYPE type)
1013 MutexLocker lock(_mutex);
1015 return getAttributeDB(type) != NULL;
1018 // Retrieve the specified attribute
1019 OSAttribute DBObject::getAttribute(CK_ATTRIBUTE_TYPE type)
1021 MutexLocker lock(_mutex);
1023 OSAttribute* attr = getAttributeDB(type);
1024 if (attr == NULL) return OSAttribute((unsigned long)0);
1029 bool DBObject::getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val)
1031 MutexLocker lock(_mutex);
1033 OSAttribute* attr = getAttributeDB(type);
1034 if (attr == NULL) return val;
1036 if (attr->isBooleanAttribute())
1038 return attr->getBooleanValue();
1042 ERROR_MSG("The attribute is not a boolean: 0x%08X", type);
1047 unsigned long DBObject::getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val)
1049 MutexLocker lock(_mutex);
1051 OSAttribute* attr = getAttributeDB(type);
1052 if (attr == NULL) return val;
1054 if (attr->isUnsignedLongAttribute())
1056 return attr->getUnsignedLongValue();
1060 ERROR_MSG("The attribute is not an unsigned long: 0x%08X", type);
1065 ByteString DBObject::getByteStringValue(CK_ATTRIBUTE_TYPE type)
1067 MutexLocker lock(_mutex);
1071 OSAttribute* attr = getAttributeDB(type);
1072 if (attr == NULL) return val;
1074 if (attr->isByteStringAttribute())
1076 return attr->getByteStringValue();
1080 ERROR_MSG("The attribute is not a byte string: 0x%08X", type);
1085 CK_ATTRIBUTE_TYPE DBObject::nextAttributeType(CK_ATTRIBUTE_TYPE)
1087 MutexLocker lock(_mutex);
1089 if (_connection == NULL)
1091 ERROR_MSG("Object is not connected to the database.");
1096 ERROR_MSG("Cannot get next attribute for invalid object.");
1100 // FIXME: implement for C_CopyObject
1104 // Set the specified attribute
1105 bool DBObject::setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute)
1107 MutexLocker lock(_mutex);
1109 if (_connection == NULL)
1111 ERROR_MSG("Object is not connected to the database.");
1116 ERROR_MSG("Cannot update invalid object.");
1120 // Retrieve and existing attribute if it exists or NULL if it doesn't
1121 OSAttribute *attr = getAttributeDB(type);
1123 // Update an existing attribute...
1126 DB::Statement statement;
1127 if (attr->isBooleanAttribute())
1129 // update boolean attribute
1130 statement = _connection->prepare(
1131 "update attribute_boolean set value=%d where type=%lu and object_id=%lld",
1132 attribute.getBooleanValue() ? 1 : 0,
1136 else if (attr->isUnsignedLongAttribute())
1138 // update integer attribute
1139 statement = _connection->prepare(
1140 "update attribute_integer set value=%lld where type=%lu and object_id=%lld",
1141 static_cast<long long>(attribute.getUnsignedLongValue()),
1145 else if (attr->isByteStringAttribute())
1147 // update binary attribute
1148 statement = _connection->prepare(
1149 "update attribute_binary set value=? where type=%lu and object_id=%lld",
1152 DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
1154 else if (attr->isMechanismTypeSetAttribute())
1156 // update binary attribute
1158 encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
1160 statement = _connection->prepare(
1161 "update attribute_binary set value=? where type=%lu and object_id=%lld",
1164 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1166 else if (attr->isAttributeMapAttribute())
1168 // update attribute map attribute
1170 if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
1175 statement = _connection->prepare(
1176 "update attribute_array set value=? where type=%lu and object_id=%lld",
1179 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1182 // Statement is valid when a prepared statement has been attached to it.
1183 if (statement.isValid())
1185 if (!_connection->execute(statement))
1187 ERROR_MSG("Failed to update attribute %lu for object %lld",type,_objectId);
1193 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->find(type);
1194 if (it != _transaction->end())
1195 *it->second = attribute;
1197 (*_transaction)[type] = new OSAttribute(attribute);
1204 DB::Statement statement;
1206 // Insert the attribute, because it is currently unknown
1207 if (attribute.isBooleanAttribute())
1209 // Could not update it, so we need to insert it.
1210 statement = _connection->prepare(
1211 "insert into attribute_boolean (value,type,object_id) values (%d,%lu,%lld)",
1212 attribute.getBooleanValue() ? 1 : 0,
1217 else if (attribute.isUnsignedLongAttribute())
1219 // Could not update it, so we need to insert it.
1220 statement = _connection->prepare(
1221 "insert into attribute_integer (value,type,object_id) values (%lld,%lu,%lld)",
1222 static_cast<long long>(attribute.getUnsignedLongValue()),
1226 else if (attribute.isByteStringAttribute())
1228 // Could not update it, so we need to insert it.
1229 statement = _connection->prepare(
1230 "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
1234 DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
1236 else if (attribute.isMechanismTypeSetAttribute())
1238 // Could not update it, so we need to insert it.
1240 encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
1242 statement = _connection->prepare(
1243 "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
1246 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1248 else if (attribute.isAttributeMapAttribute())
1250 // Could not update it, so we need to insert it.
1252 if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
1257 statement = _connection->prepare(
1258 "insert into attribute_array (value,type,object_id) values (?,%lu,%lld)",
1261 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1264 // Statement is valid when a prepared statement has been attached to it.
1265 if (statement.isValid())
1267 if (!_connection->execute(statement))
1269 ERROR_MSG("Failed to insert attribute %lu for object %lld",type,_objectId);
1274 (*_transaction)[type] = new OSAttribute(attribute);
1276 _attributes[type] = new OSAttribute(attribute);
1283 // Set the specified attribute
1284 bool DBObject::deleteAttribute(CK_ATTRIBUTE_TYPE type)
1286 MutexLocker lock(_mutex);
1288 if (_connection == NULL)
1290 ERROR_MSG("Object is not connected to the database.");
1295 ERROR_MSG("Cannot update invalid object.");
1299 // Retrieve and existing attribute if it exists or NULL if it doesn't
1300 OSAttribute *attr = getAttributeDB(type);
1303 ERROR_MSG("Cannot delete an attribute that doesn't exist.");
1307 DB::Statement statement;
1308 if (attr->isBooleanAttribute())
1310 // delete boolean attribute
1311 statement = _connection->prepare(
1312 "delete from attribute_boolean where type=%lu and object_id=%lld",
1316 else if (attr->isUnsignedLongAttribute())
1318 // delete integer attribute
1319 statement = _connection->prepare(
1320 "delete from attribute_integer where type=%lu and object_id=%lld",
1324 else if (attr->isByteStringAttribute() || attr -> isMechanismTypeSetAttribute())
1326 // delete binary attribute
1327 statement = _connection->prepare(
1328 "delete from attribute_binary where type=%lu and object_id=%lld",
1332 else if (attr->isAttributeMapAttribute())
1334 // delete attribute map attribute
1335 statement = _connection->prepare(
1336 "delete from attribute_array where type=%lu and object_id=%lld",
1341 // Statement is valid when a prepared statement has been attached to it.
1342 if (statement.isValid())
1344 if (!_connection->execute(statement))
1346 ERROR_MSG("Failed to delete attribute %lu for object %lld",type,_objectId);
1352 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->find(type);
1353 if (it != _transaction->end())
1366 // The validity state of the object
1367 bool DBObject::isValid()
1369 MutexLocker lock(_mutex);
1371 return _objectId != 0 && _connection != NULL;
1374 // Start an attribute set transaction; this method is used when - for
1375 // example - a key is generated and all its attributes need to be
1376 // persisted in one go.
1378 // N.B.: Starting a transaction locks the object!
1379 bool DBObject::startTransaction(Access access)
1381 MutexLocker lock(_mutex);
1383 if (_connection == NULL)
1385 ERROR_MSG("Object is not connected to the database.");
1391 ERROR_MSG("Transaction is already active.");
1395 _transaction = new std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>;
1396 if (_transaction == NULL)
1398 ERROR_MSG("Not enough memory to start transaction.");
1402 if (_connection->inTransaction())
1404 ERROR_MSG("Transaction in database is already active.");
1408 // Ask the connection to start the transaction.
1409 if (access == ReadWrite)
1410 return _connection->beginTransactionRW();
1412 return _connection->beginTransactionRO();
1415 // Commit an attribute transaction
1416 bool DBObject::commitTransaction()
1418 MutexLocker lock(_mutex);
1420 if (_connection == NULL)
1422 ERROR_MSG("Object is not connected to the database.");
1426 if (_transaction == NULL)
1428 ERROR_MSG("No transaction active.");
1432 if (!_connection->commitTransaction())
1437 // Copy the values from the internally stored transaction to the _attributes field.
1438 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
1439 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator attr_it = _attributes.find(it->first);
1440 if (attr_it == _attributes.end())
1442 _attributes[it->first] = it->second;
1446 *attr_it->second = *it->second;
1451 delete _transaction;
1452 _transaction = NULL;
1456 // Abort an attribute transaction; loads back the previous version of the object from disk
1457 bool DBObject::abortTransaction()
1459 MutexLocker lock(_mutex);
1461 if (_connection == NULL)
1463 ERROR_MSG("Object is not connected to the database.");
1467 // Forget the atributes that were set during the transaction.
1470 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
1474 delete _transaction;
1475 _transaction = NULL;
1478 return _connection->rollbackTransaction();
1481 // Destroy the object; WARNING: pointers to the object become invalid after this call
1482 bool DBObject::destroyObject()
1484 // NOTE: Do not lock _mutex, because _token will call us back and cause a deadlock.
1485 // There is no need to lock anyway as _token is a non-mutable pointer, so no race
1486 // conditions possible.
1490 ERROR_MSG("Cannot destroy an object that is not associated with a token");
1494 return _token->deleteObject(this);