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.

356 lines
7.9 KiB

  1. //--------------------------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation, 1996
  4. //
  5. // Description:
  6. //
  7. // Microsoft LDAP SSPI Support
  8. //
  9. // Authors:
  10. //
  11. // davidsan 05/08/96 hacked to pieces and started over
  12. //
  13. //--------------------------------------------------------------------------------------------
  14. #include "ldappch.h"
  15. #include "ldapsspi.h"
  16. #include "lclilist.h"
  17. #include "lclixd.h"
  18. HRESULT g_hrInitSSPI;
  19. HINSTANCE g_hinstSecDll = NULL;
  20. PSecurityFunctionTable g_ptblpfnSec;
  21. //$ TODO: Possibly return more descriptive errors so clients know why SSPI
  22. //$ isn't working
  23. HRESULT
  24. HrInitializeSSPI()
  25. {
  26. char *szDll;
  27. OSVERSIONINFO ovi;
  28. INIT_SECURITY_INTERFACE pfnISI = NULL;
  29. if (g_ptblpfnSec)
  30. return NOERROR;
  31. Assert(!g_hinstSecDll);
  32. ovi.dwOSVersionInfoSize = sizeof(ovi);
  33. if (!GetVersionEx(&ovi))
  34. return E_FAIL;
  35. if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
  36. szDll = "security.dll";
  37. else if (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  38. szDll = "secur32.dll";
  39. else
  40. return E_FAIL;
  41. g_hinstSecDll = LoadLibrary(szDll);
  42. pfnISI = (INIT_SECURITY_INTERFACE)GetProcAddress(g_hinstSecDll, SECURITY_ENTRYPOINT);
  43. if (!pfnISI)
  44. {
  45. LBail:
  46. FreeLibrary(g_hinstSecDll);
  47. g_hinstSecDll = NULL;
  48. return LDAP_E_AUTHNOTAVAIL;
  49. }
  50. g_ptblpfnSec = (*pfnISI)();
  51. if (!g_ptblpfnSec)
  52. goto LBail;
  53. return NOERROR;
  54. }
  55. HRESULT
  56. HrTerminateSSPI()
  57. {
  58. g_ptblpfnSec = NULL;
  59. if (g_hinstSecDll)
  60. FreeLibrary(g_hinstSecDll);
  61. g_hinstSecDll = NULL;
  62. return NOERROR;
  63. }
  64. HRESULT
  65. CLdapClient::HrGetCredentials(char *szUser, char *szPass)
  66. {
  67. HRESULT hr;
  68. SECURITY_STATUS stat;
  69. TimeStamp tsLifetime;
  70. SEC_WINNT_AUTH_IDENTITY authdata;
  71. if (FAILED(g_hrInitSSPI))
  72. return g_hrInitSSPI;
  73. Assert(g_ptblpfnSec);
  74. if (!g_ptblpfnSec)
  75. return LDAP_E_AUTHNOTAVAIL;
  76. ::EnterCriticalSection(&m_cs);
  77. if (m_fHasCred)
  78. {
  79. ::LeaveCriticalSection(&m_cs);
  80. return NOERROR;
  81. }
  82. if (szUser && szPass)
  83. {
  84. authdata.User = (BYTE *)szUser;
  85. authdata.UserLength = lstrlen(szUser);
  86. authdata.Password = (BYTE *)szPass;
  87. authdata.PasswordLength = lstrlen(szPass);
  88. authdata.Domain = (BYTE *)"";
  89. authdata.DomainLength = 0;
  90. authdata.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  91. }
  92. stat =
  93. (*g_ptblpfnSec->AcquireCredentialsHandle)
  94. (NULL,
  95. "MSN", //$ does this ever change?
  96. SECPKG_CRED_OUTBOUND,
  97. NULL,
  98. ((szUser && szPass) ? &authdata : NULL),
  99. NULL,
  100. NULL,
  101. &m_hCred,
  102. &tsLifetime);
  103. if (stat == SEC_E_OK)
  104. {
  105. m_fHasCred = TRUE;
  106. hr = NOERROR;
  107. }
  108. else
  109. hr = LDAP_E_AUTHNOTAVAIL;
  110. ::LeaveCriticalSection(&m_cs);
  111. return hr;
  112. }
  113. STDMETHODIMP
  114. CLdapClient::HrSendSSPINegotiate(char *szDN, char *szUser, char *szPass, BOOL fPrompt, PXID pxid)
  115. {
  116. HRESULT hr;
  117. SECURITY_STATUS stat;
  118. DWORD fContextAttrib;
  119. TimeStamp tsExpireTime;
  120. SecBufferDesc outSecDesc;
  121. SecBuffer outSecBuffer;
  122. DWORD grfReq = ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
  123. PXD pxd;
  124. BYTE rgb[512];
  125. pxd = g_xl.PxdNewXaction(xtypeBindSSPINegotiate);
  126. if (!pxd)
  127. return E_OUTOFMEMORY;
  128. if (FAILED(hr = this->HrGetCredentials(szUser, szPass)))
  129. return hr;
  130. outSecDesc.ulVersion = 0;
  131. outSecDesc.cBuffers = 1;
  132. outSecDesc.pBuffers = &outSecBuffer;
  133. outSecBuffer.cbBuffer = sizeof(rgb);
  134. outSecBuffer.BufferType = SECBUFFER_TOKEN;
  135. outSecBuffer.pvBuffer = rgb;
  136. if (szUser && szPass)
  137. grfReq |= ISC_REQ_USE_SUPPLIED_CREDS;
  138. else
  139. grfReq |= ISC_REQ_PROMPT_FOR_CREDS;
  140. stat =
  141. (*g_ptblpfnSec->InitializeSecurityContext)
  142. (&m_hCred,
  143. NULL, // phCurrContext
  144. NULL, // pszTargetName
  145. grfReq,
  146. 0L,
  147. SECURITY_NATIVE_DREP,
  148. NULL,
  149. 0L,
  150. &m_hCtxt,
  151. &outSecDesc,
  152. &fContextAttrib,
  153. &tsExpireTime);
  154. if (FAILED(stat))
  155. {
  156. //$ TODO: determine what errors InitializeSecurityContext can return and
  157. //$ return appropriate errors to client
  158. return E_FAIL;
  159. }
  160. m_fHasCtxt = TRUE;
  161. hr = HrSendBindMsg(
  162. pxd->Xid(),
  163. szDN,
  164. BIND_SSPI_NEGOTIATE,
  165. outSecBuffer.pvBuffer,
  166. outSecBuffer.cbBuffer
  167. );
  168. if (SUCCEEDED(hr))
  169. *pxid = pxd->Xid();
  170. return hr;
  171. }
  172. STDMETHODIMP
  173. CLdapClient::HrGetSSPIChallenge(XID xid, BYTE *pbBuf, int cbBuf, int *pcbChallenge, DWORD timeout)
  174. {
  175. PXD pxd;
  176. BOOL fDel;
  177. HRESULT hr = NOERROR;
  178. BYTE *pbData;
  179. int cbData;
  180. LBER lber;
  181. ULONG ulTag;
  182. LONG lResult;
  183. pxd = g_xl.PxdForXid(xid);
  184. if (!pxd)
  185. return LDAP_E_INVALIDXID;
  186. if (pxd->Xtype() != xtypeBindSSPINegotiate)
  187. return LDAP_E_INVALIDXTYPE;
  188. if (pxd->FCancelled())
  189. return LDAP_E_CANCELLED;
  190. if (pxd->FOOM())
  191. return E_OUTOFMEMORY;
  192. if (pxd->FHasData())
  193. fDel = TRUE;
  194. else
  195. {
  196. if (FAILED(hr = this->HrWaitForPxd(pxd, timeout, &fDel)))
  197. goto LBail;
  198. }
  199. if (!pxd->FGetBuffer(&pbData, &cbData))
  200. {
  201. //$ what's the right error here?
  202. hr = LDAP_E_UNEXPECTEDDATA;
  203. goto LBail;
  204. }
  205. VERIFY(lber.HrLoadBer(pbData, cbData));
  206. VERIFY(lber.HrStartReadSequence(LDAP_BIND_RES | BER_FORM_CONSTRUCTED | BER_CLASS_APPLICATION));
  207. VERIFY(lber.HrPeekTag(&ulTag));
  208. if (ulTag == BER_SEQUENCE)
  209. {
  210. Assert(FALSE); // i want to see if any server returns explicit sequences
  211. VERIFY(lber.HrStartReadSequence());
  212. }
  213. VERIFY(lber.HrGetEnumValue(&lResult));
  214. if (!lResult)
  215. {
  216. // we have 0 for success--the matchedDN field is the server's challenge.
  217. VERIFY(lber.HrGetStringLength(pcbChallenge));
  218. if (*pcbChallenge > cbBuf)
  219. {
  220. hr = LDAP_E_BUFFERTOOSMALL;
  221. goto LBail;
  222. }
  223. VERIFY(lber.HrGetBinaryValue(pbBuf, cbBuf));
  224. }
  225. if (ulTag == BER_SEQUENCE)
  226. {
  227. VERIFY(lber.HrEndReadSequence());
  228. }
  229. VERIFY(lber.HrEndReadSequence());
  230. hr = this->HrFromLdapResult(lResult);
  231. LBail:
  232. if (fDel)
  233. g_xl.RemovePxd(pxd);
  234. return hr;
  235. }
  236. STDMETHODIMP
  237. CLdapClient::HrSendSSPIResponse(BYTE *pbChallenge, int cbChallenge, PXID pxid)
  238. {
  239. HRESULT hr;
  240. SECURITY_STATUS stat;
  241. DWORD fContextAttrib;
  242. TimeStamp tsExpireTime;
  243. SecBufferDesc inSecDesc, outSecDesc;
  244. SecBuffer inSecBuffer, outSecBuffer;
  245. DWORD grfReq = ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
  246. PXD pxd;
  247. BYTE rgb[512];
  248. if (!m_fHasCtxt || !m_fHasCred)
  249. return LDAP_E_OUTOFSEQUENCE;
  250. pxd = g_xl.PxdNewXaction(xtypeBind);
  251. if (!pxd)
  252. return E_OUTOFMEMORY;
  253. inSecDesc.ulVersion = 0;
  254. inSecDesc.cBuffers = 1;
  255. inSecDesc.pBuffers = &inSecBuffer;
  256. inSecBuffer.cbBuffer = cbChallenge;
  257. inSecBuffer.BufferType = SECBUFFER_TOKEN;
  258. inSecBuffer.pvBuffer = (PVOID)pbChallenge;
  259. outSecDesc.ulVersion = 0;
  260. outSecDesc.cBuffers = 1;
  261. outSecDesc.pBuffers = &outSecBuffer;
  262. outSecBuffer.cbBuffer = sizeof(rgb);
  263. outSecBuffer.BufferType = SECBUFFER_TOKEN;
  264. outSecBuffer.pvBuffer = rgb;
  265. stat =
  266. (*g_ptblpfnSec->InitializeSecurityContext)
  267. (&m_hCred,
  268. &m_hCtxt,
  269. NULL, // pszTargetName
  270. ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY,
  271. 0L,
  272. SECURITY_NATIVE_DREP,
  273. &inSecDesc,
  274. 0L,
  275. &m_hCtxt,
  276. &outSecDesc,
  277. &fContextAttrib,
  278. &tsExpireTime);
  279. if (FAILED(stat))
  280. {
  281. //$ TODO: determine what errors InitializeSecurityContext can return and
  282. //$ return appropriate errors to client
  283. return E_FAIL;
  284. }
  285. m_fHasCtxt = TRUE;
  286. hr = HrSendBindMsg(
  287. pxd->Xid(),
  288. "",
  289. BIND_SSPI_RESPONSE,
  290. outSecBuffer.pvBuffer,
  291. outSecBuffer.cbBuffer
  292. );
  293. if (SUCCEEDED(hr))
  294. *pxid = pxd->Xid();
  295. return hr;
  296. }
  297. STDMETHODIMP
  298. CLdapClient::HrBindSSPI(char *szDN, char *szUser, char *szPass, BOOL fPrompt, DWORD timeout)
  299. {
  300. XID xid;
  301. HRESULT hr;
  302. BYTE rgb[512];
  303. int cbChallenge;
  304. if (FAILED(hr = this->HrSendSSPINegotiate(szDN, szUser, szPass, fPrompt, &xid)))
  305. return hr;
  306. if (FAILED(hr = this->HrGetSSPIChallenge(xid, rgb, sizeof(rgb), &cbChallenge, timeout)))
  307. return hr;
  308. if (FAILED(hr = this->HrSendSSPIResponse(rgb, cbChallenge, &xid)))
  309. return hr;
  310. return this->HrGetBindResponse(xid, timeout);
  311. }