1 /* 2 * Copyright 2005, 2006 Kai Blin 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 * 18 * This file implements the NTLM security provider. 19 */ 20 21 #include "precomp.h" 22 23 #include <assert.h> 24 #include <stdio.h> 25 #include <wincred.h> 26 #include <lm.h> 27 28 #include "hmac_md5.h" 29 30 #include <wine/unicode.h> 31 #include <wine/debug.h> 32 WINE_DEFAULT_DEBUG_CHANNEL(ntlm); 33 WINE_DECLARE_DEBUG_CHANNEL(winediag); 34 35 #define NTLM_MAX_BUF 1904 36 #define MIN_NTLM_AUTH_MAJOR_VERSION 3 37 #define MIN_NTLM_AUTH_MINOR_VERSION 0 38 #ifndef __REACTOS__ 39 #define MIN_NTLM_AUTH_MICRO_VERSION 25 40 #else 41 #define MIN_NTLM_AUTH_MICRO_VERSION 23 42 #endif 43 44 static CHAR ntlm_auth[] = "ntlm_auth"; 45 46 /*********************************************************************** 47 * QueryCredentialsAttributesA 48 */ 49 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA( 50 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) 51 { 52 SECURITY_STATUS ret; 53 54 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); 55 56 if(ulAttribute == SECPKG_ATTR_NAMES) 57 { 58 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); 59 ret = SEC_E_UNSUPPORTED_FUNCTION; 60 } 61 else 62 ret = SEC_E_UNSUPPORTED_FUNCTION; 63 64 return ret; 65 } 66 67 /*********************************************************************** 68 * QueryCredentialsAttributesW 69 */ 70 static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW( 71 PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) 72 { 73 SECURITY_STATUS ret; 74 75 TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer); 76 77 if(ulAttribute == SECPKG_ATTR_NAMES) 78 { 79 FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); 80 ret = SEC_E_UNSUPPORTED_FUNCTION; 81 } 82 else 83 ret = SEC_E_UNSUPPORTED_FUNCTION; 84 85 return ret; 86 } 87 88 static char *ntlm_GetUsernameArg(LPCWSTR userW, INT userW_length) 89 { 90 static const char username_arg[] = "--username="; 91 char *user; 92 int unixcp_size; 93 94 unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, 95 userW, userW_length, NULL, 0, NULL, NULL) + sizeof(username_arg); 96 user = HeapAlloc(GetProcessHeap(), 0, unixcp_size); 97 if (!user) return NULL; 98 memcpy(user, username_arg, sizeof(username_arg) - 1); 99 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, userW, userW_length, 100 user + sizeof(username_arg) - 1, 101 unixcp_size - sizeof(username_arg) + 1, NULL, NULL); 102 user[unixcp_size - 1] = '\0'; 103 return user; 104 } 105 106 static char *ntlm_GetDomainArg(LPCWSTR domainW, INT domainW_length) 107 { 108 static const char domain_arg[] = "--domain="; 109 char *domain; 110 int unixcp_size; 111 112 unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, 113 domainW, domainW_length, NULL, 0, NULL, NULL) + sizeof(domain_arg); 114 domain = HeapAlloc(GetProcessHeap(), 0, unixcp_size); 115 if (!domain) return NULL; 116 memcpy(domain, domain_arg, sizeof(domain_arg) - 1); 117 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domainW, 118 domainW_length, domain + sizeof(domain_arg) - 1, 119 unixcp_size - sizeof(domain) + 1, NULL, NULL); 120 domain[unixcp_size - 1] = '\0'; 121 return domain; 122 } 123 124 /*********************************************************************** 125 * AcquireCredentialsHandleW 126 */ 127 SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW( 128 SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, 129 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, 130 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) 131 { 132 SECURITY_STATUS ret; 133 PNtlmCredentials ntlm_cred; 134 LPWSTR domain = NULL, user = NULL, password = NULL; 135 PSEC_WINNT_AUTH_IDENTITY_W auth_data = NULL; 136 137 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n", 138 debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, 139 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); 140 141 switch(fCredentialUse) 142 { 143 case SECPKG_CRED_INBOUND: 144 ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred)); 145 if (!ntlm_cred) 146 ret = SEC_E_INSUFFICIENT_MEMORY; 147 else 148 { 149 ntlm_cred->mode = NTLM_SERVER; 150 ntlm_cred->username_arg = NULL; 151 ntlm_cred->domain_arg = NULL; 152 ntlm_cred->password = NULL; 153 ntlm_cred->pwlen = 0; 154 ntlm_cred->no_cached_credentials = 0; 155 156 phCredential->dwUpper = fCredentialUse; 157 phCredential->dwLower = (ULONG_PTR)ntlm_cred; 158 ret = SEC_E_OK; 159 } 160 break; 161 case SECPKG_CRED_OUTBOUND: 162 { 163 auth_data = pAuthData; 164 ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred)); 165 if (!ntlm_cred) 166 { 167 ret = SEC_E_INSUFFICIENT_MEMORY; 168 break; 169 } 170 ntlm_cred->mode = NTLM_CLIENT; 171 ntlm_cred->username_arg = NULL; 172 ntlm_cred->domain_arg = NULL; 173 ntlm_cred->password = NULL; 174 ntlm_cred->pwlen = 0; 175 ntlm_cred->no_cached_credentials = 0; 176 177 if(pAuthData != NULL) 178 { 179 int domain_len = 0, user_len = 0, password_len = 0; 180 181 if (auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) 182 { 183 if (auth_data->DomainLength) 184 { 185 domain_len = MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Domain, 186 auth_data->DomainLength, NULL, 0); 187 domain = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * domain_len); 188 if(!domain) 189 { 190 ret = SEC_E_INSUFFICIENT_MEMORY; 191 break; 192 } 193 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Domain, auth_data->DomainLength, 194 domain, domain_len); 195 } 196 197 if (auth_data->UserLength) 198 { 199 user_len = MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->User, 200 auth_data->UserLength, NULL, 0); 201 user = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * user_len); 202 if(!user) 203 { 204 ret = SEC_E_INSUFFICIENT_MEMORY; 205 break; 206 } 207 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->User, auth_data->UserLength, 208 user, user_len); 209 } 210 211 if (auth_data->PasswordLength) 212 { 213 password_len = MultiByteToWideChar(CP_ACP, 0,(char *)auth_data->Password, 214 auth_data->PasswordLength, NULL, 0); 215 password = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * password_len); 216 if(!password) 217 { 218 ret = SEC_E_INSUFFICIENT_MEMORY; 219 break; 220 } 221 MultiByteToWideChar(CP_ACP, 0, (char *)auth_data->Password, auth_data->PasswordLength, 222 password, password_len); 223 } 224 } 225 else 226 { 227 domain = auth_data->Domain; 228 domain_len = auth_data->DomainLength; 229 230 user = auth_data->User; 231 user_len = auth_data->UserLength; 232 233 password = auth_data->Password; 234 password_len = auth_data->PasswordLength; 235 } 236 237 TRACE("Username is %s\n", debugstr_wn(user, user_len)); 238 TRACE("Domain name is %s\n", debugstr_wn(domain, domain_len)); 239 240 ntlm_cred->username_arg = ntlm_GetUsernameArg(user, user_len); 241 ntlm_cred->domain_arg = ntlm_GetDomainArg(domain, domain_len); 242 243 if(password_len != 0) 244 { 245 ntlm_cred->pwlen = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, 246 password_len, NULL, 0, NULL, NULL); 247 248 ntlm_cred->password = HeapAlloc(GetProcessHeap(), 0, 249 ntlm_cred->pwlen); 250 if(!ntlm_cred->password) 251 { 252 ret = SEC_E_INSUFFICIENT_MEMORY; 253 break; 254 } 255 256 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len, 257 ntlm_cred->password, ntlm_cred->pwlen, NULL, NULL); 258 } 259 } 260 261 phCredential->dwUpper = fCredentialUse; 262 phCredential->dwLower = (ULONG_PTR)ntlm_cred; 263 TRACE("ACH phCredential->dwUpper: 0x%08lx, dwLower: 0x%08lx\n", 264 phCredential->dwUpper, phCredential->dwLower); 265 ret = SEC_E_OK; 266 break; 267 } 268 case SECPKG_CRED_BOTH: 269 FIXME("AcquireCredentialsHandle: SECPKG_CRED_BOTH stub\n"); 270 ret = SEC_E_UNSUPPORTED_FUNCTION; 271 phCredential = NULL; 272 break; 273 default: 274 phCredential = NULL; 275 ret = SEC_E_UNKNOWN_CREDENTIALS; 276 } 277 278 if (auth_data && auth_data->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) 279 { 280 HeapFree(GetProcessHeap(), 0, domain); 281 HeapFree(GetProcessHeap(), 0, user); 282 HeapFree(GetProcessHeap(), 0, password); 283 } 284 return ret; 285 } 286 287 /*********************************************************************** 288 * AcquireCredentialsHandleA 289 */ 290 static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA( 291 SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse, 292 PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, 293 PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) 294 { 295 SECURITY_STATUS ret; 296 int user_sizeW, domain_sizeW, passwd_sizeW; 297 298 SEC_WCHAR *user = NULL, *domain = NULL, *passwd = NULL, *package = NULL; 299 300 PSEC_WINNT_AUTH_IDENTITY_W pAuthDataW = NULL; 301 PSEC_WINNT_AUTH_IDENTITY_A identity = NULL; 302 303 TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n", 304 debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse, 305 pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); 306 307 if(pszPackage != NULL) 308 { 309 int package_sizeW = MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, 310 NULL, 0); 311 312 package = HeapAlloc(GetProcessHeap(), 0, package_sizeW * 313 sizeof(SEC_WCHAR)); 314 MultiByteToWideChar(CP_ACP, 0, pszPackage, -1, package, package_sizeW); 315 } 316 317 318 if(pAuthData != NULL) 319 { 320 identity = pAuthData; 321 322 if(identity->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI) 323 { 324 pAuthDataW = HeapAlloc(GetProcessHeap(), 0, 325 sizeof(SEC_WINNT_AUTH_IDENTITY_W)); 326 327 if(identity->UserLength != 0) 328 { 329 user_sizeW = MultiByteToWideChar(CP_ACP, 0, 330 (LPCSTR)identity->User, identity->UserLength, NULL, 0); 331 user = HeapAlloc(GetProcessHeap(), 0, user_sizeW * 332 sizeof(SEC_WCHAR)); 333 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->User, 334 identity->UserLength, user, user_sizeW); 335 } 336 else 337 { 338 user_sizeW = 0; 339 } 340 341 if(identity->DomainLength != 0) 342 { 343 domain_sizeW = MultiByteToWideChar(CP_ACP, 0, 344 (LPCSTR)identity->Domain, identity->DomainLength, NULL, 0); 345 domain = HeapAlloc(GetProcessHeap(), 0, domain_sizeW 346 * sizeof(SEC_WCHAR)); 347 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Domain, 348 identity->DomainLength, domain, domain_sizeW); 349 } 350 else 351 { 352 domain_sizeW = 0; 353 } 354 355 if(identity->PasswordLength != 0) 356 { 357 passwd_sizeW = MultiByteToWideChar(CP_ACP, 0, 358 (LPCSTR)identity->Password, identity->PasswordLength, 359 NULL, 0); 360 passwd = HeapAlloc(GetProcessHeap(), 0, passwd_sizeW 361 * sizeof(SEC_WCHAR)); 362 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)identity->Password, 363 identity->PasswordLength, passwd, passwd_sizeW); 364 } 365 else 366 { 367 passwd_sizeW = 0; 368 } 369 370 pAuthDataW->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; 371 pAuthDataW->User = user; 372 pAuthDataW->UserLength = user_sizeW; 373 pAuthDataW->Domain = domain; 374 pAuthDataW->DomainLength = domain_sizeW; 375 pAuthDataW->Password = passwd; 376 pAuthDataW->PasswordLength = passwd_sizeW; 377 } 378 else 379 { 380 pAuthDataW = (PSEC_WINNT_AUTH_IDENTITY_W)identity; 381 } 382 } 383 384 ret = ntlm_AcquireCredentialsHandleW(NULL, package, fCredentialUse, 385 pLogonID, pAuthDataW, pGetKeyFn, pGetKeyArgument, phCredential, 386 ptsExpiry); 387 388 HeapFree(GetProcessHeap(), 0, package); 389 HeapFree(GetProcessHeap(), 0, user); 390 HeapFree(GetProcessHeap(), 0, domain); 391 HeapFree(GetProcessHeap(), 0, passwd); 392 if(pAuthDataW != (PSEC_WINNT_AUTH_IDENTITY_W)identity) 393 HeapFree(GetProcessHeap(), 0, pAuthDataW); 394 395 return ret; 396 } 397 398 /************************************************************************* 399 * ntlm_GetTokenBufferIndex 400 * Calculates the index of the secbuffer with BufferType == SECBUFFER_TOKEN 401 * Returns index if found or -1 if not found. 402 */ 403 static int ntlm_GetTokenBufferIndex(PSecBufferDesc pMessage) 404 { 405 UINT i; 406 407 TRACE("%p\n", pMessage); 408 409 for( i = 0; i < pMessage->cBuffers; ++i ) 410 { 411 if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) 412 return i; 413 } 414 415 return -1; 416 } 417 418 /************************************************************************* 419 * ntlm_GetDataBufferIndex 420 * Calculates the index of the first secbuffer with BufferType == SECBUFFER_DATA 421 * Returns index if found or -1 if not found. 422 */ 423 static int ntlm_GetDataBufferIndex(PSecBufferDesc pMessage) 424 { 425 UINT i; 426 427 TRACE("%p\n", pMessage); 428 429 for( i = 0; i < pMessage->cBuffers; ++i ) 430 { 431 if(pMessage->pBuffers[i].BufferType == SECBUFFER_DATA) 432 return i; 433 } 434 435 return -1; 436 } 437 438 static BOOL ntlm_GetCachedCredential(const SEC_WCHAR *pszTargetName, PCREDENTIALW *cred) 439 { 440 LPCWSTR p; 441 LPCWSTR pszHost; 442 LPWSTR pszHostOnly; 443 BOOL ret; 444 445 if (!pszTargetName) 446 return FALSE; 447 448 /* try to get the start of the hostname from service principal name (SPN) */ 449 pszHost = strchrW(pszTargetName, '/'); 450 if (pszHost) 451 { 452 /* skip slash character */ 453 pszHost++; 454 455 /* find end of host by detecting start of instance port or start of referrer */ 456 p = strchrW(pszHost, ':'); 457 if (!p) 458 p = strchrW(pszHost, '/'); 459 if (!p) 460 p = pszHost + strlenW(pszHost); 461 } 462 else /* otherwise not an SPN, just a host */ 463 { 464 pszHost = pszTargetName; 465 p = pszHost + strlenW(pszHost); 466 } 467 468 pszHostOnly = HeapAlloc(GetProcessHeap(), 0, (p - pszHost + 1) * sizeof(WCHAR)); 469 if (!pszHostOnly) 470 return FALSE; 471 472 memcpy(pszHostOnly, pszHost, (p - pszHost) * sizeof(WCHAR)); 473 pszHostOnly[p - pszHost] = '\0'; 474 475 ret = CredReadW(pszHostOnly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred); 476 477 HeapFree(GetProcessHeap(), 0, pszHostOnly); 478 return ret; 479 } 480 481 /*********************************************************************** 482 * InitializeSecurityContextW 483 */ 484 SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( 485 PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, 486 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, 487 PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, 488 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) 489 { 490 SECURITY_STATUS ret; 491 PNtlmCredentials ntlm_cred; 492 PNegoHelper helper = NULL; 493 ULONG ctxt_attr = 0; 494 char* buffer, *want_flags = NULL; 495 PBYTE bin; 496 int buffer_len, bin_len, max_len = NTLM_MAX_BUF; 497 int token_idx; 498 SEC_CHAR *username = NULL; 499 SEC_CHAR *domain = NULL; 500 SEC_CHAR *password = NULL; 501 502 TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext, 503 debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, 504 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); 505 506 /**************************************** 507 * When communicating with the client, there can be the 508 * following reply packets: 509 * YR <base64 blob> should be sent to the server 510 * PW should be sent back to helper with 511 * base64 encoded password 512 * AF <base64 blob> client is done, blob should be 513 * sent to server with KK prefixed 514 * GF <string list> A string list of negotiated flags 515 * GK <base64 blob> base64 encoded session key 516 * BH <char reason> something broke 517 */ 518 /* The squid cache size is 2010 chars, and that's what ntlm_auth uses */ 519 520 if(TargetDataRep == SECURITY_NETWORK_DREP){ 521 TRACE("Setting SECURITY_NETWORK_DREP\n"); 522 } 523 524 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF); 525 bin = HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE) * NTLM_MAX_BUF); 526 527 if((phContext == NULL) && (pInput == NULL)) 528 { 529 static char helper_protocol[] = "--helper-protocol=ntlmssp-client-1"; 530 static CHAR credentials_argv[] = "--use-cached-creds"; 531 SEC_CHAR *client_argv[5]; 532 int pwlen = 0; 533 534 TRACE("First time in ISC()\n"); 535 536 if(!phCredential) 537 { 538 ret = SEC_E_INVALID_HANDLE; 539 goto isc_end; 540 } 541 542 /* As the server side of sspi never calls this, make sure that 543 * the handler is a client handler. 544 */ 545 ntlm_cred = (PNtlmCredentials)phCredential->dwLower; 546 if(ntlm_cred->mode != NTLM_CLIENT) 547 { 548 TRACE("Cred mode = %d\n", ntlm_cred->mode); 549 ret = SEC_E_INVALID_HANDLE; 550 goto isc_end; 551 } 552 553 client_argv[0] = ntlm_auth; 554 client_argv[1] = helper_protocol; 555 if (!ntlm_cred->username_arg && !ntlm_cred->domain_arg) 556 { 557 LPWKSTA_USER_INFO_1 ui = NULL; 558 NET_API_STATUS status; 559 PCREDENTIALW cred; 560 561 if (ntlm_GetCachedCredential(pszTargetName, &cred)) 562 { 563 LPWSTR p; 564 p = strchrW(cred->UserName, '\\'); 565 if (p) 566 { 567 domain = ntlm_GetDomainArg(cred->UserName, p - cred->UserName); 568 p++; 569 } 570 else 571 { 572 domain = ntlm_GetDomainArg(NULL, 0); 573 p = cred->UserName; 574 } 575 576 username = ntlm_GetUsernameArg(p, -1); 577 578 if(cred->CredentialBlobSize != 0) 579 { 580 pwlen = WideCharToMultiByte(CP_UNIXCP, 581 WC_NO_BEST_FIT_CHARS, (LPWSTR)cred->CredentialBlob, 582 cred->CredentialBlobSize / sizeof(WCHAR), NULL, 0, 583 NULL, NULL); 584 585 password = HeapAlloc(GetProcessHeap(), 0, pwlen); 586 587 WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, 588 (LPWSTR)cred->CredentialBlob, 589 cred->CredentialBlobSize / sizeof(WCHAR), 590 password, pwlen, NULL, NULL); 591 } 592 593 CredFree(cred); 594 595 client_argv[2] = username; 596 client_argv[3] = domain; 597 client_argv[4] = NULL; 598 } 599 else 600 { 601 status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui); 602 if (status != NERR_Success || ui == NULL || ntlm_cred->no_cached_credentials) 603 { 604 ret = SEC_E_NO_CREDENTIALS; 605 goto isc_end; 606 } 607 username = ntlm_GetUsernameArg(ui->wkui1_username, -1); 608 NetApiBufferFree(ui); 609 610 TRACE("using cached credentials\n"); 611 612 client_argv[2] = username; 613 client_argv[3] = credentials_argv; 614 client_argv[4] = NULL; 615 } 616 } 617 else 618 { 619 client_argv[2] = ntlm_cred->username_arg; 620 client_argv[3] = ntlm_cred->domain_arg; 621 client_argv[4] = NULL; 622 } 623 624 if((ret = fork_helper(&helper, ntlm_auth, client_argv)) != SEC_E_OK) 625 goto isc_end; 626 627 helper->mode = NTLM_CLIENT; 628 helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16); 629 if (!helper->session_key) 630 { 631 cleanup_helper(helper); 632 ret = SEC_E_INSUFFICIENT_MEMORY; 633 goto isc_end; 634 } 635 636 /* Generate the dummy session key = MD4(MD4(password))*/ 637 if(password || ntlm_cred->password) 638 { 639 SEC_WCHAR *unicode_password; 640 int passwd_lenW; 641 642 TRACE("Converting password to unicode.\n"); 643 passwd_lenW = MultiByteToWideChar(CP_ACP, 0, 644 password ? password : ntlm_cred->password, 645 password ? pwlen : ntlm_cred->pwlen, 646 NULL, 0); 647 unicode_password = HeapAlloc(GetProcessHeap(), 0, 648 passwd_lenW * sizeof(SEC_WCHAR)); 649 MultiByteToWideChar(CP_ACP, 0, password ? password : ntlm_cred->password, 650 password ? pwlen : ntlm_cred->pwlen, unicode_password, passwd_lenW); 651 652 SECUR32_CreateNTLM1SessionKey((PBYTE)unicode_password, 653 passwd_lenW * sizeof(SEC_WCHAR), helper->session_key); 654 655 HeapFree(GetProcessHeap(), 0, unicode_password); 656 } 657 else 658 memset(helper->session_key, 0, 16); 659 660 /* Allocate space for a maximal string of 661 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL 662 * NTLMSSP_FEATURE_SESSION_KEY" 663 */ 664 want_flags = HeapAlloc(GetProcessHeap(), 0, 73); 665 if(want_flags == NULL) 666 { 667 cleanup_helper(helper); 668 ret = SEC_E_INSUFFICIENT_MEMORY; 669 goto isc_end; 670 } 671 lstrcpyA(want_flags, "SF"); 672 if(fContextReq & ISC_REQ_CONFIDENTIALITY) 673 { 674 if(strstr(want_flags, "NTLMSSP_FEATURE_SEAL") == NULL) 675 lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL"); 676 } 677 if(fContextReq & ISC_REQ_CONNECTION) 678 ctxt_attr |= ISC_RET_CONNECTION; 679 if(fContextReq & ISC_REQ_EXTENDED_ERROR) 680 ctxt_attr |= ISC_RET_EXTENDED_ERROR; 681 if(fContextReq & ISC_REQ_INTEGRITY) 682 { 683 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL) 684 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); 685 } 686 if(fContextReq & ISC_REQ_MUTUAL_AUTH) 687 ctxt_attr |= ISC_RET_MUTUAL_AUTH; 688 if(fContextReq & ISC_REQ_REPLAY_DETECT) 689 { 690 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL) 691 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); 692 } 693 if(fContextReq & ISC_REQ_SEQUENCE_DETECT) 694 { 695 if(strstr(want_flags, "NTLMSSP_FEATURE_SIGN") == NULL) 696 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); 697 } 698 if(fContextReq & ISC_REQ_STREAM) 699 FIXME("ISC_REQ_STREAM\n"); 700 if(fContextReq & ISC_REQ_USE_DCE_STYLE) 701 ctxt_attr |= ISC_RET_USED_DCE_STYLE; 702 if(fContextReq & ISC_REQ_DELEGATE) 703 ctxt_attr |= ISC_RET_DELEGATE; 704 705 /* If no password is given, try to use cached credentials. Fall back to an empty 706 * password if this failed. */ 707 if(!password && !ntlm_cred->password) 708 { 709 lstrcpynA(buffer, "OK", max_len-1); 710 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) 711 { 712 cleanup_helper(helper); 713 goto isc_end; 714 } 715 /* If the helper replied with "PW", using cached credentials failed */ 716 if(!strncmp(buffer, "PW", 2)) 717 { 718 TRACE("Using cached credentials failed.\n"); 719 lstrcpynA(buffer, "PW AA==", max_len-1); 720 } 721 else /* Just do a noop on the next run */ 722 lstrcpynA(buffer, "OK", max_len-1); 723 } 724 else 725 { 726 lstrcpynA(buffer, "PW ", max_len-1); 727 if((ret = encodeBase64(password ? (unsigned char *)password : (unsigned char *)ntlm_cred->password, 728 password ? pwlen : ntlm_cred->pwlen, buffer+3, 729 max_len-3, &buffer_len)) != SEC_E_OK) 730 { 731 cleanup_helper(helper); 732 goto isc_end; 733 } 734 735 } 736 737 TRACE("Sending to helper: %s\n", debugstr_a(buffer)); 738 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) 739 { 740 cleanup_helper(helper); 741 goto isc_end; 742 } 743 744 TRACE("Helper returned %s\n", debugstr_a(buffer)); 745 746 if(lstrlenA(want_flags) > 2) 747 { 748 TRACE("Want flags are %s\n", debugstr_a(want_flags)); 749 lstrcpynA(buffer, want_flags, max_len-1); 750 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) 751 != SEC_E_OK) 752 { 753 cleanup_helper(helper); 754 goto isc_end; 755 } 756 if(!strncmp(buffer, "BH", 2)) 757 ERR("Helper doesn't understand new command set. Expect more things to fail.\n"); 758 } 759 760 lstrcpynA(buffer, "YR", max_len-1); 761 762 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) 763 { 764 cleanup_helper(helper); 765 goto isc_end; 766 } 767 768 TRACE("%s\n", buffer); 769 770 if(strncmp(buffer, "YR ", 3) != 0) 771 { 772 /* Something borked */ 773 TRACE("Helper returned %c%c\n", buffer[0], buffer[1]); 774 ret = SEC_E_INTERNAL_ERROR; 775 cleanup_helper(helper); 776 goto isc_end; 777 } 778 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, 779 max_len-1, &bin_len)) != SEC_E_OK) 780 { 781 cleanup_helper(helper); 782 goto isc_end; 783 } 784 785 /* put the decoded client blob into the out buffer */ 786 787 phNewContext->dwUpper = ctxt_attr; 788 phNewContext->dwLower = (ULONG_PTR)helper; 789 790 ret = SEC_I_CONTINUE_NEEDED; 791 } 792 else 793 { 794 int input_token_idx; 795 796 /* handle second call here */ 797 /* encode server data to base64 */ 798 if (!pInput || ((input_token_idx = ntlm_GetTokenBufferIndex(pInput)) == -1)) 799 { 800 ret = SEC_E_INVALID_TOKEN; 801 goto isc_end; 802 } 803 804 if(!phContext) 805 { 806 ret = SEC_E_INVALID_HANDLE; 807 goto isc_end; 808 } 809 810 /* As the server side of sspi never calls this, make sure that 811 * the handler is a client handler. 812 */ 813 helper = (PNegoHelper)phContext->dwLower; 814 if(helper->mode != NTLM_CLIENT) 815 { 816 TRACE("Helper mode = %d\n", helper->mode); 817 ret = SEC_E_INVALID_HANDLE; 818 goto isc_end; 819 } 820 821 if (!pInput->pBuffers[input_token_idx].pvBuffer) 822 { 823 ret = SEC_E_INTERNAL_ERROR; 824 goto isc_end; 825 } 826 827 if(pInput->pBuffers[input_token_idx].cbBuffer > max_len) 828 { 829 TRACE("pInput->pBuffers[%d].cbBuffer is: %d\n", 830 input_token_idx, 831 pInput->pBuffers[input_token_idx].cbBuffer); 832 ret = SEC_E_INVALID_TOKEN; 833 goto isc_end; 834 } 835 else 836 bin_len = pInput->pBuffers[input_token_idx].cbBuffer; 837 838 memcpy(bin, pInput->pBuffers[input_token_idx].pvBuffer, bin_len); 839 840 lstrcpynA(buffer, "TT ", max_len-1); 841 842 if((ret = encodeBase64(bin, bin_len, buffer+3, 843 max_len-3, &buffer_len)) != SEC_E_OK) 844 goto isc_end; 845 846 TRACE("Server sent: %s\n", debugstr_a(buffer)); 847 848 /* send TT base64 blob to ntlm_auth */ 849 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) 850 goto isc_end; 851 852 TRACE("Helper replied: %s\n", debugstr_a(buffer)); 853 854 if( (strncmp(buffer, "KK ", 3) != 0) && 855 (strncmp(buffer, "AF ", 3) !=0)) 856 { 857 TRACE("Helper returned %c%c\n", buffer[0], buffer[1]); 858 ret = SEC_E_INVALID_TOKEN; 859 goto isc_end; 860 } 861 862 /* decode the blob and send it to server */ 863 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, 864 &bin_len)) != SEC_E_OK) 865 { 866 goto isc_end; 867 } 868 869 phNewContext->dwUpper = ctxt_attr; 870 phNewContext->dwLower = (ULONG_PTR)helper; 871 872 ret = SEC_E_OK; 873 } 874 875 /* put the decoded client blob into the out buffer */ 876 877 if (!pOutput || ((token_idx = ntlm_GetTokenBufferIndex(pOutput)) == -1)) 878 { 879 TRACE("no SECBUFFER_TOKEN buffer could be found\n"); 880 ret = SEC_E_BUFFER_TOO_SMALL; 881 if ((phContext == NULL) && (pInput == NULL)) 882 { 883 cleanup_helper(helper); 884 phNewContext->dwUpper = 0; 885 phNewContext->dwLower = 0; 886 } 887 goto isc_end; 888 } 889 890 if (fContextReq & ISC_REQ_ALLOCATE_MEMORY) 891 { 892 pOutput->pBuffers[token_idx].pvBuffer = HeapAlloc(GetProcessHeap(), 0, bin_len); 893 pOutput->pBuffers[token_idx].cbBuffer = bin_len; 894 } 895 else if (pOutput->pBuffers[token_idx].cbBuffer < bin_len) 896 { 897 TRACE("out buffer is NULL or has not enough space\n"); 898 ret = SEC_E_BUFFER_TOO_SMALL; 899 if ((phContext == NULL) && (pInput == NULL)) 900 { 901 cleanup_helper(helper); 902 phNewContext->dwUpper = 0; 903 phNewContext->dwLower = 0; 904 } 905 goto isc_end; 906 } 907 908 if (!pOutput->pBuffers[token_idx].pvBuffer) 909 { 910 TRACE("out buffer is NULL\n"); 911 ret = SEC_E_INTERNAL_ERROR; 912 if ((phContext == NULL) && (pInput == NULL)) 913 { 914 cleanup_helper(helper); 915 phNewContext->dwUpper = 0; 916 phNewContext->dwLower = 0; 917 } 918 goto isc_end; 919 } 920 921 pOutput->pBuffers[token_idx].cbBuffer = bin_len; 922 memcpy(pOutput->pBuffers[token_idx].pvBuffer, bin, bin_len); 923 924 if(ret == SEC_E_OK) 925 { 926 TRACE("Getting negotiated flags\n"); 927 lstrcpynA(buffer, "GF", max_len - 1); 928 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) 929 goto isc_end; 930 931 if(buffer_len < 3) 932 { 933 TRACE("No flags negotiated.\n"); 934 helper->neg_flags = 0l; 935 } 936 else 937 { 938 TRACE("Negotiated %s\n", debugstr_a(buffer)); 939 sscanf(buffer + 3, "%lx", &(helper->neg_flags)); 940 TRACE("Stored 0x%08x as flags\n", helper->neg_flags); 941 } 942 943 TRACE("Getting session key\n"); 944 lstrcpynA(buffer, "GK", max_len - 1); 945 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) 946 goto isc_end; 947 948 if(strncmp(buffer, "BH", 2) == 0) 949 TRACE("No key negotiated.\n"); 950 else if(strncmp(buffer, "GK ", 3) == 0) 951 { 952 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, 953 &bin_len)) != SEC_E_OK) 954 { 955 TRACE("Failed to decode session key\n"); 956 } 957 TRACE("Session key is %s\n", debugstr_a(buffer+3)); 958 HeapFree(GetProcessHeap(), 0, helper->session_key); 959 helper->session_key = HeapAlloc(GetProcessHeap(), 0, bin_len); 960 if(!helper->session_key) 961 { 962 ret = SEC_E_INSUFFICIENT_MEMORY; 963 goto isc_end; 964 } 965 memcpy(helper->session_key, bin, bin_len); 966 } 967 968 helper->crypt.ntlm.a4i = SECUR32_arc4Alloc(); 969 SECUR32_arc4Init(helper->crypt.ntlm.a4i, helper->session_key, 16); 970 helper->crypt.ntlm.seq_num = 0l; 971 SECUR32_CreateNTLM2SubKeys(helper); 972 helper->crypt.ntlm2.send_a4i = SECUR32_arc4Alloc(); 973 helper->crypt.ntlm2.recv_a4i = SECUR32_arc4Alloc(); 974 SECUR32_arc4Init(helper->crypt.ntlm2.send_a4i, 975 helper->crypt.ntlm2.send_seal_key, 16); 976 SECUR32_arc4Init(helper->crypt.ntlm2.recv_a4i, 977 helper->crypt.ntlm2.recv_seal_key, 16); 978 helper->crypt.ntlm2.send_seq_no = 0l; 979 helper->crypt.ntlm2.recv_seq_no = 0l; 980 } 981 982 isc_end: 983 HeapFree(GetProcessHeap(), 0, username); 984 HeapFree(GetProcessHeap(), 0, domain); 985 HeapFree(GetProcessHeap(), 0, password); 986 HeapFree(GetProcessHeap(), 0, want_flags); 987 HeapFree(GetProcessHeap(), 0, buffer); 988 HeapFree(GetProcessHeap(), 0, bin); 989 return ret; 990 } 991 992 /*********************************************************************** 993 * InitializeSecurityContextA 994 */ 995 static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA( 996 PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, 997 ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, 998 PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext, 999 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) 1000 { 1001 SECURITY_STATUS ret; 1002 SEC_WCHAR *target = NULL; 1003 1004 TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext, 1005 debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, 1006 Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); 1007 1008 if(pszTargetName != NULL) 1009 { 1010 int target_size = MultiByteToWideChar(CP_ACP, 0, pszTargetName, 1011 strlen(pszTargetName)+1, NULL, 0); 1012 target = HeapAlloc(GetProcessHeap(), 0, target_size * 1013 sizeof(SEC_WCHAR)); 1014 MultiByteToWideChar(CP_ACP, 0, pszTargetName, strlen(pszTargetName)+1, 1015 target, target_size); 1016 } 1017 1018 ret = ntlm_InitializeSecurityContextW(phCredential, phContext, target, 1019 fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, 1020 phNewContext, pOutput, pfContextAttr, ptsExpiry); 1021 1022 HeapFree(GetProcessHeap(), 0, target); 1023 return ret; 1024 } 1025 1026 /*********************************************************************** 1027 * AcceptSecurityContext 1028 */ 1029 SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext( 1030 PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, 1031 ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, 1032 PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) 1033 { 1034 SECURITY_STATUS ret; 1035 char *buffer, *want_flags = NULL; 1036 PBYTE bin; 1037 int buffer_len, bin_len, max_len = NTLM_MAX_BUF; 1038 ULONG ctxt_attr = 0; 1039 PNegoHelper helper; 1040 PNtlmCredentials ntlm_cred; 1041 1042 TRACE("%p %p %p %d %d %p %p %p %p\n", phCredential, phContext, pInput, 1043 fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, 1044 ptsExpiry); 1045 1046 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char) * NTLM_MAX_BUF); 1047 bin = HeapAlloc(GetProcessHeap(),0, sizeof(BYTE) * NTLM_MAX_BUF); 1048 1049 if(TargetDataRep == SECURITY_NETWORK_DREP){ 1050 TRACE("Using SECURITY_NETWORK_DREP\n"); 1051 } 1052 1053 if(phContext == NULL) 1054 { 1055 static CHAR server_helper_protocol[] = "--helper-protocol=squid-2.5-ntlmssp"; 1056 SEC_CHAR *server_argv[] = { ntlm_auth, 1057 server_helper_protocol, 1058 NULL }; 1059 1060 if (!phCredential) 1061 { 1062 ret = SEC_E_INVALID_HANDLE; 1063 goto asc_end; 1064 } 1065 1066 ntlm_cred = (PNtlmCredentials)phCredential->dwLower; 1067 1068 if(ntlm_cred->mode != NTLM_SERVER) 1069 { 1070 ret = SEC_E_INVALID_HANDLE; 1071 goto asc_end; 1072 } 1073 1074 /* This is the first call to AcceptSecurityHandle */ 1075 if(pInput == NULL) 1076 { 1077 ret = SEC_E_INCOMPLETE_MESSAGE; 1078 goto asc_end; 1079 } 1080 1081 if(pInput->cBuffers < 1) 1082 { 1083 ret = SEC_E_INCOMPLETE_MESSAGE; 1084 goto asc_end; 1085 } 1086 1087 if(pInput->pBuffers[0].cbBuffer > max_len) 1088 { 1089 ret = SEC_E_INVALID_TOKEN; 1090 goto asc_end; 1091 } 1092 else 1093 bin_len = pInput->pBuffers[0].cbBuffer; 1094 1095 if( (ret = fork_helper(&helper, ntlm_auth, server_argv)) != 1096 SEC_E_OK) 1097 { 1098 ret = SEC_E_INTERNAL_ERROR; 1099 goto asc_end; 1100 } 1101 helper->mode = NTLM_SERVER; 1102 1103 /* Handle all the flags */ 1104 want_flags = HeapAlloc(GetProcessHeap(), 0, 73); 1105 if(want_flags == NULL) 1106 { 1107 TRACE("Failed to allocate memory for the want_flags!\n"); 1108 ret = SEC_E_INSUFFICIENT_MEMORY; 1109 cleanup_helper(helper); 1110 goto asc_end; 1111 } 1112 lstrcpyA(want_flags, "SF"); 1113 if(fContextReq & ASC_REQ_ALLOCATE_MEMORY) 1114 { 1115 FIXME("ASC_REQ_ALLOCATE_MEMORY stub\n"); 1116 } 1117 if(fContextReq & ASC_REQ_CONFIDENTIALITY) 1118 { 1119 lstrcatA(want_flags, " NTLMSSP_FEATURE_SEAL"); 1120 } 1121 if(fContextReq & ASC_REQ_CONNECTION) 1122 { 1123 /* This is default, so we'll enable it */ 1124 lstrcatA(want_flags, " NTLMSSP_FEATURE_SESSION_KEY"); 1125 ctxt_attr |= ASC_RET_CONNECTION; 1126 } 1127 if(fContextReq & ASC_REQ_EXTENDED_ERROR) 1128 { 1129 FIXME("ASC_REQ_EXTENDED_ERROR stub\n"); 1130 } 1131 if(fContextReq & ASC_REQ_INTEGRITY) 1132 { 1133 lstrcatA(want_flags, " NTLMSSP_FEATURE_SIGN"); 1134 } 1135 if(fContextReq & ASC_REQ_MUTUAL_AUTH) 1136 { 1137 FIXME("ASC_REQ_MUTUAL_AUTH stub\n"); 1138 } 1139 if(fContextReq & ASC_REQ_REPLAY_DETECT) 1140 { 1141 FIXME("ASC_REQ_REPLAY_DETECT stub\n"); 1142 } 1143 if(fContextReq & ISC_REQ_SEQUENCE_DETECT) 1144 { 1145 FIXME("ASC_REQ_SEQUENCE_DETECT stub\n"); 1146 } 1147 if(fContextReq & ISC_REQ_STREAM) 1148 { 1149 FIXME("ASC_REQ_STREAM stub\n"); 1150 } 1151 /* Done with the flags */ 1152 1153 if(lstrlenA(want_flags) > 3) 1154 { 1155 TRACE("Server set want_flags: %s\n", debugstr_a(want_flags)); 1156 lstrcpynA(buffer, want_flags, max_len - 1); 1157 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != 1158 SEC_E_OK) 1159 { 1160 cleanup_helper(helper); 1161 goto asc_end; 1162 } 1163 if(!strncmp(buffer, "BH", 2)) 1164 TRACE("Helper doesn't understand new command set\n"); 1165 } 1166 1167 /* This is the YR request from the client, encode to base64 */ 1168 1169 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len); 1170 1171 lstrcpynA(buffer, "YR ", max_len-1); 1172 1173 if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3, 1174 &buffer_len)) != SEC_E_OK) 1175 { 1176 cleanup_helper(helper); 1177 goto asc_end; 1178 } 1179 1180 TRACE("Client sent: %s\n", debugstr_a(buffer)); 1181 1182 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != 1183 SEC_E_OK) 1184 { 1185 cleanup_helper(helper); 1186 goto asc_end; 1187 } 1188 1189 TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer)); 1190 /* The expected answer is TT <base64 blob> */ 1191 1192 if(strncmp(buffer, "TT ", 3) != 0) 1193 { 1194 ret = SEC_E_INTERNAL_ERROR; 1195 cleanup_helper(helper); 1196 goto asc_end; 1197 } 1198 1199 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, 1200 &bin_len)) != SEC_E_OK) 1201 { 1202 cleanup_helper(helper); 1203 goto asc_end; 1204 } 1205 1206 /* send this to the client */ 1207 if(pOutput == NULL) 1208 { 1209 ret = SEC_E_INSUFFICIENT_MEMORY; 1210 cleanup_helper(helper); 1211 goto asc_end; 1212 } 1213 1214 if(pOutput->cBuffers < 1) 1215 { 1216 ret = SEC_E_INSUFFICIENT_MEMORY; 1217 cleanup_helper(helper); 1218 goto asc_end; 1219 } 1220 1221 pOutput->pBuffers[0].cbBuffer = bin_len; 1222 pOutput->pBuffers[0].BufferType = SECBUFFER_DATA; 1223 memcpy(pOutput->pBuffers[0].pvBuffer, bin, bin_len); 1224 ret = SEC_I_CONTINUE_NEEDED; 1225 1226 } 1227 else 1228 { 1229 /* we expect a KK request from client */ 1230 if(pInput == NULL) 1231 { 1232 ret = SEC_E_INCOMPLETE_MESSAGE; 1233 goto asc_end; 1234 } 1235 1236 if(pInput->cBuffers < 1) 1237 { 1238 ret = SEC_E_INCOMPLETE_MESSAGE; 1239 goto asc_end; 1240 } 1241 1242 helper = (PNegoHelper)phContext->dwLower; 1243 1244 if(helper->mode != NTLM_SERVER) 1245 { 1246 ret = SEC_E_INVALID_HANDLE; 1247 goto asc_end; 1248 } 1249 1250 if(pInput->pBuffers[0].cbBuffer > max_len) 1251 { 1252 ret = SEC_E_INVALID_TOKEN; 1253 goto asc_end; 1254 } 1255 else 1256 bin_len = pInput->pBuffers[0].cbBuffer; 1257 1258 memcpy(bin, pInput->pBuffers[0].pvBuffer, bin_len); 1259 1260 lstrcpynA(buffer, "KK ", max_len-1); 1261 1262 if((ret = encodeBase64(bin, bin_len, buffer+3, max_len-3, 1263 &buffer_len)) != SEC_E_OK) 1264 { 1265 goto asc_end; 1266 } 1267 1268 TRACE("Client sent: %s\n", debugstr_a(buffer)); 1269 1270 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != 1271 SEC_E_OK) 1272 { 1273 goto asc_end; 1274 } 1275 1276 TRACE("Reply from ntlm_auth: %s\n", debugstr_a(buffer)); 1277 1278 /* At this point, we get a NA if the user didn't authenticate, but a BH 1279 * if ntlm_auth could not connect to winbindd. Apart from running Wine 1280 * as root, there is no way to fix this for now, so just handle this as 1281 * a failed login. */ 1282 if(strncmp(buffer, "AF ", 3) != 0) 1283 { 1284 if(strncmp(buffer, "NA ", 3) == 0) 1285 { 1286 ret = SEC_E_LOGON_DENIED; 1287 goto asc_end; 1288 } 1289 else 1290 { 1291 size_t ntlm_pipe_err_v3_len = strlen("BH NT_STATUS_ACCESS_DENIED"); 1292 size_t ntlm_pipe_err_v4_len = strlen("BH NT_STATUS_UNSUCCESSFUL"); 1293 1294 if( (buffer_len >= ntlm_pipe_err_v3_len && 1295 strncmp(buffer, "BH NT_STATUS_ACCESS_DENIED", ntlm_pipe_err_v3_len) == 0) || 1296 (buffer_len >= ntlm_pipe_err_v4_len && 1297 strncmp(buffer, "BH NT_STATUS_UNSUCCESSFUL", ntlm_pipe_err_v4_len) == 0) ) 1298 { 1299 TRACE("Connection to winbindd failed\n"); 1300 ret = SEC_E_LOGON_DENIED; 1301 } 1302 else 1303 ret = SEC_E_INTERNAL_ERROR; 1304 1305 goto asc_end; 1306 } 1307 } 1308 pOutput->pBuffers[0].cbBuffer = 0; 1309 1310 TRACE("Getting negotiated flags\n"); 1311 lstrcpynA(buffer, "GF", max_len - 1); 1312 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) 1313 goto asc_end; 1314 1315 if(buffer_len < 3) 1316 { 1317 TRACE("No flags negotiated, or helper does not support GF command\n"); 1318 } 1319 else 1320 { 1321 TRACE("Negotiated %s\n", debugstr_a(buffer)); 1322 sscanf(buffer + 3, "%lx", &(helper->neg_flags)); 1323 TRACE("Stored 0x%08x as flags\n", helper->neg_flags); 1324 } 1325 1326 TRACE("Getting session key\n"); 1327 lstrcpynA(buffer, "GK", max_len - 1); 1328 if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK) 1329 goto asc_end; 1330 1331 if(buffer_len < 3) 1332 TRACE("Helper does not support GK command\n"); 1333 else 1334 { 1335 if(strncmp(buffer, "BH ", 3) == 0) 1336 { 1337 TRACE("Helper sent %s\n", debugstr_a(buffer+3)); 1338 HeapFree(GetProcessHeap(), 0, helper->session_key); 1339 helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16); 1340 if (!helper->session_key) 1341 { 1342 ret = SEC_E_INSUFFICIENT_MEMORY; 1343 goto asc_end; 1344 } 1345 /*FIXME: Generate the dummy session key = MD4(MD4(password))*/ 1346 memset(helper->session_key, 0 , 16); 1347 } 1348 else if(strncmp(buffer, "GK ", 3) == 0) 1349 { 1350 if((ret = decodeBase64(buffer+3, buffer_len-3, bin, max_len, 1351 &bin_len)) != SEC_E_OK) 1352 { 1353 TRACE("Failed to decode session key\n"); 1354 } 1355 TRACE("Session key is %s\n", debugstr_a(buffer+3)); 1356 HeapFree(GetProcessHeap(), 0, helper->session_key); 1357 helper->session_key = HeapAlloc(GetProcessHeap(), 0, 16); 1358 if(!helper->session_key) 1359 { 1360 ret = SEC_E_INSUFFICIENT_MEMORY; 1361 goto asc_end; 1362 } 1363 memcpy(helper->session_key, bin, 16); 1364 } 1365 } 1366 helper->crypt.ntlm.a4i = SECUR32_arc4Alloc(); 1367 SECUR32_arc4Init(helper->crypt.ntlm.a4i, helper->session_key, 16); 1368 helper->crypt.ntlm.seq_num = 0l; 1369 } 1370 1371 phNewContext->dwUpper = ctxt_attr; 1372 phNewContext->dwLower = (ULONG_PTR)helper; 1373 1374 asc_end: 1375 HeapFree(GetProcessHeap(), 0, want_flags); 1376 HeapFree(GetProcessHeap(), 0, buffer); 1377 HeapFree(GetProcessHeap(), 0, bin); 1378 return ret; 1379 } 1380 1381 /*********************************************************************** 1382 * CompleteAuthToken 1383 */ 1384 static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext, 1385 PSecBufferDesc pToken) 1386 { 1387 /* We never need to call CompleteAuthToken anyway */ 1388 TRACE("%p %p\n", phContext, pToken); 1389 if (!phContext) 1390 return SEC_E_INVALID_HANDLE; 1391 1392 return SEC_E_OK; 1393 } 1394 1395 /*********************************************************************** 1396 * DeleteSecurityContext 1397 */ 1398 SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext) 1399 { 1400 PNegoHelper helper; 1401 1402 TRACE("%p\n", phContext); 1403 if (!phContext) 1404 return SEC_E_INVALID_HANDLE; 1405 1406 helper = (PNegoHelper)phContext->dwLower; 1407 1408 phContext->dwUpper = 0; 1409 phContext->dwLower = 0; 1410 1411 SECUR32_arc4Cleanup(helper->crypt.ntlm.a4i); 1412 SECUR32_arc4Cleanup(helper->crypt.ntlm2.send_a4i); 1413 SECUR32_arc4Cleanup(helper->crypt.ntlm2.recv_a4i); 1414 HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.send_sign_key); 1415 HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.send_seal_key); 1416 HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.recv_sign_key); 1417 HeapFree(GetProcessHeap(), 0, helper->crypt.ntlm2.recv_seal_key); 1418 1419 cleanup_helper(helper); 1420 1421 return SEC_E_OK; 1422 } 1423 1424 /*********************************************************************** 1425 * QueryContextAttributesW 1426 */ 1427 SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, 1428 ULONG ulAttribute, void *pBuffer) 1429 { 1430 TRACE("%p %d %p\n", phContext, ulAttribute, pBuffer); 1431 if (!phContext) 1432 return SEC_E_INVALID_HANDLE; 1433 1434 switch(ulAttribute) 1435 { 1436 #define _x(x) case (x) : FIXME(#x" stub\n"); break 1437 _x(SECPKG_ATTR_ACCESS_TOKEN); 1438 _x(SECPKG_ATTR_AUTHORITY); 1439 _x(SECPKG_ATTR_DCE_INFO); 1440 case SECPKG_ATTR_FLAGS: 1441 { 1442 PSecPkgContext_Flags spcf = (PSecPkgContext_Flags)pBuffer; 1443 PNegoHelper helper = (PNegoHelper)phContext->dwLower; 1444 1445 spcf->Flags = 0; 1446 if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) 1447 spcf->Flags |= ISC_RET_INTEGRITY; 1448 if(helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL) 1449 spcf->Flags |= ISC_RET_CONFIDENTIALITY; 1450 return SEC_E_OK; 1451 } 1452 _x(SECPKG_ATTR_KEY_INFO); 1453 _x(SECPKG_ATTR_LIFESPAN); 1454 _x(SECPKG_ATTR_NAMES); 1455 _x(SECPKG_ATTR_NATIVE_NAMES); 1456 _x(SECPKG_ATTR_NEGOTIATION_INFO); 1457 _x(SECPKG_ATTR_PACKAGE_INFO); 1458 _x(SECPKG_ATTR_PASSWORD_EXPIRY); 1459 _x(SECPKG_ATTR_SESSION_KEY); 1460 case SECPKG_ATTR_SIZES: 1461 { 1462 PSecPkgContext_Sizes spcs = (PSecPkgContext_Sizes)pBuffer; 1463 spcs->cbMaxToken = NTLM_MAX_BUF; 1464 spcs->cbMaxSignature = 16; 1465 spcs->cbBlockSize = 0; 1466 spcs->cbSecurityTrailer = 16; 1467 return SEC_E_OK; 1468 } 1469 _x(SECPKG_ATTR_STREAM_SIZES); 1470 _x(SECPKG_ATTR_TARGET_INFORMATION); 1471 #undef _x 1472 default: 1473 TRACE("Unknown value %d passed for ulAttribute\n", ulAttribute); 1474 } 1475 1476 return SEC_E_UNSUPPORTED_FUNCTION; 1477 } 1478 1479 /*********************************************************************** 1480 * QueryContextAttributesA 1481 */ 1482 SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext, 1483 ULONG ulAttribute, void *pBuffer) 1484 { 1485 return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer); 1486 } 1487 1488 /*********************************************************************** 1489 * ImpersonateSecurityContext 1490 */ 1491 static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext) 1492 { 1493 SECURITY_STATUS ret; 1494 1495 TRACE("%p\n", phContext); 1496 if (phContext) 1497 { 1498 ret = SEC_E_UNSUPPORTED_FUNCTION; 1499 } 1500 else 1501 { 1502 ret = SEC_E_INVALID_HANDLE; 1503 } 1504 return ret; 1505 } 1506 1507 /*********************************************************************** 1508 * RevertSecurityContext 1509 */ 1510 static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext) 1511 { 1512 SECURITY_STATUS ret; 1513 1514 TRACE("%p\n", phContext); 1515 if (phContext) 1516 { 1517 ret = SEC_E_UNSUPPORTED_FUNCTION; 1518 } 1519 else 1520 { 1521 ret = SEC_E_INVALID_HANDLE; 1522 } 1523 return ret; 1524 } 1525 1526 /*********************************************************************** 1527 * ntlm_CreateSignature 1528 * As both MakeSignature and VerifySignature need this, but different keys 1529 * are needed for NTLM2, the logic goes into a helper function. 1530 * To ensure maximal reusability, we can specify the direction as NTLM_SEND for 1531 * signing/encrypting and NTLM_RECV for verifying/decrypting. When encrypting, 1532 * the signature is encrypted after the message was encrypted, so 1533 * CreateSignature shouldn't do it. In this case, encrypt_sig can be set to 1534 * false. 1535 */ 1536 static SECURITY_STATUS ntlm_CreateSignature(PNegoHelper helper, PSecBufferDesc pMessage, 1537 int token_idx, SignDirection direction, BOOL encrypt_sig) 1538 { 1539 ULONG sign_version = 1; 1540 UINT i; 1541 PBYTE sig; 1542 TRACE("%p, %p, %d, %d, %d\n", helper, pMessage, token_idx, direction, 1543 encrypt_sig); 1544 1545 sig = pMessage->pBuffers[token_idx].pvBuffer; 1546 1547 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && 1548 helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) 1549 { 1550 BYTE digest[16]; 1551 BYTE seq_no[4]; 1552 HMAC_MD5_CTX hmac_md5_ctx; 1553 1554 TRACE("Signing NTLM2 style\n"); 1555 1556 if(direction == NTLM_SEND) 1557 { 1558 seq_no[0] = (helper->crypt.ntlm2.send_seq_no >> 0) & 0xff; 1559 seq_no[1] = (helper->crypt.ntlm2.send_seq_no >> 8) & 0xff; 1560 seq_no[2] = (helper->crypt.ntlm2.send_seq_no >> 16) & 0xff; 1561 seq_no[3] = (helper->crypt.ntlm2.send_seq_no >> 24) & 0xff; 1562 1563 ++(helper->crypt.ntlm2.send_seq_no); 1564 1565 HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.send_sign_key, 16); 1566 } 1567 else 1568 { 1569 seq_no[0] = (helper->crypt.ntlm2.recv_seq_no >> 0) & 0xff; 1570 seq_no[1] = (helper->crypt.ntlm2.recv_seq_no >> 8) & 0xff; 1571 seq_no[2] = (helper->crypt.ntlm2.recv_seq_no >> 16) & 0xff; 1572 seq_no[3] = (helper->crypt.ntlm2.recv_seq_no >> 24) & 0xff; 1573 1574 ++(helper->crypt.ntlm2.recv_seq_no); 1575 1576 HMACMD5Init(&hmac_md5_ctx, helper->crypt.ntlm2.recv_sign_key, 16); 1577 } 1578 1579 HMACMD5Update(&hmac_md5_ctx, seq_no, 4); 1580 for( i = 0; i < pMessage->cBuffers; ++i ) 1581 { 1582 if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA) 1583 HMACMD5Update(&hmac_md5_ctx, pMessage->pBuffers[i].pvBuffer, 1584 pMessage->pBuffers[i].cbBuffer); 1585 } 1586 1587 HMACMD5Final(&hmac_md5_ctx, digest); 1588 1589 if(encrypt_sig && helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE) 1590 { 1591 if(direction == NTLM_SEND) 1592 SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i, digest, 8); 1593 else 1594 SECUR32_arc4Process(helper->crypt.ntlm2.recv_a4i, digest, 8); 1595 } 1596 1597 /* The NTLM2 signature is the sign version */ 1598 sig[ 0] = (sign_version >> 0) & 0xff; 1599 sig[ 1] = (sign_version >> 8) & 0xff; 1600 sig[ 2] = (sign_version >> 16) & 0xff; 1601 sig[ 3] = (sign_version >> 24) & 0xff; 1602 /* The first 8 bytes of the digest */ 1603 memcpy(sig+4, digest, 8); 1604 /* And the sequence number */ 1605 memcpy(sig+12, seq_no, 4); 1606 1607 pMessage->pBuffers[token_idx].cbBuffer = 16; 1608 1609 return SEC_E_OK; 1610 } 1611 if(helper->neg_flags & NTLMSSP_NEGOTIATE_SIGN) 1612 { 1613 ULONG crc = 0U; 1614 TRACE("Signing NTLM1 style\n"); 1615 1616 for(i=0; i < pMessage->cBuffers; ++i) 1617 { 1618 if(pMessage->pBuffers[i].BufferType & SECBUFFER_DATA) 1619 { 1620 crc = ComputeCrc32(pMessage->pBuffers[i].pvBuffer, 1621 pMessage->pBuffers[i].cbBuffer, crc); 1622 } 1623 } 1624 1625 sig[ 0] = (sign_version >> 0) & 0xff; 1626 sig[ 1] = (sign_version >> 8) & 0xff; 1627 sig[ 2] = (sign_version >> 16) & 0xff; 1628 sig[ 3] = (sign_version >> 24) & 0xff; 1629 memset(sig+4, 0, 4); 1630 sig[ 8] = (crc >> 0) & 0xff; 1631 sig[ 9] = (crc >> 8) & 0xff; 1632 sig[10] = (crc >> 16) & 0xff; 1633 sig[11] = (crc >> 24) & 0xff; 1634 sig[12] = (helper->crypt.ntlm.seq_num >> 0) & 0xff; 1635 sig[13] = (helper->crypt.ntlm.seq_num >> 8) & 0xff; 1636 sig[14] = (helper->crypt.ntlm.seq_num >> 16) & 0xff; 1637 sig[15] = (helper->crypt.ntlm.seq_num >> 24) & 0xff; 1638 1639 ++(helper->crypt.ntlm.seq_num); 1640 1641 if(encrypt_sig) 1642 SECUR32_arc4Process(helper->crypt.ntlm.a4i, sig+4, 12); 1643 return SEC_E_OK; 1644 } 1645 1646 if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN || helper->neg_flags == 0) 1647 { 1648 TRACE("Creating a dummy signature.\n"); 1649 /* A dummy signature is 0x01 followed by 15 bytes of 0x00 */ 1650 memset(pMessage->pBuffers[token_idx].pvBuffer, 0, 16); 1651 memset(pMessage->pBuffers[token_idx].pvBuffer, 0x01, 1); 1652 pMessage->pBuffers[token_idx].cbBuffer = 16; 1653 return SEC_E_OK; 1654 } 1655 1656 return SEC_E_UNSUPPORTED_FUNCTION; 1657 } 1658 1659 /*********************************************************************** 1660 * MakeSignature 1661 */ 1662 SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, 1663 ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) 1664 { 1665 PNegoHelper helper; 1666 int token_idx; 1667 1668 TRACE("%p %d %p %d\n", phContext, fQOP, pMessage, MessageSeqNo); 1669 if (!phContext) 1670 return SEC_E_INVALID_HANDLE; 1671 1672 if(fQOP) 1673 FIXME("Ignoring fQOP 0x%08x\n", fQOP); 1674 1675 if(MessageSeqNo) 1676 FIXME("Ignoring MessageSeqNo\n"); 1677 1678 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) 1679 return SEC_E_INVALID_TOKEN; 1680 1681 /* If we didn't find a SECBUFFER_TOKEN type buffer */ 1682 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1) 1683 return SEC_E_INVALID_TOKEN; 1684 1685 if(pMessage->pBuffers[token_idx].cbBuffer < 16) 1686 return SEC_E_BUFFER_TOO_SMALL; 1687 1688 helper = (PNegoHelper)phContext->dwLower; 1689 TRACE("Negotiated flags are: 0x%08x\n", helper->neg_flags); 1690 1691 return ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, TRUE); 1692 } 1693 1694 /*********************************************************************** 1695 * VerifySignature 1696 */ 1697 SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, 1698 PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) 1699 { 1700 PNegoHelper helper; 1701 UINT i; 1702 int token_idx; 1703 SECURITY_STATUS ret; 1704 SecBufferDesc local_desc; 1705 PSecBuffer local_buff; 1706 BYTE local_sig[16]; 1707 1708 TRACE("%p %p %d %p\n", phContext, pMessage, MessageSeqNo, pfQOP); 1709 if(!phContext) 1710 return SEC_E_INVALID_HANDLE; 1711 1712 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) 1713 return SEC_E_INVALID_TOKEN; 1714 1715 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1) 1716 return SEC_E_INVALID_TOKEN; 1717 1718 if(pMessage->pBuffers[token_idx].cbBuffer < 16) 1719 return SEC_E_BUFFER_TOO_SMALL; 1720 1721 if(MessageSeqNo) 1722 FIXME("Ignoring MessageSeqNo\n"); 1723 1724 helper = (PNegoHelper)phContext->dwLower; 1725 TRACE("Negotiated flags: 0x%08x\n", helper->neg_flags); 1726 1727 local_buff = HeapAlloc(GetProcessHeap(), 0, pMessage->cBuffers * sizeof(SecBuffer)); 1728 1729 local_desc.ulVersion = SECBUFFER_VERSION; 1730 local_desc.cBuffers = pMessage->cBuffers; 1731 local_desc.pBuffers = local_buff; 1732 1733 for(i=0; i < pMessage->cBuffers; ++i) 1734 { 1735 if(pMessage->pBuffers[i].BufferType == SECBUFFER_TOKEN) 1736 { 1737 local_buff[i].BufferType = SECBUFFER_TOKEN; 1738 local_buff[i].cbBuffer = 16; 1739 local_buff[i].pvBuffer = local_sig; 1740 } 1741 else 1742 { 1743 local_buff[i].BufferType = pMessage->pBuffers[i].BufferType; 1744 local_buff[i].cbBuffer = pMessage->pBuffers[i].cbBuffer; 1745 local_buff[i].pvBuffer = pMessage->pBuffers[i].pvBuffer; 1746 } 1747 } 1748 1749 if((ret = ntlm_CreateSignature(helper, &local_desc, token_idx, NTLM_RECV, TRUE)) != SEC_E_OK) 1750 return ret; 1751 1752 if(memcmp(((PBYTE)local_buff[token_idx].pvBuffer) + 8, 1753 ((PBYTE)pMessage->pBuffers[token_idx].pvBuffer) + 8, 8)) 1754 ret = SEC_E_MESSAGE_ALTERED; 1755 else 1756 ret = SEC_E_OK; 1757 1758 HeapFree(GetProcessHeap(), 0, local_buff); 1759 1760 return ret; 1761 1762 } 1763 1764 /*********************************************************************** 1765 * FreeCredentialsHandle 1766 */ 1767 SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential) 1768 { 1769 SECURITY_STATUS ret; 1770 1771 if(phCredential){ 1772 PNtlmCredentials ntlm_cred = (PNtlmCredentials) phCredential->dwLower; 1773 phCredential->dwUpper = 0; 1774 phCredential->dwLower = 0; 1775 if (ntlm_cred->password) 1776 memset(ntlm_cred->password, 0, ntlm_cred->pwlen); 1777 HeapFree(GetProcessHeap(), 0, ntlm_cred->password); 1778 HeapFree(GetProcessHeap(), 0, ntlm_cred->username_arg); 1779 HeapFree(GetProcessHeap(), 0, ntlm_cred->domain_arg); 1780 HeapFree(GetProcessHeap(), 0, ntlm_cred); 1781 ret = SEC_E_OK; 1782 } 1783 else 1784 ret = SEC_E_OK; 1785 1786 return ret; 1787 } 1788 1789 /*********************************************************************** 1790 * EncryptMessage 1791 */ 1792 SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, 1793 ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) 1794 { 1795 PNegoHelper helper; 1796 int token_idx, data_idx; 1797 1798 TRACE("(%p %d %p %d)\n", phContext, fQOP, pMessage, MessageSeqNo); 1799 1800 if(!phContext) 1801 return SEC_E_INVALID_HANDLE; 1802 1803 if(fQOP) 1804 FIXME("Ignoring fQOP\n"); 1805 1806 if(MessageSeqNo) 1807 FIXME("Ignoring MessageSeqNo\n"); 1808 1809 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) 1810 return SEC_E_INVALID_TOKEN; 1811 1812 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1) 1813 return SEC_E_INVALID_TOKEN; 1814 1815 if((data_idx = ntlm_GetDataBufferIndex(pMessage)) ==-1 ) 1816 return SEC_E_INVALID_TOKEN; 1817 1818 if(pMessage->pBuffers[token_idx].cbBuffer < 16) 1819 return SEC_E_BUFFER_TOO_SMALL; 1820 1821 helper = (PNegoHelper) phContext->dwLower; 1822 1823 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && 1824 helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL) 1825 { 1826 ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, FALSE); 1827 SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i, 1828 pMessage->pBuffers[data_idx].pvBuffer, 1829 pMessage->pBuffers[data_idx].cbBuffer); 1830 1831 if(helper->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCHANGE) 1832 SECUR32_arc4Process(helper->crypt.ntlm2.send_a4i, 1833 ((BYTE *)pMessage->pBuffers[token_idx].pvBuffer)+4, 8); 1834 } 1835 else 1836 { 1837 PBYTE sig; 1838 ULONG save_flags; 1839 1840 /* EncryptMessage always produces real signatures, so make sure 1841 * NTLMSSP_NEGOTIATE_SIGN is set*/ 1842 save_flags = helper->neg_flags; 1843 helper->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; 1844 ntlm_CreateSignature(helper, pMessage, token_idx, NTLM_SEND, FALSE); 1845 helper->neg_flags = save_flags; 1846 1847 sig = pMessage->pBuffers[token_idx].pvBuffer; 1848 1849 SECUR32_arc4Process(helper->crypt.ntlm.a4i, 1850 pMessage->pBuffers[data_idx].pvBuffer, 1851 pMessage->pBuffers[data_idx].cbBuffer); 1852 SECUR32_arc4Process(helper->crypt.ntlm.a4i, sig+4, 12); 1853 1854 if(helper->neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN || helper->neg_flags == 0) 1855 memset(sig+4, 0, 4); 1856 } 1857 return SEC_E_OK; 1858 } 1859 1860 /*********************************************************************** 1861 * DecryptMessage 1862 */ 1863 SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, 1864 PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) 1865 { 1866 SECURITY_STATUS ret; 1867 ULONG ntlmssp_flags_save; 1868 PNegoHelper helper; 1869 int token_idx, data_idx; 1870 TRACE("(%p %p %d %p)\n", phContext, pMessage, MessageSeqNo, pfQOP); 1871 1872 if(!phContext) 1873 return SEC_E_INVALID_HANDLE; 1874 1875 if(MessageSeqNo) 1876 FIXME("Ignoring MessageSeqNo\n"); 1877 1878 if(!pMessage || !pMessage->pBuffers || pMessage->cBuffers < 2) 1879 return SEC_E_INVALID_TOKEN; 1880 1881 if((token_idx = ntlm_GetTokenBufferIndex(pMessage)) == -1) 1882 return SEC_E_INVALID_TOKEN; 1883 1884 if((data_idx = ntlm_GetDataBufferIndex(pMessage)) ==-1) 1885 return SEC_E_INVALID_TOKEN; 1886 1887 if(pMessage->pBuffers[token_idx].cbBuffer < 16) 1888 return SEC_E_BUFFER_TOO_SMALL; 1889 1890 helper = (PNegoHelper) phContext->dwLower; 1891 1892 if(helper->neg_flags & NTLMSSP_NEGOTIATE_NTLM2 && helper->neg_flags & NTLMSSP_NEGOTIATE_SEAL) 1893 { 1894 SECUR32_arc4Process(helper->crypt.ntlm2.recv_a4i, 1895 pMessage->pBuffers[data_idx].pvBuffer, 1896 pMessage->pBuffers[data_idx].cbBuffer); 1897 } 1898 else 1899 { 1900 SECUR32_arc4Process(helper->crypt.ntlm.a4i, 1901 pMessage->pBuffers[data_idx].pvBuffer, 1902 pMessage->pBuffers[data_idx].cbBuffer); 1903 } 1904 1905 /* Make sure we use a session key for the signature check, EncryptMessage 1906 * always does that, even in the dummy case */ 1907 ntlmssp_flags_save = helper->neg_flags; 1908 1909 helper->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; 1910 ret = ntlm_VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP); 1911 1912 helper->neg_flags = ntlmssp_flags_save; 1913 1914 return ret; 1915 } 1916 1917 static const SecurityFunctionTableA ntlmTableA = { 1918 1, 1919 NULL, /* EnumerateSecurityPackagesA */ 1920 ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */ 1921 ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */ 1922 ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */ 1923 NULL, /* Reserved2 */ 1924 ntlm_InitializeSecurityContextA, /* InitializeSecurityContextA */ 1925 ntlm_AcceptSecurityContext, /* AcceptSecurityContext */ 1926 ntlm_CompleteAuthToken, /* CompleteAuthToken */ 1927 ntlm_DeleteSecurityContext, /* DeleteSecurityContext */ 1928 NULL, /* ApplyControlToken */ 1929 ntlm_QueryContextAttributesA, /* QueryContextAttributesA */ 1930 ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ 1931 ntlm_RevertSecurityContext, /* RevertSecurityContext */ 1932 ntlm_MakeSignature, /* MakeSignature */ 1933 ntlm_VerifySignature, /* VerifySignature */ 1934 FreeContextBuffer, /* FreeContextBuffer */ 1935 NULL, /* QuerySecurityPackageInfoA */ 1936 NULL, /* Reserved3 */ 1937 NULL, /* Reserved4 */ 1938 NULL, /* ExportSecurityContext */ 1939 NULL, /* ImportSecurityContextA */ 1940 NULL, /* AddCredentialsA */ 1941 NULL, /* Reserved8 */ 1942 NULL, /* QuerySecurityContextToken */ 1943 ntlm_EncryptMessage, /* EncryptMessage */ 1944 ntlm_DecryptMessage, /* DecryptMessage */ 1945 NULL, /* SetContextAttributesA */ 1946 }; 1947 1948 static const SecurityFunctionTableW ntlmTableW = { 1949 1, 1950 NULL, /* EnumerateSecurityPackagesW */ 1951 ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */ 1952 ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */ 1953 ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */ 1954 NULL, /* Reserved2 */ 1955 ntlm_InitializeSecurityContextW, /* InitializeSecurityContextW */ 1956 ntlm_AcceptSecurityContext, /* AcceptSecurityContext */ 1957 ntlm_CompleteAuthToken, /* CompleteAuthToken */ 1958 ntlm_DeleteSecurityContext, /* DeleteSecurityContext */ 1959 NULL, /* ApplyControlToken */ 1960 ntlm_QueryContextAttributesW, /* QueryContextAttributesW */ 1961 ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ 1962 ntlm_RevertSecurityContext, /* RevertSecurityContext */ 1963 ntlm_MakeSignature, /* MakeSignature */ 1964 ntlm_VerifySignature, /* VerifySignature */ 1965 FreeContextBuffer, /* FreeContextBuffer */ 1966 NULL, /* QuerySecurityPackageInfoW */ 1967 NULL, /* Reserved3 */ 1968 NULL, /* Reserved4 */ 1969 NULL, /* ExportSecurityContext */ 1970 NULL, /* ImportSecurityContextW */ 1971 NULL, /* AddCredentialsW */ 1972 NULL, /* Reserved8 */ 1973 NULL, /* QuerySecurityContextToken */ 1974 ntlm_EncryptMessage, /* EncryptMessage */ 1975 ntlm_DecryptMessage, /* DecryptMessage */ 1976 NULL, /* SetContextAttributesW */ 1977 }; 1978 1979 #define NTLM_COMMENT \ 1980 { 'N', 'T', 'L', 'M', ' ', \ 1981 'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', ' ', \ 1982 'P', 'a', 'c', 'k', 'a', 'g', 'e', 0} 1983 1984 static CHAR ntlm_comment_A[] = NTLM_COMMENT; 1985 static WCHAR ntlm_comment_W[] = NTLM_COMMENT; 1986 1987 #define NTLM_NAME {'N', 'T', 'L', 'M', 0} 1988 1989 static char ntlm_name_A[] = NTLM_NAME; 1990 static WCHAR ntlm_name_W[] = NTLM_NAME; 1991 1992 /* According to Windows, NTLM has the following capabilities. */ 1993 #define CAPS ( \ 1994 SECPKG_FLAG_INTEGRITY | \ 1995 SECPKG_FLAG_PRIVACY | \ 1996 SECPKG_FLAG_TOKEN_ONLY | \ 1997 SECPKG_FLAG_CONNECTION | \ 1998 SECPKG_FLAG_MULTI_REQUIRED | \ 1999 SECPKG_FLAG_IMPERSONATION | \ 2000 SECPKG_FLAG_ACCEPT_WIN32_NAME | \ 2001 SECPKG_FLAG_NEGOTIABLE | \ 2002 SECPKG_FLAG_LOGON | \ 2003 SECPKG_FLAG_RESTRICTED_TOKENS ) 2004 2005 static const SecPkgInfoW infoW = { 2006 CAPS, 2007 1, 2008 RPC_C_AUTHN_WINNT, 2009 NTLM_MAX_BUF, 2010 ntlm_name_W, 2011 ntlm_comment_W 2012 }; 2013 2014 static const SecPkgInfoA infoA = { 2015 CAPS, 2016 1, 2017 RPC_C_AUTHN_WINNT, 2018 NTLM_MAX_BUF, 2019 ntlm_name_A, 2020 ntlm_comment_A 2021 }; 2022 2023 SecPkgInfoA *ntlm_package_infoA = (SecPkgInfoA *)&infoA; 2024 SecPkgInfoW *ntlm_package_infoW = (SecPkgInfoW *)&infoW; 2025 2026 void SECUR32_initNTLMSP(void) 2027 { 2028 PNegoHelper helper; 2029 static CHAR version[] = "--version"; 2030 2031 SEC_CHAR *args[] = { 2032 ntlm_auth, 2033 version, 2034 NULL }; 2035 2036 if(fork_helper(&helper, ntlm_auth, args) != SEC_E_OK) 2037 helper = NULL; 2038 else 2039 check_version(helper); 2040 2041 if( helper && 2042 ((helper->major > MIN_NTLM_AUTH_MAJOR_VERSION) || 2043 (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION && 2044 helper->minor > MIN_NTLM_AUTH_MINOR_VERSION) || 2045 (helper->major == MIN_NTLM_AUTH_MAJOR_VERSION && 2046 helper->minor == MIN_NTLM_AUTH_MINOR_VERSION && 2047 helper->micro >= MIN_NTLM_AUTH_MICRO_VERSION)) ) 2048 { 2049 SecureProvider *provider = SECUR32_addProvider(&ntlmTableA, &ntlmTableW, NULL); 2050 SECUR32_addPackages(provider, 1L, ntlm_package_infoA, ntlm_package_infoW); 2051 } 2052 else 2053 { 2054 ERR_(winediag)("%s was not found or is outdated. " 2055 "Make sure that ntlm_auth >= %d.%d.%d is in your path. " 2056 "Usually, you can find it in the winbind package of your distribution.\n", 2057 ntlm_auth, 2058 MIN_NTLM_AUTH_MAJOR_VERSION, 2059 MIN_NTLM_AUTH_MINOR_VERSION, 2060 MIN_NTLM_AUTH_MICRO_VERSION); 2061 2062 } 2063 cleanup_helper(helper); 2064 } 2065