void PwDatabaseFacade::unlock(const QString &dbFilePath, const QString &password, const QString &keyFilePath) { // delete any leftovers clear(); // Load DB file to memory QFile dbFile (dbFilePath); if (!dbFile.open(QIODevice::ReadOnly)) { LOG("Cannot open DB file: '%s' Error: %d. Message: %s", dbFilePath.toUtf8().constData(), dbFile.error(), dbFile.errorString().toUtf8().constData()); emit fileOpenError(tr("Cannot open database file", "An error message shown when the file is not available or cannot be opened."), dbFile.errorString()); return; } LOG("DB file open ok"); QByteArray dbFileData = dbFile.readAll(); if (dbFile.error() != QFile::NoError) { // There was a problem reading the file emit fileOpenError(tr("Error loading database file", "An error message shown when the file cannot be loaded/read."), dbFile.errorString()); dbFile.close(); return; } dbFile.close(); if (dbFileData.isEmpty()) { // The file is ok, but empty emit dbUnlockError(tr("Database file is empty", "An error message"), PwDatabase::DB_FILE_EMPTY); return; } // Load key file to memory QByteArray keyFileData; if (!loadKeyFile(keyFilePath, keyFileData)) return; // Get suitable DB processor (KeePass1 vs KeePass2) db = createDatabaseInstance(dbFileData); if (!db) { emit dbUnlockError(tr("Unknown database format", "An error message for unrecognized/unsupported database file structure."), PwDatabase::UNKNOWN_DB_FORMAT); return; } // let DB instance know the original file path db->setDatabaseFilePath(dbFilePath); // Setup signal forwarding connectDatabaseSignals(); // Do the actual unlocking/loading db->load(dbFileData, password, keyFileData); Util::safeClear(dbFileData); Util::safeClear(keyFileData); }
/* Extracts the file named filename with size fileSize from archive. The file * pointer in archive must be pointing to the beginning of the body of the file * to extract. Prints a message to stderr if the extraction cannot be done. * Moves the file pointer to the end of the body of the file extracted. * Returns -1 if the archive is corrupted, else returns 0. */ char extractFile(FILE* archive, char* filename, unsigned int fileSize) { int currentLen = 0; char* currentStr = NULL; while(currentLen < strlen(filename)) { // count chars in filename up to the next slash, and include the slash currentLen += strcspn(&(filename[currentLen]), "/") + 1; currentStr = malloc(sizeof(char) * (currentLen + 1)); strncpy(currentStr, filename, currentLen); currentStr[currentLen] = '\0'; if(currentStr[currentLen - 1] == '/') // if it's a directory { ensureDirExists(currentStr); } else // it's a regular file { FILE* extractedFile = fopen(filename, "wb+"); if(extractedFile) { for(unsigned int i = 0; i < fileSize; i++) { int c = fgetc(archive); if(c == EOF) { return -1; } else { fputc(c, extractedFile); } } fclose(extractedFile); } else { fileOpenError(filename); } } } if(currentStr) free(currentStr); return 0; }
/** * Loads given key file to the given buffer. No processing, just load or emit error signals. * Empty file path is ok. * Returns true if successful, otherwise emits fileOpenError signal and returns false. */ bool PwDatabaseFacade::loadKeyFile(const QString& keyFilePath, QByteArray& keyFileData) const { if (!keyFilePath.isEmpty()) { QFile keyFile (keyFilePath); if (!keyFile.open(QIODevice::ReadOnly)) { LOG("Cannot open key file: '%s' Error: %d. Message: %s", keyFilePath.toUtf8().constData(), keyFile.error(), keyFile.errorString().toUtf8().constData()); emit fileOpenError(tr("Cannot open key file", "An error message shown when the file is not available or cannot be read. See 'key file' in the supplied thesaurus."), keyFile.errorString()); return false; } keyFileData = keyFile.readAll(); LOG("Key file is: %s", (keyFileData.isEmpty() ? "empty" : "non-empty")); keyFile.close(); } else { LOG("Key file not provided"); } return true; }
FAR_RTRN farAdd(char* archiveName, char** fileArgs, unsigned char numFileArgs) { FILE* oldArchive; // the archive file named archiveName FILE* tempArchive; // the temp archive with name TEMP_ARCHIVE_NAME FILE* fileToAdd = NULL; // a file with name from fileArgs to add to the // archive unsigned int newNumFiles = 0; // the total number of files in the NEW // archive unsigned int oldNumFiles; // the total number of files in the OLD archive charBuffer* filename; // the name of a file being copied from oldArchive unsigned int fileSize; // the size of the current file in oldArchive struct stat fileStat; // holds data from any stat() calls DIR* dir; // pointer to a directory-type file with name from fileArgs // check for no-args if(numFileArgs == 0) { return SUCCESS; } /* eliminates invalid args (and prints errors) and expands directories to * include their contents */ fileList* validArgs = fileListNew(fileArgs, numFileArgs); oldArchive = fopen(archiveName, "rb+"); // read the number of files in oldArchive if(oldArchive) { if(fread(&oldNumFiles, sizeof(unsigned int), 1, oldArchive) < 1) { fclose(oldArchive); fileListDelete(validArgs); return corruptedArchiveError(); } } else { oldNumFiles = 0; } // open the temp archive and check for error tempArchive = fopen(TEMP_ARCHIVE_NAME, "wb+"); if(!tempArchive) { fclose(oldArchive); fileListDelete(validArgs); return openTempArchiveError(); } // write numFiles simply to reserve the uint space; // it will be overwritten at the end fwrite(&newNumFiles, sizeof(unsigned int), 1, tempArchive); filename = charBufferNew(); // copy oldArchive to tempArchive, not copying any entries that appear in // validArgs for(unsigned int i = 0; i < oldNumFiles; i++) { // get filename and fileSize if(getFileName(oldArchive, filename) || fread(&fileSize, sizeof(unsigned int), 1, oldArchive) < 1) { fclose(oldArchive); fclose(tempArchive); unlink(TEMP_ARCHIVE_NAME); charBufferDelete(filename); fileListDelete(validArgs); return corruptedArchiveError(); } // check if filename appears in validArgs char shouldCopy = (isDuplicateFile(filename->str, validArgs->names, validArgs->numNames) < 0); // write filename and file size if(shouldCopy) { fwrite(filename->str, sizeof(char), filename->len, tempArchive); fwrite(&fileSize, sizeof(unsigned int), 1, tempArchive); newNumFiles++; } // read file contents and write to tempArchive if shouldCopy for(unsigned int j = 0; j < fileSize; j++) { int c = fgetc(oldArchive); if(c == EOF) { fclose(oldArchive); fclose(tempArchive); unlink(TEMP_ARCHIVE_NAME); charBufferDelete(filename); fileListDelete(validArgs); return corruptedArchiveError(); } else if(shouldCopy) { fputc(c, tempArchive); } } } // append new files to the end of tempArchive for(unsigned int i = 0; i < validArgs->numNames; i++) { if(isDuplicateFile(validArgs->names[i], validArgs->names, i) >= 0) { continue; } // call stat on the file if(stat(validArgs->names[i], &fileStat) < 0) { fileOpenError(validArgs->names[i]); continue; } // check if directory dir = opendir(validArgs->names[i]); if(dir) { // write directory name to archive fwrite(validArgs->names[i], sizeof(char), strlen(validArgs->names[i]) + 1, tempArchive); // write directory size (zero) to archive fileSize = 0; fwrite(&fileSize, sizeof(unsigned int), 1, tempArchive); newNumFiles++; closedir(dir); } else { // add this regular file to tempArchive fileToAdd = fopen(validArgs->names[i], "rb"); fileSize = fileStat.st_size; writeFileToArchive(fileToAdd, validArgs->names[i], fileSize, tempArchive); fclose(fileToAdd); // update numFiles newNumFiles++; } } finalizeArchive(oldArchive, archiveName, tempArchive, newNumFiles); // clean-up charBufferDelete(filename); fileListDelete(validArgs); return SUCCESS; }