Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1453 lines
49 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. sspi.c
  5. Abstract:
  6. This file contains the implementation for SSPI Authentication
  7. The following functions are exported by this module:
  8. UnloadAuthenticateUser
  9. AuthenticateUser
  10. PreAuthenticateUser
  11. AuthenticateUserUI
  12. Author:
  13. Sudheer Koneru (SudK) Created 2/17/96
  14. Revision History:
  15. --*/
  16. #include <wininetp.h>
  17. #include "htuu.h"
  18. //#include "msnspmh.h"
  19. #ifdef DEBUG_WINSSPI
  20. #include <stdio.h>
  21. #endif
  22. #include "auth.h"
  23. //LPSTR StrChrA(LPCSTR lpStart, WORD wMatch); // from shlwapi.h
  24. #include "sspspm.h"
  25. #include "winctxt.h"
  26. extern SspData *g_pSspData;
  27. LPVOID SSPI_InitGlobals(void);
  28. DWORD g_cSspiContexts;
  29. #define NAME_SEPERATOR 0x5c // this is a backslash character which
  30. // seperates the domain name from user name
  31. VOID
  32. WINAPI
  33. UnloadAuthenticateUser(LPVOID *lppvContext,
  34. LPSTR lpszScheme,
  35. LPSTR lpszHost)
  36. {
  37. PWINCONTEXT pWinContext = (PWINCONTEXT) (*lppvContext);
  38. UNREFERENCED_PARAMETER(lpszScheme);
  39. UNREFERENCED_PARAMETER(lpszHost);
  40. if (!SSPI_InitGlobals())
  41. return;
  42. if (*lppvContext == NULL) {
  43. return;
  44. }
  45. if (pWinContext->pInBuffer != NULL &&
  46. pWinContext->pInBuffer != pWinContext->szInBuffer)
  47. {
  48. LocalFree (pWinContext->pInBuffer);
  49. }
  50. pWinContext->pInBuffer = NULL;
  51. pWinContext->dwInBufferLength = 0;
  52. // Free SSPI security context
  53. //
  54. if (pWinContext->pSspContextHandle != NULL)
  55. (*(g_pSspData->pFuncTbl->DeleteSecurityContext))(pWinContext->pSspContextHandle);
  56. // Free SSPI credential handle
  57. //
  58. if (pWinContext->pCredential)
  59. (*(g_pSspData->pFuncTbl->FreeCredentialHandle))(pWinContext->pCredential);
  60. pWinContext->pCredential = NULL;
  61. pWinContext->pSspContextHandle = NULL;
  62. if ( (pWinContext->lpszServerName != NULL) &&
  63. (pWinContext->lpszServerName != pWinContext->szServerName) )
  64. {
  65. LocalFree(pWinContext->lpszServerName);
  66. }
  67. LocalFree(pWinContext);
  68. *lppvContext = NULL;
  69. AuthLock();
  70. g_cSspiContexts--;
  71. AuthUnlock();
  72. return;
  73. }
  74. //+---------------------------------------------------------------------------
  75. //
  76. // Function: SaveServerName
  77. //
  78. // Synopsis: This function saves the destination server name in this
  79. // connection context for AuthenticateUserUI
  80. //
  81. // Arguments: [lpszServerName] - points to the target server name
  82. // [pWinContext] - points to the connection context
  83. //
  84. // Returns: TRUE if server name is successfully saved in connection context.
  85. // Otherwise, FALSE is returned.
  86. //
  87. //----------------------------------------------------------------------------
  88. BOOL
  89. SaveServerName (
  90. LPSTR lpszServerName,
  91. PWINCONTEXT pWinContext
  92. )
  93. {
  94. DWORD dwLen = lstrlen(lpszServerName);
  95. if (dwLen < DEFAULT_SERVER_NAME_LEN)
  96. {
  97. lstrcpy(pWinContext->szServerName, lpszServerName);
  98. pWinContext->lpszServerName = pWinContext->szServerName;
  99. }
  100. else
  101. { //
  102. // Server name is longer, need to allocate memory for the name
  103. //
  104. // Free already allocated memory if any
  105. if (pWinContext->lpszServerName &&
  106. pWinContext->lpszServerName != pWinContext->szServerName)
  107. {
  108. LocalFree (pWinContext->lpszServerName);
  109. }
  110. pWinContext->lpszServerName = (char *) LocalAlloc(0, dwLen+1);
  111. if (pWinContext->lpszServerName == NULL)
  112. return FALSE;
  113. lstrcpy(pWinContext->lpszServerName, lpszServerName);
  114. }
  115. return TRUE;
  116. }
  117. // Function bHasExtendedChars
  118. // Check if an ANSI string contains extended characters
  119. BOOL bHasExtendedChars(char const *str)
  120. {
  121. signed char const *p;
  122. for (p = (signed char const *)str; *p; p++)
  123. if ( *p < 0)
  124. return TRUE;
  125. return FALSE;
  126. }
  127. //+---------------------------------------------------------------------------
  128. //
  129. // Function: BuildNTLMauthData
  130. //
  131. // Synopsis: This function builds SEC_WINNT_AUTH_IDENTITY structure
  132. // from the user name and password specified. If domain name
  133. // is not specified in the user name, the Domain field in
  134. // the structure is set to NULL. NOTE: This structure is
  135. // specific to the NTLM SSPI package.
  136. // This function allocates a chunck of memory big enough for
  137. // storing user name, domain, and password. Then setup
  138. // pointers in pAuthData to use sections of this memory.
  139. //
  140. // Arguments: [pAuthData] - points to the SEC_WINNT_AUTH_IDENTITY structure
  141. // [lpszUserName] - points to the user name, which may also
  142. // include user's domain name.
  143. // [lpszPassword] - points to user's password
  144. //
  145. // Returns: TRUE if SEC_WINNT_AUTH_IDENTITY structure is successfully
  146. // initialized and built. Otherwise, FALSE is returned.
  147. //
  148. //----------------------------------------------------------------------------
  149. BOOL
  150. BuildNTLMauthData (
  151. PSEC_WINNT_AUTH_IDENTITY pAuthData,
  152. LPTSTR lpszUserName,
  153. LPTSTR lpszPassword
  154. )
  155. {
  156. DWORD dwUserLen, dwDomainLen, dwPwdLen;
  157. LPTSTR pName;
  158. LPTSTR pDomain = NULL;
  159. BOOL bUnicodeAuth = FALSE;
  160. if ( bHasExtendedChars(lpszUserName) || bHasExtendedChars(lpszPassword))
  161. bUnicodeAuth = TRUE;
  162. pAuthData->Flags = bUnicodeAuth ? SEC_WINNT_AUTH_IDENTITY_UNICODE : SEC_WINNT_AUTH_IDENTITY_ANSI;
  163. //
  164. // Check to see if domain name is specified in lpszUserName
  165. //
  166. pName = StrChrA (lpszUserName, NAME_SEPERATOR);
  167. if (pName) // Domain name specified
  168. {
  169. // Make sure that we don't change the original string in lpszUserName
  170. // because that it would be reused for other connections
  171. // Calculate no. of bytes in domain name
  172. dwDomainLen = (int)(pName - lpszUserName);
  173. // Convert to no. of characters
  174. pAuthData->DomainLength = dwDomainLen / sizeof(TCHAR);
  175. pDomain = lpszUserName;
  176. pName++;
  177. }
  178. else // No domain specified
  179. {
  180. pName = lpszUserName;
  181. pAuthData->Domain = NULL;
  182. pDomain = NULL;
  183. dwDomainLen = pAuthData->DomainLength = 0;
  184. }
  185. dwUserLen = pAuthData->UserLength = lstrlen (pName);
  186. dwPwdLen = pAuthData->PasswordLength = lstrlen (lpszPassword);
  187. //
  188. // Allocate memory for all: name, domain, and password
  189. // The memory block is big enough for Unicode. Some bytes will be wasted in the ANSI case
  190. //
  191. pAuthData->User = (unsigned char*)LocalAlloc(LMEM_ZEROINIT, (dwUserLen + dwDomainLen + dwPwdLen + 3)*sizeof(WCHAR));
  192. // Since the buffer is zero-initialized, strings don't need their '\0' copied over.
  193. if (pAuthData->User == NULL)
  194. return (FALSE);
  195. if (bUnicodeAuth)
  196. {
  197. // Convert the user name into Unicode and store in pAuthData->User
  198. if (0 == MultiByteToWideChar(CP_ACP, 0, pName, -1, (LPWSTR)(pAuthData->User), dwUserLen+1))
  199. return FALSE;
  200. }
  201. else
  202. CopyMemory (pAuthData->User, pName, dwUserLen);
  203. // Setup memory pointer for password
  204. //
  205. pAuthData->Password = pAuthData->User + (dwUserLen + 1) * sizeof(WCHAR);
  206. if (bUnicodeAuth)
  207. {
  208. if (0 == MultiByteToWideChar(CP_ACP, 0, lpszPassword, -1, (LPWSTR)(pAuthData->Password), dwPwdLen+1))
  209. return FALSE;
  210. }
  211. else
  212. CopyMemory (pAuthData->Password, lpszPassword, dwPwdLen);
  213. if (pAuthData->DomainLength > 0)
  214. {
  215. // Setup memory pointer for domain
  216. //
  217. pAuthData->Domain = pAuthData->Password + (dwPwdLen + 1) * sizeof(WCHAR);
  218. if (bUnicodeAuth)
  219. {
  220. // pDomain is not null terminated, so provide the length
  221. if (0 == MultiByteToWideChar(CP_ACP, 0, pDomain, dwDomainLen, (LPWSTR)(pAuthData->Domain), dwDomainLen+1))
  222. return FALSE;
  223. }
  224. else
  225. CopyMemory (pAuthData->Domain, pDomain, dwDomainLen);
  226. }
  227. else
  228. {
  229. pAuthData->Domain = NULL;
  230. }
  231. return (TRUE);
  232. }
  233. //+---------------------------------------------------------------------------
  234. //
  235. // Function: FreeNTLMauthData
  236. //
  237. // Synopsis: This function frees memory allocated for the
  238. // SEC_WINNT_AUTH_IDENTITY structure
  239. //
  240. // Arguments: [pAuthData] - points to the SEC_WINNT_AUTH_IDENTITY structure
  241. //
  242. // Returns: void.
  243. //
  244. //----------------------------------------------------------------------------
  245. VOID
  246. FreeNTLMauthData (
  247. PSEC_WINNT_AUTH_IDENTITY pAuthData
  248. )
  249. {
  250. //
  251. // Free User which points to memory for all domain, name, and password
  252. //
  253. if (pAuthData->User)
  254. {
  255. int iCharacterSize = 0;
  256. if (pAuthData->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
  257. iCharacterSize = sizeof(char);
  258. else if (pAuthData->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
  259. iCharacterSize = sizeof(WCHAR);
  260. SecureZeroMemory(pAuthData->User, iCharacterSize * pAuthData->UserLength);
  261. SecureZeroMemory(pAuthData->Password, iCharacterSize * pAuthData->PasswordLength);
  262. LocalFree (pAuthData->User);
  263. }
  264. }
  265. //+---------------------------------------------------------------------------
  266. //
  267. // Function: NewWinContext
  268. //
  269. // Synopsis: This function creates a new context and a new credential
  270. // handle for this connection. If a user name/password is
  271. // specified, the credential handle is created for the
  272. // specified user. Otherwise, the credential handle is created
  273. // for the local logon user.
  274. //
  275. // Arguments: [pkgId] - the package ID (index into SSPI package list)
  276. // [lpszScheme] - the name of the current authentication scheme,
  277. // which is also the SSPI package name
  278. // [ppCtxt] - this returns the pointer of the created context
  279. // to the caller.
  280. // [lpszUserName] - the name of a specific user to be used
  281. // for authentication. If this is NULL, the
  282. // credential of the currently logon user is
  283. // used for authentication.
  284. // [lpszPassword] - the password of the specified user, if any.
  285. //
  286. // Returns: ERROR_SUCCESS - if the new context is created successfully
  287. // ERROR_NOT_ENOUGH_MEMORY - if memory allocation failed
  288. // ERROR_INVALID_PARAMETER - the SSPI call for creating the
  289. // security credential handle failed
  290. //
  291. //----------------------------------------------------------------------------
  292. DWORD
  293. NewWinContext (
  294. INT pkgId,
  295. LPSTR lpszScheme,
  296. PWINCONTEXT *ppCtxt,
  297. BOOL fCanUseLogon,
  298. LPSTR lpszUserName,
  299. LPSTR lpszPassword
  300. )
  301. {
  302. SECURITY_STATUS ss;
  303. TimeStamp Lifetime;
  304. PWINCONTEXT pWinContext;
  305. SEC_WINNT_AUTH_IDENTITY AuthData;
  306. PSEC_WINNT_AUTH_IDENTITY pAuthData;
  307. DWORD Capabilities ;
  308. DWORD SecurityBlobSize;
  309. //
  310. // need space for maxtoken size for in+out, + base64 encoding overhead for each.
  311. // really 1.34 overhead, but just round up to 1.5
  312. //
  313. SecurityBlobSize = GetPkgMaxToken(pkgId);
  314. SecurityBlobSize += (SecurityBlobSize/2);
  315. //
  316. // note: for compatibility sake, make the buffer size the MAX_BLOB_SIZE at the minimum
  317. // consider removing this once we're convinced all packages return good cbMaxToken values.
  318. //
  319. if( SecurityBlobSize < MAX_BLOB_SIZE )
  320. {
  321. SecurityBlobSize = MAX_BLOB_SIZE;
  322. }
  323. pWinContext = (PWINCONTEXT) LocalAlloc(
  324. 0,
  325. sizeof(WINCONTEXT) +
  326. (SecurityBlobSize*2)
  327. );
  328. if (pWinContext == NULL)
  329. return (ERROR_NOT_ENOUGH_MEMORY);
  330. // Initialize context
  331. //
  332. ZeroMemory( pWinContext, sizeof(WINCONTEXT) );
  333. pWinContext->pkgId = (DWORD)pkgId;
  334. pWinContext->szOutBuffer = (char*)(pWinContext+1);
  335. pWinContext->cbOutBuffer = SecurityBlobSize;
  336. pWinContext->szInBuffer = pWinContext->szOutBuffer + pWinContext->cbOutBuffer;
  337. pWinContext->cbInBuffer = SecurityBlobSize;
  338. //
  339. // Get bitmask representing the package capabilities
  340. //
  341. Capabilities = GetPkgCapabilities( pkgId );
  342. if ( ( Capabilities & SSPAUTHPKG_SUPPORT_NTLM_CREDS ) == 0 )
  343. {
  344. pAuthData = NULL;
  345. }
  346. else if (lpszUserName && lpszPassword)
  347. {
  348. // Build AuthData from the specified user name/password
  349. if (!BuildNTLMauthData (&AuthData, lpszUserName, lpszPassword))
  350. {
  351. LocalFree (pWinContext);
  352. return (ERROR_NOT_ENOUGH_MEMORY);
  353. }
  354. pAuthData = &AuthData;
  355. }
  356. else if (fCanUseLogon && !lpszUserName && !lpszPassword)
  357. {
  358. // The zone policy allows silent use of the logon credential.
  359. pAuthData = NULL;
  360. }
  361. else
  362. {
  363. LocalFree (pWinContext);
  364. // We must prompt the user for credentials.
  365. return ERROR_WINHTTP_INCORRECT_PASSWORD;
  366. }
  367. //
  368. // Call SSPI function acquire security credential for this package
  369. //
  370. ss = (*(g_pSspData->pFuncTbl->AcquireCredentialsHandle))(
  371. NULL, // New principal
  372. lpszScheme, // SSPI Package Name
  373. SECPKG_CRED_OUTBOUND,// Credential Use
  374. NULL, // Logon ID
  375. pAuthData, // Auth Data
  376. NULL, // Get key func
  377. NULL, // Get key arg
  378. &pWinContext->Credential, // Credential Handle
  379. &Lifetime );
  380. if (pAuthData)
  381. FreeNTLMauthData (pAuthData);
  382. if (ss != STATUS_SUCCESS)
  383. {
  384. LocalFree (pWinContext);
  385. return (ERROR_INVALID_PARAMETER);
  386. }
  387. pWinContext->pCredential = &pWinContext->Credential;
  388. *ppCtxt = pWinContext;
  389. AuthLock();
  390. g_cSspiContexts++;
  391. AuthUnlock();
  392. return (ERROR_SUCCESS);
  393. }
  394. //+---------------------------------------------------------------------------
  395. //
  396. // Function: RedoNTLMAuth4User
  397. //
  398. // Synopsis: This function recreates a NTLM credential handle for the
  399. // specified user and generate a NEGOTIATE message in
  400. // the provided buffer with the new credential handle.
  401. //
  402. // Arguments: [pWinContext] - points to the connection context
  403. // [pkgId] - specifies the SSPI pkg to be used for authentication
  404. // [lpszUserName] - the name of the specific user to be used
  405. // for authentication.
  406. // [lpszPassword] - the password of the specified user,
  407. // [lpszServerName] - the target server name
  408. // [lpszScheme] - the name of the current authentication scheme,
  409. // which is also the SSPI package name
  410. // [lpOutBuffer] - points to the buffer for the new authorization
  411. // header including the UUENCODED NEGOTIATE msg
  412. // [lpdwOutBufferLength] - returns the length of the generated
  413. // authorization header.
  414. //
  415. // Returns: ERROR_SUCCESS - if the new authorization header is successfully
  416. // created for the new user name/password
  417. // ERROR_NOT_ENOUGH_MEMORY - if memory allocation failed
  418. // ERROR_INVALID_HANDLE - the SSPI call for generating the
  419. // new NEGOTIATE msg failed
  420. //
  421. //----------------------------------------------------------------------------
  422. DWORD
  423. RedoNTLMAuth4User (
  424. PWINCONTEXT pWinContext,
  425. INT pkgId,
  426. LPSTR lpszUserName,
  427. LPSTR lpszPassword,
  428. LPSTR lpszServerName,
  429. LPSTR lpszScheme,
  430. IN BOOL fCanUseLogon,
  431. LPSTR lpOutBuffer,
  432. LPDWORD lpdwOutBufferLength,
  433. SECURITY_STATUS *pssResult
  434. )
  435. {
  436. SECURITY_STATUS ss;
  437. DWORD dwStatus;
  438. TimeStamp Lifetime;
  439. SEC_WINNT_AUTH_IDENTITY AuthData;
  440. ULONG fContextReq = ISC_REQ_DELEGATE;
  441. DWORD dwMaxLen;
  442. if (pWinContext->pSspContextHandle)
  443. {
  444. (*(g_pSspData->pFuncTbl->DeleteSecurityContext))(pWinContext->pSspContextHandle);
  445. pWinContext->pSspContextHandle = NULL;
  446. }
  447. // Free existing credential handle
  448. //
  449. if (pWinContext->pCredential)
  450. {
  451. (*(g_pSspData->pFuncTbl->FreeCredentialHandle))(pWinContext->pCredential);
  452. pWinContext->pCredential = NULL;
  453. }
  454. //
  455. // Build the NTLM SSPI AuthData from the specified user name/password
  456. //
  457. if (!BuildNTLMauthData (&AuthData, lpszUserName, lpszPassword))
  458. return (ERROR_NOT_ENOUGH_MEMORY);
  459. //
  460. // Call SSPI function acquire security credential for this user
  461. //
  462. ss = (*(g_pSspData->pFuncTbl->AcquireCredentialsHandle))(
  463. NULL, // New principal
  464. lpszScheme, // SSPI Package Name
  465. SECPKG_CRED_OUTBOUND,// Credential Use
  466. NULL, // Logon ID
  467. &AuthData, // Auth Data
  468. NULL, // Get key func
  469. NULL, // Get key arg
  470. &pWinContext->Credential, // Credential Handle
  471. &Lifetime );
  472. FreeNTLMauthData (&AuthData); // don't need it any more
  473. if (ss != STATUS_SUCCESS)
  474. {
  475. return (ERROR_INVALID_HANDLE);
  476. }
  477. pWinContext->pCredential = &pWinContext->Credential;
  478. dwMaxLen = *lpdwOutBufferLength;
  479. //
  480. // Generate NEGOTIATE message in the provided buffer for this user
  481. //
  482. dwStatus = GetSecAuthMsg( g_pSspData,
  483. pWinContext->pCredential,
  484. pkgId,
  485. NULL,
  486. &(pWinContext->SspContextHandle),
  487. fContextReq,
  488. NULL,
  489. 0,
  490. lpOutBuffer,
  491. lpdwOutBufferLength,
  492. lpszServerName,
  493. fCanUseLogon,
  494. TRUE,
  495. lpszScheme,
  496. pssResult);
  497. if (dwStatus != SPM_STATUS_OK)
  498. {
  499. *lpdwOutBufferLength = 0; // no exchange blob generated
  500. return(ERROR_INVALID_HANDLE);
  501. }
  502. pWinContext->pSspContextHandle = &(pWinContext->SspContextHandle);
  503. //
  504. // If we are not in the initial state, continue to a RESPONSE message
  505. //
  506. if (pWinContext->pInBuffer != NULL && pWinContext->dwInBufferLength > 0)
  507. {
  508. *lpdwOutBufferLength = dwMaxLen;
  509. ZeroMemory( lpOutBuffer, dwMaxLen );
  510. dwStatus = GetSecAuthMsg( g_pSspData,
  511. pWinContext->pCredential,
  512. pWinContext->pkgId,
  513. pWinContext->pSspContextHandle,
  514. (PCtxtHandle) &(pWinContext->SspContextHandle),
  515. fContextReq,
  516. pWinContext->pInBuffer,
  517. pWinContext->dwInBufferLength,
  518. lpOutBuffer,
  519. lpdwOutBufferLength,
  520. pWinContext->lpszServerName,
  521. fCanUseLogon,
  522. TRUE,
  523. lpszScheme,
  524. pssResult);
  525. // Clear out the input exchange blob
  526. //
  527. if (pWinContext->pInBuffer != NULL)
  528. {
  529. if (pWinContext->pInBuffer != pWinContext->szInBuffer)
  530. LocalFree (pWinContext->pInBuffer);
  531. pWinContext->pInBuffer = NULL;
  532. pWinContext->dwInBufferLength = 0;
  533. }
  534. if (dwStatus != SPM_STATUS_OK)
  535. {
  536. *lpdwOutBufferLength = 0; // no exchange blob generated
  537. return(ERROR_INVALID_HANDLE);
  538. }
  539. }
  540. return (ERROR_SUCCESS);
  541. }
  542. //
  543. // functions
  544. //
  545. /*++
  546. Routine Description:
  547. Generates a Basic User Authentication string for WinINet or
  548. other callers can use
  549. Arguments:
  550. lpContext - if the package accepts the request & authentication
  551. requires multiple transactions, the package will supply
  552. a context value which will be used in subsequent calls,
  553. Currently this contains a pointer to a pointer of a
  554. User defined Void Pointer. Can be Assume to be NULL
  555. if this is the first instance of a Realm - Host Combo
  556. lpszServerName - the name of the server we are performing
  557. authentication for. We may want to supply the full URL
  558. lpszScheme - the name of the authentication scheme we are seeking, in case the package supports multiple schemes
  559. dwFlags - on input, flags modifying how the package should behave,
  560. e.g. "only authenticate if you don't have to get user
  561. information" On output contains flags relevant to
  562. future HTTP requests, e.g. "don't cache any data from
  563. this connection". Note, this information should not be
  564. specific to HTTP - we may want to use the same flags
  565. for FTP, etc.
  566. lpszInBuffer - pointer to the string containing the response from
  567. the server (if any)
  568. dwInBufferLength - number of bytes in lpszInBuffer. No CR-LF sequence, no terminating NUL
  569. lpOutBuffer - pointer to a buffer where the challenge response will be written by the
  570. package if it can handle the request
  571. lpdwOutBufferLength - on input, contains the size of lpOutBuffer. On output, contains the
  572. number of bytes to return to the server in the next GET request
  573. (or whatever). If lpOutBuffer is too small, the package should
  574. return ERROR_INSUFFICIENT_BUFFER and set *lpdwOutBufferLength to be
  575. the required length
  576. We will keep a list of the authentication packages and the schemes they support,
  577. along with the entry point name (should be the same for all packages) in the registry.
  578. Wininet should keep enough information such that it can make a reasonable guess as to
  579. whether we need to authenticate a connection attempt, or whether we can use previously
  580. authenticated information
  581. Return Value:
  582. DWORD
  583. Success - non-zero
  584. Failure - 0. Error status is available by calling GetLastError()
  585. --*/
  586. DWORD
  587. WINAPI
  588. AuthenticateUser(
  589. IN OUT LPVOID *lppvContext,
  590. IN LPSTR lpszServerName,
  591. IN LPSTR lpszScheme,
  592. IN BOOL fCanUseLogon,
  593. IN LPSTR lpszInBuffer,
  594. IN DWORD dwInBufferLength,
  595. IN LPSTR lpszUserName,
  596. IN LPSTR lpszPassword,
  597. OUT SECURITY_STATUS *pssResult
  598. )
  599. {
  600. PWINCONTEXT pWinContext;
  601. LPSTR pServerBlob = NULL;
  602. int pkgId;
  603. DWORD SPMStatus;
  604. ULONG fContextReq = ISC_REQ_DELEGATE;
  605. BOOL bNonBlock = TRUE;
  606. if (!SSPI_InitGlobals())
  607. return ERROR_INVALID_PARAMETER;
  608. pkgId = GetPkgId(lpszScheme);
  609. if (pkgId == -1)
  610. return (ERROR_INVALID_PARAMETER);
  611. if (*lppvContext == NULL) // a new connection
  612. {
  613. DWORD dwStatus;
  614. //
  615. // First time we are getting called here, there should be no input blob
  616. //
  617. if (dwInBufferLength != 0)
  618. return (ERROR_INVALID_PARAMETER);
  619. dwStatus = NewWinContext (pkgId, lpszScheme, &pWinContext,
  620. fCanUseLogon, lpszUserName, lpszPassword);
  621. if (dwStatus != ERROR_SUCCESS)
  622. return (dwStatus);
  623. (*lppvContext) = (LPVOID) pWinContext;
  624. #ifdef DEBUG_WINSSPI
  625. (void)wsprintf (msg, "AuthenticateUser> Scheme= %s Server= '%s'\n",
  626. lpszScheme, lpszServerName);
  627. OutputDebugString(msg);
  628. #endif
  629. }
  630. else
  631. {
  632. pWinContext = (PWINCONTEXT) (*lppvContext);
  633. //
  634. // The package Id better be the same. Cant just switch packageId
  635. // arbitrarily
  636. //
  637. if (pWinContext->pkgId != (DWORD)pkgId)
  638. return (ERROR_INVALID_PARAMETER);
  639. pServerBlob = lpszInBuffer;
  640. //++(pWinContext->dwCallId); // Increment Call Id
  641. //
  642. // BUGBUG: Hack for now to know when auth failed
  643. // The only time we get lpszInBuffer to be empty is when
  644. // Web server failed the authentication request
  645. //
  646. if (dwInBufferLength == 0)
  647. {
  648. //
  649. // This means auth has failed as far as NTLM are concerned.
  650. // Will result in UI being done again for new passwd
  651. //
  652. // Make sure we should have the same server name as before
  653. //
  654. if ( pWinContext->lpszServerName != NULL &&
  655. lstrcmp (pWinContext->lpszServerName, lpszServerName) != 0 )
  656. {
  657. return(ERROR_INVALID_PARAMETER);
  658. }
  659. if (!SaveServerName (lpszServerName, pWinContext))
  660. return (ERROR_NOT_ENOUGH_MEMORY);
  661. //
  662. // Delete the original SSPI context handle and
  663. // let UI recreate one.
  664. //
  665. if (pWinContext->pSspContextHandle)
  666. {
  667. (*(g_pSspData->pFuncTbl->DeleteSecurityContext))(pWinContext->pSspContextHandle);
  668. pWinContext->pSspContextHandle = NULL;
  669. }
  670. if (pWinContext->pInBuffer != NULL &&
  671. pWinContext->pInBuffer != pWinContext->szInBuffer)
  672. {
  673. LocalFree (pWinContext->pInBuffer);
  674. }
  675. pWinContext->pInBuffer = NULL;
  676. pWinContext->dwInBufferLength = 0;
  677. //
  678. // clear buffer length for the exchange blob
  679. //
  680. pWinContext->dwOutBufferLength = 0;
  681. return (ERROR_WINHTTP_INCORRECT_PASSWORD);
  682. }
  683. }
  684. //
  685. // Setup dwOutBufferLength to represent max. memory in szOutBuffer
  686. //
  687. pWinContext->dwOutBufferLength = pWinContext->cbOutBuffer;
  688. ZeroMemory (pWinContext->szOutBuffer, pWinContext->cbOutBuffer);
  689. //
  690. // This will generate an authorization header with UUEncoded blob from SSPI.
  691. // BUGBUG: Better make sure outbuf buffer is big enough for this.
  692. //
  693. SPMStatus = GetSecAuthMsg( g_pSspData,
  694. pWinContext->pCredential,
  695. pkgId,
  696. pWinContext->pSspContextHandle,
  697. &(pWinContext->SspContextHandle),
  698. fContextReq,
  699. pServerBlob,
  700. dwInBufferLength,
  701. pWinContext->szOutBuffer,
  702. &pWinContext->dwOutBufferLength,
  703. lpszServerName,
  704. fCanUseLogon,
  705. bNonBlock,
  706. lpszScheme,
  707. pssResult);
  708. if (SPMStatus != SPM_STATUS_OK) // Fail to generate blob
  709. {
  710. pWinContext->dwOutBufferLength = 0; // no exchange blob generated
  711. //
  712. // if SSPI is requesting an opportunity to prompt for user credential
  713. //
  714. if (SPMStatus == SPM_STATUS_WOULD_BLOCK)
  715. {
  716. if (!SaveServerName (lpszServerName, pWinContext))
  717. return (ERROR_NOT_ENOUGH_MEMORY);
  718. // If there is a exchange blob, this is not the first call
  719. //
  720. if (pServerBlob && dwInBufferLength > 0)
  721. {
  722. // Save the exchange blob in the connection context
  723. // so we can call SSPI again with the exchange blob
  724. if (dwInBufferLength > MAX_BLOB_SIZE)
  725. {
  726. if (pWinContext->pInBuffer != NULL &&
  727. pWinContext->pInBuffer != pWinContext->szInBuffer)
  728. {
  729. LocalFree (pWinContext->pInBuffer);
  730. }
  731. pWinContext->pInBuffer = (PCHAR) LocalAlloc(0,
  732. dwInBufferLength);
  733. if (pWinContext->pInBuffer == NULL)
  734. return (ERROR_NOT_ENOUGH_MEMORY);
  735. }
  736. else
  737. pWinContext->pInBuffer = pWinContext->szInBuffer;
  738. CopyMemory( pWinContext->szInBuffer, pServerBlob,
  739. dwInBufferLength );
  740. pWinContext->dwInBufferLength = dwInBufferLength;
  741. }
  742. else
  743. {
  744. //
  745. // Delete the original SSPI context handle and
  746. // let UI recreate one.
  747. //
  748. if (pWinContext->pSspContextHandle)
  749. {
  750. (*(g_pSspData->pFuncTbl->DeleteSecurityContext))(pWinContext->pSspContextHandle);
  751. pWinContext->pSspContextHandle = NULL;
  752. }
  753. //
  754. // clear buffer length for the exchange blob
  755. //
  756. if (pWinContext->pInBuffer != NULL &&
  757. pWinContext->pInBuffer != pWinContext->szInBuffer)
  758. {
  759. LocalFree (pWinContext->pInBuffer);
  760. }
  761. pWinContext->pInBuffer = NULL;
  762. pWinContext->dwInBufferLength = 0;
  763. }
  764. pWinContext->dwOutBufferLength = 0;
  765. return(ERROR_WINHTTP_INCORRECT_PASSWORD);
  766. }
  767. return (ERROR_WINHTTP_LOGIN_FAILURE);
  768. }
  769. else if (pWinContext->pSspContextHandle == NULL)
  770. {
  771. // This means that we've just created a security context
  772. //
  773. pWinContext->pSspContextHandle = &(pWinContext->SspContextHandle);
  774. }
  775. return ERROR_WINHTTP_RESEND_REQUEST;
  776. }
  777. DWORD
  778. WINAPI
  779. PreAuthenticateUser(
  780. IN OUT LPVOID *lppvContext,
  781. IN LPSTR lpszServerName,
  782. IN LPSTR lpszScheme,
  783. IN BOOL fCanUseLogon,
  784. IN DWORD dwFlags,
  785. OUT LPSTR lpOutBuffer,
  786. IN OUT LPDWORD lpdwOutBufferLength,
  787. IN LPSTR lpszUserName,
  788. IN LPSTR lpszPassword,
  789. SECURITY_STATUS *pssResult
  790. )
  791. {
  792. INT pkgId;
  793. DWORD dwStatus;
  794. PWINCONTEXT pWinContext;
  795. BOOL bNonBlock = TRUE;
  796. ULONG fContextReq = ISC_REQ_DELEGATE;
  797. DWORD Capabilities ;
  798. UNREFERENCED_PARAMETER(dwFlags);
  799. if (!SSPI_InitGlobals())
  800. return ERROR_INVALID_PARAMETER;
  801. if (lpszServerName == NULL || *lpszServerName == '\0')
  802. return(ERROR_INVALID_PARAMETER);
  803. pkgId = GetPkgId(lpszScheme);
  804. if (pkgId == -1) {
  805. return(ERROR_INVALID_PARAMETER);
  806. }
  807. Capabilities = GetPkgCapabilities( pkgId );
  808. //
  809. // If this is for an existing connection
  810. //
  811. if (*lppvContext != NULL)
  812. {
  813. pWinContext = (PWINCONTEXT) (*lppvContext);
  814. if ((DWORD)pkgId != pWinContext->pkgId)
  815. return(ERROR_INVALID_PARAMETER);
  816. //
  817. // For package that does not handle its own UI, if there is no
  818. // generated blob, it means that we have just collected
  819. // user name/password.
  820. //
  821. if ( ( pWinContext->dwOutBufferLength == 0 ) &&
  822. ( Capabilities & SSPAUTHPKG_SUPPORT_NTLM_CREDS ) )
  823. {
  824. if (lpszUserName == NULL || lpszPassword == NULL)
  825. {
  826. return(ERROR_INVALID_PARAMETER);
  827. }
  828. //
  829. // Need to recreate a credential handle and
  830. // generate a new NEGOTIATE message in lpOutBuffer
  831. //
  832. dwStatus = RedoNTLMAuth4User (pWinContext,
  833. pkgId,
  834. lpszUserName,
  835. lpszPassword,
  836. lpszServerName ,
  837. lpszScheme,
  838. fCanUseLogon,
  839. lpOutBuffer,
  840. lpdwOutBufferLength,
  841. pssResult);
  842. if (dwStatus != ERROR_SUCCESS)
  843. return (dwStatus);
  844. return(ERROR_SUCCESS);
  845. }
  846. else if (pWinContext->dwOutBufferLength == 0)
  847. //
  848. // For other packages, If there is no generated blob,
  849. // something is wrong
  850. //
  851. return(ERROR_INVALID_PARAMETER);
  852. }
  853. // If not NTLM, don't pre-auth.
  854. else if ( (Capabilities & SSPAUTHPKG_SUPPORT_NTLM_CREDS ) == 0 )
  855. {
  856. return (ERROR_INVALID_HANDLE);
  857. }
  858. else
  859. {
  860. // probably sending 1st request on a new connection for the same URL
  861. // Create a new context and SSPI credential handle for this connection
  862. //
  863. // Set fCanUseLogon to TRUE : we would not be pre-authing
  864. // unless we have a valid pwc which means we already checked
  865. // zone policy for silent logon.
  866. dwStatus = NewWinContext (pkgId, lpszScheme, &pWinContext,
  867. fCanUseLogon, lpszUserName, lpszPassword);
  868. if (dwStatus != ERROR_SUCCESS)
  869. return (dwStatus);
  870. #ifdef DEBUG_WINSSPI
  871. (void)wsprintf (msg,
  872. "PreAuthenticateUser> New Context for Scheme= %s Server= '%s'\n",
  873. lpszScheme, lpszServerName);
  874. OutputDebugString(msg);
  875. #endif
  876. pWinContext->dwOutBufferLength = pWinContext->cbOutBuffer;
  877. ZeroMemory (pWinContext->szOutBuffer, pWinContext->cbOutBuffer);
  878. //
  879. // This will generate an authorization header with the
  880. // UUEncoded blob from SSPI.
  881. // BUGBUG: Better make sure outbuf buffer is big enough for this.
  882. //
  883. dwStatus = GetSecAuthMsg( g_pSspData,
  884. pWinContext->pCredential,
  885. pkgId,
  886. NULL,
  887. &(pWinContext->SspContextHandle),
  888. fContextReq,
  889. NULL,
  890. 0,
  891. pWinContext->szOutBuffer,
  892. &pWinContext->dwOutBufferLength,
  893. lpszServerName,
  894. fCanUseLogon,
  895. bNonBlock,
  896. lpszScheme,
  897. pssResult);
  898. if (dwStatus != SPM_STATUS_OK)
  899. {
  900. // This is a rare case
  901. //
  902. pWinContext->dwOutBufferLength = 0; // no exchange blob generated
  903. return(ERROR_INVALID_HANDLE);
  904. }
  905. (*lppvContext) = (LPVOID) pWinContext;
  906. // Save the pointer of the created security ctxt
  907. //
  908. pWinContext->pSspContextHandle = &(pWinContext->SspContextHandle);
  909. }
  910. //
  911. // Copy exchange blob to the output buffer
  912. // Make sure output buffer provided is big enough
  913. //
  914. if (*lpdwOutBufferLength < pWinContext->dwOutBufferLength)
  915. {
  916. *lpdwOutBufferLength = pWinContext->dwOutBufferLength + 1;
  917. return(ERROR_INSUFFICIENT_BUFFER);
  918. }
  919. CopyMemory (lpOutBuffer, pWinContext->szOutBuffer,
  920. pWinContext->dwOutBufferLength);
  921. if (*lpdwOutBufferLength > pWinContext->dwOutBufferLength)
  922. lpOutBuffer[pWinContext->dwOutBufferLength] = '\0';
  923. *lpdwOutBufferLength = pWinContext->dwOutBufferLength;
  924. //
  925. // The exchange blob has being copied to request header, so clear its len
  926. //
  927. pWinContext->dwOutBufferLength = 0;
  928. return(ERROR_SUCCESS);
  929. }
  930. BOOL g_fUUEncodeData = TRUE;
  931. typedef enum _COMPUTER_NAME_FORMAT {
  932. ComputerNameNetBIOS,
  933. ComputerNameDnsHostname,
  934. ComputerNameDnsDomain,
  935. ComputerNameDnsFullyQualified,
  936. ComputerNamePhysicalNetBIOS,
  937. ComputerNamePhysicalDnsHostname,
  938. ComputerNamePhysicalDnsDomain,
  939. ComputerNamePhysicalDnsFullyQualified,
  940. ComputerNameMax
  941. } COMPUTER_NAME_FORMAT ;
  942. typedef
  943. BOOL
  944. (WINAPI * PFN_GET_COMPUTER_NAME_EX)(
  945. IN COMPUTER_NAME_FORMAT NameType,
  946. OUT LPSTR lpBuffer,
  947. IN OUT LPDWORD nSize
  948. );
  949. PFN_GET_COMPUTER_NAME_EX g_pfnGetComputerNameExA = NULL;
  950. /*-----------------------------------------------------------------------------
  951. **
  952. ** Function: GetSecAuthMsg
  953. **
  954. ** Synopsis: This function generates a SSPI NEGOTIATE or RESPONSE
  955. ** authorization string for the specified SSPI package.
  956. ** The authorization string generated by this function
  957. ** follows the format:
  958. ** "<Package Name> <Package Specific Auth. Data>"
  959. ** If global uuencoding is turned on, this functions will
  960. ** uuencode the message before building it into an
  961. ** authorization string; by default, the uuencoding flag is
  962. ** always on.
  963. ** This functions calls InitializeSecurityContext() to
  964. ** generate the NEGOTIATE/RESPONSE message for the authori-
  965. ** zation string. If the SSPI function returns NO_CREDENTIAL,
  966. ** and if the PROMPT_CREDS flag is not turned on when blocking
  967. ** is permitted, this function will call the SSPI function
  968. ** again with the PROMPT_CREDS flag set; if SSPI returns
  969. ** NO_CREDENTIAL again, this SSPI will return ERROR to the
  970. ** caller.
  971. **
  972. **
  973. ** Arguments:
  974. **
  975. ** pData - pointer to SspData containing the SSPI function table
  976. ** and the SSPI package list.
  977. ** pkgID - the package index of the SSPI package to use.
  978. ** pInContext - pointer to a context handle. If NULL is specified,
  979. ** this function will use a temporary space for the context
  980. ** handle and delete the handle before returning to the
  981. ** caller. If non-NULL address is specified, the context
  982. ** handle created by the SSPI is returned to the caller.
  983. ** And the caller will have to delete the handle when it's
  984. ** done with it.
  985. ** fContextReq - the SSPI request flag to pass to InitializeSecurityContext
  986. ** pBuffIn - pointer to the uudecoded CHALLENGE message if any.
  987. ** For generating NEGOTIATE message, this pointer should be NULL.
  988. ** cbBuffIn - length of the CHALLENGE message. This should be zero when
  989. ** when pBuffIn is NULL.
  990. ** pFinalBuff - pointer to a buffer for the final authorization string.
  991. ** pszTarget - Server Host Name
  992. ** bNonBlock - a flag which is set if blocking is not permitted.
  993. **
  994. ** Return Value:
  995. **
  996. ** SPM_STATUS_OK - if an authorization string is generated successfully
  997. ** SPM_STATUS_WOULD_BLOCK - if generating an authorization string would
  998. ** cause blocking when blocking is not permitted.
  999. ** SPM_ERROR - if any problem/error is encountered in generating an
  1000. ** authorization string, including user hitting cancel on
  1001. ** the SSPI dialog prompt for name/password.
  1002. **
  1003. **---------------------------------------------------------------------------*/
  1004. DWORD
  1005. GetSecAuthMsg (
  1006. PSspData pData,
  1007. PCredHandle pCredential,
  1008. DWORD pkgID, // the package index into package list
  1009. PCtxtHandle pInContext,
  1010. PCtxtHandle pOutContext,
  1011. ULONG fContextReq, // Request Flags
  1012. VOID *pBuffIn,
  1013. DWORD cbBuffIn,
  1014. char *pFinalBuff,
  1015. DWORD *pcbBuffOut,
  1016. SEC_CHAR *pszTarget, // Server Host Name
  1017. BOOL fTargetTrusted,
  1018. UINT bNonBlock,
  1019. LPSTR pszScheme,
  1020. SECURITY_STATUS *pssResult
  1021. )
  1022. {
  1023. UNREFERENCED_PARAMETER(fTargetTrusted);
  1024. char *SlowDecodedBuf = NULL;
  1025. int retsize;
  1026. SECURITY_STATUS SecStat;
  1027. TimeStamp Lifetime;
  1028. SecBufferDesc OutBuffDesc;
  1029. SecBuffer OutSecBuff;
  1030. SecBufferDesc InBuffDesc;
  1031. SecBuffer InSecBuff;
  1032. ULONG ContextAttributes;
  1033. char *SlowOutBufPlain = NULL;
  1034. char *pOutMsg = NULL;
  1035. DWORD RetStatus;
  1036. long maxbufsize;
  1037. CHAR szDecoratedTarget[MAX_PATH + 6];
  1038. DWORD cbTarget;
  1039. ULONG cbMaxToken;
  1040. //
  1041. // BUGBUG: Deal with output buffer not being long enough
  1042. if (pFinalBuff == NULL) {
  1043. return(SPM_ERROR);
  1044. }
  1045. //
  1046. // Prepare our output buffer. We use a temporary buffer because
  1047. // the real output buffer will most likely need to be uuencoded
  1048. //
  1049. OutBuffDesc.ulVersion = 0;
  1050. OutBuffDesc.cBuffers = 1;
  1051. OutBuffDesc.pBuffers = &OutSecBuff;
  1052. OutSecBuff.cbBuffer = MAX_AUTH_MSG_SIZE;
  1053. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  1054. // Dynamically allocate since being in a service doesn't
  1055. // give us the guaranteed luxury of 10+KB stack allocations.
  1056. cbMaxToken = GetPkgMaxToken(pkgID);
  1057. SlowOutBufPlain = (char *) ALLOCATE_FIXED_MEMORY(cbMaxToken);
  1058. if( SlowOutBufPlain == NULL )
  1059. {
  1060. RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
  1061. goto Cleanup;
  1062. }
  1063. OutSecBuff.pvBuffer = SlowOutBufPlain;
  1064. OutSecBuff.cbBuffer = cbMaxToken;
  1065. //
  1066. // Prepare our Input buffer if a CHALLENGE message is passed in.
  1067. //
  1068. if ( pBuffIn )
  1069. {
  1070. InBuffDesc.ulVersion = 0;
  1071. InBuffDesc.cBuffers = 1;
  1072. InBuffDesc.pBuffers = &InSecBuff;
  1073. InSecBuff.BufferType = SECBUFFER_TOKEN;
  1074. //
  1075. // If this is UUENCODED, decode it first
  1076. //
  1077. if ( g_fUUEncodeData)
  1078. {
  1079. DWORD cbDecodedBuf;
  1080. cbDecodedBuf = cbBuffIn;
  1081. SlowDecodedBuf = (char*) ALLOCATE_FIXED_MEMORY(cbDecodedBuf);
  1082. if( SlowDecodedBuf == NULL )
  1083. {
  1084. RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
  1085. goto Cleanup;
  1086. }
  1087. InSecBuff.cbBuffer = HTUU_decode ((char*)pBuffIn, (UCHAR*)SlowDecodedBuf,
  1088. cbDecodedBuf);
  1089. InSecBuff.pvBuffer = SlowDecodedBuf;
  1090. }
  1091. else
  1092. {
  1093. InSecBuff.cbBuffer = cbBuffIn;
  1094. InSecBuff.pvBuffer = pBuffIn;
  1095. }
  1096. }
  1097. // If scheme is Negotiate, set ISC_REQ_MUTUAL_AUTH and decorate
  1098. // the server name indicated by pszTarget
  1099. if (pszScheme && !(lstrcmpi(pszScheme, "Negotiate")))
  1100. {
  1101. fContextReq |= ISC_REQ_MUTUAL_AUTH;
  1102. cbTarget = (pszTarget ? strlen(pszTarget) : 0);
  1103. if (cbTarget && (cbTarget <= MAX_PATH - sizeof( "HTTP/" )))
  1104. {
  1105. memcpy(szDecoratedTarget, "HTTP/", sizeof( "HTTP/" ) - 1 );
  1106. memcpy(szDecoratedTarget + sizeof( "HTTP/" ) - 1, pszTarget, cbTarget + 1);
  1107. pszTarget = szDecoratedTarget;
  1108. }
  1109. }
  1110. //
  1111. // Call SSPI function generate the NEGOTIATE/RESPONSE message
  1112. //
  1113. SspiRetry:
  1114. //
  1115. // BUGBUG: Same credential handle could be used by multiple threads at the
  1116. // same time.
  1117. //
  1118. SecStat = (*(pData->pFuncTbl->InitializeSecurityContext))(
  1119. pCredential,
  1120. pInContext,
  1121. pszTarget,
  1122. fContextReq,
  1123. 0,
  1124. SECURITY_NATIVE_DREP,
  1125. (pBuffIn) ? &InBuffDesc : NULL,
  1126. 0,
  1127. pOutContext,
  1128. &OutBuffDesc,
  1129. &ContextAttributes,
  1130. &Lifetime );
  1131. *pssResult = SecStat;
  1132. //
  1133. // If SSPI function fails
  1134. //
  1135. if ( !NT_SUCCESS( SecStat ) )
  1136. {
  1137. RetStatus = SPM_ERROR;
  1138. //
  1139. // If SSPI do not have user name/password for the secified package,
  1140. //
  1141. if (SecStat == SEC_E_NO_CREDENTIALS)
  1142. {
  1143. //
  1144. // If we have prompted the user and still get back "No Credential"
  1145. // error, it means the user does not have valid credential; the
  1146. // user hit <CANCEL> on the UI box. If we have supplied a valid
  1147. // credential, but get back a "No Credential" error, then something
  1148. // has gone wrong; we definitely should return to caller with ERROR
  1149. //
  1150. if ((fContextReq & ISC_REQ_PROMPT_FOR_CREDS) ||
  1151. (fContextReq & ISC_REQ_USE_SUPPLIED_CREDS))
  1152. {
  1153. RetStatus = SPM_ERROR; // return ERROR to caller
  1154. }
  1155. else if (bNonBlock)
  1156. {
  1157. //
  1158. // Blocking is not permitted, return WOULD_BLOCK to caller
  1159. //
  1160. RetStatus = SPM_STATUS_WOULD_BLOCK;
  1161. }
  1162. else
  1163. {
  1164. // Blocking is permitted and we have not asked the SSPI to
  1165. // prompt the user for proper credential, we should call
  1166. // the SSPI again with PROMPT_CREDS flag set.
  1167. //
  1168. fContextReq = fContextReq | ISC_REQ_PROMPT_FOR_CREDS;
  1169. goto SspiRetry;
  1170. }
  1171. }
  1172. SetLastError( SecStat );
  1173. goto Cleanup;
  1174. }
  1175. RetStatus = SPM_STATUS_OK;
  1176. //
  1177. // Only return the SSPI blob if a output buffer is specified
  1178. //
  1179. if (pFinalBuff)
  1180. {
  1181. //
  1182. // Initialize the final buffer to hold the package name followed by
  1183. // a space. And setup the pOutMsg pointer to points to the character
  1184. // following the space so that the final NEGOTIATE/RESPONSE can be
  1185. // copied into the pFinalBuff starting at the character pointed to
  1186. // by pOutMsg.
  1187. //
  1188. wsprintf (pFinalBuff, "%s ", pData->PkgList[pkgID]->pName);
  1189. pOutMsg = pFinalBuff + lstrlen(pFinalBuff);
  1190. if ( g_fUUEncodeData)
  1191. {
  1192. maxbufsize = *pcbBuffOut -
  1193. lstrlen(pData->PkgList[pkgID]->pName) - 1;
  1194. //
  1195. // uuencode it, but make sure that it fits in the given buffer
  1196. //
  1197. retsize = HTUU_encode ((BYTE *) OutSecBuff.pvBuffer,
  1198. OutSecBuff.cbBuffer,
  1199. (CHAR *) pOutMsg, maxbufsize);
  1200. if (retsize > 0)
  1201. *pcbBuffOut = retsize + lstrlen(pData->PkgList[pkgID]->pName)+1;
  1202. else
  1203. RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
  1204. }
  1205. else if ( *pcbBuffOut >= lstrlen(pData->PkgList[pkgID]->pName) +
  1206. OutSecBuff.cbBuffer + 1 )
  1207. {
  1208. CopyMemory( (CHAR *) pOutMsg,
  1209. OutSecBuff.pvBuffer,
  1210. OutSecBuff.cbBuffer );
  1211. *pcbBuffOut = lstrlen(pData->PkgList[pkgID]->pName) + 1 +
  1212. OutSecBuff.cbBuffer;
  1213. }
  1214. else
  1215. {
  1216. *pcbBuffOut = lstrlen(pData->PkgList[pkgID]->pName) +
  1217. OutSecBuff.cbBuffer + 1;
  1218. RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
  1219. }
  1220. }
  1221. Cleanup:
  1222. if( SlowOutBufPlain != NULL )
  1223. {
  1224. FREE_MEMORY( SlowOutBufPlain );
  1225. }
  1226. if( SlowDecodedBuf != NULL )
  1227. {
  1228. FREE_MEMORY( SlowDecodedBuf );
  1229. }
  1230. return (RetStatus);
  1231. }