SSPI Kerberos for delegation
- From: Kasparov <ganesh.tambat@xxxxxxxxx>
- Date: Thu, 18 Dec 2008 08:12:48 -0800 (PST)
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <malloc.h>
#define SECURITY_WIN32 1
#include <security.h>
#pragma hdrstop
//
====================================================================
// IMPORTANT NOTICE -- Check out
// http://www.mvps.org/security/sspi.html
// for the gory details of how this works
//
====================================================================
void auth( SOCKET s, CredHandle& cred, CtxtHandle& cliCtx,
const char *tokenSource, const char *name = NULL,
const char *pwd = NULL, const char *domain = NULL );
PSecurityFunctionTable pf = NULL;
void initSecLib( HINSTANCE& hSec );
bool Ganesh_auth( SOCKET s, CredHandle& cred, CtxtHandle& srvCtx )
{
int rc;
bool haveToken = true;
SecPkgInfo *secPackInfo;
int bytesReceived = 0, bytesSent = 0;
char buf[256];
DWORD bufsiz = sizeof buf;
HANDLE threadRet;
puts( "auth() entered" );
rc = (pf->QuerySecurityPackageInfo)( "Kerberos", &secPackInfo );
printf( "QSPI(): %08xh\n", rc );
if ( rc != SEC_E_OK )
haveToken = false;
TimeStamp useBefore;
rc = (pf->AcquireCredentialsHandle)( NULL, "Kerberos",
SECPKG_CRED_BOTH,
NULL, NULL, NULL, NULL, &cred, &useBefore );
rc = GetLastError();
printf( "ACH(): %08xh\n", rc );
if ( rc != SEC_E_OK )
haveToken = false;
// input and output buffers
SecBufferDesc obd, ibd;
SecBuffer ob, ib;
DWORD ctxAttr;
bool haveContext = false;
while ( 1 )
{
// prepare to get the server's response
ibd.ulVersion = SECBUFFER_VERSION;
ibd.cBuffers = 1;
ibd.pBuffers = &ib; // just one buffer
ib.BufferType = SECBUFFER_TOKEN; // preping a token here
// receive the client's POD
// MACHINE-DEPENDENT CODE! (Besides, we assume that we
// get the length with a single read, which is not guaranteed)
recv( s, (char *) &ib.cbBuffer, sizeof ib.cbBuffer, 0 );
bytesReceived += sizeof ib.cbBuffer;
ib.pvBuffer = LocalAlloc( 0, ib.cbBuffer );
char *p = (char *) ib.pvBuffer;
int n = ib.cbBuffer;
while ( n )
{
rc = recv( s, p, n, 0 );
// if ( rc == SOCKET_ERROR )
// wserr( rc, "recv" );
// if ( rc == 0 )
// wserr( 999, "recv" );
bytesReceived += rc;
n -= rc;
p += rc;
}
// by now we have an input buffer
obd.ulVersion = SECBUFFER_VERSION;
obd.cBuffers = 1;
obd.pBuffers = &ob; // just one buffer
ob.BufferType = SECBUFFER_TOKEN; // preping a token here
ob.cbBuffer = secPackInfo->cbMaxToken;
ob.pvBuffer = LocalAlloc( 0, ob.cbBuffer );
// rc = (pf->AcceptSecurityContext)( &cred, haveContext? &srvCtx:
NULL,
// &ibd, 0, SECURITY_NATIVE_DREP, &srvCtx, &obd, &ctxAttr,
// &useBefore );
rc = (pf->AcceptSecurityContext)( &cred, haveContext? &srvCtx: NULL,
&ibd, 0, SECURITY_NATIVE_DREP /*SECURITY_NETWORK_DREP*/, &srvCtx,
&obd, &ctxAttr,
&useBefore );
printf( "ASC(): %08xh\n", rc );
if ( ib.pvBuffer != NULL )
{
LocalFree( ib.pvBuffer );
ib.pvBuffer = NULL;
}
if ( rc == SEC_I_COMPLETE_AND_CONTINUE || rc ==
SEC_I_COMPLETE_NEEDED )
{
if ( pf->CompleteAuthToken != NULL ) // only if implemented
(pf->CompleteAuthToken)( &srvCtx, &obd );
if ( rc == SEC_I_COMPLETE_NEEDED )
rc = SEC_E_OK;
else if ( rc == SEC_I_COMPLETE_AND_CONTINUE )
rc = SEC_I_CONTINUE_NEEDED;
}
// send the output buffer off to the server
// warning -- this is machine-dependent! FIX IT!
if ( rc == SEC_E_OK || rc == SEC_I_CONTINUE_NEEDED )
{
if ( ob.cbBuffer != 0 )
{
send( s, (const char *) &ob.cbBuffer, sizeof ob.cbBuffer, 0 );
bytesSent += sizeof ob.cbBuffer;
send( s, (const char *) ob.pvBuffer, ob.cbBuffer, 0 );
bytesSent += ob.cbBuffer;
}
LocalFree( ob.pvBuffer );
ob.pvBuffer = NULL;
}
if ( rc != SEC_I_CONTINUE_NEEDED )
break;
haveContext = true;
// loop back for another round
puts( "looping" );
}
// we arrive here as soon as InitializeSecurityContext()
// returns != SEC_I_CONTINUE_NEEDED.
if ( rc != SEC_E_OK )
{
printf( "Oops! ASC() returned %08xh!\n", rc );
haveToken = false;
}
rc = GetLastError();
GetUserName( buf, &bufsiz );
// now we try to use the context
rc = (pf->ImpersonateSecurityContext)( &srvCtx );
printf( "ImpSC(): %08xh\n", rc );
if ( rc != SEC_E_OK )
{
printf( "Oops! ImpSC() returns %08xh!\n", rc );
haveToken = false;
}
else
{
char buf[256];
DWORD bufsiz = sizeof buf;
GetUserName( buf, &bufsiz );
printf( "user name: \"%s\"\n", buf );
(pf->RevertSecurityContext)( &srvCtx );
printf( "RSC(): %08xh\n", rc );
}
(pf->FreeContextBuffer)( secPackInfo );
printf( "auth() exiting (%d received, %d sent)\n", bytesReceived,
bytesSent );
return haveToken;
}
int Ganesh_Server_Impl()
{
int rc, port = 12000, addrlen;
bool haveToken;
SOCKET sock, s;
WSADATA wsadata;
PSERVENT pse;
SOCKADDR_IN addr;
HINSTANCE hSecLib;
initSecLib( hSecLib );
rc = WSAStartup( 2, &wsadata );
// wserr( rc, "WSAStartup" );
sock = socket( AF_INET, SOCK_STREAM, 0 );
if ( sock == INVALID_SOCKET )
{
rc = -1;
}
else
{
rc = 0;
}
// wserr( 999, "socket" );
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
// try numeric protocol first
if ( port > 0 && port < 32768 )
addr.sin_port = htons( (short) port );
else
{
}
rc = bind( sock, (SOCKADDR *) &addr, sizeof addr );
// wserr( rc, "bind" );
rc = listen( sock, 2 );
// wserr( rc, "listen" );
CredHandle cred;
CtxtHandle srvCtx;
while ( 1 )
{
addrlen = sizeof addr;
s = accept( sock, (SOCKADDR *) &addr, &addrlen );
if ( s == INVALID_SOCKET )
{
rc = -1;
}
else
{
rc = 0;
}
// wserr( s, "accept" );
haveToken = Ganesh_auth( s, cred, srvCtx );
// now we talk to the client
printf( "haveToken = %s\n\n", haveToken? "true": "false" );
send( s, (const char *) &haveToken, sizeof haveToken, 0 );
// clean up
(pf->DeleteSecurityContext)( &srvCtx );
(pf->FreeCredentialHandle)( &cred );
closesocket( s );
}
}
// wserr() displays winsock errors and aborts. No grace there.
void wserr( int rc, const char * const funcname )
{
if ( rc == 0 )
return;
fprintf( stderr, "\nWinsock error %d [gle %d] returned by %s().\n"
"Sorry, no bonus!\n", rc, WSAGetLastError(), funcname );
WSACleanup();
exit( rc );
}
void auth( SOCKET s, CredHandle& cred, CtxtHandle& cliCtx,
const char *tokenSource, const char *name /* = NULL */,
const char *pwd /* = NULL */, const char *domain /* = NULL */ )
{
int rc, rcISC;
SecPkgInfo *secPackInfo;
SEC_WINNT_AUTH_IDENTITY *nameAndPwd = NULL;
int bytesReceived = 0, bytesSent = 0;
puts( "auth() entered" );
// the arguments to ISC() is not const ... for once, I decided
// on creating writable copies instead of using a brutalizing cast.
char *myTokenSource;
myTokenSource = _strdup( tokenSource );
if ( name != NULL )
{
nameAndPwd = (SEC_WINNT_AUTH_IDENTITY *) malloc( sizeof
SEC_WINNT_AUTH_IDENTITY );
memset( nameAndPwd, '\0', sizeof *nameAndPwd );
nameAndPwd->Domain = (byte *) _strdup( domain? domain: "" );
nameAndPwd->DomainLength = domain? strlen( domain ): 0;
nameAndPwd->User = (byte *) _strdup( name? name: "" );
nameAndPwd->UserLength = name? strlen( name ): 0;
nameAndPwd->Password = (byte *) _strdup( pwd? pwd: "" );
nameAndPwd->PasswordLength = pwd? strlen( pwd ): 0;
nameAndPwd->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
}
rc = (pf->QuerySecurityPackageInfo)( "Kerberos", &secPackInfo );
printf( "QSPI(): %08xh\n", rc );
TimeStamp useBefore;
rc = (pf->AcquireCredentialsHandle)( NULL, "Kerberos",
SECPKG_CRED_BOTH,
NULL, nameAndPwd, NULL, NULL, &cred, &useBefore );
printf( "ACH(): %08xh\n", rc );
// input and output buffers
SecBufferDesc obd, ibd;
SecBuffer ob, ib;
DWORD ctxReq, ctxAttr;
// from sspi.h:
// #define ISC_REQ_DELEGATE 0x00000001
// #define ISC_REQ_MUTUAL_AUTH 0x00000002
// #define ISC_REQ_REPLAY_DETECT 0x00000004
// #define ISC_REQ_SEQUENCE_DETECT 0x00000008
// #define ISC_REQ_CONFIDENTIALITY 0x00000010
// #define ISC_REQ_USE_SESSION_KEY 0x00000020
// #define ISC_REQ_PROMPT_FOR_CREDS 0x00000040
// #define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080
// #define ISC_REQ_ALLOCATE_MEMORY 0x00000100
// #define ISC_REQ_USE_DCE_STYLE 0x00000200
// #define ISC_REQ_DATAGRAM 0x00000400
// #define ISC_REQ_CONNECTION 0x00000800
// #define ISC_REQ_CALL_LEVEL 0x00001000
// #define ISC_REQ_EXTENDED_ERROR 0x00004000
// #define ISC_REQ_STREAM 0x00008000
// #define ISC_REQ_INTEGRITY 0x00010000
ctxReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE;
bool haveInbuffer = false;
bool haveContext = false;
ib.pvBuffer = NULL;
while ( 1 )
{
obd.ulVersion = SECBUFFER_VERSION;
obd.cBuffers = 1;
obd.pBuffers = &ob; // just one buffer
ob.BufferType = SECBUFFER_TOKEN; // preping a token here
ob.cbBuffer = secPackInfo->cbMaxToken;
ob.pvBuffer = LocalAlloc( 0, ob.cbBuffer );
rcISC = (pf->InitializeSecurityContext)( &cred, haveContext?
&cliCtx: NULL,
myTokenSource, ctxReq, 0, SECURITY_NATIVE_DREP /
*SECURITY_NETWORK_DREP*/, haveInbuffer? &ibd: NULL,
0, &cliCtx, &obd, &ctxAttr, &useBefore );
printf( "ISC(): %08xh\n", rcISC );
if ( ib.pvBuffer != NULL )
{
LocalFree( ib.pvBuffer );
ib.pvBuffer = NULL;
}
if ( rcISC == SEC_I_COMPLETE_AND_CONTINUE || rcISC ==
SEC_I_COMPLETE_NEEDED )
{
if ( pf->CompleteAuthToken != NULL ) // only if implemented
(pf->CompleteAuthToken)( &cliCtx, &obd );
if ( rcISC == SEC_I_COMPLETE_NEEDED )
rcISC = SEC_E_OK;
else if ( rcISC == SEC_I_COMPLETE_AND_CONTINUE )
rcISC = SEC_I_CONTINUE_NEEDED;
}
// send the output buffer off to the server
// warning -- this is machine-dependent! FIX IT!
if ( ob.cbBuffer != 0 )
{
send( s, (const char *) &ob.cbBuffer, sizeof ob.cbBuffer, 0 );
bytesSent += sizeof ob.cbBuffer;
send( s, (const char *) ob.pvBuffer, ob.cbBuffer, 0 );
bytesSent += ob.cbBuffer;
}
LocalFree( ob.pvBuffer );
ob.pvBuffer = NULL;
if ( rcISC != SEC_I_CONTINUE_NEEDED )
break;
// prepare to get the server's response
ibd.ulVersion = SECBUFFER_VERSION;
ibd.cBuffers = 1;
ibd.pBuffers = &ib; // just one buffer
ib.BufferType = SECBUFFER_TOKEN; // preping a token here
// receive the server's response
// MACHINE-DEPENDENT CODE! (Besides, we assume that we
// get the length with a single read, which is not guaranteed)
recv( s, (char *) &ib.cbBuffer, sizeof ib.cbBuffer, 0 );
bytesReceived += sizeof ib.cbBuffer;
ib.pvBuffer = LocalAlloc( 0, ib.cbBuffer );
char *p = (char *) ib.pvBuffer;
int n = ib.cbBuffer;
while ( n )
{
rc = recv( s, p, n, 0 );
if ( rc == SOCKET_ERROR )
wserr( rc, "recv" );
if ( rc == 0 )
wserr( 999, "recv" );
bytesReceived += rc;
n -= rc;
p += rc;
}
// by now we have an input buffer and a client context
haveInbuffer = true;
haveContext = true;
// loop back for another round
puts( "looping" );
}
// we arrive here as soon as InitializeSecurityContext()
// returns != SEC_I_CONTINUE_NEEDED.
if ( rcISC != SEC_E_OK )
printf( "Oops! ISC() returned %08xh!\n", rcISC );
(pf->FreeContextBuffer)( secPackInfo );
printf( "auth() exiting (%d sent, %d received)\n", bytesSent,
bytesReceived );
free( myTokenSource );
if ( nameAndPwd != 0 )
{
if ( nameAndPwd->Domain != 0 )
free( nameAndPwd->Domain );
if ( nameAndPwd->User != 0 )
free( nameAndPwd->User );
if ( nameAndPwd->Password != 0 )
free( nameAndPwd->Password );
free( nameAndPwd );
}
}
void initSecLib( HINSTANCE& hSec )
{
PSecurityFunctionTable (*pSFT)( void );
hSec = LoadLibrary( "security.dll" );
pSFT = (PSecurityFunctionTable (*)( void )) GetProcAddress( hSec,
"InitSecurityInterfaceA" );
if ( pSFT == NULL )
{
puts( "security.dll load messed up ..." );
exit( 1 );
}
pf = pSFT();
if ( pf == NULL )
{
puts( "no function table?!?" );
exit( 1 );
}
}
int main( int argc, char *argv[] )
{
int rc, port, i, errors;
HINSTANCE hSecLib;
unsigned long naddr;
SOCKET sock;
WSADATA wsadata;
PHOSTENT phe;
PSERVENT pse;
SOCKADDR_IN addr;
//const char *tokenSource = "Authsamp", *server = "10.217.99.78";
const char *tokenSource = "win\\gtambat1", *server = "10.217.99.78";
const char *portstr = "11000", *user = 0, *pwd = 0, *domain = 0;
errors = 0;
for ( i = 1; i < argc; ++ i )
{
if ( argv[i][0] != '-' && argv[i][0] != '/' )
{
printf( "\"%s\" is not a valid switch.\n", argv[i] );
++ errors;
continue;
}
switch ( argv[i][1] )
{
case 's':
if ( i >= argc - 1 )
{
printf( "\"%s\" requires an argument.\n", argv[i] );
++ errors;
}
else if ( server != 0 )
{
printf( "\"%s\" has already been used.\n", argv[i ++] );
++ errors;
}
else
server = argv[++ i];
break;
case 'p':
if ( i >= argc - 1 )
{
printf( "\"%s\" requires an argument.\n", argv[i] );
++ errors;
}
else if ( portstr != 0 )
{
printf( "\"%s\" has already been used.\n", argv[i ++] );
++ errors;
}
else
portstr = argv[++ i];
break;
case 't':
if ( i >= argc - 1 )
{
printf( "\"%s\" requires an argument.\n", argv[i] );
++ errors;
}
else if ( tokenSource != 0 )
{
printf( "\"%s\" has already been used.\n", argv[i ++] );
++ errors;
}
else
tokenSource = argv[++ i];
break;
case 'd':
if ( i >= argc - 1 )
{
printf( "\"%s\" requires an argument.\n", argv[i] );
++ errors;
}
else if ( domain != 0 )
{
printf( "\"%s\" has already been used.\n", argv[i ++] );
++ errors;
}
else
domain = argv[++ i];
break;
case 'u':
if ( i >= argc - 2 )
{
printf( "\"%s\" requires two arguments.\n", argv[i ++] );
++ errors;
}
else if ( user != 0 )
{
printf( "\"%s\" has already been used.\n", argv[i] );
i += 2;
++ errors;
}
else
{
user = argv[++ i];
pwd = argv[++ i];
}
break;
default:
printf( "\"%s\" is not a valid switch.\n", argv[i] );
++ errors;
break;
}
}
if ( server == 0 )
{
puts( "A server name or IP address must be specified." );
++ errors;
}
if ( portstr == 0 )
{
puts( "A port name or port number must be specified." );
++ errors;
}
if ( user == 0 && domain != 0 )
puts( "No user name was specified, ignoring the domain." );
if ( errors )
{
puts( "\nusage: client -s your.server.com -p serverport" );
puts( " [-t token-source] [-u user pwd [-d domain]]" );
puts( "token-source is _required_ for Kerberos and should be
your" );
puts( "current logon name (e.g., \"MYDOMAIN\\felixk\")." );
puts( "If -u is absent, your current credentials will be used." );
return 1;
}
initSecLib( hSecLib );
rc = WSAStartup( 2, &wsadata );
wserr( rc, "WSAStartup" );
sock = socket( AF_INET, SOCK_STREAM, 0 );
if ( sock == INVALID_SOCKET )
wserr( 999, "socket" );
addr.sin_family = AF_INET;
// try numeric IP address first (inet_addr)
naddr = inet_addr( server );
if ( naddr != INADDR_NONE )
{
addr.sin_addr.s_addr = naddr;
}
else
{
phe = gethostbyname( server );
if ( phe == NULL )
wserr( 1, "gethostbyname" );
addr.sin_addr.s_addr = *( (unsigned long *) (phe->h_addr) );
memcpy( (char *) &addr.sin_addr, phe->h_addr, phe->h_length );
}
// try numeric protocol first
port = atoi( portstr );
if ( port > 0 && port < 32768 )
addr.sin_port = htons( (short) port );
else
{
pse = getservbyname( portstr, "tcp" );
if ( pse == NULL )
wserr( 1, "getservbyname" );
addr.sin_port = pse->s_port;
}
CredHandle cred;
CtxtHandle cliCtx;
rc = connect( sock, (SOCKADDR *) &addr, sizeof addr );
wserr( rc, "connect" );
struct sockaddr name;
int namelen = sizeof name;;
rc = getsockname( sock, &name, &namelen );
wserr( rc, "getsockname()" );
printf( "I am %u.%u.%u.%u\n", (unsigned int) (unsigned char)
name.sa_data[2],
(unsigned int) (unsigned char) name.sa_data[3], (unsigned int)
(unsigned char) name.sa_data[4],
(unsigned int) (unsigned char) name.sa_data[5] );
auth( sock, cred, cliCtx, tokenSource, user, pwd, server ); // this
does the real work
// Added by Ganesh
//auth( sock, cred, cliCtx, tokenSource, "ganesh", "ganesh", "ganesh-
test1" ); // this does the real work
// use the authenticated connection here
bool haveToken = false;
rc = recv( sock, (char *) &haveToken, sizeof haveToken, 0 );
if ( rc != sizeof haveToken )
wserr( 999, "result-recv" );
if ( haveToken )
puts( "That seems to have worked." );
else
puts( "Oops! Wrong user name or password?" );
// the server is probably impersonating us by now
// this is where the client and server talk business
// clean up
(pf->DeleteSecurityContext)( &cliCtx );
(pf->FreeCredentialHandle)( &cred );
rc = closesocket( sock );
wserr( rc, "closesocket" );
rc = WSACleanup();
wserr( rc, "WSACleanup" );
int j;
puts("/n/n Should I start server implemenation within client ?: ");
scanf("%d",&j);
rc = Ganesh_Server_Impl();
__try
{
FreeLibrary( hSecLib );
}
__except ( 1 )
{
puts( "Freelibrary( security.dll ) caused an access violation.
Yuck." );
}
return 0;
}
*******************
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <malloc.h>
#define SECURITY_WIN32 1
#include <sspi.h>
//#include <issperr.h> // uncomment if you have an old Platform SDK
#pragma hdrstop
//
====================================================================
// IMPORTANT NOTICE -- Check out
// http://www.mvps.org/security/sspi.html
// for the gory details of how this works
//
====================================================================
PSecurityFunctionTable pf = NULL;
int Ganesh_Client_Impl(CtxtHandle &srvCtx);
void initSecLib( HINSTANCE& hSec );
void Ganesh_auth( SOCKET s, CredHandle& cred, CtxtHandle& cliCtx,
const char *tokenSource, const char *name /* = NULL */,
const char *pwd /* = NULL */, const char *domain /* = NULL */ );
void Ganesh_auth( SOCKET s, CredHandle& cred, CtxtHandle& cliCtx,
const char *tokenSource, const char *name /* = NULL */,
const char *pwd /* = NULL */, const char *domain /* = NULL */ )
{
int rc, rcISC;
SecPkgInfo *secPackInfo;
SEC_WINNT_AUTH_IDENTITY *nameAndPwd = NULL;
int bytesReceived = 0, bytesSent = 0;
//puts( "auth() entered" );
// the arguments to ISC() is not const ... for once, I decided
// on creating writable copies instead of using a brutalizing cast.
char *myTokenSource;
myTokenSource = _strdup( tokenSource );
if ( name != NULL )
{
nameAndPwd = (SEC_WINNT_AUTH_IDENTITY *) malloc( sizeof
SEC_WINNT_AUTH_IDENTITY );
memset( nameAndPwd, '\0', sizeof *nameAndPwd );
nameAndPwd->Domain = (byte *) _strdup( domain? domain: "" );
nameAndPwd->DomainLength = domain? strlen( domain ): 0;
nameAndPwd->User = (byte *) _strdup( name? name: "" );
nameAndPwd->UserLength = name? strlen( name ): 0;
nameAndPwd->Password = (byte *) _strdup( pwd? pwd: "" );
nameAndPwd->PasswordLength = pwd? strlen( pwd ): 0;
nameAndPwd->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
}
rc = (pf->QuerySecurityPackageInfo)( "kerberos", &secPackInfo );
//printf( "QSPI(): %08xh\n", rc );
TimeStamp useBefore;
rc = GetLastError();
rc = (pf->AcquireCredentialsHandle)( NULL, "kerberos",
SECPKG_CRED_BOTH,
NULL, nameAndPwd, NULL, NULL, &cred, &useBefore );
//printf( "ACH(): %08xh\n", rc );
rc = GetLastError();
// input and output buffers
SecBufferDesc obd, ibd;
SecBuffer ob, ib;
DWORD ctxReq, ctxAttr;
// from sspi.h:
// #define ISC_REQ_DELEGATE 0x00000001
// #define ISC_REQ_MUTUAL_AUTH 0x00000002
// #define ISC_REQ_REPLAY_DETECT 0x00000004
// #define ISC_REQ_SEQUENCE_DETECT 0x00000008
// #define ISC_REQ_CONFIDENTIALITY 0x00000010
// #define ISC_REQ_USE_SESSION_KEY 0x00000020
// #define ISC_REQ_PROMPT_FOR_CREDS 0x00000040
// #define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080
// #define ISC_REQ_ALLOCATE_MEMORY 0x00000100
// #define ISC_REQ_USE_DCE_STYLE 0x00000200
// #define ISC_REQ_DATAGRAM 0x00000400
// #define ISC_REQ_CONNECTION 0x00000800
// #define ISC_REQ_CALL_LEVEL 0x00001000
// #define ISC_REQ_EXTENDED_ERROR 0x00004000
// #define ISC_REQ_STREAM 0x00008000
// #define ISC_REQ_INTEGRITY 0x00010000
ctxReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE;
bool haveInbuffer = false;
bool haveContext = false;
ib.pvBuffer = NULL;
while ( 1 )
{
obd.ulVersion = SECBUFFER_VERSION;
obd.cBuffers = 1;
obd.pBuffers = &ob; // just one buffer
ob.BufferType = SECBUFFER_TOKEN; // preping a token here
ob.cbBuffer = secPackInfo->cbMaxToken;
ob.pvBuffer = LocalAlloc( 0, ob.cbBuffer );
rcISC = (pf->InitializeSecurityContext)( &cred, haveContext?
&cliCtx: NULL,
myTokenSource, ctxReq, 0, SECURITY_NATIVE_DREP /
*SECURITY_NETWORK_DREP*/, haveInbuffer? &ibd: NULL,
0, &cliCtx, &obd, &ctxAttr, &useBefore );
// printf( "ISC(): %08xh\n", rcISC );
if ( ib.pvBuffer != NULL )
{
LocalFree( ib.pvBuffer );
ib.pvBuffer = NULL;
}
if ( rcISC == SEC_I_COMPLETE_AND_CONTINUE || rcISC ==
SEC_I_COMPLETE_NEEDED )
{
if ( pf->CompleteAuthToken != NULL ) // only if implemented
(pf->CompleteAuthToken)( &cliCtx, &obd );
if ( rcISC == SEC_I_COMPLETE_NEEDED )
rcISC = SEC_E_OK;
else if ( rcISC == SEC_I_COMPLETE_AND_CONTINUE )
rcISC = SEC_I_CONTINUE_NEEDED;
}
// send the output buffer off to the server
// warning -- this is machine-dependent! FIX IT!
if ( ob.cbBuffer != 0 )
{
send( s, (const char *) &ob.cbBuffer, sizeof ob.cbBuffer, 0 );
bytesSent += sizeof ob.cbBuffer;
send( s, (const char *) ob.pvBuffer, ob.cbBuffer, 0 );
bytesSent += ob.cbBuffer;
}
LocalFree( ob.pvBuffer );
ob.pvBuffer = NULL;
if ( rcISC != SEC_I_CONTINUE_NEEDED )
break;
// prepare to get the server's response
ibd.ulVersion = SECBUFFER_VERSION;
ibd.cBuffers = 1;
ibd.pBuffers = &ib; // just one buffer
ib.BufferType = SECBUFFER_TOKEN; // preping a token here
// receive the server's response
// MACHINE-DEPENDENT CODE! (Besides, we assume that we
// get the length with a single read, which is not guaranteed)
rc = recv( s, (char *) &ib.cbBuffer, sizeof ib.cbBuffer, 0 );
bytesReceived += sizeof ib.cbBuffer;
ib.pvBuffer = LocalAlloc( 0, ib.cbBuffer );
char *p = (char *) ib.pvBuffer;
int n = ib.cbBuffer;
while ( n )
{
rc = recv( s, p, n, 0 );
// if ( rc == SOCKET_ERROR )
// wserr( rc, "recv" );
// if ( rc == 0 )
// wserr( 999, "recv" );
bytesReceived += rc;
n -= rc;
p += rc;
}
// by now we have an input buffer and a client context
haveInbuffer = true;
haveContext = true;
// loop back for another round
// puts( "looping" );
}
// we arrive here as soon as InitializeSecurityContext()
// returns != SEC_I_CONTINUE_NEEDED.
if ( rcISC != SEC_E_OK )
{
printf( "Oops! ISC() returned %08xh!\n", rcISC );
}
(pf->FreeContextBuffer)( secPackInfo );
//printf( "auth() exiting (%d sent, %d received)\n", bytesSent,
bytesReceived );
free( myTokenSource );
if ( nameAndPwd != 0 )
{
if ( nameAndPwd->Domain != 0 )
free( nameAndPwd->Domain );
if ( nameAndPwd->User != 0 )
free( nameAndPwd->User );
if ( nameAndPwd->Password != 0 )
free( nameAndPwd->Password );
free( nameAndPwd );
}
}
// wserr() displays winsock errors and aborts. No grace there.
void wserr( int rc, const char * const funcname )
{
if ( rc == 0 )
return;
fprintf( stderr, "\nWinsock error %d [gle %d] returned by %s().\n"
"Sorry, no bonus!\n", rc, WSAGetLastError(), funcname );
WSACleanup();
exit( rc );
}
bool auth( SOCKET s, CredHandle& cred, CtxtHandle& srvCtx )
{
int rc;
bool haveToken = true;
SecPkgInfo *secPackInfo;
int bytesReceived = 0, bytesSent = 0;
char buf[256];
DWORD bufsiz = sizeof buf;
puts( "auth() entered" );
rc = (pf->QuerySecurityPackageInfo)( "kerberos", &secPackInfo );
printf( "QSPI(): %08xh\n", rc );
if ( rc != SEC_E_OK )
haveToken = false;
TimeStamp useBefore;
rc = (pf->AcquireCredentialsHandle)( NULL, "kerberos",
SECPKG_CRED_BOTH,
NULL, NULL, NULL, NULL, &cred, &useBefore );
// rc = (pf->AcquireCredentialsHandle)( NULL, "kerberos",
SECPKG_CRED_BOTH,
// NULL, NULL, NULL, NULL, &cred, &useBefore );
printf( "ACH(): %08xh\n", rc );
if ( rc != SEC_E_OK )
haveToken = false;
// input and output buffers
SecBufferDesc obd, ibd;
SecBuffer ob, ib;
DWORD ctxAttr;
bool haveContext = false;
while ( 1 )
{
// prepare to get the server's response
ibd.ulVersion = SECBUFFER_VERSION;
ibd.cBuffers = 1;
ibd.pBuffers = &ib; // just one buffer
ib.BufferType = SECBUFFER_TOKEN; // preping a token here
// receive the client's POD
// MACHINE-DEPENDENT CODE! (Besides, we assume that we
// get the length with a single read, which is not guaranteed)
recv( s, (char *) &ib.cbBuffer, sizeof ib.cbBuffer, 0 );
bytesReceived += sizeof ib.cbBuffer;
ib.pvBuffer = LocalAlloc( 0, ib.cbBuffer );
char *p = (char *) ib.pvBuffer;
int n = ib.cbBuffer;
while ( n )
{
rc = recv( s, p, n, 0 );
if ( rc == SOCKET_ERROR )
wserr( rc, "recv" );
if ( rc == 0 )
wserr( 999, "recv" );
bytesReceived += rc;
n -= rc;
p += rc;
}
// by now we have an input buffer
obd.ulVersion = SECBUFFER_VERSION;
obd.cBuffers = 1;
obd.pBuffers = &ob; // just one buffer
ob.BufferType = SECBUFFER_TOKEN; // preping a token here
ob.cbBuffer = secPackInfo->cbMaxToken;
ob.pvBuffer = LocalAlloc( 0, ob.cbBuffer );
rc = (pf->AcceptSecurityContext)( &cred, haveContext? &srvCtx: NULL,
&ibd, 0,/* SECURITY_NATIVE_DREP */ SECURITY_NATIVE_DREP /
*SECURITY_NETWORK_DREP*/, &srvCtx, &obd, &ctxAttr,
&useBefore );
printf( "ASC(): %08xh\n", rc );
if ( ib.pvBuffer != NULL )
{
LocalFree( ib.pvBuffer );
ib.pvBuffer = NULL;
}
if ( rc == SEC_I_COMPLETE_AND_CONTINUE || rc ==
SEC_I_COMPLETE_NEEDED )
{
if ( pf->CompleteAuthToken != NULL ) // only if implemented
(pf->CompleteAuthToken)( &srvCtx, &obd );
if ( rc == SEC_I_COMPLETE_NEEDED )
rc = SEC_E_OK;
else if ( rc == SEC_I_COMPLETE_AND_CONTINUE )
rc = SEC_I_CONTINUE_NEEDED;
}
// send the output buffer off to the server
// warning -- this is machine-dependent! FIX IT!
if ( rc == SEC_E_OK || rc == SEC_I_CONTINUE_NEEDED )
{
if ( ob.cbBuffer != 0 )
{
send( s, (const char *) &ob.cbBuffer, sizeof ob.cbBuffer, 0 );
bytesSent += sizeof ob.cbBuffer;
send( s, (const char *) ob.pvBuffer, ob.cbBuffer, 0 );
bytesSent += ob.cbBuffer;
}
LocalFree( ob.pvBuffer );
ob.pvBuffer = NULL;
}
if ( rc != SEC_I_CONTINUE_NEEDED )
break;
haveContext = true;
// loop back for another round
puts( "looping" );
}
// we arrive here as soon as InitializeSecurityContext()
// returns != SEC_I_CONTINUE_NEEDED.
if ( rc != SEC_E_OK )
{
printf( "Oops! ASC() returned %08xh!\n", rc );
haveToken = false;
}
GetUserName( buf, &bufsiz );
// now we try to use the context
rc = (pf->ImpersonateSecurityContext)( &srvCtx );
printf( "ImpSC(): %08xh\n", rc );
if ( rc != SEC_E_OK )
{
printf( "Oops! ImpSC() returns %08xh!\n", rc );
haveToken = false;
}
else
{
char buf[256];
DWORD bufsiz = sizeof buf;
printf( "haveToken = %s\n\n", haveToken? "true": "false" );
send( s, (const char *) &haveToken, sizeof haveToken, 0 );
GetUserName( buf, &bufsiz );
printf( "user name: \"%s\"\n", buf );
//(pf->RevertSecurityContext)( &srvCtx );
printf( "RSC(): %08xh\n", rc );
}
//(pf->FreeContextBuffer)( secPackInfo );
printf( "auth() exiting (%d received, %d sent)\n", bytesReceived,
bytesSent );
return haveToken;
}
int Ganesh_Client_Impl(CtxtHandle &srvCtx)
{
char buf[256];
DWORD bufsiz = sizeof buf;
int rc = 0;
//CtxtHandle tmpCtx = srvCtx;
SecPkgContext_Lifespan lspan;
rc = (pf->QueryContextAttributes)(&srvCtx, SECPKG_ATTR_LIFESPAN,
&lspan);
rc = GetLastError();
GetUserName( buf, &bufsiz );
//rc = (pf->ImpersonateSecurityContext)( &srvCtx );
rc = GetLastError();
GetUserName( buf, &bufsiz );
int port, i, errors;
unsigned long naddr;
SOCKET sock;
WSADATA wsadata;
PHOSTENT phe;
PSERVENT pse;
SOCKADDR_IN addr;
HINSTANCE hSecLib;
const char *tokenSource = "win\\gtambat", *server = "ganesh-test1";
//const char *tokenSource = "PUN\\gtambat"/*"Authsamp"*/, *server =
"ganesh-test1";
const char *portstr = "12000", *user = 0, *pwd = 0, *domain = 0;
errors = 0;
if ( server == 0 )
{
//puts( "A server name or IP address must be specified." );
++ errors;
}
if ( portstr == 0 )
{
//puts( "A port name or port number must be specified." );
++ errors;
}
if ( user == 0 && domain != 0 )
{
}
// puts( "No user name was specified, ignoring the domain." );
if ( errors )
{
/* puts( "\nusage: client -s your.server.com -p serverport" );
puts( " [-t token-source] [-u user pwd [-d domain]]" );
puts( "token-source is _required_ for Kerberos and should be
your" );
puts( "current logon name (e.g., \"MYDOMAIN\\felixk\")." );
puts( "If -u is absent, your current credentials will be used." );*/
return 1;
}
initSecLib( hSecLib );
rc = WSAStartup( 2, &wsadata );
//wserr( rc, "WSAStartup" );
sock = socket( AF_INET, SOCK_STREAM, 0 );
if ( sock == INVALID_SOCKET )
{
rc = -1;
}
else
{
rc = 0;
}
addr.sin_family = AF_INET;
// try numeric IP address first (inet_addr)
naddr = inet_addr( server );
if ( naddr != INADDR_NONE )
{
addr.sin_addr.s_addr = naddr;
}
else
{
phe = gethostbyname( server );
// if ( phe == NULL )
// wserr( 1, "gethostbyname" );
addr.sin_addr.s_addr = *( (unsigned long *) (phe->h_addr) );
memcpy( (char *) &addr.sin_addr, phe->h_addr, phe->h_length );
}
// try numeric protocol first
port = atoi( portstr );
if ( port > 0 && port < 32768 )
addr.sin_port = htons( (short) port );
else
{
pse = getservbyname( portstr, "tcp" );
// if ( pse == NULL )
// wserr( 1, "getservbyname" );
addr.sin_port = pse->s_port;
}
CredHandle cred;
CtxtHandle cliCtx;
rc = connect( sock, (SOCKADDR *) &addr, sizeof addr );
//wserr( rc, "connect" );
struct sockaddr name;
int namelen = sizeof name;;
rc = getsockname( sock, &name, &namelen );
/*wserr( rc, "getsockname()" );
printf( "I am %u.%u.%u.%u\n", (unsigned int) (unsigned char)
name.sa_data[2],
(unsigned int) (unsigned char) name.sa_data[3], (unsigned int)
(unsigned char) name.sa_data[4],
(unsigned int) (unsigned char) name.sa_data[5] );*/
Ganesh_auth( sock, cred, cliCtx, tokenSource, user, pwd, domain ); //
this does the real work
// use the authenticated connection here
bool haveToken = false;
rc = recv( sock, (char *) &haveToken, sizeof haveToken, 0 );
if ( rc != sizeof haveToken )
{
rc = 999;
}
// wserr( 999, "result-recv" );
if ( haveToken )
puts( "That seems to have worked." );
else
puts( "Oops! Wrong user name or password?" );
// the server is probably impersonating us by now
// this is where the client and server talk business
// clean up
(pf->DeleteSecurityContext)( &cliCtx );
(pf->FreeCredentialHandle)( &cred );
rc = closesocket( sock );
wserr( rc, "closesocket" );
rc = WSACleanup();
wserr( rc, "WSACleanup" );
__try
{
FreeLibrary( hSecLib );
}
__except ( 1 )
{
// puts( "Freelibrary( security.dll ) caused an access violation.
Yuck." );
}
return 0;
}
struct CapName
{
DWORD bits;
const char *name;
const char *comment;
} capNames[] = {
{ SECPKG_FLAG_INTEGRITY, "SECPKG_FLAG_INTEGRITY", "Supports integrity
on messages" },
{ SECPKG_FLAG_PRIVACY, "SECPKG_FLAG_PRIVACY", "Supports privacy
(confidentiality)" },
{ SECPKG_FLAG_TOKEN_ONLY, "SECPKG_FLAG_TOKEN_ONLY", "Only security
token needed" },
{ SECPKG_FLAG_DATAGRAM, "SECPKG_FLAG_DATAGRAM", "Datagram RPC
support" },
{ SECPKG_FLAG_CONNECTION, "SECPKG_FLAG_CONNECTION", "Connection
oriented RPC support" },
{ SECPKG_FLAG_MULTI_REQUIRED, "SECPKG_FLAG_MULTI_REQUIRED", "Full 3-
leg required for re-auth." },
{ SECPKG_FLAG_CLIENT_ONLY, "SECPKG_FLAG_CLIENT_ONLY", "Server side
functionality not available" },
{ SECPKG_FLAG_EXTENDED_ERROR, "SECPKG_FLAG_EXTENDED_ERROR", "Supports
extended error msgs" },
{ SECPKG_FLAG_IMPERSONATION, "SECPKG_FLAG_IMPERSONATION", "Supports
impersonation" },
{ SECPKG_FLAG_ACCEPT_WIN32_NAME, "SECPKG_FLAG_ACCEPT_WIN32_NAME",
"Accepts Win32 names" },
{ SECPKG_FLAG_STREAM, "SECPKG_FLAG_STREAM", "Supports stream
semantics" },
{ SECPKG_FLAG_NEGOTIABLE, "SECPKG_FLAG_NEGOTIABLE", "Can be used by
the negotiate package" },
{ SECPKG_FLAG_GSS_COMPATIBLE, "SECPKG_FLAG_GSS_COMPATIBLE", "GSS
Compatibility Available" },
{ SECPKG_FLAG_LOGON, "SECPKG_FLAG_LOGON", "Supports common
LsaLogonUser" },
{ SECPKG_FLAG_ASCII_BUFFERS, "SECPKG_FLAG_ASCII_BUFFERS", "Token
Buffers are in ASCII" },
{ 0xffffffffL, "(fence)", "(fence)" }
};
void initSecLib( HINSTANCE& hSec )
{
PSecurityFunctionTable (*pSFT)( void );
hSec = LoadLibrary( "security.dll" );
pSFT = (PSecurityFunctionTable (*)( void )) GetProcAddress( hSec,
"InitSecurityInterfaceA" );
if ( pSFT == NULL )
{
exit( 1 );
}
pf = pSFT();
if ( pf == NULL )
{
exit( 1 );
}
SECURITY_STATUS rc;
DWORD numPacks = 0, i, j;
SecPkgInfo *pPacks = NULL;
rc = (pf->EnumerateSecurityPackages)( &numPacks, &pPacks );
if ( rc != 0 )
{
exit( 1 );
}
for ( i = 0; i < numPacks; ++ i )
{
for ( j = 0; capNames[j].bits != 0xffffffffL; ++ j )
{
//if ( ( capNames[j].bits & pPacks[i].fCapabilities ) == capNames
[j].bits )
//printf( " %s (%s)\n", capNames[j].name, capNames
[j].comment );
}
}
if ( pPacks != NULL )
(pf->FreeContextBuffer)( pPacks );
}
int main( int argc, char *argv[] )
{
int rc, port, addrlen;
HINSTANCE hSecLib;
CtxtHandle srvCtx;
bool haveToken;
SOCKET sock, s;
WSADATA wsadata;
PSERVENT pse;
SOCKADDR_IN addr;
HANDLE threadRet;
char buf[256];
DWORD bufsiz = sizeof buf;
if ( argc != 2 )
{
puts( "usage: server portnumber" );
return 1;
}
initSecLib( hSecLib );
rc = WSAStartup( 2, &wsadata );
wserr( rc, "WSAStartup" );
sock = socket( AF_INET, SOCK_STREAM, 0 );
if ( sock == INVALID_SOCKET )
wserr( 999, "socket" );
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
// try numeric protocol first
port = atoi( argv[1] );
if ( port > 0 && port < 32768 )
addr.sin_port = htons( (short) port );
else
{
pse = getservbyname( argv[1], "tcp" );
if ( pse == NULL )
wserr( 1, "getservbyname" );
addr.sin_port = pse->s_port;
}
rc = bind( sock, (SOCKADDR *) &addr, sizeof addr );
wserr( rc, "bind" );
rc = listen( sock, 2 );
wserr( rc, "listen" );
CredHandle cred;
while ( 1 )
{
addrlen = sizeof addr;
s = accept( sock, (SOCKADDR *) &addr, &addrlen );
if ( s == INVALID_SOCKET )
wserr( s, "accept" );
haveToken = auth( s, cred, srvCtx );
// now we talk to the client
printf( "haveToken = %s\n\n", haveToken? "true": "false" );
send( s, (const char *) &haveToken, sizeof haveToken, 0 );
// clean up
// Modified by Ganesh
/*(pf->DeleteSecurityContext)( &srvCtx );
(pf->FreeCredentialHandle)( &cred );
closesocket( s );*/
break;
}
int j;
puts("/n/n Should I start client implemenation within server ?: ");
scanf("%d",&j);
LPVOID threadParam = &srvCtx;
DWORD threadId;
//PROCESS_INFORMATION Pi;
//STARTUPINFO Si;
//HANDLE hTokenNew = NULL, hTokenDup = NULL;
//ZeroMemory( &Pi,sizeof(Pi));
//ZeroMemory( &Si, sizeof( STARTUPINFO ) );
//Si.cb = sizeof( STARTUPINFO );
// Si.lpDesktop = "winsta0\\default";
//GetUserName( buf, &bufsiz );
//rc = (pf->ImpersonateSecurityContext)( &srvCtx );
//rc = GetLastError();
//GetUserName( buf, &bufsiz );
//rc = CreateProcess("C:\\WINDOWS\\system32\\notepad.exe","C:\\WINDOWS
\\system32\\notepad.exe", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS,
NULL, NULL, &Si, &Pi);
rc = GetLastError();
//threadRet = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)
Ganesh_Client_Impl, threadParam, 0, &threadId);
j = Ganesh_Client_Impl(srvCtx);
WaitForSingleObject(threadRet,INFINITE);
CloseHandle( threadRet );
FreeLibrary( hSecLib );
return 0;
}
.
- Prev by Date: Dataset or xml in remoting.
- Next by Date: Remoting performance degradation when returning custom datasets
- Previous by thread: Dataset or xml in remoting.
- Next by thread: Remoting performance degradation when returning custom datasets
- Index(es):
Relevant Pages
|