Ejemplo n.º 1
0
/*
** Rollback all database files.
*/
void sqlite3RollbackAll(sqlite3 *db){
  int i;
  int inTrans = 0;
  assert( sqlite3_mutex_held(db->mutex) );
  sqlite3MallocEnterBenignBlock(1);                 /* Enter benign region */
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].pBt ){
      if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
        inTrans = 1;
      }
      sqlite3BtreeRollback(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3VtabRollback(db);
  sqlite3MallocLeaveBenignBlock();                 /* Leave benign region */

  if( db->flags&SQLITE_InternChanges ){
    sqlite3ExpirePreparedStatements(db);
    sqlite3ResetInternalSchema(db, 0);
  }

  /* If one has been configured, invoke the rollback-hook callback */
  if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
    db->xRollbackCallback(db->pRollbackArg);
  }
}
Ejemplo n.º 2
0
/*
** Rollback all database files.
*/
void sqlite3RollbackAll(sqlite3 *db){
  int i;
  int inTrans = 0;
  assert( sqlite3_mutex_held(db->mutex) );
  sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 1);
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].pBt ){
      if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
        inTrans = 1;
      }
      sqlite3BtreeRollback(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3VtabRollback(db);
  sqlite3FaultBenign(SQLITE_FAULTINJECTOR_MALLOC, 0);

  if( db->flags&SQLITE_InternChanges ){
    sqlite3ExpirePreparedStatements(db);
    sqlite3ResetInternalSchema(db, 0);
  }

  /* If one has been configured, invoke the rollback-hook callback */
  if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
    db->xRollbackCallback(db->pRollbackArg);
  }
}
Ejemplo n.º 3
0
/*
** Rollback all database files.
*/
void sqlite3RollbackAll(sqlite3 *db){
  int i;
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].pBt ){
      sqlite3BtreeRollback(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  sqlite3ResetInternalSchema(db, 0);
}
Ejemplo n.º 4
0
int btreeVacuum(Btree *p, char **pzErrMsg) {
	sqlite3 *db;
	int rc;
	u_int32_t truncatedPages;

	db = p->db;

	/* Return directly if vacuum is on progress */
	if (p->inVacuum)
		return SQLITE_OK;

	/*
	 * We're going to do updates in this transaction at the Berkeley DB
	 * Core level (i.e., call DB->compact), but we start it read-only at
	 * the SQL level to avoid overhead from checkpoint-on-commit.
	 */
	if ((rc = sqlite3BtreeBeginTrans(p, 0)) != SQLITE_OK) {
		sqlite3SetString(pzErrMsg, db,
		    "failed to begin a vacuum transaction");
		return rc;
	}

	p->inVacuum = 1;

	truncatedPages = 0;
	/* Go through all tables */
	do {
		rc = btreeIncrVacuum(p, &truncatedPages);
	} while (rc == SQLITE_OK);
	p->needVacuum = 0;

	if (rc != SQLITE_DONE) {
		sqlite3SetString(pzErrMsg, db,
		    "error during vacuum, rolled back");
		(void)sqlite3BtreeRollback(p);
	} else if ((rc = sqlite3BtreeCommit(p)) != SQLITE_OK) {
		sqlite3SetString(pzErrMsg, db,
		    "failed to commit the vacuum transaction");
	}

	p->inVacuum = 0;

	return rc;
}
Ejemplo n.º 5
0
/*
** Rollback all database files.
*/
void sqlite3RollbackAll(sqlite3 *db){
  int i;
  int inTrans = 0;
  for(i=0; i<db->nDb; i++){
    if( db->aDb[i].pBt ){
      if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){
        inTrans = 1;
      }
      sqlite3BtreeRollback(db->aDb[i].pBt);
      db->aDb[i].inTrans = 0;
    }
  }
  if( db->flags&SQLITE_InternChanges ){
    sqlite3ResetInternalSchema(db, 0);
  }

  /* If one has been configured, invoke the rollback-hook callback */
  if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
    db->xRollbackCallback(db->pRollbackArg);
  }
}
Ejemplo n.º 6
0
/*
** Usage:   btree_rollback ID
**
** Rollback changes
*/
static int btree_rollback(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  const char **argv      /* Text of each argument */
){
  Btree *pBt;
  int rc;
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
       " ID\"", 0);
    return TCL_ERROR;
  }
  pBt = sqlite3TestTextToPtr(argv[1]);
  sqlite3BtreeEnter(pBt);
  rc = sqlite3BtreeRollback(pBt);
  sqlite3BtreeLeave(pBt);
  if( rc!=SQLITE_OK ){
    Tcl_AppendResult(interp, errorName(rc), 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}
Ejemplo n.º 7
0
/* sqlite3_rekey_v2
** Given a database, this will reencrypt the database using a new key.
** There is only one possible modes of operation - to encrypt a database
** that is already encrpyted. If the database is not already encrypted
** this should do nothing
** The proposed logic for this function follows:
** 1. Determine if the database is already encryptped
** 2. If there is NOT already a key present do nothing
** 3. If there is a key present, re-encrypt the database with the new key
*/
int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
  CODEC_TRACE(("sqlite3_rekey_v2: entered db=%p zDb=%s pKey=%s, nKey=%d\n", db, zDb, (char *)pKey, nKey));
  if(db && pKey && nKey) {
    int db_index = sqlcipher_find_db_index(db, zDb);
    struct Db *pDb = &db->aDb[db_index];
    CODEC_TRACE(("sqlite3_rekey_v2: database pDb=%p db_index:%d\n", pDb, db_index));
    if(pDb->pBt) {
      codec_ctx *ctx;
      int rc, page_count;
      Pgno pgno;
      PgHdr *page;
      Pager *pPager = pDb->pBt->pBt->pPager;

      sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
     
      if(ctx == NULL) { 
        /* there was no codec attached to this database, so this should do nothing! */ 
        CODEC_TRACE(("sqlite3_rekey_v2: no codec attached to db, exiting\n"));
        return SQLITE_OK;
      }

      sqlite3_mutex_enter(db->mutex);

      codec_set_pass_key(db, db_index, pKey, nKey, CIPHER_WRITE_CTX);
    
      /* do stuff here to rewrite the database 
      ** 1. Create a transaction on the database
      ** 2. Iterate through each page, reading it and then writing it.
      ** 3. If that goes ok then commit and put ctx->rekey into ctx->key
      **    note: don't deallocate rekey since it may be used in a subsequent iteration 
      */
      rc = sqlite3BtreeBeginTrans(pDb->pBt, 1); /* begin write transaction */
      sqlite3PagerPagecount(pPager, &page_count);
      for(pgno = 1; rc == SQLITE_OK && pgno <= (unsigned int)page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */
        if(!sqlite3pager_is_mj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */
          rc = sqlite3PagerGet(pPager, pgno, &page);
          if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
            rc = sqlite3PagerWrite(page);
            if(rc == SQLITE_OK) {
              sqlite3PagerUnref(page);
            } else {
             CODEC_TRACE(("sqlite3_rekey_v2: error %d occurred writing page %d\n", rc, pgno));  
            }
          } else {
             CODEC_TRACE(("sqlite3_rekey_v2: error %d occurred getting page %d\n", rc, pgno));  
          }
        } 
      }

      /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
      if(rc == SQLITE_OK) { 
        CODEC_TRACE(("sqlite3_rekey_v2: committing\n"));
        rc = sqlite3BtreeCommit(pDb->pBt); 
        sqlcipher_codec_key_copy(ctx, CIPHER_WRITE_CTX);
      } else {
        CODEC_TRACE(("sqlite3_rekey_v2: rollback\n"));
        sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK);
      }

      sqlite3_mutex_leave(db->mutex);
    }
    return SQLITE_OK;
  }
  return SQLITE_ERROR;
}
Ejemplo n.º 8
0
int sqlite3_rekey_v2(sqlite3 *db, const char *zDbName, const void *zKey, int nKey)
{
  /* Changes the encryption key for an existing database. */
  int dbIndex = dbFindIndex(db, zDbName);
  int rc = SQLITE_ERROR;
  Btree* pbt = db->aDb[dbIndex].pBt;
  Pager* pPager = sqlite3BtreePager(pbt);
  Codec* codec = (Codec*) mySqlite3PagerGetCodec(pPager);

  if ((zKey == NULL || nKey == 0) && (codec == NULL || !CodecIsEncrypted(codec)))
  {
    /*
    // Database not encrypted and key not specified
    // therefore do nothing
	*/
    return SQLITE_OK;
  }

  if (codec == NULL || !CodecIsEncrypted(codec))
  {
    /*
    // Database not encrypted, but key specified
    // therefore encrypt database
	*/
    if (codec == NULL)
    {
      codec = (Codec*) sqlite3_malloc(sizeof(Codec));
	    CodecInit(codec);
    }

    CodecSetIsEncrypted(codec, 1);
    CodecSetHasReadKey(codec, 0); /* Original database is not encrypted */
    CodecSetHasWriteKey(codec, 1);
    CodecGenerateWriteKey(codec, (char*) zKey, nKey);
    CodecSetBtree(codec, pbt);
#if (SQLITE_VERSION_NUMBER >= 3006016)
    mySqlite3PagerSetCodec(pPager, sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, codec);
#else
#if (SQLITE_VERSION_NUMBER >= 3003014)
    sqlite3PagerSetCodec(pPager, sqlite3Codec, codec);
#else
    sqlite3pager_set_codec(pPager, sqlite3Codec, codec);
#endif
    db->aDb[dbIndex].pAux = codec;
    db->aDb[dbIndex].xFreeAux = sqlite3CodecFree;
#endif
  }
  else if (zKey == NULL || nKey == 0)
  {
    /*
    // Database encrypted, but key not specified
    // therefore decrypt database
    // Keep read key, drop write key
	*/
    CodecSetHasWriteKey(codec, 0);
  }
  else
  {
    /*
    // Database encrypted and key specified
    // therefore re-encrypt database with new key
    // Keep read key, change write key to new key
	*/
    CodecGenerateWriteKey(codec, (char*) zKey, nKey);
    CodecSetHasWriteKey(codec, 1);
  }

  sqlite3_mutex_enter(db->mutex);

  /* Start transaction */
  rc = sqlite3BtreeBeginTrans(pbt, 1);
  if (!rc)
  {
    int pageSize = sqlite3BtreeGetPageSize(pbt);
    Pgno nSkip = WX_PAGER_MJ_PGNO(pageSize);
#if (SQLITE_VERSION_NUMBER >= 3003014)
    DbPage *pPage;
#else
    void *pPage;
#endif
    Pgno n;
    /* Rewrite all pages using the new encryption key (if specified) */
#if (SQLITE_VERSION_NUMBER >= 3007001)
    Pgno nPage;
    int nPageCount = -1;
    sqlite3PagerPagecount(pPager, &nPageCount);
    nPage = nPageCount;
#elif (SQLITE_VERSION_NUMBER >= 3006000)
    int nPageCount = -1;
    int rc = sqlite3PagerPagecount(pPager, &nPageCount);
    Pgno nPage = (Pgno) nPageCount;
#elif (SQLITE_VERSION_NUMBER >= 3003014)
    Pgno nPage = sqlite3PagerPagecount(pPager);
#else
    Pgno nPage = sqlite3pager_pagecount(pPager);
#endif

    for (n = 1; rc == SQLITE_OK && n <= nPage; n++)
    {
      if (n == nSkip) continue;
#if (SQLITE_VERSION_NUMBER >= 3003014)
      rc = sqlite3PagerGet(pPager, n, &pPage);
#else
      rc = sqlite3pager_get(pPager, n, &pPage);
#endif
      if (!rc)
      {
#if (SQLITE_VERSION_NUMBER >= 3003014)
        rc = sqlite3PagerWrite(pPage);
        sqlite3PagerUnref(pPage);
#else
        rc = sqlite3pager_write(pPage);
        sqlite3pager_unref(pPage);
#endif
      }
    }
  }

  if (rc == SQLITE_OK)
  {
    /* Commit transaction if all pages could be rewritten */
    rc = sqlite3BtreeCommit(pbt);
  }
  if (rc != SQLITE_OK)
  {
    /* Rollback in case of error */
#if (SQLITE_VERSION_NUMBER >= 3007011)
    sqlite3BtreeRollback(pbt, SQLITE_OK);
#else
    sqlite3BtreeRollback(pbt);
#endif
  }

  sqlite3_mutex_leave(db->mutex);

  if (rc == SQLITE_OK)
  {
    /* Set read key equal to write key if necessary */
    if (CodecHasWriteKey(codec))
    {
      CodecCopyKey(codec, 0);
      CodecSetHasReadKey(codec, 1);
    }
    else
    {
      CodecSetIsEncrypted(codec, 0);
    }
  }
  else
  {
    /* Restore write key if necessary */
    if (CodecHasReadKey(codec))
    {
      CodecCopyKey(codec, 1);
    }
    else
    {
      CodecSetIsEncrypted(codec, 0);
    }
  }

  if (!CodecIsEncrypted(codec))
  {
    /* Remove codec for unencrypted database */
#if (SQLITE_VERSION_NUMBER >= 3006016)
    mySqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL);
#else
#if (SQLITE_VERSION_NUMBER >= 3003014)
    sqlite3PagerSetCodec(pPager, NULL, NULL);
#else
    sqlite3pager_set_codec(pPager, NULL, NULL);
#endif
    db->aDb[dbIndex].pAux = NULL;
    db->aDb[dbIndex].xFreeAux = NULL;
    sqlite3CodecFree(codec);
#endif
  }
  return rc;
}
Ejemplo n.º 9
0
int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey)
{
    BOTANSQLITE_TRACE("sqlite3_rekey");
    // Changes the encryption key for an existing database.
    int rc = SQLITE_ERROR;
    Btree *pbt = db->aDb[0].pBt;
    Pager *pPager = sqlite3BtreePager(pbt);
    void *pCodec = sqlite3PagerGetCodec(pPager);

    if ((!zKey || nKey <= 0) && !pCodec)
    {
        // Database not encrypted and key not specified. Do nothing
        return SQLITE_OK;
    }

    if (!pCodec)
    {
        // Database not encrypted, but key specified. Encrypt database
        pCodec = InitializeNewCodec(db);
        assert(nKey >= 0);
        SetWriteKey(pCodec, (const char*) zKey, (size_t) nKey);
        
        if (HandleError(pCodec))
        {
            DeleteCodec(pCodec);
            return SQLITE_ERROR;
        }

        sqlite3PagerSetCodec(pPager, Codec, CodecSizeChange, PagerFreeCodec, pCodec);
    }
    else if (!zKey || nKey <= 0)
    {
        // Database encrypted, but key not specified. Decrypt database
        // Keep read key, drop write key
        DropWriteKey(pCodec);
    }
    else
    {
        // Database encrypted and key specified. Re-encrypt database with new key
        // Keep read key, change write key to new key
        assert(nKey >= 0);
        SetWriteKey(pCodec, (const char*) zKey, (size_t) nKey);
        if (HandleError(pCodec)) return SQLITE_ERROR;
    }

    // Start transaction
    rc = sqlite3BtreeBeginTrans(pbt, 1);
    if (rc == SQLITE_OK)
    {
        // Rewrite all pages using the new encryption key (if specified)
        int nPageCount = -1;
        sqlite3PagerPagecount(pPager, &nPageCount);
        Pgno nPage = (Pgno) nPageCount;

        Pgno nSkip = PAGER_MJ_PGNO(pPager);
        DbPage *pPage;

        Pgno n;
        for (n = 1; rc == SQLITE_OK && n <= nPage; n++)
        {
            if (n == nSkip) continue;

            rc = sqlite3PagerGet(pPager, n, &pPage, 0);

            if (rc == SQLITE_OK)
            {
                rc = sqlite3PagerWrite(pPage);
                sqlite3PagerUnref(pPage);
            }
            else
            {
                sqlite3ErrorWithMsg(db, SQLITE_ERROR, "%s", "Error while rekeying database page. Transaction Canceled.");
            }
        }
    }
    else
    {
        sqlite3ErrorWithMsg(db, SQLITE_ERROR, "%s", "Error beginning rekey transaction. Make sure that the current encryption key is correct.");
    }

    if (rc == SQLITE_OK)
    {
        // All good, commit
        rc = sqlite3BtreeCommit(pbt);

        if (rc == SQLITE_OK)
        {
            //Database rekeyed and committed successfully, update read key
            if (HasWriteKey(pCodec))
            {
                SetReadIsWrite(pCodec);
            }
            else //No write key == no longer encrypted
            {
                sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL); 
            }
        }
        else
        {
            //FIXME: can't trigger this, not sure if rollback is needed, reference implementation didn't rollback
            sqlite3ErrorWithMsg(db, SQLITE_ERROR, "%s", "Could not commit rekey transaction.");
        }
    }
    else
    {
        // Rollback, rekey failed
        sqlite3BtreeRollback(pbt, SQLITE_ERROR, 0);

        // go back to read key
        if (HasReadKey(pCodec))
        {
            SetWriteIsRead(pCodec);
        }
        else //Database wasn't encrypted to start with
        {
            sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL); 
        }
    }

    return rc;
}
Ejemplo n.º 10
0
// Changes the encryption key for an existing database.
int sqlite3_rekey(sqlite3 *db, const unsigned char *pKey, int nKeySize)
{
  Btree *pbt = db->aDb[0].pBt;
  Pager *p = sqlite3BtreePager(pbt);
  LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)sqlite3pager_get_codecarg(p);
  HCRYPTKEY hKey = DeriveKey(pKey, nKeySize);
  int rc = SQLITE_ERROR;

  if (hKey == MAXDWORD)
  {
    sqlite3Error(db, rc, SQLITECRYPTERROR_PROVIDER);
    return rc;
  }

  if (!pBlock && !hKey) return SQLITE_OK; // Wasn't encrypted to begin with

  // To rekey a database, we change the writekey for the pager.  The readkey remains
  // the same
  if (!pBlock) // Encrypt an unencrypted database
  {
    pBlock = CreateCryptBlock(hKey, p, -1, NULL);
    if (!pBlock)
      return SQLITE_NOMEM;

    pBlock->hReadKey = 0; // Original database is not encrypted
    sqlite3PagerSetCodec(sqlite3BtreePager(pbt), sqlite3Codec, sqlite3CodecSizeChange, sqlite3CodecFree, pBlock);
    //db->aDb[0].pAux = pBlock;
    //db->aDb[0].xFreeAux = DestroyCryptBlock;
  }
  else // Change the writekey for an already-encrypted database
  {
    pBlock->hWriteKey = hKey;
  }

  // Start a transaction
  rc = sqlite3BtreeBeginTrans(pbt, 1);

  if (!rc)
  {
    // Rewrite all the pages in the database using the new encryption key
    Pgno nPage;
    Pgno nSkip = PAGER_MJ_PGNO(p);
    DbPage *pPage;
    Pgno n;

    rc = sqlite3PagerPagecount(p, &nPage);

    for(n = 1; rc == SQLITE_OK && n <= nPage; n ++)
    {
      if (n == nSkip) continue;
      rc = sqlite3PagerGet(p, n, &pPage);
      if(!rc)
      {
        rc = sqlite3PagerWrite(pPage);
        sqlite3PagerUnref(pPage);
      }
    }
  }

  // If we succeeded, try and commit the transaction
  if (!rc)
  {
    rc = sqlite3BtreeCommit(pbt);
  }

  // If we failed, rollback
  if (rc)
  {
    sqlite3BtreeRollback(pbt);
  }

  // If we succeeded, destroy any previous read key this database used
  // and make the readkey equal to the writekey
  if (!rc)
  {
    if (pBlock->hReadKey)
    {
      CryptDestroyKey(pBlock->hReadKey);
    }
    pBlock->hReadKey = pBlock->hWriteKey;
  }
  // We failed.  Destroy the new writekey (if there was one) and revert it back to
  // the original readkey
  else
  {
    if (pBlock->hWriteKey)
    {
      CryptDestroyKey(pBlock->hWriteKey);
    }
    pBlock->hWriteKey = pBlock->hReadKey;
  }

  // If the readkey and writekey are both empty, there's no need for a codec on this
  // pager anymore.  Destroy the crypt block and remove the codec from the pager.
  if (!pBlock->hReadKey && !pBlock->hWriteKey)
  {
    sqlite3PagerSetCodec(p, NULL, NULL, NULL, NULL);
  }

  return rc;
}
Ejemplo n.º 11
0
/* Close or free all handles and commit or rollback the transaction. */
static int backupCleanup(sqlite3_backup *p)
{
	int rc, rc2, ret;
	void *app;
	DB *db;

	rc = rc2 = SQLITE_OK;

	if (!p || p->rc == SQLITE_OK)
		return rc;

	rc2 = sqlite3BtreeCloseCursor(&p->destCur);
	if (rc2 != SQLITE_OK)
		rc = rc2;
	if (p->srcCur) {
		db = p->srcCur->dbp;
		app = db->app_private;
		if ((ret = p->srcCur->close(p->srcCur)) == 0)
			ret = db->close(db, DB_NOSYNC);
		rc2 = dberr2sqlite(ret);
		/*
		 * The KeyInfo was allocated in btreeSetupIndex,
		 * so have to deallocate it here.
		 */
		if (app)
			sqlite3DbFree(p->pSrcDb, app);
	}
	if (rc2 != SQLITE_OK)
		rc = rc2;
	p->srcCur = 0;

	/*
	 * May retry on a locked or busy error, so keep
	 * these values.
	 */
	if (p->rc != SQLITE_LOCKED && p->rc != SQLITE_BUSY) {
		if (p->srcName)
			sqlite3_free(p->srcName);
		if (p->destName != 0)
			sqlite3_free(p->destName);
		p->srcName = p->destName = NULL;
	}

	if (p->tables != 0)
			sqlite3_free(p->tables);
	p->tables = NULL;

	if (p->pSrc->nBackup)
		p->pSrc->nBackup--;
	if (p->pDest != NULL && p->pDest->nBackup)
		p->pDest->nBackup--;
	if (p->srcTxn) {
		if (p->rc == SQLITE_DONE)
			ret = p->srcTxn->commit(p->srcTxn, 0);
		else
			ret = p->srcTxn->abort(p->srcTxn);
		rc2 = dberr2sqlite(ret);
	}
	p->srcTxn = 0;
	if (rc2 != SQLITE_OK && sqlite3BtreeIsInTrans(p->pDest)) {
		rc = rc2;
		if (p->rc == SQLITE_DONE)
			rc2 = sqlite3BtreeCommit(p->pDest);
		else
			rc2 = sqlite3BtreeRollback(p->pDest);
		if (rc2 != SQLITE_OK)
			rc = rc2;
	}

	if (p->pDest && p->openDest) {
		char path[512];

		/*
		 * If successfully done then delete the old backup, if
		 * an error then delete the current database and restore
		 * the old backup.
		 */
		sqlite3_snprintf(sizeof(path), path,
		    "%s%s", p->fullName, BACKUP_SUFFIX);
		if (p->rc == SQLITE_DONE) {
			rc2 = btreeDeleteEnvironment(p->pDest, path, 0);
		} else {
			rc2 = btreeDeleteEnvironment(p->pDest, p->fullName, 0);
			if (!__os_exists(NULL, path, 0))
				__os_rename(NULL, path, p->fullName, 0);
		}
		if (rc == SQLITE_OK)
			rc = rc2;
		if (rc == SQLITE_OK) {
			p->pDest = NULL;
			p->pDestDb->aDb[p->iDb].pBt = NULL;
			p->openDest = 0;
			rc = sqlite3BtreeOpen(p->fullName, p->pDestDb,
			    &p->pDest,
			    SQLITE_DEFAULT_CACHE_SIZE | SQLITE_OPEN_MAIN_DB,
			    p->pDestDb->openFlags);
			p->pDestDb->aDb[p->iDb].pBt = p->pDest;
			if (rc == SQLITE_OK) {
				p->pDestDb->aDb[p->iDb].pSchema =
				    sqlite3SchemaGet(p->pDestDb, p->pDest);
				if (!p->pDestDb->aDb[p->iDb].pSchema)
					p->rc = SQLITE_NOMEM;
			} else
				p->pDestDb->aDb[p->iDb].pSchema = NULL;
			if (rc == SQLITE_OK)
				p->pDest->pBt->db_oflags |= DB_CREATE;
			/*
			 * Have to delete the schema here on error to avoid
			 * assert failure.
			 */
			if (p->pDest == NULL &&
			    p->pDestDb->aDb[p->iDb].pSchema != NULL) {
				sqlite3SchemaClear(
				    p->pDestDb->aDb[p->iDb].pSchema);
				p->pDestDb->aDb[p->iDb].pSchema = NULL;
			}
#ifdef SQLITE_HAS_CODEC
			if (rc == SQLITE_OK) {
				if (p->iDb == 0)
					rc = sqlite3_key(p->pDestDb,
					    p->pSrc->pBt->encrypt_pwd,
					    p->pSrc->pBt->encrypt_pwd_len);
				else
					rc = sqlite3CodecAttach(p->pDestDb,
					    p->iDb, p->pSrc->pBt->encrypt_pwd,
					    p->pSrc->pBt->encrypt_pwd_len);
			}
#endif
		}
	}
	if (p->rc != SQLITE_LOCKED && p->rc != SQLITE_BUSY) {
		if (p->fullName != 0)
			sqlite3_free(p->fullName);
		p->fullName = NULL;
	}
	p->lastUpdate = p->pSrc->updateDuringBackup;
	return rc;
}
Ejemplo n.º 12
0
/* sqlite3_rekey 
** Given a database, this will reencrypt the database using a new key.
** There are two possible modes of operation. The first is rekeying
** an existing database that was not previously encrypted. The second
** is to change the key on an existing database.
** 
** The proposed logic for this function follows:
** 1. Determine if there is already a key present
** 2. If there is NOT already a key present, create one and attach a codec (key would be null)
** 3. Initialize a ctx->rekey parameter of the codec
** 
** Note: this will require modifications to the sqlite3Codec to support rekey
**
*/
int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
  CODEC_TRACE(("sqlite3_rekey: entered db=%d pKey=%s, nKey=%d\n", db, pKey, nKey));
  activate_openssl();
  if(db && pKey && nKey) {
    struct Db *pDb = &db->aDb[0];
    CODEC_TRACE(("sqlite3_rekey: database pDb=%d\n", pDb));
    if(pDb->pBt) {
      codec_ctx *ctx;
      int rc, page_count;
      Pgno pgno;
      PgHdr *page;
      Pager *pPager = pDb->pBt->pBt->pPager;

      sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
     
      if(ctx == NULL) { 
        CODEC_TRACE(("sqlite3_rekey: no codec attached to db, attaching now\n"));
        /* there was no codec attached to this database,so attach one now with a null password */
        sqlite3CodecAttach(db, 0, pKey, nKey);
        sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
        
        /* prepare this setup as if it had already been initialized */
        RAND_pseudo_bytes(ctx->kdf_salt, ctx->kdf_salt_sz);
        ctx->read_ctx->key_sz = ctx->read_ctx->iv_sz =  ctx->read_ctx->pass_sz = 0;
      }

      sqlite3_mutex_enter(db->mutex);

      if(ctx->read_ctx->iv_sz != ctx->write_ctx->iv_sz) {
        char *error;
        CODEC_TRACE(("sqlite3_rekey: updating page size for iv_sz change from %d to %d\n", ctx->read_ctx->iv_sz, ctx->write_ctx->iv_sz));
        db->nextPagesize = SQLITE_DEFAULT_PAGE_SIZE;
        pDb->pBt->pBt->pageSizeFixed = 0; /* required for sqlite3BtreeSetPageSize to modify pagesize setting */
        sqlite3BtreeSetPageSize(pDb->pBt, db->nextPagesize, EVP_MAX_IV_LENGTH, 0);
        sqlite3RunVacuum(&error, db);
      }

      codec_set_pass_key(db, 0, pKey, nKey, 1);
      ctx->mode_rekey = 1; 
    
      /* do stuff here to rewrite the database 
      ** 1. Create a transaction on the database
      ** 2. Iterate through each page, reading it and then writing it.
      ** 3. If that goes ok then commit and put ctx->rekey into ctx->key
      **    note: don't deallocate rekey since it may be used in a subsequent iteration 
      */
      rc = sqlite3BtreeBeginTrans(pDb->pBt, 1); /* begin write transaction */
      sqlite3PagerPagecount(pPager, &page_count);
      for(pgno = 1; rc == SQLITE_OK && pgno <= page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */
        if(!sqlite3pager_is_mj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */
          rc = sqlite3PagerGet(pPager, pgno, &page);
          if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
            rc = sqlite3PagerWrite(page);
            //printf("sqlite3PagerWrite(%d)\n", pgno);
            if(rc == SQLITE_OK) {
              sqlite3PagerUnref(page);
            } 
          } 
        } 
      }

      /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
      if(rc == SQLITE_OK) { 
        CODEC_TRACE(("sqlite3_rekey: committing\n"));
        db->nextPagesize = SQLITE_DEFAULT_PAGE_SIZE;
        rc = sqlite3BtreeCommit(pDb->pBt); 
        cipher_ctx_copy(ctx->read_ctx, ctx->write_ctx);
      } else {
        CODEC_TRACE(("sqlite3_rekey: rollback\n"));
        sqlite3BtreeRollback(pDb->pBt);
      }

      ctx->mode_rekey = 0;
      sqlite3_mutex_leave(db->mutex);
    }
    return SQLITE_OK;
  }
  return SQLITE_ERROR;
}
Ejemplo n.º 13
0
/* sqlite3_rekey 
** Given a database, this will reencrypt the database using a new key.
** There are two possible modes of operation. The first is rekeying
** an existing database that was not previously encrypted. The second
** is to change the key on an existing database.
** 
** The proposed logic for this function follows:
** 1. Determine if there is already a key present
** 2. If there is NOT already a key present, create one and attach a codec (key would be null)
** 3. Initialize a ctx->rekey parameter of the codec
** 
** Note: this will require modifications to the sqlite3Codec to support rekey
**
*/
int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
  if(db && pKey && nKey) {
    int i, prepared_key_sz;
    int key_sz =  EVP_CIPHER_key_length(CIPHER);
    void *key = sqlite3Malloc(key_sz);
    if(key == NULL) return SQLITE_NOMEM;
    
    for(i=0; i<db->nDb; i++){
      struct Db *pDb = &db->aDb[i];
      if(pDb->pBt) {
        codec_ctx *ctx;
        int rc, page_count;
        Pgno pgno;
        PgHdr *page;
        Pager *pPager = pDb->pBt->pBt->pPager;
 
        sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
        
        if(ctx == NULL) { 
          /* there was no codec attached to this database,so attach one now with a null password */
          char *error;
          db->nextPagesize =  sqlite3BtreeGetPageSize(pDb->pBt);
          pDb->pBt->pBt->pageSizeFixed = 0; /* required for sqlite3BtreeSetPageSize to modify pagesize setting */
          sqlite3BtreeSetPageSize(pDb->pBt, db->nextPagesize, EVP_CIPHER_iv_length(CIPHER), 0);
          sqlite3RunVacuum(&error, db);
          sqlite3CodecAttach(db, i, pKey, nKey);
          sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
          /* prepare this setup as if it had already been initialized */
          RAND_pseudo_bytes(ctx->salt, FILE_HEADER_SZ);
          ctx->rekey_plaintext = 1;
        }
        
        codec_prepare_key(db, pKey, nKey, ctx->salt, FILE_HEADER_SZ, key, &prepared_key_sz);  
        assert(prepared_key_sz == key_sz);
        
        ctx->rekey = key; /* set rekey to new key data - note that ctx->key is original encryption key */
      
        /* do stuff here to rewrite the database 
        ** 1. Create a transaction on the database
        ** 2. Iterate through each page, reading it and then writing it.
        ** 3. If that goes ok then commit and put ctx->rekey into ctx->key
        **    note: don't deallocate rekey since it may be used in a subsequent iteration 
        */
        rc = sqlite3BtreeBeginTrans(pDb->pBt, 1); /* begin write transaction */
        rc = sqlite3PagerPagecount(pPager, &page_count);
        for(pgno = 1; rc == SQLITE_OK && pgno <= page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */
          if(!sqlite3pager_is_mj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */
            rc = sqlite3PagerGet(pPager, pgno, &page);
            if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
              rc = sqlite3PagerWrite(page);
              //printf("sqlite3PagerWrite(%d)\n", pgno);
              if(rc == SQLITE_OK) {
                sqlite3PagerUnref(page);
              } 
            } 
          } 
        }

        /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
        if(rc == SQLITE_OK) { 
          rc = sqlite3BtreeCommit(pDb->pBt); 
          memcpy(ctx->key, ctx->rekey, key_sz); 
          if(ctx->pass) {
            memset(ctx->pass, 0, ctx->pass_sz);
            sqlite3_free(ctx->pass);
          }
          ctx->pass = sqlite3Malloc(nKey);
          if(ctx->pass == NULL) return SQLITE_NOMEM;
          memcpy(ctx->pass, pKey, nKey);
          ctx->pass_sz = nKey;

        } else {
          printf("error\n");
          sqlite3BtreeRollback(pDb->pBt);
        }

        /* cleanup rekey data, make sure to overwrite rekey_plaintext or read errors will ensue */
        ctx->rekey = NULL; 
        ctx->rekey_plaintext = 0;
      }
    }
    
    /* clear and free temporary key data */
    memset(key, 0, key_sz); 
    sqlite3_free(key);
    return SQLITE_OK;
  }
  return SQLITE_ERROR;
}