コールバック関数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 値を返す必要があります。
リターン コード | 説明 |
---|---|
|
RecordContents パラメーターで指定された構造体のメンバーが無効です。 |
|
必須のポインター引数は NULL です。 |
|
WINBIO_STORAGE_RECORD 構造体で指定されたインデックス ベクトルのサイズが、データベースの作成時に指定されたインデックス サイズと一致しません。 |
|
データベースには、 Identity パラメーターと SubFactor パラメーターで指定された値の組み合わせを含むテンプレートが既に含まれています。 |
|
データベースに未指定の問題があります。 |
|
データベースがいっぱいで、それ以上レコードを追加することはできません。 |
|
データベースがロックされています。 |
|
未指定の問題のため、レコードの追加に失敗しました。 |
|
パイプライン オブジェクトの 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 を含む) |
こちらもご覧ください
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示