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 } 369