/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1998, Microsoft Corp. All rights reserved. // // FILE // // Cracker.cpp // // SYNOPSIS // // This file defines the class NameCracker. // // MODIFICATION HISTORY // // 04/13/1998 Original version. // 08/10/1998 Remove NT4 support. // 08/21/1998 Removed initialization/shutdown routines. // /////////////////////////////////////////////////////////////////////////////// #include #include #include /////////////////////////////////////////////////////////////////////////////// // // FUNCTION // // DsCrackNameAutoChaseW // // DESCRIPTION // // Extension to DsCrackNames that automatically chases cross-forest // referrals using default credentials. // /////////////////////////////////////////////////////////////////////////////// DWORD WINAPI DsCrackNameAutoChaseW( HANDLE hDS, DS_NAME_FLAGS flags, DS_NAME_FORMAT formatOffered, DS_NAME_FORMAT formatDesired, PCWSTR name, PDS_NAME_RESULTW* ppResult, BOOL* pChased ) { DWORD error; if (pChased == NULL) { return ERROR_INVALID_PARAMETER; } *pChased = FALSE; flags = (DS_NAME_FLAGS)(flags | DS_NAME_FLAG_TRUST_REFERRAL); error = DsCrackNamesW( hDS, flags, formatOffered, formatDesired, 1, &name, ppResult ); while ((error == NO_ERROR) && ((*ppResult)->rItems->status == DS_NAME_ERROR_TRUST_REFERRAL)) { *pChased = TRUE; HANDLE hDsForeign; error = DsBindW(NULL, (*ppResult)->rItems->pDomain, &hDsForeign); DsFreeNameResultW(*ppResult); *ppResult = NULL; if (error == NO_ERROR) { error = DsCrackNamesW( hDsForeign, flags, formatOffered, formatDesired, 1, &name, ppResult ); DsUnBindW(&hDsForeign); } } return error; } /////////////////////////////////////////////////////////////////////////////// // // CLASS // // DsHandle // // DESCRIPTION // // This class represents a reference counted NTDS handle. // /////////////////////////////////////////////////////////////////////////////// class DsHandle : public NonCopyable { public: HANDLE get() const throw () { return subject; } operator HANDLE() const throw () { return subject; } protected: friend class NameCracker; // Constructor and destructor are protected since only NameCracker is // allowed to open new handles. DsHandle(HANDLE h) throw () : refCount(1), subject(h) { } ~DsHandle() throw () { if (subject) { DsUnBindW(&subject); } } void AddRef() throw () { InterlockedIncrement(&refCount); } void Release() throw () { if (!InterlockedDecrement(&refCount)) { delete this; } } LONG refCount; // reference count. HANDLE subject; // HANDLE being ref counted. }; NameCracker::NameCracker() throw () : gc(NULL) { } NameCracker::~NameCracker() throw () { if (gc) { gc->Release(); } } DWORD NameCracker::crackNames( DS_NAME_FLAGS flags, DS_NAME_FORMAT formatOffered, DS_NAME_FORMAT formatDesired, PCWSTR name, PDS_NAME_RESULTW *ppResult ) throw () { DWORD errorCode; // Get a handle to the GC. DsHandle* hDS1; errorCode = getGC(&hDS1); if (errorCode == NO_ERROR) { // Try to crack the names. BOOL chased; errorCode = DsCrackNameAutoChaseW( *hDS1, flags, formatOffered, formatDesired, name, ppResult, &chased ); if (errorCode != NO_ERROR && !chased) { // We failed, so disable the current handle ... disable(hDS1); // ... and try to get a new one. DsHandle* hDS2; errorCode = getGC(&hDS2); if (errorCode == NO_ERROR) { // Give it one more try with the new handle. errorCode = DsCrackNameAutoChaseW( *hDS2, flags, formatOffered, formatDesired, name, ppResult, &chased ); if (errorCode != NO_ERROR && !chased) { // No luck so disable the handle. disable(hDS2); } hDS2->Release(); } } hDS1->Release(); } return errorCode; } void NameCracker::disable(DsHandle* h) throw () { _serialize // If it doesn't match our cached handle, then someone else // has already disabled it. if (h == gc && gc != NULL) { gc->Release(); gc = NULL; } } DWORD NameCracker::getGC(DsHandle** h) throw () { _ASSERT(h != NULL); *h = NULL; _serialize // Do we already have a cached handle? if (!gc) { // Bind to a GC. HANDLE hGC; DWORD err = DsBindWithCredA(NULL, NULL, NULL, &hGC); if (err != NO_ERROR) { return err; } // Allocate a new DsHandle object to wrap the NTDS handle. gc = new (std::nothrow) DsHandle(hGC); if (!gc) { DsUnBindW(&hGC); return ERROR_NOT_ENOUGH_MEMORY; } } // AddRef the handle and return to caller. (*h = gc)->AddRef(); return NO_ERROR; }