095aee6cb57579ef1f6224cfd0605486156a2272
[reactos.git] / modules / rostests / winetests / secur32 / negotiate.c
1 /*
2 * Tests for the Negotiate security provider
3 *
4 * Copyright 2005, 2006 Kai Blin
5 * Copyright 2012 Hans Leidekker for CodeWeavers
6 *
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.
11 *
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.
16 *
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
20 */
21
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>
31
32 #include "wine/test.h"
33
34 #define NEGOTIATE_BASE_CAPS ( \
35 SECPKG_FLAG_INTEGRITY | \
36 SECPKG_FLAG_PRIVACY | \
37 SECPKG_FLAG_CONNECTION | \
38 SECPKG_FLAG_MULTI_REQUIRED | \
39 SECPKG_FLAG_EXTENDED_ERROR | \
40 SECPKG_FLAG_IMPERSONATION | \
41 SECPKG_FLAG_ACCEPT_WIN32_NAME | \
42 SECPKG_FLAG_NEGOTIABLE | \
43 SECPKG_FLAG_GSS_COMPATIBLE | \
44 SECPKG_FLAG_LOGON )
45
46 #define NTLM_BASE_CAPS ( \
47 SECPKG_FLAG_INTEGRITY | \
48 SECPKG_FLAG_PRIVACY | \
49 SECPKG_FLAG_TOKEN_ONLY | \
50 SECPKG_FLAG_CONNECTION | \
51 SECPKG_FLAG_MULTI_REQUIRED | \
52 SECPKG_FLAG_IMPERSONATION | \
53 SECPKG_FLAG_ACCEPT_WIN32_NAME | \
54 SECPKG_FLAG_NEGOTIABLE | \
55 SECPKG_FLAG_LOGON )
56
57 struct sspi_data
58 {
59 CredHandle cred;
60 CtxtHandle ctxt;
61 PSecBufferDesc in_buf;
62 PSecBufferDesc out_buf;
63 PSEC_WINNT_AUTH_IDENTITY_A id;
64 ULONG max_token;
65 };
66
67 static void cleanup_buffers( struct sspi_data *data )
68 {
69 unsigned int i;
70
71 if (data->in_buf)
72 {
73 for (i = 0; i < data->in_buf->cBuffers; ++i)
74 HeapFree( GetProcessHeap(), 0, data->in_buf->pBuffers[i].pvBuffer );
75 HeapFree( GetProcessHeap(), 0, data->in_buf->pBuffers );
76 HeapFree( GetProcessHeap(), 0, data->in_buf );
77 }
78 if (data->out_buf)
79 {
80 for (i = 0; i < data->out_buf->cBuffers; ++i)
81 HeapFree( GetProcessHeap(), 0, data->out_buf->pBuffers[i].pvBuffer );
82 HeapFree( GetProcessHeap(), 0, data->out_buf->pBuffers );
83 HeapFree( GetProcessHeap(), 0, data->out_buf );
84 }
85 }
86
87 static void setup_buffers( struct sspi_data *data, SecPkgInfoA *info )
88 {
89 SecBuffer *buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBuffer) );
90
91 data->in_buf = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBufferDesc) );
92 data->out_buf = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBufferDesc) );
93 data->max_token = info->cbMaxToken;
94
95 data->in_buf->ulVersion = SECBUFFER_VERSION;
96 data->in_buf->cBuffers = 1;
97 data->in_buf->pBuffers = buffer;
98
99 buffer->cbBuffer = info->cbMaxToken;
100 buffer->BufferType = SECBUFFER_TOKEN;
101 buffer->pvBuffer = HeapAlloc( GetProcessHeap(), 0, info->cbMaxToken );
102
103 buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBuffer) );
104
105 data->out_buf->ulVersion = SECBUFFER_VERSION;
106 data->out_buf->cBuffers = 1;
107 data->out_buf->pBuffers = buffer;
108
109 buffer->cbBuffer = info->cbMaxToken;
110 buffer->BufferType = SECBUFFER_TOKEN;
111 buffer->pvBuffer = HeapAlloc( GetProcessHeap(), 0, info->cbMaxToken );
112 }
113
114 static SECURITY_STATUS setup_client( struct sspi_data *data, SEC_CHAR *provider )
115 {
116 SECURITY_STATUS ret;
117 SecPkgInfoA *info;
118 TimeStamp ttl;
119
120 trace( "setting up client\n" );
121
122 ret = QuerySecurityPackageInfoA( provider, &info );
123 ok( ret == SEC_E_OK, "QuerySecurityPackageInfo returned %08x\n", ret );
124
125 setup_buffers( data, info );
126 FreeContextBuffer( info );
127
128 ret = AcquireCredentialsHandleA( NULL, provider, SECPKG_CRED_OUTBOUND, NULL,
129 data->id, NULL, NULL, &data->cred, &ttl );
130 ok( ret == SEC_E_OK, "AcquireCredentialsHandleA returned %08x\n", ret );
131 return ret;
132 }
133
134 static SECURITY_STATUS setup_server( struct sspi_data *data, SEC_CHAR *provider )
135 {
136 SECURITY_STATUS ret;
137 SecPkgInfoA *info;
138 TimeStamp ttl;
139
140 trace( "setting up server\n" );
141
142 ret = QuerySecurityPackageInfoA( provider, &info );
143 ok( ret == SEC_E_OK, "QuerySecurityPackageInfo returned %08x\n", ret );
144
145 setup_buffers( data, info );
146 FreeContextBuffer( info );
147
148 ret = AcquireCredentialsHandleA( NULL, provider, SECPKG_CRED_INBOUND, NULL,
149 NULL, NULL, NULL, &data->cred, &ttl );
150 ok( ret == SEC_E_OK, "AcquireCredentialsHandleA returned %08x\n", ret );
151 return ret;
152 }
153
154 static SECURITY_STATUS run_client( struct sspi_data *data, BOOL first )
155 {
156 SECURITY_STATUS ret;
157 TimeStamp ttl;
158 ULONG attr;
159
160 trace( "running client for the %s time\n", first ? "first" : "second" );
161
162 data->out_buf->pBuffers[0].cbBuffer = data->max_token;
163 data->out_buf->pBuffers[0].BufferType = SECBUFFER_TOKEN;
164
165 ret = InitializeSecurityContextA( first ? &data->cred : NULL, first ? NULL : &data->ctxt,
166 NULL, 0, 0, SECURITY_NETWORK_DREP, first ? NULL : data->in_buf,
167 0, &data->ctxt, data->out_buf, &attr, &ttl );
168 if (ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
169 {
170 CompleteAuthToken( &data->ctxt, data->out_buf );
171 if (ret == SEC_I_COMPLETE_AND_CONTINUE)
172 ret = SEC_I_CONTINUE_NEEDED;
173 else if (ret == SEC_I_COMPLETE_NEEDED)
174 ret = SEC_E_OK;
175 }
176 ok( data->out_buf->pBuffers[0].BufferType == SECBUFFER_TOKEN,
177 "buffer type changed from SECBUFFER_TOKEN to %u\n", data->out_buf->pBuffers[0].BufferType );
178 ok( data->out_buf->pBuffers[0].cbBuffer < data->max_token,
179 "InitializeSecurityContext didn't change buffer size\n" );
180 return ret;
181 }
182
183 static SECURITY_STATUS run_server( struct sspi_data *data, BOOL first )
184 {
185 SECURITY_STATUS ret;
186 TimeStamp ttl;
187 ULONG attr;
188
189 trace( "running server for the %s time\n", first ? "first" : "second" );
190
191 ret = AcceptSecurityContext( &data->cred, first ? NULL : &data->ctxt,
192 data->in_buf, 0, SECURITY_NETWORK_DREP,
193 &data->ctxt, data->out_buf, &attr, &ttl );
194 if (ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
195 {
196 CompleteAuthToken( &data->ctxt, data->out_buf );
197 if (ret == SEC_I_COMPLETE_AND_CONTINUE)
198 ret = SEC_I_CONTINUE_NEEDED;
199 else if (ret == SEC_I_COMPLETE_NEEDED)
200 ret = SEC_E_OK;
201 }
202 return ret;
203 }
204
205 static void communicate( struct sspi_data *from, struct sspi_data *to )
206 {
207 trace( "running communicate\n" );
208 memset( to->in_buf->pBuffers[0].pvBuffer, 0, to->max_token );
209 memcpy( to->in_buf->pBuffers[0].pvBuffer, from->out_buf->pBuffers[0].pvBuffer,
210 from->out_buf->pBuffers[0].cbBuffer );
211 to->in_buf->pBuffers[0].cbBuffer = from->out_buf->pBuffers[0].cbBuffer;
212 memset( from->out_buf->pBuffers[0].pvBuffer, 0, from->max_token );
213 }
214
215 static void test_authentication(void)
216 {
217 SECURITY_STATUS status_c = SEC_I_CONTINUE_NEEDED,
218 status_s = SEC_I_CONTINUE_NEEDED, status;
219 struct sspi_data client, server;
220 SEC_WINNT_AUTH_IDENTITY_A id;
221 SecPkgContext_NegotiationInfoA info;
222 SecPkgContext_Sizes sizes;
223 SecPkgInfoA *pi;
224 BOOL first = TRUE;
225
226 memset(&client, 0, sizeof(client));
227 memset(&server, 0, sizeof(server));
228
229 id.User = (unsigned char *)"user";
230 id.UserLength = strlen( "user" );
231 id.Domain = (unsigned char *)"domain";
232 id.DomainLength = strlen( "domain" );
233 id.Password = (unsigned char *)"password";
234 id.PasswordLength = strlen( "password" );
235 id.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
236
237 client.id = &id;
238 if ((status = setup_client( &client, (SEC_CHAR *)"Negotiate" )))
239 {
240 skip( "setup_client returned %08x, skipping test\n", status );
241 return;
242 }
243 if ((status = setup_server( &server, (SEC_CHAR *)"Negotiate" )))
244 {
245 skip( "setup_server returned %08x, skipping test\n", status );
246 FreeCredentialsHandle( &client.cred );
247 return;
248 }
249
250 while (status_c == SEC_I_CONTINUE_NEEDED && status_s == SEC_I_CONTINUE_NEEDED)
251 {
252 status_c = run_client( &client, first );
253 ok( status_c == SEC_E_OK || status_c == SEC_I_CONTINUE_NEEDED,
254 "client returned %08x, more tests will fail\n", status_c );
255
256 communicate( &client, &server );
257
258 status_s = run_server( &server, first );
259 ok( status_s == SEC_E_OK || status_s == SEC_I_CONTINUE_NEEDED ||
260 status_s == SEC_E_LOGON_DENIED,
261 "server returned %08x, more tests will fail\n", status_s );
262
263 communicate( &server, &client );
264 trace( "looping\n");
265 first = FALSE;
266 }
267 if (status_c != SEC_E_OK)
268 {
269 skip( "authentication failed, skipping remaining tests\n" );
270 goto done;
271 }
272
273 sizes.cbMaxToken = 0xdeadbeef;
274 sizes.cbMaxSignature = 0xdeadbeef;
275 sizes.cbSecurityTrailer = 0xdeadbeef;
276 sizes.cbBlockSize = 0xdeadbeef;
277 status_c = QueryContextAttributesA( &client.ctxt, SECPKG_ATTR_SIZES, &sizes );
278 ok( status_c == SEC_E_OK, "pQueryContextAttributesA returned %08x\n", status_c );
279 ok( sizes.cbMaxToken == 2888 || sizes.cbMaxToken == 1904,
280 "expected 2888 or 1904, got %u\n", sizes.cbMaxToken );
281 ok( sizes.cbMaxSignature == 16, "expected 16, got %u\n", sizes.cbMaxSignature );
282 ok( sizes.cbSecurityTrailer == 16, "expected 16, got %u\n", sizes.cbSecurityTrailer );
283 ok( !sizes.cbBlockSize, "expected 0, got %u\n", sizes.cbBlockSize );
284
285 memset( &info, 0, sizeof(info) );
286 status_c = QueryContextAttributesA( &client.ctxt, SECPKG_ATTR_NEGOTIATION_INFO, &info );
287 ok( status_c == SEC_E_OK, "QueryContextAttributesA returned %08x\n", status_c );
288
289 pi = info.PackageInfo;
290 ok( info.NegotiationState == SECPKG_NEGOTIATION_COMPLETE, "got %u\n", info.NegotiationState );
291 ok( pi != NULL, "expected non-NULL PackageInfo\n" );
292 if (pi)
293 {
294 UINT expected, got;
295 char *eob;
296
297 ok( pi->fCapabilities == NTLM_BASE_CAPS ||
298 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_READONLY_WITH_CHECKSUM) ||
299 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS) ||
300 pi->fCapabilities == (NTLM_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS|
301 SECPKG_FLAG_APPCONTAINER_CHECKS),
302 "got %08x\n", pi->fCapabilities );
303 ok( pi->wVersion == 1, "got %u\n", pi->wVersion );
304 ok( pi->wRPCID == RPC_C_AUTHN_WINNT, "got %u\n", pi->wRPCID );
305 ok( !lstrcmpA( pi->Name, "NTLM" ), "got %s\n", pi->Name );
306
307 expected = sizeof(*pi) + lstrlenA(pi->Name) + 1 + lstrlenA(pi->Comment) + 1;
308 got = HeapSize(GetProcessHeap(), 0, pi);
309 ok( got == expected, "got %u, expected %u\n", got, expected );
310 eob = (char *)pi + expected;
311 ok( pi->Name + lstrlenA(pi->Name) < eob, "Name doesn't fit into allocated block\n" );
312 ok( pi->Comment + lstrlenA(pi->Comment) < eob, "Comment doesn't fit into allocated block\n" );
313
314 status = FreeContextBuffer( pi );
315 ok( status == SEC_E_OK, "FreeContextBuffer error %#x\n", status );
316 }
317
318 done:
319 cleanup_buffers( &client );
320 cleanup_buffers( &server );
321
322 if (client.ctxt.dwLower || client.ctxt.dwUpper)
323 {
324 status_c = DeleteSecurityContext( &client.ctxt );
325 ok( status_c == SEC_E_OK, "DeleteSecurityContext returned %08x\n", status_c );
326 }
327
328 if (server.ctxt.dwLower || server.ctxt.dwUpper)
329 {
330 status_s = DeleteSecurityContext( &server.ctxt );
331 ok( status_s == SEC_E_OK, "DeleteSecurityContext returned %08x\n", status_s );
332 }
333
334 if (client.cred.dwLower || client.cred.dwUpper)
335 {
336 status_c = FreeCredentialsHandle( &client.cred );
337 ok( status_c == SEC_E_OK, "FreeCredentialsHandle returned %08x\n", status_c );
338 }
339
340 if (server.cred.dwLower || server.cred.dwUpper)
341 {
342 status_s = FreeCredentialsHandle(&server.cred);
343 ok( status_s == SEC_E_OK, "FreeCredentialsHandle returned %08x\n", status_s );
344 }
345 }
346
347 START_TEST(negotiate)
348 {
349 SecPkgInfoA *info;
350
351 if (QuerySecurityPackageInfoA( (SEC_CHAR *)"Negotiate", &info ))
352 {
353 ok( 0, "Negotiate package not installed, skipping test\n" );
354 return;
355 }
356 ok( info->fCapabilities == NEGOTIATE_BASE_CAPS ||
357 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_READONLY_WITH_CHECKSUM) ||
358 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS) ||
359 info->fCapabilities == (NEGOTIATE_BASE_CAPS|SECPKG_FLAG_RESTRICTED_TOKENS|
360 SECPKG_FLAG_APPCONTAINER_CHECKS),
361 "got %08x\n", info->fCapabilities );
362 ok( info->wVersion == 1, "got %u\n", info->wVersion );
363 ok( info->wRPCID == RPC_C_AUTHN_GSS_NEGOTIATE, "got %u\n", info->wRPCID );
364 ok( !lstrcmpA( info->Name, "Negotiate" ), "got %s\n", info->Name );
365 FreeContextBuffer( info );
366
367 test_authentication();
368 }