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.

657 lines
21 KiB

  1. /*--
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. nlldap.cxx
  5. Abstract:
  6. Routines the use the DS's ldap filter.
  7. This is actually in a .cxx file by itself to work around a compiler bug
  8. where .c files cannot include ldap.h
  9. Author:
  10. Environment:
  11. User mode only.
  12. Contains NT-specific code.
  13. Requires ANSI C extensions: slash-slash comments, long external names.
  14. Revision History:
  15. --*/
  16. #ifdef __cplusplus
  17. extern "C" {
  18. #endif /* __cplusplus */
  19. #include <nt.h> // LARGE_INTEGER definition
  20. #include <ntrtl.h> // LARGE_INTEGER definition
  21. #include <nturtl.h> // LARGE_INTEGER definition
  22. #include <ntlsa.h> // Needed by lsrvdata.h
  23. #include <ntddbrow.h> // Needed by nlcommon.h
  24. #define NOMINMAX // Avoid redefinition of min and max in stdlib.h
  25. #include <rpc.h> // Needed by logon_s.h
  26. #include <logon_s.h> // includes lmcons.h, lmaccess.h, netlogon.h, ssi.h, windef.h
  27. //
  28. #include <windows.h>
  29. #include <winsock2.h> // Winsock support
  30. #include <lmapibuf.h> // NetApiBufferFree
  31. #include <logonp.h> // NetpLogon routines
  32. #include <lsarpc.h> // Needed by lsrvdata.h and logonsrv.h
  33. #include <lsaisrv.h> // Needed by changelg.h
  34. #include <wincrypt.h> // CryptoAPI, needed by lsrvdata.h
  35. #ifdef __cplusplus
  36. } /* extern "C" */
  37. #endif /* __cplusplus */
  38. #include <netlib.h> // Needed by nlcommon.h
  39. #ifdef __cplusplus
  40. extern "C" {
  41. #endif /* __cplusplus */
  42. #include <samrpc.h> // Needed by lsrvdata.h and logonsrv.h
  43. #include <ntdsa.h> // THSave/THRestore
  44. #include <wmistr.h> // Needed by lsrvdata.h
  45. #include <evntrace.h> // Needed by lsrvdata.h
  46. #include <sspi.h> // Needed by ssiinit.h
  47. //
  48. // Netlogon specific header files.
  49. //
  50. #define _AVOID_REPL_API 1
  51. #include <nlrepl.h> // I_Net*
  52. #include "worker.h" // Worker routines
  53. #include "nlcommon.h" // Routines shared with logonsrv\common
  54. #include "domain.h" // Hosted domain definitions
  55. #include "changelg.h" // Change Log support
  56. #include "chutil.h" // Change Log utilities
  57. #include "iniparm.h" // registry parameters
  58. #include "windns.h" // needed by ssiinit.h
  59. #include "ssiinit.h" // Misc global definitions
  60. #include "nldebug.h" // Netlogon debugging
  61. #include "lsrvdata.h" // Globals
  62. // #include <string.h> // strnicmp ...
  63. #include <ldap.h> // Filter for LDAP query
  64. #define NL_MAXIMUM_USER_NAME_LENGTH 20 // The max SAM allows
  65. BOOLEAN
  66. IsFilterName(
  67. IN Filter *CurrentFilter,
  68. IN LPSTR NameToMatch
  69. )
  70. /*++
  71. Routine Description:
  72. If the CurrentFilter is for NameToMatch, return TRUE
  73. Arguments:
  74. Filter - Pointer to an equalityMatch Filter element.
  75. NameToMatch - Specifies the name to compare with the filter element.
  76. Return Value:
  77. TRUE name matches.
  78. --*/
  79. {
  80. ULONG NameLength;
  81. NameLength = strlen( NameToMatch );
  82. if ( NameLength != CurrentFilter->u.equalityMatch.attributeDesc.length ) {
  83. return FALSE;
  84. }
  85. if ( _strnicmp( NameToMatch,
  86. (LPSTR)CurrentFilter->u.equalityMatch.attributeDesc.value,
  87. NameLength ) != 0 ) {
  88. return FALSE;
  89. }
  90. return TRUE;
  91. }
  92. NET_API_STATUS
  93. FilterString(
  94. IN Filter *CurrentFilter,
  95. IN ULONG UnicodeStringBufferSize,
  96. OUT LPWSTR UnicodeStringBuffer OPTIONAL,
  97. OUT LPWSTR *UnicodeString
  98. )
  99. /*++
  100. Routine Description:
  101. Return a zero terminated unicode string containing the value of the
  102. current equalityMatch filter element.
  103. The value of the element is expected to be in UTF-8.
  104. Arguments:
  105. Filter - Pointer to an equalityMatch Filter element.
  106. UnicodeStringBuffer -- Buffer to copy the covnverted string to.
  107. If NULL, the function will allocate the needed memory and
  108. return it in UnicodeString.
  109. UnicodeStringSize - Size in wide charactes of UnicodeStringBuffer.
  110. If this size is less than what's needed to store the resulting
  111. NULL terminated unicode string, the function will allocate the
  112. needed memory and return it in UnicodeString.
  113. UnicodeString - Returns a pointer to the resulting string.
  114. If the passed in buffer for the resulting unicode string isn't
  115. large enough, the function will allocate the needed memory and
  116. the pointer to the allocated memory will be returned in this
  117. parameter. If NULL and the passed in buffer isn't large enough
  118. to store the resulting NULL terminated string, the function
  119. returns ERROR_INSUFFICIENT_BUFFER. On successful return, the
  120. caller should check whether UnicodeString != UnicodeStringBuffer
  121. and, if so, free the allocated buffer using NetApiBufferFree.
  122. Return Value:
  123. Error returned by NetpAllocWStrFromUtf8StrAsRequired.
  124. --*/
  125. {
  126. NET_API_STATUS NetStatus;
  127. LPWSTR AllocatedUnicodeString = NULL;
  128. //
  129. // Call the worker routine
  130. //
  131. NetStatus = NetpAllocWStrFromUtf8StrAsRequired(
  132. (LPSTR)CurrentFilter->u.equalityMatch.assertionValue.value,
  133. CurrentFilter->u.equalityMatch.assertionValue.length,
  134. UnicodeStringBufferSize,
  135. UnicodeStringBuffer,
  136. &AllocatedUnicodeString );
  137. //
  138. // Set the return pointer to point to the appropriate buffer
  139. //
  140. if ( NetStatus == NO_ERROR ) {
  141. if ( AllocatedUnicodeString != NULL ) {
  142. NlAssert( AllocatedUnicodeString != UnicodeStringBuffer );
  143. *UnicodeString = AllocatedUnicodeString;
  144. } else {
  145. *UnicodeString = UnicodeStringBuffer;
  146. }
  147. }
  148. return NetStatus;
  149. }
  150. NET_API_STATUS
  151. FilterBinary(
  152. IN Filter *CurrentFilter,
  153. IN ULONG BufferSize,
  154. OUT PVOID Buffer,
  155. OUT PULONG DataSize
  156. )
  157. /*++
  158. Routine Description:
  159. Returns a properly aligned pointer to the binary data.
  160. Arguments:
  161. Filter - Pointer to an equalityMatch Filter element.
  162. Buffer - Buffer to copy the data into.
  163. BufferSize - The size of the passed buffer. If the
  164. buffer isn't large enough to store the data,
  165. ERROR_INSUFFICIENT_BUFFER is returned.
  166. DataSize - Size of the data copied
  167. Return Value:
  168. NO_ERROR - The data has been successfully coppied.
  169. ERROR_INSUFFICIENT_BUFFER - The passed in buffer is too small.
  170. --*/
  171. {
  172. if ( BufferSize < CurrentFilter->u.equalityMatch.assertionValue.length ) {
  173. return ERROR_INSUFFICIENT_BUFFER;
  174. }
  175. RtlCopyMemory( Buffer,
  176. CurrentFilter->u.equalityMatch.assertionValue.value,
  177. CurrentFilter->u.equalityMatch.assertionValue.length );
  178. *DataSize = CurrentFilter->u.equalityMatch.assertionValue.length;
  179. return NO_ERROR;
  180. }
  181. NTSTATUS
  182. I_NetLogonLdapLookupEx(
  183. IN PVOID FilterParam,
  184. IN PVOID ClientSockAddr,
  185. OUT PVOID *Response,
  186. OUT PULONG ResponseSize
  187. )
  188. /*++
  189. Routine Description:
  190. This routine builds a response to an LDAP ping of a DC. DsGetDcName does
  191. such a ping to ensure the DC is functional and still meets the requirements
  192. of the DsGetDcName. DsGetDcName does an LDAP lookup of the NULL DN asking
  193. for attribute "Netlogon". The DS turns that into a call to this routine
  194. passing in the filter parameter.
  195. The DS is expected to save the DS thread state before calling. This routine
  196. calls SAM which expects to have its own DS thread state.
  197. Arguments:
  198. Filter - Filter describing the query. The filter is built by the DsGetDcName
  199. client, so we can limit the flexibility significantly.
  200. SockAddr - Socket Address of the client this request came in on.
  201. Response - Returns a pointer to an allocated buffer containing
  202. the response to return to the caller. This response is a binary blob
  203. which should be returned to the caller bit-for-bit intact.
  204. The buffer should be freed be calling I_NetLogonFree.
  205. ResponseSize - Size (in bytes) of the returned message.
  206. Return Value:
  207. STATUS_SUCCESS -- The response was returned in the supplied buffer.
  208. STATUS_INVALID_PARAMETER -- The filter was invalid.
  209. --*/
  210. {
  211. NTSTATUS Status = STATUS_SUCCESS;
  212. NET_API_STATUS NetStatus = NO_ERROR;
  213. Filter *LdapFilter = (Filter *) FilterParam;
  214. Filter *CurrentFilter;
  215. struct _setof3_ *CurrentAnd;
  216. LPSTR DnsDomainName = NULL;
  217. GUID DomainGuid;
  218. GUID *DomainGuidPtr = NULL;
  219. // The domain SID buffer must be DWORD alligned. Avoid any buffer overflow problem
  220. // due to truncation in case SECURITY_MAX_SID_SIZE isn't evenly divisible by 4
  221. ULONG DomainSid[SECURITY_MAX_SID_SIZE/sizeof(ULONG)+1];
  222. PSID DomainSidPtr = NULL;
  223. WCHAR UnicodeComputerNameBuffer[MAX_COMPUTERNAME_LENGTH+1];
  224. LPWSTR UnicodeComputerName = NULL;
  225. WCHAR UnicodeUserNameBuffer[NL_MAXIMUM_USER_NAME_LENGTH+1];
  226. LPWSTR UnicodeUserName = NULL;
  227. ULONG AllowableAccountControlBits = 0;
  228. DWORD NtVersion = LMNT_MESSAGE;
  229. DWORD NtVersionFlags = NETLOGON_NT_VERSION_5;
  230. ULONG Length = 0;
  231. SOCKADDR_IN SockAddrIn;
  232. //
  233. // Initialization.
  234. //
  235. *Response = NULL;
  236. *ResponseSize = 0;
  237. //
  238. // If caller is calling when the netlogon service isn't running,
  239. // tell it so.
  240. //
  241. if ( !NlStartNetlogonCall() ) {
  242. return STATUS_INVALID_PARAMETER;
  243. }
  244. //
  245. // Validate the client socket address.
  246. //
  247. if ( ClientSockAddr != NULL ) {
  248. if ( ((PSOCKADDR)ClientSockAddr)->sa_family != AF_INET ) {
  249. NlPrint((NL_CRITICAL,
  250. "I_NetlogonLdapLookupEx: DS passed us a SOCKADDR that wasn't AF_INET (ignoring it)\n" ));
  251. ClientSockAddr = NULL;
  252. } else {
  253. //
  254. // Force the port number to zero to avoid confusion later.
  255. SockAddrIn = *((PSOCKADDR_IN)ClientSockAddr);
  256. SockAddrIn.sin_port = 0;
  257. ClientSockAddr = &SockAddrIn;
  258. }
  259. }
  260. //
  261. // Parse the filter.
  262. //
  263. if ( LdapFilter != NULL ) {
  264. //
  265. // The first element of the filter must be an AND.
  266. //
  267. if ( LdapFilter->choice != and_chosen ) {
  268. NlPrint((NL_CRITICAL,
  269. "I_NetlogonLdapLookup: Filter doesn't have AND %ld\n",
  270. LdapFilter->choice ));
  271. Status = STATUS_INVALID_PARAMETER;
  272. goto Cleanup;
  273. }
  274. //
  275. // Loop through the AND'ed attributes.
  276. //
  277. //
  278. for ( CurrentAnd = LdapFilter->u.and;
  279. CurrentAnd != NULL;
  280. CurrentAnd = CurrentAnd->next ) {
  281. CurrentFilter = &CurrentAnd->value;
  282. if ( CurrentFilter->choice != equalityMatch_chosen ) {
  283. NlPrint((NL_CRITICAL,
  284. "I_NetlogonLdapLookup: Filter doesn't have EqualityMatch %ld\n",
  285. LdapFilter->choice ));
  286. Status = STATUS_INVALID_PARAMETER;
  287. goto Cleanup;
  288. }
  289. //
  290. // Handle DnsDomainName parameter.
  291. //
  292. if ( IsFilterName( CurrentFilter, NL_FILTER_DNS_DOMAIN_NAME ) ) {
  293. if ( CurrentFilter->u.equalityMatch.assertionValue.length == 0 ) {
  294. NlPrint((NL_CRITICAL,
  295. "I_NetlogonLdapLookup: Bad DnsDomainName\n" ));
  296. Status = STATUS_INVALID_PARAMETER;
  297. goto Cleanup;
  298. }
  299. //
  300. // Avoid leaking memory - there must be only one domain name specified
  301. //
  302. if ( DnsDomainName != NULL ) {
  303. NlPrint(( NL_CRITICAL,
  304. "I_NetlogonLdapLookup: Bad ping from %ws: multiple DnsDomainName\n",
  305. UnicodeComputerName ));
  306. Status = STATUS_INVALID_PARAMETER;
  307. goto Cleanup;
  308. }
  309. NetStatus = NetApiBufferAllocate(
  310. CurrentFilter->u.equalityMatch.assertionValue.length + sizeof(CHAR),
  311. (LPVOID *) &DnsDomainName );
  312. if ( NetStatus != NO_ERROR ) {
  313. Status = STATUS_NO_MEMORY;
  314. goto Cleanup;
  315. }
  316. RtlCopyMemory( DnsDomainName,
  317. CurrentFilter->u.equalityMatch.assertionValue.value,
  318. CurrentFilter->u.equalityMatch.assertionValue.length );
  319. DnsDomainName[ CurrentFilter->u.equalityMatch.assertionValue.length ] = '\0';
  320. //
  321. // Handle Host parameter.
  322. //
  323. } else if ( IsFilterName( CurrentFilter, NL_FILTER_HOST_NAME ) ) {
  324. //
  325. // Avoid leaking memory - there must be only one host name specified
  326. //
  327. if ( UnicodeComputerName != NULL ) {
  328. NlPrint(( NL_CRITICAL,
  329. "I_NetlogonLdapLookup: Bad ping from %ws: multiple UnicodeComputerName\n",
  330. UnicodeComputerName ));
  331. Status = STATUS_INVALID_PARAMETER;
  332. goto Cleanup;
  333. }
  334. NetStatus = FilterString( CurrentFilter,
  335. MAX_COMPUTERNAME_LENGTH+1,
  336. UnicodeComputerNameBuffer,
  337. &UnicodeComputerName );
  338. if ( NetStatus != NO_ERROR ) {
  339. NlPrint((NL_CRITICAL,
  340. "I_NetlogonLdapLookup: Bad UnicodeComputerName 0x%lx\n",
  341. NetStatus ));
  342. Status = STATUS_INVALID_PARAMETER;
  343. goto Cleanup;
  344. }
  345. //
  346. // Handle User parameter.
  347. //
  348. } else if ( IsFilterName( CurrentFilter, NL_FILTER_USER_NAME ) ) {
  349. //
  350. // Avoid leaking memory - there must be only one user name specified
  351. //
  352. if ( UnicodeUserName != NULL ) {
  353. NlPrint(( NL_CRITICAL,
  354. "I_NetlogonLdapLookup: Bad ping from %ws: multiple UnicodeUserName\n",
  355. UnicodeComputerName ));
  356. Status = STATUS_INVALID_PARAMETER;
  357. goto Cleanup;
  358. }
  359. NetStatus = FilterString( CurrentFilter,
  360. NL_MAXIMUM_USER_NAME_LENGTH+1,
  361. UnicodeUserNameBuffer,
  362. &UnicodeUserName );
  363. if ( NetStatus != NO_ERROR ) {
  364. NlPrint((NL_CRITICAL,
  365. "I_NetlogonLdapLookup: Bad UnicodeUserName 0x%lx\n",
  366. NetStatus ));
  367. Status = STATUS_INVALID_PARAMETER;
  368. goto Cleanup;
  369. }
  370. //
  371. // Handle AccountControlBits parameter.
  372. //
  373. } else if ( IsFilterName( CurrentFilter, NL_FILTER_ALLOWABLE_ACCOUNT_CONTROL ) ) {
  374. NetStatus = FilterBinary( CurrentFilter,
  375. sizeof(AllowableAccountControlBits),
  376. &AllowableAccountControlBits,
  377. &Length );
  378. if ( NetStatus != NO_ERROR || Length != sizeof(AllowableAccountControlBits) ) {
  379. NlPrint((NL_CRITICAL,
  380. "I_NetlogonLdapLookup: Bad AllowableAccountControl 0x%lx %lu\n",
  381. NetStatus,
  382. Length ));
  383. Status = STATUS_INVALID_PARAMETER;
  384. goto Cleanup;
  385. }
  386. //
  387. // Handle DomainSid parameter.
  388. //
  389. } else if ( IsFilterName( CurrentFilter, NL_FILTER_DOMAIN_SID ) ) {
  390. NetStatus = FilterBinary( CurrentFilter,
  391. sizeof(DomainSid),
  392. DomainSid,
  393. &Length );
  394. //
  395. // Check the length
  396. //
  397. if ( NetStatus != NO_ERROR ||
  398. !RtlValidSid(DomainSid) ||
  399. RtlLengthSid(DomainSid) != Length ) {
  400. NlPrint((NL_CRITICAL,
  401. "I_NetlogonLdapLookup: Bad DomainSid 0x%lx %ld\n",
  402. NetStatus,
  403. Length ));
  404. Status = STATUS_INVALID_PARAMETER;
  405. goto Cleanup;
  406. }
  407. DomainSidPtr = DomainSid;
  408. //
  409. // Handle DomainGuid parameter.
  410. //
  411. } else if ( IsFilterName( CurrentFilter, NL_FILTER_DOMAIN_GUID ) ) {
  412. NetStatus = FilterBinary( CurrentFilter,
  413. sizeof(DomainGuid),
  414. &DomainGuid,
  415. &Length );
  416. //
  417. // Check the length
  418. //
  419. if ( NetStatus != NO_ERROR ||
  420. Length != sizeof(GUID) ) {
  421. NlPrint((NL_CRITICAL,
  422. "I_NetlogonLdapLookup: Bad DomainGuid 0x%lx %ld\n",
  423. NetStatus,
  424. Length ));
  425. Status = STATUS_INVALID_PARAMETER;
  426. goto Cleanup;
  427. }
  428. DomainGuidPtr = &DomainGuid;
  429. //
  430. // Handle NtVersion parameter.
  431. //
  432. } else if ( IsFilterName( CurrentFilter, NL_FILTER_NT_VERSION ) ) {
  433. NetStatus = FilterBinary( CurrentFilter,
  434. sizeof(NtVersionFlags),
  435. &NtVersionFlags,
  436. &Length );
  437. if ( NetStatus != NO_ERROR || Length != sizeof(NtVersionFlags) ) {
  438. NlPrint((NL_CRITICAL,
  439. "I_NetlogonLdapLookup: Bad NtVersionFlags 0x%lx %ld\n",
  440. NetStatus,
  441. Length ));
  442. Status = STATUS_INVALID_PARAMETER;
  443. goto Cleanup;
  444. }
  445. //
  446. // Attributes we don't understand are ignored. That way clients
  447. // that are newer than this version can pass additional information
  448. // to newer DCs and not worry about breaking older DCs.
  449. //
  450. } else {
  451. NlPrint((NL_CRITICAL,
  452. "I_NetlogonLdapLookup: unrecognized parameter %.*s\n",
  453. CurrentFilter->u.equalityMatch.attributeDesc.length,
  454. CurrentFilter->u.equalityMatch.attributeDesc.value ));
  455. }
  456. }
  457. }
  458. //
  459. // Build the ping based on the queried information.
  460. //
  461. NetStatus = NlGetLocalPingResponse(
  462. L"UDP LDAP",
  463. TRUE, // LDAP ping
  464. NULL, // No Netbios domain name
  465. DnsDomainName,
  466. DomainGuidPtr,
  467. DomainSidPtr,
  468. FALSE, // Not PDC only
  469. UnicodeComputerName,
  470. UnicodeUserName,
  471. AllowableAccountControlBits,
  472. NtVersion,
  473. NtVersionFlags,
  474. (PSOCKADDR)ClientSockAddr,
  475. Response,
  476. ResponseSize );
  477. if ( NetStatus != NO_ERROR ) {
  478. Status = STATUS_INVALID_PARAMETER;
  479. goto Cleanup;
  480. }
  481. #if NETLOGONDBG
  482. NlpDumpBuffer( NL_MAILSLOT_TEXT, *Response, *ResponseSize );
  483. #endif // NETLOGONDBG
  484. Status = STATUS_SUCCESS;
  485. Cleanup:
  486. if ( DnsDomainName != NULL ) {
  487. NetApiBufferFree( DnsDomainName );
  488. }
  489. if ( UnicodeComputerName != NULL &&
  490. UnicodeComputerName != UnicodeComputerNameBuffer ) {
  491. NetApiBufferFree( UnicodeComputerName );
  492. }
  493. if ( UnicodeUserName != NULL &&
  494. UnicodeUserName != UnicodeUserNameBuffer ) {
  495. NetApiBufferFree( UnicodeUserName );
  496. }
  497. // Let netlogon service exit.
  498. NlEndNetlogonCall();
  499. return Status;
  500. }
  501. #ifdef __cplusplus
  502. } /* extern "C" */
  503. #endif /* __cplusplus */