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.

305 lines
8.6 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // namemapper.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file defines the class NameMapper.
  12. //
  13. ///////////////////////////////////////////////////////////////////////////////
  14. #include "ias.h"
  15. #include "iaslsa.h"
  16. #include "samutil.h"
  17. #include "namemapper.h"
  18. #include "cracker.h"
  19. #include "identityhelper.h"
  20. #include "iastlutl.h"
  21. #include "ntdsapip.h"
  22. NameCracker NameMapper::cracker;
  23. IdentityHelper NameMapper::identityHelper;
  24. STDMETHODIMP NameMapper::Initialize() const throw()
  25. {
  26. DWORD error = IASLsaInitialize();
  27. if (error) { return HRESULT_FROM_WIN32(error); }
  28. return identityHelper.initialize();
  29. }
  30. STDMETHODIMP NameMapper::Shutdown() const throw()
  31. {
  32. IASLsaUninitialize();
  33. return S_OK;
  34. }
  35. IASREQUESTSTATUS NameMapper::onSyncRequest(IRequest* pRequest) throw ()
  36. {
  37. // This is function scope, so it can be freed in the catch block.
  38. PDS_NAME_RESULTW result = NULL;
  39. wchar_t identity[254];
  40. wchar_t* pIdentity = identity;
  41. HRESULT hr = S_OK;
  42. try
  43. {
  44. size_t identitySize = sizeof(identity);
  45. IASRequest request(pRequest);
  46. bool identityRetrieved = identityHelper.getIdentity(request,
  47. pIdentity,
  48. identitySize);
  49. if (!identityRetrieved)
  50. {
  51. // allocate a big enough buffer and use it
  52. pIdentity = new wchar_t[identitySize];
  53. identityRetrieved = identityHelper.getIdentity(request,
  54. pIdentity,
  55. identitySize);
  56. if (!identityRetrieved)
  57. {
  58. IASTraceString("Error: no user identity found");
  59. _com_issue_error(IAS_PROXY_MALFORMED_RESPONSE);
  60. }
  61. }
  62. // Allocate an attribute to hold the NT4 Account Name.
  63. IASAttribute nt4Name(true);
  64. nt4Name->dwId = IAS_ATTRIBUTE_NT4_ACCOUNT_NAME;
  65. DS_NAME_FORMAT formatOffered = DS_UNKNOWN_NAME;
  66. // If it already contains a backslash
  67. // then use as is.
  68. PWCHAR delim = wcschr(identity, L'\\');
  69. if (delim)
  70. {
  71. if (IASGetRole() == IAS_ROLE_STANDALONE ||
  72. IASGetProductType() == IAS_PRODUCT_WORKSTATION)
  73. {
  74. // Strip out the domain.
  75. *delim = L'\0';
  76. // Make sure this is a local user.
  77. if (!IASIsDomainLocal(identity))
  78. {
  79. IASTraceString("Non-local users are not allowed -- rejecting.");
  80. _com_issue_error(IAS_LOCAL_USERS_ONLY);
  81. }
  82. // Restore the delimiter.
  83. *delim = L'\\';
  84. }
  85. IASTraceString("Username is already an NT4 account name.");
  86. nt4Name.setString(identity);
  87. }
  88. else if (isCrackable(identity, formatOffered) &&
  89. (IASGetRole() != IAS_ROLE_STANDALONE))
  90. {
  91. // identity seems to be crackable and IAS is not a standalone machine.
  92. // (either a domain member or a domain controller)
  93. mapName(identity, nt4Name, formatOffered, 0);
  94. }
  95. else
  96. {
  97. // Assume no domain was specified and use the default domain
  98. IASTraceString("Prepending default domain.");
  99. nt4Name->Value.String.pszWide = prependDefaultDomain(identity);
  100. nt4Name->Value.String.pszAnsi = NULL;
  101. nt4Name->Value.itType = IASTYPE_STRING;
  102. }
  103. // Convert the domain name to uppercase.
  104. delim = wcschr(nt4Name->Value.String.pszWide, L'\\');
  105. *delim = L'\0';
  106. _wcsupr(nt4Name->Value.String.pszWide);
  107. *delim = L'\\';
  108. nt4Name.store(request);
  109. // For now, we'll use this as the FQDN as well.
  110. IASStoreFQUserName(
  111. request,
  112. DS_NT4_ACCOUNT_NAME,
  113. nt4Name->Value.String.pszWide
  114. );
  115. IASTracePrintf("SAM-Account-Name is \"%S\".",
  116. nt4Name->Value.String.pszWide);
  117. }
  118. catch (const _com_error& ce)
  119. {
  120. IASTraceExcept();
  121. hr = ce.Error();
  122. }
  123. if (pIdentity != identity)
  124. {
  125. delete[] pIdentity;
  126. }
  127. if (result)
  128. {
  129. cracker.freeNameResult(result);
  130. }
  131. if ( FAILED(hr) || ((hr != S_OK) && (hr < 0x0000ffff)) )
  132. {
  133. // IAS reason code: the reason code will be used
  134. // or error code: will map to internal error
  135. return IASProcessFailure(pRequest, hr);
  136. }
  137. else
  138. {
  139. // S_OK
  140. return IAS_REQUEST_STATUS_HANDLED;
  141. }
  142. }
  143. PWSTR NameMapper::prependDefaultDomain(PCWSTR username)
  144. {
  145. IASTraceString("NameMapper::prependDefaultDomain");
  146. _ASSERT(username != NULL);
  147. // Figure out how long everything is.
  148. PCWSTR domain = IASGetDefaultDomain();
  149. ULONG domainLen = wcslen(domain);
  150. ULONG usernameLen = wcslen(username) + 1;
  151. // Allocate the needed memory.
  152. ULONG needed = domainLen + usernameLen + 1;
  153. PWSTR retval = (PWSTR)CoTaskMemAlloc(needed * sizeof(WCHAR));
  154. if (!retval) { _com_issue_error(E_OUTOFMEMORY); }
  155. // Set up the cursor used for packing the strings.
  156. PWSTR dst = retval;
  157. // Copy in the domain name.
  158. memcpy(dst, domain, domainLen * sizeof(WCHAR));
  159. dst += domainLen;
  160. // Add the delimiter.
  161. *dst++ = L'\\';
  162. // Copy in the username.
  163. // Note: usernameLen includes the null-terminator.
  164. memcpy(dst, username, usernameLen * sizeof(WCHAR));
  165. return retval;
  166. }
  167. //////////
  168. // Determines whether an identity can be cracked through DsCrackNames and which
  169. // name format should be offered if it is crackable.
  170. //////////
  171. bool NameMapper::isCrackable(
  172. const wchar_t* szIdentity,
  173. DS_NAME_FORMAT& format
  174. ) const throw ()
  175. {
  176. format = DS_UNKNOWN_NAME;
  177. if (wcschr(szIdentity, L'@') != 0)
  178. {
  179. if (allowAltSecId)
  180. {
  181. format = static_cast<DS_NAME_FORMAT>(
  182. DS_USER_PRINCIPAL_NAME_AND_ALTSECID
  183. );
  184. }
  185. return true;
  186. }
  187. return (wcschr(szIdentity, L'=') != 0) || // DS_FQDN_1779_NAME
  188. (wcschr(szIdentity, L'/') != 0); // DS_CANONICAL_NAME
  189. }
  190. void NameMapper::mapName(
  191. const wchar_t* identity,
  192. IASAttribute& nt4Name,
  193. DS_NAME_FORMAT formatOffered,
  194. const wchar_t* suffix
  195. )
  196. {
  197. _ASSERT(identity != NULL);
  198. _ASSERT(nt4Name != NULL);
  199. _ASSERT(*nt4Name != NULL);
  200. PDS_NAME_RESULTW result = NULL;
  201. HRESULT hr = S_OK;
  202. do
  203. {
  204. // call cracker
  205. DWORD dwErr = cracker.crackNames(
  206. DS_NAME_FLAG_EVAL_AT_DC,
  207. formatOffered,
  208. DS_NT4_ACCOUNT_NAME,
  209. identity,
  210. suffix,
  211. &result
  212. );
  213. if (dwErr != NO_ERROR)
  214. {
  215. IASTraceFailure("DsCrackNames", dwErr);
  216. hr = IAS_GLOBAL_CATALOG_UNAVAILABLE;
  217. break;
  218. }
  219. if (result->rItems->status == DS_NAME_NO_ERROR)
  220. {
  221. IASTraceString("Successfully cracked username.");
  222. // DsCrackNames returned an NT4 Account Name, so use it.
  223. nt4Name.setString(result->rItems->pName);
  224. }
  225. else
  226. {
  227. // GC could not crack the name
  228. if (formatOffered != DS_SID_OR_SID_HISTORY_NAME)
  229. {
  230. // Not using SID: try to append the default domain to the identity
  231. IASTraceString("Global Catalog could not crack username; "
  232. "prepending default domain.");
  233. // If it can't be cracked we'll assume that it's a flat
  234. // username with some weird characters.
  235. nt4Name->Value.String.pszWide = prependDefaultDomain(identity);
  236. nt4Name->Value.String.pszAnsi = NULL;
  237. nt4Name->Value.itType = IASTYPE_STRING;
  238. }
  239. else
  240. {
  241. // using SID. nothing else can be done.
  242. IASTracePrintf("Global Catalog could not crack username. Error %x",
  243. result->rItems->status);
  244. hr = IAS_NO_SUCH_USER;
  245. }
  246. }
  247. }
  248. while(false);
  249. cracker.freeNameResult(result);
  250. if ( FAILED(hr) || ((hr != S_OK) && (hr < 0x0000ffff)))
  251. {
  252. _com_issue_error(hr);
  253. }
  254. }