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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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).…
+//
+
+//--------------------------------------------------------------------
+// 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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).…
+//
+
+//--------------------------------------------------------------------
+// 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/…
==============================================================================
--- 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/…
==============================================================================
--- 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