d2515bde068b292a01da881522998bede09a8bf9
[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                 return true;
389         default:
390                 return false;
391         }
392 }
393
394 enum AttributeKind {
395         akUnknown,
396         akBoolean,
397         akInteger,
398         akBinary,
399         akAttrMap,
400         akMechSet
401 };
402
403 static AttributeKind attributeKind(CK_ATTRIBUTE_TYPE type)
404 {
405         switch (type) {
406         case CKA_CLASS: return akInteger;
407         case CKA_TOKEN: return akBoolean;
408         case CKA_PRIVATE: return akBoolean;
409         case CKA_LABEL: return akBinary;
410         case CKA_APPLICATION: return akBinary;
411         case CKA_VALUE: return akBinary;
412         case CKA_OBJECT_ID: return akBinary;
413         case CKA_CERTIFICATE_TYPE: return akInteger;
414         case CKA_ISSUER: return akBinary;
415         case CKA_SERIAL_NUMBER: return akBinary;
416         case CKA_AC_ISSUER: return akBinary;
417         case CKA_OWNER: return akBinary;
418         case CKA_ATTR_TYPES: return akBinary;
419         case CKA_TRUSTED: return akBoolean;
420         case CKA_CERTIFICATE_CATEGORY: return akInteger;
421         case CKA_JAVA_MIDP_SECURITY_DOMAIN: return akInteger;
422         case CKA_URL: return akBinary;
423         case CKA_HASH_OF_SUBJECT_PUBLIC_KEY: return akBinary;
424         case CKA_HASH_OF_ISSUER_PUBLIC_KEY: return akBinary;
425         case CKA_NAME_HASH_ALGORITHM: return akInteger;
426         case CKA_CHECK_VALUE: return akBinary;
427         case CKA_KEY_TYPE: return akInteger;
428         case CKA_SUBJECT: return akBinary;
429         case CKA_ID: return akBinary;
430         case CKA_SENSITIVE: return akBoolean;
431         case CKA_ENCRYPT: return akBoolean;
432         case CKA_DECRYPT: return akBoolean;
433         case CKA_WRAP: return akBoolean;
434         case CKA_UNWRAP: return akBoolean;
435         case CKA_SIGN: return akBoolean;
436         case CKA_SIGN_RECOVER: return akBoolean;
437         case CKA_VERIFY: return akBoolean;
438         case CKA_VERIFY_RECOVER: return akBoolean;
439         case CKA_DERIVE: return akBoolean;
440         case CKA_START_DATE: return akBinary;
441         case CKA_END_DATE: return akBinary;
442         case CKA_MODULUS: return akBinary;
443         case CKA_MODULUS_BITS: return akInteger;
444         case CKA_PUBLIC_EXPONENT: return akBinary;
445         case CKA_PRIVATE_EXPONENT: return akBinary;
446         case CKA_PRIME_1: return akBinary;
447         case CKA_PRIME_2: return akBinary;
448         case CKA_EXPONENT_1: return akBinary;
449         case CKA_EXPONENT_2: return akBinary;
450         case CKA_COEFFICIENT: return akBinary;
451         case CKA_PRIME: return akBinary;
452         case CKA_SUBPRIME: return akBinary;
453         case CKA_BASE: return akBinary;
454         case CKA_PRIME_BITS: return akInteger;
455         case CKA_SUBPRIME_BITS: return akInteger;
456         case CKA_VALUE_BITS: return akInteger;
457         case CKA_VALUE_LEN: return akInteger;
458         case CKA_EXTRACTABLE: return akBoolean;
459         case CKA_LOCAL: return akBoolean;
460         case CKA_NEVER_EXTRACTABLE: return akBoolean;
461         case CKA_ALWAYS_SENSITIVE: return akBoolean;
462         case CKA_KEY_GEN_MECHANISM: return akInteger;
463         case CKA_MODIFIABLE: return akBoolean;
464         case CKA_COPYABLE: return akBoolean;
465         case CKA_ECDSA_PARAMS: return akBinary;
466         case CKA_EC_POINT: return akBinary;
467         case CKA_SECONDARY_AUTH: return akBoolean;
468         case CKA_AUTH_PIN_FLAGS: return akInteger;
469         case CKA_ALWAYS_AUTHENTICATE: return akBoolean;
470         case CKA_WRAP_WITH_TRUSTED: return akBoolean;
471 /*
472         case CKA_OTP_FORMAT:
473         case CKA_OTP_LENGTH:
474         case CKA_OTP_TIME_INTERVAL:
475         case CKA_OTP_USER_FRIENDLY_MODE:
476         case CKA_OTP_CHALLENGE_REQUIREMENT:
477         case CKA_OTP_TIME_REQUIREMENT:
478         case CKA_OTP_COUNTER_REQUIREMENT:
479         case CKA_OTP_PIN_REQUIREMENT:
480         case CKA_OTP_COUNTER:
481         case CKA_OTP_TIME:
482         case CKA_OTP_USER_IDENTIFIER:
483         case CKA_OTP_SERVICE_IDENTIFIER:
484         case CKA_OTP_SERVICE_LOGO:
485         case CKA_OTP_SERVICE_LOGO_TYPE:
486 */
487         case CKA_GOSTR3410_PARAMS: return akBinary;
488         case CKA_GOSTR3411_PARAMS: return akBinary;
489         case CKA_GOST28147_PARAMS: return akBinary;
490 /*
491         case CKA_HW_FEATURE_TYPE:
492         case CKA_RESET_ON_INIT:
493         case CKA_HAS_RESET:
494         case CKA_PIXEL_X:
495         case CKA_PIXEL_Y:
496         case CKA_RESOLUTION:
497         case CKA_CHAR_ROWS:
498         case CKA_CHAR_COLUMNS:
499         case CKA_COLOR:
500         case CKA_BITS_PER_PIXEL:
501         case CKA_CHAR_SETS:
502         case CKA_ENCODING_METHODS:
503         case CKA_MIME_TYPES:
504         case CKA_MECHANISM_TYPE:
505         case CKA_REQUIRED_CMS_ATTRIBUTES:
506         case CKA_DEFAULT_CMS_ATTRIBUTES:
507         case CKA_SUPPORTED_CMS_ATTRIBUTES:
508 */
509         case CKA_WRAP_TEMPLATE: return akAttrMap;
510         case CKA_UNWRAP_TEMPLATE: return akAttrMap;
511         case CKA_DERIVE_TEMPLATE: return akAttrMap;
512         case CKA_ALLOWED_MECHANISMS: return akMechSet;
513
514         case CKA_OS_TOKENLABEL: return akBinary;
515         case CKA_OS_TOKENSERIAL: return akBinary;
516         case CKA_OS_TOKENFLAGS: return akInteger;
517         case CKA_OS_SOPIN: return akBinary;
518         case CKA_OS_USERPIN: return akBinary;
519
520         default: return akUnknown;
521         }
522 }
523
524 static bool decodeMechanismTypeSet(std::set<CK_MECHANISM_TYPE>& set, const unsigned char *binary, size_t size)
525 {
526         for (size_t pos = 0; pos < size; )
527         {
528                 // finished?
529                 if (pos == size) break;
530
531                 CK_MECHANISM_TYPE mechType;
532                 if (pos + sizeof(mechType) > size)
533                 {
534                         ERROR_MSG("mechanism type set overrun");
535                         return false;
536                 }
537
538                 memcpy(&mechType, binary + pos, sizeof(mechType));
539                 pos += sizeof(mechType);
540
541                 set.insert(mechType);
542     }
543
544         return true;
545 }
546
547 static void encodeMechanismTypeSet(ByteString& value, const std::set<CK_MECHANISM_TYPE>& set)
548 {
549         for (std::set<CK_MECHANISM_TYPE>::const_iterator i = set.begin(); i != set.end(); ++i)
550         {
551                 CK_MECHANISM_TYPE mechType = *i;
552                 value += ByteString((unsigned char *) &mechType, sizeof(mechType));
553         }
554 }
555
556 static bool decodeAttributeMap(std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& map, const unsigned char *binary, size_t size)
557 {
558         for (size_t pos = 0; pos < size; )
559         {
560                 // finished?
561                 if (pos == size) break;
562
563                 CK_ATTRIBUTE_TYPE attrType;
564                 if (pos + sizeof(attrType) > size)
565                 {
566                         goto overrun;
567                 }
568                 memcpy(&attrType, binary + pos, sizeof(attrType));
569                 pos += sizeof(attrType);
570
571                 AttributeKind attrKind;
572                 if (pos + sizeof(AttributeKind) > size)
573                 {
574                         goto overrun;
575                 }
576                 memcpy(&attrKind, binary + pos, sizeof(attrKind));
577                 pos += sizeof(attrKind);
578
579                 // Verify using attributeKind()?
580
581                 switch (attrKind)
582                 {
583                         case akBoolean:
584                         {
585                                 bool value;
586                                 if (pos + sizeof(value) > size)
587                                 {
588                                         goto overrun;
589                                 }
590                                 memcpy(&value, binary + pos, sizeof(value));
591                                 pos += sizeof(value);
592
593                                 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
594                         }
595                         break;
596
597                         case akInteger:
598                         {
599                                 unsigned long value;
600                                 if (pos + sizeof(value) > size)
601                                 {
602                                         goto overrun;
603                                 }
604                                 memcpy(&value, binary + pos, sizeof(value));
605                                 pos += sizeof(value);
606
607                                 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
608                         }
609                         break;
610
611                         case akBinary:
612                         {
613                                 ByteString value;
614                                 unsigned long len;
615                                 if (pos + sizeof(len) > size)
616                                 {
617                                         goto overrun;
618                                 }
619                                 memcpy(&len, binary + pos, sizeof(len));
620                                 pos += sizeof(len);
621
622                                 if (pos + len > size)
623                                 {
624                                         goto overrun;
625                                 }
626                                 value.resize(len);
627                                 memcpy(&value[0], binary + pos, len);
628                                 pos += len;
629
630                                 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
631                         }
632                         break;
633
634                         case akMechSet:
635                         {
636                                 unsigned long len;
637                                 if (pos + sizeof(len) > size)
638                                 {
639                                         goto overrun;
640                                 }
641                                 memcpy(&len, binary + pos, sizeof(len));
642                                 pos += sizeof(len);
643
644                                 if (pos + len > size)
645                                 {
646                                         goto overrun;
647                                 }
648
649                                 std::set<CK_MECHANISM_TYPE> value;
650                                 if (!decodeMechanismTypeSet(value, binary + pos, len)) {
651                                         return false;
652                                 }
653                                 pos += len;
654
655                                 map.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (attrType, value));
656                         }
657                         break;
658
659                         default:
660                         ERROR_MSG("unsupported attribute kind in attribute map");
661
662                         return false;
663                 }
664         }
665
666         return true;
667
668 overrun:
669         ERROR_MSG("attribute map template overrun");
670
671         return false;
672 }
673
674 static bool encodeAttributeMap(ByteString& value, const std::map<CK_ATTRIBUTE_TYPE,OSAttribute>& attributes)
675 {
676         for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute>::const_iterator i = attributes.begin(); i != attributes.end(); ++i)
677         {
678                 CK_ATTRIBUTE_TYPE attrType = i->first;
679                 value += ByteString((unsigned char*) &attrType, sizeof(attrType));
680
681                 OSAttribute attr = i->second;
682                 if (attr.isBooleanAttribute())
683                 {
684                         AttributeKind attrKind = akBoolean;
685                         value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
686
687                         bool val = attr.getBooleanValue();
688                         value += ByteString((unsigned char*) &val, sizeof(val));
689                 }
690                 else if (attr.isUnsignedLongAttribute())
691                 {
692                         AttributeKind attrKind = akInteger;
693                         value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
694
695                         unsigned long val = attr.getUnsignedLongValue();
696                         value += ByteString((unsigned char*) &val, sizeof(val));
697                 }
698                 else if (attr.isByteStringAttribute())
699                 {
700                         AttributeKind attrKind = akBinary;
701                         value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
702
703                         ByteString val = attr.getByteStringValue();
704                         unsigned long len = val.size();
705                         value += ByteString((unsigned char*) &len, sizeof(len));
706                         value += val;
707                 }
708                 else if (attr.isMechanismTypeSetAttribute())
709                 {
710                         AttributeKind attrKind = akMechSet;
711                         value += ByteString((unsigned char*) &attrKind, sizeof(attrKind));
712
713                         ByteString val;
714                         encodeMechanismTypeSet(val, attr.getMechanismTypeSetValue());
715
716                         unsigned long len = val.size();
717                         value += ByteString((unsigned char*) &len, sizeof(len));
718                         value += val;
719                 }
720                 else
721                 {
722                         ERROR_MSG("unsupported attribute kind for attribute map");
723
724                         return false;
725                 }
726         }
727
728         return true;
729 }
730
731 OSAttribute *DBObject::accessAttribute(CK_ATTRIBUTE_TYPE type)
732 {
733         switch (attributeKind(type))
734         {
735                 case akUnknown:
736                         return NULL;
737                 case akBoolean:
738                 {
739                         // try to find the attribute in the boolean attribute table
740                         DB::Statement statement = _connection->prepare(
741                                 "select value from attribute_boolean where type=%lu and object_id=%lld",
742                                 type,
743                                 _objectId);
744                         if (!statement.isValid())
745                         {
746                                 return NULL;
747                         }
748                         DB::Result result = _connection->perform(statement);
749                         if (!result.isValid())
750                         {
751                                 return NULL;
752                         }
753                         // Store the attribute in the transaction when it is active.
754                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
755                         if (_transaction)
756                                 attrs = _transaction;
757
758                         bool value = result.getInt(1) != 0;
759                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
760                         OSAttribute *attr;
761                         if (it != attrs->end())
762                         {
763                                 if (it->second != NULL)
764                                 {
765                                         delete it->second;
766                                 }
767
768                                 it->second = new OSAttribute(value);
769                                 attr = it->second;
770                         }
771                         else
772                         {
773                                 attr = new OSAttribute(value);
774                                 (*attrs)[type] = attr;
775                         }
776                         return attr;
777                 }
778                 case akInteger:
779                 {
780                         // try to find the attribute in the integer attribute table
781                         DB::Statement statement = _connection->prepare(
782                                 "select value from attribute_integer where type=%lu and object_id=%lld",
783                                 type,
784                                 _objectId);
785                         if (!statement.isValid())
786                         {
787                                 return NULL;
788                         }
789                         DB::Result result = _connection->perform(statement);
790                         if (!result.isValid())
791                         {
792                                 return NULL;
793                         }
794                         // Store the attribute in the transaction when it is active.
795                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
796                         if (_transaction)
797                                 attrs = _transaction;
798
799                         unsigned long value = result.getULongLong(1);
800                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
801                         OSAttribute *attr;
802                         if (it != attrs->end())
803                         {
804                                 if (it->second != NULL)
805                                 {
806                                         delete it->second;
807                                 }
808
809                                 it->second = new OSAttribute(value);
810                                 attr = it->second;
811                         }
812                         else
813                         {
814                                 attr = new OSAttribute(value);
815                                 (*attrs)[type] = attr;
816                         }
817                         return attr;
818                 }
819                 case akBinary:
820                 {
821                         // try to find the attribute in the binary attribute table
822                         DB::Statement statement = _connection->prepare(
823                                 "select value from attribute_binary where type=%lu and object_id=%lld",
824                                 type,
825                                 _objectId);
826                         if (!statement.isValid())
827                         {
828                                 return NULL;
829                         }
830                         DB::Result result = _connection->perform(statement);
831                         if (!result.isValid())
832                         {
833                                 return NULL;
834                         }
835                         // Store the attribute in the transaction when it is active.
836                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
837                         if (_transaction)
838                                 attrs = _transaction;
839
840                         const unsigned char *value = result.getBinary(1);
841                         size_t size = result.getFieldLength(1);
842                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
843                         OSAttribute *attr;
844                         if (it != attrs->end())
845                         {
846                                 if (it->second != NULL)
847                                 {
848                                         delete it->second;
849                                 }
850
851                                 it->second = new OSAttribute(ByteString(value,size));
852                                 attr = it->second;
853                         }
854                         else
855                         {
856                                 attr = new OSAttribute(ByteString(value,size));
857                                 (*attrs)[type] = attr;
858                                 return attr;
859                         }
860                         return attr;
861                 }
862                 case akMechSet:
863                 {
864                         // try to find the attribute in the binary attribute table
865                         DB::Statement statement = _connection->prepare(
866                                         "select value from attribute_binary where type=%lu and object_id=%lld",
867                                         type,
868                                         _objectId);
869                         if (!statement.isValid())
870                         {
871                                 return NULL;
872                         }
873                         DB::Result result = _connection->perform(statement);
874                         if (!result.isValid())
875                         {
876                                 return NULL;
877                         }
878                         // Store the attribute in the transaction when it is active.
879                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
880                         if (_transaction)
881                                 attrs = _transaction;
882
883                         const unsigned char *value = result.getBinary(1);
884                         size_t size = result.getFieldLength(1);
885
886                         std::set<CK_MECHANISM_TYPE> set;
887                         if (!decodeMechanismTypeSet(set, value, size))
888                         {
889                                 return NULL;
890                         }
891
892                         OSAttribute *attr;
893                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
894                         if (it != attrs->end())
895                         {
896                                 if (it->second != NULL)
897                                 {
898                                         delete it->second;
899                                 }
900
901                                 it->second = new OSAttribute(set);
902                                 attr = it->second;
903                         }
904                         else
905                         {
906                                 attr = new OSAttribute(set);
907                                 (*attrs)[type] = attr;
908                                 return attr;
909                         }
910                         return attr;
911                 }
912                 case akAttrMap:
913                 {
914                         // try to find the attribute in the array attribute table
915                         DB::Statement statement = _connection->prepare(
916                                 "select value from attribute_array where type=%lu and object_id=%lld",
917                                 type,
918                                 _objectId);
919                         if (!statement.isValid())
920                         {
921                                 return NULL;
922                         }
923                         DB::Result result = _connection->perform(statement);
924                         if (!result.isValid())
925                         {
926                                 return NULL;
927                         }
928                         // Store the attribute in the transaction when it is active.
929                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*> *attrs = &_attributes;
930                         if (_transaction)
931                                 attrs = _transaction;
932
933                         const unsigned char *binary = result.getBinary(1);
934                         size_t size = result.getFieldLength(1);
935                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  attrs->find(type);
936                         OSAttribute *attr;
937                         if (it != attrs->end())
938                         {
939                                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
940                                 if (!decodeAttributeMap(value,binary,size))
941                                 {
942                                         return NULL;
943                                 }
944
945                                 if (it->second != NULL)
946                                 {
947                                         delete it->second;
948                                 }
949
950                                 it->second = new OSAttribute(value);
951                                 attr = it->second;
952                         }
953                         else
954                         {
955                                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute> value;
956                                 if (!decodeAttributeMap(value,binary,size))
957                                 {
958                                         return NULL;
959                                 }
960                                 attr = new OSAttribute(value);
961                                 (*attrs)[type] = attr;
962                                 return attr;
963                         }
964                         return attr;
965                 }
966         }
967
968         return NULL;
969 }
970
971 // Retrieve the specified attribute for internal use
972 // Calling function must lock the mutex
973 OSAttribute* DBObject::getAttributeDB(CK_ATTRIBUTE_TYPE type)
974 {
975         if (_connection == NULL)
976         {
977                 ERROR_MSG("Object is not connected to the database.");
978                 return NULL;
979         }
980
981         if (_objectId == 0)
982         {
983                 ERROR_MSG("Cannot read from invalid object.");
984                 return NULL;
985         }
986
987         // If a transaction is in progress, we can just return the attribute from the transaction.
988         if (_transaction)
989         {
990                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
991                 if (it != _transaction->end())
992                         return it->second;
993         }
994
995         // If the attribute exists and is non-modifiable then return a previously retrieved attribute value.
996         if (!isModifiable(type))
997         {
998                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _attributes.find(type);
999                 if (it != _attributes.end())
1000                 {
1001                         return it->second;
1002                 }
1003         }
1004
1005         return accessAttribute(type);
1006 }
1007
1008 // Check if the specified attribute exists
1009 bool DBObject::attributeExists(CK_ATTRIBUTE_TYPE type)
1010 {
1011         MutexLocker lock(_mutex);
1012
1013         return getAttributeDB(type) != NULL;
1014 }
1015
1016 // Retrieve the specified attribute
1017 OSAttribute DBObject::getAttribute(CK_ATTRIBUTE_TYPE type)
1018 {
1019         MutexLocker lock(_mutex);
1020
1021         OSAttribute* attr = getAttributeDB(type);
1022         if (attr == NULL) return OSAttribute((unsigned long)0);
1023
1024         return *attr;
1025 }
1026
1027 bool DBObject::getBooleanValue(CK_ATTRIBUTE_TYPE type, bool val)
1028 {
1029         MutexLocker lock(_mutex);
1030
1031         OSAttribute* attr = getAttributeDB(type);
1032         if (attr == NULL) return val;
1033
1034         if (attr->isBooleanAttribute())
1035         {
1036                 return attr->getBooleanValue();
1037         }
1038         else
1039         {
1040                 ERROR_MSG("The attribute is not a boolean: 0x%08X", type);
1041                 return val;
1042         }
1043 }
1044
1045 unsigned long DBObject::getUnsignedLongValue(CK_ATTRIBUTE_TYPE type, unsigned long val)
1046 {
1047         MutexLocker lock(_mutex);
1048
1049         OSAttribute* attr = getAttributeDB(type);
1050         if (attr == NULL) return val;
1051
1052         if (attr->isUnsignedLongAttribute())
1053         {
1054                 return attr->getUnsignedLongValue();
1055         }
1056         else
1057         {
1058                 ERROR_MSG("The attribute is not an unsigned long: 0x%08X", type);
1059                 return val;
1060         }
1061 }
1062
1063 ByteString DBObject::getByteStringValue(CK_ATTRIBUTE_TYPE type)
1064 {
1065         MutexLocker lock(_mutex);
1066
1067         ByteString val;
1068
1069         OSAttribute* attr = getAttributeDB(type);
1070         if (attr == NULL) return val;
1071
1072         if (attr->isByteStringAttribute())
1073         {
1074                 return attr->getByteStringValue();
1075         }
1076         else
1077         {
1078                 ERROR_MSG("The attribute is not a byte string: 0x%08X", type);
1079                 return val;
1080         }
1081 }
1082
1083 CK_ATTRIBUTE_TYPE DBObject::nextAttributeType(CK_ATTRIBUTE_TYPE)
1084 {
1085         MutexLocker lock(_mutex);
1086
1087         if (_connection == NULL)
1088         {
1089                 ERROR_MSG("Object is not connected to the database.");
1090                 return false;
1091         }
1092         if (_objectId == 0)
1093         {
1094                 ERROR_MSG("Cannot get next attribute for invalid object.");
1095                 return false;
1096         }
1097
1098         // FIXME: implement for C_CopyObject
1099         return CKA_CLASS;
1100 }
1101
1102 // Set the specified attribute
1103 bool DBObject::setAttribute(CK_ATTRIBUTE_TYPE type, const OSAttribute& attribute)
1104 {
1105         MutexLocker lock(_mutex);
1106
1107         if (_connection == NULL)
1108         {
1109                 ERROR_MSG("Object is not connected to the database.");
1110                 return false;
1111         }
1112         if (_objectId == 0)
1113         {
1114                 ERROR_MSG("Cannot update invalid object.");
1115                 return false;
1116         }
1117
1118         // Retrieve and existing attribute if it exists or NULL if it doesn't
1119         OSAttribute *attr = getAttributeDB(type);
1120
1121         // Update an existing attribute...
1122         if (attr)
1123         {
1124                 DB::Statement statement;
1125                 if (attr->isBooleanAttribute())
1126                 {
1127                         // update boolean attribute
1128                         statement = _connection->prepare(
1129                                         "update attribute_boolean set value=%d where type=%lu and object_id=%lld",
1130                                         attribute.getBooleanValue() ? 1 : 0,
1131                                         type,
1132                                         _objectId);
1133                 }
1134                 else if (attr->isUnsignedLongAttribute())
1135                 {
1136                         // update integer attribute
1137                         statement = _connection->prepare(
1138                                         "update attribute_integer set value=%lld where type=%lu and object_id=%lld",
1139                                         static_cast<long long>(attribute.getUnsignedLongValue()),
1140                                         type,
1141                                         _objectId);
1142                 }
1143                 else if (attr->isByteStringAttribute())
1144                 {
1145                         // update binary attribute
1146                         statement = _connection->prepare(
1147                                         "update attribute_binary set value=? where type=%lu and object_id=%lld",
1148                                         type,
1149                                         _objectId);
1150                         DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
1151                 }
1152                 else if (attr->isMechanismTypeSetAttribute())
1153                 {
1154                         // update binary attribute
1155                         ByteString value;
1156                         encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
1157
1158                         statement = _connection->prepare(
1159                                         "update attribute_binary set value=? where type=%lu and object_id=%lld",
1160                                         type,
1161                                         _objectId);
1162                         DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1163                 }
1164                 else if (attr->isAttributeMapAttribute())
1165                 {
1166                         // update attribute map attribute
1167                         ByteString value;
1168                         if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
1169                         {
1170                                 return false;
1171                         }
1172
1173                         statement = _connection->prepare(
1174                                         "update attribute_array set value=? where type=%lu and object_id=%lld",
1175                                         type,
1176                                         _objectId);
1177                         DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1178                 }
1179
1180                 // Statement is valid when a prepared statement has been attached to it.
1181                 if (statement.isValid())
1182                 {
1183                         if (!_connection->execute(statement))
1184                         {
1185                                 ERROR_MSG("Failed to update attribute %lu for object %lld",type,_objectId);
1186                                 return false;
1187                         }
1188
1189                         if (_transaction)
1190                         {
1191                                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
1192                                 if (it != _transaction->end())
1193                                         *it->second = attribute;
1194                                 else
1195                                         (*_transaction)[type] = new OSAttribute(attribute);
1196                         } else
1197                                 *attr = attribute;
1198                         return true;
1199                 }
1200         }
1201
1202         DB::Statement statement;
1203
1204         // Insert the attribute, because it is currently unknown
1205         if (attribute.isBooleanAttribute())
1206         {
1207                 // Could not update it, so we need to insert it.
1208                 statement = _connection->prepare(
1209                                         "insert into attribute_boolean (value,type,object_id) values (%d,%lu,%lld)",
1210                                         attribute.getBooleanValue() ? 1 : 0,
1211                                         type,
1212                                         _objectId);
1213
1214         }
1215         else if (attribute.isUnsignedLongAttribute())
1216         {
1217                 // Could not update it, so we need to insert it.
1218                 statement = _connection->prepare(
1219                                         "insert into attribute_integer (value,type,object_id) values (%lld,%lu,%lld)",
1220                                         static_cast<long long>(attribute.getUnsignedLongValue()),
1221                                         type,
1222                                         _objectId);
1223         }
1224         else if (attribute.isByteStringAttribute())
1225         {
1226                 // Could not update it, so we need to insert it.
1227                 statement = _connection->prepare(
1228                                         "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
1229                                         type,
1230                                         _objectId);
1231
1232                 DB::Bindings(statement).bindBlob(1, attribute.getByteStringValue().const_byte_str(), attribute.getByteStringValue().size(), SQLITE_STATIC);
1233         }
1234         else if (attribute.isMechanismTypeSetAttribute())
1235         {
1236                 // Could not update it, so we need to insert it.
1237                 ByteString value;
1238                 encodeMechanismTypeSet(value, attribute.getMechanismTypeSetValue());
1239
1240                 statement = _connection->prepare(
1241                                 "insert into attribute_binary (value,type,object_id) values (?,%lu,%lld)",
1242                                 type,
1243                                 _objectId);
1244                 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1245         }
1246         else if (attribute.isAttributeMapAttribute())
1247         {
1248                 // Could not update it, so we need to insert it.
1249                 ByteString value;
1250                 if (!encodeAttributeMap(value, attribute.getAttributeMapValue()))
1251                 {
1252                         return false;
1253                 }
1254
1255                 statement = _connection->prepare(
1256                                 "insert into attribute_array (value,type,object_id) values (?,%lu,%lld)",
1257                                 type,
1258                                 _objectId);
1259                 DB::Bindings(statement).bindBlob(1, value.const_byte_str(), value.size(), SQLITE_TRANSIENT);
1260         }
1261
1262         // Statement is valid when a prepared statement has been attached to it.
1263         if (statement.isValid())
1264         {
1265                 if (!_connection->execute(statement))
1266                 {
1267                         ERROR_MSG("Failed to insert attribute %lu for object %lld",type,_objectId);
1268                         return false;
1269                 }
1270
1271                 if (_transaction)
1272                         (*_transaction)[type] = new OSAttribute(attribute);
1273                 else
1274                         _attributes[type] = new OSAttribute(attribute);
1275                 return true;
1276         }
1277
1278         return false;
1279 }
1280
1281 // Set the specified attribute
1282 bool DBObject::deleteAttribute(CK_ATTRIBUTE_TYPE type)
1283 {
1284         MutexLocker lock(_mutex);
1285
1286         if (_connection == NULL)
1287         {
1288                 ERROR_MSG("Object is not connected to the database.");
1289                 return false;
1290         }
1291         if (_objectId == 0)
1292         {
1293                 ERROR_MSG("Cannot update invalid object.");
1294                 return false;
1295         }
1296
1297         // Retrieve and existing attribute if it exists or NULL if it doesn't
1298         OSAttribute *attr = getAttributeDB(type);
1299         if (attr == NULL)
1300         {
1301                 ERROR_MSG("Cannot delete an attribute that doesn't exist.");
1302                 return false;
1303         }
1304
1305         DB::Statement statement;
1306         if (attr->isBooleanAttribute())
1307         {
1308                 // delete boolean attribute
1309                 statement = _connection->prepare(
1310                                 "delete from attribute_boolean where type=%lu and object_id=%lld",
1311                                 type,
1312                                 _objectId);
1313         }
1314         else if (attr->isUnsignedLongAttribute())
1315         {
1316                 // delete integer attribute
1317                 statement = _connection->prepare(
1318                                 "delete from attribute_integer where type=%lu and object_id=%lld",
1319                                 type,
1320                                 _objectId);
1321         }
1322         else if (attr->isByteStringAttribute() || attr -> isMechanismTypeSetAttribute())
1323         {
1324                 // delete binary attribute
1325                 statement = _connection->prepare(
1326                                 "delete from attribute_binary where type=%lu and object_id=%lld",
1327                                 type,
1328                                 _objectId);
1329         }
1330         else if (attr->isAttributeMapAttribute())
1331         {
1332                 // delete attribute map attribute
1333                 statement = _connection->prepare(
1334                                 "delete from attribute_array where type=%lu and object_id=%lld",
1335                                 type,
1336                                 _objectId);
1337         }
1338
1339         // Statement is valid when a prepared statement has been attached to it.
1340         if (statement.isValid())
1341         {
1342                 if (!_connection->execute(statement))
1343                 {
1344                         ERROR_MSG("Failed to delete attribute %lu for object %lld",type,_objectId);
1345                         return false;
1346                 }
1347
1348                 if (_transaction)
1349                 {
1350                         std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it =  _transaction->find(type);
1351                         if (it != _transaction->end())
1352                         {
1353                                 delete it->second;
1354                                 it->second = NULL;
1355                         }
1356                 }
1357
1358                 return true;
1359         }
1360
1361         return false;
1362 }
1363
1364 // The validity state of the object
1365 bool DBObject::isValid()
1366 {
1367         MutexLocker lock(_mutex);
1368
1369         return _objectId != 0 && _connection != NULL;
1370 }
1371
1372 // Start an attribute set transaction; this method is used when - for
1373 // example - a key is generated and all its attributes need to be
1374 // persisted in one go.
1375 //
1376 // N.B.: Starting a transaction locks the object!
1377 bool DBObject::startTransaction(Access access)
1378 {
1379         MutexLocker lock(_mutex);
1380
1381         if (_connection == NULL)
1382         {
1383                 ERROR_MSG("Object is not connected to the database.");
1384                 return false;
1385         }
1386
1387         if (_transaction)
1388         {
1389                 ERROR_MSG("Transaction is already active.");
1390                 return false;
1391         }
1392
1393         _transaction = new std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>;
1394         if (_transaction == NULL)
1395         {
1396                 ERROR_MSG("Not enough memory to start transaction.");
1397                 return false;
1398         }
1399
1400         if (_connection->inTransaction())
1401         {
1402                 ERROR_MSG("Transaction in database is already active.");
1403                 return false;
1404         }
1405
1406         // Ask the connection to start the transaction.
1407         if (access == ReadWrite)
1408                 return _connection->beginTransactionRW();
1409         else
1410                 return _connection->beginTransactionRO();
1411 }
1412
1413 // Commit an attribute transaction
1414 bool DBObject::commitTransaction()
1415 {
1416         MutexLocker lock(_mutex);
1417
1418         if (_connection == NULL)
1419         {
1420                 ERROR_MSG("Object is not connected to the database.");
1421                 return false;
1422         }
1423
1424         if (_transaction == NULL)
1425         {
1426                 ERROR_MSG("No transaction active.");
1427                 return false;
1428         }
1429
1430         if (!_connection->commitTransaction())
1431         {
1432                 return false;
1433         }
1434
1435         // Copy the values from the internally stored transaction to the _attributes field.
1436         for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
1437                 std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator attr_it = _attributes.find(it->first);
1438                 if (attr_it == _attributes.end())
1439                 {
1440                         _attributes[it->first] = it->second;
1441                 }
1442                 else
1443                 {
1444                         *attr_it->second = *it->second;
1445                         delete it->second;
1446                 }
1447                 it->second = NULL;
1448         }
1449         delete _transaction;
1450         _transaction = NULL;
1451         return true;
1452 }
1453
1454 // Abort an attribute transaction; loads back the previous version of the object from disk
1455 bool DBObject::abortTransaction()
1456 {
1457         MutexLocker lock(_mutex);
1458
1459         if (_connection == NULL)
1460         {
1461                 ERROR_MSG("Object is not connected to the database.");
1462                 return false;
1463         }
1464
1465         // Forget the atributes that were set during the transaction.
1466         if (_transaction)
1467         {
1468                 for (std::map<CK_ATTRIBUTE_TYPE,OSAttribute*>::iterator it = _transaction->begin(); it!=_transaction->end(); ++it) {
1469                         delete it->second;
1470                         it->second = NULL;
1471                 }
1472                 delete _transaction;
1473                 _transaction = NULL;
1474         }
1475
1476         return _connection->rollbackTransaction();
1477 }
1478
1479 // Destroy the object; WARNING: pointers to the object become invalid after this call
1480 bool DBObject::destroyObject()
1481 {
1482         // NOTE: Do not lock _mutex, because _token will call us back and cause a deadlock.
1483         // There is no need to lock anyway as _token is a non-mutable pointer, so no race
1484         // conditions possible.
1485
1486         if (_token == NULL)
1487         {
1488                 ERROR_MSG("Cannot destroy an object that is not associated with a token");
1489                 return false;
1490         }
1491
1492         return _token->deleteObject(this);
1493 }