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.

563 lines
11 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. rc4safe.c
  5. Abstract:
  6. access rc4 key material in thread safe manner, without adversly affecting
  7. performance of multi-thread users.
  8. Author:
  9. Scott Field (sfield) 02-Jul-99
  10. --*/
  11. #ifndef KMODE_RNG
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <zwapi.h>
  17. #else
  18. #include <ntosp.h>
  19. #include <windef.h>
  20. #endif // KMODE_RNG
  21. #include <rc4.h>
  22. #include <randlib.h>
  23. #include "umkm.h"
  24. typedef struct {
  25. unsigned int BytesUsed; // bytes processed for key associated with this entry
  26. __LOCK_TYPE lock; // lock for serializing key entry
  27. RC4_KEYSTRUCT rc4key; // key material associated with this entry
  28. } RC4_SAFE, *PRC4_SAFE, *LPRC4_SAFE;
  29. typedef enum _MemoryMode {
  30. Paged = 1,
  31. NonPaged
  32. } MemoryMode;
  33. typedef struct {
  34. unsigned int Entries; // count of array entries.
  35. MemoryMode Mode; // allocation & behavior mode of SAFE_ARRAY
  36. RC4_SAFE *Array[]; // array of pointers to RC4_SAFE entries.
  37. } RC4_SAFE_ARRAY, *PRC4_SAFE_ARRAY, *LPRC4_SAFE_ARRAY;
  38. //
  39. // !!! RC4_SAFE_ENTRIES must be even multiple of 4 !!!
  40. //
  41. #ifndef KMODE_RNG
  42. #define RC4_SAFE_ENTRIES (8)
  43. #else
  44. //
  45. // we don't expect as much traffic in kernel mode, so use less resources.
  46. //
  47. #define RC4_SAFE_ENTRIES (4)
  48. #endif
  49. #ifdef KMODE_RNG
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text(PAGE, rc4_safe_select)
  52. #pragma alloc_text(PAGE, rc4_safe)
  53. #pragma alloc_text(PAGE, rc4_safe_key)
  54. #pragma alloc_text(PAGE, rc4_safe_select)
  55. #pragma alloc_text(PAGE, rc4_safe_startup)
  56. #pragma alloc_text(PAGE, rc4_safe_shutdown)
  57. #endif // ALLOC_PRAGMA
  58. #endif // KMODE_RNG
  59. void
  60. rc4_safe_select(
  61. IN void *pContext,
  62. OUT unsigned int *pEntry,
  63. OUT unsigned int *pBytesUsed
  64. )
  65. /*++
  66. Routine Description:
  67. key selector: choose a thread safe key.
  68. outputs key identifier and bytes used with key.
  69. --*/
  70. {
  71. RC4_SAFE_ARRAY *pRC4SafeArray;
  72. RC4_SAFE *pRC4Safe;
  73. static unsigned int circular;
  74. unsigned int local;
  75. #ifdef KMODE_RNG
  76. PAGED_CODE();
  77. #endif // KMODE_RNG
  78. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  79. //
  80. // there are 2 ways to increment the array selector:
  81. // 1. Just increment the pointer. On a multi-processor system,
  82. // with multiple threads calling rc4_safe_select simultaneously,
  83. // this can lead to several threads selecting the same array element.
  84. // This will lead to lock contention on the array element lock.
  85. // Currently, we've decided this scenario will be fairly rare, so the
  86. // penalty associated with option 2 is avoided.
  87. // 2. Use InterlockedIncrement to determine the array element. This would
  88. // yield no collision on an array element, hence no lock contention
  89. // on the embedded array lock. This introduces additional bus traffic
  90. // on SMP machines due to the lock primitive.
  91. //
  92. //
  93. #ifdef KMODE_RNG
  94. local = (unsigned int)InterlockedIncrement( (PLONG)&circular );
  95. #else
  96. circular++;
  97. local = circular;
  98. #endif // KMODE_RNG
  99. //
  100. // array index will not wrap.
  101. //
  102. local &= ( pRC4SafeArray->Entries-1 );
  103. pRC4Safe = pRC4SafeArray->Array[local];
  104. *pEntry = local;
  105. *pBytesUsed = pRC4Safe->BytesUsed;
  106. }
  107. #ifdef KMODE_RNG
  108. void
  109. rc4_safe_select_np(
  110. IN void *pContext,
  111. OUT unsigned int *pEntry,
  112. OUT unsigned int *pBytesUsed
  113. )
  114. /*++
  115. Routine Description:
  116. Non-paged, high-IRQL version of rc4_safe_select()
  117. --*/
  118. {
  119. RC4_SAFE_ARRAY *pRC4SafeArray;
  120. RC4_SAFE *pRC4Safe;
  121. unsigned int local;
  122. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  123. if( *pEntry == 0 ) {
  124. if( pRC4SafeArray->Entries == 1 ) {
  125. local = 0;
  126. } else {
  127. static unsigned int circular;
  128. local = (unsigned int)InterlockedIncrement( (PLONG)&circular );
  129. //
  130. // array index will not wrap.
  131. //
  132. local = (local % pRC4SafeArray->Entries);
  133. }
  134. } else {
  135. local = KeGetCurrentProcessorNumber();
  136. }
  137. pRC4Safe = pRC4SafeArray->Array[local];
  138. *pEntry = local;
  139. *pBytesUsed = pRC4Safe->BytesUsed;
  140. }
  141. #endif // KMODE_RNG
  142. void
  143. rc4_safe(
  144. IN void *pContext,
  145. IN unsigned int Entry,
  146. IN unsigned int cb,
  147. IN void *pv
  148. )
  149. /*++
  150. Routine Description:
  151. Initializes the rc4 key identified by the Entry index.
  152. Input key material is pv, of size cb.
  153. --*/
  154. {
  155. RC4_SAFE_ARRAY *pRC4SafeArray;
  156. RC4_SAFE *pRC4Safe;
  157. #ifdef KMODE_RNG
  158. PAGED_CODE();
  159. #endif // KMODE_RNG
  160. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  161. Entry &= ( pRC4SafeArray->Entries - 1 );
  162. pRC4Safe = pRC4SafeArray->Array[ Entry ];
  163. ENTER_LOCK( &(pRC4Safe->lock) );
  164. rc4( &(pRC4Safe->rc4key), cb, (unsigned char*) pv );
  165. pRC4Safe->BytesUsed += cb;
  166. LEAVE_LOCK( &(pRC4Safe->lock) );
  167. }
  168. #ifdef KMODE_RNG
  169. void
  170. rc4_safe_np(
  171. IN void *pContext,
  172. IN unsigned int Entry,
  173. IN unsigned int cb,
  174. IN void *pv
  175. )
  176. /*++
  177. Routine Description:
  178. Non-paged, high IRQL version of rc4_safe()
  179. --*/
  180. {
  181. RC4_SAFE_ARRAY *pRC4SafeArray;
  182. RC4_SAFE *pRC4Safe;
  183. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  184. // NOTE:
  185. // we ignore the Entry parameter.
  186. // future consideration may be ignore only when Entry == 0xffffffff
  187. // but, this would only be perf penalty currently.
  188. //
  189. Entry = KeGetCurrentProcessorNumber();
  190. pRC4Safe = pRC4SafeArray->Array[ Entry ];
  191. rc4( &(pRC4Safe->rc4key), cb, (unsigned char*) pv );
  192. pRC4Safe->BytesUsed += cb;
  193. }
  194. #endif // KMODE_RNG
  195. void
  196. rc4_safe_key(
  197. IN void *pContext,
  198. IN unsigned int Entry,
  199. IN unsigned int cb,
  200. IN const void *pv
  201. )
  202. /*++
  203. Routine Description:
  204. Initializes the rc4 key identified by the Entry index.
  205. Input key material is pv, of size cb.
  206. --*/
  207. {
  208. RC4_SAFE_ARRAY *pRC4SafeArray;
  209. RC4_SAFE *pRC4Safe;
  210. #ifdef KMODE_RNG
  211. PAGED_CODE();
  212. #endif // KMODE_RNG
  213. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  214. Entry &= ( pRC4SafeArray->Entries - 1 );
  215. pRC4Safe = pRC4SafeArray->Array[ Entry ];
  216. ENTER_LOCK( &(pRC4Safe->lock) );
  217. rc4_key( &(pRC4Safe->rc4key), cb, (unsigned char*) pv );
  218. pRC4Safe->BytesUsed = 0;
  219. LEAVE_LOCK( &(pRC4Safe->lock) );
  220. }
  221. #ifdef KMODE_RNG
  222. void
  223. rc4_safe_key_np(
  224. IN void *pContext,
  225. IN unsigned int Entry,
  226. IN unsigned int cb,
  227. IN const void *pv
  228. )
  229. /*++
  230. Routine Description:
  231. Non-paged, high-IRQL version of rc4_safe_key()
  232. --*/
  233. {
  234. RC4_SAFE_ARRAY *pRC4SafeArray;
  235. RC4_SAFE *pRC4Safe;
  236. pRC4SafeArray = (RC4_SAFE_ARRAY*)pContext;
  237. if( Entry == 0xffffffff ) {
  238. Entry = KeGetCurrentProcessorNumber();
  239. }
  240. pRC4Safe = pRC4SafeArray->Array[ Entry ];
  241. rc4_key( &pRC4Safe->rc4key, cb, (unsigned char*) pv );
  242. pRC4Safe->BytesUsed = 0;
  243. }
  244. #endif // KMODE_RNG
  245. unsigned int
  246. rc4_safe_startup(
  247. IN OUT void **ppContext
  248. )
  249. /*++
  250. Routine Description:
  251. key selector: choose a thread safe key.
  252. outputs key identifier and bytes used with key.
  253. --*/
  254. {
  255. RC4_SAFE_ARRAY *pRC4SafeArray;
  256. RC4_SAFE *pRC4Safe;
  257. unsigned int Entries;
  258. unsigned int i;
  259. #ifdef KMODE_RNG
  260. PAGED_CODE();
  261. #endif // KMODE_RNG
  262. Entries = RC4_SAFE_ENTRIES;
  263. //
  264. // LONGHORN: ALLOC may be used here.
  265. // Why do we have to use Non-paged context in paged code? May be not.
  266. //
  267. pRC4SafeArray = (RC4_SAFE_ARRAY *)ALLOC_NP(
  268. sizeof(RC4_SAFE_ARRAY) +
  269. (Entries * sizeof(RC4_SAFE *)) +
  270. (Entries * sizeof(RC4_SAFE))
  271. );
  272. if( pRC4SafeArray == NULL ) {
  273. return FALSE;
  274. }
  275. pRC4SafeArray->Entries = Entries;
  276. pRC4SafeArray->Mode = Paged;
  277. pRC4Safe = (RC4_SAFE*) ((unsigned char*)pRC4SafeArray +
  278. sizeof(RC4_SAFE_ARRAY) +
  279. (Entries * sizeof(RC4_SAFE*))
  280. );
  281. for ( i = 0 ; i < Entries ; i++, pRC4Safe++ ) {
  282. pRC4SafeArray->Array[i] = pRC4Safe;
  283. if(!INIT_LOCK( &(pRC4Safe->lock) ))
  284. {
  285. pRC4SafeArray->Entries = i;
  286. rc4_safe_shutdown( pRC4SafeArray );
  287. return FALSE;
  288. }
  289. //
  290. // cause client to re-key for each initialized array entry.
  291. //
  292. pRC4Safe->BytesUsed = 0xffffffff;
  293. }
  294. *ppContext = pRC4SafeArray;
  295. return TRUE;
  296. }
  297. #ifdef KMODE_RNG
  298. unsigned int
  299. rc4_safe_startup_np(
  300. IN OUT void **ppContext
  301. )
  302. /*++
  303. Routine Description:
  304. Non-Paged, high IRQL version of rc4_safe_startup()
  305. --*/
  306. {
  307. RC4_SAFE_ARRAY *pRC4SafeArray;
  308. RC4_SAFE *pRC4Safe;
  309. unsigned int Entries;
  310. unsigned int i;
  311. //
  312. // get installed processor count.
  313. //
  314. Entries = KeNumberProcessors;
  315. pRC4SafeArray = (RC4_SAFE_ARRAY *)ALLOC_NP(
  316. sizeof(RC4_SAFE_ARRAY) +
  317. (Entries * sizeof(RC4_SAFE *)) +
  318. (Entries * sizeof(RC4_SAFE))
  319. );
  320. if( pRC4SafeArray == NULL ) {
  321. return FALSE;
  322. }
  323. pRC4SafeArray->Entries = Entries;
  324. pRC4SafeArray->Mode = NonPaged;
  325. pRC4Safe = (RC4_SAFE*) ((unsigned char*)pRC4SafeArray +
  326. sizeof(RC4_SAFE_ARRAY) +
  327. (Entries * sizeof(RC4_SAFE*))
  328. );
  329. for ( i = 0 ; i < Entries ; i++, pRC4Safe++ ) {
  330. pRC4SafeArray->Array[i] = pRC4Safe;
  331. //
  332. // cause client to re-key for each initialized array entry.
  333. //
  334. pRC4Safe->BytesUsed = 0xffffffff;
  335. }
  336. *ppContext = pRC4SafeArray;
  337. return TRUE;
  338. }
  339. #endif
  340. void
  341. rc4_safe_shutdown(
  342. IN void *pContext
  343. )
  344. /*++
  345. Routine Description:
  346. rc4_safe_shutdown called to free resources associated with internal structures.
  347. typically called during DLL_PROCESS_DETACH type shutdown code.
  348. --*/
  349. {
  350. RC4_SAFE_ARRAY *SafeArray;
  351. unsigned int SafeEntries;
  352. unsigned int i;
  353. #ifdef KMODE_RNG
  354. PAGED_CODE();
  355. #endif // KMODE_RNG
  356. SafeArray = (RC4_SAFE_ARRAY*)pContext;
  357. SafeEntries = SafeArray->Entries;
  358. for ( i = 0 ; i < SafeEntries ; i++ ) {
  359. RC4_SAFE *pRC4Safe = SafeArray->Array[i];
  360. DELETE_LOCK( &(pRC4Safe->lock) );
  361. }
  362. FREE( pContext );
  363. }
  364. #ifdef KMODE_RNG
  365. void
  366. rc4_safe_shutdown_np(
  367. IN void *pContext
  368. )
  369. /*++
  370. Routine Description:
  371. Non-paged, high-IRQL version of rc4_safe_shutdown()
  372. --*/
  373. {
  374. FREE( pContext );
  375. }
  376. #endif