From 8d466e052107d928409af2d30291c847cc157b97 Mon Sep 17 00:00:00 2001 From: Rahul Roshan Kachchap Date: Tue, 17 Oct 2023 23:15:02 -0400 Subject: [PATCH] Resizing Luks Volume Added functionality to resize the luks volume. Added functionality to write json config file with the used attributes to create the Luks volume. luks volume resizing procedure: - umount the filesystem - increase the size of vault file - check the filesystem for errors - resize luks volume - check the filesystem for errors - resize the filesystem - re-mount the filesystem Depends on: https://review.opendev.org/c/starlingx/integ/+/894535 Test Plan: PASSED: build-pkgs -c -p luks-fs-mgr PASSED: build-image PASSED: AIO-SX bootstrap PASSED: binary available at /usr/local/sbin/ PASSED: systemd unit file available at /lib/systemd/system PASSED: luks_config.json avaiable at /etc/luks-fs-mgr.d/ PASSED: resizing luks volume on host restart PASSED: created_luks.json file generated after successful luks volume creation PASSED: resizing luks volume with size <=256M PASSED: resizing luks volume with size >256M PASSED: created_luks.json file adjusted with new size of luks volume after resizing activity. Story: 2010872 Task: 48878 Change-Id: I4285bc8da5bf7d9516ba736fd78a85ebf761f835 Signed-off-by: Rahul Roshan Kachchap --- .../luks/src/encryption/luks-fs-mgr.cpp | 773 ++++++++++++++---- 1 file changed, 609 insertions(+), 164 deletions(-) diff --git a/filesystem/luks/src/encryption/luks-fs-mgr.cpp b/filesystem/luks/src/encryption/luks-fs-mgr.cpp index bc1b0694d..eacf535f1 100644 --- a/filesystem/luks/src/encryption/luks-fs-mgr.cpp +++ b/filesystem/luks/src/encryption/luks-fs-mgr.cpp @@ -11,13 +11,14 @@ * */ -#include -#include -#include #include #include #include +#include +#include +#include #include +#include #include "PassphraseGenerator.h" using namespace std; @@ -26,6 +27,7 @@ using namespace std; const char *configFile = "/etc/luks-fs-mgr.d/luks_config.json"; const char *defaultDirectoryPath = "/var/luks/stx"; const char *defaultMountPath = "/var/luks/stx/luks_fs"; +const char *createdConfigFile = "/etc/luks-fs-mgr.d/created_luks.json"; // Define a struct to hold configuration variables struct LuksConfig { @@ -35,6 +37,15 @@ struct LuksConfig { const char *mountPath; }; +// Define a struct to hold configuration variables for created volume +struct CreatedLuksConfig { + const char *vaultFile; + const char *vaultSize; + const char *volName; + const char *mountPath; + const char *passphraseType; +}; + /* *********************************************************************** * * Name : log @@ -49,6 +60,24 @@ void log(const string &message, int logType) { closelog(); } +// A helper function for parsing passphraseType when ConfigType +// is CreatedLuksConfig +template +typename enable_if::value, bool>::type +parsePassphraseType(ConfigType &config, json_object *passPhraseObj) { + config.passphraseType = json_object_get_string(passPhraseObj); + return true; +} + +// A helper function for parsing passphraseType when ConfigType +// is LuksConfig +template +typename enable_if::value, bool>::type +parsePassphraseType(ConfigType &, json_object *) { + // No-op when ConfigType is not CreatedLuksConfig + return true; +} + /* *********************************************************************** * * Name : parseJSONConfig @@ -59,8 +88,10 @@ void log(const string &message, int logType) { * * ************************************************************************/ -bool parseJSONConfig(const char *configFile, LuksConfig &luksConfig, +template +bool parseJSONConfig(const char *configFile, ConfigType &config, json_object **jsonConfig) { + log("Parsing " + string(configFile), LOG_INFO); bool valid = true; *jsonConfig = json_object_from_file(configFile); if (*jsonConfig == nullptr) { @@ -91,6 +122,8 @@ bool parseJSONConfig(const char *configFile, LuksConfig &luksConfig, json_object *vaultSizeObj = json_object_object_get(volumeObj, "VAULT_SIZE"); json_object *volNameObj = json_object_object_get(volumeObj, "VOL_NAME"); json_object *mountPathObj = json_object_object_get(volumeObj, "MOUNT_PATH"); + json_object *passPhraseObj = json_object_object_get(volumeObj, + "PASSPHRASE_TYPE"); if (!vaultFileObj || json_object_get_type(vaultFileObj) != json_type_string) { @@ -118,10 +151,11 @@ bool parseJSONConfig(const char *configFile, LuksConfig &luksConfig, return false; } - luksConfig.vaultFile = json_object_get_string(vaultFileObj); - luksConfig.vaultSize = json_object_get_string(vaultSizeObj); - luksConfig.volName = json_object_get_string(volNameObj); - luksConfig.mountPath = json_object_get_string(mountPathObj); + config.vaultFile = json_object_get_string(vaultFileObj); + config.vaultSize = json_object_get_string(vaultSizeObj); + config.volName = json_object_get_string(volNameObj); + config.mountPath = json_object_get_string(mountPathObj); + parsePassphraseType(config, passPhraseObj); return true; } @@ -141,7 +175,8 @@ bool createDefaultDirectory(const char *defaultDirectoryPath) { // Default directory already exists return true; } else { - string mkdirCommand = "mkdir -p " + string(defaultDirectoryPath); + string mkdirCommand = "/usr/bin/mkdir -p " + + string(defaultDirectoryPath); int status = system(mkdirCommand.c_str()); // An exit status of zero indicates success, and a nonzero value // indicates failure. @@ -176,7 +211,7 @@ bool createDirectory(const char *directoryPath) { size_t lastSlashPos = vaultDirectory.rfind('/'); if (lastSlashPos != string::npos) { string directoryPath = vaultDirectory.substr(0, lastSlashPos); - string mkdirCommand = "mkdir -p " + directoryPath; + string mkdirCommand = "/usr/bin/mkdir -p " + directoryPath; int status = system(mkdirCommand.c_str()); // An exit status of zero indicates success, and a nonzero value // indicates failure. @@ -194,24 +229,17 @@ bool createDirectory(const char *directoryPath) { /* *********************************************************************** * - * Name : createVaultFile + * Name : checkVaultSize * - * Description: This function is responsible for creating a LUKS vault file - * with a specified size and a random key using the dd and - * cryptsetup utilities. + * Description: This function is responsible for checking the vaultSize * * Note: If the size is not specified or is invalid, it sets a default * size of 256 megabytes. * * ************************************************************************/ -bool createVaultFile(const string &modifiedVaultFile, const char *vaultSize) { - // Create the directory path if it doesn't exist - if (!createDirectory(modifiedVaultFile.c_str())) { - // Directory creation failed - return false; - } - +int checkVaultSize(const char *vaultSize) { + int size = 256; // Convert const char* to string string vaultSizeStr = vaultSize; // Find the first non-numeric character @@ -222,7 +250,7 @@ bool createVaultFile(const string &modifiedVaultFile, const char *vaultSize) { string suffix = vaultSizeStr.substr(firstNonNumeric); // Convert the extracted string to an integer - int size = stoi(sizeStr); + size = stoi(sizeStr); // Determine the multiplier based on the suffix if (suffix == "M") { @@ -248,41 +276,45 @@ bool createVaultFile(const string &modifiedVaultFile, const char *vaultSize) { // Set to the minimum default size size = 256; } - string command = "dd if=/dev/urandom of=" + string(modifiedVaultFile) + - " bs=1M count=" + to_string(size); - int status = system(command.c_str()); - // An exit status of zero indicates success, and a nonzero value - // indicates failure. - if (status == 0) { - // Command executed successfully - return true; - } else { - log("Error creating LUKS vault image file: " + - string(modifiedVaultFile), LOG_ERR); - log("Command failed with return status: " + - to_string(status), LOG_ERR); - return false; - } } else { log("Invalid vault file size format: No size type found." - " Using default size of 256MB", LOG_INFO); - string command = "dd if=/dev/urandom of=" + string(modifiedVaultFile) + - " bs=1M count=256"; - int status = system(command.c_str()); - // An exit status of zero indicates success, and a nonzero value - // indicates failure. - if (status == 0) { - // Command executed successfully - return true; - } else { - // Command failed - log("Error creating LUKS vault image file: " + - string(modifiedVaultFile), LOG_ERR); - log("Command failed with return status:" + - to_string(status), LOG_ERR); - return false; - } - } + " Using default size of 256MB", LOG_INFO); + } + return size; +} + +/* *********************************************************************** + * + * Name : createVaultFile + * + * Description: This function is responsible for creating a LUKS vault file + * with a specified size and a random key using the dd and + * cryptsetup utilities. + * + * ************************************************************************/ + +bool createVaultFile(const string &modifiedVaultFile, int vaultSize) { + // Create the directory path if it doesn't exist + if (!createDirectory(modifiedVaultFile.c_str())) { + // Directory creation failed + return false; + } + + string command = "dd if=/dev/urandom of=" + string(modifiedVaultFile) + + " bs=1M count=" + to_string(vaultSize); + int status = system(command.c_str()); + // An exit status of zero indicates success, and a nonzero value + // indicates failure. + if (status == 0) { + // Command executed successfully + return true; + } else { + log("Error creating LUKS vault image file: " + + string(modifiedVaultFile), LOG_ERR); + log("Command failed with return status: " + + to_string(status), LOG_ERR); + return false; + } } /* *********************************************************************** @@ -297,6 +329,7 @@ bool createVaultFile(const string &modifiedVaultFile, const char *vaultSize) { bool setupLUKSEncryption(const string &modifiedVaultFile, const string &passphrase) { + log("Encrypting LUKS Volume", LOG_INFO); string command = "echo -n \"" + string(passphrase) + "\" | cryptsetup luksFormat " + string(modifiedVaultFile) + " -"; @@ -331,6 +364,7 @@ bool setupLUKSEncryption(const string &modifiedVaultFile, bool openLUKSVolume(const string &modifiedVaultFile, const char *volName, const string &passphrase) { + log("Unsealing LUKS Volume", LOG_INFO); string command = "echo -n \"" + string(passphrase) + "\" | cryptsetup luksOpen " + string(modifiedVaultFile) + " " + string(volName); @@ -363,6 +397,7 @@ bool openLUKSVolume(const string &modifiedVaultFile, const char *volName, * ************************************************************************/ bool createFilesystem(const char *volName) { + log("Creating EXT4 Filesystem", LOG_INFO); string mkfs_command = "mkfs.ext4 /dev/mapper/" + string(volName); // Execute the mkfs command and capture the return status int status = system(mkfs_command.c_str()); @@ -410,12 +445,13 @@ bool isMountPathValid(const char *mountPath, const char *defaultDirectoryPath) { bool mountFilesystem(const char *volName, const char *mountPath, const char *defaultDirectoryPath) { + log("Mounting Filesystem", LOG_INFO); if (!isMountPathValid(mountPath, defaultDirectoryPath)) { log("Mount path is not valid, using default mount path.", LOG_INFO); mountPath = defaultMountPath; // Use default mount path } - string mkdir_command = "mkdir -p " + string(mountPath); + string mkdir_command = "/usr/bin/mkdir -p " + string(mountPath); int status_check = system(mkdir_command.c_str()); // An exit status of zero indicates success, and a nonzero value // indicates failure. @@ -425,7 +461,8 @@ bool mountFilesystem(const char *volName, const char *mountPath, return false; } - string mount_command = "mount /dev/mapper/" + string(volName) + " " + + string mount_command = "/usr/bin/mount /dev/mapper/" + + string(volName) + " " + string(mountPath); int status = system(mount_command.c_str()); // On success, zero is returned. On error, -1 is returned, and @@ -442,57 +479,291 @@ bool mountFilesystem(const char *volName, const char *mountPath, } } +/* *********************************************************************** + * + * Name : writeJSONToFile + * + * Description: This function writes a provided JSON object to a specified file + * It handles file opening, JSON-to-string conversion, + * error detection, and file closure, returning true on successful + * write and false on failure. + * + * ************************************************************************/ + +bool writeJSONToFile(const char *filePath, json_object *jsonObj) { + log("Creating json config file", LOG_INFO); + FILE *file = fopen(filePath, "w"); + if (file == nullptr) { + log("Error opening file for writing JSON.", LOG_ERR); + return false; + } + + // Convert JSON object to a string + const char *jsonStr = json_object_to_json_string_ext(jsonObj, + JSON_C_TO_STRING_PRETTY); + if (jsonStr == nullptr) { + log("Error converting JSON to string.", LOG_ERR); + fclose(file); + return false; + } + + // Write the JSON string to the file + if (fprintf(file, "%s\n", jsonStr) < 0) { + log("Error writing JSON to file.", LOG_ERR); + fclose(file); + return false; + } + + fclose(file); + return true; +} + +/* *********************************************************************** + * + * Name : getPassPhraseType + * + * Description: This function simply returns "HWID" + * indicating the type of passphrase as "Hardware Identifier." + * + * ************************************************************************/ + +string getPassPhraseType() { + return "HWID"; +} + + +/* *********************************************************************** + * + * Name : passPhraseType + * + * Description: This function simply returns passPhraseType + * indicating the type of passphrase as "Hardware Identifier." + * + * ************************************************************************/ + +PassphraseMechanism passPhraseType() { + return HWID_Firmware; +} + +/* *********************************************************************** + * + * Name : unmountFilesystem + * + * Description: This function is responsible to umount filesystem at + * specified 'mountPath'. + * + * ************************************************************************/ + +bool unmountFilesystem(const char* mountPath) { + log("Unmounting Filesystem", LOG_INFO); + // Check if the filesystem is already unmounted + string check_mount_command = "/usr/bin/mount | grep " + string(mountPath); + if (system(check_mount_command.c_str()) == 0) { + string umount_command = "/usr/bin/umount " + string(mountPath); + if (system(umount_command.c_str()) != 0) { + log("Error unmounting the filesystem.", LOG_ERR); + return false; + } + } else { + // The filesystem is already unmounted, no action needed + log("Filesystem is already unmounted.", LOG_INFO); + } + return true; +} + +/* *********************************************************************** + * + * Name : increaseVaultSize + * + * Description: This function is resposible to increase the size of vaultfile + * to a given defaultSize in megabytes. + * + * ************************************************************************/ + +bool increaseVaultSize(const char* vaultFile, int defaultSize) { + log("Increasing Vault file size", LOG_INFO); + string increase_size_command = "/usr/bin/truncate -s " + + to_string(defaultSize) + "M " + string(vaultFile); + if (system(increase_size_command.c_str()) != 0) { + log("Error increasing the size of the vault file.", LOG_ERR); + return false; + } + return true; +} + +/* *********************************************************************** + * + * Name : resizeLUKSVolume + * + * Description: This function resizes a LUKS-encrypted + * volume specified by volName using the provided passphrase + * + * ************************************************************************/ + +bool resizeLUKSVolume(const char* volName, const char* passphrase) { + log("Resizing LUKS Volume", LOG_INFO); + string resize_command = "echo -n \"" + string(passphrase) + + "\" | /usr/sbin/cryptsetup resize " + string(volName) + " -"; + if (system(resize_command.c_str()) != 0) { + log("Error resizing the LUKS volume.", LOG_ERR); + return false; + } + return true; +} + +/* *********************************************************************** + * + * Name : checkFilesystem + * + * Description: This function performs a filesystem check using e2fsck on a + * specified volume (volName). + * + * ************************************************************************/ + +bool checkFilesystem(const char* volName) { + log("Checking Filesystem for errors", LOG_INFO); + string e2fsck_command = "/usr/sbin/e2fsck -fy /dev/mapper/" + + string(volName); + int status = system(e2fsck_command.c_str()); + if ((status == 0) || (status == 2048)) { + // Command executed successfully + return true; + } else { + log("Error checking the filesystem.", LOG_ERR); + return true; + } +} + +/* *********************************************************************** + * + * Name : resizeFilesystem + * + * Description: This function resizes the filesystem on a specified + * volume (volName). + * + * ************************************************************************/ + +bool resizeFilesystem(const char* volName) { + log("Resizing Filesystem", LOG_INFO); + string resize_fs_command = "/usr/sbin/resize2fs /dev/mapper/" + + string(volName); + if (system(resize_fs_command.c_str()) != 0) { + log("Error resizing the filesystem.", LOG_ERR); + return false; + } + return true; +} + +/* *********************************************************************** + * + * Name : remountFilesystem + * + * Description: This function is used to remount a previously + * unmounted filesystem onto a specified mountPath + * + * ************************************************************************/ + +bool remountFilesystem(const char* volName, const char* mountPath) { + log("Re-mounting Filesystem", LOG_INFO); + string mount_command = "/usr/bin/mount /dev/mapper/" + + string(volName) + " " + string(mountPath); + if (system(mount_command.c_str()) != 0) { + log("Error mounting the filesystem back.", LOG_ERR); + return false; + } + return true; +} + +/* *********************************************************************** + * + * Name : resizeVault + * + * Description: This function function orchestrates the process of resizing + * a LUKS-encrypted vault file and its associated filesystem. + * It performs a sequence of steps, including unmounting the + * filesystem, increasing the vault size, checking the + * filesystem, resizing the LUKS volume, checking the filesystem + * again, resizing the filesystem, and remounting the filesystem. + * + * ************************************************************************/ + +bool resizeVault(const char* vaultFile, + int defaultSize, + const char* volName, + const char* mountPath, + const char* passphrase) { + if (unmountFilesystem(mountPath) && + increaseVaultSize(vaultFile, defaultSize) && + checkFilesystem(volName) && + resizeLUKSVolume(volName, passphrase) && + checkFilesystem(volName) && + resizeFilesystem(volName) && + remountFilesystem(volName, mountPath)) { + log("Resize successful for LUKS volume", LOG_INFO); + return true; + } else { + log("Resize failed for LUKS Volume", LOG_ERR); + return false; + } +} + int main() { - json_object *jsonConfig; + int rc = 0; LuksConfig luksConfig; + CreatedLuksConfig createdLuksConfig; string passphrase; - PassphraseMechanism selectedMechanism = HWID_Firmware; + // create a JSON object to store the used attributes. + json_object *jsonConfig; + json_object *usedAttributes = json_object_new_object(); + json_object *luksvolumesArray = json_object_new_array(); + json_object *attributesObj = json_object_new_object(); + + // Getting Passphrase from passphraseGenerator + PassphraseMechanism selectedMechanism = passPhraseType(); auto passphraseGenerator = PassphraseGeneratorFactory::createPassphraseGenerator(selectedMechanism); bool ret = passphraseGenerator->generatePassphrase(passphrase); + // Validating if passphrase is empty if (passphrase.empty() || ret == false) { log("Passphrase generation failed or" " returned an empty passphrase.", LOG_ERR); - json_object_put(jsonConfig); - return 1; + rc = 1; + goto cleanup; } - // Create default directory for the service to create FS and mount - if (!createDefaultDirectory(defaultDirectoryPath)) { - json_object_put(jsonConfig); - return 1; - } - - // Parse JSON configuration and extract volume attributes + // Parse default configuration and extract volume attributes if (!parseJSONConfig(configFile, luksConfig, &jsonConfig)) { - // Release the JSON object memory - json_object_put(jsonConfig); - return 1; - } - // Logging the successfully parsed attributes - string log_message = "Vault File: " + string(luksConfig.vaultFile) + - ", Vault Size: " + string(luksConfig.vaultSize) + - ", Volume Name: " + string(luksConfig.volName) + - ", Mount Path: " + string(luksConfig.mountPath); - log(log_message, LOG_INFO); - - // Create a new string to hold the path+file - string modifiedVaultFile = luksConfig.vaultFile; - // Check if directory path is provided in vaultFile - size_t lastSlashPos = modifiedVaultFile.rfind('/'); - if (lastSlashPos == string::npos) { - // No directory path provided, use default directory - modifiedVaultFile = "/var/luks/stx/" + modifiedVaultFile; + rc = 1; + goto cleanup; } - // Check if the vault file exists - if ((access(luksConfig.vaultFile, F_OK) == 0) || - (access(modifiedVaultFile.c_str(), F_OK) == 0)) { - // The vault file exists, proceed to unseal - string statusCommand = "sudo cryptsetup status " + - string(luksConfig.volName) + " 2>/dev/null"; + if (access(createdConfigFile, F_OK) == 0) { + // Parse the createdConfigfile and extract volume attributes + if (!parseJSONConfig(createdConfigFile, createdLuksConfig, + &jsonConfig)) { + rc = 1; + goto cleanup; + } else { + log("created_luks.json exists", LOG_INFO); + } + // Logging the successfully parsed attributes of created_luks.json + string log_message = "Vault File: " + + string(createdLuksConfig.vaultFile) + + ", Vault Size: " + + string(createdLuksConfig.vaultSize) + + ", Volume Name: " + + string(createdLuksConfig.volName) + + ", Mount Path: " + + string(createdLuksConfig.mountPath) + + ", Passphrase Type: " + + string(createdLuksConfig.passphraseType); + log(log_message, LOG_INFO); + + // Resizing logic begin here + string statusCommand = "cryptsetup status " + + string(createdLuksConfig.volName) + " 2>/dev/null"; int status = system(statusCommand.c_str()); // Cryptsetup returns 0 on success and a non-zero value on error. // Return codes on failure: @@ -503,93 +774,267 @@ int main() { log("LUKS device is already open", LOG_INFO); } else { log("LUKS device is not open. Try opening", LOG_INFO); - if (!openLUKSVolume(modifiedVaultFile.c_str(), luksConfig.volName, + if (!openLUKSVolume(createdLuksConfig.vaultFile, + createdLuksConfig.volName, passphrase.c_str())) { - json_object_put(jsonConfig); - return 1; + rc = 1; + goto cleanup; } log("LUKS device is successfully opened", LOG_INFO); } - // Check if the mount path exists - if (access(luksConfig.mountPath, F_OK) == 0) { - string mount_command = "mountpoint -q " + string(luksConfig.mountPath); - int mountpoint_status = system(mount_command.c_str()); - // mountpoint has the following exit status values: - // 0: success; the directory is a mountpoint, - // or device is block device - // 1: failure; incorrect invocation, permissions or system error - // 32: failure; the directory is not a mountpoint, - // or device is not a block device on - if (mountpoint_status != 0) { - // Mount path directory is not mount point, proceed to mount it + int defaultsize = 0; + int createdsize = 0; + defaultsize = checkVaultSize(luksConfig.vaultSize); + createdsize = checkVaultSize(createdLuksConfig.vaultSize); + if (defaultsize > createdsize) { + log("Resizing the vault file.", LOG_INFO); + if (resizeVault(createdLuksConfig.vaultFile, + defaultsize, + createdLuksConfig.volName, + createdLuksConfig.mountPath, + passphrase.c_str())) { + // Assigning values to attributes used to write + // created_luks.json + string sizeStr = to_string(defaultsize); + luksConfig.vaultSize = (sizeStr + "M").c_str(); + json_object_object_add(attributesObj, "PASSPHRASE_TYPE", + json_object_new_string(createdLuksConfig.passphraseType)); + json_object_object_add(attributesObj, "VAULT_FILE", + json_object_new_string(createdLuksConfig.vaultFile)); + json_object_object_add(attributesObj, "VAULT_SIZE", + json_object_new_string(luksConfig.vaultSize)); + json_object_object_add(attributesObj, "VOL_NAME", + json_object_new_string(createdLuksConfig.volName)); + json_object_object_add(attributesObj, "MOUNT_PATH", + json_object_new_string(createdLuksConfig.mountPath)); + + json_object_array_add(luksvolumesArray, attributesObj); + json_object_object_add(usedAttributes, "luksvolumes", + luksvolumesArray); + + if (!writeJSONToFile(createdConfigFile, usedAttributes)) { + log("Error writing JSON file.", LOG_ERR); + rc = 1; + goto cleanup; + } + } else { + rc = 1; + goto cleanup; + } + } else { + log("No resizing required", LOG_INFO); + // No Reszing to handle, start the service normally + // Check if the mount path exists + if (access(luksConfig.mountPath, F_OK) == 0) { + string mount_command = "/usr/bin/mountpoint -q " + + string(luksConfig.mountPath); + int mountpoint_status = system(mount_command.c_str()); + // mountpoint has the following exit status values: + // 0: success; the directory is a mountpoint, + // or device is block device + // 1: failure; incorrect invocation, permissions or system error + // 32: failure; the directory is not a mountpoint, + // or device is not a block device on + if (mountpoint_status != 0) { + // Mount path directory is not mount point, + // proceed to mount it + if (!mountFilesystem(luksConfig.volName, + luksConfig.mountPath, + defaultDirectoryPath)) { + rc = 1; + goto cleanup; + } + log("Encrypted vault is mounted.", LOG_INFO); + } else { + log("Encrypted vault is already mounted.", LOG_INFO); + } + } else { + // Mount path does not exist, create filesystem and then mount + if (!createFilesystem(luksConfig.volName)) { + log("Error creating filesystem", LOG_ERR); + rc = 1; + goto cleanup; + } if (!mountFilesystem(luksConfig.volName, luksConfig.mountPath, - defaultDirectoryPath)) { - json_object_put(jsonConfig); - return 1; + defaultDirectoryPath)) { + rc = 1; + goto cleanup; + } + log("Encrypted vault is mounted.", LOG_INFO); + } + } + rc = 0; + goto cleanup; + } else { + // Execute the below code when service start during first boot + // Create default directory for the service to create FS and mount + if (!createDefaultDirectory(defaultDirectoryPath)) { + rc = 1; + goto cleanup; + } + + string log_message = "Vault File: " + string(luksConfig.vaultFile) + + ", Vault Size: " + string(luksConfig.vaultSize) + + ", Volume Name: " + string(luksConfig.volName) + + ", Mount Path: " + string(luksConfig.mountPath); + log(log_message, LOG_INFO); + + // Create a new string to hold the created values + string modifiedVaultFile = luksConfig.vaultFile; + string mountPath = luksConfig.mountPath; + // Check if directory path is provided in vaultFile + size_t lastSlashPos = modifiedVaultFile.rfind('/'); + if (lastSlashPos == string::npos) { + // No directory path provided, use default directory + modifiedVaultFile = "/var/luks/stx/" + modifiedVaultFile; + } + + // Check if the vault file exists + if ((access(luksConfig.vaultFile, F_OK) == 0) || + (access(modifiedVaultFile.c_str(), F_OK) == 0)) { + // The vault file exists, proceed to unseal + string statusCommand = "cryptsetup status " + + string(luksConfig.volName) + " 2>/dev/null"; + int status = system(statusCommand.c_str()); + // Cryptsetup returns 0 on success and a non-zero value on error. + // Return codes on failure: + // 1 wrong parameters, 2 no permission (badpassphrase), + // 3 out of memory, 4 wrong device specified, + // 5 device already exists or device is busy. + if (status == 0) { + log("LUKS device is already open", LOG_INFO); + } else { + log("LUKS device is not open. Try opening", LOG_INFO); + if (!openLUKSVolume(modifiedVaultFile.c_str(), + luksConfig.volName, passphrase.c_str())) { + rc = 1; + goto cleanup; + } + log("LUKS device is successfully opened", LOG_INFO); + } + // Check if the mount path exists + if (access(luksConfig.mountPath, F_OK) == 0) { + string mount_command = "/usr/bin/mountpoint -q " + + string(luksConfig.mountPath); + int mountpoint_status = system(mount_command.c_str()); + // mountpoint has the following exit status values: + // 0: success; the directory is a mountpoint, + // or device is block device + // 1: failure; incorrect invocation, permissions or system error + // 32: failure; the directory is not a mountpoint, + // or device is not a block device on + if (mountpoint_status != 0) { + // Mount path directory is not mount point, + // proceed to mount it + if (!mountFilesystem(luksConfig.volName, + luksConfig.mountPath, defaultDirectoryPath)) { + rc = 1; + goto cleanup; + } + log("Encrypted vault is mounted.", LOG_INFO); + } else { + log("Encrypted vault is already mounted.", LOG_INFO); + } + } else { + // Mount path does not exist, create filesystem and then mount + if (!createFilesystem(luksConfig.volName)) { + log("Error creating filesystem", LOG_ERR); + rc = 1; + goto cleanup; + } + if (!mountFilesystem(luksConfig.volName, luksConfig.mountPath, + defaultDirectoryPath)) { + rc = 1; + goto cleanup; } log("Encrypted vault is mounted.", LOG_INFO); - } else { - log("Encrypted vault is already mounted.", LOG_INFO); - } - } else { - // Mount path does not exist, create filesystem and then mount - if (!createFilesystem(luksConfig.volName)) { - log("Error creating filesystem", LOG_ERR); - json_object_put(jsonConfig); - return 1; - } - if (!mountFilesystem(luksConfig.volName, luksConfig.mountPath, - defaultDirectoryPath)) { - json_object_put(jsonConfig); - return 1; - } - log("Encrypted vault is mounted.", LOG_INFO); - } - } else { - // The vault file does not exist, create it - // Create the necessary directories if they don't exist - log("The vault image file does not exist, creating one", LOG_INFO); - if (!createVaultFile(modifiedVaultFile.c_str(), - luksConfig.vaultSize)) { - log("Error creating LUKS vault image file", LOG_ERR); - json_object_put(jsonConfig); - return 1; - } + } + } else { + // The vault file does not exist, create it + // Create the necessary directories if they don't exist + log("The vault image file does not exist, creating one", LOG_INFO); + int size = checkVaultSize(luksConfig.vaultSize); - // Set up LUKS encryption - if (!setupLUKSEncryption(modifiedVaultFile.c_str(), + if (!createVaultFile(modifiedVaultFile.c_str(), size)) { + log("Error creating LUKS vault image file", LOG_ERR); + rc = 1; + goto cleanup; + } + + // Set up LUKS encryption + if (!setupLUKSEncryption(modifiedVaultFile.c_str(), passphrase.c_str())) { - log("Error setting up LUKS encryption", LOG_ERR); - json_object_put(jsonConfig); - return 1; - } + log("Error setting up LUKS encryption", LOG_ERR); + rc = 1; + goto cleanup; + } - // Open LUKS Volume - if (!openLUKSVolume(modifiedVaultFile.c_str(), luksConfig.volName, + // Open LUKS Volume + if (!openLUKSVolume(modifiedVaultFile.c_str(), luksConfig.volName, passphrase.c_str())) { - log("Error opening LUKS volume", LOG_ERR); - json_object_put(jsonConfig); - return 1; - } + log("Error opening LUKS volume", LOG_ERR); + rc = 1; + goto cleanup; + } - // Create filesystem - if (!createFilesystem(luksConfig.volName)) { - log("Error creating filesystem", LOG_ERR); - json_object_put(jsonConfig); - return 1; - } + // Create filesystem + if (!createFilesystem(luksConfig.volName)) { + log("Error creating filesystem", LOG_ERR); + rc = 1; + goto cleanup; + } - // Mount filesystem - if (!mountFilesystem(luksConfig.volName, luksConfig.mountPath, + // Mount filesystem + if (!mountFilesystem(luksConfig.volName, luksConfig.mountPath, defaultDirectoryPath)) { - json_object_put(jsonConfig); - return 1; + rc = 1; + goto cleanup; + } + log("Encrypted vault is set up and mounted.", LOG_INFO); } - log("Encrypted vault is set up and mounted.", LOG_INFO); + + if (!isMountPathValid(luksConfig.mountPath, defaultDirectoryPath)) { + log("Mount path is not valid, using default mount path.", LOG_INFO); + mountPath = defaultMountPath; // Use default mount path + } + + // Assigning values to attributes used to write created_luks.json + int size = checkVaultSize(luksConfig.vaultSize); + string sizeStr = to_string(size); + string ppType = getPassPhraseType(); + createdLuksConfig.vaultSize = (sizeStr + "M").c_str(); + createdLuksConfig.vaultFile = modifiedVaultFile.c_str(); + createdLuksConfig.volName = luksConfig.volName; + createdLuksConfig.mountPath = mountPath.c_str(); + createdLuksConfig.passphraseType = ppType.c_str(); + + json_object_object_add(attributesObj, "PASSPHRASE_TYPE", + json_object_new_string(createdLuksConfig.passphraseType)); + json_object_object_add(attributesObj, "VAULT_FILE", + json_object_new_string(createdLuksConfig.vaultFile)); + json_object_object_add(attributesObj, "VAULT_SIZE", + json_object_new_string(createdLuksConfig.vaultSize)); + json_object_object_add(attributesObj, "VOL_NAME", + json_object_new_string(createdLuksConfig.volName)); + json_object_object_add(attributesObj, "MOUNT_PATH", + json_object_new_string(createdLuksConfig.mountPath)); + + json_object_array_add(luksvolumesArray, attributesObj); + json_object_object_add(usedAttributes, "luksvolumes", luksvolumesArray); + + if (!writeJSONToFile(createdConfigFile, usedAttributes)) { + log("Error writing JSON file.", LOG_ERR); + rc = 1; + goto cleanup; + } + rc = 0; + goto cleanup; } - // Clean up JSON object - json_object_put(jsonConfig); - - return 0; + cleanup: + json_object_put(jsonConfig); + json_object_put(usedAttributes); + json_object_put(luksvolumesArray); + json_object_put(attributesObj); + return (rc); }