From 0c89b3ccba7c9b7332ab67ae1936aff51ca62367 Mon Sep 17 00:00:00 2001 From: NingSun Date: Thu, 8 Feb 2018 08:34:03 -0800 Subject: Initial sshsm project structure Issue-ID: AAF-94 Change-Id: I5e82fff418e7567b161acf9b98013a9b85ffc5b4 Signed-off-by: NingSun --- SoftHSMv2/src/lib/object_store/DBToken.cpp | 874 +++++++++++++++++++++++++++++ 1 file changed, 874 insertions(+) create mode 100644 SoftHSMv2/src/lib/object_store/DBToken.cpp (limited to 'SoftHSMv2/src/lib/object_store/DBToken.cpp') diff --git a/SoftHSMv2/src/lib/object_store/DBToken.cpp b/SoftHSMv2/src/lib/object_store/DBToken.cpp new file mode 100644 index 0000000..e734372 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/DBToken.cpp @@ -0,0 +1,874 @@ +/* + * 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; +} -- cgit 1.2.3-korg