예제 #1
0
	bool CryptoManager::decrypt(ISC_STATUS* sv, Ods::pag* page)
	{
		// Code calling us is not ready to process exceptions correctly
		// Therefore use old (status vector based) method
		try
		{
			if (page->pag_flags & Ods::crypted_page)
			{
				if (!cryptPlugin)
				{
					// We are invoked from shared cache manager, i.e. no valid attachment in tdbb
					// Therefore create system temporary attachment like in crypt thread to be able to work with locks
					UserId user;
					user.usr_user_name = "(Crypt plugin loader)";

					Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb);
					RefPtr<SysAttachment> jAtt(new SysAttachment(attachment));
					attachment->att_interface = jAtt;
					attachment->att_filename = dbb.dbb_filename;
					attachment->att_user = &user;

					BackgroundContextHolder tdbb(&dbb, attachment, sv, FB_FUNCTION);

					// Lock crypt state
					takeStateLock(tdbb);

					Header hdr(tdbb, LCK_read);
					crypt = hdr->hdr_flags & Ods::hdr_encrypted;
					process = hdr->hdr_flags & Ods::hdr_crypt_process;

					if (crypt || process)
					{
						loadPlugin(hdr->hdr_crypt_plugin);
					}

					if (!cryptPlugin)
					{
						(Arg::Gds(isc_decrypt_error)).raise();
						return false;
					}
				}

				LocalStatus status;
				cryptPlugin->decrypt(&status, dbb.dbb_page_size - sizeof(Ods::pag), &page[1], &page[1]);
				if (!status.isSuccess())
				{
					memcpy(sv, status.get(), sizeof(ISC_STATUS_ARRAY));
					return false;
				}
			}

			return true;
		}
		catch (const Exception& ex)
		{
			ex.stuff_exception(sv);
		}
		return false;
	}
예제 #2
0
	void CryptoManager::blockingAstChangeCryptState()
	{
		AsyncContextHolder tdbb(&dbb, FB_FUNCTION);

		fb_assert(stateLock);
		LCK_release(tdbb, stateLock);
		needLock = true;
	}
예제 #3
0
	int Database::blocking_ast_sweep(void* ast_object)
	{
		Database* dbb = static_cast<Database*>(ast_object);
		AsyncContextHolder tdbb(dbb, FB_FUNCTION);

		if ((dbb->dbb_flags & DBB_sweep_starting) && !(dbb->dbb_flags & DBB_sweep_in_progress))
		{
			dbb->dbb_flags &= ~DBB_sweep_starting;
			LCK_release(tdbb, dbb->dbb_sweep_lock);
		}

		return 0;
	}
예제 #4
0
int GlobalRWLock::blocking_ast_cached_lock(void* ast_object)
{
	GlobalRWLock* globalRWLock = static_cast<GlobalRWLock*>(ast_object);

	try
	{
		Firebird::MutexLockGuard counterGuard(globalRWLock->counterMutex);
		if (!globalRWLock->cachedLock)
			return 0;

		Database* dbb = globalRWLock->cachedLock->lck_dbb;
		AstContextHolder tdbb(dbb);

		if (globalRWLock->cachedLock)
			globalRWLock->blockingAstHandler(tdbb);
	}
	catch (const Firebird::Exception&)
	{} // no-op

	return 0;
}
예제 #5
0
	void CryptoManager::cryptThread()
	{
		ISC_STATUS_ARRAY status_vector;

		try
		{
			// Try to take crypt mutex
			// If can't take that mutex - nothing to do, cryptThread already runs in our process
			MutexEnsureUnlock guard(cryptThreadMtx, FB_FUNCTION);
			if (!guard.tryEnter())
			{
				return;
			}

			// establish context
			UserId user;
			user.usr_user_name = "(Crypt thread)";

			Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb);
			RefPtr<SysAttachment> jAtt(new SysAttachment(attachment));
			attachment->att_interface = jAtt;
			attachment->att_filename = dbb.dbb_filename;
			attachment->att_user = &user;

			BackgroundContextHolder tdbb(&dbb, attachment, status_vector, FB_FUNCTION);
			tdbb->tdbb_quantum = SWEEP_QUANTUM;

			ULONG lastPage = getLastPage(tdbb);
			ULONG runpage = 1;
			Stack<ULONG> pages;

			// Take exclusive threadLock
			// If can't take that lock - nothing to do, cryptThread already runs somewhere
			if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT))
			{
				return;
			}

			bool lckRelease = false;

			try
			{
				do
				{
					// Check is there some job to do
					while ((runpage = currentPage.exchangeAdd(+1)) < lastPage)
					{
						// forced terminate
						if (down)
						{
							break;
						}

						// nbackup state check
						if (dbb.dbb_backup_manager && dbb.dbb_backup_manager->getState() != nbak_state_normal)
						{
							if (currentPage.exchangeAdd(-1) >= lastPage)
							{
								// currentPage was set to last page by thread, closing database
								break;
							}
							THD_sleep(100);
							continue;
						}

						// scheduling
						if (--tdbb->tdbb_quantum < 0)
						{
							JRD_reschedule(tdbb, SWEEP_QUANTUM, true);
						}

						// writing page to disk will change it's crypt status in usual way
						WIN window(DB_PAGE_SPACE, runpage);
						Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_write, pag_undefined);
						if (page && page->pag_type <= pag_max &&
							(bool(page->pag_flags & Ods::crypted_page) != crypt) &&
							Ods::pag_crypt_page[page->pag_type])
						{
							CCH_MARK(tdbb, &window);
							pages.push(runpage);
						}
						CCH_RELEASE_TAIL(tdbb, &window);

						// sometimes save currentPage into DB header
						++runpage;
						if ((runpage & 0x3FF) == 0)
						{
							writeDbHeader(tdbb, runpage, pages);
						}
					}

					// At this moment of time all pages with number < lastpage
					// are guaranteed to change crypt state. Check for added pages.
					lastPage = getLastPage(tdbb);

					// forced terminate
					if (down)
					{
						break;
					}
				} while (runpage < lastPage);

				// Finalize crypt
				if (!down)
				{
					writeDbHeader(tdbb, 0, pages);
				}

				// Release exclusive lock on StartCryptThread
				lckRelease = true;
				LCK_release(tdbb, threadLock);
			}
			catch (const Exception&)
			{
				try
				{
					if (!lckRelease)
					{
						// try to save current state of crypt thread
						if (!down)
						{
							writeDbHeader(tdbb, runpage, pages);
						}

						// Release exclusive lock on StartCryptThread
						LCK_release(tdbb, threadLock);
					}
				}
				catch (const Exception&)
				{ }

				throw;
			}
		}
		catch (const Exception& ex)
		{
			// Error during context creation - we can't even release lock
			iscLogException("Crypt thread:", ex);
		}
	}