Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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