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.

397 lines
11 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // IdentityHelper.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file defines the class IdentityHelper.
  12. //
  13. ///////////////////////////////////////////////////////////////////////////////
  14. #include "ias.h"
  15. #include "iaslsa.h"
  16. #include "memory"
  17. #include "samutil.h"
  18. #include "identityhelper.h"
  19. #define STRSAFE_NO_DEPRECATE
  20. #include <strsafe.h>
  21. bool IdentityHelper::initialized = false;
  22. /////////
  23. // Registry keys and values.
  24. /////////
  25. const WCHAR PARAMETERS_KEY[] =
  26. L"SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Policy";
  27. const WCHAR IDENTITY_ATTR_VALUE[] = L"User Identity Attribute";
  28. const WCHAR DEFAULT_IDENTITY_VALUE[] = L"Default User Identity";
  29. const WCHAR OVERRIDE_USERNAME_VALUE[] = L"Override User-Name";
  30. HRESULT IdentityHelper::IASReadRegistryDword(
  31. HKEY& hKey,
  32. PCWSTR valueName,
  33. DWORD defaultValue,
  34. DWORD* result
  35. )
  36. {
  37. _ASSERT (result != 0);
  38. DWORD cbData = sizeof(DWORD);
  39. DWORD type;
  40. LONG status = RegQueryValueExW(
  41. hKey,
  42. valueName,
  43. NULL,
  44. &type,
  45. (LPBYTE)result,
  46. &cbData
  47. );
  48. if (status != ERROR_SUCCESS)
  49. {
  50. if (status != ERROR_FILE_NOT_FOUND)
  51. {
  52. IASTracePrintf("Cannot read value %S. error %ld",
  53. valueName,
  54. status
  55. );
  56. return HRESULT_FROM_WIN32(status);
  57. }
  58. else
  59. {
  60. // The attribute does not exist. Set the default
  61. IASTracePrintf("The registry value %S does not exist. Using default %ld",
  62. valueName,
  63. defaultValue
  64. );
  65. *result = defaultValue;
  66. return S_OK;
  67. }
  68. }
  69. if (type != REG_DWORD || cbData != sizeof(DWORD))
  70. {
  71. IASTracePrintf("Cannot read value %S. Wrong type %ld. Size = %ld",
  72. valueName,
  73. type,
  74. cbData
  75. );
  76. return E_INVALIDARG;
  77. }
  78. return S_OK;
  79. }
  80. //
  81. // IdentityHelper::initialize
  82. // CAUTION: calls to this API MUST be serialized.
  83. // i.e. the handler's calling MapNAme::Initialize MUST complete a successful
  84. // init of each handler's before calling the Init of the next one.
  85. //
  86. HRESULT IdentityHelper::initialize() throw()
  87. {
  88. if (initialized)
  89. {
  90. return S_OK;
  91. }
  92. // Open the Parameters registry key.
  93. HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
  94. LONG status = RegOpenKeyExW(
  95. HKEY_LOCAL_MACHINE,
  96. PARAMETERS_KEY,
  97. 0,
  98. KEY_READ,
  99. &hKey
  100. );
  101. if (status != ERROR_SUCCESS)
  102. {
  103. IASTracePrintf("Cannot open the reg key %S, error %ld",
  104. PARAMETERS_KEY,
  105. status
  106. );
  107. return HRESULT_FROM_WIN32(status);
  108. }
  109. HRESULT hr = S_OK;
  110. do
  111. {
  112. // Query the Identity Attribute.
  113. hr = IASReadRegistryDword(
  114. hKey,
  115. IDENTITY_ATTR_VALUE,
  116. RADIUS_ATTRIBUTE_USER_NAME,
  117. &identityAttr
  118. );
  119. if (FAILED(hr))
  120. {
  121. break;
  122. }
  123. // Query the Override User-Name flag.
  124. hr = IASReadRegistryDword(
  125. hKey,
  126. OVERRIDE_USERNAME_VALUE,
  127. FALSE,
  128. &overrideUsername
  129. );
  130. if (FAILED(hr))
  131. {
  132. break;
  133. }
  134. DWORD type;
  135. // Query the length of the Default Identity.
  136. defaultLength = 0;
  137. status = RegQueryValueExW(
  138. hKey,
  139. DEFAULT_IDENTITY_VALUE,
  140. NULL,
  141. &type,
  142. NULL,
  143. &defaultLength
  144. );
  145. if (status != ERROR_SUCCESS)
  146. {
  147. if (status != ERROR_FILE_NOT_FOUND)
  148. {
  149. IASTracePrintf("Cannot read value %S. error %ld",
  150. DEFAULT_IDENTITY_VALUE,
  151. status
  152. );
  153. hr = HRESULT_FROM_WIN32(status);
  154. break;
  155. }
  156. else
  157. {
  158. // Done.
  159. defaultIdentity = NULL;
  160. defaultLength = 0;
  161. break;
  162. }
  163. }
  164. if (type != REG_SZ)
  165. {
  166. IASTracePrintf("Cannot read value %S. Wrong type %ld",
  167. DEFAULT_IDENTITY_VALUE,
  168. type
  169. );
  170. hr = E_INVALIDARG;
  171. break;
  172. }
  173. if (defaultLength < sizeof(WCHAR))
  174. {
  175. IASTracePrintf("Cannot read value %S. Wrong Size = %ld",
  176. DEFAULT_IDENTITY_VALUE,
  177. defaultLength
  178. );
  179. hr = E_INVALIDARG;
  180. break;
  181. }
  182. // Allocate memory to hold the Default Identity.
  183. defaultIdentity = new (std::nothrow)
  184. WCHAR[defaultLength / sizeof(WCHAR)];
  185. if (defaultIdentity == 0)
  186. {
  187. IASTraceString("Default Identity could not be retrieved due to"
  188. "out of memory condition.");
  189. defaultLength = 0;
  190. hr = E_OUTOFMEMORY;
  191. break;
  192. }
  193. // Query the value of the Default Identity.
  194. status = RegQueryValueExW(
  195. hKey,
  196. DEFAULT_IDENTITY_VALUE,
  197. NULL,
  198. &type,
  199. (LPBYTE)defaultIdentity,
  200. &defaultLength
  201. );
  202. if (status != ERROR_SUCCESS)
  203. {
  204. delete[] defaultIdentity;
  205. defaultIdentity = NULL;
  206. defaultLength = 0;
  207. hr = HRESULT_FROM_WIN32(status);
  208. IASTracePrintf("Failed to read the value %S. Error is %ld",
  209. DEFAULT_IDENTITY_VALUE,
  210. status);
  211. break;
  212. }
  213. }
  214. while(false);
  215. if (hKey != INVALID_HANDLE_VALUE)
  216. {
  217. RegCloseKey(hKey);
  218. }
  219. if (SUCCEEDED(hr))
  220. {
  221. IASTracePrintf("User identity attribute: %lu", identityAttr);
  222. IASTracePrintf("Override User-Name: %s",
  223. overrideUsername ? "TRUE" : "FALSE");
  224. IASTracePrintf("Default user identity: %S",
  225. (defaultIdentity ? defaultIdentity : L"<Guest>"));
  226. // Initialized completed
  227. initialized = true;
  228. }
  229. return hr;
  230. }
  231. IdentityHelper::IdentityHelper() throw()
  232. : identityAttr(1), defaultIdentity(NULL), defaultLength(0)
  233. {
  234. }
  235. IdentityHelper::~IdentityHelper() throw()
  236. {
  237. delete[] defaultIdentity;
  238. }
  239. bool IdentityHelper::getIdentity(IASRequest& request,
  240. wchar_t* pIdentity,
  241. size_t& identitySize)
  242. {
  243. wchar_t* identity;
  244. IASAttribute attr;
  245. HRESULT hr;
  246. WCHAR name[DNLEN + UNLEN + 2];
  247. if ((identityAttr == RADIUS_ATTRIBUTE_USER_NAME) || (!overrideUsername))
  248. {
  249. // identity chosen for override is user-name
  250. // can be more than 1 RADIUS_ATTRIBUTE_USER_NAME attribute
  251. // Use the one from access accept.
  252. getRadiusUserName(request, attr);
  253. }
  254. if (!attr && (identityAttr != RADIUS_ATTRIBUTE_USER_NAME))
  255. {
  256. // identity chosen is not user-name
  257. // only one possible identity attribute
  258. attr.load(request, identityAttr, IASTYPE_OCTET_STRING);
  259. }
  260. // if an 'identity' was retrieved, convert it then return
  261. if (attr != NULL && attr->Value.OctetString.dwLength != 0)
  262. {
  263. // previous step was successful
  264. // Convert it to a UNICODE string.
  265. if (identitySize < IAS_OCT2WIDE_LEN(attr->Value.OctetString))
  266. {
  267. IASTraceString("IASOctetStringToWide failed");
  268. identitySize = IAS_OCT2WIDE_LEN(attr->Value.OctetString);
  269. return false;
  270. }
  271. IASOctetStringToWide(attr->Value.OctetString, pIdentity);
  272. // if that fails, then the string is empty ("")
  273. if (wcslen(pIdentity) == 0)
  274. {
  275. IASTraceString("IASOctetStringToWide failed");
  276. return false;
  277. }
  278. else
  279. {
  280. IASTracePrintf(
  281. "NT-SAM Names handler received request with user identity %S.",
  282. pIdentity
  283. );
  284. return true;
  285. }
  286. }
  287. else
  288. {
  289. // previous step was not successful (No identity attribute)
  290. // use default identity or guest
  291. if (defaultIdentity)
  292. {
  293. // Use the default identity if set.
  294. identity = defaultIdentity;
  295. }
  296. else
  297. {
  298. // Otherwise use the guest account for the default domain.
  299. IASGetGuestAccountName(name);
  300. identity = name;
  301. }
  302. IASTracePrintf(
  303. "NT-SAM Names handler using default user identity %S.",
  304. identity
  305. );
  306. }
  307. IASTracePrintf("identity is \"%S\"", identity);
  308. hr = StringCbCopyW(pIdentity, identitySize, identity);
  309. if (FAILED(hr))
  310. {
  311. identitySize = (wcslen(identity) + 1) * sizeof(wchar_t) ;
  312. return false;
  313. }
  314. return true;
  315. }
  316. //
  317. // set attr to the RADIUS_ATTRIBUTE_USER_NAME found if any
  318. // if 2 are present, take the one returned by the backend server.
  319. //
  320. //
  321. void IdentityHelper::getRadiusUserName(IASRequest& request, IASAttribute &attr)
  322. {
  323. IASAttributeVectorWithBuffer<2> vector;
  324. DWORD Error = vector.load(request, RADIUS_ATTRIBUTE_USER_NAME);
  325. switch (vector.size())
  326. {
  327. case 0:
  328. // no attribute found
  329. break;
  330. case 1:
  331. // only one attribute: use it
  332. attr = vector.front().pAttribute;
  333. break;
  334. case 2:
  335. attr = vector.front().pAttribute;
  336. // IAS_RECVD_FROM_CLIENT is set when the proxy receives the attribute
  337. // in the access request or accounting request
  338. if(attr.testFlag(IAS_RECVD_FROM_CLIENT))
  339. {
  340. // if the 1st attribute was received from the client (i.e. was in the
  341. // REQUEST, then use the other one, the other should come from the
  342. // back-end server
  343. attr = vector.back().pAttribute;
  344. if (attr.testFlag(IAS_RECVD_FROM_CLIENT))
  345. {
  346. IASTraceString("ERROR 2 RADIUS_ATTRIBUTE_USER_NAME found in the"
  347. "request but both came from the client");
  348. _com_issue_error(IAS_PROXY_MALFORMED_RESPONSE);
  349. }
  350. }
  351. break;
  352. default:
  353. _com_issue_error(IAS_PROXY_MALFORMED_RESPONSE);
  354. }
  355. }