/* * Copyright (c) 2013 SURFnet bv * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /***************************************************************************** DBToken.cpp The token class; a token is stored in a directory containing a single database file. Each object is stored in multiple tables with every attribute base type stored in a different table. *****************************************************************************/ #include "config.h" #include "log.h" #include "OSAttributes.h" #include "OSAttribute.h" #include "OSPathSep.h" #include "cryptoki.h" #include "DBToken.h" #include "DBObject.h" #include "DB.h" #include "Directory.h" #include #include #include #include #include #include #include #include const char * const DBTOKEN_FILE = "sqlite3.db"; const long long DBTOKEN_OBJECT_TOKENINFO = 1; // Constructor for creating a new token. DBToken::DBToken(const std::string &baseDir, const std::string &tokenName, const ByteString &label, const ByteString &serial) : _connection(NULL), _tokenMutex(NULL) { std::string tokenDir = baseDir + OS_PATHSEP + tokenName; std::string tokenPath = tokenDir + OS_PATHSEP + DBTOKEN_FILE; // Refuse to open an already existing database. FILE *f = fopen(tokenPath.c_str(),"r"); if (f) { fclose(f); ERROR_MSG("Refusing to overwrite and existing database at \"%s\"", tokenPath.c_str()); return; } // First create the directory for the token, we expect basePath to already exist if (mkdir(tokenDir.c_str(), S_IFDIR | S_IRWXU)) { // Allow the directory to exists already. if (errno != EEXIST) { ERROR_MSG("Unable to create directory \"%s\"", tokenDir.c_str()); return; } } // Create _connection = DB::Connection::Create(tokenDir, DBTOKEN_FILE); if (_connection == NULL) { ERROR_MSG("Failed to create a database connection for \"%s\"", tokenPath.c_str()); return; } if (!_connection->connect()) { delete _connection; _connection = NULL; ERROR_MSG("Failed to connect to the database at \"%s\"", tokenPath.c_str()); // Now remove the token directory if (remove(tokenDir.c_str())) { ERROR_MSG("Failed to remove the token directory \"%s\"", tokenDir.c_str()); } return; } // Create a DBObject for the established connection to the database. DBObject tokenObject(_connection); // First create the tables that support storage of object attributes and then insert the object containing // the token info into the database. if (!tokenObject.createTables() || !tokenObject.insert() || tokenObject.objectId()!=DBTOKEN_OBJECT_TOKENINFO) { tokenObject.dropConnection(); _connection->close(); delete _connection; _connection = NULL; ERROR_MSG("Failed to create tables for storing objects in database at \"%s\"", tokenPath.c_str()); return; } // Set the initial attributes CK_ULONG flags = CKF_RNG | CKF_LOGIN_REQUIRED | // FIXME: check CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED; OSAttribute tokenLabel(label); OSAttribute tokenSerial(serial); OSAttribute tokenFlags(flags); if (!tokenObject.setAttribute(CKA_OS_TOKENLABEL, tokenLabel) || !tokenObject.setAttribute(CKA_OS_TOKENSERIAL, tokenSerial) || !tokenObject.setAttribute(CKA_OS_TOKENFLAGS, tokenFlags)) { _connection->close(); delete _connection; _connection = NULL; // Now remove the token file if (remove(tokenPath.c_str())) { ERROR_MSG("Failed to remove the token file at \"%s\"", tokenPath.c_str()); } // Now remove the token directory if (remove(tokenDir.c_str())) { ERROR_MSG("Failed to remove the token directory at \"%s\"", tokenDir.c_str()); } return; } _tokenMutex = MutexFactory::i()->getMutex(); // Success! } // Constructor for accessing an existing token. DBToken::DBToken(const std::string &baseDir, const std::string &tokenName) : _connection(NULL), _tokenMutex(NULL) { std::string tokenDir = baseDir + OS_PATHSEP + tokenName; std::string tokenPath = tokenDir + OS_PATHSEP + DBTOKEN_FILE; // Refuse to open an already existing database. FILE *f = fopen(tokenPath.c_str(),"r"); if (f == NULL) { ERROR_MSG("Refusing to open a non-existant database at \"%s\"", tokenPath.c_str()); return; } fclose(f); // Create a database connection. _connection = DB::Connection::Create(tokenDir, DBTOKEN_FILE); if (_connection == NULL) { ERROR_MSG("Failed to create a database connection for \"%s\"", tokenPath.c_str()); return; } if (!_connection->connect()) { delete _connection; _connection = NULL; ERROR_MSG("Failed to connect to the database at \"%s\"", tokenPath.c_str()); return; } // Find the DBObject for the established connection to the database. DBObject tokenObject(_connection); // First find the token obect that indicates the token is properly initialized. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { tokenObject.dropConnection(); _connection->close(); delete _connection; _connection = NULL; ERROR_MSG("Failed to open token object in the token database at \"%s\"", tokenPath.c_str()); return; } _tokenMutex = MutexFactory::i()->getMutex(); // Success! } DBToken *DBToken::createToken(const std::string basePath, const std::string tokenDir, const ByteString &label, const ByteString &serial) { Directory baseDir(basePath); if (!baseDir.isValid()) { return NULL; } // Create the token directory if (!baseDir.mkdir(tokenDir)) { return NULL; } DBToken *token = new DBToken(basePath, tokenDir, label, serial); if (!token->isValid()) { baseDir.rmdir(tokenDir); delete token; return NULL; } DEBUG_MSG("Created new token %s", tokenDir.c_str()); return token; } DBToken *DBToken::accessToken(const std::string &basePath, const std::string &tokenDir) { return new DBToken(basePath, tokenDir); } // Destructor DBToken::~DBToken() { if (_tokenMutex) { MutexFactory::i()->recycleMutex(_tokenMutex); _tokenMutex = NULL; } std::map cleanUp = _allObjects; _allObjects.clear(); for (std::map::iterator i = cleanUp.begin(); i != cleanUp.end(); ++i) { delete i->second; } if (_connection) { delete _connection; _connection = NULL; } } // Set the SO PIN bool DBToken::setSOPIN(const ByteString& soPINBlob) { if (_connection == NULL) return false; // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadWrite)) { ERROR_MSG("Unable to start a transaction for updating the SOPIN and TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } OSAttribute soPIN(soPINBlob); if (!tokenObject.setAttribute(CKA_OS_SOPIN, soPIN)) { ERROR_MSG("Error while setting SOPIN in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.attributeExists(CKA_OS_TOKENFLAGS)) { ERROR_MSG("Error while getting TOKENFLAGS from token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } // Retrieve flags from the database and reset flags related to tries and expiration of the SOPIN. CK_ULONG flags = tokenObject.getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue() & ~(CKF_SO_PIN_COUNT_LOW | CKF_SO_PIN_FINAL_TRY | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED); OSAttribute changedTokenFlags(flags); if (!tokenObject.setAttribute(CKA_OS_TOKENFLAGS, changedTokenFlags)) { ERROR_MSG("Error while setting TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.commitTransaction()) { ERROR_MSG("Error while committing SOPIN and TOKENFLAGS changes to token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } return true; } // Get the SO PIN bool DBToken::getSOPIN(ByteString& soPINBlob) { if (_connection == NULL) return false; // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadOnly)) { ERROR_MSG("Unable to start a transaction for getting the SOPIN from token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.attributeExists(CKA_OS_SOPIN)) { ERROR_MSG("Error while getting SOPIN from token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } tokenObject.commitTransaction(); soPINBlob = tokenObject.getAttribute(CKA_OS_SOPIN).getByteStringValue(); return true; } // Set the user PIN bool DBToken::setUserPIN(ByteString userPINBlob) { if (_connection == NULL) return false; // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadWrite)) { ERROR_MSG("Unable to start a transaction for updating the USERPIN and TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } OSAttribute userPIN(userPINBlob); if (!tokenObject.setAttribute(CKA_OS_USERPIN, userPIN)) { ERROR_MSG("Error while setting USERPIN in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.attributeExists(CKA_OS_TOKENFLAGS)) { ERROR_MSG("Error while getting TOKENFLAGS from token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } // Retrieve flags from the database and reset flags related to tries and expiration of the SOPIN. CK_ULONG flags = tokenObject.getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue() | (CKF_USER_PIN_INITIALIZED & ~(CKF_USER_PIN_COUNT_LOW | CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_LOCKED | CKF_USER_PIN_TO_BE_CHANGED)); OSAttribute changedTokenFlags(flags); if (!tokenObject.setAttribute(CKA_OS_TOKENFLAGS, changedTokenFlags)) { ERROR_MSG("Error while setting TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.commitTransaction()) { ERROR_MSG("Error while committing USERPIN and TOKENFLAGS changes to token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } return true; } // Get the user PIN bool DBToken::getUserPIN(ByteString& userPINBlob) { if (_connection == NULL) return false; // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadOnly)) { ERROR_MSG("Unable to start a transaction for getting the USERPIN from token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.attributeExists(CKA_OS_USERPIN)) { ERROR_MSG("Error while getting USERPIN from token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } tokenObject.commitTransaction(); userPINBlob = tokenObject.getAttribute(CKA_OS_USERPIN).getByteStringValue(); return true; } // Retrieve the token label bool DBToken::getTokenLabel(ByteString& label) { if (_connection == NULL) return false; // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadOnly)) { ERROR_MSG("Unable to start a transaction for getting the TOKENLABEL from token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.attributeExists(CKA_OS_TOKENLABEL)) { ERROR_MSG("Error while getting TOKENLABEL from token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } tokenObject.commitTransaction(); label = tokenObject.getAttribute(CKA_OS_TOKENLABEL).getByteStringValue(); return true; } // Retrieve the token serial bool DBToken::getTokenSerial(ByteString& serial) { if (_connection == NULL) return false; // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadOnly)) { ERROR_MSG("Unable to start a transaction for getting the TOKENSERIAL from token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.attributeExists(CKA_OS_TOKENSERIAL)) { ERROR_MSG("Error while getting TOKENSERIAL from token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } tokenObject.commitTransaction(); serial = tokenObject.getAttribute(CKA_OS_TOKENSERIAL).getByteStringValue(); return true; } // Get the token flags bool DBToken::getTokenFlags(CK_ULONG& flags) { if (_connection == NULL) return false; // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadOnly)) { ERROR_MSG("Unable to start a transaction for updating the SOPIN and TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.attributeExists(CKA_OS_TOKENFLAGS)) { ERROR_MSG("Error while getting TOKENFLAGS from token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } tokenObject.commitTransaction(); flags = tokenObject.getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue(); return true; } // Set the token flags bool DBToken::setTokenFlags(const CK_ULONG flags) { if (_connection == NULL) return false; // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadWrite)) { ERROR_MSG("Unable to start a transaction for setting the TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } OSAttribute tokenFlags(flags); if (!tokenObject.setAttribute(CKA_OS_TOKENFLAGS, tokenFlags)) { ERROR_MSG("Error while setting TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.commitTransaction()) { ERROR_MSG("Error while committing TOKENFLAGS changes to token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } return true; } // Retrieve objects std::set DBToken::getObjects() { std::set objects; getObjects(objects); return objects; } void DBToken::getObjects(std::set &objects) { if (_connection == NULL) return; if (!_connection->beginTransactionRO()) return; DB::Statement statement = _connection->prepare("select id from object limit -1 offset 1"); DB::Result result = _connection->perform(statement); if (result.isValid()) { do { long long objectId = result.getLongLong(1); { MutexLocker lock(_tokenMutex); std::map::iterator it = _allObjects.find(objectId); if (it == _allObjects.end()) { DBObject *object = new DBObject(_connection, this, objectId); _allObjects[objectId] = object; objects.insert(object); } else { objects.insert(it->second); } } } while (result.nextRow()); } _connection->endTransactionRO(); } // Create a new object OSObject *DBToken::createObject() { if (_connection == NULL) return NULL; DBObject *newObject = new DBObject(_connection, this); if (newObject == NULL) { ERROR_MSG("Failed to create an object: out of memory"); return NULL; } if (!newObject->startTransaction(DBObject::ReadWrite)) { delete newObject; ERROR_MSG("Unable to start a transaction in token database at \"%s\"", _connection->dbpath().c_str()); return NULL; } if (!newObject->insert()) { newObject->abortTransaction(); delete newObject; ERROR_MSG("Unable to insert an object into token database at \"%s\"", _connection->dbpath().c_str()); return NULL; } if (!newObject->isValid()) { newObject->abortTransaction(); delete newObject; ERROR_MSG("Object that was inserted in not valid"); return NULL; } if (!newObject->commitTransaction()) { newObject->abortTransaction(); delete newObject; ERROR_MSG("Unable to commit a created object to token database at \"%s\"", _connection->dbpath().c_str()); return NULL; } // Now add the new object to the list of existing objects. { MutexLocker lock(_tokenMutex); _allObjects[newObject->objectId()] = newObject; } return newObject; } bool DBToken::deleteObject(OSObject *object) { if (_connection == NULL) return false; if (object == NULL) { ERROR_MSG("Object passed in as a parameter is NULL"); return false; } if (!object->startTransaction(DBObject::ReadWrite)) { ERROR_MSG("Unable to start a transaction for deleting an object in token database at \"%s\"", _connection->dbpath().c_str()); return false; } if (!static_cast(object)->remove()) { ERROR_MSG("Error while deleting an existing object from the token database at \"%s\"", _connection->dbpath().c_str()); object->abortTransaction(); return false; } if (!object->commitTransaction()) { ERROR_MSG("Error while committing the deletion of an existing object in token database at \"%s\"", _connection->dbpath().c_str()); object->abortTransaction(); return false; } return true; } // Checks if the token is consistent bool DBToken::isValid() { return _connection != NULL && _connection->tableExists("object"); } // Invalidate the token (for instance if it is deleted) void DBToken::invalidate() { } // Delete the token. bool DBToken::clearToken() { if (_connection == NULL) return false; std::string tokenDir = _connection->dbdir(); std::string tokenPath = _connection->dbpath(); if (!DBObject(_connection).dropTables()) { ERROR_MSG("Failed to drop all tables in the token database at \"%s\"", tokenPath.c_str()); return false; } _connection->close(); delete _connection; _connection = NULL; // Remove all files from the token directory, even ones not placed there by us. Directory dir(tokenDir); std::vector tokenFiles = dir.getFiles(); for (std::vector::iterator i = tokenFiles.begin(); i != tokenFiles.end(); i++) { if (!dir.remove(*i)) { ERROR_MSG("Failed to remove \"%s\" from token directory \"%s\"", i->c_str(), tokenDir.c_str()); return false; } } // Now remove the token directory if (!dir.rmdir("")) { ERROR_MSG("Failed to remove the token directory \"%s\"", tokenDir.c_str()); return false; } DEBUG_MSG("Token instance %s was succesfully cleared", tokenDir.c_str()); return true; } // Reset the token bool DBToken::resetToken(const ByteString& label) { if (_connection == NULL) return false; std::string tokenDir = _connection->dbdir(); // Clean up std::set cleanUp = getObjects(); for (std::set::iterator i = cleanUp.begin(); i != cleanUp.end(); i++) { if (!deleteObject(*i)) { ERROR_MSG("Unable to delete all objects in token database at \"%s\"", _connection->dbpath().c_str()); return false; } } // Create a DBObject for the established connection to the token object in the database DBObject tokenObject(_connection); if (!tokenObject.startTransaction(DBObject::ReadWrite)) { ERROR_MSG("Unable to start a transaction for setting the TOKENLABEL in token database at \"%s\"", _connection->dbpath().c_str()); return false; } // First find the token object in the database. if (!tokenObject.find(DBTOKEN_OBJECT_TOKENINFO)) { ERROR_MSG("Token object not found in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (tokenObject.attributeExists(CKA_OS_USERPIN)) { if (!tokenObject.deleteAttribute(CKA_OS_USERPIN)) { ERROR_MSG("Error while deleting USERPIN in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } } if (!tokenObject.attributeExists(CKA_OS_TOKENFLAGS)) { ERROR_MSG("Error while getting TOKENFLAGS from token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } // Retrieve flags from the database and reset flags related to tries and expiration of the SOPIN. CK_ULONG flags = tokenObject.getAttribute(CKA_OS_TOKENFLAGS).getUnsignedLongValue() & ~(CKF_USER_PIN_INITIALIZED | CKF_USER_PIN_COUNT_LOW | CKF_USER_PIN_FINAL_TRY | CKF_USER_PIN_LOCKED | CKF_USER_PIN_TO_BE_CHANGED); OSAttribute changedTokenFlags(flags); if (!tokenObject.setAttribute(CKA_OS_TOKENFLAGS, changedTokenFlags)) { ERROR_MSG("Error while setting TOKENFLAGS in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } OSAttribute tokenLabel(label); if (!tokenObject.setAttribute(CKA_OS_TOKENLABEL, tokenLabel)) { ERROR_MSG("Error while setting TOKENLABEL in token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } if (!tokenObject.commitTransaction()) { ERROR_MSG("Error while committing TOKENLABEL changes to token database at \"%s\"", _connection->dbpath().c_str()); tokenObject.abortTransaction(); return false; } DEBUG_MSG("Token instance %s was succesfully reset", tokenDir.c_str()); return true; }