secur32/tests: Handle skip cleanup in negotiate more cleanly.
[wine.git] / dlls / secur32 / tests / negotiate.c
blob4f07dbe1677144b9002023f86b0cbb38ac87351d
1 /*
2 * Tests for the Negotiate security provider
4 * Copyright 2005, 2006 Kai Blin
5 * Copyright 2012 Hans Leidekker for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <windef.h>
25 #include <winbase.h>
26 #define SECURITY_WIN32
27 #include <sspi.h>
28 #include <rpc.h>
29 #include <rpcdce.h>
30 #include <secext.h>
32 #include "wine/test.h"
34 static HMODULE hsecur32;
35 static SECURITY_STATUS (SEC_ENTRY * pAcceptSecurityContext)(PCredHandle, PCtxtHandle,
36 PSecBufferDesc, ULONG, ULONG, PCtxtHandle, PSecBufferDesc, PULONG, PTimeStamp);
37 static SECURITY_STATUS (SEC_ENTRY * pAcquireCredentialsHandleA)(SEC_CHAR *, SEC_CHAR *,
38 ULONG, PLUID, PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp);
39 static SECURITY_STATUS (SEC_ENTRY * pCompleteAuthToken)(PCtxtHandle, PSecBufferDesc);
40 static SECURITY_STATUS (SEC_ENTRY * pDecryptMessage)(PCtxtHandle, PSecBufferDesc, ULONG, PULONG);
41 static SECURITY_STATUS (SEC_ENTRY * pDeleteSecurityContext)(PCtxtHandle);
42 static SECURITY_STATUS (SEC_ENTRY * pEncryptMessage)(PCtxtHandle, ULONG, PSecBufferDesc, ULONG);
43 static SECURITY_STATUS (SEC_ENTRY * pFreeContextBuffer)(PVOID);
44 static SECURITY_STATUS (SEC_ENTRY * pFreeCredentialsHandle)(PCredHandle);
45 static SECURITY_STATUS (SEC_ENTRY * pInitializeSecurityContextA)(PCredHandle, PCtxtHandle,
46 SEC_CHAR *, ULONG, ULONG, ULONG, PSecBufferDesc, ULONG, PCtxtHandle, PSecBufferDesc,
47 PULONG, PTimeStamp);
48 static PSecurityFunctionTableA (SEC_ENTRY * pInitSecurityInterfaceA)(void);
49 static SECURITY_STATUS (SEC_ENTRY * pMakeSignature)(PCtxtHandle, ULONG, PSecBufferDesc, ULONG);
50 static SECURITY_STATUS (SEC_ENTRY * pQueryContextAttributesA)(PCtxtHandle, ULONG, PVOID);
51 static SECURITY_STATUS (SEC_ENTRY * pQuerySecurityPackageInfoA)(SEC_CHAR *, PSecPkgInfoA *);
52 static SECURITY_STATUS (SEC_ENTRY * pVerifySignature)(PCtxtHandle, PSecBufferDesc, ULONG, PULONG);
54 static void init_function_ptrs(void)
56 if (!(hsecur32 = LoadLibraryA("secur32.dll"))) return;
57 pAcceptSecurityContext = (void *)GetProcAddress(hsecur32, "AcceptSecurityContext");
58 pAcquireCredentialsHandleA = (void *)GetProcAddress(hsecur32, "AcquireCredentialsHandleA");
59 pCompleteAuthToken = (void *)GetProcAddress(hsecur32, "CompleteAuthToken");
60 pDecryptMessage = (void *)GetProcAddress(hsecur32, "DecryptMessage");
61 pDeleteSecurityContext = (void *)GetProcAddress(hsecur32, "DeleteSecurityContext");
62 pEncryptMessage = (void *)GetProcAddress(hsecur32, "EncryptMessage");
63 pFreeContextBuffer = (void *)GetProcAddress(hsecur32, "FreeContextBuffer");
64 pFreeCredentialsHandle = (void *)GetProcAddress(hsecur32, "FreeCredentialsHandle");
65 pInitializeSecurityContextA = (void *)GetProcAddress(hsecur32, "InitializeSecurityContextA");
66 pInitSecurityInterfaceA = (void *)GetProcAddress(hsecur32, "InitSecurityInterfaceA");
67 pMakeSignature = (void *)GetProcAddress(hsecur32, "MakeSignature");
68 pQueryContextAttributesA = (void *)GetProcAddress(hsecur32, "QueryContextAttributesA");
69 pQuerySecurityPackageInfoA = (void *)GetProcAddress(hsecur32, "QuerySecurityPackageInfoA");
70 pVerifySignature = (void *)GetProcAddress(hsecur32, "VerifySignature");
73 #define NEGOTIATE_BASE_CAPS ( \
74 SECPKG_FLAG_INTEGRITY | \
75 SECPKG_FLAG_PRIVACY | \
76 SECPKG_FLAG_CONNECTION | \
77 SECPKG_FLAG_MULTI_REQUIRED | \
78 SECPKG_FLAG_EXTENDED_ERROR | \
79 SECPKG_FLAG_IMPERSONATION | \
80 SECPKG_FLAG_ACCEPT_WIN32_NAME | \
81 SECPKG_FLAG_NEGOTIABLE | \
82 SECPKG_FLAG_GSS_COMPATIBLE | \
83 SECPKG_FLAG_LOGON )
85 #define NTLM_BASE_CAPS ( \
86 SECPKG_FLAG_INTEGRITY | \
87 SECPKG_FLAG_PRIVACY | \
88 SECPKG_FLAG_TOKEN_ONLY | \
89 SECPKG_FLAG_CONNECTION | \
90 SECPKG_FLAG_MULTI_REQUIRED | \
91 SECPKG_FLAG_IMPERSONATION | \
92 SECPKG_FLAG_ACCEPT_WIN32_NAME | \
93 SECPKG_FLAG_NEGOTIABLE | \
94 SECPKG_FLAG_LOGON )
96 struct sspi_data
98 CredHandle cred;
99 CtxtHandle ctxt;
100 PSecBufferDesc in_buf;
101 PSecBufferDesc out_buf;
102 PSEC_WINNT_AUTH_IDENTITY_A id;
103 ULONG max_token;
106 static void cleanup_buffers( struct sspi_data *data )
108 unsigned int i;
110 if (data->in_buf)
112 for (i = 0; i < data->in_buf->cBuffers; ++i)
113 HeapFree( GetProcessHeap(), 0, data->in_buf->pBuffers[i].pvBuffer );
114 HeapFree( GetProcessHeap(), 0, data->in_buf->pBuffers );
115 HeapFree( GetProcessHeap(), 0, data->in_buf );
117 if (data->out_buf)
119 for (i = 0; i < data->out_buf->cBuffers; ++i)
120 HeapFree( GetProcessHeap(), 0, data->out_buf->pBuffers[i].pvBuffer );
121 HeapFree( GetProcessHeap(), 0, data->out_buf->pBuffers );
122 HeapFree( GetProcessHeap(), 0, data->out_buf );
126 static void setup_buffers( struct sspi_data *data, SecPkgInfoA *info )
128 SecBuffer *buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBuffer) );
130 data->in_buf = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBufferDesc) );
131 data->out_buf = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBufferDesc) );
132 data->max_token = info->cbMaxToken;
134 data->in_buf->ulVersion = SECBUFFER_VERSION;
135 data->in_buf->cBuffers = 1;
136 data->in_buf->pBuffers = buffer;
138 buffer->cbBuffer = info->cbMaxToken;
139 buffer->BufferType = SECBUFFER_TOKEN;
140 buffer->pvBuffer = HeapAlloc( GetProcessHeap(), 0, info->cbMaxToken );
142 buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBuffer) );
144 data->out_buf->ulVersion = SECBUFFER_VERSION;
145 data->out_buf->cBuffers = 1;
146 data->out_buf->pBuffers = buffer;
148 buffer->cbBuffer = info->cbMaxToken;
149 buffer->BufferType = SECBUFFER_TOKEN;
150 buffer->pvBuffer = HeapAlloc( GetProcessHeap(), 0, info->cbMaxToken );
153 static SECURITY_STATUS setup_client( struct sspi_data *data, SEC_CHAR *provider )
155 SECURITY_STATUS ret;
156 SecPkgInfoA *info;
157 TimeStamp ttl;
159 trace( "setting up client\n" );
161 ret = pQuerySecurityPackageInfoA( provider, &info );
162 ok( ret == SEC_E_OK, "QuerySecurityPackageInfo returned %08x\n", ret );
164 setup_buffers( data, info );
165 pFreeContextBuffer( info );
167 ret = pAcquireCredentialsHandleA( NULL, provider, SECPKG_CRED_OUTBOUND, NULL,
168 data->id, NULL, NULL, &data->cred, &ttl );
169 ok( ret == SEC_E_OK, "AcquireCredentialsHandleA returned %08x\n", ret );
170 return ret;
173 static SECURITY_STATUS setup_server( struct sspi_data *data, SEC_CHAR *provider )
175 SECURITY_STATUS ret;
176 SecPkgInfoA *info;
177 TimeStamp ttl;
179 trace( "setting up server\n" );
181 ret = pQuerySecurityPackageInfoA( provider, &info );
182 ok( ret == SEC_E_OK, "QuerySecurityPackageInfo returned %08x\n", ret );
184 setup_buffers( data, info );
185 pFreeContextBuffer( info );
187 ret = pAcquireCredentialsHandleA( NULL, provider, SECPKG_CRED_INBOUND, NULL,
188 NULL, NULL, NULL, &data->cred, &ttl );
189 ok( ret == SEC_E_OK, "AcquireCredentialsHandleA returned %08x\n", ret );
190 return ret;
193 static SECURITY_STATUS run_client( struct sspi_data *data, BOOL first )
195 SECURITY_STATUS ret;
196 TimeStamp ttl;
197 ULONG attr;
199 trace( "running client for the %s time\n", first ? "first" : "second" );
201 data->out_buf->pBuffers[0].cbBuffer = data->max_token;
202 data->out_buf->pBuffers[0].BufferType = SECBUFFER_TOKEN;
204 ret = pInitializeSecurityContextA( first ? &data->cred : NULL, first ? NULL : &data->ctxt,
205 NULL, 0, 0, SECURITY_NETWORK_DREP, first ? NULL : data->in_buf,
206 0, &data->ctxt, data->out_buf, &attr, &ttl );
207 if (ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
209 pCompleteAuthToken( &data->ctxt, data->out_buf );
210 if (ret == SEC_I_COMPLETE_AND_CONTINUE)
211 ret = SEC_I_CONTINUE_NEEDED;
212 else if (ret == SEC_I_COMPLETE_NEEDED)
213 ret = SEC_E_OK;
215 ok( data->out_buf->pBuffers[0].BufferType == SECBUFFER_TOKEN,
216 "buffer type changed from SECBUFFER_TOKEN to %u\n", data->out_buf->pBuffers[0].BufferType );
217 ok( data->out_buf->pBuffers[0].cbBuffer < data->max_token,
218 "InitializeSecurityContext didn't change buffer size\n" );
219 return ret;
222 static SECURITY_STATUS run_server( struct sspi_data *data, BOOL first )
224 SECURITY_STATUS ret;
225 TimeStamp ttl;
226 ULONG attr;
228 trace( "running server for the %s time\n", first ? "first" : "second" );
230 ret = pAcceptSecurityContext( &data->cred, first ? NULL : &data->ctxt,
231 data->in_buf, 0, SECURITY_NETWORK_DREP,
232 &data->ctxt, data->out_buf, &attr, &ttl );
233 if (ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
235 pCompleteAuthToken( &data->ctxt, data->out_buf );
236 if (ret == SEC_I_COMPLETE_AND_CONTINUE)
237 ret = SEC_I_CONTINUE_NEEDED;
238 else if (ret == SEC_I_COMPLETE_NEEDED)
239 ret = SEC_E_OK;
241 return ret;
244 static void communicate( struct sspi_data *from, struct sspi_data *to )
246 trace( "running communicate\n" );
247 memset( to->in_buf->pBuffers[0].pvBuffer, 0, to->max_token );
248 memcpy( to->in_buf->pBuffers[0].pvBuffer, from->out_buf->pBuffers[0].pvBuffer,
249 from->out_buf->pBuffers[0].cbBuffer );
250 to->in_buf->pBuffers[0].cbBuffer = from->out_buf->pBuffers[0].cbBuffer;
251 memset( from->out_buf->pBuffers[0].pvBuffer, 0, from->max_token );
254 static void test_authentication(void)
256 SECURITY_STATUS status_c = SEC_I_CONTINUE_NEEDED,
257 status_s = SEC_I_CONTINUE_NEEDED, status;
258 struct sspi_data client, server;
259 SEC_WINNT_AUTH_IDENTITY_A id;
260 SecPkgContext_NegotiationInfoA info;
261 SecPkgContext_Sizes sizes;
262 SecPkgInfoA *pi;
263 BOOL first = TRUE;
265 memset(&client, 0, sizeof(client));
266 memset(&server, 0, sizeof(server));
268 id.User = (unsigned char *)"user";
269 id.UserLength = strlen( "user" );
270 id.Domain = (unsigned char *)"domain";
271 id.DomainLength = strlen( "domain" );
272 id.Password = (unsigned char *)"password";
273 id.PasswordLength = strlen( "password" );
274 id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
276 client.id = &id;
277 if ((status = setup_client( &client, (SEC_CHAR *)"Negotiate" )))
279 skip( "setup_client returned %08x, skipping test\n", status );
280 return;
282 if ((status = setup_server( &server, (SEC_CHAR *)"Negotiate" )))
284 skip( "setup_server returned %08x, skipping test\n", status );
285 pFreeCredentialsHandle( &client.cred );
286 return;
289 while (status_c == SEC_I_CONTINUE_NEEDED && status_s == SEC_I_CONTINUE_NEEDED)
291 status_c = run_client( &client, first );
292 ok( status_c == SEC_E_OK || status_c == SEC_I_CONTINUE_NEEDED,
293 "client returned %08x, more tests will fail\n", status_c );
295 communicate( &client, &server );
297 status_s = run_server( &server, first );
298 ok( status_s == SEC_E_OK || status_s == SEC_I_CONTINUE_NEEDED ||
299 status_s == SEC_E_LOGON_DENIED,
300 "server returned %08x, more tests will fail\n", status_s );
302 communicate( &server, &client );
303 trace( "looping\n");
304 first = FALSE;
306 if (status_c != SEC_E_OK)
308 skip( "authentication failed, skipping remaining tests\n" );
309 goto done;
312 sizes.cbMaxToken = 0xdeadbeef;
313 sizes.cbMaxSignature = 0xdeadbeef;
314 sizes.cbSecurityTrailer = 0xdeadbeef;
315 sizes.cbBlockSize = 0xdeadbeef;
316 status_c = pQueryContextAttributesA( &client.ctxt, SECPKG_ATTR_SIZES, &sizes );
317 ok( status_c == SEC_E_OK, "pQueryContextAttributesA returned %08x\n", status_c );
318 ok( sizes.cbMaxToken == 2888 || sizes.cbMaxToken == 1904,
319 "expected 2888 or 1904, got %u\n", sizes.cbMaxToken );
320 ok( sizes.cbMaxSignature == 16, "expected 16, got %u\n", sizes.cbMaxSignature );
321 ok( sizes.cbSecurityTrailer == 16, "expected 16, got %u\n", sizes.cbSecurityTrailer );
322 ok( !sizes.cbBlockSize, "expected 0, got %u\n", sizes.cbBlockSize );
324 memset( &info, 0, sizeof(info) );
325 status_c = pQueryContextAttributesA( &client.ctxt, SECPKG_ATTR_NEGOTIATION_INFO, &info );
326 ok( status_c == SEC_E_OK, "pQueryContextAttributesA returned %08x\n", status_c );
328 pi = info.PackageInfo;
329 ok( info.NegotiationState == SECPKG_NEGOTIATION_COMPLETE, "got %u\n", info.NegotiationState );
330 ok( pi != NULL, "expected non-NULL PackageInfo\n" );
331 if (pi)
333 ok( pi->fCapabilities == NTLM_BASE_CAPS ||
334 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_READONLY_WITH_CHECKSUM) ||
335 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS) ||
336 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS|
337 SECPKG_FLAG_APPCONTAINER_CHECKS),
338 "got %08x\n", pi->fCapabilities );
339 ok( pi->wVersion == 1, "got %u\n", pi->wVersion );
340 ok( pi->wRPCID == RPC_C_AUTHN_WINNT, "got %u\n", pi->wRPCID );
341 ok( !lstrcmpA( pi->Name, "NTLM" ), "got %s\n", pi->Name );
344 done:
345 cleanup_buffers( &client );
346 cleanup_buffers( &server );
348 if (client.ctxt.dwLower || client.ctxt.dwUpper)
350 status_c = pDeleteSecurityContext( &client.ctxt );
351 ok( status_c == SEC_E_OK, "DeleteSecurityContext returned %08x\n", status_c );
354 if (server.ctxt.dwLower || server.ctxt.dwUpper)
356 status_s = pDeleteSecurityContext( &server.ctxt );
357 ok( status_s == SEC_E_OK, "DeleteSecurityContext returned %08x\n", status_s );
360 if (client.cred.dwLower || client.cred.dwUpper)
362 status_c = pFreeCredentialsHandle( &client.cred );
363 ok( status_c == SEC_E_OK, "FreeCredentialsHandle returned %08x\n", status_c );
366 if (server.cred.dwLower || server.cred.dwUpper)
368 status_s = pFreeCredentialsHandle(&server.cred);
369 ok( status_s == SEC_E_OK, "FreeCredentialsHandle returned %08x\n", status_s );
373 START_TEST(negotiate)
375 SecPkgInfoA *info;
377 init_function_ptrs();
379 if (!pFreeCredentialsHandle || !pAcquireCredentialsHandleA || !pQuerySecurityPackageInfoA ||
380 !pFreeContextBuffer)
382 win_skip("functions are not available\n");
383 return;
385 if (pQuerySecurityPackageInfoA( (SEC_CHAR *)"Negotiate", &info ))
387 ok( 0, "Negotiate package not installed, skipping test\n" );
388 return;
390 ok( info->fCapabilities == NEGOTIATE_BASE_CAPS ||
391 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_READONLY_WITH_CHECKSUM) ||
392 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS) ||
393 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS|
394 SECPKG_FLAG_APPCONTAINER_CHECKS),
395 "got %08x\n", info->fCapabilities );
396 ok( info->wVersion == 1, "got %u\n", info->wVersion );
397 ok( info->wRPCID == RPC_C_AUTHN_GSS_NEGOTIATE, "got %u\n", info->wRPCID );
398 ok( !lstrcmpA( info->Name, "Negotiate" ), "got %s\n", info->Name );
399 pFreeContextBuffer( info );
401 test_authentication();