SSPI (original) (raw)

The Security Support Provider Interface, SSPI for short, defines the mechanics of _authenticating_a user -- of verifying that he is who he claims to be, or at the very least, that he knows a secret (the password) associated with a particular user account.

Named Pipes and RPC (and DCOM, by virtue of using RPC) offer SSPI integration: the developer just specifies that he wants an authenticated, possibly even encrypted, connection, and the rest is handled transparently.

The credentials used for such an authenticated connection can be:

The first three are tried automatically, from first to last, unless explicit credentials (the fourth option) are specified.

How does SSPI work? Simple: it asks the calling applications (the client and server processes) to toss data blocks back and forth until the underlying security provider is satisfied. NT 4.x and earlier offer the NTLM security provider; NT 5.x introduces a Kerberos implementation, too. The client app is able to select a particular package among those offered (the sample below uses NTLM, by the way, but just might work with others).

MSN, incidentally, also uses SSPI to authenticate -- the package is named "MSN". The transfer mechanism varies with the protocol, and I suggest sniffing a real authentication to find out the proper way to do it. I cannot help here, as I do not have an MSN account.

Having loaded the security DLL and having selected a package (another term for security provider), the client initializes the local SSPI and gets the first gob of data to send to the server. Meanwhile, the server has initialized the server machine's SSPI. After receiving the data block, the server feeds it to SSPI; on return, the server checks if the result-gob size is greater than 0 and, if so, sends the new gob to the client which feeds it to SSPI. The client's SSPI then either requests that another gob be sent to the server, or tells the app that authentication is complete. This continues until both SSPIs are happy.

At this point, the server holds a context handle, which it can query for the user name of the client (among other things). Depending on the options the client used, the server may also be allowed to use the context to impersonate the client, to sign or encrypt messages, and so on.

Actually, there is one more, optional, step involved: To end the send-receive cycle, some security providers may request a special finishing step, which is a call to CompleteAuthToken().

There are one and a half SSPI samples in the Platform SDK -- you can find them on the CD, in \mssdk\samples\WinBase\Security\WinNT\httpauth and ...\sockauth. Unfortunately, I only discovered them after I had rolled my own. They are more elaborate than my simple (and simplistic) sample, but I think mine is clearer, even if I do say so myself. (And they are buggy, to boot.)

News flash: Jon E. Miller went over sockauth with a fine-toothed comb and came to the conclusion that it would fail under certain circumstances (which will happen far more often in future, what with Kerberos and all). As far as I can see, he is correct. I uploaded newer versions of the sample files on 26-Dec-98, which incorporate the fruit of his labor. Thanks, Jon!

For all those who downloaded this sample earlier than on 26-Dec-98: server.cpp made the transmission of the output buffer from AcceptSecurityContext() dependent on the SEC_I_CONTINUE... status from AcceptSecurityContext(). Instead, a send should always be done if the output buffer size is greater than zero. The same goes for the client and InitializeSecurityContext(). Also, the server code had the test for breaking out of the loop before the code that sends an eventual reply to the client, which is clearly the wrong thing.

9-Jun-00: Bugfix. The server would, if AcceptSecurityContext() reported an error, still send the (bogus) output buffer. As a bonus, the client now has command line switches to pick the user you want to authenticate.

Just stick all of the following files into a directory of your choice and open "sspi.dsw" with Visual C++ 6.0:

bullet <sspi.dsw>, 1 KB, the workspace file declaring the two subprojects
bullet <server.dsp>, 4 KB, the server project file
bullet <server.cpp>, 9 KB, the server side of the sample
bullet <client.dsp>, 4 KB, the client project file
bullet <client.cpp>, 12 KB, the client side of the sample