Share via


コールバック関数PIBIO_STORAGE_ADD_RECORD_FN (winbio_adapter.h)

データベースにテンプレートを追加するためにエンジン アダプターによって呼び出されます。

構文

PIBIO_STORAGE_ADD_RECORD_FN PibioStorageAddRecordFn;

HRESULT PibioStorageAddRecordFn(
  [in, out] PWINBIO_PIPELINE Pipeline,
  [in]      PWINBIO_STORAGE_RECORD RecordContents
)
{...}

パラメーター

[in, out] Pipeline

操作を実行する生体認証ユニットに関連付けられている WINBIO_PIPELINE 構造体へのポインター。

[in] RecordContents

追加するテンプレートを含む WINBIO_STORAGE_RECORD 構造体へのポインター。

戻り値

関数が成功した場合は、S_OK を返します。 関数が失敗した場合は、エラーを示すために次のいずれかの HRESULT 値を返す必要があります。

リターン コード 説明
E_INVALIDARG
RecordContents パラメーターで指定された構造体のメンバーが無効です。
E_POINTER
必須のポインター引数は NULL です
WINBIO_E_DATABASE_BAD_INDEX_VECTOR
WINBIO_STORAGE_RECORD 構造体で指定されたインデックス ベクトルのサイズが、データベースの作成時に指定されたインデックス サイズと一致しません。
WINBIO_E_DUPLICATE_ENROLLMENT
データベースには、 Identity パラメーターと SubFactor パラメーターで指定された値の組み合わせを含むテンプレートが既に含まれています。
WINBIO_E_DATABASE_CORRUPTED
データベースに未指定の問題があります。
WINBIO_E_DATABASE_FULL
データベースがいっぱいで、それ以上レコードを追加することはできません。
WINBIO_E_DATABASE_LOCKED
データベースがロックされています。
WINBIO_E_DATABASE_WRITE_ERROR
未指定の問題のため、レコードの追加に失敗しました。
WINBIO_E_INVALID_DEVICE_STATE
パイプライン オブジェクトの StorageContext メンバーが NULL であるか、 FileHandle メンバーが無効です。

注釈

RecordContents パラメーターによって識別されるメモリは、Windows 生体認証フレームワークの プロパティです。 StorageAdapterAddRecord から戻った後、記憶域アダプターは、このポインターのコピー、またはWINBIO_STORAGE_RECORD構造体に含まれるポインターのコピーを保持することはできません。

重要  

RecordContents パラメーターの SubFactor 値に指定された値の検証を試みないでください。 Windows 生体認証サービスは、指定された値を実装に渡す前に検証します。 値が WINBIO_SUBTYPE_NO_INFORMATION または WINBIO_SUBTYPE_ANY場合は、必要に応じて検証します。

 

次の擬似コードは、この関数の 1 つの可能な実装を示しています。 この例はコンパイルされません。 目的に合わせて調整する必要があります。

