Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using SSPI in a client/server environment

319 views
Skip to first unread message

Eric C

unread,
Feb 2, 2006, 12:09:37 PM2/2/06
to
I'm having some problems wrapping my brain around SSPI. Apologies for the
long post, but I prefer to get as much information in at the start. Here's
my situation...

We have a legacy product that operates as client/server over TCP/IP. There
is a working architecture for sending and receiving packets and waiting for
replies. The server is a C++ MFC Windows application that monitors a port
and responds to requests. It deals with multi-threading and all that
correctly. The client is a C++ MFC application that sends packets and waits
for replies. Both build with VC6. The server and client can exist on
separate machines or run on the same machine. The current security model
evolved over time (circa 1992) and is pretty simplistic.

I'm trying to add Windows authentication to the application instead of using
our own user/password system. For this, I'm planning on using SSPI. I've
been playing with Tomas Restrepo's WSSPI classes and sample and I've read a
bunch of Keith Brown's articles on the subject. I can make the sample build
and run with VC6. Tomas' sample has both client and server functions in the
same application. I've factored out the client code and server code into the
two separate applications. When I run in client/server, I get different
results from when I run the sample application. In the client/server app,
authentication fails.

Both the sample app and my client/server implementation use the NTLM
security package. It could use Kerberos, but the WSSPI class constructor
wants more information about the server than I have at the moment.

The sample application goes like this:

server.AcquireCredentialsHandle
client.AcquireCredentialsHandle

client.InitializeSecurityContext - Creates a block that is 57 bytes long
that has my machine name and domain embedded inside in ASCII. Block starts
with NTLMSSP.
server.AcceptSecurityContext - Creates a block that is 250 bytes long that
has my domain and machine name embedded inside in wide characters. Returns
SEC_I_CONTINUE_NEEDED.
client.InitializeSecurityContext - Using block from previous
server.AcceptSecurityContext, creates a block that is 72 bytes long and is
mostly filled with NULLs.
server.AcceptSecurityContext - Successful completion. I can now call
ImpersonateSecurityContext() and/or get a token.

The client/server application has this sequence factored into two
applications. The execution flow goes like this.

client.AcquireCredentialsHandle
client.InitializeSecurityContext - Creates a block that is 57 bytes long
that has my machine name and domain embedded inside in ASCII. Block starts
with NTLMSSP.

The 57 byte block is sent over TCP/IP, to the same machine in this case, but
it could be a separate machine. The server gets the packet and does it's
processing:

server.AcquireCredentialsHandle
server.AcceptSecurityContext - Creates a block that is 250 bytes long that
has my domain and machine name embedded inside in wide characters. Returns
SEC_I_CONTINUE_NEEDED. So far, same as the sample application.

The server returns the 250 byte block to the client. The client, in turn
does the following:

client.InitializeSecurityContext - Using block from previous
server.AcceptSecurityContext, creates a block that is 190 bytes long and
contains my domain, machine name, and local user name in wide characters.
This is different from the single application sample. The client packages
this data up and sends it to the server. The server is doling out service to
other clients, so it isn't waiting on the client to return a buffer. When
the client returns it's packet, it does the following

server.AcquireCredentialsHandle
server.AcceptSecurityContext - Fails with 0x80090308 (SEC_E_INVALID_TOKEN)

I've been reading about SSPI for several days. I suspect that I'm doing
something incorrect with the security APIs, but I can't put my finger on it.
I should be able to do this kind of client/server implementation with SSPI,
correct? It seems like this is what it is intended to do.

I tried keeping the security context handle for the server and restoring it
on the second pass on the server, but that didn't seem to work.

I have the credentials handle being recreated every time this particular bit
of code is called. Should I call it once when the server application is
invoked and just leave it? Are there any risks doing it one way or the other?

Thank you for any insights you can provide.

Eric

Alun Jones

unread,
Feb 6, 2006, 12:09:22 AM2/6/06
to
In article <27FE77C9-F1FB-41A1...@microsoft.com>,
=?Utf-8?B?RXJpYyBD?= <Er...@discussions.microsoft.com> wrote:
>The server returns the 250 byte block to the client. The client, in turn
>does the following:
>
>client.InitializeSecurityContext - Using block from previous
>server.AcceptSecurityContext, creates a block that is 190 bytes long and
>contains my domain, machine name, and local user name in wide characters.

Are you truly saying that the client code calls AcceptSecurityContext? The
client code should not call AcceptSecurityContext, and the server code should
not call InitializeSecurityContext.

>This is different from the single application sample. The client packages
>this data up and sends it to the server. The server is doling out service to
>other clients, so it isn't waiting on the client to return a buffer. When
>the client returns it's packet, it does the following
>
>server.AcquireCredentialsHandle
>server.AcceptSecurityContext - Fails with 0x80090308 (SEC_E_INVALID_TOKEN)

