Author: hbelusca Date: Thu Jun 22 00:51:51 2017 New Revision: 75164
URL: http://svn.reactos.org/svn/reactos?rev=75164&view=rev Log: [SECUR32_APITEST]: Add the beginnings of an apitest for secur32, based on code by Samuel Serapion & MSDN. What needs to be fixed here, is the client/server code to communicate the results back to the main test app being running. Work in progress.
Added: branches/sspi-bringup/rostests/apitests/secur32/ branches/sspi-bringup/rostests/apitests/secur32/CMakeLists.txt (with props) branches/sspi-bringup/rostests/apitests/secur32/client1.c (with props) branches/sspi-bringup/rostests/apitests/secur32/client2_msdn.c (with props) branches/sspi-bringup/rostests/apitests/secur32/client_server.c (with props) branches/sspi-bringup/rostests/apitests/secur32/client_server.h (with props) branches/sspi-bringup/rostests/apitests/secur32/server1.c (with props) branches/sspi-bringup/rostests/apitests/secur32/server2_msdn.c (with props) branches/sspi-bringup/rostests/apitests/secur32/testlist.c (with props) branches/sspi-bringup/rostests/apitests/secur32/utils.c (with props) Modified: branches/sspi-bringup/rostests/apitests/CMakeLists.txt
Modified: branches/sspi-bringup/rostests/apitests/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/C... ============================================================================== --- branches/sspi-bringup/rostests/apitests/CMakeLists.txt [iso-8859-1] (original) +++ branches/sspi-bringup/rostests/apitests/CMakeLists.txt [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -24,6 +24,7 @@ add_subdirectory(pefile) add_subdirectory(powrprof) add_subdirectory(sdk) +add_subdirectory(secur32) add_subdirectory(setupapi) add_subdirectory(shell32) add_subdirectory(spoolss)
Added: branches/sspi-bringup/rostests/apitests/secur32/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/CMakeLists.txt (added) +++ branches/sspi-bringup/rostests/apitests/secur32/CMakeLists.txt [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,14 @@ + +list(APPEND SOURCE + client_server.c +# client1.c + client2_msdn.c +# server1.c + server2_msdn.c + utils.c + testlist.c) + +add_executable(secur32_apitest ${SOURCE}) +set_module_type(secur32_apitest win32cui) +add_importlibs(secur32_apitest advapi32 secur32 ws2_32 msvcrt kernel32) +add_rostests_file(TARGET secur32_apitest)
Propchange: branches/sspi-bringup/rostests/apitests/secur32/CMakeLists.txt ------------------------------------------------------------------------------ svn:eol-style = native
Added: branches/sspi-bringup/rostests/apitests/secur32/client1.c URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/client1.c (added) +++ branches/sspi-bringup/rostests/apitests/secur32/client1.c [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,442 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Tests for client/server authentication via secur32 API. + * PROGRAMMERS: Samuel Serapión + */ + +#include "client_server.h" + +#define PackageName L"NTLM" + +PSecurityFunctionTable client1_SecFuncTable = NULL; + +void auth( + IN SOCKET s, + OUT PCredHandle pCred, + OUT PCtxtHandle pCliCtx, + IN LPCWSTR tokenSource, + IN LPCWSTR name OPTIONAL, + IN LPCWSTR pwd OPTIONAL, + IN LPCWSTR domain OPTIONAL) +{ + int rc, rcISC; + SecPkgInfo *secPackInfo; + SEC_WINNT_AUTH_IDENTITY_W *nameAndPwd = NULL; + int bytesReceived = 0, bytesSent = 0; + LPWSTR myTokenSource; + + TimeStamp useBefore; + + /* Input and output buffers */ + SecBufferDesc obd, ibd; + SecBuffer ob, ib; + + DWORD ctxReq, ctxAttr; + + BOOL haveInbuffer = FALSE; + BOOL haveContext = FALSE; + + trace("auth() entered\n"); + + // the arguments to ISC() is not const ... for once, I decided + // on creating writable copies instead of using a brutalizing cast. + myTokenSource = _wcsdup(tokenSource); + + if (name != NULL) + { + nameAndPwd = (SEC_WINNT_AUTH_IDENTITY_W *)malloc(sizeof(*nameAndPwd)); + memset(nameAndPwd, '\0', sizeof(*nameAndPwd)); + nameAndPwd->Domain = (unsigned short *)_wcsdup(domain? domain: L""); + nameAndPwd->DomainLength = domain? wcslen(domain): 0; + nameAndPwd->User = (unsigned short *)_wcsdup(name? name: L""); + nameAndPwd->UserLength = name? wcslen(name): 0; + nameAndPwd->Password = (unsigned short *)_wcsdup(pwd? pwd: L""); + nameAndPwd->PasswordLength = pwd? wcslen(pwd): 0; + nameAndPwd->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + } + + rc = client1_SecFuncTable->QuerySecurityPackageInfo(PackageName, &secPackInfo); + trace("QuerySecurityPackageInfo(NTLM): returned %08xh\n", rc); + + rc = client1_SecFuncTable->AcquireCredentialsHandle(NULL, PackageName, SECPKG_CRED_OUTBOUND, + NULL, nameAndPwd, NULL, NULL, pCred, &useBefore); + trace("AcquireCredentialsHandle(NTLM): returned %08xh\n", rc); + + ctxReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE; + + ib.pvBuffer = NULL; + + while (1) + { + char* p; + int n; + + 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 = client1_SecFuncTable->InitializeSecurityContext(pCred, haveContext? pCliCtx: NULL, + myTokenSource, ctxReq, 0, SECURITY_NATIVE_DREP, haveInbuffer? &ibd: NULL, + 0, pCliCtx, &obd, &ctxAttr, &useBefore); + trace("InitializeSecurityContext(): returned %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 (client1_SecFuncTable->CompleteAuthToken != NULL) // only if implemented + client1_SecFuncTable->CompleteAuthToken(pCliCtx, &obd); + if (rcISC == SEC_I_COMPLETE_NEEDED) + rcISC = SEC_E_OK; + else if (rcISC == SEC_I_COMPLETE_AND_CONTINUE) + rcISC = SEC_I_CONTINUE_NEEDED; + trace("SEC_I_COMPLETE_AND_CONTINUE or SEC_I_COMPLETE_NEEDED\n"); + } + + /* Send the output buffer off to the server */ + // WARNING -- this is machine-dependent! FIX IT! + if (ob.cbBuffer != 0) + { + send(s, (char*)&ob.cbBuffer, sizeof(ob.cbBuffer), 0); + bytesSent += sizeof(ob.cbBuffer); + send(s, (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); + + p = (char*)ib.pvBuffer; + n = ib.cbBuffer; + while (n) + { + rc = recv(s, p, n, 0); + if (rc == SOCKET_ERROR) + wserr(rc, L"recv"); + if (rc == 0) + wserr(999, L"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 */ + trace("looping"); + } + + /* + * We arrive here as soon as InitializeSecurityContext() + * returns != SEC_I_CONTINUE_NEEDED. + */ + if (rcISC != SEC_E_OK) + err("Oops! InitializeSecurityContext() returned %08xh!\n", rcISC); + + client1_SecFuncTable->FreeContextBuffer(secPackInfo); + trace("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); + } +} + +int client1_main( + char *server, + char *portstr, + char *tokenSource, + char *user, + char *pwd, + char *domain) +{ + int rc, port; + unsigned long naddr; + SOCKET sock; + WSADATA wsadata; + PHOSTENT phe; + PSERVENT pse; + SOCKADDR_IN addr; + HINSTANCE hSecLib; + + CredHandle cred; + CtxtHandle cliCtx; + + struct sockaddr name; + int namelen = sizeof(name); + + size_t converted, strsize; + LPWSTR tokenW, userW, pwdW, domainW; + BOOL haveToken = FALSE; + + initSecLib(&hSecLib, &client1_SecFuncTable); + + rc = WSAStartup(2, &wsadata); + wserr(rc, L"WSAStartup"); + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) + wserr(999, L"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, L"gethostbyname"); + addr.sin_addr.s_addr = *((unsigned long *)(phe->h_addr)); + memcpy((LPWSTR)&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, L"getservbyname"); + addr.sin_port = pse->s_port; + } + + rc = connect(sock, (SOCKADDR *)&addr, sizeof(addr)); + wserr(rc, L"connect"); + + rc = getsockname(sock, &name, &namelen); + wserr(rc, L"getsockname()"); + wprintf(L"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]); + + strsize = strlen(tokenSource)+1; + tokenW = (LPWSTR)malloc(strsize*sizeof(WCHAR)); + mbstowcs_s(&converted,tokenW,strsize,tokenSource,_TRUNCATE); + + strsize = strlen(user)+1; + userW = (LPWSTR)malloc(strsize*sizeof(WCHAR)); + mbstowcs_s(&converted,userW,strsize,user,_TRUNCATE); + + strsize = strlen(user)+1; + pwdW = (LPWSTR)malloc(strsize*sizeof(WCHAR)); + mbstowcs_s(&converted,pwdW,strsize,user,_TRUNCATE); + + strsize = strlen(user)+1; + domainW = (LPWSTR)malloc(strsize*sizeof(WCHAR)); + mbstowcs_s(&converted,domainW,strsize,user,_TRUNCATE); + + auth(sock, &cred, &cliCtx, tokenW, userW, pwdW, domainW); // this does the real work + + free(tokenW); + free(userW); + free(pwdW); + free(domainW); + + + /* Use the authenticated connection here */ + haveToken = FALSE; + rc = recv(sock, (char*)&haveToken, sizeof(haveToken), 0); + if (rc != sizeof(haveToken)) + wserr(999, L"result-recv"); + + if (haveToken) + wprintf(L"That seems to have worked."); + else + wprintf(L"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 */ + client1_SecFuncTable->DeleteSecurityContext(&cliCtx); + client1_SecFuncTable->FreeCredentialHandle(&cred); + + rc = closesocket(sock); + wserr(rc, L"closesocket"); + + rc = WSACleanup(); + wserr(rc, L"WSACleanup"); + + FreeLibrary(hSecLib); + + return 0; +} + +#if 0 +int main(int argc, _TCHAR* argv[]) +{ + int i, errors; + + char *tokenSource = "Authsamp"; + char *server = "127.0.0.1"; + char *portstr = "55", *user = "", *pwd = "", *domain = ""; + + errors = 0; + for (i = 1; i < argc; ++i) + { + if (argv[i][0] != '-' && argv[i][0] != '/') + { + wprintf(L""%s" is not a valid switch.\n", argv[i]); + ++errors; + continue; + } + + switch (argv[i][1]) + { + case L's': + //if (i >= argc - 1) + //{ + // wprintf(L""%s" requires an argument.\n", argv[i]); + // ++errors; + //} + //else if (server != 0) + //{ + // wprintf(L""%s" has already been used.\n", argv[i++]); + // ++errors; + //} + //else + // server = argv[++i]; + break; + case 'p': + //if (i >= argc - 1) + //{ + // wprintf(L""%s" requires an argument.\n", argv[i]); + // ++errors; + //} + //else if (portstr != 0) + //{ + // wprintf(L""%s" has already been used.\n", argv[i++]); + // ++errors; + //} + //else + // portstr = argv[++i]; + break; + case 't': + if (i >= argc - 1) + { + wprintf(L""%s" requires an argument.\n", argv[i]); + ++errors; + } + else if (tokenSource != NULL) + { + wprintf(L""%s" has already been used.\n", argv[i++]); + ++errors; + } + else + { + tokenSource = argv[++i]; + } + break; + case 'd': + if (i >= argc - 1) + { + wprintf(L""%s" requires an argument.\n", argv[i]); + ++errors; + } + else if (domain != NULL) + { + wprintf(L""%s" has already been used.\n", argv[i++]); + ++errors; + } + else + { + domain = argv[++i]; + } + break; + case 'u': + if (i >= argc - 2) + { + wprintf(L""%s" requires two arguments.\n", argv[i++]); + ++errors; + } + else if (user != NULL) + { + wprintf(L""%s" has already been used.\n", argv[i]); + i += 2; + ++errors; + } + else + { + user = argv[++i]; + pwd = argv[++i]; + } + break; + default: + wprintf(L""%s" is not a valid switch.\n", argv[i]); + ++errors; + break; + } + } + + if (server == NULL) + { + wprintf(L"A server name or IP address must be specified.\n"); + ++errors; + } + + if (portstr == NULL) + { + wprintf(L"A port name or port number must be specified.\n"); + ++errors; + } + + if (user == NULL && domain != NULL) + wprintf(L"No user name was specified, ignoring the domain.\n"); + + if (errors) + { + wprintf(L"\nusage: client -s your.server.com -p serverport"); + wprintf(L" [-t token-source] [-u user pwd [-d domain]]\n"); + wprintf(L"Token-source is _required_ for Kerberos and should be your"); + wprintf(L" current logon name (e.g., "MYDOMAIN\mypc")."); + wprintf(L"If -u is absent, your current credentials will be used.\n"); + return 1; + } + + return client1_main(server, portstr, tokenSource, user, pwd, domain); +} +#endif
Propchange: branches/sspi-bringup/rostests/apitests/secur32/client1.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: branches/sspi-bringup/rostests/apitests/secur32/client2_msdn.c URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/client2_msdn.c (added) +++ branches/sspi-bringup/rostests/apitests/secur32/client2_msdn.c [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,520 @@ +// +// MSDN Example "Using SSPI with a Windows Sockets Client" +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380536(v=vs.85).a... +// + +//-------------------------------------------------------------------- +// Client-side program to establish an SSPI socket connection +// with a server and exchange messages. + +//-------------------------------------------------------------------- +// Define macros and constants. + +#include "client_server.h" + +#define g_usPort 2000 + +#define BIG_BUFF 2048 + +#define cbMaxMessage 12000 +#define MessageAttribute ISC_REQ_CONFIDENTIALITY + +BOOL +client2_DoAuthentication( + IN LPCTSTR TargetName, + IN LPCTSTR PackageName, + IN SOCKET s, + IN PCredHandle hCred, + IN PSecHandle hcText); + +BOOL +GenClientContext( + PBYTE pIn, + DWORD cbIn, + PBYTE pOut, + DWORD *pcbOut, + BOOL *pfDone, + LPCTSTR pszTarget, + LPCTSTR PackageName, + PCredHandle hCred, + PSecHandle hcText); + +//-------------------------------------------------------------------- +// ConnectAuthSocket establishes an authenticated socket connection +// with a server and initializes needed security package resources. + +BOOL +client2_ConnectAuthSocket( + IN LPCTSTR ServerName, + IN LPCTSTR TargetName, + IN LPCTSTR PackageName, + OUT SOCKET *s, + OUT PCredHandle hCred, + OUT PSecHandle hcText) +{ + unsigned long ulAddress; + struct hostent *pHost; + SOCKADDR_IN sin; + +#ifdef UNICODE + char AnsiServerName[256]; + + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, + ServerName, -1, AnsiServerName, _countof(AnsiServerName), NULL, NULL); +#else +#define AnsiServerName ServerName +#endif + + /* Lookup the server's address */ + ulAddress = inet_addr(AnsiServerName); + + if (ulAddress == INADDR_NONE) + { + pHost = gethostbyname(AnsiServerName); + if (!pHost) + fatal_error("Unable to resolve host name "); + + memcpy((char *)&ulAddress, pHost->h_addr, pHost->h_length); + } + +#ifndef UNICODE +#undef AnsiServerName +#endif + + /* Create the socket */ + *s = socket(PF_INET, SOCK_STREAM, 0); + if (*s == INVALID_SOCKET) + fatal_error("Unable to create socket\n"); + + trace("client socket %x created.\n",*s); + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ulAddress; + sin.sin_port = htons(g_usPort); + + /* Connect to the server */ + if (connect(*s, (LPSOCKADDR)&sin, sizeof(sin))) + { + closesocket(*s); + fatal_error("Connect failed\n"); + } + + /* Authenticate the connection */ + if (!client2_DoAuthentication(TargetName, PackageName, + *s, hCred, hcText)) + { + closesocket(*s); + fatal_error("Authentication failed\n"); + } + + return TRUE; +} + +BOOL +client2_DoAuthentication( + IN LPCTSTR TargetName, + IN LPCTSTR PackageName, + IN SOCKET s, + IN PCredHandle hCred, + IN PSecHandle hcText) +{ + BOOL Success; + BOOL fDone = FALSE; + DWORD cbOut = 0; + DWORD cbIn = 0; + PBYTE pInBuf; + PBYTE pOutBuf; + + if (!(pInBuf = (PBYTE)malloc(cbMaxMessage))) + fatal_error("Memory allocation "); + + if (!(pOutBuf = (PBYTE)malloc(cbMaxMessage))) + fatal_error("Memory allocation "); + + cbOut = cbMaxMessage; + Success = GenClientContext(NULL, + 0, + pOutBuf, + &cbOut, + &fDone, + TargetName, + PackageName, + hCred, + hcText); + ok(Success, "GenClientContext failed\n"); + if (!Success) + { + err("GenClientContext failed!\n"); + return FALSE; + } + + if (!SendMsg(s, pOutBuf, cbOut)) + fatal_error("Send message failed "); + + while (!fDone) + { + if (!ReceiveMsg(s, pInBuf, cbMaxMessage, &cbIn)) + fatal_error("Receive message failed "); + + cbOut = cbMaxMessage; + Success = GenClientContext(pInBuf, + cbIn, + pOutBuf, + &cbOut, + &fDone, + TargetName, + PackageName, + hCred, + hcText); + ok(Success, "GenClientContext failed\n"); + if (!Success) + { + fatal_error("GenClientContext failed"); + } + if (!SendMsg(s, pOutBuf, cbOut)) + fatal_error("Send message 2 failed "); + } + + trace("DoAuthentication end\n"); + free(pInBuf); + free(pOutBuf); + return TRUE; +} + +BOOL +GenClientContext( + PBYTE pIn, + DWORD cbIn, + PBYTE pOut, + DWORD *pcbOut, + BOOL *pfDone, + LPCTSTR pszTarget, + LPCTSTR PackageName, + PCredHandle hCred, + PSecHandle hcText) +{ + SECURITY_STATUS ss; + TimeStamp Lifetime; + SecBufferDesc OutBuffDesc; + SecBuffer OutSecBuff; + SecBufferDesc InBuffDesc; + SecBuffer InSecBuff; + ULONG ContextAttributes; + + if (!pIn) + { + ss = AcquireCredentialsHandle(NULL, + (LPTSTR)PackageName, + SECPKG_CRED_OUTBOUND, + NULL, + NULL, + NULL, + NULL, + hCred, + &Lifetime); + ok(SEC_SUCCESS(ss), "AcquireCredentialsHandle failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + fatal_error("AcquireCreds failed "); + } + + //-------------------------------------------------------------------- + // Prepare the buffers. + + OutBuffDesc.ulVersion = 0; + OutBuffDesc.cBuffers = 1; + OutBuffDesc.pBuffers = &OutSecBuff; + + OutSecBuff.cbBuffer = *pcbOut; + OutSecBuff.BufferType = SECBUFFER_TOKEN; + OutSecBuff.pvBuffer = pOut; + + /* + * The input buffer is created only if a message has been received + * from the server. + */ + if (pIn) + { + InBuffDesc.ulVersion = 0; + InBuffDesc.cBuffers = 1; + InBuffDesc.pBuffers = &InSecBuff; + + InSecBuff.cbBuffer = cbIn; + InSecBuff.BufferType = SECBUFFER_TOKEN; + InSecBuff.pvBuffer = pIn; + + ss = InitializeSecurityContext(hCred, + hcText, + (LPTSTR)pszTarget, + MessageAttribute, + 0, + SECURITY_NATIVE_DREP, + &InBuffDesc, + 0, + hcText, + &OutBuffDesc, + &ContextAttributes, + &Lifetime); + } + else + { + ss = InitializeSecurityContext(hCred, + NULL, + (LPTSTR)pszTarget, + MessageAttribute, + 0, + SECURITY_NATIVE_DREP, + NULL, + 0, + hcText, + &OutBuffDesc, + &ContextAttributes, + &Lifetime); + } + + ok(SEC_SUCCESS(ss), "InitializeSecurityContext failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + fatal_error("InitializeSecurityContext failed "); + + /* If necessary, complete the token */ + if ((ss == SEC_I_COMPLETE_NEEDED) || + (ss == SEC_I_COMPLETE_AND_CONTINUE)) + { + ss = CompleteAuthToken(hcText, &OutBuffDesc); + ok(SEC_SUCCESS(ss), "CompleteAuthToken failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + err("complete failed: 0x%08x\n", ss); + return FALSE; + } + } + + *pcbOut = OutSecBuff.cbBuffer; + + *pfDone = !((ss == SEC_I_CONTINUE_NEEDED) || + (ss == SEC_I_COMPLETE_AND_CONTINUE)); + + trace("Token buffer generated (%lu bytes):\n", OutSecBuff.cbBuffer); + PrintHexDump(OutSecBuff.cbBuffer, (PBYTE)OutSecBuff.pvBuffer); + return TRUE; + +} + +PBYTE +DecryptThis( + PBYTE pBuffer, + LPDWORD pcbMessage, + PSecHandle hCtxt, + ULONG cbSecurityTrailer) +{ + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[2]; + ULONG ulQop = 0; + PBYTE pSigBuffer; + PBYTE pDataBuffer; + DWORD SigBufferSize; + + /* + * By agreement, the server encrypted the message and set the size + * of the trailer block to be just what it needed. DecryptMessage + * needs the size of the trailer block. + * The size of the trailer is in the first DWORD of the + * message received. + */ + SigBufferSize = *((DWORD*)pBuffer); + trace("data before decryption including trailer (%lu bytes):\n", + *pcbMessage); + PrintHexDump(*pcbMessage, (PBYTE)pBuffer); + + /* + * By agreement, the server placed the trailer at the beginning + * of the message that was sent immediately following the trailer + * size DWORD. + */ + pSigBuffer = pBuffer + sizeof(DWORD); + + /* The data comes after the trailer */ + pDataBuffer = pSigBuffer + SigBufferSize; + + /* *pcbMessage is reset to the size of just the encrypted bytes */ + *pcbMessage = *pcbMessage - SigBufferSize - sizeof(DWORD); + + /* + * Prepare the buffers to be passed to the DecryptMessage function + */ + + BuffDesc.ulVersion = 0; + BuffDesc.cBuffers = ARRAYSIZE(SecBuff); + BuffDesc.pBuffers = SecBuff; + + SecBuff[0].cbBuffer = SigBufferSize; + SecBuff[0].BufferType = SECBUFFER_TOKEN; + SecBuff[0].pvBuffer = pSigBuffer; + + SecBuff[1].cbBuffer = *pcbMessage; + SecBuff[1].BufferType = SECBUFFER_DATA; + SecBuff[1].pvBuffer = pDataBuffer; + + ss = DecryptMessage(hCtxt, &BuffDesc, 0, &ulQop); + ok(SEC_SUCCESS(ss), "DecryptMessage failed"); + + /* Return a pointer to the decrypted data. The trailer data is discarded. */ + return pDataBuffer; +} + +PBYTE +VerifyThis( + PBYTE pBuffer, + LPDWORD pcbMessage, + PSecHandle hCtxt, + ULONG cbMaxSignature) +{ + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[2]; + ULONG ulQop = 0; + PBYTE pSigBuffer; + PBYTE pDataBuffer; + + /* + * The global cbMaxSignature is the size of the signature + * in the message received. + */ + trace("data before verifying (including signature):\n"); + PrintHexDump(*pcbMessage, pBuffer); + + /* + * By agreement with the server, + * the signature is at the beginning of the message received, + * and the data that was signed comes after the signature. + */ + pSigBuffer = pBuffer; + pDataBuffer = pBuffer + cbMaxSignature; + + /* The size of the message is reset to the size of the data only */ + *pcbMessage = *pcbMessage - cbMaxSignature; + + /* + * Prepare the buffers to be passed to the signature verification function + */ + + BuffDesc.ulVersion = 0; + BuffDesc.cBuffers = ARRAYSIZE(SecBuff); + BuffDesc.pBuffers = SecBuff; + + SecBuff[0].cbBuffer = cbMaxSignature; + SecBuff[0].BufferType = SECBUFFER_TOKEN; + SecBuff[0].pvBuffer = pSigBuffer; + + SecBuff[1].cbBuffer = *pcbMessage; + SecBuff[1].BufferType = SECBUFFER_DATA; + SecBuff[1].pvBuffer = pDataBuffer; + + ss = VerifySignature(hCtxt, &BuffDesc, 0, &ulQop); + ok(SEC_SUCCESS(ss), "VerifySignature failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + err("VerifyMessage failed"); + else + trace("Message was properly signed.\n"); + + return pDataBuffer; +} + +DWORD WINAPI +client2_start( + IN LPCTSTR ServerName, + IN LPCTSTR TargetName, + IN LPCTSTR PackageName) +{ + SOCKET Client_Socket; + BYTE Data[BIG_BUFF]; + PCHAR pMessage; + CredHandle hCred; + SecHandle hCtxt; + SECURITY_STATUS ss; + DWORD cbRead; + ULONG cbMaxSignature; + ULONG cbSecurityTrailer; + SecPkgContext_Sizes SecPkgContextSizes; + SecPkgContext_NegotiationInfo SecPkgNegInfo; + + /* Connect to a server */ + if (!client2_ConnectAuthSocket(ServerName, TargetName, PackageName, + &Client_Socket, &hCred, &hCtxt)) + { + fatal_error("Unable to authenticate server connection \n"); + } + + /* + * An authenticated session with a server has been established. + * Receive and manage a message from the server. + * First, find and display the name of the negotiated + * SSP and the size of the signature and the encryption + * trailer blocks for this SSP. + */ + ss = QueryContextAttributes(&hCtxt, + SECPKG_ATTR_NEGOTIATION_INFO, + &SecPkgNegInfo); + ok(SEC_SUCCESS(ss), "QueryContextAttributes failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + fatal_error("QueryContextAttributes failed "); + else + trace("Package Name: %S\n", SecPkgNegInfo.PackageInfo->Name); + + ss = QueryContextAttributes(&hCtxt, + SECPKG_ATTR_SIZES, + &SecPkgContextSizes); + ok(SEC_SUCCESS(ss), "Querycontext2 failed!"); + + cbMaxSignature = SecPkgContextSizes.cbMaxSignature; + cbSecurityTrailer = SecPkgContextSizes.cbSecurityTrailer; + + + /* + * Decrypt and display the message from the server + */ + if (!ReceiveBytes(Client_Socket, + Data, + BIG_BUFF, + &cbRead)) + { + fatal_error("No response from server "); + } + + ok(cbRead != 0, "Zero bytes received "); + + pMessage = (PCHAR)DecryptThis(Data, + &cbRead, + &hCtxt, + cbSecurityTrailer); + trace("message len: %d message: %.*S\n", cbRead, cbRead/sizeof(TCHAR), pMessage); + + /* Terminate socket and security package */ + DeleteSecurityContext(&hCtxt); + FreeCredentialHandle(&hCred); + shutdown(Client_Socket, 2); + closesocket(Client_Socket); + + return 0; // EXIT_SUCCESS +} + +DWORD +client2_main( + IN LPCTSTR ServerName, // ServerName must be defined as the name of the computer running the server sample. Example: _T("127.0.0.1") + IN LPCTSTR TargetName, // TargetName must be defined as the logon name of the user running the server program. Example: _T("") + IN LPCTSTR PackageName) // Example: _T("NTLM"), or _T("Negotiate") +{ + DWORD dwRet; + WSADATA wsaData; + + /* Startup WSA */ + if (WSAStartup(0x0101, &wsaData)) + fatal_error("Could not initialize winsock.\n"); + + /* Start the client */ + dwRet = client2_start(ServerName, TargetName, PackageName); + + /* Shutdown WSA and return */ + WSACleanup(); + return dwRet; +}
Propchange: branches/sspi-bringup/rostests/apitests/secur32/client2_msdn.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: branches/sspi-bringup/rostests/apitests/secur32/client_server.c URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/client_server.c (added) +++ branches/sspi-bringup/rostests/apitests/secur32/client_server.c [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,334 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Tests for client/server authentication via secur32 API. + * PROGRAMMERS: Samuel Serapión + * Hermes Belusca-Maito + */ + +#include "client_server.h" +#include <strsafe.h> + +#ifdef SAMUEL_TESTS +// NOTE: If enabled, re-include both client1.c and server1.c in the compilation. + +int client1_main( + char *server, + char *portstr, + char *tokenSource, + char *user, + char *pwd, + char *domain); + +int server1_main( + char *portstr); + +#endif + +DWORD +server2_main( + IN LPCTSTR PackageName); // Example: _T("NTLM"), or _T("Negotiate") + +DWORD +client2_main( + IN LPCTSTR ServerName, // ServerName must be defined as the name of the computer running the server sample. Example: _T("127.0.0.1") + IN LPCTSTR TargetName, // TargetName must be defined as the logon name of the user running the server program. Example: _T("") + IN LPCTSTR PackageName); // Example: _T("NTLM"), or _T("Negotiate") + + + + +/************* F O R K ( C L I E N T ) M O D U L E S I D E ************/ + +static HANDLE hClientPipe = INVALID_HANDLE_VALUE; +static WCHAR named_pipe_name[100]; // Shared: FIXME! + +void send_msg(const char *type, const char *msg) +{ + DWORD written = 0; + char buf[512]; + + StringCbPrintfA(buf, sizeof(buf), "%s:%s", type, msg); + WriteFile(hClientPipe, buf, strlen(buf)+1, &written, NULL); +} + +void client_trace(const char *msg, ...) +{ + va_list valist; + char buf[512]; + + va_start(valist, msg); + StringCbVPrintfA(buf, sizeof(buf), msg, valist); + va_end(valist); + + send_msg("TRACE", buf); +} + +void client_ok(int cnd, const char *msg, ...) +{ + va_list valist; + char buf[512]; + + va_start(valist, msg); + StringCbVPrintfA(buf, sizeof(buf), msg, valist); + va_end(valist); + + send_msg(cnd ? "OK" : "FAIL", buf); +} + +void client_process(BOOL (*start_client)(PCSTR, PCWSTR), int argc, char** argv) +{ + BOOL res; + + StringCbCopyA(service_nameA, sizeof(service_nameA), argv[2]); + MultiByteToWideChar(CP_ACP, 0, service_nameA, -1, service_nameW, _countof(service_nameW)); + StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\.\pipe\%ls_pipe", service_nameW); + + res = WaitNamedPipeW(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT); + if (!res) + return; + + hClientPipe = CreateFileW(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hClientPipe == INVALID_HANDLE_VALUE) + return; + + client_trace("Client process starting...\n"); + res = start_client(service_nameA, service_nameW); + client_trace("Client process stopped.\n"); + + CloseHandle(hClientPipe); +} + + +/*********** T E S T E R ( S E R V E R ) M O D U L E S I D E **********/ + +static DWORD WINAPI pipe_thread(void *param) +{ + HANDLE hServerPipe = (HANDLE)param; + DWORD read; + BOOL res; + char buf[512]; + + // printf("pipe_thread -- ConnectNamedPipe...\n"); + res = ConnectNamedPipe(hServerPipe, NULL); + ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %lu\n", GetLastError()); + // printf("pipe_thread -- ConnectNamedPipe ok\n"); + + while (1) + { + res = ReadFile(hServerPipe, buf, sizeof(buf), &read, NULL); + if (!res) + { + ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE, + "ReadFile failed: %lu\n", GetLastError()); + // printf("pipe_thread -- break loop\n"); + break; + } + + if (!strncmp(buf, "TRACE:", 6)) + { + trace("client trace: %s", buf+6); + } + else if (!strncmp(buf, "OK:", 3)) + { + ok(1, "client: %s", buf+3); + } + else if (!strncmp(buf, "FAIL:", 5)) + { + ok(0, "client: %s", buf+5); + } + else + { + ok(0, "malformed client message: %s\n", buf); + } + } + + // printf("pipe_thread -- DisconnectNamedPipe\n"); + + /* + * Flush the pipe to allow the client to read + * the pipe's contents before disconnecting. + */ + FlushFileBuffers(hServerPipe); + + DisconnectNamedPipe(hServerPipe); + trace("pipe disconnected\n"); + return 0; +} + +void test_runner(void (*run_test)(PCSTR, PCWSTR, void*), void *param) +{ + HANDLE hServerPipe = INVALID_HANDLE_VALUE; + HANDLE hThread; + + StringCbPrintfW(service_nameW, sizeof(service_nameW), L"RosTestClient%lu", GetTickCount()); + WideCharToMultiByte(CP_ACP, 0, service_nameW, -1, service_nameA, _countof(service_nameA), NULL, NULL); + //trace("service_name: %ls\n", service_nameW); + StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\.\pipe\%ls_pipe", service_nameW); + + hServerPipe = CreateNamedPipeW(named_pipe_name, PIPE_ACCESS_INBOUND, + PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL); + ok(hServerPipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError()); + if (hServerPipe == INVALID_HANDLE_VALUE) + return; + + hThread = CreateThread(NULL, 0, pipe_thread, (LPVOID)hServerPipe, 0, NULL); + ok(hThread != NULL, "CreateThread failed: %lu\n", GetLastError()); + if (!hThread) + goto Quit; + + run_test(service_nameA, service_nameW, param); + + ok(WaitForSingleObject(hThread, 10000) == WAIT_OBJECT_0, "Timeout waiting for thread\n"); + +Quit: + if (hThread) + { + /* Be sure to kill the thread if it did not already terminate */ + TerminateThread(hThread, 0); + CloseHandle(hThread); + } + + if (hServerPipe != INVALID_HANDLE_VALUE) + CloseHandle(hServerPipe); +} + + + +/******************************************************************************/ + +static HANDLE +StartChildProcess( + IN PWSTR CommandLine) +{ + BOOL Success; + STARTUPINFOW StartupInfo; + PROCESS_INFORMATION ProcessInfo; + + RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + // /* HACK: running the test under rosautotest seems to keep another reference + // * to the child process around until the test finishes (on both ROS and + // * Windows)... I'm too lazy to investigate very much so let's just redirect + // * the child std handles to nowhere. ok() is useless in half the child + // * processes anyway. + // */ + // StartupInfo.dwFlags = STARTF_USESTDHANDLES; + + Success = CreateProcessW(NULL, // FileName, + CommandLine, + NULL, + NULL, + TRUE, // FALSE, + 0, + NULL, + NULL, + &StartupInfo, + &ProcessInfo); + if (!Success) + { + skip("CreateProcess failed with %lu\n", GetLastError()); + return NULL; + } + CloseHandle(ProcessInfo.hThread); + return ProcessInfo.hProcess; +} + + + +VOID +StartTest(int argc, char** argv) +{ + if (stricmp(argv[2], "client") == 0) /* Client */ + { +#ifdef SAMUEL_TESTS + if (stricmp(argv[3], "1") == 0) + client1_main(argc-4, &argv[4]); + else +#endif + if (stricmp(argv[3], "2") == 0) + client2_main(_T("127.0.0.1"), _T(""), _T("NTLM")); + else + printf("Unknown test client %s\n", argv[3]); + } + else if (stricmp(argv[2], "server") == 0) /* Server */ + { +#ifdef SAMUEL_TESTS + if (stricmp(argv[3], "1") == 0) + server1_main(argc-4, &argv[4]); + else +#endif + if (stricmp(argv[3], "2") == 0) + server2_main(_T("NTLM")); + else + printf("Unknown test server %s\n", argv[3]); + } + else + { + printf("Unknown option %s (valid ones: 'client', or 'server')\n", argv[2]); + } + + return; +} + +START_TEST(ClientServer) +{ + int argc; + char** argv; + + USHORT i; + WCHAR FileName[MAX_PATH]; + WCHAR CommandLine[MAX_PATH]; + HANDLE hClientServer[2]; + + /* Check whether this test is started as a separate process */ + argc = winetest_get_mainargs(&argv); + if (argc >= 4) + { + client_process(StartTest, argc, argv); + return; + } + + /* We are started as the real test */ + test_runner(..., NULL); + + /* Retrieve our full path */ + if (!GetModuleFileNameW(NULL, FileName, _countof(FileName)) + { + skip("GetModuleFileNameW failed with error %lu!\n", GetLastError()); + return; + } + +#ifdef SAMUEL_TESTS + for (i = 1; i <= 2; ++i) +#else + for (i = 2; i <= 2; ++i) +#endif + { + /* + * Build the server command line and start it + */ + StringCbPrintfW(CommandLine, + sizeof(CommandLine), + L""%s" ClientServer server %d", + FileName, i); + hClientServer[0] = StartChildProcess(CommandLine); + + /* Wait 500 millisecs for server initialization */ + Sleep(500); + + /* + * Build the client command line and start it + */ + StringCbPrintfW(CommandLine, + sizeof(CommandLine), + L""%s" ClientServer client %d", + FileName, i); + hClientServer[1] = StartChildProcess(CommandLine); + + /* Wait on client & server */ + // FIXME: Server can wait forever?! WTF + WaitForMultipleObjects(_countof(hClientServer), hClientServer, TRUE, INFINITE); + hClientServer[0] = hClientServer[0]; + } +}
Propchange: branches/sspi-bringup/rostests/apitests/secur32/client_server.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: branches/sspi-bringup/rostests/apitests/secur32/client_server.h URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/client_server.h (added) +++ branches/sspi-bringup/rostests/apitests/secur32/client_server.h [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,93 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Tests for client/server authentication via secur32 API. + * PROGRAMMERS: Samuel Serapión + * Hermes Belusca-Maito + */ + +#ifndef __CLIENT_SERVER_H__ +#define __CLIENT_SERVER_H__ + +#pragma once + +#define UNICODE +#define _UNICODE + +#include <apitest.h> + +#include <tchar.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include <ntstatus.h> +#define WIN32_NO_STATUS +// #define __USE_W32_SOCKETS +#include <windows.h> +// #include <winsock.h> +#include <winsock2.h> + +#define SECURITY_WIN32 // Needed by sspi.h (SECURITY_WIN32 or SECURITY_KERNEL or SECURITY_MAC) +#define _NO_KSECDD_IMPORT_ +#include <sspi.h> +/** Our broken psdk sspi.h misses this definition. But it's present in xdk sspi.h. I guess the psdk one needs some sync... **/ +#ifndef SECPKG_ID_NONE +#define SECPKG_ID_NONE 0xFFFF +#endif + +#include <ntsecapi.h> +#include <security.h> // Security.h must come *before* secext.h +#include <secext.h> + +#define SEC_SUCCESS(Status) ((Status) >= 0) + + +#define fatal_error_0(fmt, ...) \ +do { \ + printf("(%s:%d) fatal error: " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + return; /* exit(0); */ \ +} while (0) + +#define fatal_error(fmt, ...) \ +do { \ + printf("(%s:%d) fatal error: " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + return 0; /* exit(0); */ \ +} while (0) + +#define err(fmt, ...) printf("(%s:%d) " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__) + +#define printerr(errnum) \ +do { \ + LPWSTR buffer; \ + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, \ + NULL, \ + errnum, \ + LANG_USER_DEFAULT, \ + (LPWSTR)&buffer, \ + 0, \ + NULL); \ + err("%S",buffer ); \ + LocalFree(buffer); \ +} while (0) + + +extern PSecurityFunctionTable client1_SecFuncTable; +extern PSecurityFunctionTable server1_SecFuncTable; + +void PrintErrorString(int errnum); +void wserr( int rc, LPCWSTR const funcname ); + +void initSecLib( + HINSTANCE* phSec, + PSecurityFunctionTable* pSecFuncTable); + +BOOL SendMsg(SOCKET s, PBYTE pBuf, DWORD cbBuf); +BOOL ReceiveMsg(SOCKET s,PBYTE pBuf,DWORD cbBuf,DWORD *pcbRead); +BOOL SendBytes(SOCKET s, PBYTE pBuf, DWORD cbBuf); +BOOL ReceiveBytes(SOCKET s, PBYTE pBuf, DWORD cbBuf, DWORD *pcbRead); +DWORD inet_addr_w(const WCHAR *pszAddr); + +void PrintHexDump(DWORD length, PBYTE buffer); + +#endif // __CLIENT_SERVER_H__
Propchange: branches/sspi-bringup/rostests/apitests/secur32/client_server.h ------------------------------------------------------------------------------ svn:eol-style = native
Added: branches/sspi-bringup/rostests/apitests/secur32/server1.c URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/server1.c (added) +++ branches/sspi-bringup/rostests/apitests/secur32/server1.c [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,245 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Tests for client/server authentication via secur32 API. + * PROGRAMMERS: Samuel Serapión + */ + +#include "client_server.h" + +#define PackageName L"NTLM" + +PSecurityFunctionTable server1_SecFuncTable = NULL; + +BOOL auth( + IN SOCKET s, + OUT PCredHandle pCred, + OUT PCtxtHandle pSrvCtx) +{ + int rc; + BOOL haveToken = TRUE; + SecPkgInfoW *secPackInfo; + int bytesReceived = 0, bytesSent = 0; + TimeStamp useBefore; + + /* Input and output buffers */ + SecBufferDesc obd, ibd; + SecBuffer ob, ib; + + DWORD ctxAttr; + BOOL haveContext = FALSE; + + trace("auth() entered"); + + rc = server1_SecFuncTable->QuerySecurityPackageInfoW(PackageName, &secPackInfo); + trace("QSPI(): %08xh\n", rc); + if (rc != SEC_E_OK) + haveToken = FALSE; + + rc = server1_SecFuncTable->AcquireCredentialsHandleW(NULL, PackageName, SECPKG_CRED_INBOUND, + NULL, NULL, NULL, NULL, pCred, &useBefore); + trace("ACH(): %08xh\n", rc); + if (rc != SEC_E_OK) + haveToken = FALSE; + + while (1) + { + char *p; + int n; + + /* 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); + + p = (char *)ib.pvBuffer; + n = ib.cbBuffer; + while (n) + { + rc = recv(s, p, n, 0); + if (rc == SOCKET_ERROR) + wserr(rc, L"recv"); + if (rc == 0) + wserr(999, L"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 = server1_SecFuncTable->AcceptSecurityContext(pCred, haveContext? pSrvCtx: NULL, + &ibd, 0, SECURITY_NATIVE_DREP, pSrvCtx, &obd, &ctxAttr, &useBefore); + trace("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 (server1_SecFuncTable->CompleteAuthToken != NULL) // only if implemented + server1_SecFuncTable->CompleteAuthToken(pSrvCtx, &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) + { + err("Oops! ASC() returned %08xh!\n", rc); + haveToken = FALSE; + } + + /* Now we try to use the context */ + rc = server1_SecFuncTable->ImpersonateSecurityContext(pSrvCtx); + trace("ImpSC(): %08xh\n", rc); + if (rc != SEC_E_OK) + { + err("Oops! ImpSC() returns %08xh!\n", rc); + haveToken = FALSE; + } + else + { + WCHAR buf[256]; + DWORD bufsiz = ARRAYSIZE(buf); + GetUserNameW(buf, &bufsiz); + trace("user name: "%s"\n", buf); + server1_SecFuncTable->RevertSecurityContext(pSrvCtx); + trace("RSC(): %08xh\n", rc); + } + + server1_SecFuncTable->FreeContextBuffer(secPackInfo); + + trace("auth() exiting (%d received, %d sent)\n", bytesReceived, bytesSent); + return haveToken; +} + +int server1_main( + char *portstr) +{ + int rc, port, addrlen; + BOOL haveToken; + SOCKET sock, s; + WSADATA wsadata; + PSERVENT pse; + SOCKADDR_IN addr; + HINSTANCE hSecLib; + CredHandle cred; + CtxtHandle srvCtx; + + initSecLib(&hSecLib, &server1_SecFuncTable); + + rc = WSAStartup(2, &wsadata); + wserr(rc, L"WSAStartup"); + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) + wserr(999, L"socket"); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + + /* 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, L"getservbyname"); + addr.sin_port = pse->s_port; + } + + rc = bind(sock, (SOCKADDR *) &addr, sizeof(addr)); + wserr(rc, L"bind"); + + rc = listen(sock, 2); + wserr(rc, L"listen"); + + while (1) + { + addrlen = sizeof(addr); + s = accept(sock, (SOCKADDR *) &addr, &addrlen); + if (s == INVALID_SOCKET) + wserr(s, L"accept"); + + haveToken = auth(s, &cred, &srvCtx); + + /* Now we talk to the client */ + trace("haveToken = %s\n\n", haveToken? "true": "false"); + send(s, (const char *) &haveToken, sizeof(haveToken), 0); + + /* Clean up */ + server1_SecFuncTable->DeleteSecurityContext(&srvCtx); + server1_SecFuncTable->FreeCredentialHandle(&cred); + closesocket(s); + } + + FreeLibrary(hSecLib); + + return 0; +} + +#if 0 +int main(int argc, _TCHAR* argv[]) +{ + //if (argc != 1) + //{ + // puts("usage: server portnumber"); + // return 1; + //} + + return server1_main(argv[1]); +} +#endif
Propchange: branches/sspi-bringup/rostests/apitests/secur32/server1.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: branches/sspi-bringup/rostests/apitests/secur32/server2_msdn.c URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/server2_msdn.c (added) +++ branches/sspi-bringup/rostests/apitests/secur32/server2_msdn.c [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,552 @@ +// +// MSDN Example "Using SSPI with a Windows Sockets Server" +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380537(v=vs.85).a... +// + +//-------------------------------------------------------------------- +// This is a server-side SSPI Windows Sockets program. + +#include "client_server.h" + +#define g_usPort 2000 + +CredHandle hcred; +SecHandle hctxt; +PBYTE g_pInBuf; +PBYTE g_pOutBuf; +DWORD g_cbMaxMessage; + +BOOL +GenServerContext( + CredHandle hcred, + PBYTE pIn, + DWORD cbIn, + PBYTE pOut, + DWORD *pcbOut, + BOOL *pfDone, + BOOL fNewConversation); + +BOOL server2_DoAuthentication( + IN SOCKET AuthSocket, + IN LPCTSTR PackageName); + +BOOL AcceptAuthSocket( + OUT SOCKET *ServerSocket, + IN LPCTSTR PackageName) +{ + SOCKET sockListen; + SOCKET sockClient; + SOCKADDR_IN sockIn; + + /* Create listening socket */ + sockListen = socket(PF_INET, SOCK_STREAM, 0); + if (sockListen == INVALID_SOCKET) + { + err("Failed to create socket: %u\n", GetLastError()); + return FALSE; + } + else + { + trace("server socket created.\n",sockListen); + } + + /* Bind to local port */ + sockIn.sin_family = AF_INET; + sockIn.sin_addr.s_addr = 0; + sockIn.sin_port = htons(g_usPort); + + if (SOCKET_ERROR == bind(sockListen, + (LPSOCKADDR)&sockIn, + sizeof(sockIn))) + { + err("bind failed: %u\n", GetLastError()); + return FALSE; + } + + //----------------------------------------------------------------- + // Listen for client, maximum 1 connection. + + if (SOCKET_ERROR == listen(sockListen, 1)) + { + err("Listen failed: %u\n", GetLastError()); + return FALSE; + } + else + { + trace("Listening !\n"); + } + + /* Accept client */ + sockClient = accept(sockListen, + NULL, + NULL); + if (sockClient == INVALID_SOCKET) + { + err("accept failed: %u\n", GetLastError()); + return FALSE; + } + + /* Stop listening */ + closesocket(sockListen); + + trace("connection accepted on socket %x!\n",sockClient); + *ServerSocket = sockClient; + + return server2_DoAuthentication(sockClient, PackageName); +} + +BOOL server2_DoAuthentication( + IN SOCKET AuthSocket, + IN LPCTSTR PackageName) +{ + SECURITY_STATUS ss; + DWORD cbIn, cbOut; + BOOL done = FALSE; + TimeStamp Lifetime; + BOOL fNewConversation = TRUE; + + ss = AcquireCredentialsHandle(NULL, + (LPTSTR)PackageName, + SECPKG_CRED_INBOUND, + NULL, + NULL, + NULL, + NULL, + &hcred, + &Lifetime); + ok(SEC_SUCCESS(ss), "AcquireCredentialsHandle failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + err("AcquireCreds failed: 0x%08x\n", ss); + printerr(ss); + return FALSE; + } + + while (!done) + { + if (!ReceiveMsg(AuthSocket, + g_pInBuf, + g_cbMaxMessage, + &cbIn)) + { + return FALSE; + } + + cbOut = g_cbMaxMessage; + + if (!GenServerContext(hcred, + g_pInBuf, + cbIn, + g_pOutBuf, + &cbOut, + &done, + fNewConversation)) + { + err("GenServerContext failed.\n"); + return FALSE; + } + + fNewConversation = FALSE; + if (!SendMsg(AuthSocket, g_pOutBuf, cbOut)) + { + err("Sending message failed.\n"); + return FALSE; + } + } + + return TRUE; +} + +BOOL +GenServerContext( + CredHandle hcred, + PBYTE pIn, + DWORD cbIn, + PBYTE pOut, + DWORD *pcbOut, + BOOL *pfDone, + BOOL fNewConversation) +{ + SECURITY_STATUS ss; + TimeStamp Lifetime; + SecBufferDesc OutBuffDesc; + SecBuffer OutSecBuff; + SecBufferDesc InBuffDesc; + SecBuffer InSecBuff; + ULONG Attribs = 0; + + //---------------------------------------------------------------- + // Prepare output buffers. + + OutBuffDesc.ulVersion = 0; + OutBuffDesc.cBuffers = 1; + OutBuffDesc.pBuffers = &OutSecBuff; + + OutSecBuff.cbBuffer = *pcbOut; + OutSecBuff.BufferType = SECBUFFER_TOKEN; + OutSecBuff.pvBuffer = pOut; + + //---------------------------------------------------------------- + // Prepare input buffers. + + InBuffDesc.ulVersion = 0; + InBuffDesc.cBuffers = 1; + InBuffDesc.pBuffers = &InSecBuff; + + InSecBuff.cbBuffer = cbIn; + InSecBuff.BufferType = SECBUFFER_TOKEN; + InSecBuff.pvBuffer = pIn; + + trace("Token buffer received (%lu bytes):\n", InSecBuff.cbBuffer); + PrintHexDump(InSecBuff.cbBuffer, (PBYTE)InSecBuff.pvBuffer); + + ss = AcceptSecurityContext(&hcred, + fNewConversation ? NULL : &hctxt, + &InBuffDesc, + Attribs, + SECURITY_NATIVE_DREP, + &hctxt, + &OutBuffDesc, + &Attribs, + &Lifetime); + ok(SEC_SUCCESS(ss), "AcceptSecurityContext failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + err("AcceptSecurityContext failed: 0x%08x\n", ss); + printerr(ss); + return FALSE; + } + + /* Complete token if applicable */ + if ((ss == SEC_I_COMPLETE_NEEDED) || + (ss == SEC_I_COMPLETE_AND_CONTINUE)) + { + ss = CompleteAuthToken(&hctxt, &OutBuffDesc); + ok(SEC_SUCCESS(ss), "CompleteAuthToken failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + err("complete failed: 0x%08x\n", ss); + printerr(ss); + return FALSE; + } + } + + *pcbOut = OutSecBuff.cbBuffer; + + // fNewConversation equals FALSE. + + trace("Token buffer generated (%lu bytes):\n", + OutSecBuff.cbBuffer); + PrintHexDump(OutSecBuff.cbBuffer, + (PBYTE)OutSecBuff.pvBuffer); + + *pfDone = !((ss == SEC_I_CONTINUE_NEEDED) || + (ss == SEC_I_COMPLETE_AND_CONTINUE)); + + return TRUE; +} + +BOOL +EncryptThis( + PBYTE pMessage, + ULONG cbMessage, + BYTE ** ppOutput, + ULONG * pcbOutput, + ULONG cbSecurityTrailer) +{ + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[2]; + ULONG ulQop = 0; + ULONG SigBufferSize; + + /* + * The size of the trailer (signature + padding) block is + * determined from the global cbSecurityTrailer. + */ + SigBufferSize = cbSecurityTrailer; + + trace("Data before encryption: %.*S\n", cbMessage/sizeof(TCHAR), pMessage); + trace("Length of data before encryption: %d\n", cbMessage); + + /* + * Allocate a buffer to hold the signature, + * encrypted data, and a DWORD + * that specifies the size of the trailer block. + */ + *ppOutput = (PBYTE)malloc(SigBufferSize + cbMessage + sizeof(DWORD)); + + /* Prepare buffers */ + BuffDesc.ulVersion = 0; + BuffDesc.cBuffers = ARRAYSIZE(SecBuff); + BuffDesc.pBuffers = SecBuff; + + SecBuff[0].cbBuffer = SigBufferSize; + SecBuff[0].BufferType = SECBUFFER_TOKEN; + SecBuff[0].pvBuffer = *ppOutput + sizeof(DWORD); + + SecBuff[1].cbBuffer = cbMessage; + SecBuff[1].BufferType = SECBUFFER_DATA; + SecBuff[1].pvBuffer = pMessage; + + ss = EncryptMessage(&hctxt, ulQop, &BuffDesc, 0); + ok(SEC_SUCCESS(ss), "EncryptMessage failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + err("EncryptMessage failed: 0x%08x\n", ss); + return FALSE; + } + else + { + trace("The message has been encrypted.\n"); + } + + /* Indicate the size of the buffer in the first DWORD */ + *((DWORD*)*ppOutput) = SecBuff[0].cbBuffer; + + /* + * Append the encrypted data to our trailer block + * to form a single block. + * Putting trailer at the beginning of the buffer works out + * better. + */ + memcpy(*ppOutput+SecBuff[0].cbBuffer + sizeof(DWORD), pMessage, cbMessage); + + *pcbOutput = cbMessage + SecBuff[0].cbBuffer + sizeof(DWORD); + + trace("data after encryption including trailer (%lu bytes):\n", *pcbOutput); + PrintHexDump(*pcbOutput, *ppOutput); + + return TRUE; +} + +void server2_cleanup(void) +{ + trace("called server2_cleanup!\n"); + + if (g_pInBuf) + free(g_pInBuf); + + if (g_pOutBuf) + free(g_pOutBuf); + + WSACleanup(); +} + +DWORD WINAPI +server2_start( + IN LPCTSTR PackageName) +{ + BOOL Success; + PBYTE pDataToClient = NULL; + DWORD cbDataToClient = 0; + TCHAR* pUserName = NULL; + DWORD cchUserName = 0; + SOCKET Server_Socket; + SECURITY_STATUS ss; + PSecPkgInfo pkgInfo; + SecPkgContext_Sizes SecPkgContextSizes; + SecPkgContext_NegotiationInfo SecPkgNegInfo; + ULONG cbMaxSignature; + ULONG cbSecurityTrailer; + + /* + * Initialize the security package + */ + ss = QuerySecurityPackageInfo((LPTSTR)PackageName, &pkgInfo); + ok(SEC_SUCCESS(ss), "QuerySecurityPackageInfo failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + skip("Could not query package info for %S, error 0x%08x\n", + PackageName, ss); + printerr(ss); + server2_cleanup(); + return 0; + } + + g_cbMaxMessage = pkgInfo->cbMaxToken; + trace("max token = %d\n", g_cbMaxMessage); + + FreeContextBuffer(pkgInfo); + + g_pInBuf = (PBYTE)malloc(g_cbMaxMessage); + g_pOutBuf = (PBYTE)malloc(g_cbMaxMessage); + + if (!g_pInBuf || !g_pOutBuf) + { + server2_cleanup(); + fatal_error("Memory allocation error.\n"); + } + + /* Start looping for clients */ + + //while (TRUE) + { + trace("Waiting for client to connect...\n"); + + /* Make an authenticated connection with client */ + Success = AcceptAuthSocket(&Server_Socket, PackageName); + ok(Success, "AcceptAuthSocket failed\n"); + if (!Success) + { + server2_cleanup(); + fatal_error("Could not authenticate the socket.\n"); + } + + ss = QueryContextAttributes(&hctxt, + SECPKG_ATTR_SIZES, + &SecPkgContextSizes); + ok(SEC_SUCCESS(ss), "QueryContextAttributes failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + server2_cleanup(); + fatal_error("QueryContextAttributes failed: 0x%08x\n", ss); + } + + /* The following values are used for encryption and signing */ + cbMaxSignature = SecPkgContextSizes.cbMaxSignature; + cbSecurityTrailer = SecPkgContextSizes.cbSecurityTrailer; + + ss = QueryContextAttributes(&hctxt, + SECPKG_ATTR_NEGOTIATION_INFO, + &SecPkgNegInfo); + ok(SEC_SUCCESS(ss), "QueryContextAttributes failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + err("QueryContextAttributes failed: 0x%08x\n", ss); + printerr(ss); + server2_cleanup(); + fatal_error("aborting\n"); + } + else + { + trace("Package Name: %S\n", SecPkgNegInfo.PackageInfo->Name); + } + + /* Free the allocated buffer */ + FreeContextBuffer(SecPkgNegInfo.PackageInfo); + + /* Impersonate the client */ + ss = ImpersonateSecurityContext(&hctxt); + ok(SEC_SUCCESS(ss), "ImpersonateSecurityContext failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + err("Impersonate failed: 0x%08x\n", ss); + server2_cleanup(); + printerr(ss); + fatal_error("aborting\n"); + } + else + { + trace("Impersonation worked.\n"); + } + + GetUserName(NULL, &cchUserName); + pUserName = (TCHAR*)malloc(cchUserName*sizeof(TCHAR)); + if (!pUserName) + { + err("Memory allocation error.\n"); + server2_cleanup(); + fatal_error("aborting\n"); + } + + if (!GetUserName(pUserName, &cchUserName)) + { + err("Could not get the client name.\n"); + server2_cleanup(); + printerr(GetLastError()); + fatal_error("aborting\n"); + } + else + { + trace("Client connected as : %S\n", pUserName); + } + + /* Revert to self */ + ss = RevertSecurityContext(&hctxt); + ok(SEC_SUCCESS(ss), "RevertSecurityContext failed with error 0x%08x\n", ss); + if (!SEC_SUCCESS(ss)) + { + err("Revert failed: 0x%08x\n", ss); + server2_cleanup(); + printerr(GetLastError()); + fatal_error("aborting\n"); + } + else + { + trace("Reverted to self.\n"); + } + + /* + * Send the client an encrypted message + */ + { + TCHAR pMessage[200] = _T("This is your server speaking"); + DWORD cbMessage = _tcslen(pMessage) * sizeof(TCHAR); + + EncryptThis((PBYTE)pMessage, + cbMessage, + &pDataToClient, + &cbDataToClient, + cbSecurityTrailer); + } + + /* Send the encrypted data to client */ + if (!SendBytes(Server_Socket, + pDataToClient, + cbDataToClient)) + { + err("send message failed.\n"); + server2_cleanup(); + printerr(GetLastError()); + fatal_error("aborting\n"); + } + + trace(" %d encrypted bytes sent.\n", cbDataToClient); + + if (Server_Socket) + { + DeleteSecurityContext(&hctxt); + FreeCredentialHandle(&hcred); + shutdown(Server_Socket, 2); + closesocket(Server_Socket); + Server_Socket = 0; + } + + if (pUserName) + { + free(pUserName); + pUserName = NULL; + cchUserName = 0; + } + if (pDataToClient) + { + free(pDataToClient); + pDataToClient = NULL; + cbDataToClient = 0; + } + } + + trace("Server ran to completion without error.\n"); + server2_cleanup(); + return 0; +} + +DWORD +server2_main( + IN LPCTSTR PackageName) // Example: _T("NTLM"), or _T("Negotiate") +{ + DWORD dwRet; + WSADATA wsaData; + + /* Startup WSA */ + if (WSAStartup(0x0101, &wsaData)) + fatal_error("Could not initialize winsock.\n"); + + /* Start the server */ + dwRet = server2_start(PackageName); + + /* Shutdown WSA and return */ + WSACleanup(); + return dwRet; +}
Propchange: branches/sspi-bringup/rostests/apitests/secur32/server2_msdn.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: branches/sspi-bringup/rostests/apitests/secur32/testlist.c URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/testlist.c (added) +++ branches/sspi-bringup/rostests/apitests/secur32/testlist.c [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,12 @@ +#define __ROS_LONG64__ + +#define STANDALONE +#include <wine/test.h> + +extern void func_ClientServer(void); + +const struct test winetest_testlist[] = +{ + { "ClientServer", func_ClientServer }, + { 0, 0 } +};
Propchange: branches/sspi-bringup/rostests/apitests/secur32/testlist.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: branches/sspi-bringup/rostests/apitests/secur32/utils.c URL: http://svn.reactos.org/svn/reactos/branches/sspi-bringup/rostests/apitests/s... ============================================================================== --- branches/sspi-bringup/rostests/apitests/secur32/utils.c (added) +++ branches/sspi-bringup/rostests/apitests/secur32/utils.c [iso-8859-1] Thu Jun 22 00:51:51 2017 @@ -0,0 +1,329 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPLv2+ - See COPYING in the top level directory + * PURPOSE: Tests for client/server authentication via secur32 API. + * PROGRAMMERS: Samuel Serapión + * Hermes Belusca-Maito + */ + +#include "client_server.h" + +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* phSec, + PSecurityFunctionTable* pSecFuncTable) +{ + SECURITY_STATUS rc; + DWORD numPacks = 0, i, j; + SecPkgInfoW *pPacks = NULL; + + PSecurityFunctionTable (*pInitSecurityInterfaceW)(void); + + assert(phSec); + assert(pSecFuncTable); + + *phSec = LoadLibraryW(L"security.dll"); + pInitSecurityInterfaceW = (PSecurityFunctionTable(*)(void))GetProcAddress(*phSec, "InitSecurityInterfaceW"); + if (pInitSecurityInterfaceW == NULL) + { + wprintf(L"security.dll loading failed..."); + exit(1); + } + + *pSecFuncTable = pInitSecurityInterfaceW(); + if (*pSecFuncTable == NULL) + { + wprintf(L"no function table?!?"); + exit(1); + } + + rc = ((*pSecFuncTable)->EnumerateSecurityPackages)(&numPacks, &pPacks); + if (rc != 0) + { + printf("ESP() returned %ld\n", rc); + exit(1); + } + + for (i = 0; i < numPacks; ++ i) + { + printf("\nPackage: %S\n", pPacks[i].Name); + printf(" Version: %hu\n", pPacks[i].wVersion); + printf(" RPCID: %hu%S\n", pPacks[i].wRPCID, + pPacks[i].wRPCID == SECPKG_ID_NONE? " [none]": ""); + printf(" Comment: "%S"\n", pPacks[i].Comment); + printf(" Capabilities: %08lxh\n", pPacks[i].fCapabilities); + 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) + ((*pSecFuncTable)->FreeContextBuffer)(pPacks); +} + + +/* wserr() displays winsock errors and aborts. No grace there. */ +void wserr(int rc, LPCWSTR const funcname) +{ + DWORD errnum = WSAGetLastError(); + LPWSTR errbuffer; + + if (rc == 0) + return; + + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errnum, + LANG_USER_DEFAULT, + (LPWSTR)&errbuffer, + 0, + NULL); + + fwprintf(stderr, L"\nWinsock error %d [gle %d] returned by %s().\n", + rc, errnum); + fwprintf(stderr, L"\nError string: %s.\n",errbuffer); + + LocalFree(errbuffer); + WSACleanup(); + // exit(rc); +} + +void PrintHexDump( + DWORD length, + PBYTE buffer) +{ + DWORD i,count,index; + CHAR rgbDigits[]="0123456789abcdef"; + CHAR rgbLine[100]; + char cbLine; + + for (index = 0; length; + length -= count, buffer += count, index += count) + { + count = (length > 16) ? 16:length; + + snprintf(rgbLine, 100, "%4.4x ",index); + cbLine = 6; + + for (i = 0; i < count; i++) + { + rgbLine[cbLine++] = rgbDigits[buffer[i] >> 4]; + rgbLine[cbLine++] = rgbDigits[buffer[i] & 0x0f]; + if (i == 7) + { + rgbLine[cbLine++] = ':'; + } + else + { + rgbLine[cbLine++] = ' '; + } + } + for (; i < 16; i++) + { + rgbLine[cbLine++] = ' '; + rgbLine[cbLine++] = ' '; + rgbLine[cbLine++] = ' '; + } + + rgbLine[cbLine++] = ' '; + + for (i = 0; i < count; i++) + { + if (buffer[i] < 32 || buffer[i] > 126) + { + rgbLine[cbLine++] = '.'; + } + else + { + rgbLine[cbLine++] = buffer[i]; + } + } + + rgbLine[cbLine++] = 0; + printf("%s\n", rgbLine); + } +} + +BOOL SendMsg( + SOCKET s, + PBYTE pBuf, + DWORD cbBuf) +{ + if (cbBuf == 0) + return TRUE; + + /* Send the size of the message */ + if (!SendBytes(s, + (PBYTE)&cbBuf, + sizeof(cbBuf))) + { + return FALSE; + } + + /* Send the body of the message */ + if (!SendBytes(s, + pBuf, + cbBuf)) + { + return FALSE; + } + + return TRUE; +} + +BOOL SendBytes( + SOCKET s, + PBYTE pBuf, + DWORD cbBuf) +{ + PBYTE pTemp = pBuf; + int cbSent, cbRemaining = cbBuf; + + trace("sending %d bytes from buffer %p to socket %x\n", cbBuf, pBuf, s); + + if (!pBuf) + { + err("received null buffer!\n"); + return FALSE; + } + + if (cbBuf == 0) + return TRUE; + + while (cbRemaining) + { + cbSent = send(s, + (const char *)pTemp, + cbRemaining, + 0); + + if (SOCKET_ERROR == cbSent) + { + err("send failed: %u\n", GetLastError()); + printerr(GetLastError()); + return FALSE; + } + + pTemp += cbSent; + cbRemaining -= cbSent; + } + + return TRUE; +} + +BOOL ReceiveMsg( + SOCKET s, + PBYTE pBuf, + DWORD cbBuf, + DWORD *pcbRead) +{ + DWORD cbRead; + DWORD cbData; + + /* Retrieve the number of bytes in the message */ + if (!ReceiveBytes(s, + (PBYTE)&cbData, + sizeof(cbData), + &cbRead)) + { + return FALSE; + } + + trace("message size = %d\n", cbData); + + if (sizeof(cbData) != cbRead) + return FALSE; + + /* Read the full message */ + if (!ReceiveBytes(s, + pBuf, + cbData, + &cbRead)) + { + return FALSE; + } + + if (cbRead != cbData) + { + err("cbRead != cbData, was %d %d\n",cbRead, cbData); + return FALSE; + } + + *pcbRead = cbRead; + return TRUE; +} + +BOOL ReceiveBytes( + SOCKET s, + PBYTE pBuf, + DWORD cbBuf, + DWORD *pcbRead) +{ + PBYTE pTemp = pBuf; + int cbRead, cbRemaining = cbBuf; + + trace("reading %d bytes from socket %x to buffer %p\n", cbBuf, s, pBuf); + + if (!pBuf) + { + err("received null buffer!\n"); + return FALSE; + } + + while (cbRemaining) + { + cbRead = recv(s, (char*)pTemp, cbBuf, 0); + if (cbRead < 0 || cbRead == SOCKET_ERROR) + { + err("recv failed: %d\n", WSAGetLastError()); + printerr(WSAGetLastError()); + fatal_error("abort"); + break; + } + trace("received %d bytes, %d remain in buffer\n", cbRead, cbRemaining); + + if (cbRead == 0) + break; + + cbRemaining -= cbRead; + pTemp += cbRead; + } + + *pcbRead = cbBuf - cbRemaining; + return TRUE; +} + +DWORD inet_addr_w(const WCHAR *pszAddr) +{ + char szBuffer[256]; + + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, + pszAddr, -1, szBuffer, 256, NULL, NULL); + + return inet_addr(szBuffer); +}
Propchange: branches/sspi-bringup/rostests/apitests/secur32/utils.c ------------------------------------------------------------------------------ svn:eol-style = native