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.

694 lines
16 KiB

  1. /*++
  2. Copyright (c) 1990-1992 Microsoft Corporation
  3. Module Name:
  4. rpcbind.c
  5. Abstract:
  6. Contains the RPC bind and un-bind routines for the Timesource
  7. Service.
  8. Author:
  9. Rajen Shah (rajens) 02-Apr-1991
  10. Environment:
  11. User Mode -Win32
  12. Revision History:
  13. 02-Apr-1991 RajenS
  14. created
  15. 22-May-1992 JohnRo
  16. RAID 9829: winsvc.h and related file cleanup.
  17. --*/
  18. //
  19. // INCLUDES
  20. //
  21. #define NOSERVICE // Avoid <winsvc.h> vs. <lmsvc.h> conflicts.
  22. #include <nt.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <rpc.h>
  26. #include <logon_c.h> // includes lmcons.h, lmaccess.h, netlogon.h, ssi.h, windef.h
  27. #include <lmerr.h> // NERR_ and ERROR_ equates.
  28. #include <lmsvc.h>
  29. #include <ntrpcp.h>
  30. #include <tstring.h> // IS_PATH_SEPARATOR ...
  31. #include <nlbind.h> // Prototypes for these routines
  32. #include <icanon.h> // NAMETYPE_*
  33. //
  34. // DataTypes
  35. //
  36. typedef struct _CACHE_ENTRY {
  37. LIST_ENTRY Next;
  38. UNICODE_STRING UnicodeServerNameString;
  39. RPC_BINDING_HANDLE RpcBindingHandle;
  40. ULONG ReferenceCount;
  41. } CACHE_ENTRY, *PCACHE_ENTRY;
  42. //
  43. // STATIC GLOBALS
  44. //
  45. //
  46. // Maintain a cache of RPC binding handles.
  47. //
  48. CRITICAL_SECTION NlGlobalBindingCacheCritSect;
  49. LIST_ENTRY NlGlobalBindingCache;
  50. NET_API_STATUS
  51. NlBindingAttachDll (
  52. VOID
  53. )
  54. /*++
  55. Routine Description:
  56. Initialize the RPC binding handle cache on process attach.
  57. Arguments:
  58. None.
  59. Return Value:
  60. None.
  61. --*/
  62. {
  63. InitializeListHead( &NlGlobalBindingCache );
  64. //
  65. // Initialize the Global Cache Critical Section
  66. //
  67. try {
  68. InitializeCriticalSection( &NlGlobalBindingCacheCritSect );
  69. } except( EXCEPTION_EXECUTE_HANDLER ) {
  70. return STATUS_NO_MEMORY;
  71. }
  72. return NO_ERROR;
  73. }
  74. VOID
  75. NlBindingDetachDll (
  76. VOID
  77. )
  78. /*++
  79. Routine Description:
  80. Cleanup the RPC binding handle cache on process detach.
  81. Arguments:
  82. None.
  83. Return Value:
  84. None.
  85. --*/
  86. {
  87. //
  88. // The binding cache must be empty,
  89. // Netlogon cleans up after itself,
  90. // no one else uses the cache.
  91. //
  92. ASSERT( IsListEmpty( &NlGlobalBindingCache ) );
  93. DeleteCriticalSection( &NlGlobalBindingCacheCritSect );
  94. }
  95. PCACHE_ENTRY
  96. NlBindingFindCacheEntry (
  97. IN LPWSTR UncServerName
  98. )
  99. /*++
  100. Routine Description:
  101. Find the specfied cache entry.
  102. Entered with the NlGlobalBindingCacheCritSect locked.
  103. Arguments:
  104. UncServerName - Name of the server to lookup
  105. Return Value:
  106. NULL - Cache entry not found.
  107. --*/
  108. {
  109. NTSTATUS Status;
  110. PLIST_ENTRY ListEntry;
  111. PCACHE_ENTRY CacheEntry;
  112. UNICODE_STRING UnicodeServerNameString;
  113. //
  114. // Ensure the passed in parameter is really a UNC name
  115. //
  116. if ( UncServerName == NULL ||
  117. !IS_PATH_SEPARATOR( UncServerName[0] ) ||
  118. !IS_PATH_SEPARATOR( UncServerName[1] ) ) {
  119. return NULL;
  120. }
  121. //
  122. // Loop through the cache finding the entry.
  123. //
  124. RtlInitUnicodeString( &UnicodeServerNameString, UncServerName+2 );
  125. for ( ListEntry = NlGlobalBindingCache.Flink;
  126. ListEntry != &NlGlobalBindingCache;
  127. ListEntry = ListEntry->Flink ) {
  128. CacheEntry = CONTAINING_RECORD( ListEntry, CACHE_ENTRY, Next );
  129. // Consider using RtlEqualMemory since the strings will really be
  130. // bit for bit identical since Netlogon flushes this cache before it
  131. // changes the name.
  132. if ( RtlEqualUnicodeString( &UnicodeServerNameString,
  133. &CacheEntry->UnicodeServerNameString,
  134. TRUE ) ) {
  135. return CacheEntry;
  136. }
  137. }
  138. return NULL;
  139. }
  140. NTSTATUS
  141. NlBindingAddServerToCache (
  142. IN LPWSTR UncServerName,
  143. IN NL_RPC_BINDING RpcBindingType
  144. )
  145. /*++
  146. Routine Description:
  147. Bind to the specified server and add it to the binding cache.
  148. Arguments:
  149. UncServerName - UNC Name of the server to bind to.
  150. RpcBindingType - Determines whether to use unauthenticated TCP/IP transport instead of
  151. named pipes.
  152. Return Value:
  153. Status of the operation
  154. --*/
  155. {
  156. NTSTATUS Status;
  157. RPC_STATUS RpcStatus;
  158. PCACHE_ENTRY CacheEntry;
  159. ASSERT ( UncServerName != NULL &&
  160. IS_PATH_SEPARATOR( UncServerName[0] ) &&
  161. IS_PATH_SEPARATOR( UncServerName[1] ) );
  162. //
  163. // If there already is an entry in the cache,
  164. // just increment the reference count.
  165. //
  166. EnterCriticalSection( &NlGlobalBindingCacheCritSect );
  167. CacheEntry = NlBindingFindCacheEntry( UncServerName );
  168. if ( CacheEntry != NULL ) {
  169. CacheEntry->ReferenceCount++;
  170. Status = STATUS_SUCCESS;
  171. //
  172. // Otherwise, allocate an entry and bind to the named server.
  173. //
  174. } else {
  175. UNICODE_STRING UnicodeServerNameString;
  176. //
  177. // Allocate the cache entry
  178. //
  179. RtlInitUnicodeString( &UnicodeServerNameString, UncServerName+2 );
  180. CacheEntry = LocalAlloc( 0,
  181. sizeof(CACHE_ENTRY) +
  182. UnicodeServerNameString.Length );
  183. if ( CacheEntry == NULL ) {
  184. Status = STATUS_NO_MEMORY;
  185. } else {
  186. //
  187. // Initialize the cache entry.
  188. //
  189. // The caller has a 'reference' to the entry.
  190. //
  191. CacheEntry->UnicodeServerNameString.Buffer = (LPWSTR)(CacheEntry+1);
  192. CacheEntry->UnicodeServerNameString.Length =
  193. CacheEntry->UnicodeServerNameString.MaximumLength =
  194. UnicodeServerNameString.Length;
  195. RtlCopyMemory( CacheEntry->UnicodeServerNameString.Buffer,
  196. UnicodeServerNameString.Buffer,
  197. CacheEntry->UnicodeServerNameString.Length );
  198. CacheEntry->ReferenceCount = 1;
  199. //
  200. // Bind to the server
  201. // (Don't hold the crit sect for this potentially very long time.)
  202. //
  203. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  204. RpcStatus = NlRpcpBindRpc (
  205. UncServerName,
  206. SERVICE_NETLOGON,
  207. L"Security=Impersonation Dynamic False",
  208. RpcBindingType,
  209. &CacheEntry->RpcBindingHandle );
  210. EnterCriticalSection( &NlGlobalBindingCacheCritSect );
  211. if ( RpcStatus == 0 ) {
  212. //
  213. // Link the cache entry into the list
  214. //
  215. // If this were a general purpose routine, I'd have to check
  216. // if someone inserted this cache entry already while we had
  217. // the crit sect unlocked. However, the only caller is the
  218. // netlogon service that has exclusive access to this client.
  219. //
  220. // Insert the entry at the front of the list. Specifically,
  221. // insert it in front of the binding entry for the same
  222. // name but a different binding type. That'll ensure a
  223. // newer binding type is used instead of an older binding type.
  224. //
  225. InsertHeadList( &NlGlobalBindingCache, &CacheEntry->Next );
  226. Status = STATUS_SUCCESS;
  227. } else {
  228. Status = I_RpcMapWin32Status( RpcStatus );
  229. (VOID) LocalFree( CacheEntry );
  230. }
  231. }
  232. }
  233. //
  234. // Return to the caller.
  235. //
  236. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  237. return Status;
  238. }
  239. NTSTATUS
  240. NlBindingSetAuthInfo (
  241. IN LPWSTR UncServerName,
  242. IN NL_RPC_BINDING RpcBindingType,
  243. IN BOOL SealIt,
  244. IN PVOID ClientContext,
  245. IN LPWSTR ServerContext
  246. )
  247. /*++
  248. Routine Description:
  249. Bind to the specified server and add it to the binding cache.
  250. Arguments:
  251. UncServerName - UNC Name of the server to bind to.
  252. RpcBindingType - Determines whether to use unauthenticated TCP/IP transport instead of
  253. named pipes.
  254. SealIt - Specifies that the secure channel should be sealed (rather than
  255. simply signed)
  256. ClientContext - Context used by the client side of the NETLOGON security
  257. package to associate this call with the existing secure channel.
  258. ServerContext - Context used by the server side of the NETLOGON security
  259. package to associate this call with the existing secure channel.
  260. Return Value:
  261. Status of the operation
  262. --*/
  263. {
  264. NTSTATUS Status;
  265. RPC_STATUS RpcStatus;
  266. PCACHE_ENTRY CacheEntry;
  267. ASSERT ( UncServerName != NULL &&
  268. IS_PATH_SEPARATOR( UncServerName[0] ) &&
  269. IS_PATH_SEPARATOR( UncServerName[1] ) );
  270. //
  271. // Find the cache entry.
  272. //
  273. EnterCriticalSection( &NlGlobalBindingCacheCritSect );
  274. CacheEntry = NlBindingFindCacheEntry( UncServerName );
  275. if ( CacheEntry == NULL ) {
  276. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  277. return RPC_NT_INVALID_BINDING;
  278. }
  279. //
  280. // Tell RPC to start doing secure RPC
  281. //
  282. RpcStatus = RpcBindingSetAuthInfoW(
  283. CacheEntry->RpcBindingHandle,
  284. ServerContext,
  285. SealIt ? RPC_C_AUTHN_LEVEL_PKT_PRIVACY : RPC_C_AUTHN_LEVEL_PKT_INTEGRITY,
  286. RPC_C_AUTHN_NETLOGON, // Netlogon's own security package
  287. ClientContext,
  288. RPC_C_AUTHZ_NAME );
  289. if ( RpcStatus != 0 ) {
  290. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  291. return I_RpcMapWin32Status( RpcStatus );
  292. }
  293. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  294. return STATUS_SUCCESS;
  295. }
  296. NTSTATUS
  297. NlBindingDecrementAndUnlock (
  298. IN PCACHE_ENTRY CacheEntry
  299. )
  300. /*++
  301. Routine Description:
  302. Decrement the reference count and unlock the NlGlobalBindingCacheCritSect.
  303. If the reference count reaches 0, unbind the interface, unlink the cache
  304. entry and delete it.
  305. Entered with the NlGlobalBindingCacheCritSect locked.
  306. Arguments:
  307. UncServerName - UNC Name of the server to bind to.
  308. Return Value:
  309. Status of the operation
  310. --*/
  311. {
  312. NTSTATUS Status;
  313. RPC_STATUS RpcStatus;
  314. //
  315. // Decrement the reference count
  316. //
  317. // If it didn't reach zero, just unlock the crit sect and return.
  318. //
  319. if ( (--CacheEntry->ReferenceCount) != 0 ) {
  320. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  321. return STATUS_PENDING;
  322. }
  323. //
  324. // Remove the entry from the list and unlock the crit sect.
  325. //
  326. // Once the entry is removed from the list, we can safely unlock the
  327. // crit sect. Then we can unbind (a potentially lengthy operation) with
  328. // the crit sect unlocked.
  329. //
  330. RemoveEntryList( &CacheEntry->Next );
  331. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  332. //
  333. // Unbind and delete the cache entry.
  334. //
  335. RpcStatus = RpcpUnbindRpc( CacheEntry->RpcBindingHandle );
  336. if ( RpcStatus != 0 ) {
  337. Status = I_RpcMapWin32Status( RpcStatus );
  338. } else {
  339. Status = STATUS_SUCCESS;
  340. }
  341. (VOID) LocalFree( CacheEntry );
  342. return Status;
  343. }
  344. NTSTATUS
  345. NlBindingRemoveServerFromCache (
  346. IN LPWSTR UncServerName,
  347. IN NL_RPC_BINDING RpcBindingType
  348. )
  349. /*++
  350. Routine Description:
  351. Unbind to the specified server and remove it from the binding cache.
  352. Arguments:
  353. UncServerName - UNC Name of the server to unbind from.
  354. RpcBindingType - Determines whether to use unauthenticated TCP/IP transport instead of
  355. named pipes.
  356. Return Value:
  357. Status of the operation
  358. --*/
  359. {
  360. NTSTATUS Status;
  361. PCACHE_ENTRY CacheEntry;
  362. ASSERT ( UncServerName != NULL &&
  363. IS_PATH_SEPARATOR( UncServerName[0] ) &&
  364. IS_PATH_SEPARATOR( UncServerName[1] ) );
  365. //
  366. // If there is no cache entry,
  367. // silently ignore the situation.
  368. //
  369. EnterCriticalSection( &NlGlobalBindingCacheCritSect );
  370. CacheEntry = NlBindingFindCacheEntry( UncServerName );
  371. if ( CacheEntry == NULL ) {
  372. ASSERT( FALSE );
  373. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  374. return STATUS_SUCCESS;
  375. }
  376. //
  377. // Decrement the reference count and unlock the crit sect.
  378. //
  379. Status = NlBindingDecrementAndUnlock( CacheEntry );
  380. return Status;
  381. }
  382. handle_t
  383. LOGONSRV_HANDLE_bind (
  384. LOGONSRV_HANDLE UncServerName)
  385. /*++
  386. Routine Description:
  387. This routine calls a common bind routine that is shared by all services.
  388. Arguments:
  389. UncServerName - A pointer to a string containing the name of the server
  390. to bind with.
  391. Return Value:
  392. The binding handle is returned to the stub routine. If the
  393. binding is unsuccessful, a NULL will be returned.
  394. --*/
  395. {
  396. handle_t RpcBindingHandle;
  397. RPC_STATUS RpcStatus;
  398. PCACHE_ENTRY CacheEntry;
  399. //
  400. // If there is a cache entry,
  401. // increment the reference count and use the cached handle
  402. //
  403. EnterCriticalSection( &NlGlobalBindingCacheCritSect );
  404. CacheEntry = NlBindingFindCacheEntry( UncServerName );
  405. if ( CacheEntry != NULL ) {
  406. CacheEntry->ReferenceCount ++;
  407. RpcBindingHandle = CacheEntry->RpcBindingHandle;
  408. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  409. return RpcBindingHandle;
  410. }
  411. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  412. //
  413. // If there is no cache entry,
  414. // simply create a new binding.
  415. //
  416. RpcStatus = NlRpcpBindRpc (
  417. UncServerName,
  418. SERVICE_NETLOGON,
  419. L"Security=Impersonation Dynamic False",
  420. UseNamedPipe, // Always use named pipe.
  421. &RpcBindingHandle );
  422. if ( RpcStatus != 0 ) {
  423. RpcBindingHandle = NULL;
  424. }
  425. return RpcBindingHandle;
  426. }
  427. void
  428. LOGONSRV_HANDLE_unbind (
  429. LOGONSRV_HANDLE UncServerName,
  430. handle_t RpcBindingHandle)
  431. /*++
  432. Routine Description:
  433. This routine calls a common unbind routine that is shared by
  434. all services.
  435. Arguments:
  436. UncServerName - This is the name of the server from which to unbind.
  437. RpcBindingHandle - This is the binding handle that is to be closed.
  438. Return Value:
  439. none.
  440. --*/
  441. {
  442. RPC_STATUS RpcStatus;
  443. PLIST_ENTRY ListEntry;
  444. PCACHE_ENTRY CacheEntry;
  445. //
  446. // Loop through the cache finding the entry.
  447. //
  448. EnterCriticalSection( &NlGlobalBindingCacheCritSect );
  449. for ( ListEntry = NlGlobalBindingCache.Flink;
  450. ListEntry != &NlGlobalBindingCache;
  451. ListEntry = ListEntry->Flink ) {
  452. CacheEntry = CONTAINING_RECORD( ListEntry, CACHE_ENTRY, Next );
  453. //
  454. // If the cache entry was found,
  455. // decrement the reference count and unlock the crit sect.
  456. //
  457. if ( RpcBindingHandle == CacheEntry->RpcBindingHandle ) {
  458. (VOID) NlBindingDecrementAndUnlock( CacheEntry );
  459. return;
  460. }
  461. }
  462. LeaveCriticalSection( &NlGlobalBindingCacheCritSect );
  463. //
  464. // Just Unbind the handle
  465. //
  466. RpcStatus = RpcpUnbindRpc( RpcBindingHandle );
  467. return;
  468. UNREFERENCED_PARAMETER(UncServerName);
  469. }