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.

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