//================================================================================ // Copyright (C) 1997 Microsoft Corporation // Author: RameshV (critical code borrowed from shirish koti) // Description: This makes somethings easy for accessing the DS. //================================================================================ #include #include // error reporting stuff enum /* anonymous */ { REPEATED_ADDRESS1 = 0x01, // dont start error code with zero! REPEATED_ADDRESS2, REPEATED_ADDRESS3, INVALID_ADDRESS1, INVALID_ADDRESS2, INVALID_ADDRESS3, REPEATED_ADSPATH, INVALID_ADSPATH, REPEATED_FLAGS1, REPEATED_FLAGS2, INVALID_FLAGS1, INVALID_FLAGS2, REPEATED_DWORD1, REPEATED_DWORD2, INVALID_DWORD1, INVALID_DWORD2, REPEATED_STRING1, REPEATED_STRING2, REPEATED_STRING3, REPEATED_STRING4, INVALID_STRING1, INVALID_STRING2, INVALID_STRING3, INVALID_STRING4, REPEATED_BINARY1, REPEATED_BINARY2, INVALID_BINARY1, INVALID_BINARY2, INVALID_ATTRIB_FIELD, INVALID_BINARY_CODING, UNEXPECTED_COLLECTION_TYPE, UNEXPECTED_INTERNAL_ERROR, }; // // Constants // // Retrive 256 rows per query #define DHCPDS_DS_SEARCH_PAGESIZE 256 //================================================================================ // structures //================================================================================ //BeginExport(typedef) typedef struct _STORE_HANDLE { // this is what is used almost always DWORD MustBeZero; // for future use LPWSTR Location; // where does this refer to? LPWSTR UserName; // who is the user? LPWSTR Password; // what is the password? DWORD AuthFlags; // what permission was this opened with? HANDLE ADSIHandle; // handle to within ADSI ADS_SEARCH_HANDLE SearchHandle; // any searches going on? LPVOID Memory; // memory allocated for this call.. DWORD MemSize; // how much was really allocated? BOOL SearchStarted; // Did we start the search? } STORE_HANDLE, *LPSTORE_HANDLE, *PSTORE_HANDLE; //EndExport(typedef) LPWSTR _inline MakeRootDSEString( // given DSDC or domain name, produce ROOT DSE name IN LPWSTR Server ) { LPWSTR RootDSE; if( NULL == Server ) { RootDSE = MemAlloc( sizeof(DEFAULT_LDAP_ROOTDSE) ) ; if( NULL == RootDSE ) return NULL; wcscpy(RootDSE, DEFAULT_LDAP_ROOTDSE); return RootDSE; } RootDSE = MemAlloc(sizeof(LDAP_PREFIX) + SizeString(Server,FALSE) + sizeof(ROOTDSE_POSTFIX)); if( NULL == RootDSE ) return NULL; wcscpy(RootDSE, LDAP_PREFIX); wcscat(RootDSE, Server); wcscat(RootDSE, ROOTDSE_POSTFIX); return RootDSE; } LPWSTR _inline MakeServerLocationString( IN LPWSTR Server, IN LPWSTR Location ) { LPWSTR RetVal; Require(Location); RetVal = MemAlloc(sizeof(LDAP_PREFIX) + sizeof(WCHAR) + SizeString(Server,FALSE) + SizeString(Location,FALSE)); if( NULL == RetVal ) return NULL; wcscpy(RetVal, LDAP_PREFIX); if( NULL != Server ) { wcscat(RetVal, Server); wcscat(RetVal, L"/"); } wcscat(RetVal, Location); return RetVal; } HRESULT GetEnterpriseRootFromRootHandle( // given /ROOTDSE object handle, get enterprise config root handle.. IN HANDLE DSERootHandle, IN LPWSTR Server, IN LPWSTR UserName, IN LPWSTR Password, IN DWORD AuthFlags, IN OUT LPWSTR *RootLocation, IN OUT HANDLE *hRoot ) { HRESULT hResult; DWORD Chk; DWORD i, j; DWORD nAttributes; PADS_ATTR_INFO Attributes; BOOL Found; *RootLocation = NULL; hResult = ADSIGetObjectAttributes( DSERootHandle, (LPWSTR *)&constNamingContextString, 1, &Attributes, &nAttributes ); if( FAILED(hResult) ) return hResult; if( 0 == nAttributes ) { return E_ADS_PROPERTY_NOT_FOUND; } Found = FALSE; for( i = 0; i < Attributes->dwNumValues ; i ++ ) { if( Attributes->pADsValues[i].dwType != ADSTYPE_CASE_IGNORE_STRING && Attributes->pADsValues[i].dwType != ADSTYPE_DN_STRING ) continue; Chk = _wcsnicmp( ENT_ROOT_PREFIX, Attributes->pADsValues[i].CaseIgnoreString, ENT_ROOT_PREFIX_LEN ); if( 0 == Chk ) break; } if( i < Attributes->dwNumValues ) { *RootLocation = MakeServerLocationString( Server, Attributes->pADsValues[i].CaseIgnoreString ); Found = TRUE; } FreeADsMem(Attributes); if( FALSE == Found ) return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); if( NULL == *RootLocation ) return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); hResult = ADSIOpenDSObject( *RootLocation, UserName, Password, AuthFlags, hRoot ); if( SUCCEEDED(hResult) ) return S_OK; MemFree(*RootLocation); *RootLocation = NULL; return hResult; } DWORD GetEnterpriseRootObject( // get the /ROOTDSE object's naming context object.. IN LPWSTR Server, // domain controller name or domain dns name IN LPWSTR UserName, IN LPWSTR Password, IN DWORD AuthFlags, IN OUT LPWSTR *RootLocation, // what is the value of the nameingContext attrib that we used? IN OUT HANDLE *hRoot // handle to the above object.. ) { DWORD Result; LPWSTR RootDSEString; LPWSTR RootEnterpriseString; HANDLE hRootDSE; HRESULT hResult; *RootLocation = NULL; *hRoot = NULL; RootDSEString = MakeRootDSEString(Server); if( NULL == RootDSEString ) return ERROR_NOT_ENOUGH_MEMORY; hResult = ADSIOpenDSObject( RootDSEString, UserName, Password, AuthFlags, &hRootDSE ); MemFree(RootDSEString); if( FAILED(hResult) ) return ConvertHresult(hResult); hResult = GetEnterpriseRootFromRootHandle( hRootDSE, Server, UserName, Password, AuthFlags, RootLocation, hRoot ); ADSICloseDSObject(hRootDSE); if( FAILED(hResult) ) return ConvertHresult(hResult); Require(hRoot && RootLocation); return ERROR_SUCCESS; } //================================================================================ // exported functions //================================================================================ //BeginExport(function) DWORD StoreInitHandle( // initialize a handle IN OUT STORE_HANDLE *hStore, // will be filled in with stuff.. IN DWORD Reserved, // must be zero -- for future use IN LPWSTR Domain, // OPTIONAL NULL==>default Domain IN LPWSTR UserName, // OPTIONAL NULL==>default credentials IN LPWSTR Password, // OPTIONAL used only if UserName given IN DWORD AuthFlags // OPTIONAL 0 ==> default?????? ) //EndExport(function) { DWORD Result; DWORD Size; LPWSTR EnterpriseRootLocation; HANDLE RootServer; LPBYTE Memory; Result = GetEnterpriseRootObject( Domain, UserName, Password, AuthFlags, &EnterpriseRootLocation, &RootServer ); if( ERROR_SUCCESS != Result) return Result; Require(RootServer && EnterpriseRootLocation); Size = sizeof(LONG); Size += SizeString(UserName, FALSE); Size += SizeString(Password, FALSE); Memory = MemAlloc(Size); if( NULL == Memory ) { MemFree(EnterpriseRootLocation); ADSICloseDSObject(RootServer); return ERROR_NOT_ENOUGH_MEMORY; } hStore->MemSize = Size; Size = sizeof(LONG); hStore->MustBeZero = 0; hStore->Location = EnterpriseRootLocation; hStore->UserName = (LPWSTR)&Memory[Size]; Size += SizeString(UserName, FALSE); hStore->Password = (LPWSTR)&Memory[Size]; Size += SizeString(Password, FALSE); hStore->AuthFlags = AuthFlags; hStore->ADSIHandle = RootServer; hStore->SearchHandle = NULL; hStore->Memory = Memory; if( NULL == UserName ) hStore->UserName = NULL; else wcscpy(hStore->UserName, UserName); if( NULL == Password ) hStore->Password = NULL; else wcscpy(hStore->Password,Password); return ERROR_SUCCESS; } //BeginExport(function) DWORD StoreCleanupHandle( // cleanup the handle IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved ) //EndExport(function) { DWORD Result; AssertRet(hStore, ERROR_INVALID_PARAMETER); AssertRet(hStore->Location, ERROR_INVALID_PARAMETER); MemFree(hStore->Location); MemFree(hStore->Memory); if(hStore->SearchHandle) ADSICloseSearchHandle(hStore->ADSIHandle, hStore->SearchHandle); ADSICloseDSObject(hStore->ADSIHandle); // memset(hStore, 0, sizeof(*hStore)); hStore->Location = NULL; hStore->UserName = NULL; hStore->Password = NULL; hStore->AuthFlags = 0; hStore->ADSIHandle = 0; hStore->Memory = NULL; hStore->MemSize = 0; // hStore->SearchStarted = FALSE; return ERROR_SUCCESS; } //BeginExport(enum) enum { StoreGetChildType, StoreGetAbsoluteSameServerType, StoreGetAbsoluteOtherServerType } _StoreGetType; //EndExport(enum) DWORD ConvertPath( // convert a "CN=X" type spec to "LDAP://Server/CN=X".. IN LPSTORE_HANDLE hStore, // needed to get the initial strings bits IN DWORD StoreGetType, IN LPWSTR PathIn, OUT LPWSTR *PathOut ) { DWORD Size; DWORD PrefixSize; DWORD SuffixSize; LPWSTR TmpString; LPWSTR PrefixString; *PathOut = NULL; if( StoreGetChildType == StoreGetType ) { TmpString = PrefixString = hStore->Location; TmpString = wcschr(TmpString, L'/'); Require(TmpString); TmpString ++; TmpString = wcschr(TmpString, L'/'); Require(TmpString); TmpString ++; if( wcschr(TmpString, L'/') ) { TmpString = wcschr(TmpString, L'/'); TmpString ++; } PrefixSize = sizeof(WCHAR)*(DWORD)(TmpString - PrefixString ); SuffixSize = SizeString(hStore->Location, FALSE)-PrefixSize; } else if( StoreGetAbsoluteSameServerType == StoreGetType ) { TmpString = PrefixString = hStore->Location; TmpString = wcschr(TmpString, L'/'); Require(TmpString); TmpString ++; TmpString = wcschr(TmpString, L'/'); Require(TmpString); TmpString ++; if( wcschr(TmpString, L'/') ) { TmpString = wcschr(TmpString, L'/'); TmpString ++; } PrefixSize = sizeof(WCHAR)*(DWORD)(TmpString - PrefixString ); SuffixSize = 0; } else if( StoreGetAbsoluteOtherServerType == StoreGetType ) { PrefixSize = 0; // use the path given by the user SuffixSize = 0; } else { Require(FALSE); PrefixSize = SuffixSize = 0; } Size = PrefixSize + SuffixSize + SizeString(PathIn,FALSE) + sizeof(CONNECTOR) - sizeof(WCHAR); TmpString = MemAlloc(Size); if( NULL == TmpString ) return ERROR_NOT_ENOUGH_MEMORY; if( PrefixSize ) { memcpy((LPBYTE)TmpString, (LPBYTE)PrefixString, PrefixSize); } wcscpy((LPWSTR)(PrefixSize + (LPBYTE)TmpString), PathIn); if( SuffixSize ) { wcscat(TmpString, CONNECTOR); wcscat(TmpString, (LPWSTR)(PrefixSize+(LPBYTE)PrefixString)); } *PathOut = TmpString; StoreTrace2("ConvertedPath: %ws\n", TmpString); return ERROR_SUCCESS; } //BeginExport(function) DWORD StoreGetHandle( // get handle to child object, absolute object.. IN OUT LPSTORE_HANDLE hStore, // this gets modified.. IN DWORD Reserved, IN DWORD StoreGetType, // same server? just a simple child? IN LPWSTR Path, IN OUT STORE_HANDLE *hStoreOut // new handle created.. ) //EndExport(function) { HRESULT hResult; DWORD Result; DWORD Size; LPWSTR ConvertedPath; HANDLE ObjectHandle; LPBYTE Memory; AssertRet(hStore, ERROR_INVALID_PARAMETER); AssertRet(hStore->Location, ERROR_INVALID_PARAMETER); AssertRet(Path, ERROR_INVALID_PARAMETER); AssertRet(hStoreOut, ERROR_INVALID_PARAMETER); Result = ConvertPath(hStore, StoreGetType, Path, &ConvertedPath); if( ERROR_SUCCESS != Result ) return Result; Require(ConvertedPath); Memory = MemAlloc(hStore->MemSize); if( NULL == Memory ) { MemFree(ConvertedPath); return ERROR_NOT_ENOUGH_MEMORY; } hResult = ADSIOpenDSObject( ConvertedPath, hStore->UserName, hStore->Password, hStore->AuthFlags, &ObjectHandle ); if( FAILED(hResult) ) { MemFree(ConvertedPath); MemFree(Memory); return ConvertHresult(hResult); } memcpy(Memory, hStore->Memory, hStore->MemSize); Size = sizeof(LONG); hStoreOut->MemSize = hStore->MemSize; hStoreOut->MustBeZero = 0; hStoreOut->Location = ConvertedPath; hStoreOut->UserName = (LPWSTR)&Memory[Size]; Size += SizeString(hStore->UserName, FALSE); hStoreOut->Password = (LPWSTR)&Memory[Size]; Size += SizeString(hStore->Password, FALSE); hStoreOut->AuthFlags = hStore->AuthFlags; hStoreOut->ADSIHandle = ObjectHandle; hStoreOut->SearchHandle = NULL; hStoreOut->Memory = Memory; if( NULL == hStore->UserName ) hStoreOut->UserName = NULL; if( NULL == hStore->Password ) hStoreOut->Password = NULL; return ERROR_SUCCESS; } //BeginExport(function) DWORD StoreSetSearchOneLevel( // search will return everything one level below IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved ) //EndExport(function) { HRESULT hResult; ADS_SEARCHPREF_INFO SearchPref[3]; AssertRet(hStore && hStore->ADSIHandle, ERROR_INVALID_PARAMETER); AssertRet(Reserved == 0, ERROR_INVALID_PARAMETER); SearchPref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; SearchPref[0].vValue.dwType = ADSTYPE_INTEGER; SearchPref[0].vValue.Integer = ADS_SCOPE_ONELEVEL; SearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; SearchPref[1].vValue.dwType = ADSTYPE_INTEGER; SearchPref[1].vValue.Integer = DHCPDS_DS_SEARCH_PAGESIZE; // Make it cache the results at the client side. This is // default, but try it anyway. SearchPref[2].dwSearchPref = ADS_SEARCHPREF_CACHE_RESULTS; SearchPref[2].vValue.dwType = ADSTYPE_BOOLEAN; SearchPref[2].vValue.Boolean = TRUE; hResult = ADSISetSearchPreference( /* hDSObject */ hStore->ADSIHandle, /* pSearchPrefs */ SearchPref, /* dwNumPrefs */ 2 // sizeof( SearchPref ) / sizeof( SearchPref[ 0 ]) ); if( FAILED(hResult) ) return ConvertHresult(hResult); return ERROR_SUCCESS; } //BeginExport(function) DWORD StoreSetSearchSubTree( // search will return the subtree below in ANY order IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved ) //EndExport(function) { HRESULT hResult; ADS_SEARCHPREF_INFO SearchPref[3]; AssertRet(hStore && hStore->ADSIHandle, ERROR_INVALID_PARAMETER); AssertRet(Reserved == 0, ERROR_INVALID_PARAMETER); SearchPref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE; SearchPref[0].vValue.dwType = ADSTYPE_INTEGER; SearchPref[0].vValue.Integer = ADS_SCOPE_SUBTREE; SearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; SearchPref[1].vValue.dwType = ADSTYPE_INTEGER; SearchPref[1].vValue.Integer = DHCPDS_DS_SEARCH_PAGESIZE; // Make it cache the results at the client side. This is // default, but try it anyway. SearchPref[2].dwSearchPref = ADS_SEARCHPREF_CACHE_RESULTS; SearchPref[2].vValue.dwType = ADSTYPE_BOOLEAN; SearchPref[2].vValue.Boolean = TRUE; hResult = ADSISetSearchPreference( /* hDSObject */ hStore->ADSIHandle, /* pSearchPrefs */ SearchPref, /* dwNumPrefs */ sizeof( SearchPref ) / sizeof( SearchPref[ 0 ]) ); if( FAILED(hResult) ) return ConvertHresult(hResult); return ERROR_SUCCESS; } //BeginExport(function) DWORD StoreBeginSearch( IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved, IN LPWSTR SearchFilter ) //EndExport(function) { HRESULT hResult; LPWSTR nameAttrib; nameAttrib = ATTRIB_NAME; AssertRet(hStore && hStore->ADSIHandle, ERROR_INVALID_PARAMETER); AssertRet(Reserved == 0, ERROR_INVALID_PARAMETER); hResult = ADSIExecuteSearch( hStore->ADSIHandle, SearchFilter, (LPWSTR *)&nameAttrib, 1, &(hStore->SearchHandle) ); if( FAILED(hResult) ) return ConvertHresult(hResult); hStore->SearchStarted = FALSE; return ERROR_SUCCESS; } //BeginExport(function) DWORD StoreEndSearch( IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved ) //EndExport(function) { HRESULT hResult; AssertRet(hStore, ERROR_INVALID_PARAMETER); AssertRet(hStore->SearchHandle, ERROR_INVALID_PARAMETER); AssertRet(Reserved == 0, ERROR_INVALID_PARAMETER); hResult = ADSICloseSearchHandle(hStore->ADSIHandle, hStore->SearchHandle); hStore->SearchHandle = NULL; hStore->SearchStarted = FALSE; if( FAILED(hResult) ) return ConvertHresult(hResult); return ERROR_SUCCESS; } //BeginExport(function) DWORD // ERROR_NO_MORE_ITEMS if exhausted StoreSearchGetNext( IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved, OUT LPSTORE_HANDLE hStoreOut ) //EndExport(function) { DWORD Result; HRESULT hResult; ADS_SEARCH_COLUMN Column; LPWSTR ColumnName; AssertRet(hStore && hStore->ADSIHandle && hStoreOut, ERROR_INVALID_PARAMETER); AssertRet(Reserved == 0, ERROR_INVALID_PARAMETER); if ( !hStore->SearchStarted ) { hResult = ADSIGetFirstRow( hStore->ADSIHandle, hStore->SearchHandle ); hStore->SearchStarted = TRUE; } else { hResult = ADSIGetNextRow( hStore->ADSIHandle, hStore->SearchHandle ); } if( FAILED(hResult) ) return ConvertHresult(hResult); if( S_ADS_NOMORE_ROWS == hResult ) return ERROR_NO_MORE_ITEMS; hResult = ADSIGetColumn( hStore->ADSIHandle, hStore->SearchHandle, ATTRIB_NAME, &Column ); if( FAILED(hResult) ) { Require(FALSE); return ConvertHresult(hResult); } Require(1==Column.dwNumValues); // single valued if( Column.pADsValues[0].dwType == ADSTYPE_DN_STRING ) { Require(Column.pADsValues[0].DNString); ColumnName = MakeColumnName(Column.pADsValues[0].DNString); } else if( Column.pADsValues[0].dwType == ADSTYPE_CASE_IGNORE_STRING ) { Require(Column.pADsValues[0].CaseIgnoreString); ColumnName = MakeColumnName(Column.pADsValues[0].CaseIgnoreString); } else { Require(FALSE); ColumnName = NULL; } if( NULL == ColumnName ) Result = ERROR_NOT_ENOUGH_MEMORY; else { Result = StoreGetHandle( hStore, Reserved, StoreGetChildType, ColumnName, hStoreOut ); MemFree(ColumnName); } ADSIFreeColumn( hStore->ADSIHandle, &Column ); return Result; } //BeginExport(function) DWORD StoreCreateObjectVA( // create a new object - var-args ending with ADSTYPE_INVALID IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved, IN LPWSTR NewObjName, // name of the new object -- must be "CN=name" types ... // fmt is AttrType, AttrName, AttrValue [AttrValueLen] ) //EndExport(function) // LARGE_INTEGER type has hi_word followed by low_word { HRESULT hResult; DWORD Result; DWORD i; DWORD ArgType; DWORD nArgs; DWORD Arg1; va_list Args; PADS_ATTR_INFO Attributes; AssertRet(hStore, ERROR_INVALID_PARAMETER); AssertRet(NewObjName, ERROR_INVALID_PARAMETER); nArgs = 0; va_start(Args, NewObjName); do { ArgType = va_arg(Args, DWORD); if( ADSTYPE_INVALID == ArgType ) break; va_arg(Args, LPWSTR); // skip the name of attrib switch(ArgType) { case ADSTYPE_DN_STRING : case ADSTYPE_CASE_EXACT_STRING: case ADSTYPE_CASE_IGNORE_STRING: case ADSTYPE_PRINTABLE_STRING: case ADSTYPE_NUMERIC_STRING: case ADSTYPE_UTC_TIME: case ADSTYPE_OBJECT_CLASS: va_arg(Args, LPWSTR); break; case ADSTYPE_BOOLEAN: case ADSTYPE_INTEGER: va_arg(Args, DWORD); break; case ADSTYPE_OCTET_STRING: va_arg(Args, LPBYTE); va_arg(Args, DWORD); // additional DWORD values for these.. break; case ADSTYPE_LARGE_INTEGER: va_arg(Args, LONG); va_arg(Args, DWORD); // additional DWORD values for these.. break; default: return ERROR_INVALID_PARAMETER; } nArgs ++; } while( 1 ); if( 0 == nArgs ) { Attributes = NULL; } else { Attributes = MemAlloc(nArgs * sizeof(*Attributes)); if( NULL == Attributes ) return ERROR_NOT_ENOUGH_MEMORY; memset(Attributes, 0, sizeof(*Attributes)); } va_start(Args, NewObjName); for(i = 0; i < nArgs; i ++ ) { ArgType = va_arg(Args, DWORD); Require(ADSTYPE_INVALID != ArgType); Attributes[i].dwNumValues = 1; Attributes[i].pADsValues = MemAlloc(sizeof(*Attributes[i].pADsValues)); if( NULL == Attributes[i].pADsValues ) { nArgs = i; goto Cleanup; } Attributes[i].pszAttrName = (LPWSTR)va_arg(Args, LPWSTR); Attributes[i].dwControlCode = ADS_ATTR_APPEND; Attributes[i].dwADsType = ArgType; Attributes[i].pADsValues[0].dwType = ArgType; switch(ArgType) { case ADSTYPE_DN_STRING : Attributes[i].pADsValues[0].DNString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_CASE_EXACT_STRING: Attributes[i].pADsValues[0].CaseExactString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_CASE_IGNORE_STRING: Attributes[i].pADsValues[0].CaseIgnoreString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_PRINTABLE_STRING: Attributes[i].pADsValues[0].PrintableString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_NUMERIC_STRING: Attributes[i].pADsValues[0].NumericString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_BOOLEAN: Attributes[i].pADsValues[0].Boolean = va_arg(Args,DWORD); break; case ADSTYPE_INTEGER: Attributes[i].pADsValues[0].Integer = va_arg(Args,DWORD); break; case ADSTYPE_OBJECT_CLASS: Attributes[i].pADsValues[0].ClassName = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_OCTET_STRING: Attributes[i].pADsValues[0].OctetString.lpValue = (LPBYTE)va_arg(Args,LPBYTE); Attributes[i].pADsValues[0].OctetString.dwLength = va_arg(Args, DWORD); break; case ADSTYPE_LARGE_INTEGER: Attributes[i].pADsValues[0].LargeInteger.HighPart = (LONG)va_arg(Args,LONG); Attributes[i].pADsValues[0].LargeInteger.LowPart = va_arg(Args, ULONG); break; case ADSTYPE_UTC_TIME: Attributes[i].pADsValues[0].UTCTime = *((ADS_UTC_TIME*)va_arg(Args,PVOID)); break; default: nArgs = i; Result = ERROR_INVALID_PARAMETER; goto Cleanup; } } hResult = ADSICreateDSObject( hStore->ADSIHandle, NewObjName, Attributes, nArgs ); if( HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hResult || HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hResult || E_ADS_OBJECT_EXISTS == hResult ) { Result = ERROR_ALREADY_EXISTS; } else if( FAILED(hResult) ) { Result = ConvertHresult(hResult); } else { Result = ERROR_SUCCESS; } Cleanup: if( NULL != Attributes ) { for( i = 0; i < nArgs ; i ++ ) { if( Attributes[i].pADsValues ) MemFree(Attributes[i].pADsValues); } MemFree(Attributes); } return Result; } //BeginExport(function) DWORD StoreCreateObjectL( // create the object as an array IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved, IN LPWSTR NewObjName, // must be "CN=XXX" types IN PADS_ATTR_INFO Attributes, // the required attributes IN DWORD nAttributes // size of above array ) //EndExport(function) { HRESULT hResult; DWORD Result; hResult = ADSICreateDSObject( hStore->ADSIHandle, NewObjName, Attributes, nAttributes ); if( HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) == hResult || HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hResult || E_ADS_OBJECT_EXISTS == hResult ) { Result = ERROR_ALREADY_EXISTS; } else if( FAILED(hResult) ) { Result = ConvertHresult(hResult); } else { Result = ERROR_SUCCESS; } return Result; } //BeginExport(defines) #define StoreCreateObject StoreCreateObjectVA //EndExport(defines) //BeginExport(function) DWORD StoreDeleteObject( IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved, IN LPWSTR ObjectName ) //EndExport(function) { DWORD Result; HRESULT hResult; AssertRet(hStore, ERROR_INVALID_PARAMETER); AssertRet(ObjectName, ERROR_INVALID_PARAMETER); hResult = ADSIDeleteDSObject( hStore->ADSIHandle, ObjectName ); if( FAILED(hResult) ) return ConvertHresult(hResult); return ERROR_SUCCESS; } //BeginExport(function) //DOC StoreDeleteThisObject deletes the object defined by hStore,StoreGetType and ADsPath. //DOC The refer to the object just the same way as for StoreGetHandle. DWORD StoreDeleteThisObject( // delete an object IN LPSTORE_HANDLE hStore, // point of anchor frm which reference is done IN DWORD Reserved, // must be zero, reserved for future use IN DWORD StoreGetType, // path is relative, absolute or diff server? IN LPWSTR Path // ADsPath to the object or relative path ) //EndExport(function) { HRESULT hResult; DWORD Result; DWORD Size; LPWSTR ConvertedPath, ChildNameStart,ChildNameEnd; LPWSTR ChildName; HANDLE ParentObject; AssertRet(hStore, ERROR_INVALID_PARAMETER); AssertRet(hStore->Location, ERROR_INVALID_PARAMETER); AssertRet(Path, ERROR_INVALID_PARAMETER); Result = ConvertPath(hStore, StoreGetType, Path, &ConvertedPath); if( ERROR_SUCCESS != Result ) return Result; Require(ConvertedPath); ChildNameStart = wcschr(ConvertedPath, L'/'); Require(ChildNameStart); ChildNameStart++; ChildNameStart = wcschr(ChildNameStart, L'/'); Require(ChildNameStart); ChildNameStart++; if( wcschr(ChildNameStart, L'/') ) { ChildNameStart = wcschr(ChildNameStart, L'/'); Require(ChildNameStart); ChildNameStart++; } ChildNameEnd = wcschr(ChildNameStart, L','); Require(ChildNameEnd); *ChildNameEnd++ = L'\0'; ChildName = MemAlloc((DWORD)((LPBYTE)ChildNameEnd - (LPBYTE)ChildNameStart)); if( NULL == ChildName ) { MemFree(ConvertPath); return ERROR_NOT_ENOUGH_MEMORY; } memcpy(ChildName, ChildNameStart, (int)((LPBYTE)ChildNameEnd - (LPBYTE)ChildNameStart)); wcscpy(ChildNameStart, ChildNameEnd); // remove child name from ConvertPath hResult = ADSIOpenDSObject( // open the parent object ConvertedPath, hStore->UserName, hStore->Password, hStore->AuthFlags, &ParentObject ); MemFree(ConvertedPath); if( FAILED(hResult) ) { MemFree(ChildName); return ConvertHresult(hResult); } hResult = ADSIDeleteDSObject( // delete the required child object ParentObject, ChildName ); MemFree(ChildName); ADSICloseDSObject(ParentObject); // free up handles and memory if( FAILED(hResult) ) return ConvertHresult(hResult); return ERROR_SUCCESS; // : need to have better error messages than this } //BeginExport(function) DWORD StoreSetAttributesVA( // set the attributes, var_args interface (nearly similar to CreateVA) IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved, IN OUT DWORD* nAttributesModified, ... // fmt is {ADSTYPE, CtrlCode, AttribName, Value}* ending in ADSTYPE_INVALID ) //EndExport(function) { HRESULT hResult; DWORD Result; DWORD i; DWORD ArgType; DWORD nArgs; va_list Args; PADS_ATTR_INFO Attributes; AssertRet(hStore, ERROR_INVALID_PARAMETER); AssertRet(hStore->ADSIHandle, ERROR_INVALID_PARAMETER); nArgs = 0; va_start(Args, nAttributesModified); do { ArgType = va_arg(Args, DWORD); if( ADSTYPE_INVALID == ArgType ) break; va_arg(Args, DWORD); // skip control code va_arg(Args, LPWSTR); // skip the name of attrib switch(ArgType) { case ADSTYPE_DN_STRING : case ADSTYPE_CASE_EXACT_STRING: case ADSTYPE_CASE_IGNORE_STRING: case ADSTYPE_PRINTABLE_STRING: case ADSTYPE_NUMERIC_STRING: case ADSTYPE_OBJECT_CLASS: case ADSTYPE_UTC_TIME: va_arg(Args,LPWSTR); break; case ADSTYPE_BOOLEAN: case ADSTYPE_INTEGER: va_arg( Args, DWORD); break; case ADSTYPE_OCTET_STRING: va_arg(Args, LPBYTE); va_arg(Args, DWORD); // additional DWORD values for these.. case ADSTYPE_LARGE_INTEGER: va_arg(Args, LONG); va_arg(Args, DWORD); // additional DWORD values for these.. break; default: return ERROR_INVALID_PARAMETER; } nArgs ++; } while( 1 ); if( 0 == nArgs ) { Attributes = NULL; } else { Attributes = MemAlloc(nArgs * sizeof(*Attributes)); if( NULL == Attributes ) return ERROR_NOT_ENOUGH_MEMORY; memset(Attributes, 0, sizeof(*Attributes)); } va_start(Args, nAttributesModified); for(i = 0; i < nArgs; i ++ ) { ArgType = va_arg(Args, DWORD); Require(ADSTYPE_INVALID != ArgType); Attributes[i].dwNumValues = 1; Attributes[i].pADsValues = MemAlloc(sizeof(*Attributes[i].pADsValues)); if( NULL == Attributes[i].pADsValues ) { nArgs = i; goto Cleanup; } Attributes[i].dwControlCode = (DWORD)va_arg(Args, DWORD); Attributes[i].pszAttrName = (LPWSTR)va_arg(Args, LPWSTR); Attributes[i].dwADsType = ArgType; Attributes[i].pADsValues[0].dwType = ArgType; switch(ArgType) { case ADSTYPE_DN_STRING : Attributes[i].pADsValues[0].DNString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_CASE_EXACT_STRING: Attributes[i].pADsValues[0].CaseExactString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_CASE_IGNORE_STRING: Attributes[i].pADsValues[0].CaseIgnoreString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_PRINTABLE_STRING: Attributes[i].pADsValues[0].PrintableString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_NUMERIC_STRING: Attributes[i].pADsValues[0].NumericString = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_BOOLEAN: Attributes[i].pADsValues[0].Boolean = va_arg(Args,DWORD); break; case ADSTYPE_INTEGER: Attributes[i].pADsValues[0].Integer = va_arg(Args,DWORD); break; case ADSTYPE_OBJECT_CLASS: Attributes[i].pADsValues[0].ClassName = (LPWSTR)va_arg(Args,LPWSTR); break; case ADSTYPE_OCTET_STRING: Attributes[i].pADsValues[0].OctetString.lpValue = (LPBYTE)va_arg(Args,LPBYTE); Attributes[i].pADsValues[0].OctetString.dwLength = va_arg(Args, DWORD); break; case ADSTYPE_LARGE_INTEGER: Attributes[i].pADsValues[0].LargeInteger.HighPart = (LONG)va_arg(Args,LONG); Attributes[i].pADsValues[0].LargeInteger.LowPart = va_arg(Args, ULONG); break; case ADSTYPE_UTC_TIME: Attributes[i].pADsValues[0].UTCTime = *((ADS_UTC_TIME*)va_arg(Args,PVOID)); break; default: nArgs = i; Result = ERROR_INVALID_PARAMETER; goto Cleanup; } } hResult = ADSISetObjectAttributes( hStore->ADSIHandle, Attributes, nArgs, nAttributesModified ); if( FAILED(hResult) ) return ConvertHresult(hResult); Result = ERROR_SUCCESS; Cleanup: if( NULL != Attributes ) { for( i = 0; i < nArgs ; i ++ ) { if( Attributes[i].pADsValues ) MemFree(Attributes[i].pADsValues); } MemFree(Attributes); } return Result; } //BeginExport(function) DWORD StoreSetAttributesL( // PADS_ATTR_INFO array equiv for SetAttributesVA IN OUT LPSTORE_HANDLE hStore, IN DWORD Reserved, IN OUT DWORD* nAttributesModified, IN PADS_ATTR_INFO AttribArray, IN DWORD nAttributes ) //EndExport(function) { HRESULT hResult; AssertRet(hStore, ERROR_INVALID_PARAMETER); AssertRet(hStore->ADSIHandle, ERROR_INVALID_PARAMETER); hResult = ADSISetObjectAttributes( hStore->ADSIHandle, AttribArray, nAttributes, nAttributesModified ); if( FAILED(hResult) ) return ConvertHresult(hResult); return ERROR_SUCCESS; } //================================================================================ // dhcp specific stuff follow here.. //================================================================================ //BeginExport(typedef) typedef struct _EATTRIB { // encapsulated attribute unsigned int Address1_present : 1; unsigned int Address2_present : 1; unsigned int Address3_present : 1; unsigned int ADsPath_present : 1; unsigned int StoreGetType_present : 1; unsigned int Flags1_present : 1; unsigned int Flags2_present : 1; unsigned int Dword1_present : 1; unsigned int Dword2_present : 1; unsigned int String1_present : 1; unsigned int String2_present : 1; unsigned int String3_present : 1; unsigned int String4_present : 1; unsigned int Binary1_present : 1; unsigned int Binary2_present : 1; DWORD Address1; // character "i" DWORD Address2; // character "j" DWORD Address3; // character "k" LPWSTR ADsPath; // character "p" "r" "l" DWORD StoreGetType; // "p,r,l" ==> sameserver, child, otherserver DWORD Flags1; // character "f" DWORD Flags2; // character "g" DWORD Dword1; // character "d" DWORD Dword2; // character "e" LPWSTR String1; // character "s" LPWSTR String2; // character "t" LPWSTR String3; // character "u" LPWSTR String4; // character "v" LPBYTE Binary1; // character "b" DWORD BinLen1; // # of bytes of above LPBYTE Binary2; // character "d" DWORD BinLen2; // # of bytes of above } EATTRIB, *PEATTRIB, *LPEATTRIB; //EndExport(typedef) //BeginExport(defines) #define IS_ADDRESS1_PRESENT(pEA) ((pEA)->Address1_present) #define IS_ADDRESS1_ABSENT(pEA) (!IS_ADDRESS1_PRESENT(pEA)) #define ADDRESS1_PRESENT(pEA) ((pEA)->Address1_present = 1 ) #define ADDRESS1_ABSENT(pEA) ((pEA)->Address1_present = 0 ) #define IS_ADDRESS2_PRESENT(pEA) ((pEA)->Address2_present) #define IS_ADDRESS2_ABSENT(pEA) (!IS_ADDRESS2_PRESENT(pEA)) #define ADDRESS2_PRESENT(pEA) ((pEA)->Address2_present = 1 ) #define ADDRESS2_ABSENT(pEA) ((pEA)->Address2_present = 0 ) #define IS_ADDRESS3_PRESENT(pEA) ((pEA)->Address3_present) #define IS_ADDRESS3_ABSENT(pEA) (!IS_ADDRESS3_PRESENT(pEA)) #define ADDRESS3_PRESENT(pEA) ((pEA)->Address3_present = 1 ) #define ADDRESS3_ABSENT(pEA) ((pEA)->Address3_present = 0 ) #define IS_ADSPATH_PRESENT(pEA) ((pEA)->ADsPath_present) #define IS_ADSPATH_ABSENT(pEA) (!IS_ADSPATH_PRESENT(pEA)) #define ADSPATH_PRESENT(pEA) ((pEA)->ADsPath_present = 1) #define ADSPATH_ABSENT(pEA) ((pEA)->ADsPath_present = 0) #define IS_STOREGETTYPE_PRESENT(pEA) ((pEA)->StoreGetType_present) #define IS_STOREGETTYPE_ABSENT(pEA) (!((pEA)->StoreGetType_present)) #define STOREGETTYPE_PRESENT(pEA) ((pEA)->StoreGetType_present = 1) #define STOREGETTYPE_ABSENT(pEA) ((pEA)->StoreGetType_present = 0) #define IS_FLAGS1_PRESENT(pEA) ((pEA)->Flags1_present) #define IS_FLAGS1_ABSENT(pEA) (!((pEA)->Flags1_present)) #define FLAGS1_PRESENT(pEA) ((pEA)->Flags1_present = 1) #define FLAGS1_ABSENT(pEA) ((pEA)->Flags1_present = 0) #define IS_FLAGS2_PRESENT(pEA) ((pEA)->Flags2_present) #define IS_FLAGS2_ABSENT(pEA) (!((pEA)->Flags2_present)) #define FLAGS2_PRESENT(pEA) ((pEA)->Flags2_present = 1) #define FLAGS2_ABSENT(pEA) ((pEA)->Flags2_present = 0) #define IS_DWORD1_PRESENT(pEA) ((pEA)->Dword1_present) #define IS_DWORD1_ABSENT(pEA) (!((pEA)->Dword1_present)) #define DWORD1_PRESENT(pEA) ((pEA)->Dword1_present = 1) #define DWORD1_ABSENT(pEA) ((pEA)->Dword1_present = 0) #define IS_DWORD2_PRESENT(pEA) ((pEA)->Dword2_present) #define IS_DWORD2_ABSENT(pEA) (!((pEA)->Dword2_present)) #define DWORD2_PRESENT(pEA) ((pEA)->Dword2_present = 1) #define DWORD2_ABSENT(pEA) ((pEA)->Dword2_present = 0) #define IS_STRING1_PRESENT(pEA) ((pEA)->String1_present) #define IS_STRING1_ABSENT(pEA) (!((pEA)->String1_present)) #define STRING1_PRESENT(pEA) ((pEA)->String1_present = 1) #define STRING1_ABSENT(pEA) ((pEA)->String1_present = 0) #define IS_STRING2_PRESENT(pEA) ((pEA)->String2_present) #define IS_STRING2_ABSENT(pEA) (!((pEA)->String2_present)) #define STRING2_PRESENT(pEA) ((pEA)->String2_present = 1) #define STRING2_ABSENT(pEA) ((pEA)->String2_present = 0) #define IS_STRING3_PRESENT(pEA) ((pEA)->String3_present) #define IS_STRING3_ABSENT(pEA) (!((pEA)->String3_present)) #define STRING3_PRESENT(pEA) ((pEA)->String3_present = 1) #define STRING3_ABSENT(pEA) ((pEA)->String3_present = 0) #define IS_STRING4_PRESENT(pEA) ((pEA)->String4_present) #define IS_STRING4_ABSENT(pEA) (!((pEA)->String4_present)) #define STRING4_PRESENT(pEA) ((pEA)->String4_present = 1) #define STRING4_ABSENT(pEA) ((pEA)->String4_present = 0) #define IS_BINARY1_PRESENT(pEA) ((pEA)->Binary1_present) #define IS_BINARY1_ABSENT(pEA) (!((pEA)->Binary1_present)) #define BINARY1_PRESENT(pEA) ((pEA)->Binary1_present = 1) #define BINARY1_ABSENT(pEA) ((pEA)->Binary1_present = 0) #define IS_BINARY2_PRESENT(pEA) ((pEA)->Binary2_present) #define IS_BINARY2_ABSENT(pEA) (!((pEA)->Binary2_present)) #define BINARY2_PRESENT(pEA) ((pEA)->Binary2_present = 1) #define BINARY2_ABSENT(pEA) ((pEA)->Binary2_present = 0) //EndExport(defines) //BeginExport(inline) BOOL _inline IsAnythingPresent( IN PEATTRIB pEA ) { return IS_ADDRESS1_PRESENT(pEA) || IS_ADDRESS2_PRESENT(pEA) || IS_ADDRESS3_PRESENT(pEA) || IS_ADSPATH_PRESENT(pEA) || IS_STOREGETTYPE_PRESENT(pEA) || IS_FLAGS1_PRESENT(pEA) || IS_FLAGS2_PRESENT(pEA) || IS_DWORD1_PRESENT(pEA) || IS_DWORD2_PRESENT(pEA) || IS_STRING1_PRESENT(pEA) || IS_STRING2_PRESENT(pEA) || IS_STRING3_PRESENT(pEA) || IS_STRING4_PRESENT(pEA) || IS_BINARY1_PRESENT(pEA) || IS_BINARY2_PRESENT(pEA) ; } //EndExport(inline) //BeginExport(inline) BOOL _inline IsEverythingPresent( IN PEATTRIB pEA ) { return IS_ADDRESS1_PRESENT(pEA) && IS_ADDRESS2_PRESENT(pEA) && IS_ADDRESS3_PRESENT(pEA) && IS_ADSPATH_PRESENT(pEA) && IS_STOREGETTYPE_PRESENT(pEA) && IS_FLAGS1_PRESENT(pEA) && IS_FLAGS2_PRESENT(pEA) && IS_DWORD1_PRESENT(pEA) && IS_DWORD2_PRESENT(pEA) && IS_STRING1_PRESENT(pEA) && IS_STRING2_PRESENT(pEA) && IS_STRING3_PRESENT(pEA) && IS_STRING4_PRESENT(pEA) && IS_BINARY1_PRESENT(pEA) && IS_BINARY2_PRESENT(pEA) ; } //EndExport(inline) //BeginExport(inline) VOID _inline EverythingPresent( IN PEATTRIB pEA ) { ADDRESS1_PRESENT(pEA); ADDRESS2_PRESENT(pEA); ADDRESS3_PRESENT(pEA); ADSPATH_PRESENT(pEA); STOREGETTYPE_ABSENT(pEA); FLAGS1_PRESENT(pEA); FLAGS2_PRESENT(pEA); DWORD1_PRESENT(pEA); DWORD2_PRESENT(pEA); STRING1_PRESENT(pEA); STRING2_PRESENT(pEA); STRING3_PRESENT(pEA); STRING4_PRESENT(pEA); BINARY1_PRESENT(pEA); BINARY2_PRESENT(pEA); } //EndExport(inline) //BeginExport(inline) VOID _inline NothingPresent( IN PEATTRIB pEA ) { ADDRESS1_ABSENT(pEA); ADDRESS2_ABSENT(pEA); ADDRESS3_ABSENT(pEA); ADSPATH_ABSENT(pEA); STOREGETTYPE_ABSENT(pEA); FLAGS1_ABSENT(pEA); FLAGS2_ABSENT(pEA); DWORD1_ABSENT(pEA); DWORD2_ABSENT(pEA); STRING1_ABSENT(pEA); STRING2_ABSENT(pEA); STRING3_ABSENT(pEA); STRING4_ABSENT(pEA); BINARY1_ABSENT(pEA); BINARY2_ABSENT(pEA); } //EndExport(inline) const char ch_Address1 = L'i' , ch_Address2 = L'j' , ch_Address3 = L'k' , ch_ADsPath_relative = L'r' , ch_ADsPath_absolute = L'p' , ch_ADsPath_diff_srvr = L'l' , ch_Flags1 = L'f' , ch_Flags2 = L'g' , ch_Dword1 = L'd' , ch_Dword2 = L'e' , ch_String1 = L's' , ch_String2 = L't' , ch_String3 = L'u' , ch_String4 = L'v' , ch_Binary1 = L'b' , ch_Binary2 = L'c' , ch_FieldSep = L'$' ; DWORD StringToIpAddress( // convert a string to an ip-address IN LPWSTR String, IN OUT DWORD *Address ) { CHAR Buffer[20]; // large enough to hold any ip address stuff DWORD Count; LPSTR SkippedWhiteSpace; Count = wcstombs(Buffer, String, sizeof(Buffer) - 1); // save space for '\0' if( -1 == Count ) return ERROR_INVALID_DATA; Buffer[Count] = '\0'; SkippedWhiteSpace = Buffer; while(( ' ' == *SkippedWhiteSpace || '\t' == *SkippedWhiteSpace) && ( SkippedWhiteSpace < &Buffer[Count])) { SkippedWhiteSpace++; } *Address= ntohl(inet_addr(SkippedWhiteSpace));// address is in host order.. if( '\0' == *SkippedWhiteSpace ) return ERROR_INVALID_DATA; return Count <= sizeof("000.000.000.000") ? ERROR_SUCCESS : ERROR_INVALID_DATA; } DWORD _inline StringToFlags( // convert a string to a DWORD IN LPWSTR String, IN OUT DWORD *Flags ) { DWORD Count; LPWSTR Remaining; *Flags = ntohl(wcstoul(String, &Remaining,0));// see input for # base. conv to host order if( *Remaining == L'\0' ) return ERROR_SUCCESS; return ERROR_INVALID_DATA; } BYTE _inline Hex( IN WCHAR wCh ) { if( wCh >= '0' && wCh <= '9' ) return wCh - '0'; if( wCh >= 'A' && wCh <= 'F' ) return wCh - 'A' + 10; if( wCh >= 'a' && wCh <= 'f' ) return wCh - 'a' + 10; return 0x0F+1; // this means error!!! } DWORD _inline StringToBinary( // inline conversion of a string to binary IN OUT LPWSTR String, // this string is mangled while converting IN OUT LPBYTE *Bytes, // this ptr is set to some memory in String.. IN OUT DWORD *nBytes // # of hex bytes copied into location Bytes ) { LPBYTE HexString; DWORD n; BYTE ch1, ch2; HexString = *Bytes = (LPBYTE)String; n = 0; while( *String != L'\0' ) { // look at each character ch1 = Hex(*String++); ch2 = Hex(*String++); if( ch1 > 0xF || ch2 > 0xF ) { // invalid hex bytes for input? return ERROR_INVALID_DATA; } *HexString ++ = (ch1 << 4 ) | ch2; n ++; } *nBytes = n; return ERROR_SUCCESS; } DWORD ConvertStringtoEAttrib( // parse and get the fields out IN OUT LPWSTR String, // may be destroyed in the process IN OUT PEATTRIB Attrib // fill this in ) { DWORD Result; DWORD Address; DWORD Flags; WCHAR ThisChar; LPWSTR ThisString; CHAR Dummy[20]; WCHAR Sep; Require(Attrib); NothingPresent(Attrib); if( String ) StoreTrace2("ConvertStringtoEAttrib(%ws) called\n", String); Sep = ch_FieldSep; while(String && *String && (ThisChar = *String ++)) { ThisString = String; do { // skip to the next attrib String = wcschr(String, Sep); if( NULL == String ) break; if( String[1] == Sep ) { // double consequtive field-sep's stand for the real thing.. wcscpy(String, &String[1]); // remove one of the field-separators, and try looking for one lateron. String ++; continue; } *String++ = L'\0'; // ok, got a real separator: mark that zero and prepare for next break; } while(1); // this could as well be while(0) ?? if( ch_Address1 == ThisChar ) { // this is address1 SetInternalFormatError(REPEATED_ADDRESS1, IS_ADDRESS1_PRESENT(Attrib)); Result = StringToIpAddress( ThisString, &Address ); if( ERROR_SUCCESS != Result ) { // should not happen SetInternalFormatError(INVALID_ADDRESS1, TRUE); } else { ADDRESS1_PRESENT(Attrib); Attrib->Address1 = Address; StoreTrace2("Found address1 %s\n", inet_ntoa(*(struct in_addr*)&Address)); } continue; } if( ch_Address2 == ThisChar ) { SetInternalFormatError(REPEATED_ADDRESS2, IS_ADDRESS2_PRESENT(Attrib)); Result = StringToIpAddress( ThisString, &Address ); if( ERROR_SUCCESS != Result ) { // should not happen SetInternalFormatError(INVALID_ADDRESS2, TRUE); } else { ADDRESS2_PRESENT(Attrib); Attrib->Address2 = Address; StoreTrace2("Found address2 %s\n", inet_ntoa(*(struct in_addr*)&Address)); } continue; } if( ch_Address3 == ThisChar ) { SetInternalFormatError(REPEATED_ADDRESS3, IS_ADDRESS3_PRESENT(Attrib)); Result = StringToIpAddress( ThisString, &Address ); if( ERROR_SUCCESS != Result ) { // should not happen SetInternalFormatError(INVALID_ADDRESS3, TRUE); } else { ADDRESS3_PRESENT(Attrib); Attrib->Address3 = Address; StoreTrace2("Found address3 %s\n", inet_ntoa(*(struct in_addr*)&Address)); } continue; } if( ch_ADsPath_relative == ThisChar || ch_ADsPath_absolute == ThisChar || ch_ADsPath_diff_srvr == ThisChar ) { SetInternalFormatError(REPEATED_ADSPATH, IS_ADSPATH_PRESENT(Attrib)); ADSPATH_PRESENT(Attrib); STOREGETTYPE_PRESENT(Attrib); Attrib->ADsPath = ThisString; if( ch_ADsPath_relative == ThisChar ) Attrib->StoreGetType = StoreGetChildType; else if(ch_ADsPath_absolute == ThisChar ) Attrib->StoreGetType = StoreGetAbsoluteSameServerType; else if(ch_ADsPath_diff_srvr == ThisChar ) Attrib->StoreGetType = StoreGetAbsoluteOtherServerType; StoreTrace3("Found path [%ld] [%ws]\n", Attrib->StoreGetType, ThisString); continue; } if( ch_String1 == ThisChar ) { SetInternalFormatError(REPEATED_STRING1, IS_STRING1_PRESENT(Attrib)); STRING1_PRESENT(Attrib); Attrib->String1 = ThisString; StoreTrace2("Found string1 [%ws]\n", ThisString); continue; } if( ch_String2 == ThisChar ) { SetInternalFormatError(REPEATED_STRING2, IS_STRING2_PRESENT(Attrib)); STRING2_PRESENT(Attrib); Attrib->String2 = ThisString; StoreTrace2("Found string2 [%ws]\n", ThisString); continue; } if( ch_String3 == ThisChar ) { SetInternalFormatError(REPEATED_STRING3, IS_STRING3_PRESENT(Attrib)); STRING3_PRESENT(Attrib); Attrib->String3 = ThisString; StoreTrace2("Found string3 [%ws]\n", ThisString); continue; } if( ch_String4 == ThisChar ) { SetInternalFormatError(REPEATED_STRING4, IS_STRING4_PRESENT(Attrib)); STRING4_PRESENT(Attrib); Attrib->String4 = ThisString; StoreTrace2("Found string4 [%ws]\n", ThisString); continue; } if( ch_Flags1 == ThisChar ) { SetInternalFormatError(REPEATED_FLAGS1, IS_FLAGS1_PRESENT(Attrib)); Result = StringToFlags( ThisString, &Flags ); if( ERROR_SUCCESS != Result ) { SetInternalFormatError(INVALID_FLAGS1, TRUE); } else { FLAGS1_PRESENT(Attrib); Attrib->Flags1 = Flags; StoreTrace2("Found flags1: 0x%lx\n", Flags); } continue; } if( ch_Flags2 == ThisChar ) { SetInternalFormatError(REPEATED_FLAGS2, IS_FLAGS2_PRESENT(Attrib)); Result = StringToFlags( ThisString, &Flags ); if( ERROR_SUCCESS != Result ) { SetInternalFormatError(INVALID_FLAGS2, TRUE); } else { FLAGS2_PRESENT(Attrib); Attrib->Flags2 = Flags; StoreTrace2("Found flags2: 0x%lx\n", Flags); } continue; } if( ch_Dword1 == ThisChar ) { SetInternalFormatError(REPEATED_DWORD1, IS_DWORD1_PRESENT(Attrib)); Result = StringToFlags( ThisString, &Flags ); if( ERROR_SUCCESS != Result ) { SetInternalFormatError(INVALID_DWORD1, TRUE); } else { DWORD1_PRESENT(Attrib); Attrib->Dword1 = Flags; StoreTrace2("Found dword1: 0x%lx\n", Flags); } continue; } if( ch_Dword2 == ThisChar ) { SetInternalFormatError(REPEATED_DWORD2, IS_DWORD2_PRESENT(Attrib)); Result = StringToFlags( ThisString, &Flags ); if( ERROR_SUCCESS != Result ) { SetInternalFormatError(INVALID_DWORD2, TRUE); } else { DWORD2_PRESENT(Attrib); Attrib->Dword2 = Flags; StoreTrace2("Found dword2: 0x%lx\n", Flags); } continue; } if( ch_Binary1 == ThisChar ) { SetInternalFormatError(REPEATED_BINARY1, IS_BINARY1_PRESENT(Attrib)); Result = StringToBinary( ThisString, &Attrib->Binary1, &Attrib->BinLen1 ); if( ERROR_SUCCESS != Result ) { SetInternalFormatError(INVALID_BINARY1, TRUE); BINARY1_ABSENT(Attrib); } else { BINARY1_PRESENT(Attrib); StoreTrace2("Found Binary1 of length %ld\n", Attrib->BinLen1); } continue; } if( ch_Binary2 == ThisChar ) { SetInternalFormatError(REPEATED_BINARY2, IS_BINARY2_PRESENT(Attrib)); Result = StringToBinary( ThisString, &Attrib->Binary2, &Attrib->BinLen2 ); if( ERROR_SUCCESS != Result ) { SetInternalFormatError(INVALID_BINARY2, TRUE); BINARY2_ABSENT(Attrib); } else { BINARY2_PRESENT(Attrib); StoreTrace2("Found Binary2 of length %ld\n", Attrib->BinLen2); } continue; } SetInternalFormatError(INVALID_ATTRIB_FIELD, TRUE); } return IsAnythingPresent(Attrib)? ERROR_SUCCESS : ERROR_INVALID_DATA; } BOOL _inline InvalidStringInBinary( // check if the given binary stream forms a LPWSTR IN LPBYTE Data, IN DWORD DataLen ) { if( 0 == DataLen ) return TRUE; if( DataLen % sizeof(WCHAR) ) return TRUE; DataLen /= sizeof(WCHAR); if( L'\0' != ((LPWSTR)Data)[DataLen-1] ) return TRUE; return FALSE; } DWORD ConvertBinarytoEAttrib( // parse and get the fields out IN OUT LPBYTE Data, // input free format data IN DWORD DataLen, // bytes for data length IN OUT PEATTRIB Attrib // fill this in ) { DWORD Result; DWORD Address; DWORD Flags; DWORD Offset; DWORD ThisDataLen; DWORD xDataLen; LPBYTE xData; LPBYTE ThisData; WCHAR ThisChar; CHAR Dummy[20]; Require(Attrib); NothingPresent(Attrib); Offset = 0; while( Data && DataLen >= sizeof(BYTE) + sizeof(WORD) ) { ThisChar = ntohs(*(LPWORD)Data); Data += sizeof(WORD); DataLen -= sizeof(WORD); ThisDataLen = ntohs(*(LPWORD)Data); Data += sizeof(WORD); DataLen -= sizeof(WORD); if( ROUND_UP_COUNT(ThisDataLen, ALIGN_WORD) > DataLen ) { SetInternalFormatError(INVALID_BINARY_CODING, TRUE); break; } ThisData = Data; Data += ROUND_UP_COUNT(ThisDataLen, ALIGN_WORD); DataLen -= ROUND_UP_COUNT(ThisDataLen, ALIGN_WORD); if( ch_Address1 == ThisChar ) { // this is address1 SetInternalFormatError(REPEATED_ADDRESS1, IS_ADDRESS1_PRESENT(Attrib)); if( sizeof(DWORD) != ThisDataLen ) { SetInternalFormatError(INVALID_ADDRESS1, TRUE); } else { Address = ntohl(*(DWORD UNALIGNED *)ThisData); ADDRESS1_PRESENT(Attrib); Attrib->Address1 = Address; StoreTrace2("Found address1 %s\n", inet_ntoa(*(struct in_addr*)&Address)); } continue; } if( ch_Address2 == ThisChar ) { SetInternalFormatError(REPEATED_ADDRESS2, IS_ADDRESS2_PRESENT(Attrib)); if( sizeof(DWORD) != ThisDataLen ) { SetInternalFormatError(INVALID_ADDRESS2, TRUE); } else { Address = ntohl(*(DWORD UNALIGNED *)ThisData); ADDRESS2_PRESENT(Attrib); Attrib->Address2 = Address; StoreTrace2("Found address2 %s\n", inet_ntoa(*(struct in_addr*)&Address)); } continue; } if( ch_Address3 == ThisChar ) { SetInternalFormatError(REPEATED_ADDRESS3, IS_ADDRESS3_PRESENT(Attrib)); if( sizeof(DWORD) != ThisDataLen ) { SetInternalFormatError(INVALID_ADDRESS3, TRUE); } else { Address = ntohl(*(DWORD UNALIGNED *)ThisData); ADDRESS3_PRESENT(Attrib); Attrib->Address3 = Address; StoreTrace2("Found address3 %s\n", inet_ntoa(*(struct in_addr*)&Address)); } continue; } if( ch_ADsPath_relative == ThisChar || ch_ADsPath_absolute == ThisChar || ch_ADsPath_diff_srvr == ThisChar ) { SetInternalFormatError(REPEATED_ADSPATH, IS_ADSPATH_PRESENT(Attrib)); if( InvalidStringInBinary(ThisData, ThisDataLen) ) { SetInternalFormatError(INVALID_ADSPATH, TRUE); continue; } ADSPATH_PRESENT(Attrib); STOREGETTYPE_PRESENT(Attrib); Attrib->ADsPath = (LPWSTR)ThisData; if( ch_ADsPath_relative == ThisChar ) Attrib->StoreGetType = StoreGetChildType; else if(ch_ADsPath_absolute == ThisChar ) Attrib->StoreGetType = StoreGetAbsoluteSameServerType; else if(ch_ADsPath_diff_srvr == ThisChar ) Attrib->StoreGetType = StoreGetAbsoluteOtherServerType; StoreTrace3("Found path [%ld] [%ws]\n", Attrib->StoreGetType, (LPWSTR)ThisData); continue; } if( ch_String1 == ThisChar ) { SetInternalFormatError(REPEATED_STRING1, IS_STRING1_PRESENT(Attrib)); if( InvalidStringInBinary(ThisData, ThisDataLen) ) { SetInternalFormatError(INVALID_STRING1, TRUE); continue; } STRING1_PRESENT(Attrib); Attrib->String1 = (LPWSTR)ThisData; StoreTrace2("Found string1 [%ws]\n", (LPWSTR)ThisData); continue; } if( ch_String2 == ThisChar ) { SetInternalFormatError(REPEATED_STRING2, IS_STRING2_PRESENT(Attrib)); if( InvalidStringInBinary(ThisData, ThisDataLen) ) { SetInternalFormatError(INVALID_STRING2, TRUE); continue; } STRING2_PRESENT(Attrib); Attrib->String2 = (LPWSTR)ThisData; StoreTrace2("Found string2 [%ws]\n", (LPWSTR)ThisData); continue; } if( ch_String3 == ThisChar ) { SetInternalFormatError(REPEATED_STRING3, IS_STRING3_PRESENT(Attrib)); if( InvalidStringInBinary(ThisData, ThisDataLen) ) { SetInternalFormatError(INVALID_STRING3, TRUE); continue; } STRING3_PRESENT(Attrib); Attrib->String3 = (LPWSTR)ThisData; StoreTrace2("Found string3 [%ws]\n", (LPWSTR)ThisData); continue; } if( ch_String4 == ThisChar ) { SetInternalFormatError(REPEATED_STRING4, IS_STRING4_PRESENT(Attrib)); if( InvalidStringInBinary(ThisData, ThisDataLen) ) { SetInternalFormatError(INVALID_STRING4, TRUE); continue; } STRING4_PRESENT(Attrib); Attrib->String4 = (LPWSTR)ThisData; StoreTrace2("Found string4 [%ws]\n", (LPWSTR)ThisData); continue; } if( ch_Flags1 == ThisChar ) { SetInternalFormatError(REPEATED_FLAGS1, IS_FLAGS1_PRESENT(Attrib)); if( sizeof(DWORD) != ThisDataLen ) { SetInternalFormatError(INVALID_FLAGS1, TRUE); } else { Flags = ntohl(*(DWORD UNALIGNED *)ThisData); FLAGS1_PRESENT(Attrib); Attrib->Flags1 = Flags; StoreTrace2("Found flags1: 0x%lx\n", Flags); } continue; } if( ch_Flags2 == ThisChar ) { SetInternalFormatError(REPEATED_FLAGS2, IS_FLAGS2_PRESENT(Attrib)); if( sizeof(DWORD) != ThisDataLen ) { SetInternalFormatError(INVALID_FLAGS2, TRUE); } else { Flags = ntohl(*(DWORD UNALIGNED *)ThisData); FLAGS2_PRESENT(Attrib); Attrib->Flags2 = Flags; StoreTrace2("Found flags2: 0x%lx\n", Flags); } continue; } if( ch_Dword1 == ThisChar ) { SetInternalFormatError(REPEATED_DWORD1, IS_DWORD1_PRESENT(Attrib)); if( sizeof(DWORD) != ThisDataLen ) { SetInternalFormatError(INVALID_DWORD1, TRUE); } else { Flags = ntohl(*(DWORD UNALIGNED *)ThisData); DWORD1_PRESENT(Attrib); Attrib->Dword1 = Flags; StoreTrace2("Found dword1: 0x%lx\n", Flags); } continue; } if( ch_Dword2 == ThisChar ) { SetInternalFormatError(REPEATED_DWORD2, IS_DWORD2_PRESENT(Attrib)); if( sizeof(DWORD) != ThisDataLen ) { SetInternalFormatError(INVALID_DWORD2, TRUE); } else { Flags = ntohl(*(DWORD UNALIGNED *)ThisData); DWORD2_PRESENT(Attrib); Attrib->Dword2 = Flags; StoreTrace2("Found dword2: 0x%lx\n", Flags); } continue; } if( ch_Binary1 == ThisChar ) { SetInternalFormatError(REPEATED_BINARY1, IS_BINARY1_PRESENT(Attrib)); BINARY1_PRESENT(Attrib); Attrib->Binary1 = ThisData; Attrib->BinLen1 = ThisDataLen; StoreTrace2("Found %ld bytes of binary 1 data\n", ThisDataLen); continue; } if( ch_Binary2 == ThisChar ) { SetInternalFormatError(REPEATED_BINARY2, IS_BINARY2_PRESENT(Attrib)); BINARY2_PRESENT(Attrib); Attrib->Binary2 = ThisData; Attrib->BinLen2 = ThisDataLen; StoreTrace2("Found %ld bytes of binary 2 data\n", ThisDataLen); continue; } SetInternalFormatError(INVALID_ATTRIB_FIELD, TRUE); } return IsAnythingPresent(Attrib) ? ERROR_SUCCESS: ERROR_INVALID_DATA; } PEATTRIB CloneAttrib( IN PEATTRIB Attrib ) { PEATTRIB RetVal; DWORD Size; Size = sizeof(*Attrib); Size = ROUND_UP_COUNT(Size, ALIGN_WORST); if( IS_ADSPATH_PRESENT(Attrib) ) { Size += sizeof(WCHAR)*(1 + wcslen(Attrib->ADsPath)); } if( IS_STRING1_PRESENT(Attrib) ) { Size += sizeof(WCHAR)*(1 + wcslen(Attrib->String1)); } if( IS_STRING2_PRESENT(Attrib) ) { Size += sizeof(WCHAR)*(1 + wcslen(Attrib->String2)); } if( IS_STRING3_PRESENT(Attrib) ) { Size += sizeof(WCHAR)*(1 + wcslen(Attrib->String3)); } if( IS_STRING4_PRESENT(Attrib) ) { Size += sizeof(WCHAR)*(1 + wcslen(Attrib->String4)); } if( IS_BINARY1_PRESENT(Attrib) ) Size += Attrib->BinLen1; if( IS_BINARY2_PRESENT(Attrib) ) Size += Attrib->BinLen2; RetVal = (PEATTRIB)MemAlloc(Size); if( NULL == RetVal ) return NULL; Size = sizeof(*Attrib); Size = ROUND_UP_COUNT(Size, ALIGN_WORST); *RetVal = *Attrib; if( IS_ADSPATH_PRESENT(Attrib) ) { RetVal->ADsPath = (LPWSTR)(Size + (LPBYTE)RetVal); Size += sizeof(WCHAR)*(1 + wcslen(Attrib->ADsPath)); wcscpy(RetVal->ADsPath, Attrib->ADsPath); } if( IS_STRING1_PRESENT(Attrib) ) { RetVal->String1 = (LPWSTR)(Size + (LPBYTE)RetVal); Size += sizeof(WCHAR)*(1 + wcslen(Attrib->String1)); wcscpy(RetVal->String1, Attrib->String1); } if( IS_STRING2_PRESENT(Attrib) ) { RetVal->String2 = (LPWSTR)(Size + (LPBYTE)RetVal); Size += sizeof(WCHAR)*(1 + wcslen(Attrib->String2)); wcscpy(RetVal->String2, Attrib->String2); } if( IS_STRING3_PRESENT(Attrib) ) { RetVal->String3 = (LPWSTR)(Size + (LPBYTE)RetVal); Size += sizeof(WCHAR)*(1 + wcslen(Attrib->String3)); wcscpy(RetVal->String3, Attrib->String3); } if( IS_STRING4_PRESENT(Attrib) ) { RetVal->String4 = (LPWSTR)(Size + (LPBYTE)RetVal); Size += sizeof(WCHAR)*(1 + wcslen(Attrib->String4)); wcscpy(RetVal->String4, Attrib->String4); } if( IS_BINARY1_PRESENT(Attrib) ) { RetVal->Binary1 = (Size + (LPBYTE)RetVal); Size += Attrib->BinLen1; memcpy(RetVal->Binary1, Attrib->Binary1, Attrib->BinLen1); } if( IS_BINARY2_PRESENT(Attrib) ) { RetVal->Binary2 = (Size + (LPBYTE)RetVal); Size += Attrib->BinLen2; memcpy(RetVal->Binary2, Attrib->Binary2, Attrib->BinLen2); } return RetVal; } DWORD AddAttribToArray( IN OUT PARRAY Array, IN PEATTRIB Attrib ) { DWORD Result; Require(Attrib); Attrib = CloneAttrib(Attrib); if( NULL == Attrib) return ERROR_NOT_ENOUGH_MEMORY; Result = MemArrayAddElement(Array, (LPVOID)Attrib); if( ERROR_SUCCESS == Result ) return ERROR_SUCCESS; MemFree(Attrib); return Result; } BOOL _inline OnlyADsPathPresent( IN PEATTRIB pEA ) { if( ! IS_ADSPATH_PRESENT(pEA) ) return FALSE; return IS_ADDRESS1_ABSENT(pEA) && IS_ADDRESS2_ABSENT(pEA) && IS_ADSPATH_ABSENT(pEA) && IS_STOREGETTYPE_ABSENT(pEA) && IS_FLAGS1_ABSENT(pEA) && IS_FLAGS2_ABSENT(pEA) && IS_STRING1_ABSENT(pEA) && IS_STRING2_ABSENT(pEA) && IS_BINARY1_ABSENT(pEA) && IS_BINARY2_ABSENT(pEA) ; } DWORD StoreCollectAttributes( // fwd declaration IN OUT PSTORE_HANDLE hStore, IN DWORD Reserved, IN LPWSTR AttribName, IN OUT PARRAY ArrayToAddTo, IN DWORD RecursionDepth ); DWORD _inline StoreCollectAttributesInternal( IN OUT PSTORE_HANDLE hStore, IN DWORD Reserved, IN PEATTRIB Attrib, IN LPWSTR AttribName, IN OUT PARRAY ArrayToAddTo, // array of PEATTRIBs IN DWORD RecursionDepth // 0 ==> no recursion ) { DWORD Result, Result2; STORE_HANDLE hStore2; if( 0 == RecursionDepth ) { Result = AddAttribToArray(ArrayToAddTo, Attrib); if( ERROR_SUCCESS != Result ) SetInternalFormatError(UNEXPECTED_INTERNAL_ERROR, TRUE); return ERROR_STACK_OVERFLOW; } StoreTrace2("Recursing to %ws\n", Attrib->ADsPath); Result = StoreGetHandle( hStore, /*Reserved*/ 0, Attrib->StoreGetType, Attrib->ADsPath, &hStore2 ); if( ERROR_SUCCESS != Result ) return Result; Result = StoreCollectAttributes( &hStore2, Reserved, AttribName, ArrayToAddTo, RecursionDepth-1 ); Result2 = StoreCleanupHandle( &hStore2, 0 ); return Result; } //BeginExport(function) DWORD StoreCollectAttributes( IN OUT PSTORE_HANDLE hStore, IN DWORD Reserved, IN LPWSTR AttribName, // this attrib must be some kind of a text string IN OUT PARRAY ArrayToAddTo, // array of PEATTRIBs IN DWORD RecursionDepth // 0 ==> no recursion ) //EndExport(function) { HRESULT hResult; DWORD Result; DWORD Error; DWORD nAttributes; DWORD i; PADS_ATTR_INFO Attributes; LPWSTR Attribs[1]; LPWSTR ThisAttribStr; EATTRIB ThisEAttrib; Attribs[0] = AttribName; Attributes = NULL; nAttributes = 0; hResult = ADSIGetObjectAttributes( hStore->ADSIHandle, Attribs, sizeof(Attribs)/sizeof(Attribs[0]), &Attributes, &nAttributes ); if( HRESULT_FROM_WIN32( ERROR_DS_NO_ATTRIBUTE_OR_VALUE) == hResult ) { return ERROR_SUCCESS; } if( FAILED(hResult) ) return ConvertHresult(hResult); if( 0 == nAttributes || NULL == Attributes ) return ERROR_SUCCESS; Require( 1 == nAttributes ); Error = ERROR_SUCCESS; for( i = 0; i < Attributes[0].dwNumValues ; i ++ ) { switch(Attributes[0].pADsValues[i].dwType) { case ADSTYPE_DN_STRING: ThisAttribStr = Attributes[0].pADsValues[i].DNString; break; case ADSTYPE_CASE_EXACT_STRING: ThisAttribStr = Attributes[0].pADsValues[i].CaseExactString; break; case ADSTYPE_CASE_IGNORE_STRING: ThisAttribStr = Attributes[0].pADsValues[i].CaseIgnoreString; break; case ADSTYPE_PRINTABLE_STRING: ThisAttribStr = Attributes[0].pADsValues[i].PrintableString; break; default: SetInternalFormatError(UNEXPECTED_COLLECTION_TYPE, TRUE); continue; } Require(ThisAttribStr); Result = ConvertStringtoEAttrib(ThisAttribStr, &ThisEAttrib); if( ERROR_SUCCESS == Result ) { if( OnlyADsPathPresent(&ThisEAttrib) ) { Result = StoreCollectAttributesInternal( hStore, Reserved, &ThisEAttrib, AttribName, ArrayToAddTo, RecursionDepth ); } else { Result = AddAttribToArray(ArrayToAddTo, &ThisEAttrib); } if( ERROR_SUCCESS != Result ) Error = Result; } else Error = Result; } FreeADsMem(Attributes); return Error; } DWORD StoreCollectBinaryAttributes( // fwd declaration IN OUT PSTORE_HANDLE hStore, IN DWORD Reserved, IN LPWSTR AttribName, IN OUT PARRAY ArrayToAddTo, IN DWORD RecursionDepth ); DWORD _inline StoreCollectBinaryAttributesInternal( IN OUT PSTORE_HANDLE hStore, IN DWORD Reserved, IN PEATTRIB Attrib, IN LPWSTR AttribName, IN OUT PARRAY ArrayToAddTo, // array of PEATTRIBs IN DWORD RecursionDepth // 0 ==> no recursion ) { DWORD Result, Result2; STORE_HANDLE hStore2; if( 0 == RecursionDepth ) { Result = AddAttribToArray(ArrayToAddTo, Attrib); if( ERROR_SUCCESS != Result ) SetInternalFormatError(UNEXPECTED_INTERNAL_ERROR, TRUE); return ERROR_STACK_OVERFLOW; } StoreTrace2("Recursing to %ws\n", Attrib->ADsPath); Result = StoreGetHandle( hStore, /*Reserved*/ 0, Attrib->StoreGetType, Attrib->ADsPath, &hStore2 ); if( ERROR_SUCCESS != Result ) return Result; Result = StoreCollectBinaryAttributes( &hStore2, Reserved, AttribName, ArrayToAddTo, RecursionDepth-1 ); Result2 = StoreCleanupHandle( &hStore2, 0 ); return Result; } //BeginExport(function) DWORD StoreCollectBinaryAttributes( IN OUT PSTORE_HANDLE hStore, IN DWORD Reserved, IN LPWSTR AttribName, // accept only attrib type OCTET_STRING IN OUT PARRAY ArrayToAddTo, // array of PEATTRIBs IN DWORD RecursionDepth // 0 ==> no recursion ) //EndExport(function) { HRESULT hResult; DWORD Result; DWORD Error; DWORD nAttributes; DWORD i; DWORD DataLength; PADS_ATTR_INFO Attributes; LPWSTR Attribs[1]; LPBYTE Data; EATTRIB ThisEAttrib; Attribs[0] = AttribName; Attributes = NULL; nAttributes = 0; hResult = ADSIGetObjectAttributes( hStore->ADSIHandle, Attribs, sizeof(Attribs)/sizeof(Attribs[0]), &Attributes, &nAttributes ); if( HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) == hResult ) { return ERROR_SUCCESS; } if( FAILED(hResult) ) return ConvertHresult(hResult); if( 0 == nAttributes || NULL == Attributes ) return ERROR_SUCCESS; Require( 1 == nAttributes ); Error = ERROR_SUCCESS; for( i = 0; i < Attributes[0].dwNumValues ; i ++ ) { if( ADSTYPE_OCTET_STRING != Attributes[0].pADsValues[i].dwType ) { SetInternalFormatError(UNEXPECTED_COLLECTION_TYPE, TRUE); continue; } Data = Attributes[0].pADsValues[i].OctetString.lpValue; DataLength = Attributes[0].pADsValues[i].OctetString.dwLength; Result = ConvertBinarytoEAttrib(Data, DataLength, &ThisEAttrib); if( ERROR_SUCCESS == Result ) { if( OnlyADsPathPresent(&ThisEAttrib) ) { Result = StoreCollectBinaryAttributesInternal( hStore, Reserved, &ThisEAttrib, AttribName, ArrayToAddTo, RecursionDepth ); } else { Result = AddAttribToArray(ArrayToAddTo, &ThisEAttrib); } if( ERROR_SUCCESS != Result ) Error = Result; } else Error = Result; } FreeADsMem(Attributes); return Error; } DWORD _inline SizeAfterSeparation( // the field separation character has to doubled. IN LPWSTR String, // string with field separation character not escape'ed. IN WCHAR Sep ) { DWORD RetVal; RetVal = wcslen(String); while(String = wcschr(String, Sep ) ) { RetVal ++; } return RetVal; } LPWSTR ConvertStringToString( // duplicate any field_sep characters found IN LPWSTR InStr, IN WCHAR PrefixChar, IN LPWSTR Str, // copy into this pre-allocated buffer IN WCHAR Sep ) { *Str++ = PrefixChar; while( *InStr ) { if( Sep != *InStr ) { *Str ++ = *InStr; } else { *Str ++ = Sep; *Str ++ = Sep; } InStr ++; } *Str = L'\0'; return Str; } LPWSTR // Return the ptr to where the '\0' is stored ConvertAddressToString( // convert ip address to dotted notation LPWSTR IN DWORD Address, IN WCHAR PrefixChar, IN LPWSTR Str // copy into this pre-allocated buffer ) { LPSTR AsciiStr; Address = htonl(Address); // convert to n/w order before making string.. *Str ++ = PrefixChar; AsciiStr = inet_ntoa(*(struct in_addr *)&Address); while( *Str ++ = (WCHAR) *AsciiStr ++ ) ; Str --; *Str = L'\0'; return Str; } LPWSTR ConvertDwordToString( // convert a DWORD to string in 0x.... fmt IN DWORD Dword, IN WCHAR PrefixChar, IN LPWSTR Str // copy into this pre-allocated buffer ) { UCHAR Ch; LPWSTR Stream; DWORD i; Dword = htonl(Dword); // convert to n/w order before making string. *Str ++ = PrefixChar; *Str ++ = L'0'; *Str ++ = L'x' ; Stream = Str; Str += sizeof(Dword)*2; for( i = sizeof(Dword); i ; i -- ) { Ch = (BYTE)(Dword & 0x0F); Dword >>= 4; Stream[i*2 -1] = (Ch < 10)? (L'0'+Ch) : (Ch-10 + L'A'); Ch = (BYTE)(Dword & 0x0F); Dword >>= 4; Stream[i*2 -2] = (Ch < 10)? (L'0'+Ch) : (Ch-10 + L'A'); } *Str = L'\0'; return Str; } LPWSTR ConvertBinaryToString( // convert a binary byte sequence to a string as 0F321B etc.. IN LPBYTE Bytes, IN DWORD nBytes, IN WCHAR PrefixChar, IN LPWSTR Str ) { BYTE Ch, Ch1, Ch2; DWORD i; *Str ++ = PrefixChar; for( i = 0; i < nBytes; i ++ ) { Ch = *Bytes ++; Ch1 = Ch >> 4; Ch2 = Ch & 0x0F; if( Ch1 >= 10 ) *Str ++ = Ch1 - 10 + L'A'; else *Str ++ = Ch1 + L'0'; if( Ch2 >= 10 ) *Str ++ = Ch2 - 10 + L'A'; else *Str ++ = Ch2 + L'0'; } *Str = L'\0'; return Str; } DWORD ConvertEAttribToString( // inverse of ConvertStringtoEAttrib IN PEATTRIB Attrib, // the attrib to encapsulate IN OUT LPWSTR *String, // allocated string IN WCHAR Sep ) { DWORD nChars; LPWSTR Str; WCHAR PrefixChar; AssertRet(String && Attrib, ERROR_INVALID_PARAMETER); *String = NULL; nChars = 0; if( IS_ADDRESS1_PRESENT(Attrib) ) nChars += sizeof(L"$i000.000.000.000"); if( IS_ADDRESS2_PRESENT(Attrib) ) nChars += sizeof(L"$j000.000.000.000"); if( IS_ADDRESS3_PRESENT(Attrib) ) nChars += sizeof(L"$k000.000.000.000"); if( IS_ADSPATH_PRESENT(Attrib) ) { AssertRet( IS_STOREGETTYPE_PRESENT(Attrib), ERROR_INVALID_PARAMETER ); AssertRet( Attrib->ADsPath, ERROR_INVALID_PARAMETER ); nChars += sizeof(WCHAR) * SizeAfterSeparation(Attrib->ADsPath,Sep); nChars += sizeof(L"$p"); } if( IS_FLAGS1_PRESENT(Attrib) ) nChars += sizeof(L"$f0x") + sizeof(DWORD)*2*sizeof(WCHAR); if( IS_FLAGS2_PRESENT(Attrib) ) nChars += sizeof(L"$g0x") + sizeof(DWORD)*2*sizeof(WCHAR); if( IS_DWORD1_PRESENT(Attrib) ) nChars += sizeof(L"$d0x") + sizeof(DWORD)*2*sizeof(WCHAR); if( IS_DWORD2_PRESENT(Attrib) ) nChars += sizeof(L"$e0x") + sizeof(DWORD)*2*sizeof(WCHAR); if( IS_STRING1_PRESENT(Attrib) ) { AssertRet( Attrib->String1, ERROR_INVALID_PARAMETER ); nChars += sizeof(WCHAR) * SizeAfterSeparation(Attrib->String1,Sep); nChars += sizeof(L"$s"); } if( IS_STRING2_PRESENT(Attrib) ) { AssertRet( Attrib->String2, ERROR_INVALID_PARAMETER ); nChars += sizeof(WCHAR) * SizeAfterSeparation(Attrib->String2,Sep); nChars += sizeof(L"$t"); } if( IS_STRING3_PRESENT(Attrib) ) { AssertRet( Attrib->String3, ERROR_INVALID_PARAMETER ); nChars += sizeof(WCHAR) * SizeAfterSeparation(Attrib->String3,Sep); nChars += sizeof(L"$u"); } if( IS_STRING4_PRESENT(Attrib) ) { AssertRet( Attrib->String4, ERROR_INVALID_PARAMETER ); nChars += sizeof(WCHAR) * SizeAfterSeparation(Attrib->String4,Sep); nChars += sizeof(L"$v"); } if( IS_BINARY1_PRESENT(Attrib) ) { nChars += sizeof(WCHAR) * 2 * Attrib->BinLen1; nChars += sizeof(L"$b"); } if( IS_BINARY2_PRESENT(Attrib) ) { nChars += sizeof(WCHAR) * 2 * Attrib->BinLen2; nChars += sizeof(L"$c"); } if( 0 == nChars ) return ERROR_SUCCESS; // nothing is present really. Str = MemAlloc(nChars + sizeof(L"") ); // take care of terminating the string if( NULL == Str ) return ERROR_NOT_ENOUGH_MEMORY; *String = Str; // save the return value, as Str keeps changing if( IS_ADDRESS1_PRESENT(Attrib) ) { Str = ConvertAddressToString(Attrib->Address1, ch_Address1, Str); *Str++ = Sep; } if( IS_ADDRESS2_PRESENT(Attrib) ) { Str = ConvertAddressToString(Attrib->Address2, ch_Address2, Str); *Str++ = Sep; } if( IS_ADDRESS3_PRESENT(Attrib) ) { Str = ConvertAddressToString(Attrib->Address3, ch_Address3, Str); *Str++ = Sep; } if( IS_ADSPATH_PRESENT(Attrib) ) { switch(Attrib->StoreGetType) { case StoreGetChildType: PrefixChar = ch_ADsPath_relative; break; case StoreGetAbsoluteSameServerType: PrefixChar = ch_ADsPath_absolute; break; case StoreGetAbsoluteOtherServerType: PrefixChar = ch_ADsPath_diff_srvr; break; default: Require(FALSE); // too late to do anything about this now. PrefixChar = ch_ADsPath_diff_srvr; break; } Str = ConvertStringToString(Attrib->ADsPath, PrefixChar, Str,Sep); *Str++ = Sep; } if( IS_FLAGS1_PRESENT(Attrib) ) { Str = ConvertDwordToString(Attrib->Flags1, ch_Flags1, Str); *Str++ = Sep; } if( IS_FLAGS2_PRESENT(Attrib) ) { Str = ConvertDwordToString(Attrib->Flags2, ch_Flags2, Str); *Str++ = Sep; } if( IS_DWORD1_PRESENT(Attrib) ) { Str = ConvertDwordToString(Attrib->Dword1, ch_Dword1, Str); *Str++ = Sep; } if( IS_DWORD2_PRESENT(Attrib) ) { Str = ConvertDwordToString(Attrib->Dword2, ch_Dword2, Str); *Str++ = Sep; } if( IS_STRING1_PRESENT(Attrib) ) { Str = ConvertStringToString(Attrib->String1, ch_String1, Str,Sep); *Str++ = Sep; } if( IS_STRING2_PRESENT(Attrib) ) { Str = ConvertStringToString(Attrib->String2, ch_String2, Str,Sep); *Str++ = Sep; } if( IS_STRING3_PRESENT(Attrib) ) { Str = ConvertStringToString(Attrib->String3, ch_String3, Str,Sep); *Str++ = Sep; } if( IS_STRING4_PRESENT(Attrib) ) { Str = ConvertStringToString(Attrib->String4, ch_String4, Str,Sep); *Str++ = Sep; } if( IS_BINARY1_PRESENT(Attrib) ) { Str = ConvertBinaryToString(Attrib->Binary1, Attrib->BinLen1, ch_Binary1, Str); *Str++ = Sep; } if( IS_BINARY2_PRESENT(Attrib) ) { Str = ConvertBinaryToString(Attrib->Binary2, Attrib->BinLen2, ch_Binary2, Str); } *Str = L'\0'; Require(((LPBYTE)Str) < nChars + 1 + ((LPBYTE)(*String)) ); return ERROR_SUCCESS; } LPBYTE ConvertDwordToBinary( // pack a DWORD in binary format IN DWORD Dword, IN WCHAR Character, IN LPBYTE Buffer ) { *(LPWORD)Buffer = htons(Character); Buffer += sizeof(WORD); *(LPWORD)Buffer = htons(sizeof(DWORD)); Buffer += sizeof(WORD); *(DWORD UNALIGNED *)Buffer = htonl(Dword); Buffer += sizeof(DWORD); return Buffer; } LPBYTE ConvertAddressToBinary( // pack an address to binary format.. IN DWORD Address, IN WCHAR Character, IN LPBYTE Buffer ) { return ConvertDwordToBinary(Address,Character,Buffer); } LPBYTE ConvertStringToBinary( // pack a string in binary format IN LPWSTR Str, IN WCHAR Character, IN LPBYTE Buffer ) { DWORD Size; Size = sizeof(WCHAR)*(1+wcslen(Str)); *(LPWORD)Buffer = htons(Character); Buffer += sizeof(WORD); *(LPWORD)Buffer = htons((WORD)Size); Buffer += sizeof(WORD); memcpy(Buffer, Str, Size); Buffer += ROUND_UP_COUNT(Size, ALIGN_WORD); return Buffer; } DWORD ConvertEAttribToBinary( // inverse of ConvertBinarytoEAttrib IN PEATTRIB Attrib, // the attrib to encapsulate IN OUT LPBYTE *Bytes, // allocated buffer IN OUT DWORD *nBytes // # of bytes allocated ) { DWORD nChars; LPBYTE Buf; WCHAR PrefixChar; AssertRet(Bytes && Attrib && nBytes, ERROR_INVALID_PARAMETER); *Bytes = NULL; *nBytes =0; nChars = 0; // WCHAR_opcode ~ WORD_size ~ DWORD_ipAddress if( IS_ADDRESS1_PRESENT(Attrib) ) nChars += sizeof(WORD) + sizeof(WORD) + sizeof(DWORD); if( IS_ADDRESS2_PRESENT(Attrib) ) nChars += sizeof(WORD) + sizeof(WORD) + sizeof(DWORD); if( IS_ADDRESS3_PRESENT(Attrib) ) nChars += sizeof(WORD) + sizeof(WORD) + sizeof(DWORD); if( IS_ADSPATH_PRESENT(Attrib) ) { AssertRet( IS_STOREGETTYPE_PRESENT(Attrib), ERROR_INVALID_PARAMETER ); AssertRet( Attrib->ADsPath, ERROR_INVALID_PARAMETER ); nChars += sizeof(WORD) + sizeof(WORD); // WCHAR_opcode ~ WORD_size nChars += sizeof(WCHAR) * (1+ wcslen(Attrib->ADsPath)); } // WCHAR_opcode ~ WORD_size ~ DWORD_flags if( IS_FLAGS1_PRESENT(Attrib) ) nChars += sizeof(WORD) + sizeof(WORD) + sizeof(DWORD); if( IS_FLAGS2_PRESENT(Attrib) ) nChars += sizeof(WORD) + sizeof(WORD) + sizeof(DWORD); if( IS_DWORD1_PRESENT(Attrib) ) nChars += sizeof(WORD) + sizeof(WORD) + sizeof(DWORD); if( IS_DWORD2_PRESENT(Attrib) ) nChars += sizeof(WORD) + sizeof(WORD) + sizeof(DWORD); if( IS_STRING1_PRESENT(Attrib) ) { AssertRet( Attrib->String1, ERROR_INVALID_PARAMETER ); nChars += sizeof(WORD) + sizeof(WORD); // WCHAR_opcode ~ WORD_size nChars += sizeof(WCHAR) * (1 + wcslen(Attrib->String1)); } if( IS_STRING2_PRESENT(Attrib) ) { AssertRet( Attrib->String2, ERROR_INVALID_PARAMETER ); nChars += sizeof(WORD) + sizeof(WORD); // WCHAR_opcode ~ WORD_size nChars += sizeof(WCHAR) * (1 + wcslen(Attrib->String2)); } if( IS_STRING3_PRESENT(Attrib) ) { AssertRet( Attrib->String3, ERROR_INVALID_PARAMETER ); nChars += sizeof(WORD) + sizeof(WORD); // WCHAR_opcode ~ WORD_size nChars += sizeof(WCHAR) * (1 + wcslen(Attrib->String3)); } if( IS_STRING4_PRESENT(Attrib) ) { AssertRet( Attrib->String4, ERROR_INVALID_PARAMETER ); nChars += sizeof(WORD) + sizeof(WORD); // WCHAR_opcode ~ WORD_size nChars += sizeof(WCHAR) * (1 + wcslen(Attrib->String4)); } if( IS_BINARY1_PRESENT(Attrib) ) { nChars += sizeof(WORD) + sizeof(WORD); // WCHAR_opcode ~ WORD_size nChars += ROUND_UP_COUNT(Attrib->BinLen1, ALIGN_WORD); } if( IS_BINARY2_PRESENT(Attrib) ) { nChars += sizeof(WORD) + sizeof(WORD); // WCHAR_opcode ~ WORD_size nChars += ROUND_UP_COUNT(Attrib->BinLen2, ALIGN_WORD); } if( 0 == nChars ) return ERROR_SUCCESS; // nothing is present really. Buf = MemAlloc(nChars); if( NULL == Buf ) return ERROR_NOT_ENOUGH_MEMORY; *Bytes = Buf; // save the return value.. Buf itself is changed.. *nBytes = nChars; if( IS_ADDRESS1_PRESENT(Attrib) ) Buf = ConvertAddressToBinary(Attrib->Address1, ch_Address1, Buf); if( IS_ADDRESS2_PRESENT(Attrib) ) Buf = ConvertAddressToBinary(Attrib->Address2, ch_Address2, Buf); if( IS_ADDRESS3_PRESENT(Attrib) ) Buf = ConvertAddressToBinary(Attrib->Address3, ch_Address3, Buf); if( IS_ADSPATH_PRESENT(Attrib) ) { switch(Attrib->StoreGetType) { case StoreGetChildType: PrefixChar = ch_ADsPath_relative; break; case StoreGetAbsoluteSameServerType: PrefixChar = ch_ADsPath_absolute; break; case StoreGetAbsoluteOtherServerType: PrefixChar = ch_ADsPath_diff_srvr; break; default: Require(FALSE); // too late to do anything about this now. PrefixChar = ch_ADsPath_diff_srvr; break; } Buf = ConvertStringToBinary(Attrib->ADsPath, PrefixChar, Buf); } if( IS_FLAGS1_PRESENT(Attrib) ) Buf = ConvertDwordToBinary(Attrib->Flags1, ch_Flags1, Buf); if( IS_FLAGS2_PRESENT(Attrib) ) Buf = ConvertDwordToBinary(Attrib->Flags2, ch_Flags2, Buf); if( IS_DWORD1_PRESENT(Attrib) ) Buf = ConvertDwordToBinary(Attrib->Dword1, ch_Dword1, Buf); if( IS_DWORD2_PRESENT(Attrib) ) Buf = ConvertDwordToBinary(Attrib->Dword2, ch_Dword2, Buf); if( IS_STRING1_PRESENT(Attrib) ) Buf = ConvertStringToBinary(Attrib->String1, ch_String1, Buf); if( IS_STRING2_PRESENT(Attrib) ) Buf = ConvertStringToBinary(Attrib->String2, ch_String2, Buf); if( IS_STRING3_PRESENT(Attrib) ) Buf = ConvertStringToBinary(Attrib->String3, ch_String3, Buf); if( IS_STRING4_PRESENT(Attrib) ) Buf = ConvertStringToBinary(Attrib->String4, ch_String4, Buf); if( IS_BINARY1_PRESENT(Attrib) ) { *(LPWORD)Buf = htons(ch_Binary1); Buf += sizeof(WORD); *(LPWORD)Buf = htons((WORD)Attrib->BinLen1); Buf += sizeof(WORD); memcpy(Buf, Attrib->Binary1, Attrib->BinLen1); Buf += ROUND_UP_COUNT(Attrib->BinLen1, ALIGN_WORD); } if( IS_BINARY2_PRESENT(Attrib) ) { *(LPWORD)Buf = htons(ch_Binary2); Buf += sizeof(WORD); *(LPWORD)Buf = htons((WORD)Attrib->BinLen2); Buf += sizeof(WORD); memcpy(Buf, Attrib->Binary2, Attrib->BinLen2); Buf += ROUND_UP_COUNT(Attrib->BinLen2, ALIGN_WORD); } Require( Buf == nChars + (*Bytes) ); return ERROR_SUCCESS; } StoreUpdateAttributesInternal( // update a list of attributes IN OUT LPSTORE_HANDLE hStore, // handle to obj to update IN DWORD Reserved, // for future use, must be zero IN LPWSTR AttribName, // name of attrib, must be string type IN PARRAY Array, // list of attribs IN WCHAR Sep ) //EndExport(function) { DWORD Result; HRESULT hResult; LONG nValues, i; ADS_ATTR_INFO Attribute; PADSVALUE Values; ARRAY_LOCATION Loc; LPWSTR Str; PEATTRIB ThisAttrib; if( NULL == hStore || NULL == hStore->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == AttribName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; if( NULL == Array ) return ERROR_INVALID_PARAMETER; nValues = MemArraySize(Array); if( 0 == nValues ) { // delete the attribute Attribute.pszAttrName = AttribName; Attribute.dwControlCode = ADS_ATTR_CLEAR; Attribute.dwADsType = ADSTYPE_CASE_IGNORE_STRING; Attribute.pADsValues = NULL; Attribute.dwNumValues = 0; hResult = ADSISetObjectAttributes( /* hDSObject */ hStore->ADSIHandle, /* pAttributeEntr.. */ &Attribute, /* dwNumAttributes */ 1, /* pdwNumAttribut.. */ &nValues ); if( FAILED(hResult) || 1 != nValues ) { // something went wrong return ConvertHresult(hResult); } return ERROR_SUCCESS; } Values = MemAlloc(nValues * sizeof(ADSVALUE)); if( NULL == Values ) { // could not allocate ADs array return ERROR_NOT_ENOUGH_MEMORY; } for(i = 0, Result = MemArrayInitLoc(Array, &Loc) ; ERROR_FILE_NOT_FOUND != Result ; // convert to PADS_ATTR_INFO i ++ , Result = MemArrayNextLoc(Array, &Loc) ) { Result = MemArrayGetElement(Array, &Loc, &ThisAttrib); //- ERROR_SUCCESS == Result && NULL != ThisAttrib Str = NULL; Result = ConvertEAttribToString(ThisAttrib, &Str, Sep); if( ERROR_SUCCESS != Result ) { // something went wrong! goto Cleanup; // free allocated memory } Values[i].dwType = ADSTYPE_CASE_IGNORE_STRING; Values[i].CaseIgnoreString = Str; } Attribute.pszAttrName = AttribName; Attribute.dwControlCode = ADS_ATTR_UPDATE; Attribute.dwADsType = ADSTYPE_CASE_IGNORE_STRING; Attribute.pADsValues = Values; Attribute.dwNumValues = nValues; hResult = ADSISetObjectAttributes( /* hDSObject */ hStore->ADSIHandle, /* pAttributeEntr.. */ &Attribute, /* dwNumAttributes */ 1, /* pdwNumAttribut.. */ &nValues ); if( FAILED(hResult) || 1 != nValues ) { // something went wrong Result = ConvertHresult(hResult); } else Result = ERROR_SUCCESS; Cleanup: if( Values ) { // got to free allocated memory while( i -- ) { // got to free converted strings if( Values[i].CaseIgnoreString ) MemFree(Values[i].CaseIgnoreString); } MemFree(Values); } return Result; } //BeginExport(function) //DOC StoreUpdateAttributes is sort of the converse of StoreCollectAttributes. //DOC This function takes an array of type EATTRIB elements and updates the DS //DOC with this array. This function does not work when the attrib is of type //DOC OCTET_STRING etc. It works only with types that can be derived from //DOC PrintableString. DWORD StoreUpdateAttributes( // update a list of attributes IN OUT LPSTORE_HANDLE hStore, // handle to obj to update IN DWORD Reserved, // for future use, must be zero IN LPWSTR AttribName, // name of attrib, must be string type IN PARRAY Array // list of attribs ) //EndExport(function) { DWORD Result; HRESULT hResult; Result = StoreUpdateAttributesInternal( hStore, Reserved, AttribName, Array, ch_FieldSep ); return Result; } //BeginExport(function) //DOC StoreUpdateBinaryAttributes is sort of the converse of StoreCollectBinaryAttributes //DOC This function takes an array of type EATTRIB elements and updates the DS //DOC with this array. This function works only when the attrib is of type //DOC OCTET_STRING etc. It doesnt work with types that can be derived from //DOC PrintableString!!!. DWORD StoreUpdateBinaryAttributes( // update a list of attributes IN OUT LPSTORE_HANDLE hStore, // handle to obj to update IN DWORD Reserved, // for future use, must be zero IN LPWSTR AttribName, // name of attrib, must be OCTET_STRING type IN PARRAY Array // list of attribs ) //EndExport(function) { DWORD Result; HRESULT hResult; LONG nValues, i, nBytes; ADS_ATTR_INFO Attribute; PADSVALUE Values; ARRAY_LOCATION Loc; LPBYTE Bytes; PEATTRIB ThisAttrib; if( NULL == hStore || NULL == hStore->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == AttribName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; if( NULL == Array ) return ERROR_INVALID_PARAMETER; nValues = MemArraySize(Array); if( 0 == nValues ) { // delete the attribute Attribute.pszAttrName = AttribName; Attribute.dwControlCode = ADS_ATTR_CLEAR; Attribute.dwADsType = ADSTYPE_OCTET_STRING; Attribute.pADsValues = NULL; Attribute.dwNumValues = 0; hResult = ADSISetObjectAttributes( /* hDSObject */ hStore->ADSIHandle, /* pAttributeEntr.. */ &Attribute, /* dwNumAttributes */ 1, /* pdwNumAttribut.. */ &nValues ); if( FAILED(hResult) || 1 != nValues ) { // something went wrong return ConvertHresult(hResult); } return ERROR_SUCCESS; } Values = MemAlloc(nValues * sizeof(ADSVALUE)); if( NULL == Values ) { // could not allocate ADs array return ERROR_NOT_ENOUGH_MEMORY; } for(i = 0, Result = MemArrayInitLoc(Array, &Loc) ; ERROR_FILE_NOT_FOUND != Result ; // convert to PADS_ATTR_INFO i ++ , Result = MemArrayNextLoc(Array, &Loc) ) { Result = MemArrayGetElement(Array, &Loc, &ThisAttrib); //- ERROR_SUCCESS == Result && NULL != ThisAttrib Bytes = NULL; nBytes =0; Result = ConvertEAttribToBinary(ThisAttrib, &Bytes, &nBytes); if( ERROR_SUCCESS != Result ) { // something went wrong! goto Cleanup; // free allocated memory } Values[i].dwType = ADSTYPE_OCTET_STRING; Values[i].OctetString.dwLength = nBytes; Values[i].OctetString.lpValue = Bytes; } Attribute.pszAttrName = AttribName; Attribute.dwControlCode = ADS_ATTR_UPDATE; Attribute.dwADsType = ADSTYPE_OCTET_STRING; Attribute.pADsValues = Values; Attribute.dwNumValues = nValues; hResult = ADSISetObjectAttributes( /* hDSObject */ hStore->ADSIHandle, /* pAttributeEntr.. */ &Attribute, /* dwNumAttributes */ 1, /* pdwNumAttribut.. */ &nValues ); if( FAILED(hResult) || 1 != nValues ) { // something went wrong Result = ConvertHresult(hResult); } else Result = ERROR_SUCCESS; Cleanup: if( Values ) { // got to free allocated memory while( i -- ) { // got to free converted strings if( Values[i].OctetString.lpValue ) MemFree(Values[i].OctetString.lpValue); } MemFree(Values); } return Result; } //================================================================================ // end of file //================================================================================