//================================================================================ // Copyright (C) 1997 Microsoft Corporation // Author: RameshV // Description: most of the rpc apis are here and some miscellaneous functions too // all the functions here go to the DS directly. //================================================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //================================================================================ // helper functions //================================================================================ #include // // Allow Debug prints to ntsd or kd // // #ifdef DBG // #define DsAuthPrint(_x_) DsAuthDebugPrintRoutine _x_ // #else // #define DebugPrint(_x_) // #endif extern LPWSTR CloneString( IN LPWSTR String ); typedef enum { LDAP_OPERATOR_EQUAL_TO, LDAP_OPERATOR_APPROX_EQUAL_TO, LDAP_OPERATOR_LESS_OR_EQUAL_TO, LDAP_OPERATOR_GREATER_OR_EQUAL_TO, LDAP_OPERATOR_AND, LDAP_OPERATOR_OR, LDAP_OPERATOR_NOT, LDAP_OPERATOR_TOTAL } LDAP_OPERATOR_ENUM; LPWSTR LdapOperators[ LDAP_OPERATOR_TOTAL ] = { L"=", L"~=", L"<=", L">=", L"&", L"|", L"!" }; VOID DsAuthPrintRoutine( LPWSTR Format, ... ) { WCHAR buf[2 * 256]; va_list arg; DWORD len; va_start( arg, Format ); len = wsprintf(buf, L"DSAUTH: "); wvsprintf( &buf[ len ], Format, arg ); va_end( arg ); OutputDebugString( buf ); } // DsAuthPrint() // // This function creates an LDAP query filter string // with the option type, value and operator. // // Syntax: // primitive : =() // complex : () // LPWSTR MakeLdapFilter( IN LPWSTR Operand1, IN LDAP_OPERATOR_ENUM Operator, IN LPWSTR Operand2, IN BOOL Primitive ) { LPWSTR Result; DWORD Size; DWORD Len; CHAR buffer[100]; Result = NULL; AssertRet((( NULL != Operand1 ) && ( NULL != Operand2 ) && (( Operator >= 0 ) && ( Operator < LDAP_OPERATOR_TOTAL ))), NULL ); // calculate the amount of memory needed Size = 0; Size += ROUND_UP_COUNT( sizeof( L"(" ), ALIGN_WORST ); Size += ROUND_UP_COUNT( sizeof( L")" ), ALIGN_WORST ); Size += ROUND_UP_COUNT( wcslen( Operand1 ), ALIGN_WORST ); Size += ROUND_UP_COUNT( wcslen( Operand2 ), ALIGN_WORST ); Size += ROUND_UP_COUNT( wcslen( LdapOperators[ Operator ] ), ALIGN_WORST ); Size += 16; // padding Result = MemAlloc( Size * sizeof( WCHAR )); if ( NULL == Result ) { return NULL; } if ( Primitive ) { Len = wsprintf( Result, L"(%ws%ws%ws)", Operand1, LdapOperators[ Operator ], Operand2 ); } else { Len = wsprintf( Result, L"(%ws%ws%ws)", LdapOperators[ Operator ], Operand1, Operand2 ); } // else AssertRet( Len <= Size, NULL ); return Result; } // MakeLdapFilter() // // Make a LDAP query filter like this: // (&(objectCategory=dHCPClass)(|(dhcpServer="i*")(dhcpServer="*s*"))) // LPWSTR MakeFilter( LPWSTR LookupServerIP, // Printable IP addr LPWSTR HostName ) { LPWSTR Filter1, Filter2, Filter3, Filter4, SearchFilter; LPWSTR Buf; DWORD Len, CopiedLen; AssertRet((( NULL != LookupServerIP ) && ( NULL != HostName )), NULL ); Filter1 = NULL; Filter2 = NULL; Filter3 = NULL; Filter4 = NULL; SearchFilter = NULL; do { Len = wcslen( HostName ) + 10 ; Buf = MemAlloc( Len * sizeof( WCHAR )); if ( NULL == Buf ) { break; } // make (objectCategory=dHCPClass) Filter1 = MakeLdapFilter( ATTRIB_OBJECT_CATEGORY, LDAP_OPERATOR_EQUAL_TO, DEFAULT_DHCP_CLASS_ATTRIB_VALUE, TRUE ); if ( NULL == Filter1 ) { break; } // The IP needs to be sent as i* to match the query // make (dhcpServers="i*") CopiedLen = _snwprintf( Buf, Len, L"i%ws*", LookupServerIP ); Require( CopiedLen > 0 ); Filter2 = MakeLdapFilter( DHCP_ATTRIB_SERVERS, LDAP_OPERATOR_EQUAL_TO, Buf, TRUE ); if ( NULL == Filter2 ) { break; } // make (dhcpServers="*s*") CopiedLen = _snwprintf( Buf, Len, L"*s%ws*", HostName ); Require( CopiedLen > 0 ); Filter3 = MakeLdapFilter( DHCP_ATTRIB_SERVERS, LDAP_OPERATOR_EQUAL_TO, Buf, TRUE ); if ( NULL == Filter3 ) { break; } // make (|()(Flags2) == RANGE_TYPE_EXCL ) { continue; // skip exclusions } if( ThisAttrib->Address2 < ThisAttrib->Address1 ) { continue; //= ds inconsistent } Cond = MemRangeCompare( RangeStart,RangeEnd, // range X and below is range Y ThisAttrib->Address1, ThisAttrib->Address2 ); switch(Cond) { // make comparisons on 2 ranges case X_LESSTHAN_Y_OVERLAP: case Y_LESSTHAN_X_OVERLAP: if( NULL != *Extender ) return TRUE; // double extensions not allowed *Extender = ThisAttrib; break; case X_IN_Y: case Y_IN_X: return TRUE; // head on collision is fatal } } return FALSE; } BOOL ServerMatched( IN PEATTRIB ThisAttrib, IN LPWSTR ServerName, IN ULONG IpAddress, OUT BOOL *fExactMatch ) { BOOL fIpMatch, fNameMatch, fWildcardIp; (*fExactMatch) = FALSE; fIpMatch = (ThisAttrib->Address1 == IpAddress); if( INADDR_BROADCAST == ThisAttrib->Address1 || INADDR_BROADCAST == IpAddress ) { fWildcardIp = TRUE; } else { fWildcardIp = FALSE; } if( FALSE == fIpMatch ) { // // If IP Addresses don't match, then check to see if // one of the IP addresses is a broadcast address.. // if( !fWildcardIp ) return FALSE; } fNameMatch = DnsNameCompare_W(ThisAttrib->String1, ServerName); if( FALSE == fNameMatch ) { // // If names don't match _and_ IP's don't match, no match. // if( FALSE == fIpMatch || fWildcardIp ) return FALSE; } else { if( FALSE == fIpMatch ) return TRUE; (*fExactMatch) = TRUE; } return TRUE; } DWORD GetListOfAllServersMatchingFilter( IN OUT LPSTORE_HANDLE hDhcpC, IN OUT PARRAY Servers, IN LPWSTR SearchFilter OPTIONAL ) { DWORD Err, LastErr; STORE_HANDLE hContainer; LPWSTR Filter; AssertRet( ( NULL != hDhcpC ) && ( NULL != Servers ), ERROR_INVALID_PARAMETER ); Err = StoreSetSearchOneLevel( hDhcpC, DDS_RESERVED_DWORD ); AssertRet( Err == NO_ERROR, Err ); if ( NULL == SearchFilter ) { Filter = DHCP_SEARCH_FILTER; } else { Filter = SearchFilter; } AssertRet( NULL != Filter, ERROR_INVALID_PARAMETER ); Err = StoreBeginSearch( hDhcpC, DDS_RESERVED_DWORD, Filter ); AssertRet( Err == NO_ERROR, Err ); while( TRUE ) { Err = StoreSearchGetNext( hDhcpC, DDS_RESERVED_DWORD, &hContainer ); if( ERROR_DS_INVALID_DN_SYNTAX == Err ) { // // This nasty problem is because of an upgrade issue // in DS where some bad-named objects may exist.. // Err = NO_ERROR; continue; } if( NO_ERROR != Err ) break; Err = DhcpDsGetLists ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ &hContainer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ Servers, // array of PEATTRIB 's /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); StoreCleanupHandle( &hContainer, DDS_RESERVED_DWORD ); if( NO_ERROR != Err ) break; } if( Err == ERROR_NO_MORE_ITEMS ) Err = NO_ERROR; LastErr = StoreEndSearch( hDhcpC, DDS_RESERVED_DWORD ); //Require( LastErr == NO_ERROR ); return Err; } DWORD DhcpDsAddServerInternal( // add a server in DS IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle IN DWORD Reserved, // must be zero, future use IN LPWSTR ServerName, // [DNS?] name of server IN LPWSTR ReservedPtr, // Server location? future use IN DWORD IpAddress, // ip address of server IN DWORD State // currently un-interpreted ) { DWORD Err, Err2, unused; ARRAY Servers; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; EATTRIB DummyAttrib; BOOL fServerExists; LPWSTR ServerLocation, Tmp; DWORD ServerLocType; if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Servers); // cant fail //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of servers ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hDhcpRoot, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ &Servers, // array of PEATTRIB 's /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; Tmp = NULL; ServerLocation = NULL; fServerExists = FALSE; // did we find the same servername? for( // search list of servers Err = MemArrayInitLoc(&Servers, &Loc) // initialize ; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element ) { BOOL fExactMatch = FALSE; //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server continue; //= ds inconsistent } if( ServerMatched(ThisAttrib, ServerName, IpAddress, &fExactMatch ) ) { // // Server found in the list of servers. Exact match not allowed. // if( fExactMatch ) { MemArrayFree(&Servers,MemFreeFunc);// free allocated memory return ERROR_DDS_SERVER_ALREADY_EXISTS; } fServerExists = TRUE; if( IS_ADDRESS1_PRESENT(ThisAttrib) && NULL == ServerLocation ) { // remember location in DS. ServerLocation = ThisAttrib->ADsPath; ServerLocType = ThisAttrib->StoreGetType; } } } if( !fServerExists ) { // if freshly adding a server, create obj WCHAR Buf[sizeof("000.000.000.000")]; LPWSTR SName; if( L'\0' != ServerName[0] ) { SName = ServerName; } else { ULONG IpAddr; LPSTR IpAddrString; IpAddr = htonl(IpAddress); IpAddrString = inet_ntoa(*(struct in_addr *)&IpAddr); Err = mbstowcs(Buf, IpAddrString, sizeof(Buf)/sizeof(WCHAR)); if( -1 == Err ) { MemArrayFree(&Servers, MemFreeFunc); return ERROR_CAN_NOT_COMPLETE; } SName = Buf; } ServerLocation = Tmp = MakeColumnName(SName); ServerLocType = StoreGetChildType; } NothingPresent(&DummyAttrib); // fill in attrib w/ srvr info STRING1_PRESENT(&DummyAttrib); // name ADDRESS1_PRESENT(&DummyAttrib); // ip addr FLAGS1_PRESENT(&DummyAttrib); // state DummyAttrib.String1 = ServerName; DummyAttrib.Address1 = IpAddress; DummyAttrib.Flags1 = State; if( ServerLocation ) { ADSPATH_PRESENT(&DummyAttrib); // ADsPath of location of server object STOREGETTYPE_PRESENT(&DummyAttrib); DummyAttrib.ADsPath = ServerLocation; DummyAttrib.StoreGetType = ServerLocType; } Err = MemArrayAddElement(&Servers, &DummyAttrib); if( ERROR_SUCCESS != Err ) { // could not add this to attrib array MemArrayFree(&Servers, MemFreeFunc); // free allocated memory if( Tmp ) MemFree(Tmp); // if allocate mem for ServerLocation.. return Err; } Err = DhcpDsSetLists // now set the new attrib list ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hDhcpRoot, /* SetParams */ &unused, /* Servers */ &Servers, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescription */ NULL, /* Classes */ NULL ); Err2 = MemArrayLastLoc(&Servers, &Loc); // theres atleast 1 elt in array //= require ERROR_SUCCESS == Err2 Err2 = MemArrayDelElement(&Servers, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err2 && ThisAttrib == &DummyAttrib MemArrayFree(&Servers, MemFreeFunc); // free allocated memory if( ERROR_SUCCESS != Err || fServerExists ) { if( Tmp ) MemFree(Tmp); // if allocated memory for ServerLocation.. if( ERROR_SUCCESS != Err) return Err; // check err for DhcpDsSetLists //: This wont do if there is a problem... if( fServerExists ) return ERROR_SUCCESS; // if server already existed.. not much work needed? } if( Tmp ) MemFree(Tmp); return Err; } //================================================================================ // exported functions //================================================================================ //BeginExport(function) //DOC DhcpDsAddServer adds a server's entry in the DS. Note that only the name //DOC uniquely determines the server. There can be one server with many ip addresses. //DOC If the server is created first time, a separate object is created for the //DOC server. : TO DO: The newly added server should also have its data //DOC updated in the DS uploaded from the server itself if it is still up. //DOC Note that it takes as parameter the Dhcp root container. //DOC If the requested address already exists in the DS (maybe to some other //DOC server), then the function returns ERROR_DDS_SERVER_ALREADY_EXISTS DWORD DhcpDsAddServer( // add a server in DS IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle IN DWORD Reserved, // must be zero, future use IN LPWSTR ServerName, // [DNS?] name of server IN LPWSTR ReservedPtr, // Server location? future use IN DWORD IpAddress, // ip address of server IN DWORD State // currently un-interpreted ) //EndExport(function) { DWORD Err, Err2, unused; ARRAY Servers; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; BOOL fServerExists; LPWSTR ServerLocation, Tmp; DWORD ServerLocType; STORE_HANDLE hDhcpServer; if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Servers); // cant fail //= require ERROR_SUCCESS == Err DsAuthPrint(( L"DhcpAddServer() \n" )); Err = GetListOfAllServersMatchingFilter( hDhcpC, &Servers, DHCP_SEARCH_FILTER ); if( ERROR_SUCCESS != Err ) return Err; Tmp = NULL; ServerLocation = NULL; fServerExists = FALSE; // did we find the same servername? for( // search list of servers Err = MemArrayInitLoc(&Servers, &Loc) // initialize ; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element ) { BOOL fExactMatch = FALSE; //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server continue; //= ds inconsistent } if( ServerMatched(ThisAttrib, ServerName, IpAddress, &fExactMatch ) ) { // // Server found in the list of servers. Exact match not allowed. // if( fExactMatch ) { MemArrayFree(&Servers,MemFreeFunc);// free allocated memory return ERROR_DDS_SERVER_ALREADY_EXISTS; } fServerExists = TRUE; if( IS_ADDRESS1_PRESENT(ThisAttrib) && NULL == ServerLocation ) { // remember location in DS. ServerLocation = ThisAttrib->ADsPath; ServerLocType = ThisAttrib->StoreGetType; } } } // for if( !fServerExists ) { // if freshly adding a server, create obj WCHAR Buf[sizeof("000.000.000.000")]; LPWSTR SName; if( L'\0' != ServerName[0] ) { // do not use the name. Use the printable IP addr instead SName = ServerName; } else { ULONG IpAddr; LPSTR IpAddrString; IpAddr = htonl(IpAddress); IpAddrString = inet_ntoa(*(struct in_addr *)&IpAddr); Err = mbstowcs(Buf, IpAddrString, sizeof(Buf)/sizeof(WCHAR)); if( -1 == Err ) { MemArrayFree(&Servers, MemFreeFunc); return ERROR_CAN_NOT_COMPLETE; } SName = Buf; } Err = CreateServerObject( /* hDhcpC */ hDhcpC, /* ServerName */ SName ); if( ERROR_SUCCESS != Err ) { // dont add server if obj cant be created MemArrayFree(&Servers, MemFreeFunc); // free allocated memory return Err; } ServerLocation = Tmp = MakeColumnName(SName); ServerLocType = StoreGetChildType; } Err = StoreGetHandle( hDhcpC, 0, ServerLocType, ServerLocation, &hDhcpServer ); if( NO_ERROR == Err ) { Err = DhcpDsAddServerInternal( hDhcpC, &hDhcpServer, Reserved, ServerName, ReservedPtr, IpAddress, State ); StoreCleanupHandle( &hDhcpServer, 0 ); } MemArrayFree(&Servers, MemFreeFunc); // free allocated memory if( ERROR_SUCCESS != Err || fServerExists ) { if( Tmp ) MemFree(Tmp); // if allocated memory for ServerLocation.. if( ERROR_SUCCESS != Err) return Err; // check err for DhcpDsSetLists //: This wont do if there is a problem... if( fServerExists ) return ERROR_SUCCESS; // if server already existed.. not much work needed? } Err = ServerAddAddress // add the info into the server ( /* hDhcpC */ hDhcpC, /* ServerName */ ServerName, /* ADsPath */ ServerLocation, /* IpAddress */ IpAddress, /* State */ State ); if( Tmp ) MemFree(Tmp); return Err; } DWORD DhcpDsDelServerInternal( // Delete a server from memory IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle IN DWORD Reserved, // must be zero, for future use IN LPWSTR ServerName, // which server to delete for IN LPWSTR ReservedPtr, // server location ? future use IN DWORD IpAddress // the IpAddress to delete.. ) { DWORD Err, Err2, unused; ARRAY Servers; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib, SavedAttrib; BOOL fServerExists; BOOL fServerDeleted; LPWSTR SName; LPWSTR ServerLoc = NULL; DWORD ServerLocType; WCHAR Buf[sizeof("000.000.000.000")]; if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Servers); // cant fail //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of servers ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hDhcpRoot, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ &Servers, // array of PEATTRIB 's /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; SavedAttrib = NULL; fServerExists = fServerDeleted = FALSE; for( // search list of servers Err = MemArrayInitLoc(&Servers, &Loc) // initialize ; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element ) { BOOL fExactMatch = FALSE; //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server continue; //= ds inconsistent } if( ServerMatched(ThisAttrib, ServerName, IpAddress, &fExactMatch ) ) { // // Server found. If exact match, remove the element from list. // if( fExactMatch ) { Err2 = MemArrayDelElement(&Servers, &Loc, &ThisAttrib); //= ERROR_SUCCESS == Err2 && NULL != ThisAttrib } if( (NULL == ServerLoc || fExactMatch) && IS_ADSPATH_PRESENT(ThisAttrib) ) { ServerLocType = ThisAttrib->StoreGetType; ServerLoc = ThisAttrib->ADsPath; // remember this path.. SavedAttrib = ThisAttrib; // remember this attrib.. to del later } else { // this attrib is useless, free it if( fExactMatch ) MemFree(ThisAttrib); } if( fExactMatch ) fServerDeleted = TRUE; else fServerExists = TRUE; } } if( !fServerDeleted ) { // never found the requested entry.. MemArrayFree(&Servers, MemFreeFunc); // free up memory return ERROR_DDS_SERVER_DOES_NOT_EXIST; } Err = DhcpDsSetLists // now set the new attrib list ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hDhcpRoot, /* SetParams */ &unused, /* Servers */ &Servers, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescription */ NULL, /* Classes */ NULL ); MemArrayFree(&Servers, MemFreeFunc); // free allocated memory if( ERROR_SUCCESS != Err) { // check err for DhcpDsSetLists if(SavedAttrib) MemFree(SavedAttrib); return Err; } if( fServerExists ) { // still some addr left for this srvr if( SavedAttrib ) MemFree(SavedAttrib); return ERROR_SUCCESS; } if( SavedAttrib ) MemFree(SavedAttrib); return Err; } //BeginExport(function) //DOC DhcpDsDelServer removes the requested servername-ipaddress pair from the ds. //DOC If this is the last ip address for the given servername, then the server //DOC is also removed from memory. But objects referred by the Server are left in //DOC the DS as they may also be referred to from else where. This needs to be //DOC fixed via references being tagged as direct and symbolic -- one causing deletion //DOC and other not causing any deletion. THIS NEEDS TO BE FIXED. DWORD DhcpDsDelServer( // Delete a server from memory IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle IN DWORD Reserved, // must be zero, for future use IN LPWSTR ServerName, // which server to delete for IN LPWSTR ReservedPtr, // server location ? future use IN DWORD IpAddress // the IpAddress to delete.. ) //EndExport(function) { DWORD Err, LastErr, ReturnError; STORE_HANDLE hDhcpServer; ARRAY Servers; BOOL fEmpty; LPWSTR Location; LPWSTR IsDhcpRoot = NULL; MemArrayInit(&Servers); Err = StoreSetSearchOneLevel( hDhcpC, DDS_RESERVED_DWORD ); AssertRet( Err == NO_ERROR, Err ); Err = StoreBeginSearch( hDhcpC, DDS_RESERVED_DWORD, DHCP_SEARCH_FILTER ); AssertRet( Err == NO_ERROR, Err ); // // Look at each dhcp object in container // ReturnError = ERROR_DDS_SERVER_DOES_NOT_EXIST; while( TRUE ) { Err = StoreSearchGetNext( hDhcpC, DDS_RESERVED_DWORD, &hDhcpServer ); if( ERROR_DS_INVALID_DN_SYNTAX == Err ) { // // This nasty problem is because of an upgrade issue // in DS where some bad-named objects may exist.. // Err = NO_ERROR; continue; } if( NO_ERROR != Err ) break; // // Attempt to delete reqd server // Err = DhcpDsDelServerInternal( hDhcpC, &hDhcpServer, Reserved, ServerName, ReservedPtr, IpAddress ); if( ERROR_DDS_SERVER_DOES_NOT_EXIST == Err ) { StoreCleanupHandle( &hDhcpServer, DDS_RESERVED_DWORD ); continue; } if( NO_ERROR != Err ) { StoreCleanupHandle( &hDhcpServer, DDS_RESERVED_DWORD ); break; } ReturnError = NO_ERROR; // // If the above succeeded, then check if the container // has no servers defined -- in this case we can delete // the container itself // Err = DhcpDsGetLists ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ &hDhcpServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ &Servers, // array of PEATTRIB 's /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( NO_ERROR != Err ) { StoreCleanupHandle( &hDhcpServer, DDS_RESERVED_DWORD ); break; } fEmpty = (0 == MemArraySize(&Servers)); MemArrayFree(&Servers, MemFreeFunc); Location = CloneString(hDhcpServer.Location); StoreCleanupHandle( &hDhcpServer, DDS_RESERVED_DWORD ); if( NULL == Location ) { Err = ERROR_NOT_ENOUGH_MEMORY; break; } IsDhcpRoot = wcsstr( Location, DHCP_ROOT_OBJECT_NAME ); if( fEmpty && ( IsDhcpRoot == NULL ) ) Err = StoreDeleteThisObject( hDhcpC, DDS_RESERVED_DWORD, StoreGetAbsoluteOtherServerType, Location ); MemFree( Location ); if( NO_ERROR != Err ) break; } if( Err == ERROR_NO_MORE_ITEMS ) Err = NO_ERROR; LastErr = StoreEndSearch( hDhcpC, DDS_RESERVED_DWORD ); //Require( LastErr == NO_ERROR ); if( NO_ERROR == Err ) Err = ReturnError; return Err; } // DhcpDsDelServer() //BeginExport(function) BOOL DhcpDsLookupServer( // get info about a server IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle IN DWORD Reserved, // must be zero, for future use IN LPWSTR LookupServerIP,// Server to lookup IP IN LPWSTR HostName // Hostname to lookup ) //EndExport(function) { DWORD Err, Err2, Size, Size2, i, N; ARRAY Servers; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; LPDHCPDS_SERVERS LocalServers; LPBYTE Ptr; LPWSTR SearchFilter; STORE_HANDLE hContainer; if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params return FALSE; if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return FALSE; if (( NULL == HostName ) || ( NULL == LookupServerIP )) { return FALSE; } SearchFilter = MakeFilter( LookupServerIP, HostName ); if ( NULL == SearchFilter ) { return FALSE; } DsAuthPrint(( L"hostname = %ws, IP = %ws, Filter = %ws\n", HostName, LookupServerIP, SearchFilter )); Err = StoreSetSearchOneLevel( hDhcpC, DDS_RESERVED_DWORD ); AssertRet( Err == NO_ERROR, Err ); Err = StoreBeginSearch( hDhcpC, DDS_RESERVED_DWORD, SearchFilter ); MemFree( SearchFilter ); AssertRet( Err == NO_ERROR, Err ); Err = StoreSearchGetNext( hDhcpC, DDS_RESERVED_DWORD, &hContainer ); StoreEndSearch( hDhcpC, DDS_RESERVED_DWORD ); return ( NO_ERROR == Err ); } // DhcpDsLookupServer() //BeginExport(function) //DOC DhcpDsEnumServers retrieves a bunch of information about each server that //DOC has an entry in the Servers attribute of the root object. There are no guarantees //DOC on the order.. //DOC The memory for this is allocated in ONE shot -- so the output can be freed in //DOC one shot too. //DOC DWORD DhcpDsEnumServers( // get info abt all existing servers IN OUT LPSTORE_HANDLE hDhcpC, // container for dhcp objects IN OUT LPSTORE_HANDLE hDhcpRoot, // dhcp root object handle IN DWORD Reserved, // must be zero, for future use OUT LPDHCPDS_SERVERS *ServersInfo // array of servers ) //EndExport(function) { DWORD Err, Err2, Size, Size2, i, N; ARRAY Servers; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; LPDHCPDS_SERVERS LocalServers; LPBYTE Ptr; LPWSTR Filter1, Filter2, Filter3; if( NULL == hDhcpRoot || NULL == hDhcpC ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hDhcpRoot->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( 0 != Reserved || NULL == ServersInfo ) return ERROR_INVALID_PARAMETER; *ServersInfo = NULL; i = N = Size = Size2 = 0; Err = MemArrayInit(&Servers); // cant fail //= require ERROR_SUCCESS == Err DsAuthPrint(( L"DhcpDsEnumServers \n" )); Err = GetListOfAllServersMatchingFilter( hDhcpC, &Servers, DHCP_SEARCH_FILTER ); if( ERROR_SUCCESS != Err ) return Err; Size = Size2 = 0; for( // walk thru list of servers Err = MemArrayInitLoc(&Servers, &Loc) // initialize ; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server continue; //= ds inconsistent } Size2 = sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String1)); if( IS_ADSPATH_PRESENT(ThisAttrib) ) { // if ADsPath there, account for it Size2 += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->ADsPath)); } Size += Size2; // keep track of total mem reqd i ++; } Size += ROUND_UP_COUNT(sizeof(DHCPDS_SERVERS), ALIGN_WORST); Size += ROUND_UP_COUNT(sizeof(DHCPDS_SERVER)*i, ALIGN_WORST); Ptr = MemAlloc(Size); // allocate memory if( NULL == Ptr ) { MemArrayFree(&Servers, MemFreeFunc ); // free allocated memory return ERROR_NOT_ENOUGH_MEMORY; } LocalServers = (LPDHCPDS_SERVERS)Ptr; LocalServers->NumElements = i; LocalServers->Flags = 0; Size = 0; // start from offset 0 Size += ROUND_UP_COUNT(sizeof(DHCPDS_SERVERS), ALIGN_WORST); LocalServers->Servers = (LPDHCPDS_SERVER)(Size + Ptr); Size += ROUND_UP_COUNT(sizeof(DHCPDS_SERVER)*i, ALIGN_WORST); i = Size2 = 0; for( // copy list of servers Err = MemArrayInitLoc(&Servers, &Loc) // initialize ; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts Err = MemArrayNextLoc(&Servers, &Loc) // skip to next element ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Servers, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no name for this server !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no address for this server continue; //= ds inconsistent } LocalServers->Servers[i].Version =0; // version is always zero in this build LocalServers->Servers[i].State=0; LocalServers->Servers[i].ServerName = (LPWSTR)(Size + Ptr); wcscpy((LPWSTR)(Size+Ptr), ThisAttrib->String1); Size += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->String1)); LocalServers->Servers[i].ServerAddress = ThisAttrib->Address1; if( IS_FLAGS1_PRESENT(ThisAttrib) ) { // State present LocalServers->Servers[i].Flags = ThisAttrib->Flags1; } else { LocalServers->Servers[i].Flags = 0; // if no flags present, use zero } if( IS_ADSPATH_PRESENT(ThisAttrib) ) { // if ADsPath there, copy it too LocalServers->Servers[i].DsLocType = ThisAttrib->StoreGetType; LocalServers->Servers[i].DsLocation = (LPWSTR)(Size + Ptr); wcscpy((LPWSTR)(Size + Ptr), ThisAttrib->ADsPath); Size += sizeof(WCHAR)*(1 + wcslen(ThisAttrib->ADsPath)); } else { // no ADsPath present LocalServers->Servers[i].DsLocType = 0; LocalServers->Servers[i].DsLocation = NULL; } i ++; } *ServersInfo = LocalServers; MemArrayFree(&Servers, MemFreeFunc ); // free allocated memory return ERROR_SUCCESS; } // DhcpDsEnumServers() //BeginExport(function) //DOC DhcpDsSetSScope modifies the superscope that a subnet belongs to. //DOC The function tries to set the superscope of the subnet referred by //DOC address IpAddress to SScopeName. It does not matter if the superscope //DOC by that name does not exist, it is automatically created. //DOC If the subnet already had a superscope, then the behaviour depends on //DOC the flag ChangeSScope. If this is TRUE, it sets the new superscopes. //DOC If the flag is FALSE, it returns ERROR_DDS_SUBNET_HAS_DIFF_SSCOPE. //DOC This flag is ignored if the subnet does not have a superscope already. //DOC If SScopeName is NULL, the function removes the subnet from any superscope //DOC if it belonged to one before. //DOC If the specified subnet does not exist, it returns ERROR_DDS_SUBNET_NOT_PRESENT. DWORD DhcpDsSetSScope( // change superscope of subnet IN OUT LPSTORE_HANDLE hDhcpC, // container where dhcp objects are stored IN OUT LPSTORE_HANDLE hServer, // the server object referred IN DWORD Reserved, // must be zero, for future use IN DWORD IpAddress, // subnet address to use IN LPWSTR SScopeName, // sscope it must now be in IN BOOL ChangeSScope // if it already has a SScope, change it? ) //EndExport(function) { DWORD Err, unused; ARRAY Subnets; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; BOOL SubnetPresent; if( 0 != Reserved ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hDhcpC || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == hServer || NULL == hServer->ADSIHandle ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // fetch subnet array ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; // shouldn't really fail SubnetPresent = FALSE; for( // search for specified subnet Err = MemArrayInitLoc(&Subnets, &Loc) // init ; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no subnet name !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no subnet address continue; //= ds inconsistent } if( ThisAttrib->Address1 != IpAddress ) { // not this subnet we're looking for continue; } SubnetPresent = TRUE; // found the subnet we're intersted in break; } if( !SubnetPresent ) { // did not even find the subnet? MemArrayFree(&Subnets, MemFreeFunc); // free up memory taken return ERROR_DDS_SUBNET_NOT_PRESENT; } if( NULL == SScopeName ) { // we're trying to remove from sscope if( !IS_STRING3_PRESENT(ThisAttrib) ) { // does not belong to any sscope ? MemArrayFree(&Subnets, MemFreeFunc); return ERROR_SUCCESS; // return as no change reqd } STRING3_ABSENT(ThisAttrib); // remove SScope.. } else { if( IS_STRING3_PRESENT(ThisAttrib) ) { // sscope present.. trying to change it if( FALSE == ChangeSScope ) { // we were not asked to do this MemArrayFree(&Subnets, MemFreeFunc); return ERROR_DDS_SUBNET_HAS_DIFF_SSCOPE; } } STRING3_PRESENT(ThisAttrib); ThisAttrib->String3 = SScopeName; // set the new SScope for this } Err = DhcpDsSetLists // now write back the new info onto the DS ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescripti.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescriptio.. */ NULL, /* Classes */ NULL ); MemArrayFree(&Subnets, MemFreeFunc); return Err; } //BeginExport(function) //DOC DhcpDsDelSScope deletes the superscope and removes all elements //DOC that belong to that superscope in one shot. There is no error if the //DOC superscope does not exist. DWORD DhcpDsDelSScope( // delete superscope off DS IN OUT LPSTORE_HANDLE hDhcpC, // container where dhcp objects are stored IN OUT LPSTORE_HANDLE hServer, // the server object referred IN DWORD Reserved, // must be zero, for future use IN LPWSTR SScopeName // sscope to delete ) //EndExport(function) { DWORD Err, unused; ARRAY Subnets; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; BOOL AnythingChanged; if( 0 != Reserved || NULL == SScopeName ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hDhcpC || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == hServer || NULL == hServer->ADSIHandle ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // fetch subnet array ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; // shouldn't really fail AnythingChanged = FALSE; for( // search for specified SScope Err = MemArrayInitLoc(&Subnets, &Loc) // init ; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no subnet name !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no subnet address continue; //= ds inconsistent } if( !IS_STRING3_PRESENT(ThisAttrib) ) { // this subnet does not have a sscope anyways continue; } if( 0 != wcscmp(ThisAttrib->String3, SScopeName) ) { continue; // not the same superscope } STRING3_ABSENT(ThisAttrib); // kill the superscope AnythingChanged = TRUE; } if( !AnythingChanged ) { Err = ERROR_SUCCESS; // nothing more to do now.. } else { Err = DhcpDsSetLists // now write back the new info onto the DS ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescripti..*/ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescriptio..*/ NULL, /* Classes */ NULL ); } MemArrayFree(&Subnets, MemFreeFunc); return Err; } //BeginExport(function) //DOC DhcpDsGetSScopeInfo retrieves the SuperScope table for the server of interest. //DOC The table itself is allocated in one blob, so it can be freed lateron. //DOC The SuperScopeNumber is garbage (always zero) and the NextInSuperScope reflects //DOC the order in the DS which may/maynot be the same in the DHCP server. //DOC SuperScopeName is NULL in for subnets that done have a sscope. DWORD DhcpDsGetSScopeInfo( // get superscope table from ds IN OUT LPSTORE_HANDLE hDhcpC, // container where dhcp objects are stored IN OUT LPSTORE_HANDLE hServer, // the server object referred IN DWORD Reserved, // must be zero, for future use OUT LPDHCP_SUPER_SCOPE_TABLE *SScopeTbl // allocated by this func in one blob ) //EndExport(function) { DWORD Err, unused, Size, Size2, i; DWORD Index, nSubnets; ARRAY Subnets; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; LPDHCP_SUPER_SCOPE_TABLE LocalTbl; LPBYTE Ptr; if( 0 != Reserved ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hDhcpC || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == hServer || NULL == hServer->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == SScopeTbl ) return ERROR_INVALID_PARAMETER; *SScopeTbl = NULL; Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // fetch subnet array ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; // shouldn't really fail Size = Size2 = i = 0; for( // search for specified SScope Err = MemArrayInitLoc(&Subnets, &Loc) // init ; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no subnet name !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no subnet address continue; //= ds inconsistent } if( IS_STRING3_PRESENT(ThisAttrib) ) { // make space for sscope name Size += sizeof(WCHAR)*(1+wcslen(ThisAttrib->String3)); } i ++; // keep right count of # of subnets } Size += ROUND_UP_COUNT(sizeof(DHCP_SUPER_SCOPE_TABLE),ALIGN_WORST); Size += ROUND_UP_COUNT(i*sizeof(DHCP_SUPER_SCOPE_TABLE_ENTRY), ALIGN_WORST); Ptr = MemAlloc(Size); // allocate the blob if( NULL == Ptr ) { MemArrayFree(&Subnets, MemFreeFunc); return ERROR_NOT_ENOUGH_MEMORY; } LocalTbl = (LPDHCP_SUPER_SCOPE_TABLE)Ptr; Size = ROUND_UP_COUNT(sizeof(DHCP_SUPER_SCOPE_TABLE),ALIGN_WORST); LocalTbl->cEntries = i; if( i ) LocalTbl->pEntries = (LPDHCP_SUPER_SCOPE_TABLE_ENTRY)(Size+Ptr); else LocalTbl->pEntries = NULL; Size += ROUND_UP_COUNT(i*sizeof(DHCP_SUPER_SCOPE_TABLE_ENTRY), ALIGN_WORST); i = 0; for( // search for specified SScope Err = MemArrayInitLoc(&Subnets, &Loc) // init ; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_STRING1_PRESENT(ThisAttrib) || // no subnet name !IS_ADDRESS1_PRESENT(ThisAttrib) ) { // no subnet address continue; //= ds inconsistent } LocalTbl->pEntries[i].SubnetAddress = ThisAttrib->Address1; LocalTbl->pEntries[i].SuperScopeNumber = 0; LocalTbl->pEntries[i].NextInSuperScope = 0; LocalTbl->pEntries[i].SuperScopeName = NULL; if( !IS_STRING3_PRESENT(ThisAttrib) ) { // no sscope, nothin to do i ++; continue; } LocalTbl->pEntries[i].SuperScopeName = (LPWSTR)(Size + Ptr); wcscpy((LPWSTR)(Size+Ptr), ThisAttrib->String3); Size += sizeof(WCHAR)*(1+wcslen(ThisAttrib->String3)); i ++; // keep right count of # of subnets } MemArrayFree(&Subnets, MemFreeFunc); nSubnets = i; for( Index = 0; Index < nSubnets ; Index ++){ // calculate for each Index, next value if( NULL == LocalTbl->pEntries[Index].SuperScopeName) continue; // skip subnets that dont have sscope LocalTbl->pEntries[Index].NextInSuperScope = Index; for( i = 0; i < Index ; i ++ ) { // first set it to just prev subnet if( NULL == LocalTbl->pEntries[i].SuperScopeName) continue; if( 0 == wcscmp( LocalTbl->pEntries[Index].SuperScopeName, LocalTbl->pEntries[i].SuperScopeName) ) { // both subnets have same superscope LocalTbl->pEntries[Index].NextInSuperScope = i; // set next as last match in array before position Index } } for( i = Index + 1; i < nSubnets; i ++ ) {// check to see if any real next exists if( NULL == LocalTbl->pEntries[i].SuperScopeName) continue; if( 0 == wcscmp( LocalTbl->pEntries[Index].SuperScopeName, LocalTbl->pEntries[i].SuperScopeName) ) { // both subnets have same superscope LocalTbl->pEntries[Index].NextInSuperScope = i; break; } } } *SScopeTbl = LocalTbl; // done. return ERROR_SUCCESS; } //BeginExport(function) //DOC DhcpDsServerAddSubnet tries to add a subnet to a given server. Each subnet //DOC address has to be unique, but the other parameters dont have to. //DOC The subnet address being added should not belong to any other subnet. //DOC In this case it returns error ERROR_DDS_SUBNET_EXISTS DWORD DhcpDsServerAddSubnet( // create a new subnet IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN LPDHCP_SUBNET_INFO Info // info on new subnet to create ) //EndExport(function) { DWORD Err, Err2, unused, i; DWORD Index, nSubnets; ARRAY Subnets; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; EATTRIB Dummy; LPWSTR SubnetObjName; if( 0 != Reserved ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hDhcpC || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == hServer || NULL == hServer->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == Info || NULL == ServerName ) return ERROR_INVALID_PARAMETER; if( Info->SubnetAddress != (Info->SubnetAddress & Info->SubnetMask ) ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // fetch subnet array ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; // shouldn't really fail for( // search for specified SScope Err = MemArrayInitLoc(&Subnets, &Loc) // init ; ERROR_FILE_NOT_FOUND != Err ; // 'til v run out of elts Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next elt ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address !IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask continue; //= ds inconsistent } if( (Info->SubnetAddress & ThisAttrib->Address2 ) == ThisAttrib->Address1 ) { return ERROR_DDS_SUBNET_EXISTS; // Info belongs to this subnet } if( Info->SubnetAddress == (ThisAttrib->Address1 & Info->SubnetMask) ) { return ERROR_DDS_SUBNET_EXISTS; // Info subsumes some other subnet } } SubnetObjName = MakeSubnetLocation(ServerName, Info->SubnetAddress); if( NULL == SubnetObjName ) { // not enough memory? MemArrayFree(&Subnets, MemFreeFunc); return ERROR_NOT_ENOUGH_MEMORY; } Err = CreateSubnetObject // try creating the subnet obj 1st ( /* hDhcpC */ hDhcpC, // create obj here.. /* SubnetName */ SubnetObjName ); if( ERROR_SUCCESS != Err ) { // could not create obj, dont proceed MemArrayFree(&Subnets, MemFreeFunc); MemFree(SubnetObjName); return Err; } NothingPresent(&Dummy); // prepare info for new subnet ADDRESS1_PRESENT(&Dummy); // subnet address Dummy.Address1 = Info->SubnetAddress; ADDRESS2_PRESENT(&Dummy); // subnet mask Dummy.Address2 = Info->SubnetMask; FLAGS1_PRESENT(&Dummy); // subnet state Dummy.Flags1 = Info->SubnetState; if( Info->SubnetName ) { // subnet name STRING1_PRESENT(&Dummy); Dummy.String1 = Info->SubnetName; } if( Info->SubnetComment ) { // subnet comment STRING2_PRESENT(&Dummy); Dummy.String2 = Info->SubnetComment; } ADSPATH_PRESENT(&Dummy); // subnet obj location STOREGETTYPE_PRESENT(&Dummy); Dummy.ADsPath = SubnetObjName; Dummy.StoreGetType = StoreGetChildType; Err = MemArrayAddElement(&Subnets, &Dummy); // add new attrib at end if( ERROR_SUCCESS != Err ) { // add failed for some reason MemFree(SubnetObjName); MemArrayFree(&Subnets, MemFreeFunc); // cleanup any mem used return Err; } Err = DhcpDsSetLists // write back new info onto DS ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescripti.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescriptio.. */ NULL, /* Classes */ NULL ); MemFree(SubnetObjName); Err2 = MemArrayLastLoc(&Subnets, &Loc); //= require ERROR_SUCCESS == Err Err2 = MemArrayDelElement(&Subnets, &Loc, &ThisAttrib); MemArrayFree(&Subnets, MemFreeFunc); return Err; } //BeginExport(function) //DOC DhcpDsServerDelSubnet removes a subnet from a given server. It removes not //DOC just the subnet, but also all dependent objects like reservations etc. //DOC This fn returns ERROR_DDS_SUBNET_NOT_PRESENT if the subnet is not found. DWORD DhcpDsServerDelSubnet( // Delete the subnet IN OUT LPSTORE_HANDLE hDhcpC, // root container to create obj IN LPSTORE_HANDLE hServer, // server obj IN DWORD Reserved, // for future use, must be zero IN LPWSTR ServerName, // name of dhcp server 2 del off IN DWORD IpAddress // ip address of subnet to del ) //EndExport(function) { DWORD Err, Err2, unused; ARRAY Subnets; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; BOOL fSubnetExists; BOOL fSubnetDeleted; LPWSTR SubnetCNName; LPWSTR SubnetLoc; DWORD SubnetLocType; if( NULL == hServer || NULL == hDhcpC ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of subnets ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ &Subnets, // array of PEATTRIB 's /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; fSubnetExists = fSubnetDeleted = FALSE; for( // search list of subnets Err = MemArrayInitLoc(&Subnets, &Loc) // initialize ; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next element ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address !IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask continue; //= ds inconsistent } if( ThisAttrib->Address1 == IpAddress ) { // matching address? fSubnetExists = TRUE; Err2 = MemArrayDelElement(&Subnets, &Loc, &ThisAttrib); //= ERROR_SUCCESS == Err2 && NULL != ThisAttrib break; } } if( !fSubnetExists ) { // no matching subnet found MemArrayFree(&Subnets, MemFreeFunc); return ERROR_DDS_SUBNET_NOT_PRESENT; } Err = DhcpDsSetLists // now set the new attrib list ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescription */ NULL, /* Classes */ NULL ); MemArrayFree(&Subnets, MemFreeFunc); // free allocated memory if( ERROR_SUCCESS != Err) { // check err for DhcpDsSetLists MemFree(ThisAttrib); return Err; } if( IS_ADSPATH_PRESENT(ThisAttrib) ) { // remember the location to delete SubnetLocType = ThisAttrib->StoreGetType; SubnetLoc = ThisAttrib->ADsPath; } else { SubnetLoc = NULL; } if( NULL == SubnetLoc ) { // Dont know location SubnetCNName = MakeSubnetLocation(ServerName,IpAddress); SubnetLoc = SubnetCNName; // set name for subnet obj SubnetLocType = StoreGetChildType; // assume located in DhcpC container } else { SubnetCNName = NULL; // Did not allocate subnet name } if( NULL == SubnetLoc ) { // MakeSubnetLocation failed Err = ERROR_NOT_ENOUGH_MEMORY; } else { // lets try to delete the subnet Err = ServerDeleteSubnet // delete the dhcp subnet object ( /* hDhcpC */ hDhcpC, /* ServerName */ ServerName, /* hServer */ hServer, /* ADsPath */ SubnetLoc, /* StoreGetType */ SubnetLocType ); } if( SubnetCNName ) MemFree(SubnetCNName); // if we allocated mem, free it MemFree(ThisAttrib); // lonely attrib needs to be freed return Err; } //BeginExport(function) //DOC DhcpDsServerModifySubnet changes the subnet name, comment, state, mask //DOC fields of the subnet. Actually, currently, the mask should probably not //DOC be changed, as no checks are performed in this case. The address cannot //DOC be changed.. If the subnet is not present, the error returned is //DOC ERROR_DDS_SUBNET_NOT_PRESENT DWORD DhcpDsServerModifySubnet( // modify subnet info IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN LPDHCP_SUBNET_INFO Info // info on new subnet to create ) //EndExport(function) { DWORD Err, Err2, unused; ARRAY Subnets; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; BOOL fSubnetExists, fSubnetDeleted; if( NULL == hDhcpC ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; if( NULL == Info ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of subnets ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ &Subnets, // array of PEATTRIB 's /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; fSubnetExists = fSubnetDeleted = FALSE; for( // search list of subnets Err = MemArrayInitLoc(&Subnets, &Loc) // initialize ; ERROR_FILE_NOT_FOUND != Err ; // until we run out of elts Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next element ) { //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address !IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask continue; //= ds inconsistent } if( ThisAttrib->Address1 == Info->SubnetAddress ) { fSubnetExists = TRUE; // matching address? break; } } if( !fSubnetExists ) { // no matching subnet found MemArrayFree(&Subnets, MemFreeFunc); return ERROR_DDS_SUBNET_NOT_PRESENT; } ThisAttrib->Address2 = Info->SubnetMask; // alter information FLAGS1_PRESENT(ThisAttrib); ThisAttrib->Flags1 = Info->SubnetState; if( NULL == Info->SubnetName ) { STRING1_ABSENT(ThisAttrib); } else { STRING1_PRESENT(ThisAttrib); ThisAttrib->String1 = Info->SubnetName; } if( NULL == Info->SubnetComment ) { STRING2_ABSENT(ThisAttrib); } else { STRING2_PRESENT(ThisAttrib); ThisAttrib->String2 = Info->SubnetComment; } Err = DhcpDsSetLists // now set the new attrib list ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ &Subnets, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescription */ NULL, /* Classes */ NULL ); MemArrayFree(&Subnets, MemFreeFunc); // free allocated memory return Err; } //BeginExport(function) //DOC DhcpDsServerEnumSubnets is not yet implemented. DWORD DhcpDsServerEnumSubnets( // get subnet list IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using OUT LPDHCP_IP_ARRAY *SubnetsArray // give array of subnets ) //EndExport(function) { LPDHCP_IP_ARRAY LocalSubnetArray; DWORD Err, Err2, unused, Size; ARRAY Subnets; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; if( NULL == hDhcpC ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; if( NULL == SubnetsArray ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of subnets ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ &Subnets, // array of PEATTRIB 's /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; LocalSubnetArray = MemAlloc(sizeof(DHCP_IP_ARRAY)); if( NULL == LocalSubnetArray ) { MemArrayFree(&Subnets, MemFreeFunc); return ERROR_NOT_ENOUGH_MEMORY; } LocalSubnetArray->NumElements = 0; LocalSubnetArray->Elements = NULL; Size = sizeof(DHCP_IP_ADDRESS)*MemArraySize(&Subnets); if( Size ) LocalSubnetArray->Elements = MemAlloc(Size); for( // accumulate the subnets Err = MemArrayInitLoc(&Subnets, &Loc) // for each subnet ; ERROR_FILE_NOT_FOUND != Err ; // until there are no more Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next ) { Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address !IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask continue; //= ds inconsistent } LocalSubnetArray->Elements[LocalSubnetArray->NumElements++] = ThisAttrib->Address1; } MemArrayFree(&Subnets, MemFreeFunc); *SubnetsArray = LocalSubnetArray; return ERROR_SUCCESS; } //BeginExport(function) //DOC DhcpDsServerGetSubnetInfo is not yet implemented. DWORD DhcpDsServerGetSubnetInfo( // get info on subnet IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN DHCP_IP_ADDRESS SubnetAddress, // address of subnet to get info for OUT LPDHCP_SUBNET_INFO *SubnetInfo // o/p: allocated info ) //EndExport(function) { DWORD Err, Err2, unused; ARRAY Subnets; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; LPDHCP_SUBNET_INFO Info; BOOL fSubnetExists; if( NULL == hDhcpC ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; if( NULL == SubnetInfo ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Subnets); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of subnets ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hServer, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ &Subnets, // array of PEATTRIB 's /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; fSubnetExists = FALSE; for( // accumulate the subnets Err = MemArrayInitLoc(&Subnets, &Loc) // for each subnet ; ERROR_FILE_NOT_FOUND != Err ; // until there are no more Err = MemArrayNextLoc(&Subnets, &Loc) // skip to next ) { Err = MemArrayGetElement(&Subnets, &Loc, &ThisAttrib); if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address !IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask continue; //= ds inconsistent } if( ThisAttrib->Address1 == SubnetAddress ) { fSubnetExists = TRUE; // found the required subnet break; } } if( !fSubnetExists ) { // no subnet matching address MemArrayFree(&Subnets, MemFreeFunc); return ERROR_DDS_SUBNET_NOT_PRESENT; } Info = MemAlloc(sizeof(LPDHCP_SUBNET_INFO)); if( NULL == Info) { MemArrayFree(&Subnets, MemFreeFunc); return ERROR_NOT_ENOUGH_MEMORY; } Info->SubnetAddress = ThisAttrib->Address1; // subnet address Info->SubnetMask = ThisAttrib->Address2; // subnet mask if( !IS_STRING1_PRESENT(ThisAttrib) ) { // subnet name? Info->SubnetName = NULL; } else { Info->SubnetName = MemAlloc(sizeof(WCHAR) * (1+wcslen(ThisAttrib->String1))); if( NULL != Info->SubnetName ) { wcscpy(Info->SubnetName, ThisAttrib->String1); } } if( !IS_STRING2_PRESENT(ThisAttrib) ) { // subnet comment? Info->SubnetComment = NULL; // no subnet comment } else { Info->SubnetComment = MemAlloc(sizeof(WCHAR) * (1+wcslen(ThisAttrib->String2))); if( NULL != Info->SubnetComment ) { wcscpy(Info->SubnetComment, ThisAttrib->String2); } } if( !IS_FLAGS1_PRESENT(ThisAttrib) ) { // subnet state information Info->SubnetState = DhcpSubnetEnabled; } else { Info->SubnetState = ThisAttrib->Flags1; } MemArrayFree(&Subnets, MemFreeFunc); // clear up memory *SubnetInfo = Info; Info->PrimaryHost.IpAddress = 0; // : unsupported fields.. Info->PrimaryHost.NetBiosName = NULL; Info->PrimaryHost.HostName = NULL; return ERROR_SUCCESS; } //BeginExport(function) //DOC DhcpDsSubnetAddRangeOrExcl adds a range/excl to an existing subnet. //DOC If there is a collision with between ranges, then the error code returned //DOC is ERROR_DDS_POSSIBLE_RANGE_CONFLICT. Note that no checks are made for //DOC exclusions though. Also, if a RANGE is extended via this routine, then //DOC there is no error returned, but a limitation currently is that multiple //DOC ranges (two only right) cannot be simultaneously extended. //DOC BUBGUG: The basic check of whether the range belongs in the subnet is //DOC not done.. DWORD DhcpDsSubnetAddRangeOrExcl( // add a range or exclusion IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN OUT LPSTORE_HANDLE hSubnet, // subnet object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN DWORD Start, // start addr in range IN DWORD End, // end addr in range IN BOOL RangeOrExcl // TRUE ==> Range,FALSE ==> Excl ) //EndExport(function) { DWORD Err, Err2, Type, unused; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; EATTRIB Dummy; ARRAY Ranges; if( NULL == hDhcpC || NULL == hServer ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == hSubnet || NULL == hSubnet->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; if( Start > End ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Ranges); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of ranges frm ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ &Ranges, // array of PEATTRIB 's /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; Type = (RangeOrExcl? RANGE_TYPE_RANGE: RANGE_TYPE_EXCL); ThisAttrib = NULL; if( FindCollisions(&Ranges,Start,End,Type, &ThisAttrib) ) { MemArrayFree(&Ranges, MemFreeFunc); return ERROR_DDS_POSSIBLE_RANGE_CONFLICT; // hit a range conflict! } if( NULL != ThisAttrib ) { // this is a collision case if( Start == ThisAttrib->Address2 ) { // this is the collapse point ThisAttrib->Address2 = End; } else { ThisAttrib->Address1 = Start; } } else { // not a collision NothingPresent(&Dummy); // create a new range ADDRESS1_PRESENT(&Dummy); // range start Dummy.Address1 = Start; ADDRESS2_PRESENT(&Dummy); // range end Dummy.Address2 = End; FLAGS1_PRESENT(&Dummy); Dummy.Flags1 = 0; FLAGS2_PRESENT(&Dummy); // range type or excl type? Dummy.Flags2 = Type; Err = MemArrayAddElement(&Ranges, &Dummy); if( ERROR_SUCCESS != Err ) { // could not create new lists MemArrayFree(&Ranges, MemFreeFunc); return Err; } } Err = DhcpDsSetLists // write back new list to ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ &Ranges, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescription */ NULL, /* Classes */ NULL ); if( NULL == ThisAttrib ) { // in case we added the new range Err2 = MemArrayLastLoc(&Ranges, &Loc); // try to delete frm mem the new elt Err2 = MemArrayDelElement(&Ranges, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && ThisAttrib == &Dummy } MemArrayFree(&Ranges, MemFreeFunc); return Err; // DhcpDsSetLists's ret code } //BeginExport(function) //DOC DhcpDsSubnetDelRangeOrExcl deletes a range or exclusion from off the ds. //DOC To specify range, set the RangeOrExcl parameter to TRUE. DWORD DhcpDsSubnetDelRangeOrExcl( // del a range or exclusion IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN OUT LPSTORE_HANDLE hSubnet, // subnet object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN DWORD Start, // start addr in range IN DWORD End, // end addr in range IN BOOL RangeOrExcl // TRUE ==> Range,FALSE ==> Excl ) //EndExport(function) { DWORD Err, Err2, Type, ThisType, unused; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; ARRAY Ranges; BOOL Changed; if( NULL == hDhcpC || NULL == hServer ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == hSubnet || NULL == hSubnet->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; if( Start > End ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Ranges); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of ranges frm ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ &Ranges, // array of PEATTRIB 's /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; Type = (RangeOrExcl? RANGE_TYPE_RANGE: RANGE_TYPE_EXCL); Changed = FALSE; for( // look for matching range/excl Err = MemArrayInitLoc(&Ranges, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Ranges, &Loc) ) { Err = MemArrayGetElement(&Ranges, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address !IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask continue; //= ds inconsistent } if( !IS_FLAGS2_PRESENT(ThisAttrib) ) { // this is a RANGE_TYPE_RANGE ThisType = RANGE_TYPE_RANGE; } else ThisType = ThisAttrib->Flags2; if( Start != ThisAttrib->Address1 || End != ThisAttrib->Address2 ) { // range mismatch continue; } if(Type != ThisType ) { // looking for x, bug this is !x. continue; } Err2 = MemArrayDelElement(&Ranges, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib MemFreeFunc(ThisAttrib); Changed = TRUE; } if( !Changed ) { // nothing found ni registry Err = ERROR_DDS_RANGE_DOES_NOT_EXIST; } else { Err = DhcpDsSetLists // write back new list to ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ &Ranges, /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescription */ NULL, /* Classes */ NULL ); } MemArrayFree(&Ranges, MemFreeFunc); return Err; // DhcpDsSetLists's ret code } DWORD ConvertAttribToRanges( // convert from array of attribs .. IN DWORD nRanges, // # of ranges, IN PARRAY Ranges, // input array of attribs IN ULONG Type, // TYPE_RANGE_TYPE or TYPE_EXCLUSION_TYPE? OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *pRanges //output array.. ) { DWORD Err; ULONG Count, ThisType; PEATTRIB ThisAttrib; LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 localRanges; ARRAY_LOCATION Loc; DHCP_IP_RANGE *ThisRange; localRanges = MemAlloc(sizeof(DHCP_SUBNET_ELEMENT_INFO_ARRAY_V4)); *pRanges = localRanges; if( NULL == localRanges ) return ERROR_NOT_ENOUGH_MEMORY; if( 0 == nRanges ) { localRanges->NumElements = 0; localRanges->Elements = NULL; return ERROR_SUCCESS; } localRanges->Elements = MemAlloc(nRanges*sizeof(DHCP_SUBNET_ELEMENT_DATA_V4)); if( NULL == localRanges->Elements ) { MemFree(localRanges); *pRanges = NULL; return ERROR_NOT_ENOUGH_MEMORY; } localRanges->NumElements = nRanges; for( Count = 0 ; Count < nRanges ; Count ++ ) { localRanges->Elements[Count].Element.IpRange = localRanges->Elements[Count].Element.ExcludeIpRange = ThisRange = MemAlloc(sizeof(DHCP_IP_RANGE)); if( NULL == ThisRange ) { // oops could not allocate ? free everything and bail! while( Count != 0 ) { // remember Count is unsigned .. Count --; MemFree(localRanges->Elements[Count].Element.IpRange); } MemFree(localRanges->Elements); MemFree(localRanges); *pRanges = NULL; return ERROR_NOT_ENOUGH_MEMORY; } } Count = 0; for( // look for matching range/excl Err = MemArrayInitLoc(Ranges, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(Ranges, &Loc) ) { Err = MemArrayGetElement(Ranges, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address !IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask continue; //= ds inconsistent } if( !IS_FLAGS2_PRESENT(ThisAttrib) ) { // this is a RANGE_TYPE_RANGE ThisType = RANGE_TYPE_RANGE; } else ThisType = ThisAttrib->Flags2; if(Type != ThisType ) { // looking for x, bug this is !x. continue; } //= require ThisAttrib->Address1 < ThisAttrib->Address2 if( RANGE_TYPE_RANGE == Type ) { localRanges->Elements[Count].ElementType = DhcpIpRanges ; localRanges->Elements[Count].Element.IpRange->StartAddress = ThisAttrib->Address1; localRanges->Elements[Count].Element.IpRange->EndAddress = ThisAttrib->Address2; } else { localRanges->Elements[Count].ElementType = DhcpExcludedIpRanges; localRanges->Elements[Count].Element.ExcludeIpRange->StartAddress = ThisAttrib->Address1; localRanges->Elements[Count].Element.ExcludeIpRange->EndAddress = ThisAttrib->Address2; } Count ++; } return ERROR_SUCCESS; } //BeginExport(function) //DOC DhcpDsEnumRangesOrExcl is not yet implemented. DWORD DhcpDsEnumRangesOrExcl( // enum list of ranges 'n excl IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN OUT LPSTORE_HANDLE hSubnet, // subnet object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN BOOL RangeOrExcl, // TRUE ==> Range, FALSE ==> Excl OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *pRanges ) //EndExport(function) { DWORD Err, Err2, Type, ThisType, unused; DWORD Count; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; ARRAY Ranges; if( NULL == hDhcpC || NULL == hServer ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == hSubnet || NULL == hSubnet->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Ranges); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of ranges frm ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ &Ranges, // array of PEATTRIB 's /* Sites */ NULL, /* Reservations */ NULL, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; Type = (RangeOrExcl? RANGE_TYPE_RANGE: RANGE_TYPE_EXCL); Count = 0; for( // look for matching range/excl Err = MemArrayInitLoc(&Ranges, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Ranges, &Loc) ) { Err = MemArrayGetElement(&Ranges, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no subnet address !IS_ADDRESS2_PRESENT(ThisAttrib) ) { // no subnet mask continue; //= ds inconsistent } if( !IS_FLAGS2_PRESENT(ThisAttrib) ) { // this is a RANGE_TYPE_RANGE ThisType = RANGE_TYPE_RANGE; } else ThisType = ThisAttrib->Flags2; if(Type != ThisType ) { // looking for x, bug this is !x. continue; } Count ++; } Err = ConvertAttribToRanges(Count, &Ranges, Type, pRanges); MemArrayFree(&Ranges, MemFreeFunc); return Err; } //BeginExport(function) //DOC DhcpDsSubnetAddReservation tries to add a reservation object in the DS. //DOC Neither the ip address not hte hw-address must exist in the DS prior to this. //DOC If they do exist, the error returned is ERROR_DDS_RESERVATION_CONFLICT. //DOC No checks are made on the sanity of the address in this subnet.. DWORD DhcpDsSubnetAddReservation( // add a reservation IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN OUT LPSTORE_HANDLE hSubnet, // subnet object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN DWORD ReservedAddr, // reservation ip address to add IN LPBYTE HwAddr, // RAW [ethernet?] hw addr of the client IN DWORD HwAddrLen, // length in # of bytes of hw addr IN DWORD ClientType // client is BOOTP, DHCP, or both? ) //EndExport(function) { DWORD Err, Err2, Type, ClientUIDSize, unused; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; EATTRIB Dummy; ARRAY Reservations; LPBYTE ClientUID; LPWSTR ReservationCNName; if( NULL == hDhcpC || NULL == hServer ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; if( NULL == HwAddr || 0 == HwAddrLen ) return ERROR_INVALID_PARAMETER; ClientUID = NULL; Err = DhcpMakeClientUID( HwAddr, HwAddrLen, HARDWARE_TYPE_10MB_EITHERNET, ReservedAddr, &ClientUID, &ClientUIDSize ); if( ERROR_SUCCESS != Err ) { // should not happen return Err; } Err = MemArrayInit(&Reservations); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of ranges frm ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ &Reservations, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) { MemFree(ClientUID); return Err; } for( // search for existing reservation Err = MemArrayInitLoc(&Reservations, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Reservations, &Loc) ) { BOOL Mismatch; //= require ERROR_SUCCESS == Err Err = MemArrayGetElement(&Reservations, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) // no address for reservations || !IS_BINARY1_PRESENT(ThisAttrib) // no hw len specified || !IS_FLAGS1_PRESENT(ThisAttrib) ) { // no client type present continue; //= ds inconsistent } Mismatch = FALSE; if( ThisAttrib->Address1 == ReservedAddr ) { Mismatch = TRUE; // address already reserved } if( ThisAttrib->BinLen1 == ClientUIDSize // see if hw address matches && 0 == memcmp(ThisAttrib->Binary1, ClientUID, ClientUIDSize) ) { Mismatch = TRUE; } if( Mismatch ) { // ip addr or hw-addr in use MemArrayFree(&Reservations, MemFreeFunc); MemFree(ClientUID); return ERROR_DDS_RESERVATION_CONFLICT; } } ReservationCNName = MakeReservationLocation(ServerName, ReservedAddr); if( NULL == ReservationCNName ) { // not enough mem to create string Err = ERROR_NOT_ENOUGH_MEMORY; } else { Err = CreateReservationObject // create the new reservation object ( /* hDhcpC */ hDhcpC, // container to create obj in /* ReserveCNName */ ReservationCNName ); } if( ERROR_SUCCESS != Err ) { // could not create reservation object MemArrayFree(&Reservations, MemFreeFunc); MemFree(ClientUID); return Err; } NothingPresent(&Dummy); // create a new reservation ADDRESS1_PRESENT(&Dummy); // ip address Dummy.Address1 = ReservedAddr; FLAGS1_PRESENT(&Dummy); // client type Dummy.Flags1 = ClientType; BINARY1_PRESENT(&Dummy); // client uid Dummy.BinLen1 = ClientUIDSize; Dummy.Binary1 = ClientUID; STOREGETTYPE_PRESENT(&Dummy); // relative location for reservation obj ADSPATH_PRESENT(&Dummy); Dummy.StoreGetType = StoreGetChildType; Dummy.ADsPath = ReservationCNName; Err = MemArrayAddElement(&Reservations,&Dummy); if( ERROR_SUCCESS != Err ) { // oops, cannot add reservation MemArrayFree(&Reservations, MemFreeFunc); MemFree(ClientUID); MemFree(ReservationCNName); return Err; } Err = DhcpDsSetLists // write back new list to ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ &Reservations, /* SuperScopes */ NULL, /* OptionDescription.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescription */ NULL, /* Classes */ NULL ); Err2 = MemArrayLastLoc(&Reservations, &Loc); // try to delete frm mem the new elt Err2 = MemArrayDelElement(&Reservations, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && ThisAttrib == &Dummy MemArrayFree(&Reservations, MemFreeFunc); MemFree(ClientUID); MemFree(ReservationCNName); return Err; // DhcpDsSetLists's ret code } //BeginExport(function) //DOC DhcpDsSubnetDelReservation deletes a reservation from the DS. //DOC If the reservation does not exist, it returns ERROR_DDS_RESERVATION_NOT_PRESENT. //DOC Reservations cannot be deleted by anything but ip address for now. DWORD DhcpDsSubnetDelReservation( // delete a reservation IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN OUT LPSTORE_HANDLE hSubnet, // subnet object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN DWORD ReservedAddr // ip address to delete reserv. by ) //EndExport(function) { DWORD Err, Err2, Type, ThisType, unused; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; ARRAY Reservations; BOOL ReservationExists; LPWSTR ReservationLocPath, ReservationCNName; DWORD ReservationLocType; if( NULL == hDhcpC || NULL == hServer ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Reservations); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of ranges frm ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ &Reservations, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; ReservationExists = FALSE; for( // look for matching range/excl Err = MemArrayInitLoc(&Reservations, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Reservations, &Loc) ) { Err = MemArrayGetElement(&Reservations, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no reservation address !IS_BINARY1_PRESENT(ThisAttrib) ) { // no hw addr specified continue; //= ds inconsistent } if( ThisAttrib->Address1 != ReservedAddr ) { continue; // not this reservation } ReservationExists = TRUE; Err2 = MemArrayDelElement(&Reservations, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib break; } if( !ReservationExists ) { // no matching reservation found MemArrayFree(&Reservations, MemFreeFunc); return ERROR_DDS_RESERVATION_NOT_PRESENT; } Err = DhcpDsSetLists // write back new list to ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* SetParams */ &unused, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ &Reservations, /* SuperScopes */ NULL, /* OptionDescription.. */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* ClassDescription */ NULL, /* Classes */ NULL ); MemArrayFree(&Reservations, MemFreeFunc); if( ERROR_SUCCESS != Err ) { MemFree(ThisAttrib); return Err; } if( IS_ADSPATH_PRESENT(ThisAttrib) ) { // deleted reservation's location in ds ReservationLocType = ThisAttrib->StoreGetType; ReservationLocPath = ThisAttrib->ADsPath; } else { ReservationLocPath = NULL; } if( NULL == ReservationLocPath ) { // no path present, but guess it anyways ReservationCNName = MakeReservationLocation(ServerName,ReservedAddr); ReservationLocPath = ReservationCNName; // same name that is used generally ReservationLocType = StoreGetChildType; // child object } else { ReservationCNName = NULL; // NULL indicating no alloc } if( NULL == ReservationLocPath ) { // dont know what to delete.. Err = ERROR_NOT_ENOUGH_MEMORY; // MakeReservationLocation failed } else { // try to delete subnet object Err = SubnetDeleteReservation // actual delete in ds ( /* hDhcpC */ hDhcpC, /* ServerName */ ServerName, /* hServer */ hServer, /* hSubnet */ hSubnet, /* ADsPath */ ReservationLocPath, /* StoreGetType */ ReservationLocType ); } if( ReservationCNName ) MemFree(ReservationCNName); MemFree(ThisAttrib); // free all ptrs left.. return Err; } LPBYTE _inline DupeBytes( // allocate mem and copy bytes IN LPBYTE Data, IN ULONG DataLen ) { LPBYTE NewData; if( 0 == DataLen ) return NULL; NewData = MemAlloc(DataLen); if( NULL != NewData ) { memcpy(NewData, Data, DataLen); } return NewData; } DWORD ConvertAttribToReservations( // convert from arry of attribs .. IN DWORD nRes, // # of reservatiosn to convert IN PARRAY Res, // the actual array of reservations OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *pResInfo ) { LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 localRes; DWORD Err, Count; LPWSTR ReservationLocPath, ReservationCNName; DWORD ReservationLocType; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; ARRAY Reservations; LPDHCP_IP_RESERVATION_V4 ThisRes; LPVOID Data; localRes = MemAlloc(sizeof(DHCP_SUBNET_ELEMENT_INFO_ARRAY_V4)); *pResInfo = localRes; if( NULL == localRes ) return ERROR_NOT_ENOUGH_MEMORY; if( 0 == nRes ) { localRes->NumElements = 0; localRes->Elements = NULL; return ERROR_SUCCESS; } localRes->Elements = MemAlloc(nRes*sizeof(DHCP_SUBNET_ELEMENT_DATA_V4)); if( NULL == localRes->Elements ) { MemFree(localRes); *pResInfo = NULL; return ERROR_NOT_ENOUGH_MEMORY; } localRes->NumElements = nRes; for( Count = 0 ; Count < nRes ; Count ++ ) { localRes->Elements[Count].Element.ReservedIp = ThisRes = MemAlloc(sizeof(DHCP_IP_RESERVATION_V4)); if( NULL != ThisRes ) { // successfull allocation.. ThisRes->ReservedForClient = MemAlloc(sizeof(DHCP_CLIENT_UID)); if( NULL == ThisRes->ReservedForClient) { MemFree(ThisRes); // duh it failed here.. ThisRes = NULL; // fake an upper level fail } } if( NULL == ThisRes ) { // oops could not allocate ? free everything and bail! while( Count != 0 ) { // remember Count is unsigned .. Count --; MemFree(localRes->Elements[Count].Element.ReservedIp->ReservedForClient); MemFree(localRes->Elements[Count].Element.ReservedIp); } MemFree(localRes->Elements); MemFree(localRes); *pResInfo = NULL; return ERROR_NOT_ENOUGH_MEMORY; } } Count = 0; for( // look for matching range/excl Err = MemArrayInitLoc(Res, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(Res, &Loc) ) { Err = MemArrayGetElement(Res, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no reservation address !IS_BINARY1_PRESENT(ThisAttrib) ) { // no hw addr specified continue; //= ds inconsistent } localRes->Elements[Count].ElementType = DhcpReservedIps; if( IS_FLAGS1_PRESENT(ThisAttrib) ) { localRes->Elements[Count].Element.ReservedIp->bAllowedClientTypes = (BYTE)ThisAttrib->Flags1; } else { localRes->Elements[Count].Element.ReservedIp->bAllowedClientTypes = 0; } localRes->Elements[Count].Element.ReservedIp->ReservedIpAddress = ThisAttrib->Address1; localRes->Elements[Count].Element.ReservedIp->ReservedForClient->Data = Data = DupeBytes(ThisAttrib->Binary1, ThisAttrib->BinLen1); if( NULL == Data ) { // could not allocate memory.. localRes->Elements[Count].Element.ReservedIp->ReservedForClient->DataLength = 0; } else { localRes->Elements[Count].Element.ReservedIp->ReservedForClient->DataLength = ThisAttrib->BinLen1; } Count++; } return ERROR_SUCCESS; } //BeginExport(function) //DOC DhcpDsEnumReservations enumerates the reservations.. DWORD DhcpDsEnumReservations( // enumerate reservations frm DS IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN OUT LPSTORE_HANDLE hSubnet, // subnet object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *pReservations ) //EndExport(function) { DWORD Err, Err2, Type, ThisType, unused; DWORD Count; ARRAY_LOCATION Loc; PEATTRIB ThisAttrib; ARRAY Reservations; if( NULL == hDhcpC || NULL == hServer ) // check params return ERROR_INVALID_PARAMETER; if( NULL == hServer->ADSIHandle || NULL == hDhcpC->ADSIHandle ) return ERROR_INVALID_PARAMETER; if( NULL == ServerName || 0 != Reserved ) return ERROR_INVALID_PARAMETER; Err = MemArrayInit(&Reservations); //= require ERROR_SUCCESS == Err Err = DhcpDsGetLists // get list of ranges frm ds ( /* Reserved */ DDS_RESERVED_DWORD, /* hStore */ hSubnet, /* RecursionDepth */ 0xFFFFFFFF, /* Servers */ NULL, /* Subnets */ NULL, /* IpAddress */ NULL, /* Mask */ NULL, /* Ranges */ NULL, /* Sites */ NULL, /* Reservations */ &Reservations, /* SuperScopes */ NULL, /* OptionDescription */ NULL, /* OptionsLocation */ NULL, /* Options */ NULL, /* Classes */ NULL ); if( ERROR_SUCCESS != Err ) return Err; Count = 0; for( // look for matching range/excl Err = MemArrayInitLoc(&Reservations, &Loc) ; ERROR_FILE_NOT_FOUND != Err ; Err = MemArrayNextLoc(&Reservations, &Loc) ) { Err = MemArrayGetElement(&Reservations, &Loc, &ThisAttrib); //= require ERROR_SUCCESS == Err && NULL != ThisAttrib if( !IS_ADDRESS1_PRESENT(ThisAttrib) || // no reservation address !IS_BINARY1_PRESENT(ThisAttrib) ) { // no hw addr specified continue; //= ds inconsistent } } Err = ConvertAttribToReservations(Count, &Reservations, pReservations); MemArrayFree(&Reservations, MemFreeFunc); return Err; } //BeginExport(function) //DOC DhcpDsEnumSubnetElements enumerates the list of subnet elements in a //DOC subnet... such as IpRanges, Exclusions, Reservations.. //DOC DWORD DhcpDsEnumSubnetElements( IN OUT LPSTORE_HANDLE hDhcpC, // root container to create objects IN OUT LPSTORE_HANDLE hServer, // server object IN OUT LPSTORE_HANDLE hSubnet, // subnet object IN DWORD Reserved, // for future use, reserved IN LPWSTR ServerName, // name of server we're using IN DHCP_SUBNET_ELEMENT_TYPE ElementType, // what kind of elt to enum? OUT LPDHCP_SUBNET_ELEMENT_INFO_ARRAY_V4 *ElementInfo ) //EndExport(function) { DWORD Err; switch(ElementType) { case DhcpIpRanges: Err = DhcpDsEnumRangesOrExcl( hDhcpC, hServer, hSubnet, Reserved, ServerName, TRUE, ElementInfo ); break; case DhcpExcludedIpRanges: Err = DhcpDsEnumRangesOrExcl( hDhcpC, hServer, hSubnet, Reserved, ServerName, FALSE, ElementInfo ); break; case DhcpReservedIps: Err = DhcpDsEnumReservations( hDhcpC, hServer, hSubnet, Reserved, ServerName, ElementInfo ); break; default: return ERROR_CALL_NOT_IMPLEMENTED; } return Err; } //================================================================================ // end of file //================================================================================