Source code of Windows XP (NT5)
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.

5862 lines
136 KiB

  1. /*++
  2. Copyright (c) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. winrnr.c
  5. Abstract:
  6. Rnr provider for ActiveDirectory.
  7. Work items:
  8. 1) Need to support the NTDS Global catalog on LUP_DEEP from Root searches.
  9. 2) Need to add bind handle caching.
  10. Author:
  11. GlennC 23-Jul-1996
  12. Revision History:
  13. GlennC Added support for LUP_CONTAINERS in NSP2LookupServiceXXX
  14. functions.
  15. jamesg Jan 2001 cleanup, bug fixes, proper alignment
  16. jamesg May 2001 rewrite
  17. - 64-bit completely broken because 32-bit
  18. structures used as bervals
  19. - leaks
  20. - duplicate code
  21. - simplify flat buffer building macros
  22. - allow for sockaddrs other than IP4
  23. --*/
  24. #include <stdio.h>
  25. #include <nt.h>
  26. #include <ntrtl.h>
  27. #include <nturtl.h>
  28. #include <windows.h>
  29. #include <rpc.h>
  30. #include <rpcdce.h>
  31. #include <winsock2.h>
  32. #include <ws2spi.h>
  33. #include <wsipx.h>
  34. #include <svcguid.h>
  35. #include <rnraddrs.h>
  36. #include <align.h>
  37. #include <winldap.h>
  38. #include <windns.h> // alignment macro
  39. #include <dnslib.h> // flat buffer stuff, memory allocation
  40. //
  41. // RnR context
  42. //
  43. // Context we keep during a given RnR lookup session.
  44. //
  45. typedef struct
  46. {
  47. PLDAP pLdapServer;
  48. PLDAP pLdapGlobalCatalog;
  49. PWSTR DomainDN;
  50. PWSTR WinsockServicesDN;
  51. }
  52. RNR_CONNECTION, *PRNR_CONNECTION;
  53. typedef struct
  54. {
  55. DWORD Count;
  56. DWORD CurrentIndex;
  57. PWSTR Strings[0];
  58. }
  59. DN_ARRAY, *PDN_ARRAY;
  60. typedef struct
  61. {
  62. DWORD Signature;
  63. DWORD ControlFlags;
  64. DWORD CurrentDN;
  65. DWORD NumberOfProtocols;
  66. PWSTR pwsServiceName;
  67. PRNR_CONNECTION pRnrConnection;
  68. PDN_ARRAY pDnArray;
  69. PWSTR pwsContext;
  70. PAFPROTOCOLS pafpProtocols;
  71. PWSAVERSION pVersion;
  72. WSAVERSION WsaVersion;
  73. GUID ServiceClassGuid;
  74. GUID ProviderGuid;
  75. }
  76. RNR_LOOKUP, *PRNR_LOOKUP;
  77. //
  78. // WSANSCLASSINFO stored in berval
  79. //
  80. // ClassInfo blobs read and written to directory with
  81. // pointers replaced by offsets.
  82. //
  83. // Note: need to explicitly make this structure, because
  84. // the WSANSCLASSINFO struct is different sizes for
  85. // 32/64bit; this structure will match the 32-bit
  86. // WSANSCLASSINFO which have already been written to
  87. // the directory in Win2K deployments
  88. //
  89. typedef struct _ClassInfoAsBerval
  90. {
  91. DWORD NameOffset;
  92. DWORD dwNameSpace;
  93. DWORD dwValueType;
  94. DWORD dwValueSize;
  95. DWORD ValueOffset;
  96. }
  97. CLASSINFO_BERVAL, *PCLASSINFO_BERVAL;
  98. //
  99. // CSADDR stored in berval
  100. //
  101. // CSADDRs read and written to directory with
  102. // pointers replaced by offsets.
  103. //
  104. // Note: as with WSANSCLASSINFO above CSADDR can not
  105. // be used directly in both 32 and 64 bit. Make a structure
  106. // that explicitly uses offsets and matches the already
  107. // deployed 32-bit form.
  108. //
  109. typedef struct _CsaddrAsBerval
  110. {
  111. DWORD LocalZero;
  112. LONG LocalLength;
  113. DWORD RemoteZero;
  114. LONG RemoteLength;
  115. LONG iSocketType;
  116. LONG iProtocol;
  117. }
  118. CSADDR_BERVAL, *PCSADDR_BERVAL;
  119. //
  120. // RnR defines
  121. //
  122. #define RNR_SIGNATURE 0x7364736e // "nsds"
  123. #define RNR_SIGNATURE_FREE 0x65657266 // "free"
  124. #define LDAP_GLOBAL_CATALOG 3268
  125. //
  126. // Standard out-of-mem rcode
  127. //
  128. #define ERROR_NO_MEMORY WSA_NOT_ENOUGH_MEMORY
  129. //
  130. // Defs to straight pointer
  131. //
  132. typedef LPGUID PGUID;
  133. typedef LPWSASERVICECLASSINFOW PWSASERVICECLASSINFOW;
  134. typedef DWORD RNR_STATUS;
  135. #define GuidEqual(x,y) RtlEqualMemory( x, y, sizeof(GUID) )
  136. //
  137. // Debug printing
  138. //
  139. #ifdef DBG
  140. //#define WINRNR_PRINT( foo ) KdPrint( foo )
  141. #define WINRNR_PRINT( foo ) DNS_PRINT( foo )
  142. #else
  143. #define WINRNR_PRINT( foo )
  144. #endif
  145. #ifdef DBG
  146. #define DnsDbg_DnArray(h,p) Print_DnArray( DnsPR, NULL, (h), (p) )
  147. #define DnsDbg_RnrConnection(h,p) Print_RnrConnection( DnsPR, NULL, (h), (p) )
  148. #define DnsDbg_RnrLookup(h,p) Print_RnrLookup( DnsPR, NULL, (h), (p) )
  149. #else
  150. #define DnsDbg_DnArray(h,p)
  151. #define DnsDbg_RnrConnection(h,p)
  152. #define DnsDbg_RnrLookup(h,p)
  153. #endif
  154. //
  155. // LDAP search stuff
  156. // - DN pieces
  157. // - attributes
  158. // - filters
  159. //
  160. WCHAR g_NtdsContainer[] = L"Container";
  161. WCHAR g_CommonName[] = L"CN";
  162. WCHAR g_DisplayName[] = L"displayName";
  163. WCHAR g_Comment[] = L"description";
  164. WCHAR g_DefaultDn[] = L"defaultNamingContext";
  165. WCHAR g_ObjectClass[] = L"objectClass";
  166. WCHAR g_ObjectName[] = L"name";
  167. WCHAR g_ServiceClass[] = L"serviceClass";
  168. WCHAR g_ServiceClassId[] = L"serviceClassID";
  169. WCHAR g_ServiceClassInfo[] = L"serviceClassInfo";
  170. WCHAR g_ServiceInstance[] = L"serviceInstance";
  171. WCHAR g_ServiceVersion[] = L"serviceInstanceVersion";
  172. WCHAR g_WinsockAddresses[] = L"winsockAddresses";
  173. WCHAR g_WinsockServicesDn[] = L"CN=WinsockServices,CN=System,";
  174. WCHAR g_FilterObjectClass_ServiceClass[] = L"(objectClass=serviceClass)";
  175. WCHAR g_FilterObjectClass_ServiceInstance[] = L"(objectClass=serviceInstance)";
  176. WCHAR g_FilterObjectClass_Container[] = L"(objectClass=Container)";
  177. WCHAR g_FilterObjectClass_Star[] = L"(objectClass=*)";
  178. WCHAR g_FilterCnEquals[] = L"CN=";
  179. WCHAR g_FilterParenCnEquals[] = L"(CN=";
  180. WCHAR g_FilterParenServiceClassIdEquals[] = L"(serviceClassId=";
  181. WCHAR g_FilterParenServiceVersionEquals[] = L"(serviceVersion=";
  182. //
  183. // Access with #defines
  184. //
  185. #define NTDS_CONTAINER g_NtdsContainer
  186. #define COMMON_NAME g_CommonName
  187. #define DEFAULT_DOMAIN_DN g_DefaultDn
  188. #define OBJECT_CLASS g_ObjectClass
  189. #define OBJECT_COMMENT g_Comment
  190. #define OBJECT_NAME g_ObjectName
  191. #define SERVICE_CLASS g_ServiceClass
  192. #define SERVICE_CLASS_ID g_ServiceClassId
  193. #define SERVICE_CLASS_INFO g_ServiceClassInfo
  194. #define SERVICE_CLASS_NAME g_DisplayName
  195. #define SERVICE_COMMENT g_Comment
  196. #define SERVICE_INSTANCE g_ServiceInstance
  197. #define SERVICE_INSTANCE_NAME g_DisplayName
  198. #define SERVICE_VERSION g_ServiceVersion
  199. #define WINSOCK_ADDRESSES g_WinsockAddresses
  200. #define WINSOCK_SERVICES g_WinsockServicesDn
  201. // Filters
  202. #define FILTER_OBJECT_CLASS_SERVICE_CLASS g_FilterObjectClass_ServiceClass
  203. #define FILTER_OBJECT_CLASS_SERVICE_INSTANCE g_FilterObjectClass_ServiceInstance
  204. #define FILTER_OBJECT_CLASS_NTDS_CONTAINER g_FilterObjectClass_Container
  205. #define FILTER_OBJECT_CLASS_STAR g_FilterObjectClass_Star
  206. #define FILTER_CN_EQUALS g_FilterCnEquals
  207. #define FILTER_PAREN_CN_EQUALS g_FilterParenCnEquals
  208. #define FILTER_PAREN_SERVICE_CLASS_ID_EQUALS g_FilterParenServiceClassIdEquals
  209. #define FILTER_PAREN_SERVICE_VERSION_EQUALS g_FilterParenServiceVersionEquals
  210. //
  211. // GUID generated by uuidgen.exe for provider identifer,
  212. // (3b2637ee-e580-11cf-a555-00c04fd8d4ac)
  213. //
  214. GUID g_NtdsProviderGuid =
  215. {
  216. 0x3b2637ee,
  217. 0xe580,
  218. 0x11cf,
  219. {0xa5, 0x55, 0x00, 0xc0, 0x4f, 0xd8, 0xd4, 0xac}
  220. };
  221. WCHAR g_NtdsProviderName[] = L"NTDS";
  222. WCHAR g_NtdsProviderPath[] = L"%SystemRoot%\\System32\\winrnr.dll";
  223. PWSTR g_pHostName = NULL;
  224. PWSTR g_pFullName = NULL;
  225. DWORD g_TlsIndex;
  226. GUID HostAddrByInetStringGuid = SVCID_INET_HOSTADDRBYINETSTRING;
  227. GUID ServiceByNameGuid = SVCID_INET_SERVICEBYNAME;
  228. GUID HostAddrByNameGuid = SVCID_INET_HOSTADDRBYNAME;
  229. GUID HostNameGuid = SVCID_HOSTNAME;
  230. //
  231. // Heap
  232. //
  233. #define ALLOC_HEAP_ZERO( size ) Dns_AllocZero( size )
  234. #define ALLOC_HEAP( size ) Dns_Alloc( size )
  235. #define FREE_HEAP( p ) Dns_Free( p )
  236. #ifdef DBG
  237. //
  238. // Debug print utils
  239. //
  240. VOID
  241. Print_DnArray(
  242. IN PRINT_ROUTINE PrintRoutine,
  243. IN PPRINT_CONTEXT PrintContext,
  244. IN PSTR pszHeader,
  245. IN PDN_ARRAY pDnArray
  246. )
  247. /*++
  248. Routine Description:
  249. Print DN array
  250. Arguments:
  251. pDnArray -- DN array to free
  252. Return Value:
  253. None
  254. --*/
  255. {
  256. DWORD iter;
  257. if ( !pszHeader )
  258. {
  259. pszHeader = "DN Array:";
  260. }
  261. if ( !pDnArray )
  262. {
  263. PrintRoutine(
  264. PrintContext,
  265. "%s NULL DN Array!\n",
  266. pszHeader );
  267. return;
  268. }
  269. DnsPrint_Lock();
  270. PrintRoutine(
  271. PrintContext,
  272. "%s\n"
  273. "\tPtr = %p\n"
  274. "\tCount = %d\n"
  275. "\tStrings:\n",
  276. pszHeader,
  277. pDnArray,
  278. pDnArray->Count );
  279. for ( iter = 0; iter < pDnArray->Count; iter++ )
  280. {
  281. PrintRoutine(
  282. PrintContext,
  283. "\t\tDN[%d] %S\n",
  284. iter,
  285. pDnArray->Strings[iter] );
  286. }
  287. DnsPrint_Unlock();
  288. }
  289. VOID
  290. Print_RnrConnection(
  291. IN PRINT_ROUTINE PrintRoutine,
  292. IN PPRINT_CONTEXT PrintContext,
  293. IN PSTR pszHeader,
  294. IN PRNR_CONNECTION pRnrCon
  295. )
  296. /*++
  297. Routine Description:
  298. Print RnR connection info.
  299. Arguments:
  300. pRnrCon -- Rnr connection blob
  301. Return Value:
  302. None
  303. --*/
  304. {
  305. if ( !pszHeader )
  306. {
  307. pszHeader = "RnR Connection:";
  308. }
  309. if ( !pRnrCon )
  310. {
  311. PrintRoutine(
  312. PrintContext,
  313. "%s NULL RnR Connection!\n",
  314. pszHeader );
  315. return;
  316. }
  317. PrintRoutine(
  318. PrintContext,
  319. "%s\n"
  320. "\tPtr = %p\n"
  321. "\tpLdap = %p\n"
  322. "\tpLdap GC = %p\n"
  323. "\tDomain DN = %S\n"
  324. "\tWsockServicesDN = %S\n",
  325. pszHeader,
  326. pRnrCon,
  327. pRnrCon->pLdapServer,
  328. pRnrCon->pLdapGlobalCatalog,
  329. pRnrCon->DomainDN,
  330. pRnrCon->WinsockServicesDN
  331. );
  332. }
  333. VOID
  334. Print_RnrLookup(
  335. IN PRINT_ROUTINE PrintRoutine,
  336. IN PPRINT_CONTEXT PrintContext,
  337. IN PSTR pszHeader,
  338. IN PRNR_LOOKUP pRnr
  339. )
  340. /*++
  341. Routine Description:
  342. Print RnR lookup blob.
  343. Arguments:
  344. pRnr -- Rnr lookup blob
  345. Return Value:
  346. None
  347. --*/
  348. {
  349. CHAR serviceGuidBuffer[ GUID_STRING_BUFFER_LENGTH ];
  350. CHAR providerGuidBuffer[ GUID_STRING_BUFFER_LENGTH ];
  351. if ( !pszHeader )
  352. {
  353. pszHeader = "RnR Lookup:";
  354. }
  355. if ( !pRnr )
  356. {
  357. PrintRoutine(
  358. PrintContext,
  359. "%s NULL RnR Lookup!\n",
  360. pszHeader );
  361. return;
  362. }
  363. // convert GUIDs to strings
  364. DnsStringPrint_Guid(
  365. serviceGuidBuffer,
  366. &pRnr->ServiceClassGuid
  367. );
  368. DnsStringPrint_Guid(
  369. providerGuidBuffer,
  370. &pRnr->ProviderGuid
  371. );
  372. DnsPrint_Lock();
  373. PrintRoutine(
  374. PrintContext,
  375. "%s\n"
  376. "\tPtr = %p\n"
  377. "\tSig = %08x\n"
  378. "\tCntrl Flags = %08x\n"
  379. "\tService Name = %S\n"
  380. "\tpConnection = %p\n"
  381. "\tpDnArray = %p\n"
  382. "\tDN Index = %d\n"
  383. "\tClass GUID = %s\n"
  384. "\tProvider GUID = %s\n"
  385. "\tpContext = %S\n"
  386. "\tVersion = %p %08x %d\n"
  387. "\tpProtocols = %p\n"
  388. "\tNum Protocols = %d\n",
  389. pszHeader,
  390. pRnr,
  391. pRnr->Signature,
  392. pRnr->ControlFlags,
  393. pRnr->pwsServiceName,
  394. pRnr->pRnrConnection,
  395. pRnr->pDnArray,
  396. pRnr->CurrentDN,
  397. serviceGuidBuffer,
  398. providerGuidBuffer,
  399. pRnr->pwsContext,
  400. pRnr->pVersion,
  401. pRnr->WsaVersion.dwVersion,
  402. pRnr->WsaVersion.ecHow,
  403. pRnr->pafpProtocols,
  404. pRnr->NumberOfProtocols
  405. );
  406. if ( pRnr->pRnrConnection )
  407. {
  408. Print_RnrConnection(
  409. PrintRoutine,
  410. PrintContext,
  411. NULL,
  412. pRnr->pRnrConnection );
  413. }
  414. if ( pRnr->pDnArray )
  415. {
  416. Print_DnArray(
  417. PrintRoutine,
  418. PrintContext,
  419. NULL,
  420. pRnr->pDnArray );
  421. }
  422. if ( pRnr->pafpProtocols )
  423. {
  424. DnsPrint_AfProtocolsArray(
  425. PrintRoutine,
  426. PrintContext,
  427. "\tProtocol array:",
  428. pRnr->pafpProtocols,
  429. pRnr->NumberOfProtocols );
  430. }
  431. PrintRoutine(
  432. PrintContext,
  433. "\n" );
  434. DnsPrint_Unlock();
  435. }
  436. #endif
  437. //
  438. // Basic utils
  439. //
  440. PDN_ARRAY
  441. AllocDnArray(
  442. IN DWORD Count
  443. )
  444. /*++
  445. Routine Description:
  446. Create DN array
  447. Arguments:
  448. Count -- string count to handle
  449. Return Value:
  450. None
  451. --*/
  452. {
  453. PDN_ARRAY parray;
  454. //
  455. // free strings in array
  456. //
  457. parray = (PDN_ARRAY) ALLOC_HEAP_ZERO(
  458. sizeof(*parray) +
  459. Count*sizeof(PSTR) );
  460. if ( parray )
  461. {
  462. parray->Count = Count;
  463. }
  464. return parray;
  465. }
  466. VOID
  467. FreeDnArray(
  468. IN OUT PDN_ARRAY pDnArray
  469. )
  470. /*++
  471. Routine Description:
  472. Free DN array
  473. Arguments:
  474. pDnArray -- DN array to free
  475. Return Value:
  476. None
  477. --*/
  478. {
  479. DWORD iter;
  480. if ( !pDnArray )
  481. {
  482. return;
  483. }
  484. //
  485. // free strings in array
  486. //
  487. for ( iter = 0; iter < pDnArray->Count; iter++ )
  488. {
  489. PWSTR pstr = pDnArray->Strings[iter];
  490. if ( pstr )
  491. {
  492. FREE_HEAP( pstr );
  493. }
  494. }
  495. FREE_HEAP( pDnArray );
  496. }
  497. RNR_STATUS
  498. BuildDnArrayFromResults(
  499. IN OUT PLDAP pLdap,
  500. IN PLDAPMessage pLdapResults,
  501. OUT PDWORD pdwCount, OPTIONAL
  502. OUT PDN_ARRAY * ppDnArray OPTIONAL
  503. )
  504. /*++
  505. Routine Description:
  506. Build DN array from LDAP results
  507. Arguments:
  508. pLdap -- LDAP connection
  509. pLdapResults -- LDAP results from search
  510. pdwCount -- addr to receive count if getting count
  511. ppDnArray -- addr to receive ptr to DN array
  512. if not given, no DN array built
  513. Return Value:
  514. NO_ERROR if successful.
  515. ErrorCode on memory allocation failure.
  516. --*/
  517. {
  518. DWORD status;
  519. DWORD count;
  520. PDN_ARRAY pdnArray = NULL;
  521. LDAPMessage * pnext;
  522. DWORD iter;
  523. DNSDBG( TRACE, (
  524. "BuildDnArrayFromResults()\n"
  525. "\tpLdap = %p\n"
  526. "\tpResults = %p\n"
  527. "\tpCount OUT = %p\n"
  528. "\tpDnArray OUT = %p\n",
  529. pLdap,
  530. pLdapResults,
  531. pdwCount,
  532. ppDnArray ));
  533. //
  534. // count search hits
  535. //
  536. count = ldap_count_entries(
  537. pLdap,
  538. pLdapResults );
  539. if ( count == 0 || !ppDnArray )
  540. {
  541. status = NO_ERROR;
  542. goto Done;
  543. }
  544. //
  545. // build DN array from ldap results
  546. // - note that allocated strings are IN dnarray
  547. //
  548. pdnArray = AllocDnArray( count );
  549. if ( !pdnArray )
  550. {
  551. status = ERROR_NO_MEMORY;
  552. goto Done;
  553. }
  554. for ( pnext = ldap_first_entry( pLdap, pLdapResults ), iter=0;
  555. pnext != NULL;
  556. pnext = ldap_next_entry( pLdap, pnext ), iter++ )
  557. {
  558. PWSTR pnextDn = ldap_get_dn( pLdap, pnext );
  559. PWSTR pdn;
  560. pdn = Dns_CreateStringCopy_W( pnextDn );
  561. ldap_memfree( pnextDn );
  562. if ( !pdn )
  563. {
  564. FREE_HEAP( pdnArray );
  565. pdnArray = NULL;
  566. status = ERROR_NO_MEMORY;
  567. goto Done;
  568. }
  569. if ( iter >= count )
  570. {
  571. DNS_ASSERT( FALSE );
  572. break;
  573. }
  574. pdnArray->Strings[iter] = pdn;
  575. }
  576. status = NO_ERROR;
  577. Done:
  578. if ( ppDnArray )
  579. {
  580. *ppDnArray = pdnArray;
  581. }
  582. if ( pdwCount )
  583. {
  584. *pdwCount = count;
  585. }
  586. IF_DNSDBG( TRACE )
  587. {
  588. DnsDbg_Lock();
  589. DNS_PRINT((
  590. "Leave BuildDnArrayFromResults() => %d\n"
  591. "\tcount = %d\n",
  592. status,
  593. count ));
  594. DnsDbg_DnArray(
  595. NULL,
  596. pdnArray );
  597. DnsDbg_Unlock();
  598. }
  599. return status;
  600. }
  601. PWSTR
  602. CreateFilterElement(
  603. IN PBYTE pBlob,
  604. IN DWORD BlobLength
  605. )
  606. /*++
  607. Routine Description:
  608. Create filter element for flat blob.
  609. Arguments:
  610. pBlob -- ptr to blob
  611. BlobLength -- length
  612. Return Value:
  613. Ptr to allocated filter element.
  614. NULL on error.
  615. --*/
  616. {
  617. PWSTR pfilter;
  618. DWORD size;
  619. DNSDBG( TRACE, (
  620. "CreateFilterElement( %p, %d )\n",
  621. pBlob,
  622. BlobLength ));
  623. //
  624. // get size of filter string
  625. //
  626. // DCR: hard to believe the size should go *WCHAR
  627. // seems like that would be taken care of
  628. //
  629. size = ldap_escape_filter_element(
  630. pBlob,
  631. BlobLength,
  632. NULL, // no buffer
  633. 0 );
  634. size *= sizeof(WCHAR);
  635. pfilter = ALLOC_HEAP_ZERO( size );
  636. if ( !pfilter )
  637. {
  638. SetLastError( ERROR_NO_MEMORY );
  639. return NULL;
  640. }
  641. ldap_escape_filter_element(
  642. pBlob,
  643. BlobLength,
  644. pfilter,
  645. size );
  646. DNSDBG( TRACE, (
  647. "Leave CreateFilterElement() => %S\n",
  648. pfilter ));
  649. return pfilter;
  650. }
  651. RNR_STATUS
  652. SetError(
  653. IN RNR_STATUS dwError
  654. )
  655. /*++
  656. Routine Description:
  657. Wraps SetLastError() and SOCKET_ERROR return.
  658. Arguments:
  659. dwError -- error code
  660. Return Value:
  661. NO_ERROR if dwError==NO_ERROR
  662. SOCKET_ERROR on any other error.
  663. --*/
  664. {
  665. if ( dwError )
  666. {
  667. SetLastError( dwError );
  668. return( (DWORD) SOCKET_ERROR );
  669. }
  670. else
  671. {
  672. return( NO_ERROR );
  673. }
  674. }
  675. BOOL
  676. IsNameADn(
  677. IN PWSTR szName,
  678. OUT PWSTR * ppwsRdn,
  679. OUT PWSTR * ppwsContext
  680. )
  681. {
  682. #define NTDS_MAX_DN_LEN 1024
  683. DWORD status = NO_ERROR;
  684. WCHAR szNameBuf[ NTDS_MAX_DN_LEN ];
  685. PWSTR szTemp;
  686. PWSTR szComma = NULL;
  687. DWORD i;
  688. BOOL fQuoted = FALSE;
  689. DNSDBG( TRACE, (
  690. "IsNameADn( %S )\n",
  691. szName ));
  692. wcsncpy( szNameBuf, szName, NTDS_MAX_DN_LEN );
  693. szNameBuf[ NTDS_MAX_DN_LEN-1 ] = 0;
  694. szTemp = szNameBuf;
  695. for ( i = 0; i < wcslen( szName ); i++ )
  696. {
  697. if ( szTemp[i] == L',' )
  698. {
  699. if ( !fQuoted )
  700. {
  701. szComma = &szTemp[i];
  702. break;
  703. }
  704. }
  705. if ( szTemp[i] == L'\"' )
  706. {
  707. #if 0
  708. // this one is a classic ... saving for posterity
  709. if ( fQuoted )
  710. fQuoted = FALSE;
  711. else
  712. fQuoted = TRUE;
  713. #endif
  714. fQuoted = !fQuoted;
  715. }
  716. }
  717. if ( i >= wcslen( szName ) )
  718. {
  719. return FALSE;
  720. }
  721. szComma[0] = 0;
  722. szComma++;
  723. if ( szComma[0] == L' ' )
  724. szComma++;
  725. if ( wcslen( szComma ) == 0 )
  726. return FALSE;
  727. *ppwsContext = (LPWSTR) ALLOC_HEAP_ZERO( ( wcslen( szComma ) + 1 ) *
  728. sizeof( WCHAR ) );
  729. if ( *ppwsContext == NULL )
  730. {
  731. return FALSE;
  732. }
  733. wcscpy( *ppwsContext, szComma );
  734. *ppwsRdn = (LPWSTR) ALLOC_HEAP_ZERO( ( wcslen( szNameBuf ) + 1 ) *
  735. sizeof( WCHAR ) );
  736. if ( *ppwsRdn == NULL )
  737. {
  738. (void) FREE_HEAP( *ppwsContext );
  739. *ppwsContext = NULL;
  740. return FALSE;
  741. }
  742. if ( szNameBuf[0] == L'C' || szNameBuf[0] == L'c' &&
  743. szNameBuf[1] == L'N' || szNameBuf[1] == L'n' &&
  744. szNameBuf[2] == L'=' )
  745. {
  746. wcscpy( *ppwsRdn, szNameBuf + 3 );
  747. }
  748. else
  749. {
  750. wcscpy( *ppwsRdn, szNameBuf );
  751. }
  752. return TRUE;
  753. }
  754. //
  755. // Recursion locking
  756. //
  757. // Idea here is to keep LDAP calls from recursing back
  758. // into these functions through ConnectToDefaultDirectory
  759. // Simply set TLS pointer to one when do LDAP search and
  760. // test in ConnectToDefaultDirectory(), quiting if already
  761. // set.
  762. //
  763. BOOL
  764. GetRecurseLock(
  765. IN PSTR pszFunctionName
  766. )
  767. {
  768. if ( TlsSetValue( g_TlsIndex, (LPVOID) 1 ) == FALSE )
  769. {
  770. WINRNR_PRINT((
  771. "WINRNR!%s - TlsSetValue( %d, 1 ) failed!\n"
  772. "\terror code: 0%x\n",
  773. pszFunctionName,
  774. g_TlsIndex,
  775. GetLastError() ));
  776. return( FALSE );
  777. }
  778. return( TRUE );
  779. }
  780. BOOL
  781. ReleaseRecurseLock(
  782. IN PSTR pszFunctionName
  783. )
  784. {
  785. if ( TlsSetValue( g_TlsIndex, NULL ) == FALSE )
  786. {
  787. WINRNR_PRINT((
  788. "WINRNR!%s - TlsSetValue( %d, NULL ) failed!\n"
  789. "\terror code: 0%x\n",
  790. pszFunctionName,
  791. g_TlsIndex,
  792. GetLastError() ));
  793. return( FALSE );
  794. }
  795. return( TRUE );
  796. }
  797. BOOL
  798. IsRecurseLocked(
  799. VOID
  800. )
  801. {
  802. return TlsGetValue( g_TlsIndex ) ? TRUE : FALSE;
  803. }
  804. RNR_STATUS
  805. DoLdapSearch(
  806. IN PSTR pszFunction,
  807. IN BOOL fLocked,
  808. IN PLDAP pLdap,
  809. IN PWSTR pwsDN,
  810. IN DWORD Flag,
  811. IN PWSTR pwsFilter,
  812. IN PWSTR * Attributes,
  813. OUT PLDAPMessage * ppResults
  814. )
  815. /*++
  816. Routine Description:
  817. Do ldap search.
  818. Wrapper function to do ldap search with recurse locking
  819. and debug print.
  820. Arguments:
  821. pszFunction -- function calling in
  822. fLocked -- already recurse locked
  823. LDAP search params:
  824. pLdap -- LDAP connection
  825. pwsDN -- DN to search at
  826. Flag -- search flag
  827. pwsFilter -- filter
  828. Attributes -- attribute array
  829. ppResults -- addr to recv ptr to result message
  830. caller must free
  831. Return Value:
  832. NO_ERROR if successful.
  833. WSAEFAULT if buffer too small.
  834. ErrorCode on failure.
  835. --*/
  836. {
  837. RNR_STATUS status;
  838. IF_DNSDBG( TRACE )
  839. {
  840. DnsDbg_Lock();
  841. DNSDBG( TRACE, (
  842. "DoLdapSearch()\n"
  843. "\tFunction = %s\n"
  844. "\tLocked = %d\n"
  845. "\tLDAP search params:\n"
  846. "\tpLdap = %p\n"
  847. "\tDN = %S\n"
  848. "\tFlags = %08x\n"
  849. "\tpFilter = %S\n"
  850. "\tppResults = %p\n",
  851. pszFunction,
  852. fLocked,
  853. pLdap,
  854. pwsDN,
  855. Flag,
  856. pwsFilter,
  857. ppResults ));
  858. DnsDbg_StringArray(
  859. " Search Attributes:",
  860. (PSTR *) Attributes,
  861. 0, // count unknown, array NULL terminated
  862. TRUE // in unicode
  863. );
  864. DnsDbg_Unlock();
  865. }
  866. //
  867. // search
  868. //
  869. if ( !fLocked &&
  870. !GetRecurseLock( pszFunction ) )
  871. {
  872. status = ERROR_LOCK_FAILED;
  873. goto Exit;
  874. }
  875. status = ldap_search_s(
  876. pLdap,
  877. pwsDN,
  878. Flag,
  879. pwsFilter,
  880. Attributes,
  881. 0,
  882. ppResults );
  883. if ( !fLocked &&
  884. !ReleaseRecurseLock( pszFunction ) )
  885. {
  886. status = ERROR_LOCK_FAILED;
  887. goto Exit;
  888. }
  889. if ( status != NO_ERROR && !*ppResults )
  890. {
  891. WINRNR_PRINT((
  892. "WINRNR!%s -- ldap_search_s() failed 0%x\n",
  893. pszFunction,
  894. status ));
  895. DNSDBG( ANY, (
  896. "ERROR: ldap_search_s() Failed! => %d\n"
  897. "\tIn function %s\n"
  898. "\tDN %S\n"
  899. "\tFlag %08x\n"
  900. "\tFilter %S\n",
  901. status,
  902. pszFunction,
  903. pwsDN,
  904. Flag,
  905. pwsFilter ));
  906. }
  907. Exit:
  908. DNSDBG( TRACE, (
  909. "Leave DoLdapSearch() => %d\n",
  910. status ));
  911. return status;
  912. }
  913. VOID
  914. DisconnectFromLDAPDirectory(
  915. IN OUT PRNR_CONNECTION * ppRnrConnection
  916. )
  917. /*++
  918. Routine Description:
  919. Disconnect and cleanup RnR connection to directory.
  920. Arguments:
  921. pCsAddr -- ptr to CSADDR buffer to write
  922. pBerval -- ptr to berval
  923. NumberOfProtocols -- number of protocols in protocol array
  924. pafpProtocols -- protocol array
  925. Return Value:
  926. None
  927. --*/
  928. {
  929. DNSDBG( TRACE, (
  930. "DisconnectFromLDAPDirectory( %p (%p) )\n",
  931. ppRnrConnection,
  932. (ppRnrConnection) ? *ppRnrConnection : NULL ));
  933. if ( ppRnrConnection )
  934. {
  935. PRNR_CONNECTION prnr = *ppRnrConnection;
  936. if ( prnr )
  937. {
  938. ldap_unbind( prnr->pLdapServer );
  939. ldap_unbind( prnr->pLdapGlobalCatalog );
  940. FREE_HEAP( prnr->WinsockServicesDN );
  941. FREE_HEAP( prnr->DomainDN );
  942. FREE_HEAP( prnr );
  943. *ppRnrConnection = NULL;
  944. }
  945. }
  946. }
  947. RNR_STATUS
  948. ConnectToDefaultLDAPDirectory(
  949. IN BOOL fNeedGlobalCatalog,
  950. OUT PRNR_CONNECTION * ppRnrConnection
  951. )
  952. /*++
  953. Routine Description:
  954. Connect to directory.
  955. Arguments:
  956. fNeedGlobalCatalog -- TRUE if need to connect to GC
  957. ppRnrConnection -- addr to recv connection blob
  958. Return Value:
  959. NO_ERROR if successful.
  960. ErrorCode on failure.
  961. --*/
  962. {
  963. RNR_STATUS status = NO_ERROR;
  964. PRNR_CONNECTION prnr = NULL;
  965. PLDAP pldap = NULL;
  966. PWSTR pstr;
  967. DWORD count = 0;
  968. BOOL frecurseLocked = FALSE;
  969. LDAPMessage * results = NULL;
  970. LDAPMessage * object;
  971. PWSTR * ppvalue = NULL;
  972. PWSTR stringArray[4];
  973. PWSTR attrs[3] = { COMMON_NAME,
  974. DEFAULT_DOMAIN_DN,
  975. NULL };
  976. DNSDBG( TRACE, (
  977. "ConnectToDefaultLDAPDirectory()\n"
  978. "\tNeed global catalog = %d\n"
  979. "\tPtr to get Rnr conn = %p\n",
  980. fNeedGlobalCatalog,
  981. ppRnrConnection ));
  982. //
  983. // allocate blob of connection info
  984. //
  985. if ( ppRnrConnection == NULL )
  986. {
  987. return( WSA_INVALID_PARAMETER );
  988. }
  989. prnr = (PRNR_CONNECTION) ALLOC_HEAP_ZERO( sizeof(RNR_CONNECTION) );
  990. *ppRnrConnection = prnr;
  991. if ( !prnr )
  992. {
  993. return( WSA_NOT_ENOUGH_MEMORY );
  994. }
  995. //
  996. // being called recursively -- bail
  997. //
  998. if ( IsRecurseLocked() )
  999. {
  1000. status = WSAEFAULT;
  1001. goto Exit;
  1002. }
  1003. if ( !GetRecurseLock( "ConnectToDefaultLDAPDirectory" ) )
  1004. {
  1005. status = WSAEFAULT;
  1006. goto Exit;
  1007. }
  1008. frecurseLocked = TRUE;
  1009. //
  1010. // We need to keep the TLS value non-zero not just on the open but also
  1011. // across the bind and any other ldap calls for that matter. This is
  1012. // because the LDAP bind may do a reverse name lookup, in which case
  1013. // we'd come looping through here.
  1014. //
  1015. pldap = ldap_open( NULL, LDAP_PORT );
  1016. prnr->pLdapServer = pldap;
  1017. if ( fNeedGlobalCatalog )
  1018. {
  1019. prnr->pLdapGlobalCatalog = ldap_open( NULL, LDAP_GLOBAL_CATALOG );
  1020. }
  1021. if ( !pldap )
  1022. {
  1023. DNSDBG( TRACE, ( "Failed ldap_open() of default directory!\n" ));
  1024. status = WSAEHOSTUNREACH;
  1025. goto Exit;
  1026. }
  1027. //
  1028. // If fNeedGlobalCatalog was TRUE and ldap_open failed against the
  1029. // GC server, don't bother about returning with error. We can still
  1030. // use the pldap handle.
  1031. //
  1032. // End of comment.
  1033. //
  1034. status = ldap_bind_s(
  1035. pldap,
  1036. NULL,
  1037. NULL,
  1038. LDAP_AUTH_SSPI );
  1039. if ( status )
  1040. {
  1041. DNSDBG( TRACE, (
  1042. "Failed ldap_bind_s() => %d\n",
  1043. status ));
  1044. status = WSAENOTCONN;
  1045. goto Exit;
  1046. }
  1047. //
  1048. // for the server that we are connected to, get the DN of the Domain
  1049. //
  1050. // need some general error code -- not WSAEFAULT
  1051. //
  1052. status = DoLdapSearch(
  1053. "ConnectToDefaultDirectory",
  1054. TRUE, // already locked
  1055. pldap,
  1056. NULL,
  1057. LDAP_SCOPE_BASE,
  1058. FILTER_OBJECT_CLASS_STAR,
  1059. attrs,
  1060. &results );
  1061. frecurseLocked = FALSE;
  1062. if ( !ReleaseRecurseLock( "ConnectToDefaultLDAPDirectory" ) )
  1063. {
  1064. status = ERROR_LOCK_FAILED;
  1065. goto Exit;
  1066. }
  1067. if ( status && !results )
  1068. {
  1069. status = WSAEFAULT;
  1070. goto Exit;
  1071. }
  1072. //
  1073. // count results
  1074. // - searched with flag LDAP_OBJECT_BASE should have one object
  1075. //
  1076. count = ldap_count_entries(
  1077. pldap,
  1078. results );
  1079. if ( count == 0 )
  1080. {
  1081. DNSDBG( TRACE, (
  1082. "No entries found in base search()\n" ));
  1083. status = WSATYPE_NOT_FOUND;
  1084. goto Exit;
  1085. }
  1086. DNS_ASSERT( count == 1 );
  1087. //
  1088. // get object from results
  1089. //
  1090. object = ldap_first_entry(
  1091. pldap,
  1092. results );
  1093. if ( !object )
  1094. {
  1095. DNSDBG( TRACE, ( "Failed ldap_first_entry()\n" ));
  1096. status = WSANO_DATA;
  1097. goto Exit;
  1098. }
  1099. //
  1100. // read the defaultDomainDN base attribute
  1101. //
  1102. ppvalue = ldap_get_values(
  1103. pldap,
  1104. object,
  1105. DEFAULT_DOMAIN_DN );
  1106. if ( !ppvalue )
  1107. {
  1108. DNSDBG( TRACE, ( "Failed ldap_get_values()\n" ));
  1109. status = WSANO_DATA;
  1110. goto Exit;
  1111. }
  1112. //
  1113. // create DNs
  1114. // - winsock services \ default domain
  1115. // - domain
  1116. //
  1117. stringArray[0] = WINSOCK_SERVICES;
  1118. stringArray[1] = ppvalue[0];
  1119. stringArray[2] = NULL;
  1120. pstr = Dns_CreateConcatenatedString_W( stringArray );
  1121. if ( !pstr )
  1122. {
  1123. status = WSA_NOT_ENOUGH_MEMORY;
  1124. goto Exit;
  1125. }
  1126. prnr->WinsockServicesDN = pstr;
  1127. pstr = Dns_CreateStringCopy_W( ppvalue[0] );
  1128. if ( !pstr )
  1129. {
  1130. status = WSA_NOT_ENOUGH_MEMORY;
  1131. goto Exit;
  1132. }
  1133. prnr->DomainDN = pstr;
  1134. status = NO_ERROR;
  1135. Exit:
  1136. if ( frecurseLocked )
  1137. {
  1138. ReleaseRecurseLock( "ConnectToDefaultLDAPDirectory" );
  1139. }
  1140. ldap_value_free( ppvalue );
  1141. ldap_msgfree( results );
  1142. if ( status != NO_ERROR )
  1143. {
  1144. DisconnectFromLDAPDirectory( ppRnrConnection );
  1145. DNS_ASSERT( *ppRnrConnection == NULL );
  1146. }
  1147. DNSDBG( TRACE, (
  1148. "Leaving ConnectToDefaultLDAPDirectory() => %d\n",
  1149. status ));
  1150. IF_DNSDBG( TRACE )
  1151. {
  1152. if ( status == NO_ERROR )
  1153. {
  1154. DnsDbg_RnrConnection(
  1155. "New RnR connection:",
  1156. *ppRnrConnection );
  1157. }
  1158. }
  1159. return( status );
  1160. }
  1161. VOID
  1162. FreeRnrLookup(
  1163. IN OUT PRNR_LOOKUP pRnr
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. Free RnR lookup blob.
  1168. Arguments:
  1169. pRnr -- ptr to Rnr lookup blob
  1170. Return Value:
  1171. None
  1172. --*/
  1173. {
  1174. DNSDBG( TRACE, (
  1175. "FreeRnrLookup( %p )\n",
  1176. pRnr ));
  1177. if ( !pRnr )
  1178. {
  1179. return;
  1180. }
  1181. // disconnect from directory
  1182. if ( pRnr->pRnrConnection )
  1183. {
  1184. DisconnectFromLDAPDirectory( &pRnr->pRnrConnection );
  1185. }
  1186. // free subfields
  1187. FreeDnArray( pRnr->pDnArray );
  1188. Dns_Free( pRnr->pwsServiceName );
  1189. Dns_Free( pRnr->pwsContext );
  1190. Dns_Free( pRnr->pafpProtocols );
  1191. // specifically invalidate sig to help catch
  1192. // multiple frees
  1193. pRnr->Signature = RNR_SIGNATURE_FREE;
  1194. FREE_HEAP( pRnr );
  1195. }
  1196. //
  1197. // CSADDR read\write routines
  1198. //
  1199. RNR_STATUS
  1200. ModifyAddressInServiceInstance(
  1201. IN PRNR_CONNECTION pRnrConnection,
  1202. IN PWSTR pwsDn,
  1203. IN PCSADDR_INFO pCsAddr,
  1204. IN BOOL fAdd
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. Modify address (CSADDR) in service instance.
  1209. Arguments:
  1210. pRnrConnection -- RnR connection
  1211. pwsDn -- DN to make mod at
  1212. pCsAddr -- CSADDR for mode
  1213. fAdd -- TRUE for add, FALSE for delete
  1214. Return Value:
  1215. NO_ERROR if successful.
  1216. ErrorCode on failure.
  1217. --*/
  1218. {
  1219. RNR_STATUS status = NO_ERROR;
  1220. LDAPMod * modPtrArray[2];
  1221. LDAPMod mod;
  1222. PLDAP_BERVAL modBValues[2];
  1223. LDAP_BERVAL berval;
  1224. DWORD lenBerval;
  1225. DWORD lenLocal;
  1226. DWORD lenRemote;
  1227. DWORD offset;
  1228. DWORD op;
  1229. PCSADDR_BERVAL pcsaddrBerval;
  1230. DNSDBG( TRACE, (
  1231. "ModifyAddressInServiceInstance()\n"
  1232. "\tpRnrCon = %p\n"
  1233. "\tpwsDN = %S\n"
  1234. "\tpCsAddr = %p\n"
  1235. "\tfAdd = %d\n",
  1236. pRnrConnection,
  1237. pwsDn,
  1238. pCsAddr,
  1239. fAdd ));
  1240. //
  1241. // allocate CSADDR_BERVAL
  1242. // - can not use CSADDR as contains pointers and will break in 64bit
  1243. // - CSADDR_BERVAL maps to 32-bit CSADDR size
  1244. //
  1245. lenLocal = pCsAddr->LocalAddr.iSockaddrLength;
  1246. lenRemote = pCsAddr->RemoteAddr.iSockaddrLength;
  1247. lenBerval = sizeof(CSADDR_BERVAL) + lenLocal + lenRemote;
  1248. pcsaddrBerval = (PCSADDR_BERVAL) ALLOC_HEAP_ZERO( lenBerval );
  1249. if ( !pcsaddrBerval )
  1250. {
  1251. status = ERROR_NO_MEMORY;
  1252. goto Done;
  1253. }
  1254. //
  1255. // fill in CSADDR berval with CSADDR fields -- zero pointers
  1256. //
  1257. pcsaddrBerval->LocalZero = 0;
  1258. pcsaddrBerval->LocalLength = lenLocal;
  1259. pcsaddrBerval->RemoteZero = 0;
  1260. pcsaddrBerval->RemoteLength = lenRemote;
  1261. pcsaddrBerval->iSocketType = pCsAddr->iSocketType;
  1262. pcsaddrBerval->iProtocol = pCsAddr->iProtocol;
  1263. //
  1264. // copy sockaddrs
  1265. // - store offsets of sockaddrs from berval start
  1266. // (this allows any sockaddr
  1267. //
  1268. if ( lenLocal )
  1269. {
  1270. offset = sizeof(CSADDR_BERVAL);
  1271. RtlCopyMemory(
  1272. (PBYTE)pcsaddrBerval + offset,
  1273. pCsAddr->LocalAddr.lpSockaddr,
  1274. lenLocal );
  1275. }
  1276. if ( lenRemote )
  1277. {
  1278. offset = sizeof(CSADDR_BERVAL) + lenLocal;
  1279. RtlCopyMemory(
  1280. (PBYTE)pcsaddrBerval + offset,
  1281. pCsAddr->RemoteAddr.lpSockaddr,
  1282. lenRemote );
  1283. }
  1284. //
  1285. // WINSOCK_ADDRESSES attribute
  1286. // - CSADDR berval
  1287. //
  1288. if ( fAdd )
  1289. {
  1290. op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  1291. }
  1292. else
  1293. {
  1294. op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
  1295. }
  1296. mod.mod_op = op;
  1297. mod.mod_type = WINSOCK_ADDRESSES;
  1298. mod.mod_bvalues = modBValues;
  1299. modBValues[0] = & berval;
  1300. modBValues[1] = NULL;
  1301. berval.bv_len = lenBerval;
  1302. berval.bv_val = (PBYTE) pcsaddrBerval;
  1303. modPtrArray[0] = &mod;
  1304. modPtrArray[1] = NULL;
  1305. //
  1306. // do modify
  1307. //
  1308. if ( !GetRecurseLock( "ModifyAddressInServiceInstance" ) )
  1309. {
  1310. status = WSAEFAULT;
  1311. goto Done;
  1312. }
  1313. status = ldap_modify_s(
  1314. pRnrConnection->pLdapServer,
  1315. pwsDn,
  1316. modPtrArray );
  1317. if ( !ReleaseRecurseLock( "ModifyAddressInServiceInstance" ) )
  1318. {
  1319. status = WSAEFAULT;
  1320. goto Done;
  1321. }
  1322. //
  1323. // modify failed?
  1324. // - add treats already-exists as success
  1325. // - deleter treats doesn't-exist as success
  1326. //
  1327. if ( status != NO_ERROR )
  1328. {
  1329. if ( fAdd && status == LDAP_ATTRIBUTE_OR_VALUE_EXISTS )
  1330. {
  1331. DNSDBG( TRACE, (
  1332. "AlreadyExists error on add modify for %S\n"
  1333. "\ttreating as success\n",
  1334. pwsDn ));
  1335. status = NO_ERROR;
  1336. }
  1337. else if ( !fAdd && status == LDAP_NO_SUCH_ATTRIBUTE )
  1338. {
  1339. DNSDBG( TRACE, (
  1340. "NoSuchAttribute error on remove modify for %S\n"
  1341. "\ttreating as success\n",
  1342. pwsDn ));
  1343. status = NO_ERROR;
  1344. }
  1345. else
  1346. {
  1347. WINRNR_PRINT((
  1348. "WINRNR!ModifyAddressInServiceInstance -\n"
  1349. "ldap_modify_s() failed with error code: 0%x\n",
  1350. status ));
  1351. DNSDBG( TRACE, (
  1352. "ERROR: %d on CSADDR ldap_modify_s() for %S\n"
  1353. "\tfAdd = %d\n",
  1354. status,
  1355. pwsDn,
  1356. fAdd ));
  1357. status = WSAEFAULT;
  1358. }
  1359. }
  1360. Done:
  1361. FREE_HEAP( pcsaddrBerval );
  1362. DNSDBG( TRACE, (
  1363. "Leave ModifyAddressInServiceInstance() => %d\n",
  1364. status ));
  1365. return status;
  1366. }
  1367. BOOL
  1368. ExtractCsaddrFromBerval(
  1369. OUT PCSADDR_INFO pCsAddr,
  1370. IN PLDAP_BERVAL pBerval,
  1371. IN DWORD NumberOfProtocols,
  1372. IN PAFPROTOCOLS pafpProtocols
  1373. )
  1374. /*++
  1375. Routine Description:
  1376. Extract CSADDR from berval, and validate it matches
  1377. desired protocol.
  1378. Arguments:
  1379. pCsAddr -- ptr to CSADDR buffer to write
  1380. pBerval -- ptr to berval
  1381. NumberOfProtocols -- number of protocols in protocol array
  1382. pafpProtocols -- protocol array
  1383. Return Value:
  1384. TRUE if valid CSADDR of desired protocol.
  1385. FALSE otherwise.
  1386. --*/
  1387. {
  1388. PCSADDR_BERVAL pcsaBval;
  1389. PCHAR pend;
  1390. DWORD iter;
  1391. BOOL retval = FALSE;
  1392. INT lenLocal;
  1393. INT lenRemote;
  1394. PSOCKADDR psaLocal;
  1395. PSOCKADDR psaRemote;
  1396. DNSDBG( TRACE, (
  1397. "ExtractCsaddrFromBerval()\n"
  1398. "\tpCsaddr OUT = %p\n"
  1399. "\tpBerval = %p\n"
  1400. "\tProto array = %p\n",
  1401. pCsAddr,
  1402. pBerval,
  1403. pafpProtocols ));
  1404. IF_DNSDBG( TRACE )
  1405. {
  1406. DnsDbg_AfProtocolsArray(
  1407. "\tProtocol array:",
  1408. pafpProtocols,
  1409. NumberOfProtocols );
  1410. }
  1411. //
  1412. // unpack
  1413. // - verify csaddr has both sockaddrs within berval
  1414. // - unpack into real CSADDR, note we set the pointers
  1415. // but do NOT copy the sockaddrs
  1416. //
  1417. // note: we can't directly use the CSADDR_BERVAL because it is
  1418. // not a CSADDR in 64-bit
  1419. //
  1420. // note: perhaps should get the family fields out for test below
  1421. // with UNALIGNED copy; but as long as future sockaddrs are
  1422. // fixed, then their size will always be WORD aligned; since
  1423. // we unpack as vanilla SOCKADDR which only assumes WORD
  1424. // alignment we're ok; just need to make sure don't write
  1425. // odd byte count
  1426. //
  1427. pcsaBval = (PCSADDR_BERVAL) pBerval->bv_val;
  1428. pend = (PBYTE)pcsaBval + pBerval->bv_len;
  1429. // unpack local sockaddr info
  1430. psaLocal = NULL;
  1431. lenLocal = pcsaBval->LocalLength;
  1432. if ( lenLocal )
  1433. {
  1434. psaLocal = (PSOCKADDR) (pcsaBval + 1);
  1435. if ( lenLocal < 0 ||
  1436. (PBYTE)psaLocal + (DWORD)lenLocal > pend )
  1437. {
  1438. DNS_ASSERT( FALSE );
  1439. goto Exit;
  1440. }
  1441. }
  1442. // unpack remote sockaddr info
  1443. psaRemote = NULL;
  1444. lenRemote = pcsaBval->RemoteLength;
  1445. if ( lenRemote )
  1446. {
  1447. psaRemote = (PSOCKADDR) ((PBYTE)(pcsaBval + 1) + lenLocal);
  1448. if ( lenRemote < 0 ||
  1449. (PBYTE)psaRemote + (DWORD)lenRemote > pend )
  1450. {
  1451. DNS_ASSERT( FALSE );
  1452. goto Exit;
  1453. }
  1454. }
  1455. // fill in CSADDR fields
  1456. pCsAddr->LocalAddr.lpSockaddr = psaLocal;
  1457. pCsAddr->LocalAddr.iSockaddrLength = lenLocal;
  1458. pCsAddr->RemoteAddr.lpSockaddr = psaRemote;
  1459. pCsAddr->RemoteAddr.iSockaddrLength = lenRemote;
  1460. pCsAddr->iSocketType = pcsaBval->iSocketType;
  1461. pCsAddr->iProtocol = pcsaBval->iProtocol;
  1462. //
  1463. // if given protocols, sockaddr must match
  1464. //
  1465. retval = TRUE;
  1466. if ( pafpProtocols )
  1467. {
  1468. retval = FALSE;
  1469. for ( iter = 0; iter < NumberOfProtocols; iter++ )
  1470. {
  1471. INT proto = pafpProtocols[iter].iProtocol;
  1472. INT family = pafpProtocols[iter].iAddressFamily;
  1473. if ( proto == PF_UNSPEC ||
  1474. proto == pCsAddr->iProtocol )
  1475. {
  1476. if ( family == AF_UNSPEC ||
  1477. family == psaLocal->sa_family ||
  1478. family == psaRemote->sa_family )
  1479. {
  1480. retval = TRUE;
  1481. break;
  1482. }
  1483. }
  1484. }
  1485. }
  1486. Exit:
  1487. DNSDBG( TRACE, ( "Leave ExtractCsaddrFromBerval() => found = %d\n", retval ));
  1488. return retval;
  1489. }
  1490. //
  1491. // Add routines
  1492. //
  1493. RNR_STATUS
  1494. AddServiceClass(
  1495. IN PRNR_CONNECTION pRnrConnection,
  1496. IN PGUID pServiceClassId,
  1497. IN PWSTR pwsClassName,
  1498. OUT PDN_ARRAY * ppDnArray OPTIONAL
  1499. )
  1500. {
  1501. RNR_STATUS status = NO_ERROR;
  1502. PWSTR pwsDn;
  1503. PWSTR stringArray[6];
  1504. PDN_ARRAY pdnArray = NULL;
  1505. // mod data
  1506. // - need up to four mods
  1507. // - three string
  1508. // - one berval
  1509. PLDAPMod modPtrArray[5];
  1510. LDAPMod modArray[4];
  1511. PWSTR modValues1[2];
  1512. PWSTR modValues2[2];
  1513. PWSTR modValues3[2];
  1514. PLDAP_BERVAL modBvalues1[2];
  1515. LDAP_BERVAL berval1;
  1516. PLDAPMod pmod;
  1517. DWORD index;
  1518. DNSDBG( TRACE, (
  1519. "AddServiceClass()\n"
  1520. "\tpRnr = %p\n"
  1521. "\tpClassGuid = %p\n"
  1522. "\tClassName = %S\n",
  1523. pRnrConnection,
  1524. pServiceClassId,
  1525. pwsClassName
  1526. ));
  1527. //
  1528. // build DN for the ServiceClass object to be created
  1529. //
  1530. index = 0;
  1531. stringArray[index++] = FILTER_CN_EQUALS;
  1532. stringArray[index++] = pwsClassName;
  1533. stringArray[index++] = L",";
  1534. stringArray[index++] = pRnrConnection->WinsockServicesDN;
  1535. stringArray[index++] = NULL;
  1536. pwsDn = Dns_CreateConcatenatedString_W( stringArray );
  1537. if ( !pwsDn )
  1538. {
  1539. status = ERROR_NO_MEMORY;
  1540. goto Exit;
  1541. }
  1542. //
  1543. // build attributes for new service class
  1544. // - CN
  1545. // - ServiceClassName
  1546. // - ObjectClass
  1547. // - ServiceClassId (GUID)
  1548. //
  1549. pmod = modArray;
  1550. pmod->mod_op = LDAP_MOD_ADD;
  1551. pmod->mod_type = COMMON_NAME;
  1552. pmod->mod_values = modValues1;
  1553. modValues1[0] = pwsClassName;
  1554. modValues1[1] = NULL;
  1555. modPtrArray[0] = pmod++;
  1556. pmod->mod_op = LDAP_MOD_ADD;
  1557. pmod->mod_type = SERVICE_CLASS_NAME;
  1558. pmod->mod_values = modValues2;
  1559. modValues2[0] = pwsClassName;
  1560. modValues2[1] = NULL;
  1561. modPtrArray[1] = pmod++;
  1562. pmod->mod_op = LDAP_MOD_ADD;
  1563. pmod->mod_type = OBJECT_CLASS;
  1564. pmod->mod_values = modValues3;
  1565. modValues3[0] = SERVICE_CLASS;
  1566. modValues3[1] = NULL;
  1567. modPtrArray[2] = pmod++;
  1568. pmod->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  1569. pmod->mod_type = SERVICE_CLASS_ID;
  1570. pmod->mod_bvalues = modBvalues1;
  1571. modBvalues1[0] = & berval1;
  1572. modBvalues1[1] = NULL;
  1573. berval1.bv_len = sizeof(GUID);
  1574. berval1.bv_val = (LPBYTE) pServiceClassId;
  1575. modPtrArray[3] = pmod++;
  1576. modPtrArray[4] = NULL;
  1577. //
  1578. // add the service class
  1579. //
  1580. if ( !GetRecurseLock("AddServiceClass") )
  1581. {
  1582. status = WSAEFAULT;
  1583. goto Exit;
  1584. }
  1585. status = ldap_add_s(
  1586. pRnrConnection->pLdapServer,
  1587. pwsDn,
  1588. modPtrArray );
  1589. if ( !ReleaseRecurseLock("AddServiceClass") )
  1590. {
  1591. status = WSAEFAULT;
  1592. goto Exit;
  1593. }
  1594. if ( status != NO_ERROR )
  1595. {
  1596. WINRNR_PRINT((
  1597. "WINRNR!AddServiceClass -\n"
  1598. "ldap_add_s() failed with error code: 0%x\n", status ));
  1599. status = WSAEFAULT;
  1600. goto Exit;
  1601. }
  1602. //
  1603. // create DN array for added service class
  1604. //
  1605. // DCR: do we need DN or just service
  1606. //
  1607. if ( ppDnArray )
  1608. {
  1609. pdnArray = AllocDnArray( 1 );
  1610. if ( !pdnArray )
  1611. {
  1612. status = ERROR_NO_MEMORY;
  1613. goto Exit;
  1614. }
  1615. pdnArray->Strings[0] = pwsDn;
  1616. *ppDnArray = pdnArray;
  1617. pwsDn = NULL;
  1618. }
  1619. Exit:
  1620. FREE_HEAP( pwsDn );
  1621. DNSDBG( TRACE, (
  1622. "Leaving AddServiceClass() => %d\n",
  1623. status ));
  1624. return( status );
  1625. }
  1626. RNR_STATUS
  1627. AddClassInfoToServiceClass(
  1628. IN PRNR_CONNECTION pRnrConnection,
  1629. IN PWSTR pwsServiceClassDN,
  1630. IN PWSANSCLASSINFO pNSClassInfo
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. Add class info to a service class object.
  1635. This is helper routine for AddServiceInstance().
  1636. Arguments:
  1637. pRnrConnection -- Rnr blob
  1638. pwsServiceClassDN -- DN for service class being added
  1639. pNSClassInfo -- class info to add
  1640. Return Value:
  1641. NO_ERROR if successful.
  1642. ErrorCode on failure.
  1643. --*/
  1644. {
  1645. RNR_STATUS status = NO_ERROR;
  1646. LDAPMod * modPtrArray[2];
  1647. LDAPMod mod;
  1648. PLDAP_BERVAL modBValues[2];
  1649. LDAP_BERVAL berval;
  1650. DWORD blobSize;
  1651. DWORD nameLen;
  1652. PCLASSINFO_BERVAL pblob;
  1653. DNSDBG( TRACE, (
  1654. "AddClassInfoToServiceClass()\n"
  1655. "\tpRnr = %p\n"
  1656. "\tServiceClassDN = %S\n"
  1657. "\tpClassInfo = %p\n",
  1658. pRnrConnection,
  1659. pwsServiceClassDN,
  1660. pNSClassInfo ));
  1661. //
  1662. // build ClassInfo as berval
  1663. //
  1664. // - not directly using WSANSCLASSINFO as it contains
  1665. // pointers making length vary 32\64-bit
  1666. // - to handle this, offsets to name and value fields are
  1667. // encoded in DWORD fields where ptrs would be in WSANSCLASSINFO
  1668. //
  1669. // - name immediately follows CLASSINFO
  1670. // - value follows name (rounded to DWORD)
  1671. //
  1672. nameLen = (wcslen( pNSClassInfo->lpszName ) + 1) * sizeof(WCHAR);
  1673. nameLen = ROUND_UP_COUNT( nameLen, ALIGN_DWORD );
  1674. blobSize = sizeof(CLASSINFO_BERVAL)
  1675. + nameLen
  1676. + pNSClassInfo->dwValueSize;
  1677. pblob = (PCLASSINFO_BERVAL) ALLOC_HEAP_ZERO( blobSize );
  1678. if ( !pblob )
  1679. {
  1680. status = ERROR_NO_MEMORY;
  1681. goto Exit;
  1682. }
  1683. pblob->dwNameSpace = pNSClassInfo->dwNameSpace;
  1684. pblob->dwValueType = pNSClassInfo->dwValueType;
  1685. pblob->dwValueSize = pNSClassInfo->dwValueSize;
  1686. pblob->NameOffset = sizeof(CLASSINFO_BERVAL);
  1687. pblob->ValueOffset = sizeof(CLASSINFO_BERVAL) + nameLen;
  1688. wcscpy(
  1689. (PWSTR) ((PBYTE)pblob + pblob->NameOffset),
  1690. (PWSTR) pNSClassInfo->lpszName );
  1691. RtlCopyMemory(
  1692. (PBYTE)pblob + pblob->ValueOffset,
  1693. pNSClassInfo->lpValue,
  1694. pNSClassInfo->dwValueSize );
  1695. //
  1696. // ldap mod to add service class info
  1697. //
  1698. mod.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  1699. mod.mod_type = SERVICE_CLASS_INFO;
  1700. mod.mod_bvalues = modBValues;
  1701. modBValues[0] = & berval;
  1702. modBValues[1] = NULL;
  1703. berval.bv_len = blobSize;
  1704. berval.bv_val = (PCHAR) pblob;
  1705. modPtrArray[0] = &mod;
  1706. modPtrArray[1] = NULL;
  1707. //
  1708. // add the class info to the service class
  1709. //
  1710. if ( !GetRecurseLock("AddClassInfoToServiceClass") )
  1711. {
  1712. status = WSAEFAULT;
  1713. goto Exit;
  1714. }
  1715. status = ldap_modify_s(
  1716. pRnrConnection->pLdapServer,
  1717. pwsServiceClassDN,
  1718. modPtrArray );
  1719. if ( !ReleaseRecurseLock("AddClassInfoToServiceClass") )
  1720. {
  1721. status = WSAEFAULT;
  1722. goto Exit;
  1723. }
  1724. //
  1725. // modify failed?
  1726. // - treat already exits as success
  1727. //
  1728. if ( status != NO_ERROR )
  1729. {
  1730. if ( status == LDAP_ATTRIBUTE_OR_VALUE_EXISTS )
  1731. {
  1732. status = NO_ERROR;
  1733. goto Exit;
  1734. }
  1735. WINRNR_PRINT((
  1736. "WINRNR!AddClassInfoToServiceClass -\n"
  1737. "ldap_modify_s() failed with error code: 0%x\n",
  1738. status ));
  1739. status = WSAEFAULT;
  1740. }
  1741. Exit:
  1742. FREE_HEAP( pblob );
  1743. DNSDBG( TRACE, (
  1744. "Leave AddClassInfoToServiceClass() => %d\n",
  1745. status ));
  1746. return( status );
  1747. }
  1748. RNR_STATUS
  1749. AddServiceInstance(
  1750. IN PRNR_CONNECTION pRnrConnection,
  1751. IN PWSTR pwsServiceName,
  1752. IN PGUID pServiceClassId,
  1753. IN PWSAVERSION pVersion, OPTIONAL
  1754. IN PWSTR pwsComment, OPTIONAL
  1755. OUT PDN_ARRAY * ppDnArray
  1756. )
  1757. /*++
  1758. Routine Description:
  1759. Add a service to the directory.
  1760. Arguments:
  1761. pRnrConnection -- Rnr blob
  1762. pwsServiceName -- name of service being added
  1763. pServiceClassId -- class GUID
  1764. pVersion -- version data
  1765. pwsComment -- comment data
  1766. //
  1767. // DCR: should we just pass back name?
  1768. //
  1769. ppDnArray -- addr to receive DN array
  1770. Return Value:
  1771. NO_ERROR if successful.
  1772. ErrorCode on failure.
  1773. --*/
  1774. {
  1775. RNR_STATUS status = NO_ERROR;
  1776. // mod data
  1777. // - need up to six mods
  1778. // - four string
  1779. // - two berval
  1780. LDAPMod * modPtrArray[7];
  1781. LDAPMod modArray[6];
  1782. PWSTR modValues1[2];
  1783. PWSTR modValues2[2];
  1784. PWSTR modValues3[2];
  1785. PWSTR modValues4[2];
  1786. PLDAP_BERVAL modBvalues1[2];
  1787. PLDAP_BERVAL modBvalues2[2];
  1788. LDAP_BERVAL berval1;
  1789. LDAP_BERVAL berval2;
  1790. PLDAPMod pmod;
  1791. DWORD modIndex;
  1792. BOOL fuseDN;
  1793. PWSTR pwsRdn = NULL;
  1794. PWSTR psearchContextAllocated = NULL;
  1795. PWSTR pcontextDN = NULL;
  1796. DWORD contextLen;
  1797. PWSTR pnameService = NULL;
  1798. PWSTR pwsDN = NULL;
  1799. PDN_ARRAY pdnArray = NULL;
  1800. PWSTR stringArray[6];
  1801. DWORD index;
  1802. DNSDBG( TRACE, (
  1803. "AddServiceInstance()\n"
  1804. "\tpRnrCon = %p\n"
  1805. "\tServiceName = %S\n"
  1806. "\tClass GUID = %p\n"
  1807. "\tpVersion = %p\n"
  1808. "\tComment = %S\n"
  1809. "\tppArray OUT = %p\n",
  1810. pRnrConnection,
  1811. pwsServiceName,
  1812. pServiceClassId,
  1813. pVersion,
  1814. pwsComment,
  1815. ppDnArray ));
  1816. //
  1817. // determine service instance name
  1818. //
  1819. fuseDN = IsNameADn(
  1820. pwsServiceName,
  1821. & pwsRdn,
  1822. & psearchContextAllocated
  1823. );
  1824. if ( fuseDN )
  1825. {
  1826. pnameService = pwsRdn;
  1827. }
  1828. else
  1829. {
  1830. pnameService = pwsServiceName;
  1831. }
  1832. //
  1833. // build up an object DN for the ServiceClass object to be created.
  1834. // - if no context found from passed in name, append
  1835. // WinsockServices container
  1836. pcontextDN = psearchContextAllocated;
  1837. if ( !pcontextDN )
  1838. {
  1839. pcontextDN = pRnrConnection->WinsockServicesDN;
  1840. }
  1841. index = 0;
  1842. stringArray[index++] = FILTER_CN_EQUALS;
  1843. stringArray[index++] = pnameService;
  1844. stringArray[index++] = L",";
  1845. stringArray[index++] = pcontextDN;
  1846. stringArray[index++] = NULL;
  1847. pwsDN = Dns_CreateConcatenatedString_W( stringArray );
  1848. if ( !pwsDN )
  1849. {
  1850. status = ERROR_NO_MEMORY;
  1851. goto Exit;
  1852. }
  1853. //
  1854. // fill out attribute list to define new ServiceClass object
  1855. // - need to have CN, ObjectClass, and ServiceClassId
  1856. //
  1857. pmod = modArray;
  1858. pmod->mod_op = LDAP_MOD_ADD;
  1859. pmod->mod_type = COMMON_NAME;
  1860. pmod->mod_values = modValues1;
  1861. modValues1[0] = pnameService;
  1862. modValues1[1] = NULL;
  1863. modPtrArray[0] = pmod++;
  1864. pmod->mod_op = LDAP_MOD_ADD;
  1865. pmod->mod_type = SERVICE_INSTANCE_NAME;
  1866. pmod->mod_values = modValues2;
  1867. modValues2[0] = pnameService;
  1868. modValues2[1] = NULL;
  1869. modPtrArray[1] = pmod++;
  1870. pmod->mod_op = LDAP_MOD_ADD;
  1871. pmod->mod_type = OBJECT_CLASS;
  1872. pmod->mod_values = modValues3;
  1873. modValues3[0] = SERVICE_INSTANCE;
  1874. modValues3[1] = NULL;
  1875. modPtrArray[2] = pmod++;
  1876. pmod->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  1877. pmod->mod_type = SERVICE_CLASS_ID;
  1878. pmod->mod_bvalues = modBvalues1;
  1879. modBvalues1[0] = & berval1;
  1880. modBvalues1[1] = NULL;
  1881. berval1.bv_len = sizeof(GUID);
  1882. berval1.bv_val = (LPBYTE) pServiceClassId;
  1883. modPtrArray[3] = pmod++;
  1884. //
  1885. // write optional attributes
  1886. //
  1887. modIndex = 4;
  1888. if ( pVersion )
  1889. {
  1890. pmod->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  1891. pmod->mod_type = SERVICE_VERSION;
  1892. pmod->mod_bvalues = modBvalues2;
  1893. modBvalues2[0] = & berval2;
  1894. modBvalues2[1] = NULL;
  1895. berval2.bv_len = sizeof(WSAVERSION);
  1896. berval2.bv_val = (PBYTE) pVersion;
  1897. modPtrArray[ modIndex++ ] = pmod++;
  1898. }
  1899. if ( pwsComment )
  1900. {
  1901. pmod->mod_op = LDAP_MOD_ADD;
  1902. pmod->mod_type = SERVICE_COMMENT;
  1903. pmod->mod_values = modValues4;
  1904. modValues4[0] = pwsComment;
  1905. modValues4[1] = NULL;
  1906. modPtrArray[ modIndex++ ] = pmod++;
  1907. }
  1908. modPtrArray[ modIndex ] = NULL;
  1909. //
  1910. // Set thread table to (1) to prevent possible recursion in ldap_ call.
  1911. //
  1912. if ( !GetRecurseLock( "AddServiceInstance" ) )
  1913. {
  1914. status = WSAEFAULT;
  1915. goto Exit;
  1916. }
  1917. status = ldap_add_s(
  1918. pRnrConnection->pLdapServer,
  1919. pwsDN,
  1920. modPtrArray );
  1921. if ( status == LDAP_ALREADY_EXISTS )
  1922. {
  1923. status = ldap_modify_s(
  1924. pRnrConnection->pLdapServer,
  1925. pwsDN,
  1926. modPtrArray );
  1927. }
  1928. if ( !ReleaseRecurseLock( "AddServiceInstance" ) )
  1929. {
  1930. status = WSAEFAULT;
  1931. goto Exit;
  1932. }
  1933. if ( status != NO_ERROR )
  1934. {
  1935. DNSDBG( ANY, (
  1936. "AddServiceInstance - ldap_modify\\add failed %d (%0x)\n",
  1937. status, status ));
  1938. status = WSAEFAULT;
  1939. goto Exit;
  1940. }
  1941. // create out DN array -- if requested
  1942. pdnArray = AllocDnArray( 1 );
  1943. if ( !pdnArray )
  1944. {
  1945. status = ERROR_NO_MEMORY;
  1946. goto Exit;
  1947. }
  1948. pdnArray->Strings[0] = pwsDN;
  1949. Exit:
  1950. *ppDnArray = pdnArray;
  1951. FREE_HEAP( pwsRdn );
  1952. FREE_HEAP( psearchContextAllocated );
  1953. if ( status != NO_ERROR )
  1954. {
  1955. FREE_HEAP( pwsDN );
  1956. DNS_ASSERT( pdnArray == NULL );
  1957. }
  1958. DNSDBG( TRACE, ( "Leave AddServiceInstance()\n" ));
  1959. return status;
  1960. }
  1961. RNR_STATUS
  1962. GetAddressCountFromServiceInstance(
  1963. IN PRNR_CONNECTION pRnrConnection,
  1964. IN PWSTR pwsDN,
  1965. OUT PDWORD pdwAddressCount
  1966. )
  1967. {
  1968. RNR_STATUS status = NO_ERROR;
  1969. PLDAP pldap = pRnrConnection->pLdapServer;
  1970. LDAPMessage * results = NULL;
  1971. DWORD count;
  1972. DWORD countAddrs = 0;
  1973. LDAPMessage * object;
  1974. PLDAP_BERVAL * ppbval = NULL;
  1975. PWSTR attrs[3] = { SERVICE_CLASS_NAME,
  1976. WINSOCK_ADDRESSES,
  1977. NULL };
  1978. DNSDBG( TRACE, (
  1979. "GetAddressCountFromServiceInstance()\n"
  1980. "\tpRnrCon = %p\n"
  1981. "\tDN = %S\n",
  1982. pRnrConnection,
  1983. pwsDN ));
  1984. //
  1985. // search
  1986. //
  1987. status = DoLdapSearch(
  1988. "GetAddressCountFromServiceInstance",
  1989. FALSE,
  1990. pldap,
  1991. pwsDN,
  1992. LDAP_SCOPE_BASE,
  1993. FILTER_OBJECT_CLASS_SERVICE_INSTANCE,
  1994. attrs,
  1995. &results );
  1996. if ( status && !results )
  1997. {
  1998. // ldap_search_s was not successful, return known error code.
  1999. status = WSATYPE_NOT_FOUND;
  2000. goto Exit;
  2001. }
  2002. //
  2003. // search completed successfully -- count results
  2004. //
  2005. count = ldap_count_entries( pldap, results );
  2006. if ( count == 0 )
  2007. {
  2008. WINRNR_PRINT((
  2009. "WINRNR!GetAddressCountFromServiceInstance -\n"
  2010. "ldap_count_entries() failed\n" ));
  2011. status = WSATYPE_NOT_FOUND;
  2012. goto Exit;
  2013. }
  2014. //
  2015. // We performed a search with flag LDAP_OBJECT_BASE, we should have
  2016. // only 1 entry returned for count.
  2017. //
  2018. // ASSERT( count == 1 );
  2019. //
  2020. // Parse the results.
  2021. //
  2022. object = ldap_first_entry( pldap, results );
  2023. if ( !object )
  2024. {
  2025. WINRNR_PRINT(( "WINRNR!GetAddressCountFromServiceInstance -\n" ));
  2026. WINRNR_PRINT(( "ldap_first_entry() failed\n" ));
  2027. status = WSANO_DATA;
  2028. goto Exit;
  2029. }
  2030. //
  2031. // Read the WinsockAddresses (if any) and get the count value.
  2032. // Remember these are BER values (Octet strings).
  2033. //
  2034. ppbval = ldap_get_values_len(
  2035. pldap,
  2036. object,
  2037. WINSOCK_ADDRESSES );
  2038. if ( !ppbval )
  2039. {
  2040. // Attribute not present, return address count of zero.
  2041. DNSDBG( ANY, (
  2042. "ERROR: GetAddressCountFromServiceInstance()\n"
  2043. "\tldap_get_values_len() failed\n" ));
  2044. status = NO_ERROR;
  2045. goto Exit;
  2046. }
  2047. countAddrs = ldap_count_values_len( ppbval );
  2048. ldap_value_free_len( ppbval );
  2049. status = NO_ERROR;
  2050. Exit:
  2051. ldap_msgfree( results );
  2052. // count out param
  2053. *pdwAddressCount = countAddrs;
  2054. return( status );
  2055. }
  2056. RNR_STATUS
  2057. FindServiceClass(
  2058. IN PRNR_CONNECTION pRnrConnection,
  2059. IN PWSTR pwsServiceClassName, OPTIONAL
  2060. IN PGUID pServiceClassId,
  2061. OUT PDWORD pdwDnArrayCount, OPTIONAL
  2062. OUT PDN_ARRAY * ppDnArray OPTIONAL
  2063. )
  2064. /*++
  2065. Routine Description:
  2066. Find service class in directory.
  2067. Arguments:
  2068. pRnrConnection -- RnR connection
  2069. pwsServiceClassName -- service class name
  2070. pServiceClassId -- class GUID
  2071. pdwArrayCount -- addr to receive count
  2072. ppDnArray -- addr to recv DN array
  2073. Return Value:
  2074. NO_ERROR if successful.
  2075. ErrorCode on failure.
  2076. --*/
  2077. {
  2078. RNR_STATUS status = NO_ERROR;
  2079. PLDAP pldap = pRnrConnection->pLdapServer;
  2080. PWSTR pclassFilter = NULL;
  2081. PWSTR pfinalStr;
  2082. PWSTR pfilter = NULL;
  2083. LDAPMessage * presults = NULL;
  2084. PDN_ARRAY pdnArray = NULL;
  2085. DWORD count;
  2086. LDAPMessage * pnext;
  2087. DWORD iter = 0;
  2088. DWORD index;
  2089. PWSTR stringArray[12];
  2090. PWSTR searchAttributes[2] = { COMMON_NAME, NULL };
  2091. DNSDBG( TRACE, (
  2092. "FindServiceClass()\n"
  2093. "\tpRnrCon = %p\n"
  2094. "\tClass Name = %S\n",
  2095. pRnrConnection,
  2096. pwsServiceClassName
  2097. ));
  2098. //
  2099. // convert the GUID to a string for the search filter
  2100. //
  2101. pclassFilter = CreateFilterElement(
  2102. (PCHAR) pServiceClassId,
  2103. sizeof(GUID) );
  2104. if ( !pclassFilter )
  2105. {
  2106. return( ERROR_NO_MEMORY );
  2107. }
  2108. //
  2109. // build search filter
  2110. // class == ServiceClass
  2111. // AND
  2112. // CN == ServiceClassName
  2113. // OR
  2114. // serviceClass == ServiceClassGuid
  2115. //
  2116. // (&(OBJECT_CLASS=SERVICE_CLASS)
  2117. // (|(CN=xxxx)
  2118. // (SERVICE_CLASS_ID=yyyy)))
  2119. //
  2120. index = 0;
  2121. stringArray[index++] = L"(&";
  2122. stringArray[index++] = FILTER_OBJECT_CLASS_SERVICE_CLASS;
  2123. pfinalStr = L"))";
  2124. if ( pwsServiceClassName )
  2125. {
  2126. stringArray[index++] = L"(|(";
  2127. stringArray[index++] = FILTER_CN_EQUALS;
  2128. stringArray[index++] = pwsServiceClassName;
  2129. stringArray[index++] = L")";
  2130. pfinalStr = L")))";
  2131. }
  2132. stringArray[index++] = FILTER_PAREN_SERVICE_CLASS_ID_EQUALS;
  2133. stringArray[index++] = pclassFilter;
  2134. stringArray[index++] = pfinalStr;
  2135. stringArray[index] = NULL;
  2136. pfilter = Dns_CreateConcatenatedString_W( stringArray );
  2137. if ( !pfilter )
  2138. {
  2139. status = ERROR_NO_MEMORY;
  2140. goto Exit;
  2141. }
  2142. //
  2143. // search the default Winsock Services container
  2144. //
  2145. status = DoLdapSearch(
  2146. "FindServiceClass",
  2147. FALSE,
  2148. pldap,
  2149. pRnrConnection->WinsockServicesDN,
  2150. LDAP_SCOPE_ONELEVEL,
  2151. pfilter,
  2152. searchAttributes,
  2153. &presults );
  2154. //
  2155. // if search unsuccessful, bail
  2156. //
  2157. if ( status != NO_ERROR && !presults )
  2158. {
  2159. //status = WSAEFAULT; // DCR: wrong error code
  2160. status = WSANO_DATA;
  2161. goto Exit;
  2162. }
  2163. //
  2164. // build DN array from results
  2165. //
  2166. status = BuildDnArrayFromResults(
  2167. pldap,
  2168. presults,
  2169. pdwDnArrayCount,
  2170. ppDnArray );
  2171. Exit:
  2172. ldap_msgfree( presults );
  2173. FREE_HEAP( pclassFilter );
  2174. FREE_HEAP( pfilter );
  2175. // set results OUT param
  2176. if ( status != NO_ERROR )
  2177. {
  2178. if ( ppDnArray )
  2179. {
  2180. *ppDnArray = NULL;
  2181. }
  2182. if ( pdwDnArrayCount )
  2183. {
  2184. *pdwDnArrayCount = 0;
  2185. }
  2186. }
  2187. DNSDBG( TRACE, (
  2188. "Leave FindServiceClass() => %d\n"
  2189. "\tcount = %d\n"
  2190. "\tpdnArray = %p\n"
  2191. "\tfirst DN = %S\n",
  2192. status,
  2193. pdwDnArrayCount ? *pdwDnArrayCount : 0,
  2194. (ppDnArray && *ppDnArray)
  2195. ? *ppDnArray
  2196. : NULL,
  2197. (ppDnArray && *ppDnArray)
  2198. ? (*ppDnArray)->Strings[0]
  2199. : NULL
  2200. ));
  2201. return( status );
  2202. }
  2203. RNR_STATUS
  2204. FindServiceInstance(
  2205. IN PRNR_CONNECTION pRnrConnection,
  2206. IN PWSTR pwsServiceName OPTIONAL,
  2207. IN PGUID pServiceClassId OPTIONAL,
  2208. IN PWSAVERSION pVersion OPTIONAL,
  2209. IN PWSTR pwsContext OPTIONAL,
  2210. IN BOOL fPerformDeepSearch,
  2211. OUT PDWORD pdwDnArrayCount,
  2212. OUT PDN_ARRAY * ppDnArray OPTIONAL
  2213. )
  2214. {
  2215. RNR_STATUS status = NO_ERROR;
  2216. PLDAP pldap = pRnrConnection->pLdapServer;
  2217. PWSTR pnameService;
  2218. PWSTR pwsRdn = NULL;
  2219. PWSTR psearchContextAllocated = NULL;
  2220. PWSTR pserviceContext;
  2221. PWSTR pclassFilter = NULL;
  2222. PWSTR pversionFilter = NULL;
  2223. PWSTR pfilter = NULL;
  2224. LDAPMessage * presults = NULL;
  2225. BOOL fuseDN;
  2226. DWORD index;
  2227. PWSTR psearchContext = NULL;
  2228. PWSTR stringArray[15];
  2229. PWSTR searchAttributes[2] = { COMMON_NAME, NULL };
  2230. DNSDBG( TRACE, (
  2231. "FindServiceInstance()\n"
  2232. "\tpRnrCon = %p\n"
  2233. "\tServiceName = %S\n"
  2234. "\tpClassGUID = %p\n"
  2235. "\tpVersion = %p\n"
  2236. "\tpwsContext = %S\n"
  2237. "\tpCount OUT = %p\n"
  2238. "\tpDnArray OUT = %p\n",
  2239. pRnrConnection,
  2240. pwsServiceName,
  2241. pServiceClassId,
  2242. pVersion,
  2243. pwsContext,
  2244. pdwDnArrayCount,
  2245. ppDnArray
  2246. ));
  2247. //
  2248. // get service name
  2249. // - if given name
  2250. // - get DN or is DN
  2251. // - else
  2252. // - search for any service "*"
  2253. //
  2254. pnameService = L"*";
  2255. if ( pwsServiceName )
  2256. {
  2257. // note, this can allocate pwsRdn and psearchContext
  2258. fuseDN = IsNameADn(
  2259. pwsServiceName,
  2260. & pwsRdn,
  2261. & psearchContextAllocated );
  2262. if ( fuseDN )
  2263. {
  2264. pnameService = pwsRdn;
  2265. }
  2266. else
  2267. {
  2268. pnameService = pwsServiceName;
  2269. }
  2270. }
  2271. //
  2272. // if service class specified make filter
  2273. //
  2274. if ( pServiceClassId )
  2275. {
  2276. pclassFilter = CreateFilterElement(
  2277. (PCHAR) pServiceClassId,
  2278. sizeof(GUID) );
  2279. if ( !pclassFilter )
  2280. {
  2281. status = ERROR_NO_MEMORY;
  2282. goto Exit;
  2283. }
  2284. }
  2285. //
  2286. // version specified -- make filter
  2287. //
  2288. if ( pVersion )
  2289. {
  2290. pversionFilter = CreateFilterElement(
  2291. (PCHAR) pVersion,
  2292. sizeof(WSAVERSION) );
  2293. if ( !pversionFilter )
  2294. {
  2295. status = ERROR_NO_MEMORY;
  2296. goto Exit;
  2297. }
  2298. }
  2299. //
  2300. // context
  2301. // - use context found above or
  2302. // - passed in context or
  2303. // - WinsockServices DN
  2304. //
  2305. if ( psearchContextAllocated )
  2306. {
  2307. pserviceContext = psearchContextAllocated;
  2308. }
  2309. else if ( pwsContext )
  2310. {
  2311. pserviceContext = pwsContext;
  2312. }
  2313. else
  2314. {
  2315. pserviceContext = pRnrConnection->WinsockServicesDN;
  2316. }
  2317. //
  2318. // build filter
  2319. // - objects of class ServiceClass
  2320. // - with common name equal to pServiceInstanceName
  2321. //
  2322. // (&(objectClass=serviceInstance)
  2323. // (CN=pnameService)
  2324. // (serviceClassId=pclassFilter)
  2325. // (serviceVersion=pversionFilter))
  2326. //
  2327. index = 0;
  2328. stringArray[index++] = L"(&";
  2329. stringArray[index++] = FILTER_OBJECT_CLASS_SERVICE_INSTANCE;
  2330. stringArray[index++] = FILTER_PAREN_CN_EQUALS;
  2331. stringArray[index++] = pnameService;
  2332. stringArray[index++] = L")";
  2333. if ( pServiceClassId )
  2334. {
  2335. stringArray[index++] = FILTER_PAREN_SERVICE_CLASS_ID_EQUALS;
  2336. stringArray[index++] = pclassFilter;
  2337. stringArray[index++] = L")";
  2338. }
  2339. if ( pVersion )
  2340. {
  2341. stringArray[index++] = FILTER_PAREN_SERVICE_VERSION_EQUALS;
  2342. stringArray[index++] = pversionFilter;
  2343. stringArray[index++] = L")";
  2344. }
  2345. stringArray[index++] = L")";
  2346. stringArray[index] = NULL;
  2347. pfilter = Dns_CreateConcatenatedString_W( stringArray );
  2348. if ( !pfilter )
  2349. {
  2350. status = ERROR_NO_MEMORY;
  2351. goto Exit;
  2352. }
  2353. //
  2354. // search
  2355. // - in pserviceContext defined above
  2356. //
  2357. // DCR: - We may want to perform all of these searches against the
  2358. // Global Catalog server.
  2359. //
  2360. status = DoLdapSearch(
  2361. "FindServiceInstance",
  2362. FALSE,
  2363. pldap,
  2364. pserviceContext,
  2365. fPerformDeepSearch
  2366. ? LDAP_SCOPE_SUBTREE
  2367. : LDAP_SCOPE_ONELEVEL,
  2368. pfilter,
  2369. searchAttributes,
  2370. &presults );
  2371. if ( status && !presults )
  2372. {
  2373. status = WSAEFAULT;
  2374. goto Exit;
  2375. }
  2376. //
  2377. // build DN array from results
  2378. //
  2379. status = BuildDnArrayFromResults(
  2380. pldap,
  2381. presults,
  2382. pdwDnArrayCount,
  2383. ppDnArray );
  2384. Exit:
  2385. ldap_msgfree( presults );
  2386. FREE_HEAP( pwsRdn );
  2387. FREE_HEAP( psearchContextAllocated );
  2388. FREE_HEAP( pclassFilter );
  2389. FREE_HEAP( pversionFilter );
  2390. FREE_HEAP( pfilter );
  2391. if ( status != NO_ERROR )
  2392. {
  2393. if ( pdwDnArrayCount )
  2394. {
  2395. *pdwDnArrayCount = 0;
  2396. }
  2397. if ( ppDnArray )
  2398. {
  2399. *ppDnArray = NULL;
  2400. }
  2401. }
  2402. DNSDBG( TRACE, (
  2403. "Leave FindServiceInstance() => %d\n"
  2404. "\tpDnArray OUT = %p\n"
  2405. "\tfirst DN = %S\n",
  2406. status,
  2407. (ppDnArray && *ppDnArray)
  2408. ? *ppDnArray
  2409. : NULL,
  2410. (ppDnArray && *ppDnArray)
  2411. ? (*ppDnArray)->Strings[0]
  2412. : NULL
  2413. ));
  2414. return( status );
  2415. }
  2416. RNR_STATUS
  2417. FindSubordinateContainers(
  2418. IN PRNR_CONNECTION pRnrConnection,
  2419. IN PWSTR pwsServiceName OPTIONAL,
  2420. IN PWSTR pwsContext OPTIONAL,
  2421. IN BOOL fPerformDeepSearch,
  2422. OUT PDN_ARRAY * ppDnArray OPTIONAL
  2423. )
  2424. {
  2425. RNR_STATUS status = NO_ERROR;
  2426. PLDAP pldap = pRnrConnection->pLdapServer;
  2427. PWSTR pnameService;
  2428. PWSTR pwsRdn = NULL;
  2429. PWSTR psearchContextAllocated = NULL;
  2430. PWSTR psearchContext;
  2431. PWSTR pfilter = NULL;
  2432. DWORD index;
  2433. BOOL fuseDN;
  2434. PWSTR stringArray[8];
  2435. LDAPMessage * presults = NULL;
  2436. DNSDBG( TRACE, (
  2437. "FindSubordinateContainers()\n"
  2438. "\tpRnrCon = %p\n"
  2439. "\tServiceName = %S\n"
  2440. "\tpwsContext = %S\n"
  2441. "\tfDeepSearch = %d\n"
  2442. "\tpDnArray OUT = %p\n",
  2443. pRnrConnection,
  2444. pwsServiceName,
  2445. pwsContext,
  2446. fPerformDeepSearch,
  2447. ppDnArray
  2448. ));
  2449. //
  2450. // get service name
  2451. // - if given name
  2452. // - get DN or is DN
  2453. // - else
  2454. // - search for any service "*"
  2455. //
  2456. pnameService = L"*";
  2457. if ( pwsServiceName )
  2458. {
  2459. // note, this can allocate pwsRdn and psearchContext
  2460. fuseDN = IsNameADn(
  2461. pwsServiceName,
  2462. & pwsRdn,
  2463. & psearchContextAllocated );
  2464. if ( fuseDN )
  2465. {
  2466. pnameService = pwsRdn;
  2467. }
  2468. else
  2469. {
  2470. pnameService = pwsServiceName;
  2471. }
  2472. }
  2473. //
  2474. // build filter
  2475. // - objects of class NTDS container
  2476. // - with common name equal to pServiceInstanceName
  2477. //
  2478. // (&(OBJECT_CLASS=NTDS_CONTAINER)
  2479. // (COMMON_NAME=ServiceName))
  2480. //
  2481. index = 0;
  2482. stringArray[index++] = L"(&";
  2483. stringArray[index++] = FILTER_OBJECT_CLASS_NTDS_CONTAINER;
  2484. stringArray[index++] = FILTER_PAREN_CN_EQUALS;
  2485. stringArray[index++] = pnameService;
  2486. stringArray[index++] = L"))";
  2487. stringArray[index] = NULL;
  2488. pfilter = Dns_CreateConcatenatedString_W( stringArray );
  2489. if ( !pfilter )
  2490. {
  2491. status = ERROR_NO_MEMORY;
  2492. goto Exit;
  2493. }
  2494. //
  2495. // search context
  2496. // - use allocated from passed in DN or
  2497. // - passed in context
  2498. // - special context to indicated DomainDN or
  2499. // - winsock services DN
  2500. //
  2501. if ( psearchContextAllocated )
  2502. {
  2503. psearchContext = psearchContextAllocated;
  2504. }
  2505. else if ( pwsContext )
  2506. {
  2507. if ( wcscmp( pwsContext, L"\\" ) == 0 )
  2508. {
  2509. psearchContext = pRnrConnection->DomainDN;
  2510. }
  2511. else
  2512. {
  2513. psearchContext = pwsContext;
  2514. }
  2515. }
  2516. else
  2517. {
  2518. psearchContext = pRnrConnection->WinsockServicesDN;
  2519. }
  2520. //
  2521. // search
  2522. // - in pserviceContext defined above
  2523. //
  2524. // DCR: - We may want to perform all of these searches against the
  2525. // Global Catalog server.
  2526. //
  2527. status = DoLdapSearch(
  2528. "FindSubordinateContainer",
  2529. FALSE, // no locked
  2530. pldap,
  2531. psearchContext,
  2532. fPerformDeepSearch
  2533. ? LDAP_SCOPE_SUBTREE
  2534. : LDAP_SCOPE_ONELEVEL,
  2535. pfilter,
  2536. NULL, // no attribute selection
  2537. &presults );
  2538. if ( status && !presults )
  2539. {
  2540. status = WSAEFAULT;
  2541. goto Exit;
  2542. }
  2543. //
  2544. // build DN array from results
  2545. //
  2546. status = BuildDnArrayFromResults(
  2547. pldap,
  2548. presults,
  2549. NULL,
  2550. ppDnArray );
  2551. Exit:
  2552. ldap_msgfree( presults );
  2553. FREE_HEAP( pfilter );
  2554. FREE_HEAP( pwsRdn );
  2555. FREE_HEAP( psearchContextAllocated );
  2556. DNSDBG( TRACE, (
  2557. "Leave FindSubordinateContainer() => %d\n"
  2558. "\tpDnArray OUT = %p\n",
  2559. "\tfirst DN = %S\n",
  2560. status,
  2561. (ppDnArray && *ppDnArray)
  2562. ? *ppDnArray
  2563. : NULL,
  2564. (ppDnArray && *ppDnArray)
  2565. ? (*ppDnArray)->Strings[0]
  2566. : NULL
  2567. ));
  2568. return( status );
  2569. }
  2570. //
  2571. // Read routines
  2572. //
  2573. // These routines read directory data and write into
  2574. // RnR buffer. They are the working functions for
  2575. // RnR "Get" routines.
  2576. //
  2577. RNR_STATUS
  2578. ReadServiceClass(
  2579. IN PRNR_CONNECTION pRnrConnection,
  2580. IN PWSTR pwsDN,
  2581. IN OUT PDWORD pdwBufSize,
  2582. IN OUT PWSASERVICECLASSINFOW pServiceClassInfo
  2583. )
  2584. /*++
  2585. Routine Description:
  2586. Return service class info to caller.
  2587. Helper routine for NTDS_GetServiceClassInfo().
  2588. Read service class info for given DN and return
  2589. service class info buffer to caller.
  2590. Arguments:
  2591. Return Value:
  2592. NO_ERROR if successful.
  2593. WSAEFAULT if buffer too small.
  2594. ErrorCode on failure.
  2595. --*/
  2596. {
  2597. RNR_STATUS status = NO_ERROR;
  2598. PLDAP pldap = pRnrConnection->pLdapServer;
  2599. LDAPMessage * presults = NULL;
  2600. DWORD count;
  2601. DWORD iter;
  2602. LDAPMessage * object;
  2603. PWSTR * ppvalue = NULL;
  2604. PLDAP_BERVAL * ppberVal = NULL;
  2605. FLATBUF flatbuf;
  2606. PWSANSCLASSINFOW pbufClassInfoArray;
  2607. PBYTE pbuf;
  2608. PWSTR pbufString;
  2609. PWSTR attrs[4] = {
  2610. SERVICE_CLASS_INFO,
  2611. SERVICE_CLASS_ID,
  2612. SERVICE_CLASS_NAME,
  2613. NULL };
  2614. DNSDBG( TRACE, (
  2615. "ReadServiceClass()\n"
  2616. "\tprnr = %p\n"
  2617. "\tDN = %S\n"
  2618. "\tbuf size = %p (%d)\n"
  2619. "\tbuffer = %p\n",
  2620. pRnrConnection,
  2621. pwsDN,
  2622. pdwBufSize,
  2623. pdwBufSize ? *pdwBufSize : 0,
  2624. pServiceClassInfo ));
  2625. //
  2626. // create flat buffer for building response
  2627. // - starts immediately after service class info struct itself
  2628. //
  2629. ASSERT( pServiceClassInfo != NULL );
  2630. RtlZeroMemory(
  2631. (PBYTE) pServiceClassInfo,
  2632. *pdwBufSize );
  2633. FlatBuf_Init(
  2634. & flatbuf,
  2635. (LPBYTE) pServiceClassInfo + sizeof(WSASERVICECLASSINFOW),
  2636. (INT) *pdwBufSize - sizeof(WSASERVICECLASSINFOW)
  2637. );
  2638. //
  2639. // search
  2640. //
  2641. status = DoLdapSearch(
  2642. "ReadServiceClass",
  2643. FALSE, // no locked
  2644. pldap,
  2645. pwsDN,
  2646. LDAP_SCOPE_BASE,
  2647. FILTER_OBJECT_CLASS_SERVICE_CLASS,
  2648. attrs,
  2649. &presults );
  2650. if ( status && !presults )
  2651. {
  2652. status = WSATYPE_NOT_FOUND;
  2653. goto Done;
  2654. }
  2655. //
  2656. // search completed
  2657. // - should have found just one service class
  2658. //
  2659. count = ldap_count_entries( pldap, presults );
  2660. if ( count == 0 )
  2661. {
  2662. WINRNR_PRINT((
  2663. "WINRNR!ReadServiceClass -\n"
  2664. "ldap_count_entries() failed\n" ));
  2665. status = WSATYPE_NOT_FOUND;
  2666. goto Done;
  2667. }
  2668. DNS_ASSERT( count == 1 );
  2669. object = ldap_first_entry(
  2670. pldap,
  2671. presults );
  2672. if ( !object )
  2673. {
  2674. WINRNR_PRINT((
  2675. "WINRNR!ReadServiceClass -\n"
  2676. "ldap_first_entry() failed\n" ));
  2677. status = WSATYPE_NOT_FOUND;
  2678. goto Done;
  2679. }
  2680. //
  2681. // read the ServiceClassInfo(s) from bervals
  2682. // and write them to buffer
  2683. //
  2684. ppberVal = ldap_get_values_len(
  2685. pldap,
  2686. object,
  2687. SERVICE_CLASS_INFO );
  2688. count = 0;
  2689. if ( ppberVal )
  2690. {
  2691. count = ldap_count_values_len( ppberVal );
  2692. }
  2693. pServiceClassInfo->dwCount = count;
  2694. // reserve space for class info array
  2695. pbufClassInfoArray = (PWSANSCLASSINFOW)
  2696. FlatBuf_Reserve(
  2697. & flatbuf,
  2698. count * sizeof(WSANSCLASSINFOW),
  2699. ALIGN_LPVOID
  2700. );
  2701. pServiceClassInfo->lpClassInfos = pbufClassInfoArray;
  2702. //
  2703. // copy each WSANSCLASSINFO we find
  2704. // - note that do not stop loop even if out of space
  2705. // continue for sizing purposes
  2706. //
  2707. for ( iter = 0; iter < count; iter++ )
  2708. {
  2709. PCLASSINFO_BERVAL pclassInfo;
  2710. PWSTR pname;
  2711. PBYTE pvalue;
  2712. PBYTE pdataEnd;
  2713. // recover WSANSCLASSINFO as structure
  2714. //
  2715. // WSANSCLASSINFO structures are stored as octect string in
  2716. // directory with offsets from structure start for pointer
  2717. // fields
  2718. //
  2719. // note: that the "pointer fields" are offsets in the
  2720. // structure and hence are NOT the size of pointers in 64-bit
  2721. // so we can NOT simply recover the structure and fixup
  2722. //
  2723. pclassInfo = (PCLASSINFO_BERVAL) ppberVal[iter]->bv_val;
  2724. pdataEnd = (PBYTE)pclassInfo + ppberVal[iter]->bv_len;
  2725. pvalue = ((PBYTE) pclassInfo + pclassInfo->ValueOffset);
  2726. pname = (PWSTR) ((PBYTE) pclassInfo + pclassInfo->NameOffset);
  2727. //
  2728. // validity check recovered data
  2729. // - name aligned
  2730. // - value within berval
  2731. // - name within berval
  2732. //
  2733. // DCR: explicit string validity\length check
  2734. //
  2735. if ( !POINTER_IS_ALIGNED( pname, ALIGN_WCHAR ) ||
  2736. pvalue < (PBYTE) (pclassInfo+1) ||
  2737. (pvalue + pclassInfo->dwValueSize) > pdataEnd ||
  2738. pname < (PWSTR) (pclassInfo+1) ||
  2739. pname >= (PWSTR) pdataEnd )
  2740. {
  2741. DNS_ASSERT( FALSE );
  2742. status = WSATYPE_NOT_FOUND;
  2743. goto Done;
  2744. }
  2745. //
  2746. // copy NSCLASSINFO to buffer
  2747. // - flat copy of DWORD types and sizes
  2748. // - copy name string
  2749. // - copy value
  2750. pbufString = (PWSTR) FlatBuf_WriteString_W(
  2751. & flatbuf,
  2752. pname );
  2753. pbuf = FlatBuf_CopyMemory(
  2754. & flatbuf,
  2755. pvalue,
  2756. pclassInfo->dwValueSize,
  2757. 0 // no alignment required
  2758. );
  2759. // write only if had space for NSCLASSINFO array above
  2760. if ( pbufClassInfoArray )
  2761. {
  2762. PWSANSCLASSINFO pbufClassInfo = &pbufClassInfoArray[iter];
  2763. pbufClassInfo->dwNameSpace = pclassInfo->dwNameSpace;
  2764. pbufClassInfo->dwValueType = pclassInfo->dwValueType;
  2765. pbufClassInfo->dwValueSize = pclassInfo->dwValueSize;
  2766. pbufClassInfo->lpszName = pbufString;
  2767. pbufClassInfo->lpValue = pbuf;
  2768. }
  2769. }
  2770. ldap_value_free_len( ppberVal );
  2771. ppberVal = NULL;
  2772. //
  2773. // Read the ServiceClassId and write it into buffer.
  2774. // Remember this is a BER value (Octet string).
  2775. //
  2776. ppberVal = ldap_get_values_len(
  2777. pldap,
  2778. object,
  2779. SERVICE_CLASS_ID );
  2780. if ( !ppberVal || !ppberVal[0] )
  2781. {
  2782. WINRNR_PRINT((
  2783. "WINRNR!ReadServiceClass -\n"
  2784. "ldap_get_values_len() failed\n" ));
  2785. status = WSATYPE_NOT_FOUND;
  2786. goto Done;
  2787. }
  2788. if ( ppberVal[0]->bv_len != sizeof(GUID) )
  2789. {
  2790. WINRNR_PRINT((
  2791. "WINRNR!ReadServiceClass - corrupted DS data!\n"
  2792. "\tservice class id berval %p with invalid length %d\n",
  2793. ppberVal[0],
  2794. ppberVal[0]->bv_len ));
  2795. DNS_ASSERT( ppberVal[0]->bv_len == sizeof(GUID) );
  2796. status = WSATYPE_NOT_FOUND;
  2797. goto Done;
  2798. }
  2799. // ASSERT( ldap_count_values_len( ppberVal ) == 1 );
  2800. // write the service class id GUID to buffer
  2801. pbuf = FlatBuf_CopyMemory(
  2802. & flatbuf,
  2803. ppberVal[0]->bv_val,
  2804. sizeof(GUID),
  2805. ALIGN_DWORD );
  2806. pServiceClassInfo->lpServiceClassId = (PGUID) pbuf;
  2807. ldap_value_free_len( ppberVal );
  2808. ppberVal = NULL;
  2809. //
  2810. // Read the ServiceClassName and write it into buffer.
  2811. //
  2812. ppvalue = ldap_get_values(
  2813. pldap,
  2814. object,
  2815. SERVICE_CLASS_NAME );
  2816. if ( !ppvalue )
  2817. {
  2818. WINRNR_PRINT((
  2819. "WINRNR!ReadServiceClass -\n"
  2820. "ldap_get_values() failed\n" ));
  2821. status = WSATYPE_NOT_FOUND;
  2822. goto Done;
  2823. }
  2824. // copy service class name
  2825. pbufString = (PWSTR) FlatBuf_WriteString_W(
  2826. & flatbuf,
  2827. ppvalue[0] );
  2828. pServiceClassInfo->lpszServiceClassName = pbufString;
  2829. ldap_value_free( ppvalue );
  2830. //
  2831. // check for inadequate space
  2832. // - set actual buffer size used
  2833. //
  2834. // DCR_QUESTION: do we fix up space all the time?
  2835. // or only when fail
  2836. //
  2837. status = NO_ERROR;
  2838. //*pdwBufSize -= flatbuf.BytesLeft;
  2839. if ( flatbuf.BytesLeft < 0 )
  2840. {
  2841. *pdwBufSize -= flatbuf.BytesLeft;
  2842. status = WSAEFAULT;
  2843. }
  2844. Done:
  2845. ldap_value_free_len( ppberVal );
  2846. ldap_msgfree( presults );
  2847. DNSDBG( TRACE, (
  2848. "Leave ReadServiceClass() = %d\n",
  2849. status ));
  2850. return( status );
  2851. }
  2852. RNR_STATUS
  2853. ReadQuerySet(
  2854. IN PRNR_LOOKUP pRnr,
  2855. IN PWSTR pwsDN,
  2856. IN OUT PDWORD pdwBufSize,
  2857. IN OUT PWSAQUERYSETW pqsResults
  2858. )
  2859. /*++
  2860. Routine Description:
  2861. Read query set info.
  2862. Does LDAP search and fills in query set with desired results.
  2863. This collapses previous ReadServiceInstance() and
  2864. ReadSubordinateContainer() functions which had huge signatures
  2865. and basically had the same code except for the LDAP attributes.
  2866. The old functions had signature like this:
  2867. if ( prnr->ControlFlags & LUP_CONTAINERS )
  2868. {
  2869. status = ReadSubordinateContainer(
  2870. prnr->pRnrConnection,
  2871. preadDn,
  2872. prnr->ControlFlags,
  2873. prnr->ProviderGuid,
  2874. pdwBufSize,
  2875. pqsResults );
  2876. }
  2877. else
  2878. {
  2879. status = ReadServiceInstance(
  2880. prnr->pRnrConnection,
  2881. preadDn,
  2882. prnr->ControlFlags,
  2883. prnr->ProviderGuid,
  2884. prnr->ServiceClassGuid,
  2885. prnr->NumberOfProtocols,
  2886. prnr->pafpProtocols,
  2887. pdwBufSize,
  2888. pqsResults );
  2889. }
  2890. Arguments:
  2891. pRnrConnection -- RnR LDAP connection info
  2892. pwsDN -- DN to read at
  2893. pdwBufSize -- addr of result buffer length;
  2894. on return receives required buffer length
  2895. pqsResults -- query set result buffer
  2896. on return receives results of query
  2897. Return Value:
  2898. NO_ERROR if successful.
  2899. WSAEFAULT if buffer too small.
  2900. ErrorCode on failure.
  2901. --*/
  2902. {
  2903. RNR_STATUS status = NO_ERROR;
  2904. PLDAP pldap;
  2905. DWORD controlFlags;
  2906. BOOL fserviceInstance;
  2907. BOOL freturnedData = FALSE;
  2908. LDAPMessage * presults = NULL;
  2909. DWORD count = 0;
  2910. FLATBUF flatbuf;
  2911. LDAPMessage * object;
  2912. PWSTR * ppvalue = NULL;
  2913. PLDAP_BERVAL * ppberVal = NULL;
  2914. PCSADDR_INFO ptempCsaddrArray = NULL;
  2915. PBYTE pbuf;
  2916. PSTR pbufString;
  2917. PWSTR pcontext;
  2918. WSAQUERYSETW dummyResults;
  2919. INT bufSize;
  2920. PWSTR pfilter;
  2921. PWSTR pname;
  2922. PWSTR pcomment;
  2923. PWSTR attributes[6];
  2924. DNSDBG( TRACE, (
  2925. "ReadQuerySet()\n"
  2926. "\tpRnr = %p\n"
  2927. "\tDN = %S\n"
  2928. "\tbuf size = %p (%d)\n"
  2929. "\tbuffer = %p\n",
  2930. pRnr,
  2931. pwsDN,
  2932. pdwBufSize,
  2933. pdwBufSize ? *pdwBufSize : 0,
  2934. pqsResults ));
  2935. //
  2936. // grab a few common params
  2937. //
  2938. if ( !pRnr->pRnrConnection )
  2939. {
  2940. DNS_ASSERT( FALSE );
  2941. status = WSA_INVALID_PARAMETER;
  2942. goto Exit;
  2943. }
  2944. pldap = pRnr->pRnrConnection->pLdapServer;
  2945. controlFlags = pRnr->ControlFlags;
  2946. //
  2947. // setup ReadServiceInstance\ReadSubordinateContainer diffs
  2948. // - search attributes
  2949. // - search filter
  2950. // - attribute for name
  2951. // - attribute for comment
  2952. //
  2953. // DCR: could select attributes based on LUP_X flags
  2954. // but doubt there's much perf impact here
  2955. //
  2956. fserviceInstance = !(controlFlags & LUP_CONTAINERS);
  2957. if ( fserviceInstance )
  2958. {
  2959. attributes[0] = SERVICE_INSTANCE_NAME;
  2960. attributes[1] = SERVICE_CLASS_ID;
  2961. attributes[2] = SERVICE_VERSION;
  2962. attributes[3] = SERVICE_COMMENT;
  2963. attributes[4] = WINSOCK_ADDRESSES;
  2964. attributes[5] = NULL;
  2965. pfilter = FILTER_OBJECT_CLASS_SERVICE_INSTANCE;
  2966. pname = SERVICE_INSTANCE_NAME;
  2967. pcomment = SERVICE_COMMENT;
  2968. }
  2969. else // read container
  2970. {
  2971. attributes[0] = OBJECT_CLASS;
  2972. attributes[1] = OBJECT_COMMENT;
  2973. attributes[2] = OBJECT_NAME;
  2974. attributes[3] = NULL;
  2975. pfilter = FILTER_OBJECT_CLASS_NTDS_CONTAINER;
  2976. pname = OBJECT_NAME;
  2977. pcomment = OBJECT_COMMENT;
  2978. }
  2979. //
  2980. // init the buffer and flatbuf builder
  2981. //
  2982. // if given buffer that's even less than QUERYSET size
  2983. // use a dummy buffer to avoid useless tests while we
  2984. // build\size
  2985. //
  2986. bufSize = *pdwBufSize - sizeof(WSAQUERYSET);
  2987. if ( bufSize < 0 )
  2988. {
  2989. pqsResults = &dummyResults;
  2990. }
  2991. RtlZeroMemory(
  2992. (PBYTE) pqsResults,
  2993. sizeof(WSAQUERYSETW) );
  2994. FlatBuf_Init(
  2995. & flatbuf,
  2996. (PBYTE) pqsResults + sizeof(WSAQUERYSETW),
  2997. bufSize
  2998. );
  2999. //
  3000. // search
  3001. //
  3002. status = DoLdapSearch(
  3003. "ReadQuerySet",
  3004. FALSE, // no locked
  3005. pldap,
  3006. pwsDN,
  3007. LDAP_SCOPE_BASE,
  3008. pfilter,
  3009. attributes,
  3010. & presults );
  3011. if ( status && !presults )
  3012. {
  3013. WINRNR_PRINT((
  3014. "WINRNR!ReadQuerySet -\n"
  3015. "ldap_search_s() failed with error code: 0%x\n",
  3016. status ));
  3017. status = WSANO_DATA;
  3018. goto Exit;
  3019. }
  3020. //
  3021. // search completed -- check for valid presults
  3022. // - should have one object matching search criteria
  3023. count = ldap_count_entries( pldap, presults );
  3024. if ( count == 0 )
  3025. {
  3026. WINRNR_PRINT((
  3027. "WINRNR!ReadQuerySet -\n"
  3028. "ldap_count_entries() failed\n" ));
  3029. status = WSANO_DATA;
  3030. goto Exit;
  3031. }
  3032. object = ldap_first_entry( pldap, presults );
  3033. if ( !object )
  3034. {
  3035. WINRNR_PRINT((
  3036. "WINRNR!ReadQuerySet -\n"
  3037. "ldap_first_entry() failed\n" ));
  3038. status = WSANO_DATA;
  3039. goto Exit;
  3040. }
  3041. //
  3042. // for ReadServiceInstance -- read the sockaddrs and write to buffer
  3043. // - these are BER values
  3044. //
  3045. if ( fserviceInstance &&
  3046. controlFlags & LUP_RETURN_ADDR )
  3047. {
  3048. DWORD countBerval;
  3049. DWORD iter;
  3050. DWORD countCsaddr = 0;
  3051. PCSADDR_INFO pcsaddr;
  3052. ppberVal = ldap_get_values_len(
  3053. pldap,
  3054. object,
  3055. WINSOCK_ADDRESSES );
  3056. if ( !ppberVal )
  3057. {
  3058. goto WriteName;
  3059. }
  3060. countBerval = ldap_count_values_len( ppberVal );
  3061. //
  3062. // extract each acceptable CSADDR to result buffer
  3063. //
  3064. // note: CSADDRs are written in packed array, so must write
  3065. // them all before writing their corresponding sockaddrs;
  3066. // and since we don't know whether result buffer is
  3067. // sufficient, must allocate temp array to handle unpacking
  3068. //
  3069. ptempCsaddrArray = (PCSADDR_INFO) ALLOC_HEAP(
  3070. countBerval * sizeof(CSADDR_INFO) );
  3071. if ( !ptempCsaddrArray )
  3072. {
  3073. status = ERROR_NO_MEMORY;
  3074. goto Exit;
  3075. }
  3076. //
  3077. // build temp CSADDR_INFO array
  3078. // - unpack from CSADDR_BERVAL format
  3079. // - verify acceptable protocol and family
  3080. pcsaddr = ptempCsaddrArray;
  3081. for ( iter = 0; iter < countBerval; iter++ )
  3082. {
  3083. if ( ! ExtractCsaddrFromBerval(
  3084. pcsaddr,
  3085. ppberVal[iter],
  3086. pRnr->NumberOfProtocols,
  3087. pRnr->pafpProtocols ) )
  3088. {
  3089. continue;
  3090. }
  3091. countCsaddr++;
  3092. pcsaddr++;
  3093. }
  3094. //
  3095. // protocol restrictions eliminated all address data?
  3096. // - return error code to skip this entry so caller
  3097. // can call down again
  3098. //
  3099. // DCR_QUESTION: why is this different than search failing?
  3100. if ( countCsaddr == 0 &&
  3101. pRnr->pafpProtocols &&
  3102. pRnr->NumberOfProtocols )
  3103. {
  3104. status = WSANO_ADDRESS;
  3105. goto Exit;
  3106. }
  3107. //
  3108. // reserve space for CSADDR array
  3109. //
  3110. pbuf = FlatBuf_Reserve(
  3111. & flatbuf,
  3112. countCsaddr * sizeof(CSADDR_INFO),
  3113. ALIGN_LPVOID
  3114. );
  3115. pqsResults->lpcsaBuffer = (PCSADDR_INFO) pbuf;
  3116. pqsResults->dwNumberOfCsAddrs = countCsaddr;
  3117. //
  3118. // write sockaddrs for CSADDRs to result buffer
  3119. //
  3120. // note: that CSADDRs have been written to the result buffer
  3121. // with their sockaddr pointers pointing to the original
  3122. // sockaddrs IN the BERVAL; when we copy the sockaddr data
  3123. // we also need to reset the CSADDR sockaddr pointer
  3124. //
  3125. pcsaddr = ptempCsaddrArray;
  3126. for ( iter = 0; iter < countCsaddr; iter++ )
  3127. {
  3128. // write local sockaddr
  3129. pbuf = FlatBuf_CopyMemory(
  3130. & flatbuf,
  3131. (PBYTE) pcsaddr->LocalAddr.lpSockaddr,
  3132. pcsaddr->LocalAddr.iSockaddrLength,
  3133. ALIGN_DWORD );
  3134. pcsaddr->LocalAddr.lpSockaddr = (PSOCKADDR) pbuf;
  3135. // write remote sockaddr
  3136. pbuf = FlatBuf_CopyMemory(
  3137. & flatbuf,
  3138. (PBYTE) pcsaddr->LocalAddr.lpSockaddr,
  3139. pcsaddr->LocalAddr.iSockaddrLength,
  3140. ALIGN_DWORD );
  3141. pcsaddr->LocalAddr.lpSockaddr = (PSOCKADDR) pbuf;
  3142. pcsaddr++;
  3143. }
  3144. //
  3145. // copy temp CSADDR array to result buffer
  3146. // - space was reserved and aligned above
  3147. //
  3148. pbuf = (PBYTE) pqsResults->lpcsaBuffer;
  3149. if ( pbuf )
  3150. {
  3151. RtlCopyMemory(
  3152. pbuf,
  3153. ptempCsaddrArray,
  3154. countCsaddr * sizeof(CSADDR_INFO) );
  3155. }
  3156. freturnedData = TRUE;
  3157. }
  3158. WriteName:
  3159. //
  3160. // read the name and write it into buffer.
  3161. //
  3162. if ( controlFlags & LUP_RETURN_NAME )
  3163. {
  3164. ppvalue = ldap_get_values(
  3165. pldap,
  3166. object,
  3167. pname );
  3168. if ( ppvalue )
  3169. {
  3170. pbufString = FlatBuf_WriteString_W(
  3171. & flatbuf,
  3172. ppvalue[0] );
  3173. pqsResults->lpszServiceInstanceName = (PWSTR) pbufString;
  3174. freturnedData = TRUE;
  3175. ldap_value_free( ppvalue );
  3176. }
  3177. }
  3178. //
  3179. // for service instance
  3180. // - get serviceClassId
  3181. // - get serviceVersion
  3182. //
  3183. if ( fserviceInstance )
  3184. {
  3185. //
  3186. // read ServiceClassId (GUID) and write it to buffer
  3187. //
  3188. // DCR_QUESTION: originally we copied ServiceClassId passed in
  3189. // rather than one we read?
  3190. //
  3191. if ( controlFlags & LUP_RETURN_TYPE )
  3192. {
  3193. ppberVal = ldap_get_values_len(
  3194. pldap,
  3195. object,
  3196. SERVICE_CLASS_ID );
  3197. if ( ppberVal )
  3198. {
  3199. if ( ppberVal[0]->bv_len == sizeof(GUID) )
  3200. {
  3201. pbuf = FlatBuf_CopyMemory(
  3202. & flatbuf,
  3203. ppberVal[0]->bv_val,
  3204. sizeof(GUID),
  3205. ALIGN_DWORD
  3206. );
  3207. pqsResults->lpServiceClassId = (PGUID) pbuf;
  3208. freturnedData = TRUE;
  3209. }
  3210. ldap_value_free_len( ppberVal );
  3211. }
  3212. }
  3213. //
  3214. // read ServiceVersion and write it to buffer
  3215. //
  3216. if ( controlFlags & LUP_RETURN_VERSION )
  3217. {
  3218. ppberVal = ldap_get_values_len(
  3219. pldap,
  3220. object,
  3221. SERVICE_VERSION );
  3222. if ( ppberVal )
  3223. {
  3224. if ( ppberVal[0]->bv_len == sizeof(WSAVERSION) )
  3225. {
  3226. pbuf = FlatBuf_CopyMemory(
  3227. & flatbuf,
  3228. ppberVal[0]->bv_val,
  3229. sizeof(WSAVERSION),
  3230. ALIGN_DWORD
  3231. );
  3232. pqsResults->lpVersion = (LPWSAVERSION) pbuf;
  3233. freturnedData = TRUE;
  3234. }
  3235. ldap_value_free_len( ppberVal );
  3236. }
  3237. }
  3238. }
  3239. //
  3240. // read comment and copy to buffer
  3241. //
  3242. if ( controlFlags & LUP_RETURN_COMMENT )
  3243. {
  3244. ppvalue = ldap_get_values(
  3245. pldap,
  3246. object,
  3247. pcomment );
  3248. if ( ppvalue )
  3249. {
  3250. pbufString = FlatBuf_WriteString_W(
  3251. & flatbuf,
  3252. ppvalue[0]
  3253. );
  3254. pqsResults->lpszComment = (PWSTR) pbufString;
  3255. freturnedData = TRUE;
  3256. ldap_value_free( ppvalue );
  3257. }
  3258. }
  3259. //
  3260. // if no search results written -- done
  3261. //
  3262. if ( !freturnedData )
  3263. {
  3264. status = WSANO_DATA;
  3265. goto Exit;
  3266. }
  3267. //
  3268. // fill in other queryset fields
  3269. //
  3270. pqsResults->dwSize = sizeof( WSAQUERYSETW );
  3271. pqsResults->dwNameSpace = NS_NTDS;
  3272. //
  3273. // add the provider GUID
  3274. //
  3275. pbuf = FlatBuf_CopyMemory(
  3276. & flatbuf,
  3277. & pRnr->ProviderGuid,
  3278. sizeof(GUID),
  3279. ALIGN_DWORD
  3280. );
  3281. pqsResults->lpNSProviderId = (PGUID) pbuf;
  3282. //
  3283. // add the context string
  3284. //
  3285. pcontext = wcschr( pwsDN, L',' );
  3286. pcontext++;
  3287. pbufString = FlatBuf_WriteString_W(
  3288. & flatbuf,
  3289. pcontext );
  3290. pqsResults->lpszContext = (PWSTR) pbufString;
  3291. //
  3292. // check for inadequate space
  3293. // - set actual buffer size used
  3294. //
  3295. // DCR_QUESTION: do we fix up space all the time?
  3296. // or only when fail
  3297. //
  3298. status = NO_ERROR;
  3299. //*pdwBufSize -= flatbuf.BytesLeft;
  3300. if ( flatbuf.BytesLeft < 0 )
  3301. {
  3302. *pdwBufSize -= flatbuf.BytesLeft;
  3303. status = WSAEFAULT;
  3304. }
  3305. Exit:
  3306. ldap_msgfree( presults );
  3307. FREE_HEAP( ptempCsaddrArray );
  3308. DNSDBG( TRACE, (
  3309. "Leave ReadQuerySet() => %d\n"
  3310. "\tpRnr = %p\n"
  3311. "\tpQuerySet = %p\n"
  3312. "\tbufLength = %d\n",
  3313. status,
  3314. pRnr,
  3315. pqsResults,
  3316. pdwBufSize ? *pdwBufSize : 0
  3317. ));
  3318. return( status );
  3319. }
  3320. //
  3321. // NSP definition
  3322. //
  3323. INT
  3324. WINAPI
  3325. NTDS_Cleanup(
  3326. IN PGUID pProviderId
  3327. )
  3328. /*++
  3329. Routine Description:
  3330. Cleanup NTDS provider.
  3331. This is called by WSACleanup() if NSPStartup was called.
  3332. Arguments:
  3333. pProviderId -- provider GUID
  3334. Return Value:
  3335. None
  3336. --*/
  3337. {
  3338. DNSDBG( TRACE, ( "NTDS_Cleanup( %p )\n", pProviderId ));
  3339. // free any global memory allocated
  3340. DnsApiFree( g_pHostName );
  3341. DnsApiFree( g_pFullName );
  3342. g_pHostName = NULL;
  3343. g_pFullName = NULL;
  3344. //
  3345. // DCR: note potentially leaking RnR lookup handles
  3346. // we are not keeping list of lookup handles,
  3347. // so can not clean them up, if callers expect WSACleanup() to
  3348. // handle it -- they'll leak
  3349. //
  3350. return( NO_ERROR );
  3351. }
  3352. INT
  3353. WINAPI
  3354. NTDS_InstallServiceClass(
  3355. IN PGUID pProviderId,
  3356. IN PWSASERVICECLASSINFOW pServiceClassInfo
  3357. )
  3358. /*++
  3359. Routine Description:
  3360. Install service class in directory.
  3361. Arguments:
  3362. pProviderId -- provider GUID
  3363. pServiceClassInfo -- service class info blob
  3364. Return Value:
  3365. NO_ERROR if successful.
  3366. SOCKET_ERROR on failure. GetLastError() contains status.
  3367. --*/
  3368. {
  3369. RNR_STATUS status = NO_ERROR;
  3370. PRNR_CONNECTION prnrCon = NULL;
  3371. DWORD iter;
  3372. DWORD count = 0;
  3373. PDN_ARRAY pdnArray = NULL;
  3374. BOOL fisNTDS = FALSE;
  3375. PGUID pclassGuid;
  3376. DNSDBG( TRACE, (
  3377. "NTDS_InstallServiceClass()\n"
  3378. "\tpGuid = %p\n"
  3379. "\tpServiceClass = %p\n",
  3380. pProviderId,
  3381. pServiceClassInfo ));
  3382. IF_DNSDBG( TRACE )
  3383. {
  3384. DnsDbg_Guid(
  3385. "InstallServiceClass Provider GUID:",
  3386. pProviderId );
  3387. }
  3388. IF_DNSDBG( TRACE )
  3389. {
  3390. DnsDbg_WsaServiceClassInfo(
  3391. "InstallServiceClass() ServiceClassInfo:",
  3392. pServiceClassInfo,
  3393. TRUE // unicode
  3394. );
  3395. }
  3396. //
  3397. // validate service class
  3398. //
  3399. if ( ! pServiceClassInfo ||
  3400. ! pServiceClassInfo->lpServiceClassId ||
  3401. ! pServiceClassInfo->lpszServiceClassName ||
  3402. ( pServiceClassInfo->dwCount &&
  3403. !pServiceClassInfo->lpClassInfos ) )
  3404. {
  3405. status = WSA_INVALID_PARAMETER;
  3406. goto Exit;
  3407. }
  3408. //
  3409. // don't install the DNS services -- they already exist
  3410. //
  3411. pclassGuid = pServiceClassInfo->lpServiceClassId;
  3412. if ( GuidEqual( pclassGuid, &HostAddrByInetStringGuid ) ||
  3413. GuidEqual( pclassGuid, &ServiceByNameGuid ) ||
  3414. GuidEqual( pclassGuid, &HostAddrByNameGuid ) ||
  3415. GuidEqual( pclassGuid, &HostNameGuid ) ||
  3416. IS_SVCID_DNS( pclassGuid ) )
  3417. {
  3418. status = WSA_INVALID_PARAMETER;
  3419. goto Exit;
  3420. }
  3421. for ( iter = 0; iter < pServiceClassInfo->dwCount; iter++ )
  3422. {
  3423. if ( pServiceClassInfo->lpClassInfos[iter].dwNameSpace == NS_NTDS ||
  3424. pServiceClassInfo->lpClassInfos[iter].dwNameSpace == NS_ALL )
  3425. {
  3426. fisNTDS = TRUE;
  3427. break;
  3428. }
  3429. }
  3430. if ( !fisNTDS )
  3431. {
  3432. status = WSA_INVALID_PARAMETER;
  3433. goto Exit;
  3434. }
  3435. //
  3436. // connect to directory
  3437. //
  3438. status = ConnectToDefaultLDAPDirectory( FALSE, &prnrCon );
  3439. if ( status != NO_ERROR )
  3440. {
  3441. goto Exit;
  3442. }
  3443. //
  3444. // check if service class already installed in directory
  3445. //
  3446. status = FindServiceClass(
  3447. prnrCon,
  3448. pServiceClassInfo->lpszServiceClassName,
  3449. pclassGuid,
  3450. NULL, // don't need count
  3451. &pdnArray );
  3452. if ( status != NO_ERROR )
  3453. {
  3454. goto Exit;
  3455. }
  3456. //
  3457. // service class not found -- add it
  3458. //
  3459. if ( !pdnArray )
  3460. {
  3461. status = AddServiceClass(
  3462. prnrCon,
  3463. pclassGuid,
  3464. pServiceClassInfo->lpszServiceClassName,
  3465. &pdnArray );
  3466. if ( status != NO_ERROR )
  3467. {
  3468. goto Exit;
  3469. }
  3470. }
  3471. //
  3472. // loop through the WSANSCLASSINFO's for the given pServiceClassInfo
  3473. // - add/modify the ones with our dwNameSpace to the NSClassInfo
  3474. // property of the ServiceClass object.
  3475. //
  3476. // DCR: continue on error here and just save failing status?
  3477. //
  3478. for ( iter = 0; iter < pServiceClassInfo->dwCount; iter++ )
  3479. {
  3480. PWSANSCLASSINFO pclassInfo = &pServiceClassInfo->lpClassInfos[iter];
  3481. if ( pclassInfo->dwNameSpace == NS_NTDS ||
  3482. pclassInfo->dwNameSpace == NS_ALL )
  3483. {
  3484. status = AddClassInfoToServiceClass(
  3485. prnrCon,
  3486. pdnArray->Strings[0],
  3487. pclassInfo );
  3488. if ( status != NO_ERROR )
  3489. {
  3490. goto Exit;
  3491. }
  3492. }
  3493. }
  3494. Exit:
  3495. FreeDnArray( pdnArray );
  3496. DisconnectFromLDAPDirectory( &prnrCon );
  3497. DNSDBG( TRACE, (
  3498. "Leave InstallServiceClass() => %d\n",
  3499. status ));
  3500. return( SetError( status ) );
  3501. }
  3502. INT
  3503. WINAPI
  3504. NTDS_RemoveServiceClass(
  3505. IN PGUID pProviderId,
  3506. IN PGUID pServiceClassId
  3507. )
  3508. /*++
  3509. Routine Description:
  3510. Remove service class from directory.
  3511. Arguments:
  3512. pProviderId -- provider GUID
  3513. pServiceClassInfo -- service class info blob
  3514. Return Value:
  3515. NO_ERROR if successful.
  3516. SOCKET_ERROR on failure. GetLastError() contains status.
  3517. --*/
  3518. {
  3519. RNR_STATUS status = NO_ERROR;
  3520. PRNR_CONNECTION prnrCon = NULL;
  3521. DWORD serviceCount = 0;
  3522. DWORD iter;
  3523. PDN_ARRAY pdnArray = NULL;
  3524. DNSDBG( TRACE, (
  3525. "NTDS_RemoveServiceClass()\n"
  3526. "\tpProviderGuid = %p\n"
  3527. "\tpClassGuid = %p\n",
  3528. pProviderId,
  3529. pServiceClassId ));
  3530. IF_DNSDBG( TRACE )
  3531. {
  3532. DnsDbg_Guid(
  3533. "RemoveServiceClass Provider GUID:",
  3534. pProviderId );
  3535. }
  3536. IF_DNSDBG( TRACE )
  3537. {
  3538. DnsDbg_Guid(
  3539. "RemoveServiceClass GUID:",
  3540. pServiceClassId );
  3541. }
  3542. //
  3543. // validation
  3544. //
  3545. if ( !pServiceClassId )
  3546. {
  3547. return( SetError( WSA_INVALID_PARAMETER ) );
  3548. }
  3549. //
  3550. // connect to directory
  3551. //
  3552. status = ConnectToDefaultLDAPDirectory(
  3553. FALSE,
  3554. &prnrCon );
  3555. if ( status != NO_ERROR )
  3556. {
  3557. goto Exit;
  3558. }
  3559. //
  3560. // find service class in directory
  3561. //
  3562. status = FindServiceClass(
  3563. prnrCon,
  3564. NULL,
  3565. pServiceClassId,
  3566. NULL, // don't need count
  3567. & pdnArray );
  3568. if ( status != NO_ERROR )
  3569. {
  3570. goto Exit;
  3571. }
  3572. if ( !pdnArray )
  3573. {
  3574. status = WSATYPE_NOT_FOUND;
  3575. goto Exit;
  3576. }
  3577. //
  3578. // should have found only one ServiceClass in the container,
  3579. // CN=WinsockServices, ... , with a ServiceClassId of pServiceClassId.
  3580. //
  3581. ASSERT( pdnArray->Count == 1 );
  3582. //
  3583. // found service class
  3584. // - check for service instances objects for the the class
  3585. // if found, we can't remove the class until instances
  3586. // are removed
  3587. //
  3588. status = FindServiceInstance(
  3589. prnrCon,
  3590. NULL, // no instance names
  3591. pServiceClassId, // find class by GUID
  3592. NULL, // no version
  3593. prnrCon->DomainDN, // context
  3594. TRUE, // search entire subtree
  3595. &serviceCount, // retrieve count
  3596. NULL // don't need DNs just count
  3597. );
  3598. if ( status != NO_ERROR )
  3599. {
  3600. goto Exit;
  3601. }
  3602. if ( serviceCount > 0 )
  3603. {
  3604. // still have service instances that reference the class
  3605. // so can't remove class
  3606. status = WSAETOOMANYREFS;
  3607. goto Exit;
  3608. }
  3609. //
  3610. // remove the service class
  3611. // - first string in pdnArray contains DN of the ServiceClass
  3612. //
  3613. status = ldap_delete_s(
  3614. prnrCon->pLdapServer,
  3615. pdnArray->Strings[0] );
  3616. if ( status != NO_ERROR )
  3617. {
  3618. WINRNR_PRINT((
  3619. "WINRNR!NTDS_RemoveServiceClass - ldap_delete_s()\n"
  3620. "failed with error code: 0%x\n",
  3621. status ));
  3622. status = WSAEACCES;
  3623. goto Exit;
  3624. }
  3625. Exit:
  3626. FreeDnArray( pdnArray );
  3627. DisconnectFromLDAPDirectory( &prnrCon );
  3628. DNSDBG( TRACE, (
  3629. "Leave RemoveServiceClass() => %d\n",
  3630. status ));
  3631. return( SetError( status ) );
  3632. }
  3633. INT
  3634. WINAPI
  3635. NTDS_GetServiceClassInfo(
  3636. IN PGUID pProviderId,
  3637. IN OUT PDWORD pdwBufSize,
  3638. IN OUT PWSASERVICECLASSINFOW pServiceClassInfo
  3639. )
  3640. /*++
  3641. Routine Description:
  3642. Read service class info
  3643. Arguments:
  3644. pProviderId -- provider GUID
  3645. pdwBufSize -- addr with and to recv buffer size
  3646. input: buffer size
  3647. output: bytes required or written
  3648. pServiceClassInfo -- service class info buffer
  3649. input: valid service class GUID (lpServiceClassId)
  3650. output: filled in with service class info; subfield data follows
  3651. WSASERVICECLASSINFO struct
  3652. Return Value:
  3653. NO_ERROR if successful.
  3654. SOCKET_ERROR on failure. GetLastError() contains status.
  3655. --*/
  3656. {
  3657. RNR_STATUS status = NO_ERROR;
  3658. PRNR_CONNECTION prnrCon = NULL;
  3659. DWORD count = 0;
  3660. PDN_ARRAY pdnArray = NULL;
  3661. DNSDBG( TRACE, (
  3662. "NTDS_GetServiceClassInfo()\n"
  3663. "\tpProviderGuid = %p\n"
  3664. "\tpdwBufSize = %p (%d)\n"
  3665. "\tpClassInfo = %p\n",
  3666. pProviderId,
  3667. pdwBufSize,
  3668. pdwBufSize ? *pdwBufSize : 0,
  3669. pServiceClassInfo ));
  3670. //
  3671. // validate
  3672. //
  3673. if ( !pServiceClassInfo || !pdwBufSize )
  3674. {
  3675. status = WSA_INVALID_PARAMETER;
  3676. goto Exit;
  3677. }
  3678. IF_DNSDBG( TRACE )
  3679. {
  3680. DnsDbg_WsaServiceClassInfo(
  3681. "GetServiceClassInfo ServiceClassInfo:",
  3682. pServiceClassInfo,
  3683. TRUE // unicode
  3684. );
  3685. }
  3686. //
  3687. // connect
  3688. //
  3689. status = ConnectToDefaultLDAPDirectory(
  3690. FALSE,
  3691. &prnrCon );
  3692. if ( status != NO_ERROR )
  3693. {
  3694. goto Exit;
  3695. }
  3696. //
  3697. // find service class
  3698. //
  3699. status = FindServiceClass(
  3700. prnrCon,
  3701. NULL,
  3702. pServiceClassInfo->lpServiceClassId,
  3703. NULL, // don't need count
  3704. &pdnArray );
  3705. if ( status != NO_ERROR )
  3706. {
  3707. goto Exit;
  3708. }
  3709. if ( !pdnArray )
  3710. {
  3711. status = WSATYPE_NOT_FOUND;
  3712. goto Exit;
  3713. }
  3714. // should be only one ServiceClass in the container,
  3715. // OU=WinsockServices, ... , with a ServiceClassId of pServiceClassId.
  3716. ASSERT( pdnArray->Count == 1 );
  3717. //
  3718. // read attributes of the ServiceClass into buffer
  3719. //
  3720. status = ReadServiceClass(
  3721. prnrCon,
  3722. pdnArray->Strings[0],
  3723. pdwBufSize,
  3724. pServiceClassInfo );
  3725. Exit:
  3726. FreeDnArray( pdnArray );
  3727. DisconnectFromLDAPDirectory( &prnrCon );
  3728. IF_DNSDBG( TRACE )
  3729. {
  3730. DNS_PRINT((
  3731. "Leave GetServiceClassInfo() = %d\n"
  3732. "\tbuf size = %d\n",
  3733. status,
  3734. pdwBufSize ? *pdwBufSize : 0 ));
  3735. if ( status == NO_ERROR )
  3736. {
  3737. DnsDbg_WsaServiceClassInfo(
  3738. "Leaving GetServiceClassInfo:",
  3739. pServiceClassInfo,
  3740. TRUE // unicode
  3741. );
  3742. }
  3743. }
  3744. return( SetError( status ) );
  3745. }
  3746. INT
  3747. WINAPI
  3748. NTDS_SetService(
  3749. IN PGUID pProviderId,
  3750. IN PWSASERVICECLASSINFOW pServiceClassInfo,
  3751. IN PWSAQUERYSETW pqsReqInfo,
  3752. IN WSAESETSERVICEOP essOperation,
  3753. IN DWORD dwControlFlags
  3754. )
  3755. /*++
  3756. Routine Description:
  3757. Read service class info
  3758. Arguments:
  3759. pProviderId -- provider GUID
  3760. pdwBufSize -- addr with and to recv buffer size
  3761. input: buffer size
  3762. output: bytes required or written
  3763. pServiceClassInfo -- service class info buffer
  3764. input: valid service class GUID (lpServiceClassId)
  3765. output: filled in with service class info; subfield data follows
  3766. WSASERVICECLASSINFO struct
  3767. Return Value:
  3768. NO_ERROR if successful.
  3769. SOCKET_ERROR on failure. GetLastError() contains status.
  3770. --*/
  3771. {
  3772. RNR_STATUS status = NO_ERROR;
  3773. PRNR_CONNECTION prnrCon = NULL;
  3774. DWORD count = 0;
  3775. DWORD iter;
  3776. PDN_ARRAY pdnArray = NULL;
  3777. DNSDBG( TRACE, (
  3778. "NTDS_SetService()\n"
  3779. "\tpProviderGuid = %p\n"
  3780. "\tpServiceClassInfo = %p\n"
  3781. "\tpQuerySet = %p\n"
  3782. "\tOperation = %d\n"
  3783. "\tControlFlags = %08x\n",
  3784. pProviderId,
  3785. pServiceClassInfo,
  3786. pqsReqInfo,
  3787. essOperation,
  3788. dwControlFlags ));
  3789. IF_DNSDBG( TRACE )
  3790. {
  3791. DnsDbg_Lock();
  3792. DnsDbg_Guid(
  3793. "SetService() Provider GUID:",
  3794. pProviderId );
  3795. DnsDbg_WsaServiceClassInfo(
  3796. "SetService ServiceClassInfo:",
  3797. pServiceClassInfo,
  3798. TRUE // unicode
  3799. );
  3800. DnsDbg_WsaQuerySet(
  3801. "SetService QuerySet:",
  3802. pqsReqInfo,
  3803. TRUE // unicode
  3804. );
  3805. DnsDbg_Unlock();
  3806. }
  3807. //
  3808. // param validation
  3809. //
  3810. if ( !pqsReqInfo )
  3811. {
  3812. return( SetError( WSA_INVALID_PARAMETER ) );
  3813. }
  3814. if ( pqsReqInfo->dwSize != sizeof( WSAQUERYSET ) )
  3815. {
  3816. return( SetError( WSAVERNOTSUPPORTED ) );
  3817. }
  3818. //
  3819. // connect
  3820. //
  3821. status = ConnectToDefaultLDAPDirectory(
  3822. FALSE,
  3823. &prnrCon );
  3824. if ( status != NO_ERROR )
  3825. {
  3826. goto Exit;
  3827. }
  3828. //
  3829. // Figure out what operation and with what control flags are to be
  3830. // performed.
  3831. //
  3832. switch( essOperation )
  3833. {
  3834. case RNRSERVICE_REGISTER:
  3835. //
  3836. // check if service already registered
  3837. //
  3838. status = FindServiceInstance(
  3839. prnrCon,
  3840. pqsReqInfo->lpszServiceInstanceName,
  3841. pqsReqInfo->lpServiceClassId,
  3842. pqsReqInfo->lpVersion,
  3843. NULL, // no context
  3844. FALSE, // one level search
  3845. NULL, // don't need count
  3846. &pdnArray // get instance DNs
  3847. );
  3848. if ( status != NO_ERROR )
  3849. {
  3850. goto Exit;
  3851. }
  3852. //
  3853. // service instances doesn't exist => need to add
  3854. // - verify service class (matching GUID) exists
  3855. // - create instance of class
  3856. //
  3857. if ( !pdnArray )
  3858. {
  3859. PDN_ARRAY pserviceArray = NULL;
  3860. status = FindServiceClass(
  3861. prnrCon,
  3862. NULL, // no class name, using GUID
  3863. pqsReqInfo->lpServiceClassId,
  3864. & count,
  3865. NULL // class DN not required
  3866. );
  3867. if ( status != NO_ERROR )
  3868. {
  3869. goto Exit;
  3870. }
  3871. if ( count == 0 )
  3872. {
  3873. status = WSA_INVALID_PARAMETER;
  3874. goto Exit;
  3875. }
  3876. DNS_ASSERT( count == 1 );
  3877. status = AddServiceInstance(
  3878. prnrCon,
  3879. pqsReqInfo->lpszServiceInstanceName,
  3880. pqsReqInfo->lpServiceClassId,
  3881. pqsReqInfo->lpVersion,
  3882. pqsReqInfo->lpszComment,
  3883. & pdnArray
  3884. );
  3885. if ( status != NO_ERROR )
  3886. {
  3887. goto Exit;
  3888. }
  3889. }
  3890. //
  3891. // add CSADDR_INFO
  3892. // to an Octet string, then try add it.
  3893. //
  3894. for ( iter = 0; iter < pqsReqInfo->dwNumberOfCsAddrs; iter++ )
  3895. {
  3896. status = ModifyAddressInServiceInstance(
  3897. prnrCon,
  3898. pdnArray->Strings[0],
  3899. & pqsReqInfo->lpcsaBuffer[iter],
  3900. TRUE // add address
  3901. );
  3902. if ( status != NO_ERROR )
  3903. {
  3904. goto Exit;
  3905. }
  3906. }
  3907. break;
  3908. case RNRSERVICE_DEREGISTER:
  3909. case RNRSERVICE_DELETE:
  3910. status = FindServiceInstance(
  3911. prnrCon,
  3912. pqsReqInfo->lpszServiceInstanceName,
  3913. pqsReqInfo->lpServiceClassId,
  3914. pqsReqInfo->lpVersion,
  3915. NULL, // no context
  3916. FALSE, // one level search
  3917. NULL, // don't need count
  3918. & pdnArray // get DN array
  3919. );
  3920. if ( status != NO_ERROR )
  3921. {
  3922. goto Exit;
  3923. }
  3924. if ( !pdnArray )
  3925. {
  3926. // no service instance of given name found
  3927. status = WSATYPE_NOT_FOUND;
  3928. goto Exit;
  3929. }
  3930. DNS_ASSERT( pdnArray->Count == 1 );
  3931. //
  3932. // delete each CSADDR_INFO in pqsReqInfo from service instance
  3933. //
  3934. for ( iter = 0; iter < pqsReqInfo->dwNumberOfCsAddrs; iter++ )
  3935. {
  3936. status = ModifyAddressInServiceInstance(
  3937. prnrCon,
  3938. pdnArray->Strings[0],
  3939. & pqsReqInfo->lpcsaBuffer[iter],
  3940. FALSE // remove address
  3941. );
  3942. if ( status != NO_ERROR )
  3943. {
  3944. goto Exit;
  3945. }
  3946. }
  3947. //
  3948. // delete service?
  3949. // - RNRSERVICE_DELETE operation
  3950. // - no addresses on ServiceInstance object
  3951. // => then delete the serviceInstance
  3952. //
  3953. // DCR_QUESTION: RNRSERVICE_DELETE doesn't whack service
  3954. // regardless of existing CSADDRs?
  3955. //
  3956. if ( essOperation == RNRSERVICE_DELETE )
  3957. {
  3958. status = GetAddressCountFromServiceInstance(
  3959. prnrCon,
  3960. pdnArray->Strings[0],
  3961. & count );
  3962. if ( status != NO_ERROR )
  3963. {
  3964. goto Exit;
  3965. }
  3966. if ( count == 0 )
  3967. {
  3968. status = ldap_delete_s(
  3969. prnrCon->pLdapServer,
  3970. pdnArray->Strings[0] );
  3971. if ( status != NO_ERROR )
  3972. {
  3973. WINRNR_PRINT((
  3974. "WINRNR!NTDS_SetService - ldap_delete_s()\n"
  3975. "failed with error code: 0%x\n",
  3976. status ));
  3977. status = WSAEACCES;
  3978. goto Exit;
  3979. }
  3980. }
  3981. }
  3982. break;
  3983. default :
  3984. status = WSA_INVALID_PARAMETER;
  3985. goto Exit;
  3986. }
  3987. Exit:
  3988. DNSDBG( TRACE, (
  3989. "Leave NTDS_SetService() => %d\n",
  3990. status ));
  3991. FreeDnArray( pdnArray );
  3992. DisconnectFromLDAPDirectory( &prnrCon );
  3993. return( SetError(status) );
  3994. }
  3995. INT
  3996. WINAPI
  3997. NTDS_LookupServiceBegin(
  3998. IN PGUID pProviderId,
  3999. IN PWSAQUERYSETW pqsRestrictions,
  4000. IN PWSASERVICECLASSINFOW pServiceClassInfo,
  4001. IN DWORD dwControlFlags,
  4002. OUT PHANDLE phLookup
  4003. )
  4004. /*++
  4005. Routine Description:
  4006. Start an NTDS service query.
  4007. Arguments:
  4008. pProviderId -- provider GUID
  4009. pqsRestrictions -- restrictions on query
  4010. pServiceClassInfo -- service class info blob
  4011. dwControlFlags -- query control flags
  4012. phLookup -- addr to recv RnR lookup handle
  4013. Return Value:
  4014. NO_ERROR if successful.
  4015. SOCKET_ERROR on failure. GetLastError() contains status.
  4016. --*/
  4017. {
  4018. RNR_STATUS status = NO_ERROR;
  4019. PRNR_LOOKUP prnr = NULL;
  4020. DWORD iter;
  4021. PWSTR pstring;
  4022. PBYTE pmem;
  4023. PGUID pclassGuid;
  4024. DNSDBG( TRACE, (
  4025. "NTDS_LookupServiceBegin()\n"
  4026. "\tpProviderGuid = %p\n"
  4027. "\tpqsRestrictions = %p\n"
  4028. "\tpServiceClassInfo = %p\n"
  4029. "\tControlFlags = %08x\n",
  4030. pProviderId,
  4031. pqsRestrictions,
  4032. pServiceClassInfo,
  4033. dwControlFlags ));
  4034. IF_DNSDBG( TRACE )
  4035. {
  4036. DnsDbg_Lock();
  4037. DnsDbg_Guid(
  4038. "LookupServiceBegin Provider GUID:",
  4039. pProviderId
  4040. );
  4041. DnsDbg_WsaQuerySet(
  4042. "LookupServiceBegin QuerySet:",
  4043. pqsRestrictions,
  4044. TRUE // unicode
  4045. );
  4046. DnsDbg_WsaServiceClassInfo(
  4047. "LookupServiceBegin ServiceClassInfo:",
  4048. pServiceClassInfo,
  4049. TRUE // unicode
  4050. );
  4051. DnsDbg_Unlock();
  4052. }
  4053. //
  4054. // parameter validation
  4055. //
  4056. if ( !pqsRestrictions ||
  4057. !pProviderId ||
  4058. !pqsRestrictions->lpServiceClassId )
  4059. {
  4060. status = WSA_INVALID_PARAMETER;
  4061. goto Failed;
  4062. }
  4063. if ( pqsRestrictions->dwNameSpace != NS_ALL &&
  4064. pqsRestrictions->dwNameSpace != NS_NTDS )
  4065. {
  4066. status = WSAEINVAL;
  4067. goto Failed;
  4068. }
  4069. //
  4070. // if known DNS lookup -- you're in the wrong provider
  4071. //
  4072. pclassGuid = pqsRestrictions->lpServiceClassId;
  4073. if ( GuidEqual( pclassGuid, &HostAddrByInetStringGuid ) ||
  4074. GuidEqual( pclassGuid, &ServiceByNameGuid ) ||
  4075. GuidEqual( pclassGuid, &HostAddrByNameGuid ) ||
  4076. GuidEqual( pclassGuid, &HostNameGuid ) ||
  4077. IS_SVCID_DNS( pclassGuid ) )
  4078. {
  4079. status = WSASERVICE_NOT_FOUND;
  4080. goto Failed;
  4081. }
  4082. if ( !( dwControlFlags & LUP_CONTAINERS ) &&
  4083. pqsRestrictions->lpszServiceInstanceName == NULL )
  4084. {
  4085. status = WSA_INVALID_PARAMETER;
  4086. goto Failed;
  4087. }
  4088. DNSDBG( TRACE, (
  4089. "VALID LookupServiceBegin ...\n" ));
  4090. //
  4091. // If were not enumerating containers, we need to test to see if name
  4092. // is TCPs (DNS).
  4093. //
  4094. if ( !( dwControlFlags & LUP_CONTAINERS ) )
  4095. {
  4096. //
  4097. // Need to test the ppwsServiceName to see if it is the same
  4098. // as that of the local machine name. If it is, then we return with
  4099. // an error since we don't know how to handle this scenario.
  4100. //
  4101. // DCR: fix local name compare
  4102. // DCR: this doesn't work on local name as service instance!!!!
  4103. //
  4104. if ( !g_pHostName )
  4105. {
  4106. g_pHostName = DnsQueryConfigAlloc(
  4107. DnsConfigHostName_W,
  4108. NULL );
  4109. }
  4110. if ( DnsNameCompare_W(
  4111. pqsRestrictions->lpszServiceInstanceName,
  4112. g_pHostName ) )
  4113. {
  4114. status = WSA_INVALID_PARAMETER;
  4115. goto Failed;
  4116. }
  4117. //
  4118. // Need to test the ppwsServiceName to see if it is the same
  4119. // as that of the local machine's DNS name. If it is, then we return with
  4120. // an error since we don't know how to handle this scenario.
  4121. //
  4122. if ( !g_pFullName )
  4123. {
  4124. g_pFullName = DnsQueryConfigAlloc(
  4125. DnsConfigFullHostName_W,
  4126. NULL );
  4127. }
  4128. if ( DnsNameCompare_W(
  4129. pqsRestrictions->lpszServiceInstanceName,
  4130. g_pFullName ) )
  4131. {
  4132. status = WSA_INVALID_PARAMETER;
  4133. goto Failed;
  4134. }
  4135. }
  4136. if ( pqsRestrictions->dwSize != sizeof( WSAQUERYSET ) )
  4137. {
  4138. status = WSAVERNOTSUPPORTED;
  4139. goto Failed;
  4140. }
  4141. if ( pqsRestrictions->lpNSProviderId &&
  4142. !GuidEqual( pqsRestrictions->lpNSProviderId, pProviderId ) )
  4143. {
  4144. status = WSAEINVALIDPROVIDER;
  4145. goto Failed;
  4146. }
  4147. //
  4148. // create RnR lookup context
  4149. //
  4150. prnr = (PRNR_LOOKUP) ALLOC_HEAP_ZERO( sizeof(RNR_LOOKUP) );
  4151. if ( !prnr )
  4152. {
  4153. status = ERROR_NO_MEMORY;
  4154. goto Failed;
  4155. }
  4156. prnr->Signature = RNR_SIGNATURE;
  4157. prnr->ControlFlags = dwControlFlags;
  4158. //
  4159. // copy subfields
  4160. // - service class GUID and version have buffers in RnR blob
  4161. // - instance name, context, proto array we alloc
  4162. //
  4163. RtlCopyMemory(
  4164. &prnr->ProviderGuid,
  4165. pProviderId,
  4166. sizeof(GUID) );
  4167. if ( pqsRestrictions->lpServiceClassId )
  4168. {
  4169. RtlCopyMemory(
  4170. &prnr->ServiceClassGuid,
  4171. pqsRestrictions->lpServiceClassId,
  4172. sizeof(GUID) );
  4173. }
  4174. if ( pqsRestrictions->lpVersion )
  4175. {
  4176. RtlCopyMemory(
  4177. &prnr->WsaVersion,
  4178. pqsRestrictions->lpVersion,
  4179. sizeof(WSAVERSION) );
  4180. prnr->pVersion = &prnr->WsaVersion;
  4181. }
  4182. if ( pqsRestrictions->lpszServiceInstanceName )
  4183. {
  4184. pstring = Dns_CreateStringCopy_W(
  4185. pqsRestrictions->lpszServiceInstanceName );
  4186. if ( !pstring )
  4187. {
  4188. status = ERROR_NO_MEMORY;
  4189. goto Failed;
  4190. }
  4191. prnr->pwsServiceName = pstring;
  4192. }
  4193. if ( pqsRestrictions->lpszContext )
  4194. {
  4195. pstring = Dns_CreateStringCopy_W(
  4196. pqsRestrictions->lpszContext );
  4197. if ( !pstring )
  4198. {
  4199. status = ERROR_NO_MEMORY;
  4200. goto Failed;
  4201. }
  4202. prnr->pwsContext = pstring;
  4203. }
  4204. if ( pqsRestrictions->dwNumberOfProtocols > 0 )
  4205. {
  4206. pmem = Dns_AllocMemCopy(
  4207. pqsRestrictions->lpafpProtocols,
  4208. pqsRestrictions->dwNumberOfProtocols * sizeof(AFPROTOCOLS) );
  4209. if ( !pmem )
  4210. {
  4211. status = ERROR_NO_MEMORY;
  4212. goto Failed;
  4213. }
  4214. prnr->pafpProtocols = (LPAFPROTOCOLS) pmem;
  4215. prnr->NumberOfProtocols = pqsRestrictions->dwNumberOfProtocols;
  4216. }
  4217. *phLookup = (HANDLE) prnr;
  4218. DNSDBG( TRACE, (
  4219. "Leave NTDS_LookupServiceBegin() => Success\n"
  4220. "\tpRnr = %p\n",
  4221. prnr ));
  4222. IF_DNSDBG( TRACE )
  4223. {
  4224. DnsDbg_RnrLookup( "RnR Lookup Handle:", prnr );
  4225. }
  4226. return NO_ERROR;
  4227. Failed:
  4228. FreeRnrLookup( prnr );
  4229. DNSDBG( TRACE, (
  4230. "Leave NTDS_LookupServiceBegin() => %d\n",
  4231. status ));
  4232. return SetError(status);
  4233. }
  4234. INT
  4235. WINAPI
  4236. NTDS_LookupServiceNext(
  4237. IN HANDLE hLookup,
  4238. IN DWORD dwControlFlags,
  4239. IN OUT PDWORD pdwBufferLength,
  4240. OUT PWSAQUERYSETW pqsResults
  4241. )
  4242. /*++
  4243. Routine Description:
  4244. Execute NTDS name space service query.
  4245. Queries for next instance result of query.
  4246. Arguments:
  4247. hLookup -- RnR lookup handle from NTDS_LookupServiceBegin
  4248. dwControlFlags -- control flags on query
  4249. pdwBufSize -- addr with and to recv buffer size
  4250. input: buffer size
  4251. output: bytes required or written
  4252. pqsResults -- query set buffer
  4253. input: ignored
  4254. output: filled in with query set results; subfield data follows
  4255. WSASQUERYSET struct
  4256. Return Value:
  4257. NO_ERROR if successful.
  4258. SOCKET_ERROR on failure. GetLastError() contains status.
  4259. WSA_E_NO_MORE -- if no more results for query
  4260. WSASERVICE_NOT_FOUND -- if no results found for query
  4261. --*/
  4262. {
  4263. RNR_STATUS status = NO_ERROR;
  4264. PRNR_LOOKUP prnr = (PRNR_LOOKUP) hLookup;
  4265. PDN_ARRAY pdnArray = NULL;
  4266. DNSDBG( TRACE, (
  4267. "NTDS_LookupServiceNext()\n"
  4268. "\tpRnr = %p\n"
  4269. "\tControlFlags = %08x\n"
  4270. "\tpdwBufLength = %p (len=%d)\n"
  4271. "\tpResultBuffer = %p\n",
  4272. hLookup,
  4273. dwControlFlags,
  4274. pdwBufferLength,
  4275. pdwBufferLength ? *pdwBufferLength : 0,
  4276. pqsResults ));
  4277. //
  4278. // validate RnR handle
  4279. //
  4280. if ( !prnr ||
  4281. prnr->Signature != RNR_SIGNATURE )
  4282. {
  4283. DNSDBG( ANY, (
  4284. "ERROR: Invalid RnR lookup handle!\n"
  4285. "\thandle = %p\n"
  4286. "\tsig = %p\n",
  4287. prnr,
  4288. prnr ? prnr->Signature : 0 ));
  4289. DNS_ASSERT( !prnr || prnr->Signature != RNR_SIGNATURE_FREE );
  4290. status = WSA_INVALID_HANDLE;
  4291. goto Exit;
  4292. }
  4293. IF_DNSDBG( TRACE )
  4294. {
  4295. DnsDbg_RnrLookup(
  4296. "LookupServiceNext RnR Handle:",
  4297. prnr );
  4298. }
  4299. //
  4300. // if no connection -- first LookupServiceNext
  4301. // - connect to directory
  4302. // - do search for desired objects
  4303. //
  4304. if ( !prnr->pRnrConnection )
  4305. {
  4306. status = ConnectToDefaultLDAPDirectory(
  4307. TRUE,
  4308. &prnr->pRnrConnection );
  4309. if ( status != NO_ERROR )
  4310. {
  4311. goto Exit;
  4312. }
  4313. //
  4314. // LUP_CONTAINERS
  4315. // - search for subordinate container objects to
  4316. // prnr->ServiceInstanceName
  4317. //
  4318. if ( prnr->ControlFlags & LUP_CONTAINERS )
  4319. {
  4320. status = FindSubordinateContainers(
  4321. prnr->pRnrConnection,
  4322. prnr->pwsServiceName,
  4323. ( (prnr->ControlFlags & LUP_DEEP) &&
  4324. !prnr->pwsContext )
  4325. ? prnr->pRnrConnection->DomainDN
  4326. : prnr->pwsContext,
  4327. ( prnr->ControlFlags & LUP_DEEP )
  4328. ? TRUE
  4329. : FALSE,
  4330. & pdnArray );
  4331. }
  4332. //
  4333. // not LUP_CONTAINERS -- find service instance
  4334. //
  4335. else
  4336. {
  4337. status = FindServiceInstance(
  4338. prnr->pRnrConnection,
  4339. prnr->pwsServiceName,
  4340. &prnr->ServiceClassGuid,
  4341. prnr->pVersion,
  4342. ( (prnr->ControlFlags & LUP_DEEP) &&
  4343. !prnr->pwsContext )
  4344. ? prnr->pRnrConnection->DomainDN
  4345. : prnr->pwsContext,
  4346. (prnr->ControlFlags & LUP_DEEP)
  4347. ? TRUE
  4348. : FALSE,
  4349. NULL, // don't need count
  4350. &pdnArray );
  4351. }
  4352. if ( status != NO_ERROR )
  4353. {
  4354. goto Exit;
  4355. }
  4356. // if couldn't find container or service instance -- bail
  4357. if ( !pdnArray )
  4358. {
  4359. status = WSASERVICE_NOT_FOUND;
  4360. goto Exit;
  4361. }
  4362. // save DN array to lookup blob
  4363. // - need on next LookupServiceNext call
  4364. prnr->pDnArray = pdnArray;
  4365. }
  4366. //
  4367. // have DN array
  4368. // - from search above
  4369. // - or previous LookupServiceNext() call
  4370. //
  4371. pdnArray = prnr->pDnArray;
  4372. if ( !pdnArray )
  4373. {
  4374. DNS_ASSERT( FALSE );
  4375. status = WSA_E_NO_MORE;
  4376. goto Exit;
  4377. }
  4378. if ( dwControlFlags & LUP_FLUSHPREVIOUS )
  4379. {
  4380. prnr->CurrentDN++;
  4381. DNSDBG( TRACE, (
  4382. "NTDS_LookupServiceNext() -- flushing previous\n"
  4383. "\tDN index now %d\n",
  4384. prnr->CurrentDN ));
  4385. }
  4386. //
  4387. // loop until successfully read info from DN
  4388. //
  4389. while ( 1 )
  4390. {
  4391. PWSTR preadDn;
  4392. if ( pdnArray->Count <= prnr->CurrentDN )
  4393. {
  4394. DNSDBG( TRACE, (
  4395. "NTDS_LookupServiceNext() -- used all the DNs\n"
  4396. "\tDN index now %d\n",
  4397. prnr->CurrentDN ));
  4398. status = WSA_E_NO_MORE;
  4399. goto Exit;
  4400. }
  4401. preadDn = pdnArray->Strings[ prnr->CurrentDN ];
  4402. //
  4403. // read properties and write to query set
  4404. //
  4405. // LUP_CONTAINERS
  4406. // - from container
  4407. // not LUP_CONTAINERS
  4408. // - service instance
  4409. //
  4410. status = ReadQuerySet(
  4411. prnr,
  4412. preadDn,
  4413. pdwBufferLength,
  4414. pqsResults );
  4415. // if successful, return
  4416. if ( status == NO_ERROR )
  4417. {
  4418. prnr->CurrentDN++;
  4419. goto Exit;
  4420. }
  4421. // if out of addresses, continue
  4422. if ( status == WSANO_ADDRESS )
  4423. {
  4424. prnr->CurrentDN++;
  4425. status = NO_ERROR;
  4426. continue;
  4427. }
  4428. break; // other errors are terminal
  4429. }
  4430. Exit:
  4431. DNSDBG( TRACE, (
  4432. "Leave NTDS_LookupServiceNext() => %d\n"
  4433. "\tpRnr = %p\n"
  4434. "\t DN Array = %p\n"
  4435. "\t DN Index = %d\n"
  4436. "\tbufLength = %d\n",
  4437. status,
  4438. hLookup,
  4439. prnr->pDnArray,
  4440. prnr->CurrentDN,
  4441. pdwBufferLength ? *pdwBufferLength : 0
  4442. ));
  4443. if ( status != NO_ERROR )
  4444. {
  4445. SetLastError( status );
  4446. status = SOCKET_ERROR;
  4447. }
  4448. return( status );
  4449. }
  4450. INT
  4451. WINAPI
  4452. NTDS_LookupServiceEnd(
  4453. IN HANDLE hLookup
  4454. )
  4455. /*++
  4456. Routine Description:
  4457. End\cleanup query on RnR handle.
  4458. Arguments:
  4459. hLookup -- RnR query handle from NTDS_LookupServiceBegin
  4460. Return Value:
  4461. NO_ERROR if successful.
  4462. SOCKET_ERROR on failure. GetLastError() contains status.
  4463. --*/
  4464. {
  4465. PRNR_LOOKUP prnr = (PRNR_LOOKUP) hLookup;
  4466. DNSDBG( TRACE, (
  4467. "NTDS_LookupServiceEnd( %p )\n",
  4468. hLookup ));
  4469. //
  4470. // validate lookup handle
  4471. // - close LDAP connection
  4472. // - free lookup blob
  4473. //
  4474. if ( !prnr ||
  4475. prnr->Signature != RNR_SIGNATURE )
  4476. {
  4477. DNS_ASSERT( prnr && prnr->Signature == RNR_SIGNATURE_FREE );
  4478. return SetError( WSA_INVALID_HANDLE );
  4479. }
  4480. DisconnectFromLDAPDirectory( & prnr->pRnrConnection );
  4481. FreeRnrLookup( prnr );
  4482. return( NO_ERROR );
  4483. }
  4484. //
  4485. // NSP defintion
  4486. //
  4487. NSP_ROUTINE nsrVector =
  4488. {
  4489. FIELD_OFFSET( NSP_ROUTINE, NSPIoctl ),
  4490. 1, // major version
  4491. 1, // minor version
  4492. NTDS_Cleanup,
  4493. NTDS_LookupServiceBegin,
  4494. NTDS_LookupServiceNext,
  4495. NTDS_LookupServiceEnd,
  4496. NTDS_SetService,
  4497. NTDS_InstallServiceClass,
  4498. NTDS_RemoveServiceClass,
  4499. NTDS_GetServiceClassInfo
  4500. };
  4501. INT
  4502. WINAPI
  4503. NSPStartup(
  4504. IN PGUID pProviderId,
  4505. OUT LPNSP_ROUTINE psnpRoutines
  4506. )
  4507. /*++
  4508. Routine Description:
  4509. Main NTDS provider entry point.
  4510. This exposes the NTDS provider to the world.
  4511. Arguments:
  4512. pProviderId -- provider GUID
  4513. psnpRoutines -- address to receive the NTDS provider definition
  4514. (the NSP table);
  4515. Return Value:
  4516. None
  4517. --*/
  4518. {
  4519. DNSDBG( TRACE, (
  4520. "NSPStartup( %p %p )\n",
  4521. pProviderId,
  4522. psnpRoutines ));
  4523. IF_DNSDBG( TRACE )
  4524. {
  4525. DnsDbg_Guid(
  4526. "NSPStartup() Provider GUID:",
  4527. pProviderId );
  4528. }
  4529. //
  4530. // copy NTDS RnR NSP table to caller
  4531. //
  4532. RtlCopyMemory( psnpRoutines, &nsrVector, sizeof(nsrVector) );
  4533. return( NO_ERROR );
  4534. }
  4535. //
  4536. // DLL exports
  4537. //
  4538. // Other exports beyond NSPStartup
  4539. //
  4540. RNR_STATUS
  4541. WINAPI
  4542. InstallNTDSProvider(
  4543. IN PWSTR szProviderName OPTIONAL,
  4544. IN PWSTR szProviderPath OPTIONAL,
  4545. IN PGUID pProviderId OPTIONAL
  4546. )
  4547. /*++
  4548. IN PWSTR szProviderName OPTIONAL, // NULL defaults to name "NTDS"
  4549. IN PWSTR szProviderPath OPTIONAL, // NULL defaults to path
  4550. // "%SystemRoot%\System32\winrnr.dll"
  4551. IN PGUID pProviderId OPTIONAL ); // NULL defaults to GUID
  4552. // 3b2637ee-e580-11cf-a555-00c04fd8d4ac
  4553. --*/
  4554. {
  4555. WORD wVersionRequested;
  4556. WSADATA wsaData;
  4557. INT err;
  4558. wVersionRequested = MAKEWORD( 1, 1 );
  4559. err = WSAStartup( wVersionRequested, &wsaData );
  4560. if ( err != 0 )
  4561. {
  4562. return( ERROR_ACCESS_DENIED );
  4563. }
  4564. //
  4565. // Confirm that the WinSock DLL supports 1.1.
  4566. // Note that if the DLL supports versions greater
  4567. // than 2.0 in addition to 1.1, it will still return
  4568. // 2.0 in wVersion since that is the version we
  4569. // requested.
  4570. //
  4571. if ( LOBYTE( wsaData.wVersion ) != 1 ||
  4572. HIBYTE( wsaData.wVersion ) != 1 )
  4573. {
  4574. err = ERROR_FILE_NOT_FOUND;
  4575. goto Done;
  4576. }
  4577. err = WSCInstallNameSpace(
  4578. szProviderName ? szProviderName : g_NtdsProviderName,
  4579. szProviderPath ? szProviderPath : g_NtdsProviderPath,
  4580. NS_NTDS,
  4581. 0,
  4582. pProviderId ? pProviderId : &g_NtdsProviderGuid );
  4583. if ( err != ERROR_SUCCESS )
  4584. {
  4585. WSCUnInstallNameSpace( pProviderId ? pProviderId : &g_NtdsProviderGuid );
  4586. err = WSCInstallNameSpace(
  4587. szProviderName ? szProviderName : g_NtdsProviderName,
  4588. szProviderPath ? szProviderPath : g_NtdsProviderPath,
  4589. NS_NTDS,
  4590. 0,
  4591. pProviderId ? pProviderId : &g_NtdsProviderGuid );
  4592. if ( err )
  4593. {
  4594. err = ERROR_BAD_ENVIRONMENT;
  4595. }
  4596. }
  4597. Done:
  4598. WSACleanup();
  4599. return( (DWORD)err );
  4600. }
  4601. RNR_STATUS
  4602. WINAPI
  4603. RemoveNTDSProvider(
  4604. IN PGUID pProviderId OPTIONAL
  4605. )
  4606. {
  4607. WORD wVersionRequested;
  4608. WSADATA wsaData;
  4609. INT err;
  4610. wVersionRequested = MAKEWORD( 1, 1 );
  4611. err = WSAStartup( wVersionRequested, &wsaData );
  4612. if ( err != 0 )
  4613. {
  4614. return( ERROR_ACCESS_DENIED );
  4615. }
  4616. //
  4617. // Confirm that the WinSock DLL supports 1.1.
  4618. // Note that if the DLL supports versions greater
  4619. // than 2.0 in addition to 1.1, it will still return
  4620. // 2.0 in wVersion since that is the version we
  4621. // requested.
  4622. //
  4623. if ( LOBYTE( wsaData.wVersion ) != 1 ||
  4624. HIBYTE( wsaData.wVersion ) != 1 )
  4625. {
  4626. WSACleanup();
  4627. return( ERROR_FILE_NOT_FOUND );
  4628. }
  4629. WSCUnInstallNameSpace( pProviderId ? pProviderId : &g_NtdsProviderGuid );
  4630. WSACleanup();
  4631. return( NO_ERROR );
  4632. }
  4633. //
  4634. // DLL init\cleanup
  4635. //
  4636. BOOL
  4637. InitializeDll(
  4638. IN HINSTANCE hInstance,
  4639. IN DWORD dwReason,
  4640. IN PVOID pReserved
  4641. )
  4642. /*++
  4643. Routine Description:
  4644. Dll init.
  4645. Arguments:
  4646. hdll -- instance handle
  4647. dwReason -- reason
  4648. pReserved -- reserved
  4649. Return Value:
  4650. TRUE if successful.
  4651. FALSE on error.
  4652. --*/
  4653. {
  4654. //
  4655. // process attach
  4656. // - ignore thread attach\detach
  4657. //
  4658. if ( dwReason == DLL_PROCESS_ATTACH )
  4659. {
  4660. if ( ! DisableThreadLibraryCalls( hInstance ) )
  4661. {
  4662. return( FALSE );
  4663. }
  4664. //
  4665. // create recurse lock through TLS
  4666. // - start open
  4667. //
  4668. g_TlsIndex = TlsAlloc();
  4669. if ( g_TlsIndex == 0xFFFFFFFF )
  4670. {
  4671. // Could not allocate a thread table index.
  4672. WINRNR_PRINT(( "WINRNR!InitializeDll - TlsAlloc() failed\n" ));
  4673. return( FALSE );
  4674. }
  4675. if ( !ReleaseRecurseLock( "InitializeDll" ) )
  4676. {
  4677. return( FALSE );
  4678. }
  4679. #if DBG
  4680. //
  4681. // init debug logging
  4682. // - do for any process beyond simple attach
  4683. //
  4684. // start logging with log filename generated to be
  4685. // unique for this process
  4686. //
  4687. // do NOT put drive specification in the file path
  4688. // do NOT set the debug flag -- the flag is read from
  4689. // the winrnr.flag file
  4690. //
  4691. {
  4692. CHAR szlogFileName[ 30 ];
  4693. sprintf(
  4694. szlogFileName,
  4695. "winrnr.%d.log",
  4696. GetCurrentProcessId() );
  4697. Dns_StartDebug(
  4698. 0,
  4699. "winrnr.flag",
  4700. NULL,
  4701. szlogFileName,
  4702. 0 );
  4703. }
  4704. #endif
  4705. }
  4706. //
  4707. // process detach
  4708. // - cleanup IF pReserved==NULL which indicates detach due
  4709. // to FreeLibrary
  4710. // - if process is exiting do nothing
  4711. //
  4712. else if ( dwReason == DLL_PROCESS_DETACH
  4713. &&
  4714. pReserved == NULL )
  4715. {
  4716. if ( g_TlsIndex != 0xFFFFFFFF )
  4717. {
  4718. if ( TlsFree( g_TlsIndex ) == FALSE )
  4719. {
  4720. // Could not free thread table index.
  4721. WINRNR_PRINT((
  4722. "WINRNR!InitializeDll - TlsFree( Index )\n"
  4723. "failed with error code: 0%x\n",
  4724. GetLastError() ));
  4725. return( FALSE );
  4726. }
  4727. g_TlsIndex = 0xFFFFFFFF;
  4728. }
  4729. }
  4730. return( TRUE );
  4731. }
  4732. //
  4733. // End winrnr.c
  4734. //