include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / secur32 / tests / negotiate.c
blobdc470a332c730f9f1410058aba437eef71218dae
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>
25 #include <ntstatus.h>
26 #define WIN32_NO_STATUS
27 #include <windef.h>
28 #include <winbase.h>
29 #define SECURITY_WIN32
30 #include <sspi.h>
31 #include <rpc.h>
32 #include <rpcdce.h>
33 #include <secext.h>
34 #include <security.h>
35 #include <ntsecapi.h>
36 #include <winternl.h>
38 #include "wine/test.h"
40 #define NEGOTIATE_BASE_CAPS ( \
41 SECPKG_FLAG_INTEGRITY | \
42 SECPKG_FLAG_PRIVACY | \
43 SECPKG_FLAG_CONNECTION | \
44 SECPKG_FLAG_MULTI_REQUIRED | \
45 SECPKG_FLAG_EXTENDED_ERROR | \
46 SECPKG_FLAG_IMPERSONATION | \
47 SECPKG_FLAG_ACCEPT_WIN32_NAME | \
48 SECPKG_FLAG_NEGOTIABLE | \
49 SECPKG_FLAG_GSS_COMPATIBLE | \
50 SECPKG_FLAG_LOGON )
52 #define NTLM_BASE_CAPS ( \
53 SECPKG_FLAG_INTEGRITY | \
54 SECPKG_FLAG_PRIVACY | \
55 SECPKG_FLAG_TOKEN_ONLY | \
56 SECPKG_FLAG_CONNECTION | \
57 SECPKG_FLAG_MULTI_REQUIRED | \
58 SECPKG_FLAG_IMPERSONATION | \
59 SECPKG_FLAG_ACCEPT_WIN32_NAME | \
60 SECPKG_FLAG_NEGOTIABLE | \
61 SECPKG_FLAG_LOGON )
63 struct sspi_data
65 CredHandle cred;
66 CtxtHandle ctxt;
67 PSecBufferDesc in_buf;
68 PSecBufferDesc out_buf;
69 PSEC_WINNT_AUTH_IDENTITY_A id;
70 ULONG max_token;
73 static void cleanup_buffers( struct sspi_data *data )
75 unsigned int i;
77 if (data->in_buf)
79 for (i = 0; i < data->in_buf->cBuffers; ++i)
80 HeapFree( GetProcessHeap(), 0, data->in_buf->pBuffers[i].pvBuffer );
81 HeapFree( GetProcessHeap(), 0, data->in_buf->pBuffers );
82 HeapFree( GetProcessHeap(), 0, data->in_buf );
84 if (data->out_buf)
86 for (i = 0; i < data->out_buf->cBuffers; ++i)
87 HeapFree( GetProcessHeap(), 0, data->out_buf->pBuffers[i].pvBuffer );
88 HeapFree( GetProcessHeap(), 0, data->out_buf->pBuffers );
89 HeapFree( GetProcessHeap(), 0, data->out_buf );
93 static void setup_buffers( struct sspi_data *data, SecPkgInfoA *info )
95 SecBuffer *buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBuffer) );
97 data->in_buf = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBufferDesc) );
98 data->out_buf = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBufferDesc) );
99 data->max_token = info->cbMaxToken;
101 data->in_buf->ulVersion = SECBUFFER_VERSION;
102 data->in_buf->cBuffers = 1;
103 data->in_buf->pBuffers = buffer;
105 buffer->cbBuffer = info->cbMaxToken;
106 buffer->BufferType = SECBUFFER_TOKEN;
107 buffer->pvBuffer = HeapAlloc( GetProcessHeap(), 0, info->cbMaxToken );
109 buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBuffer) );
111 data->out_buf->ulVersion = SECBUFFER_VERSION;
112 data->out_buf->cBuffers = 1;
113 data->out_buf->pBuffers = buffer;
115 buffer->cbBuffer = info->cbMaxToken;
116 buffer->BufferType = SECBUFFER_TOKEN;
117 buffer->pvBuffer = HeapAlloc( GetProcessHeap(), 0, info->cbMaxToken );
120 static SECURITY_STATUS setup_client( struct sspi_data *data, SEC_CHAR *provider )
122 SECURITY_STATUS ret;
123 SecPkgInfoA *info;
124 TimeStamp ttl;
126 trace( "setting up client\n" );
128 ret = QuerySecurityPackageInfoA( provider, &info );
129 ok( ret == SEC_E_OK, "QuerySecurityPackageInfo returned %08lx\n", ret );
131 setup_buffers( data, info );
132 FreeContextBuffer( info );
134 ret = AcquireCredentialsHandleA( NULL, provider, SECPKG_CRED_OUTBOUND, NULL,
135 data->id, NULL, NULL, &data->cred, &ttl );
136 ok( ret == SEC_E_OK, "AcquireCredentialsHandleA returned %08lx\n", ret );
137 return ret;
140 static SECURITY_STATUS setup_server( struct sspi_data *data, SEC_CHAR *provider )
142 SECURITY_STATUS ret;
143 SecPkgInfoA *info;
144 TimeStamp ttl;
146 trace( "setting up server\n" );
148 ret = QuerySecurityPackageInfoA( provider, &info );
149 ok( ret == SEC_E_OK, "QuerySecurityPackageInfo returned %08lx\n", ret );
151 setup_buffers( data, info );
152 FreeContextBuffer( info );
154 ret = AcquireCredentialsHandleA( NULL, provider, SECPKG_CRED_INBOUND, NULL,
155 NULL, NULL, NULL, &data->cred, &ttl );
156 ok( ret == SEC_E_OK, "AcquireCredentialsHandleA returned %08lx\n", ret );
157 return ret;
160 static SECURITY_STATUS run_client( struct sspi_data *data, BOOL first )
162 SECURITY_STATUS ret;
163 TimeStamp ttl;
164 ULONG attr;
166 trace( "running client for the %s time\n", first ? "first" : "second" );
168 data->out_buf->pBuffers[0].cbBuffer = data->max_token;
169 data->out_buf->pBuffers[0].BufferType = SECBUFFER_TOKEN;
171 ret = InitializeSecurityContextA( first ? &data->cred : NULL, first ? NULL : &data->ctxt,
172 NULL, 0, 0, SECURITY_NETWORK_DREP, first ? NULL : data->in_buf,
173 0, &data->ctxt, data->out_buf, &attr, &ttl );
174 if (ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
176 CompleteAuthToken( &data->ctxt, data->out_buf );
177 if (ret == SEC_I_COMPLETE_AND_CONTINUE)
178 ret = SEC_I_CONTINUE_NEEDED;
179 else if (ret == SEC_I_COMPLETE_NEEDED)
180 ret = SEC_E_OK;
182 ok( data->out_buf->pBuffers[0].BufferType == SECBUFFER_TOKEN,
183 "buffer type changed from SECBUFFER_TOKEN to %lu\n", data->out_buf->pBuffers[0].BufferType );
184 ok( data->out_buf->pBuffers[0].cbBuffer < data->max_token,
185 "InitializeSecurityContext didn't change buffer size\n" );
186 return ret;
189 static SECURITY_STATUS run_server( struct sspi_data *data, BOOL first )
191 SECURITY_STATUS ret;
192 TimeStamp ttl;
193 ULONG attr;
195 trace( "running server for the %s time\n", first ? "first" : "second" );
197 ret = AcceptSecurityContext( &data->cred, first ? NULL : &data->ctxt,
198 data->in_buf, 0, SECURITY_NETWORK_DREP,
199 &data->ctxt, data->out_buf, &attr, &ttl );
200 if (ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
202 CompleteAuthToken( &data->ctxt, data->out_buf );
203 if (ret == SEC_I_COMPLETE_AND_CONTINUE)
204 ret = SEC_I_CONTINUE_NEEDED;
205 else if (ret == SEC_I_COMPLETE_NEEDED)
206 ret = SEC_E_OK;
208 return ret;
211 static void communicate( struct sspi_data *from, struct sspi_data *to )
213 trace( "running communicate\n" );
214 memset( to->in_buf->pBuffers[0].pvBuffer, 0, to->max_token );
215 memcpy( to->in_buf->pBuffers[0].pvBuffer, from->out_buf->pBuffers[0].pvBuffer,
216 from->out_buf->pBuffers[0].cbBuffer );
217 to->in_buf->pBuffers[0].cbBuffer = from->out_buf->pBuffers[0].cbBuffer;
218 memset( from->out_buf->pBuffers[0].pvBuffer, 0, from->max_token );
221 static void test_authentication(void)
223 SECURITY_STATUS status_c = SEC_I_CONTINUE_NEEDED,
224 status_s = SEC_I_CONTINUE_NEEDED, status;
225 struct sspi_data client, server;
226 SEC_WINNT_AUTH_IDENTITY_A id;
227 SecPkgContext_NegotiationInfoA info;
228 SecPkgContext_Sizes sizes;
229 SecPkgInfoA *pi;
230 BOOL first = TRUE;
232 memset(&client, 0, sizeof(client));
233 memset(&server, 0, sizeof(server));
235 id.User = (unsigned char *)"user";
236 id.UserLength = strlen( "user" );
237 id.Domain = (unsigned char *)"domain";
238 id.DomainLength = strlen( "domain" );
239 id.Password = (unsigned char *)"password";
240 id.PasswordLength = strlen( "password" );
241 id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
243 client.id = &id;
244 if ((status = setup_client( &client, (SEC_CHAR *)"Negotiate" )))
246 skip( "setup_client returned %08lx, skipping test\n", status );
247 return;
249 if ((status = setup_server( &server, (SEC_CHAR *)"Negotiate" )))
251 skip( "setup_server returned %08lx, skipping test\n", status );
252 FreeCredentialsHandle( &client.cred );
253 return;
256 while (status_c == SEC_I_CONTINUE_NEEDED && status_s == SEC_I_CONTINUE_NEEDED)
258 status_c = run_client( &client, first );
259 ok( status_c == SEC_E_OK || status_c == SEC_I_CONTINUE_NEEDED,
260 "client returned %08lx, more tests will fail\n", status_c );
262 communicate( &client, &server );
264 status_s = run_server( &server, first );
265 ok( status_s == SEC_E_OK || status_s == SEC_I_CONTINUE_NEEDED ||
266 status_s == SEC_E_LOGON_DENIED,
267 "server returned %08lx, more tests will fail\n", status_s );
269 communicate( &server, &client );
270 trace( "looping\n");
271 first = FALSE;
273 if (status_c != SEC_E_OK)
275 skip( "authentication failed, skipping remaining tests\n" );
276 goto done;
279 sizes.cbMaxToken = 0xdeadbeef;
280 sizes.cbMaxSignature = 0xdeadbeef;
281 sizes.cbSecurityTrailer = 0xdeadbeef;
282 sizes.cbBlockSize = 0xdeadbeef;
283 status_c = QueryContextAttributesA( &client.ctxt, SECPKG_ATTR_SIZES, &sizes );
284 ok( status_c == SEC_E_OK, "pQueryContextAttributesA returned %08lx\n", status_c );
285 ok( sizes.cbMaxToken == 2888 || sizes.cbMaxToken == 1904,
286 "expected 2888 or 1904, got %lu\n", sizes.cbMaxToken );
287 ok( sizes.cbMaxSignature == 16, "expected 16, got %lu\n", sizes.cbMaxSignature );
288 ok( sizes.cbSecurityTrailer == 16, "expected 16, got %lu\n", sizes.cbSecurityTrailer );
289 ok( !sizes.cbBlockSize, "expected 0, got %lu\n", sizes.cbBlockSize );
291 memset( &info, 0, sizeof(info) );
292 status_c = QueryContextAttributesA( &client.ctxt, SECPKG_ATTR_NEGOTIATION_INFO, &info );
293 ok( status_c == SEC_E_OK, "QueryContextAttributesA returned %08lx\n", status_c );
295 pi = info.PackageInfo;
296 ok( info.NegotiationState == SECPKG_NEGOTIATION_COMPLETE, "got %lu\n", info.NegotiationState );
297 ok( pi != NULL, "expected non-NULL PackageInfo\n" );
298 if (pi)
300 UINT expected, got;
301 char *eob;
303 ok( pi->fCapabilities == NTLM_BASE_CAPS ||
304 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_READONLY_WITH_CHECKSUM) ||
305 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS) ||
306 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS|SECPKG_FLAG_APPCONTAINER_CHECKS) ||
307 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS|SECPKG_FLAG_APPLY_LOOPBACK) ||
308 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS|SECPKG_FLAG_APPLY_LOOPBACK|
309 SECPKG_FLAG_APPCONTAINER_CHECKS),
310 "got %08lx\n", pi->fCapabilities );
311 ok( pi->wVersion == 1, "got %u\n", pi->wVersion );
312 ok( pi->wRPCID == RPC_C_AUTHN_WINNT, "got %u\n", pi->wRPCID );
313 ok( !lstrcmpA( pi->Name, "NTLM" ), "got %s\n", pi->Name );
315 expected = sizeof(*pi) + lstrlenA(pi->Name) + 1 + lstrlenA(pi->Comment) + 1;
316 got = HeapSize(GetProcessHeap(), 0, pi);
317 ok( got == expected, "got %u, expected %u\n", got, expected );
318 eob = (char *)pi + expected;
319 ok( pi->Name + lstrlenA(pi->Name) < eob, "Name doesn't fit into allocated block\n" );
320 ok( pi->Comment + lstrlenA(pi->Comment) < eob, "Comment doesn't fit into allocated block\n" );
322 status = FreeContextBuffer( pi );
323 ok( status == SEC_E_OK, "FreeContextBuffer error %#lx\n", status );
326 done:
327 cleanup_buffers( &client );
328 cleanup_buffers( &server );
330 if (client.ctxt.dwLower || client.ctxt.dwUpper)
332 status_c = DeleteSecurityContext( &client.ctxt );
333 ok( status_c == SEC_E_OK, "DeleteSecurityContext returned %08lx\n", status_c );
336 if (server.ctxt.dwLower || server.ctxt.dwUpper)
338 status_s = DeleteSecurityContext( &server.ctxt );
339 ok( status_s == SEC_E_OK, "DeleteSecurityContext returned %08lx\n", status_s );
342 if (client.cred.dwLower || client.cred.dwUpper)
344 status_c = FreeCredentialsHandle( &client.cred );
345 ok( status_c == SEC_E_OK, "FreeCredentialsHandle returned %08lx\n", status_c );
348 if (server.cred.dwLower || server.cred.dwUpper)
350 status_s = FreeCredentialsHandle(&server.cred);
351 ok( status_s == SEC_E_OK, "FreeCredentialsHandle returned %08lx\n", status_s );
355 static void test_Negotiate(void)
357 HANDLE lsa;
358 NTSTATUS status, call_status;
359 LSA_STRING name;
360 ULONG size, id;
361 NEGOTIATE_CALLER_NAME_REQUEST req;
362 NEGOTIATE_CALLER_NAME_RESPONSE *resp;
364 status = LsaConnectUntrusted(&lsa);
365 ok(!status, "got %08lx\n", status);
367 RtlInitAnsiString(&name, "Negotiate");
368 id = 0xdeadbeef;
369 status = LsaLookupAuthenticationPackage(lsa, &name, &id);
370 ok(!status, "got %08lx\n", status);
371 ok(id == 0, "got %lu\n", id);
373 req.MessageType = NegGetCallerName;
374 req.LogonId.LowPart = 0;
375 req.LogonId.HighPart = 0;
376 resp = (void *)(ULONG_PTR)0xdeadbeef;
377 size = 0xdeadbeef;
378 call_status = 0xdeadbeef;
379 status = LsaCallAuthenticationPackage(lsa, 0, &req, sizeof(req), (void **)&resp, &size, &call_status);
380 ok(status == STATUS_SUCCESS, "got %08lx\n", status);
381 ok(call_status == STATUS_NO_SUCH_LOGON_SESSION || call_status == STATUS_SUCCESS, "got %08lx\n", call_status);
382 if (call_status == STATUS_NO_SUCH_LOGON_SESSION)
384 ok(size == 0, "got %lu\n", size);
385 ok(resp == NULL, "got %p\n", resp);
387 else /* STATUS_SUCCESS */
389 if (resp && resp->CallerName)
390 trace("resp->CallerName = %s\n", debugstr_w(resp->CallerName));
391 ok(resp != NULL, "got NULL\n");
392 ok(resp->MessageType == NegGetCallerName, "got %lu\n", resp->MessageType);
393 ok((char *)resp->CallerName >= (char *)(resp + 1), "got %p/%p\n", resp, resp->CallerName);
394 ok(size >= sizeof(*resp) + (wcslen(resp->CallerName) + 1) * sizeof(WCHAR), "got %lu\n", size);
397 size = 0xdeadbeef;
398 call_status = 0xdeadbeef;
399 status = LsaCallAuthenticationPackage(lsa, 0, NULL, 0, NULL, &size, &call_status);
400 ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status);
401 ok(call_status == STATUS_SUCCESS, "got %08lx\n", call_status);
402 ok(size == 0, "got %08lx\n", size);
404 size = 0xdeadbeef;
405 status = LsaCallAuthenticationPackage(lsa, 0, NULL, 0, NULL, &size, NULL);
406 ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status);
407 ok(size == 0, "got %08lx\n", size);
409 call_status = 0xdeadbeef;
410 status = LsaCallAuthenticationPackage(lsa, 0, NULL, 0, NULL, NULL, &call_status);
411 ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status);
412 ok(call_status == STATUS_SUCCESS, "got %08lx\n", call_status);
414 resp = (void *)(ULONG_PTR)0xdeadbeef;
415 size = 0xdeadbeef;
416 call_status = 0xdeadbeef;
417 status = LsaCallAuthenticationPackage(lsa, 0xdeadbeef, NULL, 0, (void **)&resp, &size, &call_status);
418 ok(status == STATUS_NO_SUCH_PACKAGE, "got %08lx\n", status);
419 ok(call_status == STATUS_SUCCESS, "got %08lx\n", call_status);
420 ok(size == 0, "got %08lx\n", size);
421 ok(resp == NULL, "got %p\n", resp);
423 LsaDeregisterLogonProcess(lsa);
426 START_TEST(negotiate)
428 SecPkgInfoA *info;
430 if (QuerySecurityPackageInfoA( (SEC_CHAR *)"Negotiate", &info ))
432 ok( 0, "Negotiate package not installed, skipping test\n" );
433 return;
435 ok( info->fCapabilities == NEGOTIATE_BASE_CAPS ||
436 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_READONLY_WITH_CHECKSUM) ||
437 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS) ||
438 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS|
439 SECPKG_FLAG_APPCONTAINER_CHECKS),
440 "got %08lx\n", info->fCapabilities );
441 ok( info->wVersion == 1, "got %u\n", info->wVersion );
442 ok( info->wRPCID == RPC_C_AUTHN_GSS_NEGOTIATE, "got %u\n", info->wRPCID );
443 ok( !lstrcmpA( info->Name, "Negotiate" ), "got %s\n", info->Name );
444 FreeContextBuffer( info );
446 test_authentication();
447 test_Negotiate();