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.

393 lines
13 KiB

  1. /*#----------------------------------------------------------------------------
  2. **
  3. ** File: sspcalls.c
  4. **
  5. ** Synopsis: This module contains SSPI function calls for SSPI SPM DLL.
  6. **
  7. ** Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  8. **
  9. ** Authors: LucyC Created 25 Sept. 1995
  10. **
  11. **---------------------------------------------------------------------------*/
  12. #include "msnspmh.h"
  13. #include <debugmem.h>
  14. #include "urlmon.h"
  15. BOOL g_fUUEncodeData = TRUE;
  16. typedef enum _COMPUTER_NAME_FORMAT {
  17. ComputerNameNetBIOS,
  18. ComputerNameDnsHostname,
  19. ComputerNameDnsDomain,
  20. ComputerNameDnsFullyQualified,
  21. ComputerNamePhysicalNetBIOS,
  22. ComputerNamePhysicalDnsHostname,
  23. ComputerNamePhysicalDnsDomain,
  24. ComputerNamePhysicalDnsFullyQualified,
  25. ComputerNameMax
  26. } COMPUTER_NAME_FORMAT ;
  27. typedef
  28. BOOL
  29. (WINAPI * PFN_GET_COMPUTER_NAME_EX)(
  30. IN COMPUTER_NAME_FORMAT NameType,
  31. OUT LPSTR lpBuffer,
  32. IN OUT LPDWORD nSize
  33. );
  34. PFN_GET_COMPUTER_NAME_EX g_pfnGetComputerNameExA = NULL;
  35. DWORD GetZoneFromUrl(LPSTR pszUrl);
  36. /*-----------------------------------------------------------------------------
  37. **
  38. ** Function: GetSecAuthMsg
  39. **
  40. ** Synopsis: This function generates a SSPI NEGOTIATE or RESPONSE
  41. ** authorization string for the specified SSPI package.
  42. ** The authorization string generated by this function
  43. ** follows the format:
  44. ** "<Package Name> <Package Specific Auth. Data>"
  45. ** If global uuencoding is turned on, this functions will
  46. ** uuencode the message before building it into an
  47. ** authorization string; by default, the uuencoding flag is
  48. ** always on.
  49. ** This functions calls InitializeSecurityContext() to
  50. ** generate the NEGOTIATE/RESPONSE message for the authori-
  51. ** zation string. If the SSPI function returns NO_CREDENTIAL,
  52. ** and if the PROMPT_CREDS flag is not turned on when blocking
  53. ** is permitted, this function will call the SSPI function
  54. ** again with the PROMPT_CREDS flag set; if SSPI returns
  55. ** NO_CREDENTIAL again, this SSPI will return ERROR to the
  56. ** caller.
  57. **
  58. **
  59. ** Arguments:
  60. **
  61. ** pData - pointer to SspData containing the SSPI function table
  62. ** and the SSPI package list.
  63. ** pkgID - the package index of the SSPI package to use.
  64. ** pInContext - pointer to a context handle. If NULL is specified,
  65. ** this function will use a temporary space for the context
  66. ** handle and delete the handle before returning to the
  67. ** caller. If non-NULL address is specified, the context
  68. ** handle created by the SSPI is returned to the caller.
  69. ** And the caller will have to delete the handle when it's
  70. ** done with it.
  71. ** fContextReq - the SSPI request flag to pass to InitializeSecurityContext
  72. ** pBuffIn - pointer to the uudecoded CHALLENGE message if any.
  73. ** For generating NEGOTIATE message, this pointer should be NULL.
  74. ** cbBuffIn - length of the CHALLENGE message. This should be zero when
  75. ** when pBuffIn is NULL.
  76. ** pFinalBuff - pointer to a buffer for the final authorization string.
  77. ** pszTarget - Server Host Name
  78. ** bNonBlock - a flag which is set if blocking is not permitted.
  79. **
  80. ** Return Value:
  81. **
  82. ** SPM_STATUS_OK - if an authorization string is generated successfully
  83. ** SPM_STATUS_WOULD_BLOCK - if generating an authorization string would
  84. ** cause blocking when blocking is not permitted.
  85. ** SPM_ERROR - if any problem/error is encountered in generating an
  86. ** authorization string, including user hitting cancel on
  87. ** the SSPI dialog prompt for name/password.
  88. **
  89. **---------------------------------------------------------------------------*/
  90. DWORD
  91. GetSecAuthMsg (
  92. PSspData pData,
  93. PCredHandle pCredential,
  94. DWORD pkgID, // the package index into package list
  95. PCtxtHandle pInContext,
  96. PCtxtHandle pOutContext,
  97. ULONG fContextReq, // Request Flags
  98. VOID *pBuffIn,
  99. DWORD cbBuffIn,
  100. char *pFinalBuff,
  101. DWORD *pcbBuffOut,
  102. SEC_CHAR *pszTarget, // Server Host Name
  103. UINT bNonBlock,
  104. LPSTR pszScheme,
  105. PCSTR lpszUrl,
  106. SECURITY_STATUS *pssResult
  107. )
  108. {
  109. // char szDecodedBuf[MAX_BLOB_SIZE];
  110. // char *szDecodedBuf;
  111. // char FastDecodedBuf[MAX_BLOB_SIZE];
  112. char *SlowDecodedBuf = NULL;
  113. int retsize;
  114. SECURITY_STATUS SecStat;
  115. TimeStamp Lifetime;
  116. SecBufferDesc OutBuffDesc;
  117. SecBuffer OutSecBuff;
  118. SecBufferDesc InBuffDesc;
  119. SecBuffer InSecBuff;
  120. ULONG ContextAttributes;
  121. // char OutBufPlain[MAX_AUTH_MSG_SIZE];
  122. char *SlowOutBufPlain = NULL;
  123. char *pOutMsg = NULL;
  124. DWORD RetStatus;
  125. long maxbufsize;
  126. CHAR szDecoratedTarget[MAX_PATH + 6];
  127. DWORD cbTarget;
  128. ULONG cbMaxToken;
  129. //
  130. // BUGBUG: Deal with output buffer not being long enough
  131. if (pFinalBuff == NULL) {
  132. return(SPM_ERROR);
  133. }
  134. //
  135. // Prepare our output buffer. We use a temporary buffer because
  136. // the real output buffer will most likely need to be uuencoded
  137. //
  138. OutBuffDesc.ulVersion = 0;
  139. OutBuffDesc.cBuffers = 1;
  140. OutBuffDesc.pBuffers = &OutSecBuff;
  141. OutSecBuff.cbBuffer = MAX_AUTH_MSG_SIZE;
  142. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  143. // Always use the slow alloc'ed buf as a quick fix to appease
  144. // DAV redir stress scenarios, which run in svchost and starts
  145. // with a 4KB stack limit.
  146. cbMaxToken = GetPkgMaxToken( pkgID );
  147. SlowOutBufPlain = (char *) ALLOCATE_FIXED_MEMORY(cbMaxToken);
  148. if( SlowOutBufPlain == NULL )
  149. {
  150. RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
  151. goto Cleanup;
  152. }
  153. OutSecBuff.pvBuffer = SlowOutBufPlain;
  154. OutSecBuff.cbBuffer = cbMaxToken;
  155. //
  156. // Prepare our Input buffer if a CHALLENGE message is passed in.
  157. //
  158. if ( pBuffIn )
  159. {
  160. InBuffDesc.ulVersion = 0;
  161. InBuffDesc.cBuffers = 1;
  162. InBuffDesc.pBuffers = &InSecBuff;
  163. InSecBuff.BufferType = SECBUFFER_TOKEN;
  164. //
  165. // If this is UUENCODED, decode it first
  166. //
  167. if ( g_fUUEncodeData)
  168. {
  169. DWORD cbDecodedBuf;
  170. cbDecodedBuf = cbBuffIn;
  171. SlowDecodedBuf = ALLOCATE_FIXED_MEMORY(cbDecodedBuf);
  172. if( SlowDecodedBuf == NULL )
  173. {
  174. RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
  175. goto Cleanup;
  176. }
  177. InSecBuff.cbBuffer = HTUU_decode (pBuffIn, SlowDecodedBuf,
  178. cbDecodedBuf);
  179. InSecBuff.pvBuffer = SlowDecodedBuf;
  180. }
  181. else
  182. {
  183. InSecBuff.cbBuffer = cbBuffIn;
  184. InSecBuff.pvBuffer = pBuffIn;
  185. }
  186. }
  187. // If scheme is Negotiate, set ISC_REQ_MUTUAL_AUTH and decorate
  188. // the server name indicated by pszTarget by appending a '$' to the
  189. // server name.
  190. if (pszScheme && !(lstrcmpi(pszScheme, "Negotiate")))
  191. {
  192. fContextReq |= ISC_REQ_MUTUAL_AUTH;
  193. cbTarget = (pszTarget ? strlen(pszTarget) : 0);
  194. if (cbTarget && (cbTarget <= MAX_PATH - sizeof( "HTTP/" )))
  195. {
  196. memcpy(szDecoratedTarget, "HTTP/", sizeof( "HTTP/" ) - 1 );
  197. memcpy(szDecoratedTarget + sizeof( "HTTP/" ) - 1, pszTarget, cbTarget + 1);
  198. pszTarget = szDecoratedTarget;
  199. // OutputDebugStringA(pszTarget);
  200. }
  201. }
  202. //
  203. // Call SSPI function generate the NEGOTIATE/RESPONSE message
  204. //
  205. if (fContextReq & ISC_REQ_DELEGATE)
  206. {
  207. // we should only request delegation when calling InitializeSecurityContext if
  208. // the site is in the intranet or trusted sites zone. Otherwise you will be giving
  209. // the user's TGT to any web server that is trusted for delegation.
  210. DWORD dwZone = GetZoneFromUrl((PSTR)lpszUrl);
  211. if ((dwZone != URLZONE_INTRANET) && (dwZone != URLZONE_TRUSTED))
  212. {
  213. fContextReq &= ~ISC_REQ_DELEGATE;
  214. }
  215. }
  216. SspiRetry:
  217. //
  218. // BUGBUG: Same credential handle could be used by multiple threads at the
  219. // same time.
  220. //
  221. SecStat = (*(pData->pFuncTbl->InitializeSecurityContext))(
  222. pCredential,
  223. pInContext,
  224. pszTarget,
  225. fContextReq,
  226. 0,
  227. SECURITY_NATIVE_DREP,
  228. (pBuffIn) ? &InBuffDesc : NULL,
  229. 0,
  230. pOutContext,
  231. &OutBuffDesc,
  232. &ContextAttributes,
  233. &Lifetime );
  234. *pssResult = SecStat;
  235. //
  236. // If SSPI function fails
  237. //
  238. if ( !NT_SUCCESS( SecStat ) )
  239. {
  240. RetStatus = SPM_ERROR;
  241. //
  242. // If SSPI do not have user name/password for the secified package,
  243. //
  244. if ((SecStat == SEC_E_NO_CREDENTIALS) ||
  245. (g_fIsWhistler && (SecStat == SEC_E_LOGON_DENIED)))
  246. {
  247. //
  248. // If we have prompted the user and still get back "No Credential"
  249. // error, it means the user does not have valid credential; the
  250. // user hit <CANCEL> on the UI box. If we have supplied a valid
  251. // credential, but get back a "No Credential" error, then something
  252. // has gone wrong; we definitely should return to caller with ERROR
  253. //
  254. if ((fContextReq & ISC_REQ_PROMPT_FOR_CREDS) ||
  255. (fContextReq & ISC_REQ_USE_SUPPLIED_CREDS))
  256. {
  257. RetStatus = SPM_ERROR; // return ERROR to caller
  258. }
  259. else if (bNonBlock)
  260. {
  261. //
  262. // Blocking is not permitted, return WOULD_BLOCK to caller
  263. //
  264. RetStatus = SPM_STATUS_WOULD_BLOCK;
  265. }
  266. else
  267. {
  268. // Blocking is permitted and we have not asked the SSPI to
  269. // prompt the user for proper credential, we should call
  270. // the SSPI again with PROMPT_CREDS flag set.
  271. //
  272. fContextReq = fContextReq | ISC_REQ_PROMPT_FOR_CREDS;
  273. goto SspiRetry;
  274. }
  275. }
  276. SetLastError( SecStat );
  277. goto Cleanup;
  278. }
  279. RetStatus = SPM_STATUS_OK;
  280. #if 0
  281. //
  282. // note: when support for processing final MUTUAL_AUTH blob is added,
  283. // will need to allow for non-existent output buffer.
  284. //
  285. if( OutSecBuff.cbBuffer == 0 )
  286. {
  287. *pcbBuffOut = 0;
  288. goto Cleanup;
  289. }
  290. #endif
  291. //
  292. // Only return the SSPI blob if a output buffer is specified
  293. //
  294. if (pFinalBuff)
  295. {
  296. //
  297. // Initialize the final buffer to hold the package name followed by
  298. // a space. And setup the pOutMsg pointer to points to the character
  299. // following the space so that the final NEGOTIATE/RESPONSE can be
  300. // copied into the pFinalBuff starting at the character pointed to
  301. // by pOutMsg.
  302. //
  303. wsprintf (pFinalBuff, "%s ", pData->PkgList[pkgID]->pName);
  304. pOutMsg = pFinalBuff + lstrlen(pFinalBuff);
  305. if ( g_fUUEncodeData)
  306. {
  307. maxbufsize = *pcbBuffOut -
  308. lstrlen(pData->PkgList[pkgID]->pName) - 1;
  309. //
  310. // uuencode it, but make sure that it fits in the given buffer
  311. //
  312. retsize = HTUU_encode ((BYTE *) OutSecBuff.pvBuffer,
  313. OutSecBuff.cbBuffer,
  314. (CHAR *) pOutMsg, maxbufsize);
  315. if (retsize > 0)
  316. *pcbBuffOut = retsize + lstrlen(pData->PkgList[pkgID]->pName)+1;
  317. else
  318. RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
  319. }
  320. else if ( *pcbBuffOut >= lstrlen(pData->PkgList[pkgID]->pName) +
  321. OutSecBuff.cbBuffer + 1 )
  322. {
  323. CopyMemory( (CHAR *) pOutMsg,
  324. OutSecBuff.pvBuffer,
  325. OutSecBuff.cbBuffer );
  326. *pcbBuffOut = lstrlen(pData->PkgList[pkgID]->pName) + 1 +
  327. OutSecBuff.cbBuffer;
  328. }
  329. else
  330. {
  331. *pcbBuffOut = lstrlen(pData->PkgList[pkgID]->pName) +
  332. OutSecBuff.cbBuffer + 1;
  333. RetStatus = SPM_STATUS_INSUFFICIENT_BUFFER;
  334. }
  335. }
  336. Cleanup:
  337. if( SlowOutBufPlain != NULL )
  338. {
  339. FREE_MEMORY( SlowOutBufPlain );
  340. }
  341. if( SlowDecodedBuf != NULL )
  342. {
  343. FREE_MEMORY( SlowDecodedBuf );
  344. }
  345. return (RetStatus);
  346. }