You've already called AcquireCredentialsHandle once at each end - you should
be using the same credentials handle for further parts of the same
negotiation, and not call AcquireCredentialsHandle again. This may not
matter, because the credential handle should only be required when you are
doing the first call to ASC or ISC, after which it will pick it out of the
partial security contexts that you are keeping in memory at each end. For
sheer good coding practice, though, follow the documentation unless it
conflicts with the sample, in which case, you use whichever one works.

>I've been reading about SSPI for several days. I suspect that I'm doing
>something incorrect with the security APIs, but I can't put my finger on it.
>I should be able to do this kind of client/server implementation with SSPI,
>correct? It seems like this is what it is intended to do.
>
>I tried keeping the security context handle for the server and restoring it
>on the second pass on the server, but that didn't seem to work.

That is the way to go. Don't forget that there are two places for the
security context handle - one, when you are creating the security context
handle in the first call, and the other, when you are passing in the
already-created value for subsequent calls.

>I have the credentials handle being recreated every time this particular bit
>of code is called. Should I call it once when the server application is
>invoked and just leave it? Are there any risks doing it one way or the other?

At the very least, call it no more than once at each end for each session -
connection, if you will - between client and server. Whether you call it once
per application run, or once per connection, depends on how long your
application will be alive, as opposed to how long the credential will be
likely to remain valid.

Alun.
~~~~

[Please don't email posters, if a Usenet response is appropriate.]
--
Texas Imperial Software | Find us at http://www.wftpd.com or email
23921 57th Ave SE | al...@wftpd.com.
Washington WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
Fax/Voice +1(425)807-1787 | Try our NEW client software, WFTPD Explorer.

Eric C

unread,
Feb 8, 2006, 5:50:02 PM2/8/06
to
Alun,

Thank you for the reply. I've managed to get this working in similar
fashion to what you've described. I'll summarize for posterity and I have a
few more questions if you don't mind answering.

> >client.InitializeSecurityContext - Using block from previous
> >server.AcceptSecurityContext, creates a block that is 190 bytes long and
> >contains my domain, machine name, and local user name in wide characters.
>
> Are you truly saying that the client code calls AcceptSecurityContext? The
> client code should not call AcceptSecurityContext, and the server code should
> not call InitializeSecurityContext.

No, the client calls ISC and the server calls ASC.

> You've already called AcquireCredentialsHandle once at each end - you should
> be using the same credentials handle for further parts of the same
> negotiation, and not call AcquireCredentialsHandle again.

That is exactly what was causing my problem. Once I started caching the
security handle, it started working. That led to a different problem, though.
Since my server can handle multiple requests for authentication
simultaneously, do I have to have a different credentials handle for each
client? I'm operating on the assumption that I do and created thread safe
storage for them.

> Texas Imperial Software | Find us at http://www.wftpd.com or email
> 23921 57th Ave SE | al...@wftpd.com.
> Washington WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
> Fax/Voice +1(425)807-1787 | Try our NEW client software, WFTPD Explorer.

BTW, I've been a fan of wftpd since '98 or so. It's very useful in a mixed
OS environment and on my recovery disks. Keep up the good work.

-E

Alun Jones

unread,
Feb 9, 2006, 9:43:32 PM2/9/06
to
In article <617CAFAB-5A0A-480C...@microsoft.com>,
=?Utf-8?B?RXJpYyBD?= <Er...@discussions.microsoft.com> wrote:
>That is exactly what was causing my problem. Once I started caching the
>security handle, it started working. That led to a different problem, though.
> Since my server can handle multiple requests for authentication
>simultaneously, do I have to have a different credentials handle for each
>client? I'm operating on the assumption that I do and created thread safe
>storage for them.

I believe that the credentials handle can be re-used (you could try it and
see), but one reason you might want to close and recreate it is that the
configuration of your server may change - in such a case, you would want to
use the most recently configured server certificate. You could simply wait on
configuration changes, and close / recreate the handle then, of course.

>> Texas Imperial Software | Find us at http://www.wftpd.com or email
>> 23921 57th Ave SE | al...@wftpd.com.
>> Washington WA 98072-8661 | WFTPD, WFTPD Pro are Windows FTP servers.
>> Fax/Voice +1(425)807-1787 | Try our NEW client software, WFTPD Explorer.
>
>BTW, I've been a fan of wftpd since '98 or so. It's very useful in a mixed
>OS environment and on my recovery disks. Keep up the good work.

Thanks - I'm glad to hear we've been of help.

Alun.
~~~~

[Please don't email posters, if a Usenet response is appropriate.]
--

0 new messages