/////////////////////////////////////////////////////////////////////////////////////////
//
// StorageAdapterAddRecord
//
// Purpose:
//      Adds a template to the database.
//
// Parameters:
//      Pipeline       - Pointer to a WINBIO_PIPELINE structure associated with 
//                       the biometric unit performing the operation.
//      RecordContents - Pointer to a WINBIO_STORAGE_RECORD structure that contains 
//                       the template to add.
//
static HRESULT
WINAPI
StorageAdapterAddRecord(
    __inout PWINBIO_PIPELINE Pipeline,
    __in PWINBIO_STORAGE_RECORD RecordContents
    )
{
    HRESULT hr = S_OK;
    struct _MY_ADAPTER_RECORD_HEADER *newRecord = NULL;
    SIZE_T newRecordSize = 0;
    BOOL lockAcquired = FALSE;
    ULONG index = 0;
    PUCHAR encryptedTemplateBlob = NULL;
    SIZE_T encryptedTemplateBlobSize = 0;
    struct _MY_ADAPTER_FILE_HEADER fileHeader = {0};
    SIZE_T templateBlobOffset = 0;
    SIZE_T payloadBlobOffset = 0;
    struct _MY_ADAPTER_DPAPI_DATA protectedData = {0};
    SIZE_T duplicateRecordCount = 0;

    // Verify that pointer arguments are not NULL.
    if (!ARGUMENT_PRESENT(Pipeline) ||
        !ARGUMENT_PRESENT(RecordContents))
    {
        hr = E_POINTER;
        goto cleanup;
    }

    // Retrieve the context from the pipeline.
    PWINBIO_STORAGE_CONTEXT storageContext = (PWINBIO_STORAGE_CONTEXT)Pipeline->StorageContext;

    // Verify the pipeline state.
    if (storageContext == NULL || storageContext->FileHandle == INVALID_HANDLE_VALUE)
    {
        hr =  WINBIO_E_INVALID_DEVICE_STATE;
        goto cleanup;
    }

    // Check various values associated with the record contents. The
    // following example code assumes that a database record contains
    // a valid:
    //    Identity
    //    Sub-factor characteristic
    //    Biometric template
    //    Payload associated with the template
    //    Index vector
    //
    if (!ARGUMENT_PRESENT(RecordContents->Identity))
    {
        hr = E_POINTER;
        goto cleanup;
    }

    if (RecordContents->Identity->Type != WINBIO_ID_TYPE_GUID &&
        RecordContents->Identity->Type != WINBIO_ID_TYPE_SID)
    {
        hr = E_INVALIDARG;
        goto cleanup;
    }

    if (RecordContents->SubFactor == WINBIO_SUBTYPE_NO_INFORMATION ||
        RecordContents->SubFactor == WINBIO_SUBTYPE_ANY)
    {
        hr = E_INVALIDARG;
        goto cleanup;
    }

    if (RecordContents->TemplateBlobSize == 0 ||
        !ARGUMENT_PRESENT(RecordContents->TemplateBlob))
    {
        hr = E_INVALIDARG;
        goto cleanup;
    }

    if (RecordContents->PayloadBlobSize > 0 && 
        !ARGUMENT_PRESENT(RecordContents->PayloadBlob))
    {
        hr = E_POINTER;
        goto cleanup;
    }

    if (RecordContents->IndexElementCount != storageContext->IndexElementCount)
    {
        hr = WINBIO_E_DATABASE_BAD_INDEX_VECTOR;
        goto cleanup;
    }

    if (RecordContents->IndexElementCount > 0 &&
        !ARGUMENT_PRESENT(RecordContents->IndexVector))
    {
        hr = E_POINTER;
        goto cleanup;
    }

    // Call a private function (_CheckForDuplicateEnrollments) to query the
    // database for existing records with the same identity and sub-factor 
    // values as the new record. If a duplicate is found, return.
    hr = _CheckForDuplicateEnrollments(
            Pipeline,
            RecordContents->Identity,
            RecordContents->SubFactor,
            &duplicateRecordCount
            );
    if (FAILED(hr))
    {
        goto cleanup;
    }
    if (duplicateRecordCount > 0)
    {
        hr = WINBIO_E_DUPLICATE_ENROLLMENT;
        goto cleanup;
    }

    // Call a custom function (_EncryptTemplateData) to encrypt the template 
    // data. Do this now so that you can determine how much space will be 
    // required to store the encrypted template.
    hr = _EncryptTemplateData(
            &storageContext->CryptoContext,
            RecordContents->TemplateBlob,
            RecordContents->TemplateBlobSize,
            &encryptedTemplateBlob,
            &encryptedTemplateBlobSize
            );
    if (FAILED(hr))
    {
        hr = WINBIO_E_DATABASE_WRITE_ERROR;
        goto cleanup;
    }

    // Call a custom function (_AllocateNewRecord) to allocate memory for the 
    // new record. You must allocate enough memory to hold the index vector, the
    // encrypted template, the identity structure, sub-factor information, and the 
    // payload blob. You must also allocate enough memory to hold and any other 
    // data that will be used by the storage adapter but that will
    // not be made visible to the engine adapter.
    hr = _AllocateNewRecord(
            RecordContents->IndexElementCount, 
            encryptedTemplateBlobSize,
            RecordContents->PayloadBlobSize,
            &newRecord,                         // [out] Address of the new record buffer
            &newRecordSize                      // [out] Size of the new record buffer
            );
    if (FAILED(hr))
    {
        goto cleanup;
    }

    // Copy the identity information into the new record.
    CopyMemory(
        &newRecord->Identity,
        RecordContents->Identity,
        sizeof(WINBIO_IDENTITY)
        );

    // Copy the sub-factor information to the new record.
    newRecord->SubFactor = RecordContents->SubFactor;

    // Copy the index vector, if present, into the new record.
    if (RecordContents->IndexElementCount > 0)
    {
        PULONG indexVector = _GetIndexVector(newRecord);
        for (index=0; index < RecordContents->IndexElementCount; ++index)
        {
            indexVector[index] = RecordContents->IndexVector[index];
        }
    }

    // Copy the encrypted template.
    templateBlobOffset = 
        sizeof(struct _MY_ADAPTER_RECORD_HEADER) + 
        RecordContents->IndexElementCount * sizeof(ULONG);

    newRecord->TemplateBlobSize = RecordContents->TemplateBlobSize;
    newRecord->EncryptedTemplateBlobSize = encryptedTemplateBlobSize;

    CopyMemory(
        (PUCHAR)newRecord + templateBlobOffset,
        encryptedTemplateBlob,
        encryptedTemplateBlobSize
        );
       
    // Copy the payload blob if present.
    if (RecordContents->PayloadBlobSize > 0)
    {
        payloadBlobOffset =
            templateBlobOffset + 
            encryptedTemplateBlobSize;

        newRecord->PayloadBlobSize = RecordContents->PayloadBlobSize;

        CopyMemory(
            (PUCHAR)newRecord + payloadBlobOffset, 
            RecordContents->PayloadBlob, 
            RecordContents->PayloadBlobSize
            );
    }

    // Call a custom function (_LockDatabase) to lock the database for writing
    // (EXCLUSIVE ownership).
    hr = _LockDatabase(Pipeline->StorageHandle, TRUE);
    if (FAILED(hr))
    {
        goto cleanup;
    }
    lockAcquired = TRUE;

    // Call a custom function (_ReadFileHeader) to read the header block.
    hr = _ReadFileHeader( Pipeline->StorageHandle, &fileHeader );
    if (FAILED(hr))
    {
        goto cleanup;
    }

    // Write the new data record to the first free byte at the end of the
    // active data area in the database file.
    hr = _WriteRecord( 
            Pipeline->StorageHandle, 
            fileHeader.FirstFreeByte, 
            newRecord 
            );
    if (FAILED(hr))
    {
        goto cleanup;
    }

    // Update the bookkeeping information in the header and write the header
    // back to the file.
    fileHeader.FirstFreeByte.QuadPart += newRecord->RecordSize;
    ++fileHeader.TotalRecordCount;

    hr = _WriteFileHeader(
            Pipeline->StorageHandle,
            &fileHeader
            );
    if (FAILED(hr))
    {
        hr = WINBIO_E_DATABASE_CORRUPTED;
        goto cleanup;
    }

    // Recompute the file hash and write it to the protected data area in the database
    // file. The hash value is an integrity check on data stored in the file. Note that
    // the DPAPI-protected data block is NOT included in the hash.
    hr = _ReadProtectedData(
            Pipeline->StorageHandle,
            &protectedData
            );
    if (FAILED(hr))
    {
        goto cleanup;
    }

    hr = _ComputeFileHash(
            Pipeline->StorageHandle,
            _MY_ADAPTER_DPAPI_BLOCK_OFFSET,
            (SIZE_T)(fileHeader.FirstFreeByte.QuadPart - 
                     _MY_ADAPTER_DPAPI_BLOCK_SIZE),
            protectedData.FileHash,
            _MY_ADAPTER_FILE_HASH_LENGTH,
            (PSIZE_T)&protectedData.FileHashLength
            );
    if (FAILED(hr))
    {
        hr = WINBIO_E_DATABASE_CORRUPTED;
        goto cleanup;
    }

    hr = _WriteProtectedData(
                Pipeline->StorageHandle,
                &protectedData
                );
    if (FAILED(hr))
    {
        hr = WINBIO_E_DATABASE_CORRUPTED;
        goto cleanup;
    }

cleanup:

    // Call the SecureZero function to overwrite the template encryption key 
    // on the stack.
    SecureZeroMemory( &protectedData, sizeof(struct _MY_ADAPTER_DPAPI_DATA));

    if (lockAcquired == TRUE)
    {
        _UnlockDatabase( Pipeline->StorageHandle);
        lockAcquired = FALSE;
    }

    if (encryptedTemplateBlob != NULL)
    {
        SecureZeroMemory(encryptedTemplateBlob, encryptedTemplateBlobSize);
        _AdapterRelease(encryptedTemplateBlob);
        encryptedTemplateBlob = NULL;
    }

    if (newRecord != NULL)
    {
        SecureZeroMemory( newRecord, newRecordSize);
        _AdapterRelease(newRecord);
        newRecord = NULL;
    }

    return hr;
}

要件

要件
サポートされている最小のクライアント Windows 7 [デスクトップ アプリのみ]
サポートされている最小のサーバー Windows Server 2008 R2 [デスクトップ アプリのみ]
対象プラットフォーム Windows
ヘッダー winbio_adapter.h (Winbio_adapter.h を含む)

こちらもご覧ください

プラグイン関数

StorageAdapterDeleteRecord