ハンドシェイク対応するサーバーはこちらSSPIによる認証は、クライアントとサーバーがデータを交換することで行われます。最終的にコンテキストが作成されるという点は、どのようなSSPを使用する場合でも共通しています。コンテキストに格納される暗号鍵を通じて暗号化を行うことができるようになります。クライアントとサーバーの一連のデータ交換はハンドシェイクと呼ばれます。SSPIにおけるハンドシェイクは、クライアントを先頭に行われます。サーバーに送信するためのデータを作成します。ptsExpiry);phCredentialは、クレデンシャルハンドルのアドレスを指定します。phContextは、コンテキストハンドルのアドレスを指定します。コンテキストハンドルは、作成されたコンテキストを表すハンドルです。pszTargetNameは、サーバーを識別する文字列を指定します。具体的にどのような形式になるかは、SSPによって異なります。Reserved1は、予約されているため0を指定します。fContextReqは、コンテキストに要求したい定数を指定します。TargetDataRepは、バイトオーダーを表す定数を指定します。通常は、SECURITY_NETWORK_DREPを指定します。pInputは、サーバーによって作成されたデータを指定します。Reserved2は、予約されているため0を指定します。受け取る変数のアドレスを指定します。pOutputは、サーバーに送信するためのデータを受け取るバッファを指定します。pfContextAttrは、コンテキストに割り当てられた定数を受け取る変数のアドレスを指定します。ptsExpiryは、コンテキストの有効期限切れ時間を受け取る変数のアドレスを指定します。不要な場合は、NULLを指定することができます。データをSecBufferDesc構造体で表しています。この構造体は、次のように定義されています。*PSecBufferDesculVersionは、SECBUFFER_VERSIONを指定します。cBuffersは、pBuffersに指定したSecBuffer構造体の数を指定します。pBuffersは、SecBuffer構造体の配列を指定します。SecBufferDescは複数のSecBuffer構造体を1つとして扱うために存在しています。SecBuffer構造体は、次のように定義されています。*PSecBuffer;cbBufferは、pvBufferに指定したバッファのサイズを指定します。BufferTypeは、バッファの種類を表す定数を指定します。pvBufferは、データを格納したバッファを指定します。実際にサーバーとデータの交換を行うのは、アプリケーションの役割であることに注意してください。サーバーと通信することができます。アプリケーションは、送受信することになるデータの中身を意識する必要はありません。クライアントから送られてきたデータをAcceptSecurityContextに指定するだけで問題ありません。不要になったコンテキストハンドルは、DeleteSecurityContextで削除します。phContext);phContextは、コンテキストハンドルを指定します。今回のプログラムは、クライアントにおけるハンドシェイクの例を示しています。実際にサーバーと通信するコードは含まれていないため、実行しても失敗することになります。TEXT("クレデンシャルハンドルの取得に失敗しました。TEXT("認証に失敗しました。した処理はアプリケーションが用意しなければなりません。ReceiveDataは通信相手からデータを受信する関数です。SendDataとReceiveDataの存在はダミーとなっています。ハンドシェイクを行うClientHandshake関数の呼び出しです。今回は、NTLM認証を行うため、AcquireCredentialsHandleの第2引数にNTLMを指定しています。第2引数は関数内部で作成されたコンテキストハンドルを受け取ります。コンテキストハンドルは、CtxtHandle構造体で表されます。ClientHandshakeの内部を順に見ていきます。SEC_I_CONTINUE_NEEDED;bFirstは、サーバーにデータを送信するのが初めての場合にTRUEになります。InitializeSecurityContextの呼び出しが変化することになります。uSizeは、サーバーから受信したデータのサイズを格納します。uAttributesは、コンテキストに要求したい定数を指定します。ISC_REQ_STREAMは、ストリーム通信を行うことを意味します。sbInはサーバーから受信したデータを格納します。sbdOutはsbOutを格納し、sbdInはsbInを格納します。ssは、InitializeSecurityContextの戻り値を格納します。引き続きInitializeSecurityContextを呼び出してサーバーとのハンドシェイクを行います。これをサーバーに送信することで行われます。サーバーから取得したデータをInitializeSecurityContextに指定することになります。InitializeSecurityContextの呼び出しに必要なsbdInとsbdOutは、次のように初期化されています。サーバーからの応答がクライアントに届いているはずです。これをReceiveDataで取得し、取得したデータをsbIn[0].pvBufferに指定します。cbBufferにはデータのサイズを指定し、BufferTypeにはSECBUFFER_TOKENを指定します。sbInの初期化が終われば、このアドレスをsbdInに指定します。sbOutは、サーバーに送信するデータを格納しますが、pvBufferにはNULLを指定しています。理由は、送信するデータがInitializeSecurityContextによって作成されるからです。sbOutの初期化が終われば、このアドレスをsbdOutに指定します。InitializeSecurityContextの呼び出しは、次のようになっています。bFirstがTRUEの場合はNULLを指定します。これは、1回目の呼び出し時点ではコンテキストハンドルが作成されていないからです。これについてもbFirstがTRUEの場合はNULLを指定します。有効なデータを指定することはできません。ISC_REQ_ALLOCATE_MEMORYはuAttributesに格納していません。別途指定するようにしています。InitializeSecurityContextが制御を返せば、作成されたデータをサーバーに送信します。これをSendDataでサーバーに送信します。データの送信を終えたら、これは不要になるためFreeContextBufferで開放します。bFirstをFALSEにしているのは、1回目のInitializeSecurityContextの呼び出しを終えたからです。次に、InitializeSecurityContextが呼ばれるのは、サーバーから送られてきたデータを取得してからになります。