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.

703 lines
22 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. //
  6. // File: idt_ldap.cxx
  7. //
  8. // Contents: Intra-domain table based on LDAP.
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. //
  15. //
  16. // History: 18-Nov-96 BillMo Created.
  17. //
  18. // Notes:
  19. //
  20. // Codework:
  21. //
  22. //--------------------------------------------------------------------------
  23. #include "pch.cxx"
  24. #pragma hdrstop
  25. #include "trksvr.hxx"
  26. CLdapOMTAddModify::CLdapOMTAddModify(
  27. const CDomainRelativeObjId & ldKey,
  28. const CDomainRelativeObjId & ldNew,
  29. const CDomainRelativeObjId & ldBirth,
  30. const ULONG & seqRefresh,
  31. BYTE bFlags,
  32. int mod_op )
  33. :
  34. _lsmClass(s_objectClass, s_linkTrackOMTEntry, 0),
  35. _lbmCurrentLocation( s_currentLocation, reinterpret_cast<PCCH>(&ldNew), sizeof(ldNew), mod_op ),
  36. _lbmBirthLocation( s_birthLocation, reinterpret_cast<PCCH>(&ldBirth), sizeof(ldBirth), mod_op ),
  37. _ltvRefresh( seqRefresh ),
  38. _lsmRefresh( s_timeRefresh, _ltvRefresh, mod_op ),
  39. _lbmFlags( s_oMTIndxGuid, reinterpret_cast<PCCH>(&bFlags), sizeof(BYTE), mod_op )
  40. {
  41. int i = 0;
  42. if (mod_op == LDAP_MOD_ADD)
  43. {
  44. _mods[i++] = &_lsmClass._mod;
  45. _mods[i++] = &_lbmFlags._mod;
  46. }
  47. _mods[i++] = &_lbmCurrentLocation._mod;
  48. if (ldKey != ldBirth)
  49. _mods[i++] = &_lbmBirthLocation._mod;
  50. _mods[i++] = &_lsmRefresh._mod;
  51. _mods[i++] = NULL;
  52. TrkAssert(i <= sizeof(_mods)/sizeof(_mods[0]));
  53. }
  54. void
  55. CIntraDomainTable::Initialize( CTrkSvrConfiguration *pTrkSvrConfiguration, CQuotaTable* pqtable )
  56. {
  57. _fInitializeCalled = TRUE;
  58. _pqtable = pqtable;
  59. _pTrkSvrConfiguration = pTrkSvrConfiguration;
  60. _QuotaReported.Initialize();
  61. }
  62. void
  63. CIntraDomainTable::UnInitialize()
  64. {
  65. if (_fInitializeCalled)
  66. {
  67. }
  68. _fInitializeCalled = FALSE;
  69. }
  70. //+----------------------------------------------------------------------------
  71. //
  72. // CIntraDomainTable::Add
  73. //
  74. // Add an entry to the move table. Return TRUE if the entry was added, but
  75. // didn't already exist. Return FALSE if the entry already exists. If
  76. // there's an error, raise an exception.
  77. //
  78. //+----------------------------------------------------------------------------
  79. BOOL
  80. CIntraDomainTable::Add(const CDomainRelativeObjId &ldKey,
  81. const CDomainRelativeObjId &ldNew,
  82. const CDomainRelativeObjId &ldBirth,
  83. BOOL *pfQuotaExceeded OPTIONAL )
  84. {
  85. int err;
  86. BYTE bFlags = QFLAG_UNCOUNTED;
  87. CLdapIdtKeyDn dnKey(GetBaseDn(), ldKey);
  88. // The following constructor sets up the mods array for
  89. // the ldap_add_s call that we're about to do.
  90. CLdapOMTAddModify lam( ldKey, // Key
  91. ldNew, // New droid
  92. ldBirth, // Birth droid
  93. // Current sequence number
  94. _pRefreshSequenceStorage->GetSequenceNumber(),
  95. bFlags, // Flags, will be pointed to
  96. // (so can't e.g. use a #define value)
  97. LDAP_MOD_ADD); // Add this element
  98. // Return FALSE here means that we pretend to the caller that the entry
  99. // already exists. We don't want to raise an exception here. Our caller
  100. // always tries to add the entry, if the add fails because the entry
  101. // already exists, the caller will then try to modify the entry. If the
  102. // quota has been exceeded, we don't want to add more entries, but we
  103. // still want entries already in the table to be modifiable. So instead of
  104. // raising an exception, we really want the caller to try to modify the
  105. // entry instead.
  106. if(_pqtable->IsMoveQuotaExceeded())
  107. {
  108. if( NULL != pfQuotaExceeded )
  109. *pfQuotaExceeded = TRUE;
  110. if( !_QuotaReported.IsSet() )
  111. {
  112. _QuotaReported.Set();
  113. TrkReportEvent( EVENT_TRK_SERVICE_MOVE_QUOTA_EXCEEDED, EVENTLOG_WARNING_TYPE,
  114. TRKREPORT_LAST_PARAM );
  115. }
  116. return FALSE;
  117. }
  118. else
  119. {
  120. _QuotaReported.Clear();
  121. }
  122. err = ldap_add_s(Ldap(), dnKey, lam._mods);
  123. if (err == LDAP_SUCCESS)
  124. {
  125. {
  126. LDAPMod* mods[2];
  127. BYTE bFlags = QFLAG_UNCOUNTED;
  128. CLdapBinaryMod lbm(s_oMTIndxGuid, reinterpret_cast<PCCH>(&bFlags), sizeof(BYTE), LDAP_MOD_REPLACE);
  129. mods[0] = &lbm._mod;
  130. mods[1] = NULL;
  131. err = ldap_modify_s(Ldap(), dnKey, mods);
  132. }
  133. _pqtable->IncrementMoveCountCache();
  134. return(TRUE);
  135. }
  136. else
  137. if (err == LDAP_ALREADY_EXISTS)
  138. {
  139. return(FALSE);
  140. }
  141. else
  142. {
  143. TrkRaiseWin32Error(LdapMapErrorToWin32(err));
  144. return(FALSE);
  145. }
  146. }
  147. // TRUE if found and deleted, FALSE if not found, exception on other errors
  148. BOOL
  149. CIntraDomainTable::Delete(const CDomainRelativeObjId &ldKey)
  150. {
  151. int err;
  152. CLdapIdtKeyDn dnKey(GetBaseDn(), ldKey);
  153. BOOL fFound;
  154. fFound = _pqtable->UpdateFlags(Ldap(), dnKey, QFLAG_DELETED);
  155. if( fFound )
  156. _pqtable->DecrementMoveCountCache();
  157. return fFound;
  158. }
  159. // TRUE if entry exists and modified, FALSE if not existent, exception otherwise
  160. BOOL
  161. CIntraDomainTable::Modify(const CDomainRelativeObjId &ldKey,
  162. const CDomainRelativeObjId &ldNew,
  163. const CDomainRelativeObjId &ldBirth )
  164. {
  165. int err;
  166. CLdapIdtKeyDn dnKey(GetBaseDn(), ldKey);
  167. CLdapOMTAddModify lam( ldKey,
  168. ldNew,
  169. ldBirth,
  170. _pRefreshSequenceStorage->GetSequenceNumber(),
  171. 0, // Only used with LDAP_MOD_ADD
  172. LDAP_MOD_REPLACE);
  173. err = ldap_modify_s(Ldap(), dnKey, lam._mods);
  174. if (err == LDAP_SUCCESS)
  175. {
  176. return(TRUE);
  177. }
  178. else
  179. if (err == LDAP_NO_SUCH_OBJECT)
  180. {
  181. return(FALSE);
  182. }
  183. else
  184. {
  185. TrkRaiseWin32Error(LdapMapErrorToWin32(err));
  186. return(FALSE);
  187. }
  188. }
  189. // must leave outputs unchanged if returning FALSE
  190. BOOL
  191. CIntraDomainTable::Query(const CDomainRelativeObjId &ldKey,
  192. CDomainRelativeObjId *pldNew,
  193. CDomainRelativeObjId *pldBirth,
  194. BOOL *pfDeleted OPTIONAL,
  195. BOOL *pfCounted OPTIONAL )
  196. {
  197. int err;
  198. TCHAR *aptszAttrs[] = { const_cast<TCHAR*>(s_currentLocation),
  199. const_cast<TCHAR*>(s_birthLocation),
  200. const_cast<TCHAR*>(s_oMTIndxGuid),
  201. NULL };
  202. LDAPMessage * pRes = NULL;
  203. CLdapIdtKeyDn dnKey(GetBaseDn(), ldKey);
  204. BOOL fFound = FALSE;
  205. __try
  206. {
  207. err = ldap_search_s( Ldap(),
  208. dnKey,
  209. LDAP_SCOPE_BASE,
  210. TEXT("(objectclass=*)"),
  211. aptszAttrs,
  212. 0, // attribute types and values are wanted
  213. &pRes );
  214. if (err == LDAP_SUCCESS)
  215. {
  216. // found it, lets get the attributes out
  217. if (ldap_count_entries(Ldap(), pRes) == 1)
  218. {
  219. LDAPMessage * pEntry = ldap_first_entry(Ldap(), pRes);
  220. if (pEntry == NULL)
  221. {
  222. TrkRaiseWin32Error(LdapMapErrorToWin32(Ldap()->ld_errno));
  223. }
  224. fFound = Query( Ldap(), pEntry, ldKey, pldNew, pldBirth, pfDeleted, pfCounted );
  225. }
  226. }
  227. else
  228. if (err != LDAP_NO_SUCH_OBJECT)
  229. {
  230. TrkRaiseWin32Error(LdapMapErrorToWin32(err));
  231. }
  232. }
  233. __finally
  234. {
  235. if (NULL != pRes)
  236. ldap_msgfree(pRes);
  237. }
  238. return(fFound);
  239. }
  240. BOOL
  241. CIntraDomainTable::Query( LDAP* pLdap,
  242. LDAPMessage *pEntry,
  243. const CDomainRelativeObjId ldKey,
  244. CDomainRelativeObjId *pldNew,
  245. CDomainRelativeObjId *pldBirth,
  246. BOOL *pfDeleted OPTIONAL,
  247. BOOL *pfCounted OPTIONAL )
  248. {
  249. BOOL fFound = FALSE;
  250. struct berval **ppbvCurrentLocation = NULL;
  251. struct berval **ppbvBirthLocation = NULL;
  252. struct berval **ppbvQuotaFlags = NULL;
  253. BYTE bQuotaFlags = 0;
  254. if( NULL != pfDeleted )
  255. *pfDeleted = FALSE;
  256. __try
  257. {
  258. ppbvBirthLocation = ldap_get_values_len(pLdap, pEntry,
  259. const_cast<TCHAR*>(s_birthLocation) );
  260. if (NULL != ppbvBirthLocation
  261. &&
  262. sizeof(*pldBirth) > (*ppbvBirthLocation)->bv_len)
  263. {
  264. TrkLog((TRKDBG_ERROR, TEXT("Couldn't get current location for %s"),
  265. (const TCHAR*)CDebugString(ldKey) ));
  266. TrkRaiseWin32Error( LdapMapErrorToWin32(pLdap->ld_errno) );
  267. }
  268. ppbvCurrentLocation = ldap_get_values_len(pLdap, pEntry,
  269. const_cast<TCHAR*>(s_currentLocation) );
  270. if (NULL == ppbvCurrentLocation
  271. ||
  272. sizeof(*pldNew) > (*ppbvCurrentLocation)->bv_len)
  273. {
  274. TrkLog((TRKDBG_ERROR, TEXT("Couldn't get current location for %s"),
  275. (const TCHAR*)CDebugString(ldKey) ));
  276. TrkRaiseWin32Error( LdapMapErrorToWin32(pLdap->ld_errno) );
  277. }
  278. ppbvQuotaFlags = ldap_get_values_len(pLdap, pEntry,
  279. const_cast<TCHAR*>(s_oMTIndxGuid) );
  280. if (NULL != ppbvQuotaFlags
  281. &&
  282. sizeof(BYTE) <= (*ppbvQuotaFlags)->bv_len)
  283. {
  284. bQuotaFlags = *(BYTE*)(*ppbvQuotaFlags)->bv_val;
  285. }
  286. if( NULL != pfCounted )
  287. {
  288. if( bQuotaFlags & QFLAG_UNCOUNTED )
  289. *pfCounted = FALSE;
  290. else
  291. *pfCounted = TRUE;
  292. }
  293. if( bQuotaFlags & QFLAG_DELETED )
  294. {
  295. if( NULL != pfDeleted )
  296. *pfDeleted = TRUE;
  297. TrkLog(( TRKDBG_IDT, TEXT("IdtQuery: Entry marked deleted will be ignored (0x%x): %s"),
  298. bQuotaFlags,
  299. (const TCHAR*)CDebugString(ldKey) ));
  300. }
  301. else
  302. {
  303. *pldNew = *reinterpret_cast<CDomainRelativeObjId*>( (*ppbvCurrentLocation)->bv_val );
  304. if (NULL != ppbvBirthLocation)
  305. *pldBirth = *reinterpret_cast<CDomainRelativeObjId*>( (*ppbvBirthLocation)->bv_val );
  306. else
  307. *pldBirth = ldKey;
  308. fFound = TRUE;
  309. }
  310. }
  311. __finally
  312. {
  313. if (NULL != ppbvCurrentLocation)
  314. ldap_value_free_len(ppbvCurrentLocation);
  315. if (NULL != ppbvBirthLocation)
  316. ldap_value_free_len(ppbvBirthLocation);
  317. if (NULL != ppbvQuotaFlags)
  318. ldap_value_free_len(ppbvQuotaFlags);
  319. }
  320. return( fFound );
  321. }
  322. //+----------------------------------------------------------------------------
  323. //
  324. // CIntraDomainTable::Touch
  325. //
  326. // Update the refresh attribute for an entry in the move table.
  327. // Return TRUE if the entry exists and was touched, FALSE if it
  328. // doesn't exist, and raise an exception if there's an error.
  329. //
  330. //+----------------------------------------------------------------------------
  331. // BUGBUG: if we ever move to per-user quotas,
  332. // check ownership of entry being touched.
  333. BOOL
  334. CIntraDomainTable::Touch(
  335. const CDomainRelativeObjId &ldKey
  336. )
  337. {
  338. BOOL fReturn = FALSE;
  339. int err;
  340. CLdapTimeValue ltvRefresh( _pRefreshSequenceStorage->GetSequenceNumber());
  341. CLdapStringMod lsmRefresh( s_timeRefresh, ltvRefresh, LDAP_MOD_REPLACE );
  342. CLdapIdtKeyDn dnKey(GetBaseDn(), ldKey);
  343. TCHAR ** pptszRefresh = NULL;
  344. LDAPMessage * pEntry = NULL;
  345. LDAPMessage* pRes = NULL;
  346. LDAPMod * mods[2];
  347. CObjId objZero;
  348. __try
  349. {
  350. //
  351. // if the birth id is zero, then it is invalid and not worth doing a refresh
  352. //
  353. if (ldKey.GetObjId() == objZero)
  354. {
  355. __leave;
  356. }
  357. //
  358. // Check to see if the object already has a recent sequence number.
  359. //
  360. TCHAR* rgptszAttrs[2];
  361. rgptszAttrs[0] = const_cast<TCHAR*>(s_timeRefresh);
  362. rgptszAttrs[1] = NULL;
  363. err = ldap_search_s(Ldap(),
  364. dnKey,
  365. LDAP_SCOPE_BASE,
  366. TEXT("(ObjectClass=*)"),
  367. rgptszAttrs,
  368. 0,
  369. &pRes);
  370. if (err == LDAP_SUCCESS)
  371. {
  372. // The search call worked, but did we find an object?
  373. if( 1 == ldap_count_entries(Ldap(), pRes) )
  374. {
  375. // The object already exists
  376. pEntry = ldap_first_entry(Ldap(), pRes);
  377. if( NULL != pEntry )
  378. {
  379. // Get the refresh counter
  380. pptszRefresh = ldap_get_values( Ldap(), pEntry, const_cast<TCHAR*>(s_timeRefresh) );
  381. if( NULL != pptszRefresh )
  382. {
  383. SequenceNumber seqRefresh = 0;
  384. if( 1 == _stscanf( *pptszRefresh, TEXT("%d"), &seqRefresh ))
  385. {
  386. // Is the refresh counter already set to a recent value?
  387. // We'll consider it recent enough if it's within half of the
  388. // refresh cycle (15 days)
  389. // First, how long is the GC timer in seconds?
  390. LONG lGCTimerInSeconds = _pTrkSvrConfiguration->GetGCPeriod() // 30 days in seconds
  391. / _pTrkSvrConfiguration->GetGCDivisor(); // => 1 day in seconds
  392. // Next, how many ticks is half the period?
  393. LONG lWindow = _pTrkSvrConfiguration->GetGCPeriod() // 30 days (in seconds)
  394. / 2 // => 15 days (in seconds)
  395. / lGCTimerInSeconds; // => 15
  396. TrkLog(( TRKDBG_WARNING, TEXT("Window = %d"), lWindow ));
  397. if( seqRefresh + lWindow
  398. >= _pRefreshSequenceStorage->GetSequenceNumber()
  399. )
  400. {
  401. TrkLog(( TRKDBG_GARBAGE_COLLECT | TRKDBG_IDT,
  402. TEXT("Not touching %s with %d, seq %d already set"),
  403. (const TCHAR*)CDebugString(ldKey),
  404. _pRefreshSequenceStorage->GetSequenceNumber(),
  405. seqRefresh ));
  406. __leave;
  407. }
  408. }
  409. }
  410. }
  411. }
  412. }
  413. else if (err == LDAP_NO_SUCH_OBJECT)
  414. {
  415. TrkLog((TRKDBG_GARBAGE_COLLECT | TRKDBG_IDT,
  416. TEXT("Touch: object %s not found"),
  417. (const TCHAR*) CDebugString(ldKey) ));
  418. __leave;
  419. }
  420. //
  421. // Set the correct sequence number
  422. //
  423. mods[0] = &lsmRefresh._mod;
  424. mods[1] = NULL;
  425. err = ldap_modify_s(Ldap(), dnKey, mods);
  426. if (err == LDAP_SUCCESS)
  427. {
  428. TrkLog((TRKDBG_GARBAGE_COLLECT | TRKDBG_IDT,
  429. TEXT("Touch: object %s touched"),
  430. (const TCHAR*) CDebugString(ldKey) ));
  431. fReturn = TRUE;
  432. __leave;
  433. }
  434. else
  435. if (err == LDAP_NO_SUCH_OBJECT)
  436. {
  437. TrkLog((TRKDBG_GARBAGE_COLLECT | TRKDBG_IDT,
  438. TEXT("Touch: object %s not found"),
  439. (const TCHAR*) CDebugString(ldKey) ));
  440. __leave;
  441. }
  442. else
  443. if (err == LDAP_NO_SUCH_ATTRIBUTE)
  444. {
  445. TrkLog((TRKDBG_GARBAGE_COLLECT | TRKDBG_SVR,
  446. TEXT("Touch: object %s attribute not found"),
  447. (const TCHAR*) CDebugString(ldKey) ));
  448. // deal with old server data
  449. CLdapStringMod lsmRefresh( s_timeRefresh, ltvRefresh, LDAP_MOD_ADD );
  450. mods[0] = &lsmRefresh._mod;
  451. err = ldap_modify_s(Ldap(), dnKey, mods);
  452. }
  453. if (err != LDAP_SUCCESS)
  454. {
  455. TrkLog((TRKDBG_GARBAGE_COLLECT | TRKDBG_IDT,
  456. TEXT("Touch: object %s --> exceptional error"),
  457. (const TCHAR*) CDebugString(ldKey) ));
  458. __leave;
  459. }
  460. }
  461. __except( BreakOnDebuggableException() )
  462. {
  463. TrkLog(( TRKDBG_ERROR, TEXT("Ignoring exception during IDT::Touch (%08x)"), GetExceptionCode() ));
  464. }
  465. if (pptszRefresh != NULL)
  466. ldap_value_free(pptszRefresh);
  467. if(pRes != NULL)
  468. ldap_msgfree(pRes);
  469. return( fReturn );
  470. }
  471. ULONG
  472. CIntraDomainTable::GarbageCollect( SequenceNumber seqCurrent, SequenceNumber seqOldestToKeep, const BOOL * pfAbort )
  473. {
  474. CLdapIdtKeyDn dn(GetBaseDn());
  475. TCHAR * apszAttrs[3];
  476. GC_ENUM_CONTEXT EnumContext;
  477. apszAttrs[0] = const_cast<TCHAR*>(s_Cn);
  478. apszAttrs[1] = const_cast<TCHAR*>(s_timeRefresh);
  479. apszAttrs[2] = 0;
  480. TrkLog(( TRKDBG_GARBAGE_COLLECT | TRKDBG_IDT, TEXT("GC-ing move table (%d/%d)"),
  481. seqCurrent, seqOldestToKeep ));
  482. memset( &EnumContext, 0, sizeof(EnumContext) );
  483. EnumContext.seqOldestToKeep = seqOldestToKeep;
  484. EnumContext.seqCurrent = seqCurrent;
  485. EnumContext.pfAbort = pfAbort;
  486. EnumContext.dwRepetitiveTaskDelay = _pTrkSvrConfiguration->GetRepetitiveTaskDelay();
  487. EnumContext.pqtable = _pqtable;
  488. if (!LdapEnumerate(
  489. Ldap(),
  490. dn,
  491. LDAP_SCOPE_ONELEVEL,
  492. TEXT("(objectClass=*)"),
  493. apszAttrs,
  494. GcEnumerateCallback,
  495. &EnumContext ))
  496. {
  497. TrkRaiseException(TRK_E_SERVICE_STOPPING);
  498. }
  499. TrkLog(( TRKDBG_GARBAGE_COLLECT | TRKDBG_IDT,
  500. TEXT("GC-ed %d entries from the move table"),
  501. EnumContext.cEntries ));
  502. _pqtable->OnMoveTableGcComplete( EnumContext.cEntries );
  503. return EnumContext.cEntries;
  504. }
  505. #if DBG
  506. void
  507. CIntraDomainTable::PurgeAll()
  508. {
  509. int err;
  510. TCHAR *apszAttrs[2] = { TEXT("cn"), NULL };
  511. LDAPMessage * pRes;
  512. TCHAR tszObjectMoveTable[MAX_PATH+1];
  513. __try
  514. {
  515. _tcscpy(tszObjectMoveTable, s_ObjectMoveTableRDN);
  516. _tcscat(tszObjectMoveTable, GetBaseDn());
  517. err = ldap_search_s( Ldap(),
  518. tszObjectMoveTable,
  519. LDAP_SCOPE_ONELEVEL,
  520. TEXT("(objectclass=*)"),
  521. apszAttrs,
  522. 0, // attribute types and values are wanted
  523. &pRes );
  524. if (err == LDAP_SUCCESS)
  525. {
  526. // found it, lets get the attributes out
  527. int cEntries = ldap_count_entries(Ldap(), pRes);
  528. LDAPMessage * pEntry = ldap_first_entry(Ldap(), pRes);
  529. if (pEntry != NULL)
  530. {
  531. do
  532. {
  533. TCHAR * ptszDn = ldap_get_dn(Ldap(), pEntry);
  534. int errd = ldap_delete_s(Ldap(),ptszDn);
  535. TrkLog((TRKDBG_ERROR, TEXT("Purged %s status=%d"), ptszDn, errd));
  536. ldap_memfree(ptszDn);
  537. } while ( pEntry = ldap_next_entry(Ldap(), pEntry));
  538. }
  539. }
  540. }
  541. __finally
  542. {
  543. if (err == LDAP_SUCCESS)
  544. {
  545. ldap_msgfree(pRes);
  546. }
  547. }
  548. }
  549. #endif
  550. void
  551. CDomainRelativeObjId::FillLdapIdtKeyBuffer(TCHAR * const pchCN,
  552. DWORD cch) const
  553. {
  554. TCHAR *pchBuf = pchCN;
  555. _tcscpy(pchBuf, TEXT("CN="));
  556. pchBuf = pchBuf + 3;
  557. _volume.Stringize(pchBuf);
  558. _object.Stringize(pchBuf);
  559. TrkAssert(pchBuf <= pchCN+cch);
  560. }
  561. void
  562. CDomainRelativeObjId::ReadLdapIdtKeyBuffer(const TCHAR * pchCN )
  563. {
  564. const TCHAR *pchBuf;
  565. Init();
  566. if( 0 == _tcsncmp( pchCN, TEXT("CN="), 3 ))
  567. {
  568. pchBuf = &pchCN[3];
  569. if( !_volume.Unstringize(pchBuf)
  570. ||
  571. !_object.Unstringize(pchBuf) )
  572. {
  573. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't unstringize droid from %s"), pchCN ));
  574. Init();
  575. }
  576. }
  577. }
  578. void
  579. CDomainRelativeObjId::InitFromLdapBuffer(char * pVolumeId, int cbVolumeId,
  580. char * pObjId, int cbObjId)
  581. {
  582. DWORD iBuf = 0;
  583. if (cbVolumeId != sizeof(_volume) ||
  584. cbObjId != sizeof(_object))
  585. {
  586. TrkRaiseException(TRK_E_CORRUPT_IDT);
  587. }
  588. memcpy(&_volume, pVolumeId, sizeof(_volume));
  589. memcpy(&_object, pObjId, sizeof(_object));
  590. }