Source code of Windows XP (NT5)
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.

272 lines
5.7 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // Cracker.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file defines the class NameCracker.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 04/13/1998 Original version.
  16. // 08/10/1998 Remove NT4 support.
  17. // 08/21/1998 Removed initialization/shutdown routines.
  18. //
  19. ///////////////////////////////////////////////////////////////////////////////
  20. #include <ias.h>
  21. #include <cracker.h>
  22. #include <new>
  23. ///////////////////////////////////////////////////////////////////////////////
  24. //
  25. // FUNCTION
  26. //
  27. // DsCrackNameAutoChaseW
  28. //
  29. // DESCRIPTION
  30. //
  31. // Extension to DsCrackNames that automatically chases cross-forest
  32. // referrals using default credentials.
  33. //
  34. ///////////////////////////////////////////////////////////////////////////////
  35. DWORD
  36. WINAPI
  37. DsCrackNameAutoChaseW(
  38. HANDLE hDS,
  39. DS_NAME_FLAGS flags,
  40. DS_NAME_FORMAT formatOffered,
  41. DS_NAME_FORMAT formatDesired,
  42. PCWSTR name,
  43. PDS_NAME_RESULTW* ppResult,
  44. BOOL* pChased
  45. )
  46. {
  47. DWORD error;
  48. if (pChased == NULL)
  49. {
  50. return ERROR_INVALID_PARAMETER;
  51. }
  52. *pChased = FALSE;
  53. flags = (DS_NAME_FLAGS)(flags | DS_NAME_FLAG_TRUST_REFERRAL);
  54. error = DsCrackNamesW(
  55. hDS,
  56. flags,
  57. formatOffered,
  58. formatDesired,
  59. 1,
  60. &name,
  61. ppResult
  62. );
  63. while ((error == NO_ERROR) &&
  64. ((*ppResult)->rItems->status == DS_NAME_ERROR_TRUST_REFERRAL))
  65. {
  66. *pChased = TRUE;
  67. HANDLE hDsForeign;
  68. error = DsBindW(NULL, (*ppResult)->rItems->pDomain, &hDsForeign);
  69. DsFreeNameResultW(*ppResult);
  70. *ppResult = NULL;
  71. if (error == NO_ERROR)
  72. {
  73. error = DsCrackNamesW(
  74. hDsForeign,
  75. flags,
  76. formatOffered,
  77. formatDesired,
  78. 1,
  79. &name,
  80. ppResult
  81. );
  82. DsUnBindW(&hDsForeign);
  83. }
  84. }
  85. return error;
  86. }
  87. ///////////////////////////////////////////////////////////////////////////////
  88. //
  89. // CLASS
  90. //
  91. // DsHandle
  92. //
  93. // DESCRIPTION
  94. //
  95. // This class represents a reference counted NTDS handle.
  96. //
  97. ///////////////////////////////////////////////////////////////////////////////
  98. class DsHandle
  99. : public NonCopyable
  100. {
  101. public:
  102. HANDLE get() const throw ()
  103. { return subject; }
  104. operator HANDLE() const throw ()
  105. { return subject; }
  106. protected:
  107. friend class NameCracker;
  108. // Constructor and destructor are protected since only NameCracker is
  109. // allowed to open new handles.
  110. DsHandle(HANDLE h) throw ()
  111. : refCount(1), subject(h)
  112. { }
  113. ~DsHandle() throw ()
  114. {
  115. if (subject) { DsUnBindW(&subject); }
  116. }
  117. void AddRef() throw ()
  118. {
  119. InterlockedIncrement(&refCount);
  120. }
  121. void Release() throw ()
  122. {
  123. if (!InterlockedDecrement(&refCount)) { delete this; }
  124. }
  125. LONG refCount; // reference count.
  126. HANDLE subject; // HANDLE being ref counted.
  127. };
  128. NameCracker::NameCracker() throw ()
  129. : gc(NULL)
  130. { }
  131. NameCracker::~NameCracker() throw ()
  132. {
  133. if (gc) { gc->Release(); }
  134. }
  135. DWORD NameCracker::crackNames(
  136. DS_NAME_FLAGS flags,
  137. DS_NAME_FORMAT formatOffered,
  138. DS_NAME_FORMAT formatDesired,
  139. PCWSTR name,
  140. PDS_NAME_RESULTW *ppResult
  141. ) throw ()
  142. {
  143. DWORD errorCode;
  144. // Get a handle to the GC.
  145. DsHandle* hDS1;
  146. errorCode = getGC(&hDS1);
  147. if (errorCode == NO_ERROR)
  148. {
  149. // Try to crack the names.
  150. BOOL chased;
  151. errorCode = DsCrackNameAutoChaseW(
  152. *hDS1,
  153. flags,
  154. formatOffered,
  155. formatDesired,
  156. name,
  157. ppResult,
  158. &chased
  159. );
  160. if (errorCode != NO_ERROR && !chased)
  161. {
  162. // We failed, so disable the current handle ...
  163. disable(hDS1);
  164. // ... and try to get a new one.
  165. DsHandle* hDS2;
  166. errorCode = getGC(&hDS2);
  167. if (errorCode == NO_ERROR)
  168. {
  169. // Give it one more try with the new handle.
  170. errorCode = DsCrackNameAutoChaseW(
  171. *hDS2,
  172. flags,
  173. formatOffered,
  174. formatDesired,
  175. name,
  176. ppResult,
  177. &chased
  178. );
  179. if (errorCode != NO_ERROR && !chased)
  180. {
  181. // No luck so disable the handle.
  182. disable(hDS2);
  183. }
  184. hDS2->Release();
  185. }
  186. }
  187. hDS1->Release();
  188. }
  189. return errorCode;
  190. }
  191. void NameCracker::disable(DsHandle* h) throw ()
  192. {
  193. _serialize
  194. // If it doesn't match our cached handle, then someone else
  195. // has already disabled it.
  196. if (h == gc && gc != NULL)
  197. {
  198. gc->Release();
  199. gc = NULL;
  200. }
  201. }
  202. DWORD NameCracker::getGC(DsHandle** h) throw ()
  203. {
  204. _ASSERT(h != NULL);
  205. *h = NULL;
  206. _serialize
  207. // Do we already have a cached handle?
  208. if (!gc)
  209. {
  210. // Bind to a GC.
  211. HANDLE hGC;
  212. DWORD err = DsBindWithCredA(NULL, NULL, NULL, &hGC);
  213. if (err != NO_ERROR)
  214. {
  215. return err;
  216. }
  217. // Allocate a new DsHandle object to wrap the NTDS handle.
  218. gc = new (std::nothrow) DsHandle(hGC);
  219. if (!gc)
  220. {
  221. DsUnBindW(&hGC);
  222. return ERROR_NOT_ENOUGH_MEMORY;
  223. }
  224. }
  225. // AddRef the handle and return to caller.
  226. (*h = gc)->AddRef();
  227. return NO_ERROR;
  228. }