Added a new Attribute to store TPM key handle
[aaf/sshsm.git] / SoftHSMv2 / src / lib / object_store / DBObject.cpp
1 /*
2  * Copyright (c) 2013 SURFnet bv
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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.
25  */
26
27 /*****************************************************************************
28  DBObject.h
29
30  This class represents object records in a database
31  *****************************************************************************/
32
33 #include "config.h"
34 #include "DBObject.h"
35 #include "OSPathSep.h"
36 #include "DB.h"
37 #include "OSAttributes.h"
38
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42
43 #include <cstdio>
44 #include <map>
45
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)
49 {
50
51 }
52
53 DBObject::DBObject(DB::Connection *connection, ObjectStoreToken *token, long long objectId)
54         : _mutex(MutexFactory::i()->getMutex()), _connection(connection), _token(token), _objectId(objectId), _transaction(NULL)
55 {
56 }
57
58 // Destructor
59 DBObject::~DBObject()
60 {
61         for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _attributes.begin(); it!=_attributes.end(); ++it) {
62                 delete it->second;
63                 it->second = NULL;
64         }
65         if (_transaction)
66         {
67                 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
68                         delete it->second;
69                         it->second = NULL;
70                 }
71                 delete _transaction;
72         }
73         MutexFactory::i()->recycleMutex(_mutex);
74 }
75
76 void DBObject::dropConnection()
77 {
78         MutexLocker lock(_mutex);
79
80         _connection = NULL;
81 }
82
83 // create tables to support storage of attributes for the DBObject
84 bool DBObject::createTables()
85 {
86         MutexLocker lock(_mutex);
87
88         if (_connection == NULL)
89         {
90                 ERROR_MSG("Object is not connected to the database.");
91                 return false;
92         }
93
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))
97         {
98                 ERROR_MSG("Failed to create \"object\" table");
99                 return false;
100         }
101
102         // attribute_text
103         DB::Statement cr_attr_text = _connection->prepare(
104                 "create table attribute_text ("
105                 "value text,"
106                 "type integer,"
107                 "object_id integer references object(id) on delete cascade,"
108                 "id integer primary key autoincrement)"
109                 );
110         if (!_connection->execute(cr_attr_text))
111         {
112                 ERROR_MSG("Failed to create \"attribute_text\" table");
113                 return false;
114         }
115
116         // attribute_integer
117         DB::Statement cr_attr_integer = _connection->prepare(
118                 "create table attribute_integer ("
119                 "value integer,"
120                 "type integer,"
121                 "object_id integer references object(id) on delete cascade,"
122                 "id integer primary key autoincrement)"
123                 );
124         if (!_connection->execute(cr_attr_integer))
125         {
126                 ERROR_MSG("Failed to create \"attribute_integer\" table");
127                 return false;
128         }
129
130         // attribute_binary
131         DB::Statement cr_attr_binary = _connection->prepare(
132                 "create table attribute_binary ("
133                 "value blob,"
134                 "type integer,"
135                 "object_id integer references object(id) on delete cascade,"
136                 "id integer primary key autoincrement)"
137                 );
138         if (!_connection->execute(cr_attr_binary))
139         {
140                 ERROR_MSG("Failed to create \"attribute_binary\" table");
141                 return false;
142         }
143
144         // attribute_array
145         DB::Statement cr_attr_array = _connection->prepare(
146                 "create table attribute_array ("
147                 "value blob,"
148                 "type integer,"
149                 "object_id integer references object(id) on delete cascade,"
150                 "id integer primary key autoincrement)"
151                 );
152         if (!_connection->execute(cr_attr_array))
153         {
154                 ERROR_MSG("Failed to create \"attribute_array\" table");
155                 return false;
156         }
157
158         // attribute_boolean
159         DB::Statement cr_attr_boolean = _connection->prepare(
160                 "create table attribute_boolean ("
161                 "value boolean,"
162                 "type integer,"
163                 "object_id integer references object(id) on delete cascade,"
164                 "id integer primary key autoincrement)"
165                 );
166         if (!_connection->execute(cr_attr_boolean))
167         {
168                 ERROR_MSG("Failed to create \"attribute_boolean\" table");
169                 return false;
170         }
171
172         // attribute_datetime
173         DB::Statement cr_attr_datetime = _connection->prepare(
174                 "create table attribute_datetime ("
175                 "value datetime,"
176                 "type integer,"
177                 "object_id integer references object(id) on delete cascade,"
178                 "id integer primary key autoincrement)"
179                 );
180         if (!_connection->execute(cr_attr_datetime))
181         {
182                 ERROR_MSG("Failed to create \"attribute_datetime\" table");
183                 return false;
184         }
185
186         // attribute_real
187         DB::Statement cr_attr_real = _connection->prepare(
188                 "create table attribute_real ("
189                 "value real,"
190                 "type integer,"
191                 "object_id integer references object(id) on delete cascade,"
192                 "id integer primary key autoincrement)"
193                 );
194         if (!_connection->execute(cr_attr_real))
195         {
196                 ERROR_MSG("Failed to create \"attribute_real\" table");
197                 return false;
198         }
199
200         return true;
201 }
202
203 bool DBObject::dropTables()
204 {
205         MutexLocker lock(_mutex);
206
207         if (_connection == NULL)
208         {
209                 ERROR_MSG("Object is not connected to the database.");
210                 return false;
211         }
212
213         // Create the tables inside the database
214         DB::Statement dr_object = _connection->prepare("drop table object");
215         if (!_connection->execute(dr_object))
216         {
217                 ERROR_MSG("Failed to drop \"object\" table");
218                 return false;
219         }
220
221         // attribute_text
222         DB::Statement dr_attr_text = _connection->prepare("drop table attribute_text");
223         if (!_connection->execute(dr_attr_text))
224         {
225                 ERROR_MSG("Failed to drop \"attribute_text\" table");
226                 return false;
227         }
228
229         // attribute_integer
230         DB::Statement dr_attr_integer = _connection->prepare("drop table attribute_integer");
231         if (!_connection->execute(dr_attr_integer))
232         {
233                 ERROR_MSG("Failed to drop \"attribute_integer\" table");
234                 return false;
235         }
236
237         // attribute_binary
238         DB::Statement dr_attr_binary = _connection->prepare("drop table attribute_binary");
239         if (!_connection->execute(dr_attr_binary))
240         {
241                 ERROR_MSG("Failed to drop \"attribute_binary\" table");
242                 return false;
243         }
244
245         // attribute_array
246         DB::Statement dr_attr_array = _connection->prepare("drop table attribute_array");
247         if (!_connection->execute(dr_attr_array))
248         {
249                 ERROR_MSG("Failed to drop \"attribute_array\" table");
250                 return false;
251         }
252
253         // attribute_boolean
254         DB::Statement dr_attr_boolean = _connection->prepare("drop table attribute_boolean");
255         if (!_connection->execute(dr_attr_boolean))
256         {
257                 ERROR_MSG("Failed to drop \"attribute_boolean\" table");
258                 return false;
259         }
260
261         // attribute_datetime
262         DB::Statement dr_attr_datetime = _connection->prepare("drop table attribute_datetime");
263         if (!_connection->execute(dr_attr_datetime))
264         {
265                 ERROR_MSG("Failed to drop \"attribute_datetime\" table");
266                 return false;
267         }
268
269         // attribute_real
270         DB::Statement dr_attr_real = _connection->prepare("drop table attribute_real");
271         if (!_connection->execute(dr_attr_real))
272         {
273                 ERROR_MSG("Failed to drop \"attribute_real\" table");
274                 return false;
275         }
276
277         return true;
278 }
279
280 bool DBObject::find(long long objectId)
281 {
282         MutexLocker lock(_mutex);
283
284         if (_connection == NULL)
285         {
286                 ERROR_MSG("Object is not connected to the database.");
287                 return false;
288         }
289
290         if (objectId == 0) {
291                 ERROR_MSG("Invalid object_id 0 passed to find");
292                 return false;
293         }
294
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",
298                                 objectId);
299         if (!statement.isValid()) {
300                 ERROR_MSG("Preparing object selection statement failed");
301                 return false;
302         }
303
304         DB::Result result = _connection->perform(statement);
305         if (result.getLongLong(1) != objectId) {
306                 ERROR_MSG("Failed to find object with id %lld",objectId);
307                 return false;
308         }
309
310         _objectId = objectId;
311         return true;
312 }
313
314 bool DBObject::insert()
315 {
316         MutexLocker lock(_mutex);
317
318         if (_connection == NULL)
319         {
320                 ERROR_MSG("Object is not connected to the database.");
321                 return false;
322         }
323
324         DB::Statement statement = _connection->prepare("insert into object default values");
325
326         if (!_connection->execute(statement)) {
327                 ERROR_MSG("Failed to insert a new object");
328                 return false;
329         }
330
331         _objectId = _connection->lastInsertRowId();
332         return _objectId != 0;
333 }
334
335 bool DBObject::remove()
336 {
337         MutexLocker lock(_mutex);
338
339         if (_connection == NULL)
340         {
341                 ERROR_MSG("Object is not connected to the database.");
342                 return false;
343         }
344
345         DB::Statement statement = _connection->prepare("delete from object where id=%lld",_objectId);
346
347         if (!_connection->execute(statement)) {
348                 ERROR_MSG("Failed to remove an existing object");
349                 return false;
350         }
351
352         _objectId = 0;
353         return true;
354 }
355
356 long long DBObject::objectId()
357 {
358         MutexLocker lock(_mutex);
359
360         return _objectId;
361 }
362
363 static bool isModifiable(CK_ATTRIBUTE_TYPE type)
364 {
365         switch (type) {
366         case CKA_LABEL:
367         case CKA_TRUSTED:
368         case CKA_ID:
369         case CKA_ISSUER:
370         case CKA_SERIAL_NUMBER:
371         case CKA_START_DATE:
372         case CKA_END_DATE:
373         case CKA_DERIVE:
374         case CKA_SUBJECT:
375         case CKA_ENCRYPT:
376         case CKA_VERIFY:
377         case CKA_VERIFY_RECOVER:
378         case CKA_WRAP:
379         case CKA_SENSITIVE:
380         case CKA_DECRYPT:
381         case CKA_SIGN:
382         case CKA_SIGN_RECOVER:
383         case CKA_UNWRAP:
384         case CKA_EXTRACTABLE:
385         case CKA_OS_TOKENFLAGS:
386         case CKA_OS_SOPIN:
387         case CKA_OS_USERPIN:
388         case CKA_OS_PRIVATE_HANDLE:
389                 return true;
390         default:
391                 return false;
392         }
393 }
394
395 enum AttributeKind {
396         akUnknown,
397         akBoolean,
398         akInteger,
399         akBinary,
400         akAttrMap,
401         akMechSet
402 };
403
404 static AttributeKind attributeKind(CK_ATTRIBUTE_TYPE type)
405 {
406         switch (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;
472 /*
473         case CKA_OTP_FORMAT:
474         case CKA_OTP_LENGTH:
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:
482         case CKA_OTP_TIME:
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:
487 */
488         case CKA_GOSTR3410_PARAMS: return akBinary;
489         case CKA_GOSTR3411_PARAMS: return akBinary;
490         case CKA_GOST28147_PARAMS: return akBinary;
491 /*
492         case CKA_HW_FEATURE_TYPE:
493         case CKA_RESET_ON_INIT:
494         case CKA_HAS_RESET:
495         case CKA_PIXEL_X:
496         case CKA_PIXEL_Y:
497         case CKA_RESOLUTION:
498         case CKA_CHAR_ROWS:
499         case CKA_CHAR_COLUMNS:
500         case CKA_COLOR:
501         case CKA_BITS_PER_PIXEL:
502         case CKA_CHAR_SETS:
503         case CKA_ENCODING_METHODS:
504         case CKA_MIME_TYPES:
505         case CKA_MECHANISM_TYPE:
506         case CKA_REQUIRED_CMS_ATTRIBUTES:
507         case CKA_DEFAULT_CMS_ATTRIBUTES:
508         case CKA_SUPPORTED_CMS_ATTRIBUTES:
509 */
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;
514
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;
521
522         default: return akUnknown;
523         }
524 }
525
526 static bool decodeMechanismTypeSet(std::set<CK_MECHANISM_TYPE>& set, const unsigned char *binary, size_t size)
527 {
528         for (size_t pos = 0; pos < size; )
529         {
530                 // finished?
531                 if (pos == size) break;
532
533                 CK_MECHANISM_TYPE mechType;
534                 if (pos + sizeof(mechType) > size)
535                 {
536                         ERROR_MSG("mechanism type set overrun");
537                         return false;
538                 }
539
540                 memcpy(&mechType, binary + pos, sizeof(mechType));
541                 pos += sizeof(mechType);
542
543                 set.insert(mechType);
544     }
545
546         return true;
547 }
548
549 static void encodeMechanismTypeSet(ByteString& value, const std::set<CK_MECHANISM_TYPE>& set)
550 {
551         for (std::set<CK_MECHANISM_TYPE>::const_iterator i = set.begin(); i != set.end(); ++i)
552         {
553                 CK_MECHANISM_TYPE mechType = *i;
554                 value += ByteString((unsigned char *) &mechType, sizeof(mechType));
555         }
556 }
557
558 static bool decodeAttributeMap(std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& map, const unsigned char *binary, size_t size)
559 {
560         for (size_t pos = 0; pos < size; )
561         {
562                 // finished?
563                 if (pos == size) break;
564
565                 CK_ATTRIBUTE_TYPE attrType;
566                 if (pos + sizeof(attrType) > size)
567                 {
568                         goto overrun;
569                 }
570                 memcpy(&attrType, binary + pos, sizeof(attrType));
571                 pos += sizeof(attrType);
572
573                 AttributeKind attrKind;
574                 if (pos + sizeof(AttributeKind) > size)
575                 {
576                         goto overrun;
577                 }
578                 memcpy(&attrKind, binary + pos, sizeof(attrKind));
579                 pos += sizeof(attrKind);
580
581                 // Verify using attributeKind()?
582
583                 switch (attrKind)
584                 {
585                         case akBoolean:
586                         {
587                                 bool value;
588                                 if (pos + sizeof(value) > size)
589                                 {
590                                         goto overrun;
591                                 }
592                                 memcpy(&value, binary + pos, sizeof(value));
593                                 pos += sizeof(value);
594
595                                 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
596                         }
597                         break;
598
599                         case akInteger:
600                         {
601                                 unsigned long value;
602                                 if (pos + sizeof(value) > size)
603                                 {
604                                         goto overrun;
605                                 }
606                                 memcpy(&value, binary + pos, sizeof(value));
607                                 pos += sizeof(value);
608
609                                 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
610                         }
611                         break;
612
613                         case akBinary:
614                         {
615                                 ByteString value;
616                                 unsigned long len;
617                                 if (pos + sizeof(len) > size)
618                                 {
619                                         goto overrun;
620                                 }
621                                 memcpy(&len, binary + pos, sizeof(len));
622                                 pos += sizeof(len);
623
624                                 if (pos + len > size)
625                                 {
626                                         goto overrun;
627                                 }
628                                 value.resize(len);
629                                 memcpy(&value[0], binary + pos, len);
630                                 pos += len;
631
632                                 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
633                         }
634                         break;
635
636                         case akMechSet:
637                         {
638                                 unsigned long len;
639                                 if (pos + sizeof(len) > size)
640                                 {
641                                         goto overrun;
642                                 }
643                                 memcpy(&len, binary + pos, sizeof(len));
644                                 pos += sizeof(len);
645
646                                 if (pos + len > size)
647                                 {
648                                         goto overrun;
649                                 }
650
651                                 std::set<CK_MECHANISM_TYPE> value;
652                                 if (!decodeMechanismTypeSet(value, binary + pos, len)) {
653                                         return false;
654                                 }
655                                 pos += len;
656
657                                 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
658                         }
659                         break;
660
661                         default:
662                         ERROR_MSG("unsupported attribute kind in attribute map");
663
664                         return false;
665                 }
666         }
667
668         return true;
669
670 overrun:
671         ERROR_MSG("attribute map template overrun");
672
673         return false;
674 }
675
676 static bool encodeAttributeMap(ByteString& value, const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& attributes)
677 {
678         for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator i = attributes.begin(); i != attributes.end(); ++i)
679         {
680                 CK_ATTRIBUTE_TYPE attrType = i->first;
681                 value += ByteString((unsigned char*) &attrType, sizeof(attrType));
682
683                 OSAttribute attr = i->second;
684                 if (attr.isBooleanAttribute())
685                 {
686                         AttributeKind attrKind = akBoolean;
687                         value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
688
689                         bool val = attr.getBooleanValue();
690                         value += ByteString((unsigned char*) &val, sizeof(val));
691                 }
692                 else if (attr.isUnsignedLongAttribute())
693                 {
694                         AttributeKind attrKind = akInteger;
695                         value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
696
697                         unsigned long val = attr.getUnsignedLongValue();
698                         value += ByteString((unsigned char*) &val, sizeof(val));
699                 }
700                 else if (attr.isByteStringAttribute())
701                 {
702                         AttributeKind attrKind = akBinary;
703                         value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
704
705                         ByteString val = attr.getByteStringValue();
706                         unsigned long len = val.size();
707                         value += ByteString((unsigned char*) &len, sizeof(len));
708                         value += val;
709                 }
710                 else if (attr.isMechanismTypeSetAttribute())
711                 {
712                         AttributeKind attrKind = akMechSet;
713                         value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
714
715                         ByteString val;
716                         encodeMechanismTypeSet(val, attr.getMechanismTypeSetValue());
717
718                         unsigned long len = val.size();
719                         value += ByteString((unsigned char*) &len, sizeof(len));
720                         value += val;
721                 }
722                 else
723                 {
724                         ERROR_MSG("unsupported attribute kind for attribute map");
725
726                         return false;
727                 }
728         }
729
730         return true;
731 }
732
733 OSAttribute *DBObject::accessAttribute(CK_ATTRIBUTE_TYPE type)
734 {
735         switch (attributeKind(type))
736         {
737                 case akUnknown:
738                         return NULL;
739                 case akBoolean:
740                 {
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",
744                                 type,
745                                 _objectId);
746                         if (!statement.isValid())
747                         {
748                                 return NULL;
749                         }
750                         DB::Result result = _connection->perform(statement);
751                         if (!result.isValid())
752                         {
753                                 return NULL;
754                         }
755                         // Store the attribute in the transaction when it is active.
756                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
757                         if (_transaction)
758                                 attrs = _transaction;
759
760                         bool value = result.getInt(1) != 0;
761                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
762                         OSAttribute *attr;
763                         if (it != attrs->end())
764                         {
765                                 if (it->second != NULL)
766                                 {
767                                         delete it->second;
768                                 }
769
770                                 it->second = new OSAttribute(value);
771                                 attr = it->second;
772                         }
773                         else
774                         {
775                                 attr = new OSAttribute(value);
776                                 (*attrs)[type] = attr;
777                         }
778                         return attr;
779                 }
780                 case akInteger:
781                 {
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",
785                                 type,
786                                 _objectId);
787                         if (!statement.isValid())
788                         {
789                                 return NULL;
790                         }
791                         DB::Result result = _connection->perform(statement);
792                         if (!result.isValid())
793                         {
794                                 return NULL;
795                         }
796                         // Store the attribute in the transaction when it is active.
797                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
798                         if (_transaction)
799                                 attrs = _transaction;
800
801                         unsigned long value = result.getULongLong(1);
802                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
803                         OSAttribute *attr;
804                         if (it != attrs->end())
805                         {
806                                 if (it->second != NULL)
807                                 {
808                                         delete it->second;
809                                 }
810
811                                 it->second = new OSAttribute(value);
812                                 attr = it->second;
813                         }
814                         else
815                         {
816                                 attr = new OSAttribute(value);
817                                 (*attrs)[type] = attr;
818                         }
819                         return attr;
820                 }
821                 case akBinary:
822                 {
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",
826                                 type,
827                                 _objectId);
828                         if (!statement.isValid())
829                         {
830                                 return NULL;
831                         }
832                         DB::Result result = _connection->perform(statement);
833                         if (!result.isValid())
834                         {
835                                 return NULL;
836                         }
837                         // Store the attribute in the transaction when it is active.
838                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
839                         if (_transaction)
840                                 attrs = _transaction;
841
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);
845                         OSAttribute *attr;
846                         if (it != attrs->end())
847                         {
848                                 if (it->second != NULL)
849                                 {
850                                         delete it->second;
851                                 }
852
853                                 it->second = new OSAttribute(ByteString(value,size));
854                                 attr = it->second;
855                         }
856                         else
857                         {
858                                 attr = new OSAttribute(ByteString(value,size));
859                                 (*attrs)[type] = attr;
860                                 return attr;
861                         }
862                         return attr;
863                 }
864                 case akMechSet:
865                 {
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",
869                                         type,
870                                         _objectId);
871                         if (!statement.isValid())
872                         {
873                                 return NULL;
874                         }
875                         DB::Result result = _connection->perform(statement);
876                         if (!result.isValid())
877                         {
878                                 return NULL;
879                         }
880                         // Store the attribute in the transaction when it is active.
881                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
882                         if (_transaction)
883                                 attrs = _transaction;
884
885                         const unsigned char *value = result.getBinary(1);
886                         size_t size = result.getFieldLength(1);
887
888                         std::set<CK_MECHANISM_TYPE> set;
889                         if (!decodeMechanismTypeSet(set, value, size))
890                         {
891                                 return NULL;
892                         }
893
894                         OSAttribute *attr;
895                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
896                         if (it != attrs->end())
897                         {
898                                 if (it->second != NULL)
899                                 {
900                                         delete it->second;
901                                 }
902
903                                 it->second = new OSAttribute(set);
904                                 attr = it->second;
905                         }
906                         else
907                         {
908                                 attr = new OSAttribute(set);
909                                 (*attrs)[type] = attr;
910                                 return attr;
911                         }
912                         return attr;
913                 }
914                 case akAttrMap:
915                 {
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",
919                                 type,
920                                 _objectId);
921                         if (!statement.isValid())
922                         {
923                                 return NULL;
924                         }
925                         DB::Result result = _connection->perform(statement);
926                         if (!result.isValid())
927                         {
928                                 return NULL;
929                         }
930                         // Store the attribute in the transaction when it is active.
931                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
932                         if (_transaction)
933                                 attrs = _transaction;
934
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);
938                         OSAttribute *attr;
939                         if (it != attrs->end())
940                         {
941                                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
942                                 if (!decodeAttributeMap(value,binary,size))
943                                 {
944                                         return NULL;
945                                 }
946
947                                 if (it->second != NULL)
948                                 {
949                                         delete it->second;
950                                 }
951
952                                 it->second = new OSAttribute(value);
953                                 attr = it->second;
954                         }
955                         else
956                         {
957                                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
958                                 if (!decodeAttributeMap(value,binary,size))
959                                 {
960                                         return NULL;
961                                 }
962                                 attr = new OSAttribute(value);
963                                 (*attrs)[type] = attr;
964                                 return attr;
965                         }
966                         return attr;
967                 }
968         }
969
970         return NULL;
971 }
972
973 // Retrieve the specified attribute for internal use
974 // Calling function must lock the mutex
975 OSAttribute* DBObject::getAttributeDB(CK_ATTRIBUTE_TYPE type)
976 {
977         if (_connection == NULL)
978         {
979                 ERROR_MSG("Object is not connected to the database.");
980                 return NULL;
981         }
982
983         if (_objectId == 0)
984         {
985                 ERROR_MSG("Cannot read from invalid object.");
986                 return NULL;
987         }
988
989         // If a transaction is in progress, we can just return the attribute from the transaction.
990         if (_transaction)
991         {
992                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
993                 if (it != _transaction->end())
994                         return it->second;
995         }
996
997         // If the attribute exists and is non-modifiable then return a previously retrieved attribute value.
998         if (!isModifiable(type))
999         {
1000                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _attributes.find(type);
1001                 if (it != _attributes.end())
1002                 {
1003                         return it->second;
1004                 }
1005         }
1006
1007         return accessAttribute(type);
1008 }
1009
1010 // Check if the specified attribute exists
1011 bool DBObject::attributeExists(CK_ATTRIBUTE_TYPE type)
1012 {
1013         MutexLocker lock(_mutex);
1014
1015         return getAttributeDB(type) != NULL;
1016 }
1017
1018 // Retrieve the specified attribute
1019 OSAttribute DBObject::getAttribute(CK_ATTRIBUTE_TYPE type)
1020 {
1021         MutexLocker lock(_mutex);
1022
1023         OSAttribute* attr = getAttributeDB(type);
1024         if (attr == NULL) return OSAttribute((unsigned long)0);
1025
1026         return *attr;
1027 }
1028
1029 bool DBObject::getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val)
1030 {
1031         MutexLocker lock(_mutex);
1032
1033         OSAttribute* attr = getAttributeDB(type);
1034         if (attr == NULL) return val;
1035
1036         if (attr->isBooleanAttribute())
1037         {
1038                 return attr->getBooleanValue();
1039         }
1040         else
1041         {
1042                 ERROR_MSG("The attribute is not a boolean: 0x%08X", type);
1043                 return val;
1044         }
1045 }
1046
1047 unsigned long DBObject::getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val)
1048 {
1049         MutexLocker lock(_mutex);
1050
1051         OSAttribute* attr = getAttributeDB(type);
1052         if (attr == NULL) return val;
1053
1054         if (attr->isUnsignedLongAttribute())
1055         {
1056                 return attr->getUnsignedLongValue();
1057         }
1058         else
1059         {
1060                 ERROR_MSG("The attribute is not an unsigned long: 0x%08X", type);
1061                 return val;
1062         }
1063 }
1064
1065 ByteString DBObject::getByteStringValue(CK_ATTRIBUTE_TYPE type)
1066 {
1067         MutexLocker lock(_mutex);
1068
1069         ByteString val;
1070
1071         OSAttribute* attr = getAttributeDB(type);
1072         if (attr == NULL) return val;
1073
1074         if (attr->isByteStringAttribute())
1075         {
1076                 return attr->getByteStringValue();
1077         }
1078         else
1079         {
1080                 ERROR_MSG("The attribute is not a byte string: 0x%08X", type);
1081                 return val;
1082         }
1083 }
1084
1085 CK_ATTRIBUTE_TYPE DBObject::nextAttributeType(CK_ATTRIBUTE_TYPE)
1086 {
1087         MutexLocker lock(_mutex);
1088
1089         if (_connection == NULL)
1090         {
1091                 ERROR_MSG("Object is not connected to the database.");
1092                 return false;
1093         }
1094         if (_objectId == 0)
1095         {
1096                 ERROR_MSG("Cannot get next attribute for invalid object.");
1097                 return false;
1098         }
1099
1100         // FIXME: implement for C_CopyObject
1101         return CKA_CLASS;
1102 }
1103
1104 // Set the specified attribute
1105 bool DBObject::setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute)
1106 {
1107         MutexLocker lock(_mutex);
1108
1109         if (_connection == NULL)
1110         {
1111                 ERROR_MSG("Object is not connected to the database.");
1112                 return false;
1113         }
1114         if (_objectId == 0)
1115         {
1116                 ERROR_MSG("Cannot update invalid object.");
1117                 return false;
1118         }
1119
1120         // Retrieve and existing attribute if it exists or NULL if it doesn't
1121         OSAttribute *attr = getAttributeDB(type);
1122
1123         // Update an existing attribute...
1124         if (attr)
1125         {
1126                 DB::Statement statement;
1127                 if (attr->isBooleanAttribute())
1128                 {
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,
1133                                         type,
1134                                         _objectId);
1135                 }
1136                 else if (attr->isUnsignedLongAttribute())
1137                 {
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()),
1142                                         type,
1143                                         _objectId);
1144                 }
1145                 else if (attr->isByteStringAttribute())
1146                 {
1147                         // update binary attribute
1148                         statement = _connection->prepare(
1149                                         "update attribute_binary set value=? where type=%lu and object_id=%lld",
1150                                         type,
1151                                         _objectId);
1152                         DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
1153                 }
1154                 else if (attr->isMechanismTypeSetAttribute())
1155                 {
1156                         // update binary attribute
1157                         ByteString value;
1158                         encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
1159
1160                         statement = _connection->prepare(
1161                                         "update attribute_binary set value=? where type=%lu and object_id=%lld",
1162                                         type,
1163                                         _objectId);
1164                         DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1165                 }
1166                 else if (attr->isAttributeMapAttribute())
1167                 {
1168                         // update attribute map attribute
1169                         ByteString value;
1170                         if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
1171                         {
1172                                 return false;
1173                         }
1174
1175                         statement = _connection->prepare(
1176                                         "update attribute_array set value=? where type=%lu and object_id=%lld",
1177                                         type,
1178                                         _objectId);
1179                         DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1180                 }
1181
1182                 // Statement is valid when a prepared statement has been attached to it.
1183                 if (statement.isValid())
1184                 {
1185                         if (!_connection->execute(statement))
1186                         {
1187                                 ERROR_MSG("Failed to update attribute %lu for object %lld",type,_objectId);
1188                                 return false;
1189                         }
1190
1191                         if (_transaction)
1192                         {
1193                                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
1194                                 if (it != _transaction->end())
1195                                         *it->second = attribute;
1196                                 else
1197                                         (*_transaction)[type] = new OSAttribute(attribute);
1198                         } else
1199                                 *attr = attribute;
1200                         return true;
1201                 }
1202         }
1203
1204         DB::Statement statement;
1205
1206         // Insert the attribute, because it is currently unknown
1207         if (attribute.isBooleanAttribute())
1208         {
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,
1213                                         type,
1214                                         _objectId);
1215
1216         }
1217         else if (attribute.isUnsignedLongAttribute())
1218         {
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()),
1223                                         type,
1224                                         _objectId);
1225         }
1226         else if (attribute.isByteStringAttribute())
1227         {
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)",
1231                                         type,
1232                                         _objectId);
1233
1234                 DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
1235         }
1236         else if (attribute.isMechanismTypeSetAttribute())
1237         {
1238                 // Could not update it, so we need to insert it.
1239                 ByteString value;
1240                 encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
1241
1242                 statement = _connection->prepare(
1243                                 "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
1244                                 type,
1245                                 _objectId);
1246                 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1247         }
1248         else if (attribute.isAttributeMapAttribute())
1249         {
1250                 // Could not update it, so we need to insert it.
1251                 ByteString value;
1252                 if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
1253                 {
1254                         return false;
1255                 }
1256
1257                 statement = _connection->prepare(
1258                                 "insert into attribute_array (value,type,object_id) values (?,%lu,%lld)",
1259                                 type,
1260                                 _objectId);
1261                 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1262         }
1263
1264         // Statement is valid when a prepared statement has been attached to it.
1265         if (statement.isValid())
1266         {
1267                 if (!_connection->execute(statement))
1268                 {
1269                         ERROR_MSG("Failed to insert attribute %lu for object %lld",type,_objectId);
1270                         return false;
1271                 }
1272
1273                 if (_transaction)
1274                         (*_transaction)[type] = new OSAttribute(attribute);
1275                 else
1276                         _attributes[type] = new OSAttribute(attribute);
1277                 return true;
1278         }
1279
1280         return false;
1281 }
1282
1283 // Set the specified attribute
1284 bool DBObject::deleteAttribute(CK_ATTRIBUTE_TYPE type)
1285 {
1286         MutexLocker lock(_mutex);
1287
1288         if (_connection == NULL)
1289         {
1290                 ERROR_MSG("Object is not connected to the database.");
1291                 return false;
1292         }
1293         if (_objectId == 0)
1294         {
1295                 ERROR_MSG("Cannot update invalid object.");
1296                 return false;
1297         }
1298
1299         // Retrieve and existing attribute if it exists or NULL if it doesn't
1300         OSAttribute *attr = getAttributeDB(type);
1301         if (attr == NULL)
1302         {
1303                 ERROR_MSG("Cannot delete an attribute that doesn't exist.");
1304                 return false;
1305         }
1306
1307         DB::Statement statement;
1308         if (attr->isBooleanAttribute())
1309         {
1310                 // delete boolean attribute
1311                 statement = _connection->prepare(
1312                                 "delete from attribute_boolean where type=%lu and object_id=%lld",
1313                                 type,
1314                                 _objectId);
1315         }
1316         else if (attr->isUnsignedLongAttribute())
1317         {
1318                 // delete integer attribute
1319                 statement = _connection->prepare(
1320                                 "delete from attribute_integer where type=%lu and object_id=%lld",
1321                                 type,
1322                                 _objectId);
1323         }
1324         else if (attr->isByteStringAttribute() || attr -> isMechanismTypeSetAttribute())
1325         {
1326                 // delete binary attribute
1327                 statement = _connection->prepare(
1328                                 "delete from attribute_binary where type=%lu and object_id=%lld",
1329                                 type,
1330                                 _objectId);
1331         }
1332         else if (attr->isAttributeMapAttribute())
1333         {
1334                 // delete attribute map attribute
1335                 statement = _connection->prepare(
1336                                 "delete from attribute_array where type=%lu and object_id=%lld",
1337                                 type,
1338                                 _objectId);
1339         }
1340
1341         // Statement is valid when a prepared statement has been attached to it.
1342         if (statement.isValid())
1343         {
1344                 if (!_connection->execute(statement))
1345                 {
1346                         ERROR_MSG("Failed to delete attribute %lu for object %lld",type,_objectId);
1347                         return false;
1348                 }
1349
1350                 if (_transaction)
1351                 {
1352                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
1353                         if (it != _transaction->end())
1354                         {
1355                                 delete it->second;
1356                                 it->second = NULL;
1357                         }
1358                 }
1359
1360                 return true;
1361         }
1362
1363         return false;
1364 }
1365
1366 // The validity state of the object
1367 bool DBObject::isValid()
1368 {
1369         MutexLocker lock(_mutex);
1370
1371         return _objectId != 0 && _connection != NULL;
1372 }
1373
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.
1377 //
1378 // N.B.: Starting a transaction locks the object!
1379 bool DBObject::startTransaction(Access access)
1380 {
1381         MutexLocker lock(_mutex);
1382
1383         if (_connection == NULL)
1384         {
1385                 ERROR_MSG("Object is not connected to the database.");
1386                 return false;
1387         }
1388
1389         if (_transaction)
1390         {
1391                 ERROR_MSG("Transaction is already active.");
1392                 return false;
1393         }
1394
1395         _transaction = new std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>;
1396         if (_transaction == NULL)
1397         {
1398                 ERROR_MSG("Not enough memory to start transaction.");
1399                 return false;
1400         }
1401
1402         if (_connection->inTransaction())
1403         {
1404                 ERROR_MSG("Transaction in database is already active.");
1405                 return false;
1406         }
1407
1408         // Ask the connection to start the transaction.
1409         if (access == ReadWrite)
1410                 return _connection->beginTransactionRW();
1411         else
1412                 return _connection->beginTransactionRO();
1413 }
1414
1415 // Commit an attribute transaction
1416 bool DBObject::commitTransaction()
1417 {
1418         MutexLocker lock(_mutex);
1419
1420         if (_connection == NULL)
1421         {
1422                 ERROR_MSG("Object is not connected to the database.");
1423                 return false;
1424         }
1425
1426         if (_transaction == NULL)
1427         {
1428                 ERROR_MSG("No transaction active.");
1429                 return false;
1430         }
1431
1432         if (!_connection->commitTransaction())
1433         {
1434                 return false;
1435         }
1436
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())
1441                 {
1442                         _attributes[it->first] = it->second;
1443                 }
1444                 else
1445                 {
1446                         *attr_it->second = *it->second;
1447                         delete it->second;
1448                 }
1449                 it->second = NULL;
1450         }
1451         delete _transaction;
1452         _transaction = NULL;
1453         return true;
1454 }
1455
1456 // Abort an attribute transaction; loads back the previous version of the object from disk
1457 bool DBObject::abortTransaction()
1458 {
1459         MutexLocker lock(_mutex);
1460
1461         if (_connection == NULL)
1462         {
1463                 ERROR_MSG("Object is not connected to the database.");
1464                 return false;
1465         }
1466
1467         // Forget the atributes that were set during the transaction.
1468         if (_transaction)
1469         {
1470                 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
1471                         delete it->second;
1472                         it->second = NULL;
1473                 }
1474                 delete _transaction;
1475                 _transaction = NULL;
1476         }
1477
1478         return _connection->rollbackTransaction();
1479 }
1480
1481 // Destroy the object; WARNING: pointers to the object become invalid after this call
1482 bool DBObject::destroyObject()
1483 {
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.
1487
1488         if (_token == NULL)
1489         {
1490                 ERROR_MSG("Cannot destroy an object that is not associated with a token");
1491                 return false;
1492         }
1493
1494         return _token->deleteObject(this);
1495 }