diff options
Diffstat (limited to 'private/net/svcdlls/rpl')
152 files changed, 36638 insertions, 0 deletions
diff --git a/private/net/svcdlls/rpl/client/makefile b/private/net/svcdlls/rpl/client/makefile new file mode 100644 index 000000000..f0db8e4a7 --- /dev/null +++ b/private/net/svcdlls/rpl/client/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS LINE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/client/rplapi.c b/private/net/svcdlls/rpl/client/rplapi.c new file mode 100644 index 000000000..881161ea2 --- /dev/null +++ b/private/net/svcdlls/rpl/client/rplapi.c @@ -0,0 +1,1893 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rpl.c + +Abstract: + + This file contains program to test RPL APIs. + +Author: + + Vladimiv Z. Vulovic (vladimv) 19-November-1993 + +Environment: + + User Mode - Win32 + +Revision History: + +--*/ + +// +// INCLUDES +// + +#include <nt.h> // DbgPrint prototype +#include <ntrtl.h> // DbgPrint prototype +#include <nturtl.h> // Needed by winbase.h + +#include <windows.h> // DWORD, IN, File APIs, etc. + +#include <lmcons.h> // NET_API_STATUS +#include <lmerr.h> // NetError codes +#include <lmrpl.h> // RPL_HANDLE +#include <i_lmrpl.h> // RPL_CONFIG_INFO_1 +#include <lmapibuf.h> // NetApiBufferFree() +#include <stdlib.h> // exit() +#include <stdio.h> // printf +#include <ctype.h> // toupper - bombs if I use it + +#define RPL_BUFFER_GET_ALL ((DWORD)-1) + +#define Call( fn ) \ + { \ + int _ApiError = fn; \ + if ( _ApiError != NO_ERROR) { \ + printf( "Line = %d, _ApiError = %d\n", __LINE__, _ApiError); \ + DbgPrint( "[RplApi] Line = %d, _ApiError = %d\n", __LINE__, _ApiError); \ + DbgUserBreakPoint(); \ + } \ + } + +#define RPL_ASSERT( condition) \ + { \ + if ( !( condition)) { \ + printf( "File %s, Line %d\n", __FILE__, __LINE__); \ + DbgPrint( "[RplApi] File %s, Line %d\n", __FILE__, __LINE__); \ + DbgUserBreakPoint(); \ + } \ + } + +PWCHAR G_ServerName; // GLOBAL +RPL_HANDLE G_ServerHandle; // GLOBAL + + +BOOL ReadString( + IN PCHAR StringName, + OUT PWCHAR * pString, + IN BOOL MustHaveInput + ) +{ + BYTE Line[ 300]; + WCHAR WcharBuffer[ 300]; + DWORD Length; // includes terminal null wchar + + printf( "%s=", StringName); + + *pString = NULL; + + if ( gets( Line) == NULL) { + return( FALSE); + } + if ( *Line == 0) { + // + // Zero length input is OK only when input is optional (and in that + // case pointer is assumed to be NULL). + // + if ( MustHaveInput == FALSE) { + return( TRUE); + } else { + printf( "%s must be supplied\n", StringName); + return( FALSE); + } + } + Length = MultiByteToWideChar( CP_OEMCP, MB_PRECOMPOSED, Line, + -1, WcharBuffer, sizeof( WcharBuffer)); + if ( Length == 0) { + printf( "Invalid string = %s\n, Line"); + return( FALSE); + } + *pString = LocalAlloc( GMEM_FIXED, Length * sizeof(WCHAR)); + if ( *pString == NULL) { + printf( "LocalAlloc failed"); + return( FALSE); + } + wcscpy( *pString, WcharBuffer); + return( TRUE); +} + + +BOOL ReadInt( + IN PCHAR FieldName, + OUT int * pInt, + IN BOOL MustHaveInput + ) +{ + BYTE Line[ 300]; + printf( "%s=", FieldName); + if ( gets( Line) == NULL) { + return( FALSE); + } + if ( sscanf( Line, "%d", pInt) != 1) { + if ( MustHaveInput == FALSE) { + return( TRUE); + } else { + printf( "%s must be supplied\n", FieldName); + return( FALSE); + } + } + return( TRUE); +} + + +BOOL ReadWchar( + IN PCHAR FieldName, + OUT PWCHAR pWchar, + IN BOOL MustHaveInput + ) +{ + BYTE Line[ 300]; + CHAR Char; + + printf( "%s=", FieldName); + if ( gets( Line) == NULL) { + return( FALSE); + } + // + // Note that "%1s" instead of "%1c" would nicely overwrite stack + // (due to terminating NULL added). + // + if ( sscanf( Line, "%1c", &Char) != 1) { + if ( MustHaveInput == FALSE) { + return( TRUE); + } else { + printf( "%s must be supplied\n", FieldName); + return( FALSE); + } + } + *pWchar = Char; + return( TRUE); +} + + +VOID TestConnect( VOID) +{ + RPL_HANDLE ServerHandle; + Call( NetRplOpen( G_ServerName, &ServerHandle);) + printf( "ServerHandle = 0x%x\n", ServerHandle); + Call( NetRplClose( ServerHandle);) +} + + +DWORD ConfigDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_CONFIG_INFO_2 Info = Buffer; + + if ( Level > 2) { + return( ERROR_INVALID_LEVEL); + } + printf( "ConfigName=%ws\n\tConfigComment=%ws\n", Info->ConfigName, Info->ConfigComment); + if ( Level == 0) { + return( NO_ERROR); + } + printf( "\tFlags = 0x%x\n", Info->Flags); + if ( Level == 1) { + return( NO_ERROR); + } + printf( "\tBootName=%ws\n\tDirName=%ws\n\tDirname2=%ws\n\t" + "Dirname3=%ws\n\tDirName4=%ws\n\tFitShared=%ws\n\tFitPersonal=%ws\n", + Info->BootName, Info->DirName, Info->DirName2, + Info->DirName3, Info->DirName4, Info->FitShared, Info->FitPersonal); + return( NO_ERROR); +} + + + +VOID TestConfigEnum( + IN DWORD Level, + IN PWCHAR AdapterName, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_CONFIG_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_CONFIG_INFO_1); + break; + case 2: + CoreSize = sizeof( RPL_CONFIG_INFO_2); + break; + default: + printf( "\nTestConfigEnum: invalid Level=%d", Level); + return; + break; + } + + printf( "\nTestConfigEnum: Level=%d", Level); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + printf( ", PrefMaxLength=%ld", PrefMaxLength); + } else { + printf( ", unlimited buffer size"); + } + if ( AdapterName != NULL) { + printf( ", AdapterName=%ws", AdapterName); + } + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle=0x%x\n\n", *pResumeHandle); + } else { + printf( ", not resumable.\n\n"); + } + + for ( ; ; ) { + Error = NetRplConfigEnum( G_ServerHandle, AdapterName, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + printf( "Error = %d\n", Error); + break; + } + + printf( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries); + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle = 0x%x\n", *pResumeHandle); + } else { + printf("\n"); + } + + for ( index = 0; index < EntriesRead; index++) { + ConfigDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + RPL_ASSERT( Error == NO_ERROR); + break; + } + RPL_ASSERT( Error == ERROR_MORE_DATA); + } +} + + +DWORD ProfileDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_PROFILE_INFO_2 Info = Buffer; + + if ( Level > 2) { + return( ERROR_INVALID_LEVEL); + } + printf( "ProfileName=%ws\n\tProfileComment=%ws\n", Info->ProfileName, Info->ProfileComment); + if ( Level == 0) { + return( NO_ERROR); + } + printf( "\tFlags = 0x%x\n", Info->Flags); + if ( Level == 1) { + return( NO_ERROR); + } + printf( "\tConfigName=%ws\n\tBootName=%ws\n\tFitShared=%ws\n\tFitPersonal=%ws\n", + Info->ConfigName, Info->BootName, Info->FitShared, Info->FitPersonal); + return( NO_ERROR); +} + + + +VOID TestProfileEnum( + IN DWORD Level, + IN PWCHAR AdapterName, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_PROFILE_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_PROFILE_INFO_1); + break; + case 2: + CoreSize = sizeof( RPL_PROFILE_INFO_2); + break; + default: + printf( "\nTestProfileEnum: invalid Level=%d", Level); + return; + break; + } + + printf( "\nTestProfileEnum: Level=%d", Level); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + printf( ", PrefMaxLength=%ld", PrefMaxLength); + } else { + printf( ", unlimited buffer size"); + } + if ( AdapterName != NULL) { + printf( ", AdapterName=%ws", AdapterName); + } + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle=0x%x\n\n", *pResumeHandle); + } else { + printf( ", not resumable.\n\n"); + } + + for ( ; ; ) { + Error = NetRplProfileEnum( G_ServerHandle, AdapterName, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + printf( "Error = %d\n", Error); + break; + } + + printf( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries); + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle = 0x%x\n", *pResumeHandle); + } else { + printf("\n"); + } + + for ( index = 0; index < EntriesRead; index++) { + ProfileDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + RPL_ASSERT( Error == NO_ERROR); + break; + } + RPL_ASSERT( Error == ERROR_MORE_DATA); + } +} + + +DWORD ServiceDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_INFO_0 Info = Buffer; + + if ( Level > 0) { + return( ERROR_INVALID_LEVEL); + } + printf( "Flags = 0x%x\n", Info->Flags); + return( NO_ERROR); +} + + + +DWORD WkstaDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_WKSTA_INFO_2 Info = Buffer; + + if ( Level > 2) { + return( ERROR_INVALID_LEVEL); + } + printf( "WkstaName=%ws\n\tWkstaComment=%ws\n", Info->WkstaName, Info->WkstaComment); + if ( Level == 0) { + return( NO_ERROR); + } + printf( "\tFlags=0x%x\n\tProfileName=%ws\n", Info->Flags, Info->ProfileName); + if ( Level == 1) { + return( NO_ERROR); + } + printf( "\tBootName=%ws\n", Info->BootName); + printf( "\tFitFile=%ws\n", Info->FitFile); + printf( "\tAdapterName=%ws\n", Info->AdapterName); + printf( "\tTcpIpAddress=0x%x\n", Info->TcpIpAddress); + printf( "\tTcpIpSubnet=0x%x\n", Info->TcpIpSubnet); + printf( "\tTcpIpGateway=0x%x\n", Info->TcpIpGateway); + return( NO_ERROR); +} + + + +VOID TestWkstaEnum( + IN DWORD Level, + IN PWCHAR ProfileName, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_WKSTA_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_WKSTA_INFO_1); + break; + case 2: + CoreSize = sizeof( RPL_WKSTA_INFO_2); + break; + default: + printf( "\nTestWkstaEnum: invalid Level=%d", Level); + return; + break; + } + + printf( "\nTestWkstaEnum: Level=%d", Level); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + printf( ", PrefMaxLength=%ld", PrefMaxLength); + } else { + printf( ", unlimited buffer size"); + } + if ( ProfileName != NULL) { + printf( ", ProfileName=%ws", ProfileName); + } + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle=0x%x\n\n", *pResumeHandle); + } else { + printf( ", not resumable.\n\n"); + } + + for ( ; ; ) { + Error = NetRplWkstaEnum( G_ServerHandle, ProfileName, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + printf( "Error = %d\n", Error); + break; + } + + printf( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries); + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle = 0x%x\n", *pResumeHandle); + } else { + printf("\n"); + } + + for ( index = 0; index < EntriesRead; index++) { + WkstaDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + RPL_ASSERT( Error == NO_ERROR); + break; + } + RPL_ASSERT( Error == ERROR_MORE_DATA); + } +} + + +DWORD VendorDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_VENDOR_INFO_1 Info = Buffer; + + if ( Level > 1) { + return( ERROR_INVALID_LEVEL); + } + printf( "VendorName=%ws\n\tVendorComment=%ws\n", Info->VendorName, Info->VendorComment); + if ( Level == 0) { + return( NO_ERROR); + } + printf( "\tFlags=0x%x\n", Info->Flags); + return( NO_ERROR); +} + + + +DWORD BootDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_BOOT_INFO_2 Info = Buffer; + + if ( Level > 2) { + return( ERROR_INVALID_LEVEL); + } + printf( "BootName=%ws\n\tBootComment=%ws\n", Info->BootName, Info->BootComment); + if ( Level == 0) { + return( NO_ERROR); + } + printf( "\tFlags=0x%x\n\tVendorName=%ws\n", Info->Flags, Info->VendorName); + if ( Level == 1) { + return( NO_ERROR); + } + printf( "\tBbcFile=%ws\n", Info->BbcFile); + printf( "\tWindowSize=0x%x\n", Info->WindowSize); + return( NO_ERROR); +} + + + +DWORD AdapterDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_ADAPTER_INFO_1 Info = Buffer; + + if ( Level > 1) { + return( ERROR_INVALID_LEVEL); + } + printf( "AdapterName=%ws\n\tAdapterComment=%ws\n", Info->AdapterName, Info->AdapterComment); + if ( Level == 0) { + return( NO_ERROR); + } + printf( "\tFlags=0x%x\n", Info->Flags); + return( NO_ERROR); +} + + + +VOID TestAdapterEnum( + IN DWORD Level, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_ADAPTER_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_ADAPTER_INFO_1); + break; + default: + printf( "\nTestAdapterEnum: invalid Level=%d", Level); + return; + break; + } + + printf( "\nTestAdapterEnum: Level=%d", Level); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + printf( ", PrefMaxLength=%ld", PrefMaxLength); + } else { + printf( ", unlimited buffer size"); + } + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle=0x%x\n\n", *pResumeHandle); + } else { + printf( ", not resumable.\n\n"); + } + + for ( ; ; ) { + Error = NetRplAdapterEnum( G_ServerHandle, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + printf( "Error = %d\n", Error); + break; + } + + printf( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries); + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle = 0x%x\n", *pResumeHandle); + } else { + printf("\n"); + } + + for ( index = 0; index < EntriesRead; index++) { + AdapterDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + RPL_ASSERT( Error == NO_ERROR); + break; + } + RPL_ASSERT( Error == ERROR_MORE_DATA); + } +} + + +VOID TestAdapterAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + + printf( "\nTestAdapterAdd\n"); + AdapterDisplayInfo( 1, Buffer); + Error = NetRplAdapterAdd( G_ServerHandle, 1, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID AdapterAdd( VOID) +{ + RPL_ADAPTER_INFO_1 Info; + + if ( !ReadString( "AdapterName", &Info.AdapterName, TRUE)) { + return; + } + Info.Flags = 0; + printf( "\tAll other parameters are optional\n"); + if ( !ReadString( "AdapterComment", &Info.AdapterComment, FALSE)) { + return; + } + TestAdapterAdd( &Info); +} + + +VOID TestBootAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + + printf( "\nTestBootAdd\n"); + BootDisplayInfo( 2, Buffer); + Error = NetRplBootAdd( G_ServerHandle, 2, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID BootAdd( VOID) +{ + RPL_BOOT_INFO_2 Info; + + if ( !ReadString( "BootName", &Info.BootName, TRUE)) { + return; + } + if ( !ReadString( "VendorName", &Info.VendorName, TRUE)) { + return; + } + if ( !ReadString( "ConfigName", &Info.BbcFile, TRUE)) { + return; + } + Info.Flags = 0; + printf( "\tAll other parameters are optional\n"); + if ( !ReadString( "BootComment", &Info.BootComment, FALSE)) { + return; + } + Info.WindowSize = 1; + if ( !ReadInt( "WindowSize", &Info.WindowSize, FALSE)) { + return; + } + TestBootAdd( &Info); +} + + +VOID BootDel( VOID) +{ + PWCHAR BootName; + PWCHAR VendorName; + DWORD Error; + + if ( !ReadString( "BootName", &BootName, TRUE)) { + return; + } + if ( !ReadString( "VendorName", &VendorName, TRUE)) { + return; + } + Error = NetRplBootDel( G_ServerHandle, BootName, VendorName); + if ( Error != NO_ERROR) { + printf( "Error = %d\n", Error); + return; + } +} + + +VOID TestBootEnum( + IN DWORD Level, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_BOOT_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_BOOT_INFO_1); + break; + case 2: + CoreSize = sizeof( RPL_BOOT_INFO_2); + break; + default: + printf( "\nTestBootEnum: invalid Level=%d", Level); + return; + break; + } + + printf( "\nTestBootEnum: Level=%d", Level); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + printf( ", PrefMaxLength=%ld", PrefMaxLength); + } else { + printf( ", unlimited buffer size"); + } + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle=0x%x\n\n", *pResumeHandle); + } else { + printf( ", not resumable.\n\n"); + } + + for ( ; ; ) { + Error = NetRplBootEnum( G_ServerHandle, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + printf( "Error = %d\n", Error); + break; + } + + printf( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries); + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle = 0x%x\n", *pResumeHandle); + } else { + printf("\n"); + } + + for ( index = 0; index < EntriesRead; index++) { + BootDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + RPL_ASSERT( Error == NO_ERROR); + break; + } + RPL_ASSERT( Error == ERROR_MORE_DATA); + } +} + + +VOID BootEnum( VOID) +{ + BYTE Line[ 300]; + DWORD Count; + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + + printf( "Input: Level & PrefMaxLength\n"); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %d", &Level, &PrefMaxLength); + if ( Count != 2) { + printf( "Bad number of arguments.\n"); + return; + } + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestBootEnum( Level, PrefMaxLength, &ResumeHandle); + } else { + TestBootEnum( Level, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID TestConfigAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + + printf( "\nTestConfigAdd\n"); + ConfigDisplayInfo( 2, Buffer); + Error = NetRplConfigAdd( G_ServerHandle, 2, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID ConfigAdd( VOID) +{ + RPL_CONFIG_INFO_2 Info; + + if ( !ReadString( "ConfigName", &Info.ConfigName, TRUE)) { + return; + } + if ( !ReadString( "BootName", &Info.BootName, TRUE)) { + return; + } + if ( !ReadString( "DirName", &Info.DirName, TRUE)) { + return; + } + if ( !ReadString( "FitShared", &Info.FitShared, TRUE)) { + return; + } + if ( !ReadString( "FitPersonal", &Info.FitPersonal, TRUE)) { + return; + } + Info.Flags = 0; + printf( "\tAll other parameters are optional\n"); + if ( !ReadString( "ConfigComment", &Info.ConfigComment, FALSE)) { + return; + } + if ( !ReadString( "DirName2", &Info.DirName2, TRUE)) { + return; + } + if ( !ReadString( "DirName3", &Info.DirName3, TRUE)) { + return; + } + if ( !ReadString( "DirName4", &Info.DirName4, TRUE)) { + return; + } + TestConfigAdd( &Info); +} + + +VOID ConfigDel( VOID) +{ + PWCHAR ConfigName; + DWORD Error; + + if ( !ReadString( "ConfigName", &ConfigName, FALSE)) { + return; + } + Error = NetRplConfigDel( G_ServerHandle, ConfigName); + if ( Error != 0) { + printf( "Failed to delete ConfigName=%ws, Error = %d\n", ConfigName, Error); + } +} + + +VOID TestVendorAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + + printf( "\nTestVendorAdd\n"); + VendorDisplayInfo( 1, Buffer); + Error = NetRplVendorAdd( G_ServerHandle, 1, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID VendorAdd( VOID) +{ + RPL_VENDOR_INFO_1 Info; + + if ( !ReadString( "VendorName", &Info.VendorName, TRUE)) { + return; + } + Info.Flags = 0; + printf( "\tAll other parameters are optional\n"); + if ( !ReadString( "VendorComment", &Info.VendorComment, FALSE)) { + return; + } + TestVendorAdd( &Info); +} + + +VOID VendorDel( VOID) +{ + PWCHAR VendorName; + DWORD Error; + + if ( !ReadString( "VendorName", &VendorName, FALSE)) { + return; + } + Error = NetRplVendorDel( G_ServerHandle, VendorName); + if ( Error != 0) { + printf( "Failed to delete VendorName=%ws, Error = %d\n", VendorName, Error); + } +} + + +VOID TestVendorEnum( + IN DWORD Level, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_VENDOR_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_VENDOR_INFO_1); + break; + default: + printf( "\nTestVendorEnum: invalid Level=%d", Level); + return; + break; + } + + printf( "\nTestVendorEnum: Level=%d", Level); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + printf( ", PrefMaxLength=%ld", PrefMaxLength); + } else { + printf( ", unlimited buffer size"); + } + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle=0x%x\n\n", *pResumeHandle); + } else { + printf( ", not resumable.\n\n"); + } + + for ( ; ; ) { + Error = NetRplVendorEnum( G_ServerHandle, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + printf( "Error = %d\n", Error); + break; + } + + printf( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries); + if ( pResumeHandle != NULL) { + printf( ", ResumeHandle = 0x%x\n", *pResumeHandle); + } else { + printf("\n"); + } + + for ( index = 0; index < EntriesRead; index++) { + VendorDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + RPL_ASSERT( Error == NO_ERROR); + break; + } + RPL_ASSERT( Error == ERROR_MORE_DATA); + } +} + + +VOID VendorEnum( VOID) +{ + BYTE Line[ 300]; + DWORD Count; + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + + printf( "Input: Level & PrefMaxLength\n"); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %d", &Level, &PrefMaxLength); + if ( Count != 2) { + printf( "Bad number of arguments.\n"); + return; + } + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestVendorEnum( Level, PrefMaxLength, &ResumeHandle); + } else { + TestVendorEnum( Level, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID TestProfileAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + + printf( "\nTestProfileAdd"); + ProfileDisplayInfo( 2, Buffer); + Error = NetRplProfileAdd( G_ServerHandle, 2, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID TestProfileGetInfo( + IN DWORD Level, + IN PWCHAR ProfileName + ) +{ + LPBYTE Buffer; + DWORD Error; + printf( "\nTestProfileGetInfo: Level=%d, ProfileName=%ws\n", Level, ProfileName); + Error = NetRplProfileGetInfo( G_ServerHandle, ProfileName, Level, &Buffer); + if ( Error != NO_ERROR) { + printf( "Error = %d\n", Error); + return; + } + ProfileDisplayInfo( Level, Buffer); + NetApiBufferFree( Buffer); // =~ MIDL_user_free() +} + + +VOID TestProfileSetInfo( + IN DWORD Level, + IN PWCHAR ProfileName, + IN LPVOID Buffer + ) +{ + DWORD Error; + DWORD ErrorParameter; + + printf( "\nTestProfileSetInfo: Level=%d, ProfileName=%ws\n", Level, ProfileName); + ProfileDisplayInfo( Level, Buffer); + Error = NetRplProfileSetInfo( G_ServerHandle, ProfileName, Level, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID TestWkstaAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + + printf( "\nTestWkstaAdd\n"); + WkstaDisplayInfo( 2, Buffer); + Error = NetRplWkstaAdd( G_ServerHandle, 2, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID TestWkstaGetInfo( + IN DWORD Level, + IN PWCHAR WkstaName + ) +{ + LPBYTE Buffer; + DWORD Error; + printf( "\nTestWkstaGetInfo: Level=%d, WkstaName=%ws\n", Level, WkstaName); + Error = NetRplWkstaGetInfo( G_ServerHandle, WkstaName, Level, &Buffer); + if ( Error != NO_ERROR) { + printf( "Error = %d\n", Error); + return; + } + WkstaDisplayInfo( Level, Buffer); + NetApiBufferFree( Buffer); // =~ MIDL_user_free() +} + + +VOID TestWkstaSetInfo( + IN DWORD Level, + IN PWCHAR WkstaName, + IN LPVOID Buffer + ) +{ + DWORD Error; + DWORD ErrorParameter; + + printf( "\nTestWkstaSetInfo: Level=%d, WkstaName=%ws\n", Level, WkstaName); + WkstaDisplayInfo( Level, Buffer); + Error = NetRplWkstaSetInfo( G_ServerHandle, WkstaName, Level, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID AdapterDel( VOID) +{ + PWCHAR AdapterName; + DWORD Error; + + if ( !ReadString( "AdapterName", &AdapterName, FALSE)) { + return; + } + if ( AdapterName == NULL) { + printf( "You requested to delete all adapters!\n"); + } + + Error = NetRplAdapterDel( G_ServerHandle, AdapterName); + if ( Error != 0) { + printf( "Failed to delete AdapterName=%ws, Error = %d\n", AdapterName, Error); + } +} + + +VOID AdapterEnum( VOID) +{ + BYTE Line[ 300]; + DWORD Count; + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + + printf( "Input: Level & PrefMaxLength\n"); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %d", &Level, &PrefMaxLength); + if ( Count != 2) { + printf( "Bad number of arguments.\n"); + return; + } + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestAdapterEnum( Level, PrefMaxLength, &ResumeHandle); + } else { + TestAdapterEnum( Level, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID ConfigEnum( VOID) +{ + BYTE Line[ 300]; + DWORD Count; + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + PWCHAR AdapterName; + + printf( "Input: Level & PrefMaxLength\n"); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %d", &Level, &PrefMaxLength); + if ( Count != 2) { + printf( "Bad number of arguments.\n"); + return; + } + if( !ReadString( "[filter] AdapterName", &AdapterName, FALSE)) { + return; + } + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestConfigEnum( Level, AdapterName, PrefMaxLength, &ResumeHandle); + } else { + TestConfigEnum( Level, AdapterName, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID ProfileAdd( VOID) +{ + RPL_PROFILE_INFO_2 Info; + + if ( !ReadString( "ProfileName", &Info.ProfileName, TRUE)) { + return; + } + if ( !ReadString( "ConfigName", &Info.ConfigName, TRUE)) { + return; + } + Info.Flags = 0; + printf( "\tAll other parameters are optional\n"); + if ( !ReadString( "ProfileComment", &Info.ProfileComment, FALSE)) { + return; + } + if ( !ReadString( "BootName", &Info.BootName, FALSE)) { + return; + } + if ( !ReadString( "FitShared", &Info.FitShared, FALSE)) { + return; + } + if ( !ReadString( "FitPersonal", &Info.FitPersonal, FALSE)) { + return; + } + TestProfileAdd( &Info); +} + + +VOID ProfileClone( VOID) +{ + PWCHAR SourceProfileName; + PWCHAR TargetProfileName; + PWCHAR TargetProfileComment; + DWORD Error; + + if ( !ReadString( "SourceProfileName", &SourceProfileName, TRUE)) { + return; + } + if ( !ReadString( "TargetProfileName", &TargetProfileName, TRUE)) { + return; + } + if ( !ReadString( "TargetProfileComment", &TargetProfileComment, FALSE)) { + return; + } + Error = NetRplProfileClone( G_ServerHandle, SourceProfileName, + TargetProfileName, TargetProfileComment); + if ( Error != NO_ERROR) { + printf( "Error = %d\n", Error); + return; + } +} + + +VOID ProfileDel( VOID) +{ + PWCHAR ProfileName; + DWORD Error; + + if ( !ReadString( "ProfileName", &ProfileName, TRUE)) { + return; + } + Error = NetRplProfileDel( G_ServerHandle, ProfileName); + if ( Error != NO_ERROR) { + printf( "Error = %d\n", Error); + return; + } +} + + +VOID ProfileEnum( VOID) +{ + BYTE Line[ 300]; + DWORD Count; + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + PWCHAR AdapterName; + + printf( "Input: Level & PrefMaxLength\n"); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %d", &Level, &PrefMaxLength); + if ( Count != 2) { + printf( "Bad number of arguments.\n"); + return; + } + if( !ReadString( "[filter] AdapterName", &AdapterName, FALSE)) { + return; + } + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestProfileEnum( Level, AdapterName, PrefMaxLength, &ResumeHandle); + } else { + TestProfileEnum( Level, AdapterName, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID ProfileGetInfo( VOID) +{ + BYTE Line[ 300]; + WCHAR ProfileName[ 20]; + CHAR ProfileNameA[ 20]; + DWORD Length; + DWORD Count; + DWORD Level; + + printf( "Input: Level & ProfileName\n"); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %s", &Level, ProfileNameA); + if ( Count != 2) { + printf( "Bad number of arguments.\n"); + return; + } + Length = MultiByteToWideChar( CP_OEMCP, MB_PRECOMPOSED, ProfileNameA, -1, + ProfileName, sizeof( ProfileName)); + if ( Length == 0) { + printf( "Invalid ProfileName = %s\n, ProfileNameA"); + return; + } + TestProfileGetInfo( Level, ProfileName); +} + + +VOID ProfileSetInfo( VOID) +{ + PWCHAR ProfileName; + DWORD Level; + RPL_PROFILE_INFO_2 Info; + LPVOID Buffer; + + Buffer = &Info; + + if ( !ReadInt( "Level", &Level, TRUE) || Level > 2) { + return; + } + if ( !ReadString( "ProfileName", &ProfileName, TRUE)) { + return; + } + Info.ProfileName = NULL; + // ReadString( "ProfileName", &Info.ProfileName); + if ( !ReadString( "ProfileComment", &Info.ProfileComment, FALSE)) { + return; + } + if ( Level == 0) { + goto testit; + } + if ( !ReadInt( "Flags", &Info.Flags, TRUE)) { + return; + } + if ( Level == 1) { + goto testit; + } + Info.BootName = NULL; + // ReadString( "BootName", &Info.ProfileName); + if ( !ReadString( "FitShared", &Info.ProfileName, FALSE)) { + return; + } + if ( !ReadString( "FitPersonal", &Info.ProfileName, FALSE)) { + return; + } +testit: + TestProfileSetInfo( Level, ProfileName, Buffer); +} + + +VOID ServiceClose( VOID) +{ + Call( NetRplClose( G_ServerHandle);) +} + + +VOID ServiceGetInfo( VOID) +{ + LPBYTE Buffer; + DWORD Error; + Error = NetRplGetInfo( G_ServerHandle, 0, &Buffer); + if ( Error != NO_ERROR) { + printf( "Error = %d\n", Error); + return; + } + ServiceDisplayInfo( 0, Buffer); + NetApiBufferFree( Buffer); // =~ MIDL_user_free() +} + + +VOID ServiceOpen( VOID) +{ + Call( NetRplOpen( G_ServerName, &G_ServerHandle);) +} + + +VOID ServiceSetInfo( VOID) +{ + DWORD Level; + LPVOID Buffer; + DWORD Error; + DWORD ErrorParameter; + + if ( !ReadInt( "Level", &Level, FALSE)) { + return; + } + + switch( Level) { + case 0: { + RPL_INFO_0 Info; + Buffer = &Info; + if ( !ReadInt( "Flags", &Info.Flags, TRUE)) { + return; + } + break; + } + default: + return; + break; + } + Error = NetRplSetInfo( G_ServerHandle, 0, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + printf( "Error = %d, ErrorParameter = %d\n", Error, ErrorParameter); + return; + } +} + + +VOID WkstaAdd( VOID) +{ + RPL_WKSTA_INFO_2 Info; + + if ( !ReadString( "WkstaName", &Info.WkstaName, TRUE)) { + return; + } + if ( !ReadString( "ProfileName", &Info.ProfileName, TRUE)) { + return; + } + if ( !ReadString( "AdapterName", &Info.AdapterName, TRUE)) { + return; + } + if ( !ReadInt( "Flags", &Info.Flags, TRUE)) { + return; + } + Info.Flags = 0; + printf( "\tAll other parameters are optional\n"); + if ( !ReadString( "WkstaComment", &Info.WkstaComment, FALSE)) { + return; + } + if ( !ReadString( "BootName", &Info.BootName, FALSE)) { + return; + } + if ( !ReadString( "FitFile", &Info.FitFile, FALSE)) { + return; + } + Info.TcpIpAddress = (DWORD)-1; + if ( !ReadInt( "TcpIpAddress", &Info.TcpIpAddress, FALSE)) { + return; + } + Info.TcpIpSubnet = (DWORD)-1; + if ( !ReadInt( "TcpIpSubnet", &Info.TcpIpSubnet, FALSE)) { + return; + } + Info.TcpIpGateway = (DWORD)-1; + if ( !ReadInt( "TcpIpGateway", &Info.TcpIpGateway, FALSE)) { + return; + } + TestWkstaAdd( &Info); +} + + +VOID WkstaClone( VOID) +{ + PWCHAR SourceWkstaName; + PWCHAR TargetWkstaName; + PWCHAR TargetWkstaComment; + PWCHAR TargetAdapterName; + DWORD TargetTcpIpAddress; + DWORD Error; + + if ( !ReadString( "SourceWkstaName", &SourceWkstaName, TRUE)) { + return; + } + if ( !ReadString( "TargetWkstaName", &TargetWkstaName, TRUE)) { + return; + } + if ( !ReadString( "TargetAdapterName", &TargetAdapterName, TRUE)) { + return; + } + printf( "\tAll other parameters are optional\n"); + if ( !ReadString( "TargetWkstaComment", &TargetWkstaComment, FALSE)) { + return; + } + TargetTcpIpAddress = (DWORD)-1; + if( !ReadInt( "TcpIpAddress", &TargetTcpIpAddress, FALSE)) { + return; + } + Error = NetRplWkstaClone( G_ServerHandle, SourceWkstaName, + TargetWkstaName, TargetWkstaComment, TargetAdapterName, TargetTcpIpAddress); + if ( Error != NO_ERROR) { + printf( "Error = %d\n", Error); + return; + } +} + + +VOID WkstaDel( VOID) +{ + PWCHAR WkstaName; + DWORD Error; + + if ( !ReadString( "WkstaName", &WkstaName, TRUE)) { + return; + } + Error = NetRplWkstaDel( G_ServerHandle, WkstaName); + if ( Error != NO_ERROR) { + printf( "Error = %d\n", Error); + return; + } +} + + +VOID WkstaEnum( VOID) +{ + BYTE Line[ 300]; + DWORD Count; + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + PWCHAR ProfileName; + + printf( "Input: Level, PrefMaxLength\n"); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %d", &Level, &PrefMaxLength); + if ( Count != 2) { + printf( "Bad number of arguments.\n"); + return; + } + if( !ReadString( "[filter] ProfileName", &ProfileName, FALSE)) { + return; + } + ResumeHandle = 0, TestWkstaEnum( Level, ProfileName, PrefMaxLength, &ResumeHandle); +} + + +VOID WkstaGetInfo( VOID) +{ + BYTE Line[ 300]; + WCHAR WkstaName[ 20]; + CHAR WkstaNameA[ 20]; + DWORD Length; + DWORD Count; + DWORD Level; + + printf( "Input: Level & WkstaName\n"); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %s", &Level, WkstaNameA); + if ( Count != 2) { + printf( "Bad number of arguments.\n"); + return; + } + Length = MultiByteToWideChar( CP_OEMCP, MB_PRECOMPOSED, WkstaNameA, -1, + WkstaName, sizeof( WkstaName)); + if ( Length == 0) { + printf( "Invalid WkstaName = %s\n, WkstaNameA"); + return; + } + TestWkstaGetInfo( Level, WkstaName); +} + + +VOID WkstaSetInfo( VOID) +{ + PWCHAR WkstaName; + DWORD Level; + LPVOID Buffer; + + if ( !ReadInt( "Level", &Level, FALSE)) { + return; + } + if ( !ReadString( "WkstaName", &WkstaName, FALSE)) { + return; + } + + switch( Level) { + case 0: { + RPL_WKSTA_INFO_0 Info; + Buffer = &Info; + Info.WkstaName = NULL; + // ReadString( "WkstaName", &Info.WkstaName); + if( !ReadString( "WkstaComment", &Info.WkstaComment, FALSE)) { + return; + } + break; + } + case 1: { + RPL_WKSTA_INFO_1 Info; + Buffer = &Info; + Info.WkstaName = NULL; + // ReadString( "WkstaName", &Info.WkstaName); + if( !ReadString( "WkstaComment", &Info.WkstaComment, FALSE)) { + return; + } + if( !ReadString( "ProfileName", &Info.ProfileName, FALSE)) { + return; + } + break; + } + case 2: { + RPL_WKSTA_INFO_2 Info; + Buffer = &Info; + Info.WkstaName = NULL; + // ReadString( "WkstaName", &Info.WkstaName); + if( !ReadString( "WkstaComment", &Info.WkstaComment, FALSE)) { + return; + } + if( !ReadString( "ProfileName", &Info.ProfileName, FALSE)) { + return; + } + break; + } + default: + return; + break; + } + TestWkstaSetInfo( Level, WkstaName, Buffer); +} + + +VOID Worker( VOID) +{ + BYTE Line[ 300]; + CHAR response; + + for ( ; ;) { + printf("Adapter Boot Config Profile Service Vendor Wksta [Quit]: "); + if ( gets( Line) == NULL) { + return; + } + sscanf( Line, " %1c", &response); + switch( toupper(response)) { + case 'A': + printf( " Add Del Enum: "); + if ( gets( Line) == NULL) { + return; + } + sscanf( Line, " %1c", &response); + switch( toupper(response)) { + case 'A': + AdapterAdd(); + break; + case 'D': + AdapterDel(); + break; + case 'E': + AdapterEnum(); + break; + } + break; + case 'B': + printf( " Add Del Enum: "); + if ( gets( Line) == NULL) { + return; + } + sscanf( Line, " %1c", &response); + switch( toupper(response)) { + case 'A': + BootAdd(); + break; + case 'D': + BootDel(); + break; + case 'E': + BootEnum(); + break; + } + break; + case 'C': + printf( " Add Del Enum: "); + if ( gets( Line) == NULL) { + return; + } + sscanf( Line, " %1c", &response); + switch( toupper(response)) { + case 'A': + ConfigAdd(); + break; + case 'D': + ConfigDel(); + break; + case 'E': + ConfigEnum(); + break; + } + break; + case 'P': + printf( " Add Clone Del Enum GetInfo SetInfo: "); + if ( gets( Line) == NULL) { + return; + } + sscanf( Line, " %1c", &response); + switch( toupper(response)) { + case 'A': + ProfileAdd(); + break; + case 'C': + ProfileClone(); + break; + case 'D': + ProfileDel(); + break; + case 'E': + ProfileEnum(); + break; + case 'G': + ProfileGetInfo(); + break; + case 'S': + ProfileSetInfo(); + break; + } + break; + case 'S': + printf( " Close GetInfo Open SetInfo: "); + if ( gets( Line) == NULL) { + return; + } + sscanf( Line, " %1c", &response); + switch( toupper(response)) { + case 'C': + ServiceClose(); + break; + case 'G': + ServiceGetInfo(); + break; + case 'O': + ServiceOpen(); + break; + case 'S': + ServiceSetInfo(); + break; + } + break; + case 'V': + printf( " Add Del Enum: "); + if ( gets( Line) == NULL) { + return; + } + sscanf( Line, " %1c", &response); + switch( toupper(response)) { + case 'A': + VendorAdd(); + break; + case 'D': + VendorDel(); + break; + case 'E': + VendorEnum(); + break; + } + break; + case 'W': + printf( " Add Clone Del Enum GetInfo SetInfo: "); + if ( gets( Line) == NULL) { + return; + } + sscanf( Line, " %1c", &response); + switch( toupper(response)) { + case 'A': + WkstaAdd(); + break; + case 'C': + WkstaClone(); + break; + case 'D': + WkstaDel(); + break; + case 'E': + WkstaEnum(); + break; + case 'G': + WkstaGetInfo(); + break; + case 'S': + WkstaSetInfo(); + break; + } + break; + case 'Q': + return; + break; + default: + printf( "Your input '%1c' is invalid. Try again.\n", response); + break; + } + } +} + + +DWORD _CRTAPI1 main( int argc, char **argv) +{ + DWORD ResumeHandle; + + if ( argc == 1) { + G_ServerName = NULL; + } else if ( argc == 2) { + WCHAR Buffer[ CNLEN + 1]; + DWORD Length; + Length = MultiByteToWideChar( + CP_OEMCP, + MB_PRECOMPOSED, + argv[ 1], + -1, + Buffer, + sizeof( Buffer) + ); + if ( Length == 0) { + printf( "Invalid ServerName\n"); + return( 1); + } + G_ServerName = Buffer; + printf( "ServerName = %ws\n", G_ServerName); + } else { + printf( "Usage: RplApi [ServerName]\n"); + return( 1); + } + + TestConnect(); + + Call( NetRplOpen( G_ServerName, &G_ServerHandle);) + printf( "G_ServerHandle = 0x%x\n", G_ServerHandle); + +// #define NOT_YET +#ifdef NOT_YET + for ( ; ; ) { + TestConfigEnum( 0, NULL, RPL_BUFFER_GET_ALL, NULL); + ResumeHandle = 0, NULL, TestConfigEnum( 1, NULL, 400, &ResumeHandle); + ResumeHandle = 0, NULL, TestConfigEnum( 2, NULL, 10, &ResumeHandle); + + TestConfigEnum( 2, NULL, RPL_BUFFER_GET_ALL, NULL); + TestConfigEnum( 1, NULL, 500, NULL); + ResumeHandle = 0, TestConfigEnum( 0, NULL, 500, &ResumeHandle); + + TestProfileEnum( 2, NULL, RPL_BUFFER_GET_ALL, NULL); + ResumeHandle = 0, TestProfileEnum( 0, NULL, 10, &ResumeHandle); + ResumeHandle = 0, TestProfileEnum( 1, NULL, 30, &ResumeHandle); + ResumeHandle = 0, TestProfileEnum( 2, NULL, 50, &ResumeHandle); + + TestWkstaEnum( 2, NULL, RPL_BUFFER_GET_ALL, NULL); + ResumeHandle = 0, TestWkstaEnum( 0, NULL, 10, &ResumeHandle); + ResumeHandle = 0, TestWkstaEnum( 1, NULL, 30, &ResumeHandle); + ResumeHandle = 0, TestWkstaEnum( 2, L"elnk2", 30, &ResumeHandle); + ResumeHandle = 0, TestWkstaEnum( 1, L"xxx", 30, &ResumeHandle); + + ResumeHandle = 0, TestAdapterEnum( 0, 30, &ResumeHandle); + + TestWkstaGetInfo( 0, L"elnk2_"); + TestWkstaGetInfo( 0, L"3sta_"); + } +#endif + + Worker(); + + Call( NetRplClose( G_ServerHandle);) + return(0); +} diff --git a/private/net/svcdlls/rpl/client/rplbind.c b/private/net/svcdlls/rpl/client/rplbind.c new file mode 100644 index 000000000..9a89ee7b4 --- /dev/null +++ b/private/net/svcdlls/rpl/client/rplbind.c @@ -0,0 +1,119 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rplbind.c + +Abstract: + + Contains the RPC bind and un-bind routines for the Remote (Initial) + Program Load service. + +Author: + + Vladimir Z. Vulovic (vladimv) 27 - July - 1993 + +Environment: + + User Mode -Win32 + +Revision History: + + +--*/ + +// +// INCLUDES +// +#include <nt.h> // DbgPrint prototype +#include <rpc.h> // DataTypes and runtime APIs +#include <rplsvc_c.h> // generated by the MIDL complier +#include <rpcutil.h> // NetRpc utils +#include <netlib.h> // UNUSED macro +#include <rplnames.h> // RPL_INTERFACE_NAME + + + +/****************************************************************************/ +handle_t +RPL_NAME_bind ( + RPL_NAME ServerName + ) +/*++ + +Routine Description: + This routine calls a common bind routine that is shared by all services. + This routine is called from the remote boot service client stubs when + it is necessary to bind to a server. + +Arguments: + + ServerName - A pointer to a string containing the name of the server + to bind with. + +Return Value: + + The binding handle is returned to the stub routine. If the + binding is unsuccessful, a NULL will be returned. + +--*/ +{ + handle_t bindingHandle; + RPC_STATUS status; + + status = NetpBindRpc ( + ServerName, + RPL_INTERFACE_NAME, + 0, + &bindingHandle); + +#ifdef DEBUG + DbgPrint("RPLSVC_HANDLE_bind:NetpBindRpc status=%d\n",status); + DbgPrint("RPLSVC_HANDLE_bind: handle=%d\n",bindingHandle); +#endif + + return( bindingHandle); +} + + + +/****************************************************************************/ +void +RPL_NAME_unbind ( + RPL_NAME ServerName, + handle_t BindingHandle + ) +/*++ + +Routine Description: + + This routine calls a common unbind routine that is shared by + all services. + This routine is called from the remote boot service client stubs when + it is necessary to unbind to a server. + + +Arguments: + + ServerName - This is the name of the server from which to unbind. + + BindingHandle - This is the binding handle that is to be closed. + +Return Value: + + none. + +--*/ +{ + UNUSED(ServerName); // This parameter is not used + +#ifdef DEBUG + DbgPrint("RPLSVC_HANDLE_unbind: handle=%d\n",BindingHandle); +#endif + + NetpUnbindRpc ( BindingHandle); + return; +} + diff --git a/private/net/svcdlls/rpl/client/rplstub.c b/private/net/svcdlls/rpl/client/rplstub.c new file mode 100644 index 000000000..89d91f3de --- /dev/null +++ b/private/net/svcdlls/rpl/client/rplstub.c @@ -0,0 +1,1279 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rplstub.c + +Abstract: + + These are the Remote (Initial) Program Load Service API RPC client stubs. + +Author: + + Vladimir Z. Vulovic (vladimv) 27 - July - 1993 + +Environment: + + User Mode - Win32 + +Revision History: + + 27-Jul-1993 vladimv + Created + +--*/ + +// +// INCLUDES +// + +#include <nt.h> // DbgPrint prototype +#include <ntrtl.h> // DbgPrint prototype +#include <nturtl.h> // Needed by winbase.h + +#include <windef.h> // DWORD +#include <winbase.h> // EXCEPTION_STATUS_VIOLATION + +#include <rpc.h> // DataTypes and runtime APIs +#include <rpcutil.h> // NetRpc utils + +#include <lmsvc.h> +#include <lmcons.h> // NET_API_STATUS +#include <lmerr.h> // NetError codes + +#include <netlib.h> // NetpServiceIsStarted() (needed by netrpc.h). +#include <netdebug.h> // needed for netrpc.h +#include <netrpc.h> // NET_REMOTE macros. + +#include <rplsvc_c.h> // generated by the MIDL complier + +DWORD RplMapRpcError( + IN DWORD RpcError, + IN DWORD BadContextError + ); + + + +NET_API_STATUS NET_API_FUNCTION +NetRplOpen( + IN LPTSTR ServerName, + OUT LPRPL_HANDLE ServerHandle + ) +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ +{ + NET_API_STATUS status = ERROR_SUCCESS; + + RpcTryExcept { + *ServerHandle = NULL; // needed for RPC to create new context handle + status = NetrRplOpen( ServerName, (LPRPL_RPC_HANDLE)ServerHandle); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + if (status != NO_ERROR){ + ServerHandle = NULL; + } + + return( status); +} + + + +NET_API_STATUS NET_API_FUNCTION +NetRplClose( + IN RPL_HANDLE ServerHandle + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplClose( (LPRPL_RPC_HANDLE)&ServerHandle); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + + +NET_API_STATUS NET_API_FUNCTION +NetRplGetInfo( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer + ) +/*++ + +Routine Description: + + This is the DLL entrypoint for NetRplGetInfo. + +Arguments: + + ServerHandle - Handle obtained through NetRplOpen(). + + InfoLevel - This indicates the level of information that is desired. + + PointerToBuffer - Pointer to a Location where the pointer to the returned + information structure is to be placed. + +Return Value: + + NET_API_STATUS - NERR_Success or reason for failure. + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + *PointerToBuffer = NULL; // Must be NULL so RPC knows to fill it in. + status = NetrRplGetInfo( + (RPL_RPC_HANDLE)ServerHandle, + InfoLevel, + (LPRPL_INFO_STRUCT)PointerToBuffer + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplSetInfo( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +/*++ + +Routine Description: + + This is the DLL entrypoint for NetRplSetInfo. + +Arguments: + + ServerHandle - Handle obtained through NetRplOpen(). + + InfoLevel - This indicates the level of information that is desired. + + Buffer - Pointer to the information structure to be set. InfoLevel describes + the structure in this buffer. + + ErrorParameter - - Returns the identifier to the invalid parameter in Buffer if this + function returns ERROR_INVALID_PARAMETER. + +Return Value: + + NET_API_STATUS - NERR_Success or reason for failure. + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplSetInfo( + (RPL_RPC_HANDLE)ServerHandle, + InfoLevel, + (LPRPL_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +// +// BOOT block apis +// + + +NET_API_STATUS NET_API_FUNCTION +NetRplBootAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplBootAdd( + (RPL_RPC_HANDLE)ServerHandle, + InfoLevel, + (LPRPL_BOOT_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + +// +// NetRplBootDel: if VendorName is NULL, then all boot block records with +// given BootName will be deleted. +// + +NET_API_STATUS NET_API_FUNCTION +NetRplBootDel( + IN RPL_HANDLE ServerHandle, + IN LPTSTR BootName, + IN LPTSTR VendorName + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplBootDel( + (RPL_RPC_HANDLE)ServerHandle, + BootName, + VendorName + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplBootEnum( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer, + IN DWORD PrefMaxLength, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries, + OUT LPDWORD ResumeHandle + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + GENERIC_ENUM_STRUCT InfoStruct; + GENERIC_INFO_CONTAINER GenericInfoContainer; + + GenericInfoContainer.Buffer = NULL; + GenericInfoContainer.EntriesRead = 0; + + InfoStruct.Container = &GenericInfoContainer; + InfoStruct.Level = InfoLevel; + + RpcTryExcept { + status = NetrRplBootEnum( + (RPL_RPC_HANDLE)ServerHandle, + (LPRPL_BOOT_ENUM)&InfoStruct, + PrefMaxLength, + TotalEntries, + ResumeHandle + ); + if ( status == NERR_Success || status == ERROR_MORE_DATA) { + *PointerToBuffer = (LPBYTE)GenericInfoContainer.Buffer; + *EntriesRead = GenericInfoContainer.EntriesRead; + } + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + +// +// CONFIG apis +// + + +NET_API_STATUS NET_API_FUNCTION +NetRplConfigAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplConfigAdd( + (RPL_RPC_HANDLE)ServerHandle, + InfoLevel, + (LPRPL_CONFIG_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplConfigDel( + IN RPL_HANDLE ServerHandle, + IN LPTSTR ConfigName + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplConfigDel( + (RPL_RPC_HANDLE)ServerHandle, + ConfigName + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplConfigEnum( + IN RPL_HANDLE ServerHandle, + IN LPTSTR AdapterName, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer, + IN DWORD PrefMaxLength, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries, + OUT LPDWORD ResumeHandle + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + GENERIC_ENUM_STRUCT InfoStruct; + GENERIC_INFO_CONTAINER GenericInfoContainer; + + GenericInfoContainer.Buffer = NULL; + GenericInfoContainer.EntriesRead = 0; + + InfoStruct.Container = &GenericInfoContainer; + InfoStruct.Level = InfoLevel; + + RpcTryExcept { + status = NetrRplConfigEnum( + (RPL_RPC_HANDLE)ServerHandle, + AdapterName, + (LPRPL_CONFIG_ENUM)&InfoStruct, + PrefMaxLength, + TotalEntries, + ResumeHandle + ); + if ( status == NERR_Success || status == ERROR_MORE_DATA) { + *PointerToBuffer = (LPBYTE)GenericInfoContainer.Buffer; + *EntriesRead = GenericInfoContainer.EntriesRead; + } + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +// +// PROFILE apis +// + + +NET_API_STATUS NET_API_FUNCTION +NetRplProfileAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplProfileAdd( + (RPL_RPC_HANDLE)ServerHandle, + InfoLevel, + (LPRPL_PROFILE_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplProfileClone( + IN RPL_HANDLE ServerHandle, + IN LPTSTR SourceProfileName, + IN LPTSTR TargetProfileName, + IN LPTSTR TargetProfileComment OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplProfileClone( + (RPL_RPC_HANDLE)ServerHandle, + SourceProfileName, + TargetProfileName, + TargetProfileComment + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + + +NET_API_STATUS NET_API_FUNCTION +NetRplProfileDel( + IN RPL_HANDLE ServerHandle, + IN LPTSTR ProfileName + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplProfileDel( + (RPL_RPC_HANDLE)ServerHandle, + ProfileName + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplProfileEnum( + IN RPL_HANDLE ServerHandle, + IN LPTSTR AdapterName, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer, + IN DWORD PrefMaxLength, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries, + OUT LPDWORD ResumeHandle + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + GENERIC_ENUM_STRUCT InfoStruct; + GENERIC_INFO_CONTAINER GenericInfoContainer; + + GenericInfoContainer.Buffer = NULL; + GenericInfoContainer.EntriesRead = 0; + + InfoStruct.Container = &GenericInfoContainer; + InfoStruct.Level = InfoLevel; + + RpcTryExcept { + status = NetrRplProfileEnum( + (RPL_RPC_HANDLE)ServerHandle, + AdapterName, + (LPRPL_PROFILE_ENUM)&InfoStruct, + PrefMaxLength, + TotalEntries, + ResumeHandle + ); + if ( status == NERR_Success || status == ERROR_MORE_DATA) { + *PointerToBuffer = (LPBYTE)GenericInfoContainer.Buffer; + *EntriesRead = GenericInfoContainer.EntriesRead; + } + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplProfileGetInfo( + IN RPL_HANDLE ServerHandle, + IN LPTSTR ProfileName, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + *PointerToBuffer = NULL; // Must be NULL so RPC knows to fill it in. + status = NetrRplProfileGetInfo( + (RPL_RPC_HANDLE)ServerHandle, + ProfileName, + InfoLevel, + (LPRPL_PROFILE_INFO_STRUCT)PointerToBuffer + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplProfileSetInfo( + IN RPL_HANDLE ServerHandle, + IN LPTSTR ProfileName, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplProfileSetInfo( + (RPL_RPC_HANDLE)ServerHandle, + ProfileName, + InfoLevel, + (LPRPL_PROFILE_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + +// +// VENDOR apis +// + + +NET_API_STATUS NET_API_FUNCTION +NetRplVendorAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplVendorAdd( + (RPL_RPC_HANDLE)ServerHandle, + InfoLevel, + (LPRPL_VENDOR_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplVendorDel( + IN RPL_HANDLE ServerHandle, + IN LPTSTR VendorName + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplVendorDel( + (RPL_RPC_HANDLE)ServerHandle, + VendorName + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplVendorEnum( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer, + IN DWORD PrefMaxLength, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries, + OUT LPDWORD ResumeHandle + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + GENERIC_ENUM_STRUCT InfoStruct; + GENERIC_INFO_CONTAINER GenericInfoContainer; + + GenericInfoContainer.Buffer = NULL; + GenericInfoContainer.EntriesRead = 0; + + InfoStruct.Container = &GenericInfoContainer; + InfoStruct.Level = InfoLevel; + + RpcTryExcept { + status = NetrRplVendorEnum( + (RPL_RPC_HANDLE)ServerHandle, + (LPRPL_VENDOR_ENUM)&InfoStruct, + PrefMaxLength, + TotalEntries, + ResumeHandle + ); + if ( status == NERR_Success || status == ERROR_MORE_DATA) { + *PointerToBuffer = (LPBYTE)GenericInfoContainer.Buffer; + *EntriesRead = GenericInfoContainer.EntriesRead; + } + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + +// +// ADAPTER apis +// + + +NET_API_STATUS NET_API_FUNCTION +NetRplAdapterAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplAdapterAdd( + (RPL_RPC_HANDLE)ServerHandle, + InfoLevel, + (LPRPL_ADAPTER_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplAdapterDel( + IN RPL_HANDLE ServerHandle, + IN LPTSTR AdapterName OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplAdapterDel( + (RPL_RPC_HANDLE)ServerHandle, + AdapterName + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplAdapterEnum( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer, + IN DWORD PrefMaxLength, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries, + OUT LPDWORD ResumeHandle + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + GENERIC_ENUM_STRUCT InfoStruct; + GENERIC_INFO_CONTAINER GenericInfoContainer; + + GenericInfoContainer.Buffer = NULL; + GenericInfoContainer.EntriesRead = 0; + + InfoStruct.Container = &GenericInfoContainer; + InfoStruct.Level = InfoLevel; + + RpcTryExcept { + status = NetrRplAdapterEnum( + (RPL_RPC_HANDLE)ServerHandle, + (LPRPL_ADAPTER_ENUM)&InfoStruct, + PrefMaxLength, + TotalEntries, + ResumeHandle + ); + if ( status == NERR_Success || status == ERROR_MORE_DATA) { + *PointerToBuffer = (LPBYTE)GenericInfoContainer.Buffer; + *EntriesRead = GenericInfoContainer.EntriesRead; + } + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +// +// WKSTA apis +// + + +NET_API_STATUS NET_API_FUNCTION +NetRplWkstaAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplWkstaAdd( + (RPL_RPC_HANDLE)ServerHandle, + InfoLevel, + (LPRPL_WKSTA_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplWkstaClone( + IN RPL_HANDLE ServerHandle, + IN LPTSTR SourceWkstaName, + IN LPTSTR TargetWkstaName, + IN LPTSTR TargetWkstaComment OPTIONAL, + IN LPTSTR TargetAdapterName, + IN DWORD TargetWkstaIpAddress + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplWkstaClone( + (RPL_RPC_HANDLE)ServerHandle, + SourceWkstaName, + TargetWkstaName, + TargetWkstaComment, + TargetAdapterName, + TargetWkstaIpAddress + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplWkstaDel( + IN RPL_HANDLE ServerHandle, + IN LPTSTR WkstaName + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplWkstaDel( + (RPL_RPC_HANDLE)ServerHandle, + WkstaName + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplWkstaEnum( + IN RPL_HANDLE ServerHandle, + IN LPTSTR ProfileName, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer, + IN DWORD PrefMaxLength, + OUT LPDWORD EntriesRead, + OUT LPDWORD TotalEntries, + OUT LPDWORD ResumeHandle + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + GENERIC_ENUM_STRUCT InfoStruct; + GENERIC_INFO_CONTAINER GenericInfoContainer; + + GenericInfoContainer.Buffer = NULL; + GenericInfoContainer.EntriesRead = 0; + + InfoStruct.Container = &GenericInfoContainer; + InfoStruct.Level = InfoLevel; + + RpcTryExcept { + status = NetrRplWkstaEnum( + (RPL_RPC_HANDLE)ServerHandle, + ProfileName, + (LPRPL_WKSTA_ENUM)&InfoStruct, + PrefMaxLength, + TotalEntries, + ResumeHandle + ); + if ( status == NERR_Success || status == ERROR_MORE_DATA) { + *PointerToBuffer = (LPBYTE)GenericInfoContainer.Buffer; + *EntriesRead = GenericInfoContainer.EntriesRead; + } + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplWkstaGetInfo( + IN RPL_HANDLE ServerHandle, + IN LPTSTR WkstaName, + IN DWORD InfoLevel, + OUT LPBYTE * PointerToBuffer + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + *PointerToBuffer = NULL; // Must be NULL so RPC knows to fill it in. + status = NetrRplWkstaGetInfo( + (RPL_RPC_HANDLE)ServerHandle, + WkstaName, + InfoLevel, + (LPRPL_WKSTA_INFO_STRUCT)PointerToBuffer + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplWkstaSetInfo( + IN RPL_HANDLE ServerHandle, + IN LPTSTR WkstaName, + IN DWORD InfoLevel, + IN LPBYTE Buffer, + OUT LPDWORD ErrorParameter OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplWkstaSetInfo( + (RPL_RPC_HANDLE)ServerHandle, + WkstaName, + InfoLevel, + (LPRPL_WKSTA_INFO_STRUCT)&Buffer, + ErrorParameter + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +NET_API_STATUS NET_API_FUNCTION +NetRplSetSecurity( + IN RPL_HANDLE ServerHandle, + IN LPTSTR WkstaName OPTIONAL, + IN DWORD WkstaRid, + IN DWORD RplUserRid + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + NET_API_STATUS status; + + RpcTryExcept { + status = NetrRplSetSecurity( + (RPL_RPC_HANDLE)ServerHandle, + WkstaName, + WkstaRid, + RplUserRid + ); + } + RpcExcept( EXCEPTION_EXECUTE_HANDLER) { + status = RplMapRpcError( RpcExceptionCode(), ERROR_INVALID_HANDLE); + } + RpcEndExcept + + return( status); +} + + +DWORD RplMapRpcError( + IN DWORD RpcError, + IN DWORD BadContextError + ) +/*++ + +Routine Description: + + This routine maps the RPC error into a more meaningful error + for the caller. + +Arguments: + + RpcError - Supplies the exception error raised by RPC + + BadContextError - Supplies the error code to return whenever an error + which indicates invalid context is received. In some cases, this + value is ERROR_INVALID_HANDLE in others, it is ERROR_INVALID_SERVICE_LOCK. + +Return Value: + + Returns the mapped error. + +--*/ +{ + switch ( RpcError) { + + case RPC_S_INVALID_BINDING: + case RPC_X_SS_IN_NULL_CONTEXT: + case RPC_X_SS_CONTEXT_DAMAGED: + case RPC_X_SS_HANDLES_MISMATCH: + case ERROR_INVALID_HANDLE: + return( BadContextError); + + case RPC_X_NULL_REF_POINTER: + return( ERROR_INVALID_PARAMETER); + + case EXCEPTION_ACCESS_VIOLATION: + return( ERROR_INVALID_ADDRESS); + + default: + return( RpcError); + } +} + diff --git a/private/net/svcdlls/rpl/client/sources b/private/net/svcdlls/rpl/client/sources new file mode 100644 index 000000000..6227f5162 --- /dev/null +++ b/private/net/svcdlls/rpl/client/sources @@ -0,0 +1,62 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Vladimir Z. Vulovic (vladimv) 27 - July - 1993 + + +Revision History: + +!ENDIF + +MAJORCOMP = net +MINORCOMP = services +TARGETNAME= rplsvc + + +NTPROFILEINPUT=YES + +TARGETPATH=obj +TARGETTYPE=LIBRARY +TARGETLIBS= + +INCLUDES=.;..\inc;..\..\..\inc;..\..\..\..\inc + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES=rplstub.c \ + rplbind.c \ + rplsvc_c.c + + +UMTYPE= console +!IF 0 +UMAPPL= rplapi +!ELSE +UMTEST= rplapi +!ENDIF +UMLIBS= \ + $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib + +C_DEFINES=-DRPC_NO_WINDOWS_H diff --git a/private/net/svcdlls/rpl/command/makefile b/private/net/svcdlls/rpl/command/makefile new file mode 100644 index 000000000..f0db8e4a7 --- /dev/null +++ b/private/net/svcdlls/rpl/command/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS LINE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/command/makefile.inc b/private/net/svcdlls/rpl/command/makefile.inc new file mode 100644 index 000000000..803916b39 --- /dev/null +++ b/private/net/svcdlls/rpl/command/makefile.inc @@ -0,0 +1,4 @@ +rplmsg.rc: msg00001.bin + +rplmsg.h msg00001.bin: rplmsg.mc + mc -v rplmsg.mc diff --git a/private/net/svcdlls/rpl/command/rplcmd.c b/private/net/svcdlls/rpl/command/rplcmd.c new file mode 100644 index 000000000..b5f2b32e9 --- /dev/null +++ b/private/net/svcdlls/rpl/command/rplcmd.c @@ -0,0 +1,2408 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rplcmd.c + +Abstract: + + This file contains program for RemoteBoot command program. + This program originated from rplapi.c in ..\client directory. + +Author: + + Vladimiv Z. Vulovic (vladimv) 19-November-1993 + +Environment: + + User Mode - Win32 + +Revision History: + +--*/ + +// +// INCLUDES +// + +#include <nt.h> // DbgPrint prototype +#include <ntrtl.h> // DbgPrint prototype +#include <nturtl.h> // Needed by winbase.h + +#include <windows.h> // DWORD, IN, File APIs, etc. + +#include <lmcons.h> // NET_API_STATUS +#include <lmerr.h> // NetError codes +#include <lmrpl.h> // RPL_HANDLE +#include <i_lmrpl.h> // RPL_CONFIG_INFO_1 +#include <lmapibuf.h> // NetApiBufferFree() +#include <stdlib.h> // exit() +#include <stdio.h> // printf +#include <ctype.h> // toupper - bombs if I use it +#include "jet.h" // JetError (for rpllib.h) + +#include "rplmsg.h" // private RPL command error codes & messages +#include "rpllib.h" // RplPrintf + +#define RPL_BUFFER_GET_ALL ((DWORD)-1) + +#if DBG +#define RPL_DEBUG +#endif // DBG + +#ifdef RPL_DEBUG +#define RplDbgPrint( _x_) printf _x_ +#define RPL_ASSERT( condition) \ + { \ + if ( !( condition)) { \ + RplDbgPrint( "File %s, Line %d\n", __FILE__, __LINE__); \ + DbgPrint( "[RplApi] File %s, Line %d\n", __FILE__, __LINE__); \ + DbgUserBreakPoint(); \ + } \ + } +#else +#define RplDbgPrint( _x_) +#define RPL_ASSERT( condition) +#endif + +#define QUESTION_SW L"/?" +#define QUESTION_SW_TOO L"-?" +#define RPL_GENERIC_ERROR 1 + +RPL_HANDLE GlobalServerHandle; +BOOL GlobalHaveServerHandle = FALSE; +PWCHAR GlobalServerName; +HANDLE GlobalMessageHandle; + + +int FileIsConsole( int fh) +{ + unsigned htype ; + + htype = GetFileType(GetStdHandle(fh)); + htype &= ~FILE_TYPE_REMOTE; + return htype == FILE_TYPE_CHAR; +} + + + +DWORD ConsolePrint( + LPWSTR pch, + int cch + ) +{ + int cchOut; + BOOL Success; + CHAR *pchOemBuffer; + + if ( cch == 0) { + return( 0); + } + + if ( FileIsConsole(STD_OUTPUT_HANDLE)) { + Success = WriteConsole( + GetStdHandle(STD_OUTPUT_HANDLE), + pch, cch, &cchOut, NULL); + if ( Success) { + return( cchOut); + } + } + + cchOut = WideCharToMultiByte( CP_OEMCP, 0, pch, cch, NULL, 0, NULL,NULL); + if (cchOut == 0) { + return 0; + } + + if ((pchOemBuffer = (CHAR *)malloc(cchOut)) != NULL) { + WideCharToMultiByte(CP_OEMCP, 0, pch, cch, + pchOemBuffer, cchOut, NULL, NULL); + WriteFile( GetStdHandle(STD_OUTPUT_HANDLE), + pchOemBuffer, cchOut, &cch, NULL); + free(pchOemBuffer); + } + + return cchOut; +} + + + +DWORD MessagePrint( + IN DWORD MessageId, + ... + ) +/*++ + +Routine Description: + + Finds the unicode message corresponding to the supplied message id, + merges it with caller supplied string(s), and prints the resulting + string. + +Arguments: + + MessageId - message id + +Return Value: + + Count of characters, not counting the terminating null character, + printed by this routine. Zero return value indicates failure. + +--*/ +{ + va_list arglist; + WCHAR * buffer = NULL; + DWORD length; + LPVOID lpSource; + DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER; + + if ( MessageId == NO_ERROR) { + return( 0); + } + + va_start( arglist, MessageId); + + if ( MessageId < NERR_BASE) { + // + // Get message from system. + // + lpSource = NULL; // redundant step according to FormatMessage() spec + dwFlags |= FORMAT_MESSAGE_FROM_SYSTEM; + + } else if ( MessageId >= IDS_LOAD_LIBRARY_FAILURE + && MessageId <= IDS_RPLSVC_LOCAL_COMPUTER ) { + // + // Get message from this module. + // + lpSource = NULL; + dwFlags |= FORMAT_MESSAGE_FROM_HMODULE; + } else { + // + // Get message from netmsg.dll. + // + lpSource = GlobalMessageHandle; + dwFlags |= FORMAT_MESSAGE_FROM_HMODULE; + } + + length = FormatMessage( + dwFlags, // dwFlags + lpSource, // lpSource + MessageId, // MessageId + 0L, // dwLanguageId + (LPTSTR)&buffer, // lpBuffer + 0, // size + &arglist // lpArguments + ); + + length = ConsolePrint(buffer, length); + + LocalFree(buffer); + + return( length); + +} // MessagePrint() + + + +BOOL ReadString( + IN DWORD MessageId, + OUT PWCHAR * pString, + IN BOOL MustHaveInput + ) +{ + BYTE Line[ 300]; + WCHAR WcharBuffer[ 300]; + DWORD Length; // includes terminal null wchar + + RplPrintf0( MessageId ); + + *pString = NULL; + + if ( gets( Line) == NULL) { + return( FALSE); + } + if ( *Line == 0) { + // + // Zero length input is OK only when input is optional (and in that + // case pointer is assumed to be NULL). + // + if ( MustHaveInput == FALSE) { + return( TRUE); + } else { + RplPrintfID( IDS_NOTSUPPLIED, MessageId ); + return( FALSE); + } + } + Length = MultiByteToWideChar( CP_OEMCP, MB_PRECOMPOSED, Line, + -1, WcharBuffer, sizeof( WcharBuffer)); + if ( Length == 0) { + RplPrintf1( IDS_INVALIDSTRING_CHARSTRINGA, (PWCHAR)Line ); + return( FALSE); + } + *pString = LocalAlloc( GMEM_FIXED, Length * sizeof(WCHAR)); + if ( *pString == NULL) { + RplDbgPrint(( "LocalAlloc failed")); + return( FALSE); + } + wcscpy( *pString, WcharBuffer); + return( TRUE); +} + + +// +// returns -1 on error, position of selection (starting from 0) otherwise +// +int ReadFromMenu( + IN DWORD MenuMessageId, + IN DWORD FilterMessageId + ) +{ + int ReturnValue = -1; + WCHAR Char = L'\0'; + PWCHAR InputBuffer = NULL; + PWCHAR FilterBuffer = NULL; + int pos; + + RplSPrintfN( FilterMessageId, NULL, 0, &FilterBuffer ); + if (FilterBuffer == NULL) { + // this should never happen + goto nomsg_cleanup; + } + + if ( !ReadString( MenuMessageId, &InputBuffer, FALSE ) ) { + goto nomsg_cleanup; + } + + if ( InputBuffer == NULL + || (*InputBuffer) == L'\0' + || !CharUpperBuff( InputBuffer, 1 ) ) { + goto cleanup; + } + Char = InputBuffer[0]; + + pos = 0; + while (FilterBuffer[pos] != L'\0') { + if (Char == FilterBuffer[pos]) { + break; + } + pos++; + } + + if (FilterBuffer[pos] == L'\0') { + goto cleanup; + } + + ReturnValue = pos; + + +cleanup: + if ( ReturnValue == -1 ) { + if (InputBuffer == NULL) { + RplPrintf2( IDS_BADMENUSEL, L"", FilterBuffer); + } else { + if (InputBuffer[0] != L'\0') { + InputBuffer[1] = L'\0'; + } + RplPrintf2( IDS_BADMENUSEL, InputBuffer, FilterBuffer); + } + } + +nomsg_cleanup: + + if (FilterBuffer != NULL) { + LocalFree( FilterBuffer ); + } + if (InputBuffer != NULL) { + LocalFree( InputBuffer ); + } + + return( ReturnValue); +} + + +BOOL ReadInt( + IN DWORD MessageId, + OUT int * pInt, + IN BOOL MustHaveInput + ) +{ + BYTE Line[ 300]; + RplPrintf0( MessageId ); + if ( gets( Line) == NULL) { + return( FALSE); + } + if ( sscanf( Line, "%d", pInt) != 1) { + if ( MustHaveInput == FALSE) { + return( TRUE); + } else { + RplPrintfID( IDS_NOTSUPPLIED, MessageId ); + return( FALSE); + } + } + return( TRUE); +} + + +BOOL ReadWkstaFlags( + OUT PDWORD pFlags + ) +{ + *pFlags = 0; + + switch( ReadFromMenu( IDS_PROMPT_MENU_WKSTA_LOGON_INPUT, + IDS_PROMPT_FILTER_WKSTA_LOGON_INPUT )) { + case 0: + *pFlags |= WKSTA_FLAGS_LOGON_INPUT_REQUIRED; + break; + case 1: + *pFlags |= WKSTA_FLAGS_LOGON_INPUT_OPTIONAL; + break; + case 2: + *pFlags |= WKSTA_FLAGS_LOGON_INPUT_IMPOSSIBLE; + break; + default: + // this really shouldn't happen; fall through + case -1: + return( FALSE); + } + + switch( ReadFromMenu( IDS_PROMPT_MENU_WKSTA_SHAREDORPRIVATE, + IDS_PROMPT_FILTER_WKSTA_SHAREDORPRIVATE )) { + case 0: + *pFlags |= WKSTA_FLAGS_SHARING_TRUE; + break; + case 1: + *pFlags |= WKSTA_FLAGS_SHARING_FALSE; + break; + default: + // this really shouldn't happen; fall through + case -1: + return( FALSE); + } + + switch( ReadFromMenu( IDS_PROMPT_MENU_WKSTA_DHCP, + IDS_PROMPT_FILTER_YN)) { + case 0: + *pFlags |= WKSTA_FLAGS_DHCP_TRUE; + break; + case 1: + *pFlags |= WKSTA_FLAGS_DHCP_FALSE; + break; + default: + // this really shouldn't happen; fall through + case -1: + return( FALSE); + } + + switch( ReadFromMenu( IDS_PROMPT_MENU_WKSTA_DELETE, + IDS_PROMPT_FILTER_YN)) { + case 0: + *pFlags |= WKSTA_FLAGS_DELETE_TRUE; + break; + case 1: + *pFlags |= WKSTA_FLAGS_DELETE_FALSE; + break; + default: + // this really shouldn't happen; fall through + case -1: + return( FALSE); + } + + return( TRUE); +} + + + +DWORD ConfigDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_CONFIG_INFO_2 Info = Buffer; + + if ( Level > 2) { + return( ERROR_INVALID_LEVEL); + } + RplPrintf1( IDS_CONFIGNAME_NOTAB, Info->ConfigName ); + RplPrintf1( IDS_CONFIGCOMMENT, Info->ConfigComment ); + if ( Level == 0) { + return( NO_ERROR); + } + switch( Info->Flags & CONFIG_FLAGS_MASK_ENABLED) { + case CONFIG_FLAGS_ENABLED_TRUE: + RplPrintf0( IDS_CONFIGENABLED ); + break; + case CONFIG_FLAGS_ENABLED_FALSE: + RplPrintf0( IDS_CONFIGDISABLED ); + break; + default: + RplPrintf1( IDS_CONFIGBADFLAGS, (PWSTR)Info->Flags ); + break; + } + if ( Level == 1) { + return( NO_ERROR); + } + RplPrintf1( IDS_BOOTNAME, Info->BootName ); + RplPrintf1( IDS_DIRNAME, Info->DirName ); + RplPrintf1( IDS_DIRNAME2, Info->DirName2 ); + RplPrintf1( IDS_DIRNAME3, Info->DirName3 ); + RplPrintf1( IDS_DIRNAME4, Info->DirName4 ); + RplPrintf1( IDS_FITSHARED, Info->FitShared ); + RplPrintf1( IDS_FITPERSONAL, Info->FitPersonal ); + return( NO_ERROR); +} + + + +VOID TestConfigEnum( + IN DWORD Level, + IN PWCHAR AdapterName, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_CONFIG_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_CONFIG_INFO_1); + break; + case 2: + CoreSize = sizeof( RPL_CONFIG_INFO_2); + break; + default: + return; + break; + } + +#ifdef RPL_DEBUG + printf( "\nConfigEnum: Level=%d", Level); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + printf( ", PrefMaxLength=%ld", PrefMaxLength); + } else { + RplDbgPrint(( ", unlimited buffer size")); + } + if ( AdapterName != NULL) { + RplDbgPrint(( ", AdapterName=%ws", AdapterName)); + } + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle=0x%x\n\n", *pResumeHandle)); + } else { + RplDbgPrint(( ", not resumable.\n\n")); + } +#endif + + for ( ; ; ) { + Error = NetRplConfigEnum( GlobalServerHandle, AdapterName, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + MessagePrint( Error); + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries)); + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle = 0x%x\n", *pResumeHandle)); + } else { + RplDbgPrint(("\n")); + } +#endif + + for ( index = 0; index < EntriesRead; index++) { + ConfigDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + if ( Error != NO_ERROR) { + MessagePrint( Error); + } + break; + } + if ( Error != ERROR_MORE_DATA) { + MessagePrint( Error); + MessagePrint( IDS_UNEXPECTED_RETURN_CODE, Error); + break; + } + } +} + +#define PROFILE_FLAGS_DISK_PRESENT_TRUE ((DWORD)0x00000001) +#define PROFILE_FLAGS_DISK_PRESENT_FALSE ((DWORD)0x00000002) +#define PROFILE_FLAGS_MASK_DISK_PRESENT \ + ( PROFILE_FLAGS_DISK_PRESENT_FALSE | \ + PROFILE_FLAGS_DISK_PRESENT_TRUE ) + +typedef enum _DISPLAY_ACTION { + DisplayActionSetInfo = 0, + DisplayActionGetInfo +} DISPLAY_ACTION; + + +DWORD ProfileDisplayInfo( + IN BOOL SetInfo, + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_PROFILE_INFO_2 Info = Buffer; + + if ( Level > 2) { + return( ERROR_INVALID_LEVEL); + } + RplPrintf1(IDS_PROFILENAME_NOTAB, Info->ProfileName ); + RplPrintf1(IDS_PROFILECOMMENT, Info->ProfileComment ); + if ( Level == 0) { + return( NO_ERROR); + } + switch( Info->Flags & PROFILE_FLAGS_MASK_DISK_PRESENT) { + case PROFILE_FLAGS_DISK_PRESENT_TRUE: + break; // do not report anything if all is good + case PROFILE_FLAGS_DISK_PRESENT_FALSE: + RplPrintf0( IDS_PROFILENODISKTREE ); + break; + case 0: + // + // 0 is OK value for SetInfo, but not for Add & GetInfo + // + if ( SetInfo == TRUE) { + break; + } + default: + RplPrintf1( IDS_PROFILEBADFLAGS, (LPWSTR)Info->Flags); + break; + } + if ( Level == 1) { + return( NO_ERROR); + } + RplPrintf1( IDS_CONFIGNAME, Info->ConfigName ); + RplPrintf1( IDS_BOOTNAME, Info->BootName ); + RplPrintf1( IDS_FITSHARED, Info->FitShared ); + RplPrintf1( IDS_FITPERSONAL, Info->FitPersonal ); + return( NO_ERROR); +} + + + +VOID TestProfileEnum( + IN DWORD Level, + IN PWCHAR AdapterName, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_PROFILE_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_PROFILE_INFO_1); + break; + case 2: + CoreSize = sizeof( RPL_PROFILE_INFO_2); + break; + default: + return; + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nProfileEnum: Level=%d", Level)); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + RplDbgPrint(( ", PrefMaxLength=%ld", PrefMaxLength)); + } else { + RplDbgPrint(( ", unlimited buffer size")); + } + if ( AdapterName != NULL) { + RplDbgPrint(( ", AdapterName=%ws", AdapterName)); + } + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle=0x%x\n\n", *pResumeHandle)); + } else { + RplDbgPrint(( ", not resumable.\n\n")); + } +#endif + + for ( ; ; ) { + Error = NetRplProfileEnum( GlobalServerHandle, AdapterName, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + MessagePrint( Error); + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries)); + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle = 0x%x\n", *pResumeHandle)); + } else { + RplDbgPrint(("\n")); + } +#endif + + for ( index = 0; index < EntriesRead; index++) { + ProfileDisplayInfo( FALSE, Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + if ( Error != NO_ERROR) { + MessagePrint( Error); + } + break; + } + if ( Error != ERROR_MORE_DATA) { + MessagePrint( Error); + MessagePrint( IDS_UNEXPECTED_RETURN_CODE, Error); + break; + } + } +} + + +DWORD ServiceDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_INFO_0 Info = Buffer; + + if ( Level > 0) { + return( ERROR_INVALID_LEVEL); + } + switch( Info->Flags) { + case 0: + break; + default: + RplPrintf1( IDS_SERVICEBADFLAGS, (PWCHAR)Info->Flags); + } + return( NO_ERROR); +} + + + +DWORD WkstaDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_WKSTA_INFO_2 Info = Buffer; + + if ( Level > 2) { + return( ERROR_INVALID_LEVEL); + } + RplPrintf1( IDS_WKSTANAME_NOTAB, Info->WkstaName ); + RplPrintf1( IDS_WKSTACOMMENT, Info->WkstaComment ); + if ( Level == 0) { + return( NO_ERROR); + } + switch( Info->Flags & WKSTA_FLAGS_MASK_LOGON_INPUT) { + case WKSTA_FLAGS_LOGON_INPUT_REQUIRED: + RplPrintf0( IDS_WKSTALOGONREQD ); + break; + case WKSTA_FLAGS_LOGON_INPUT_OPTIONAL: + RplPrintf0( IDS_WKSTALOGONOPT ); + break; + case WKSTA_FLAGS_LOGON_INPUT_IMPOSSIBLE: + RplPrintf0( IDS_WKSTALOGONNONE ); + break; + default: + RplPrintf1( IDS_WKSTALOGONBADFLAGS, (LPWSTR)Info->Flags ); + break; + } + switch( Info->Flags & WKSTA_FLAGS_MASK_SHARING) { + case WKSTA_FLAGS_SHARING_TRUE: + RplPrintf0( IDS_WKSTASHARINGTRUE ); + break; + case WKSTA_FLAGS_SHARING_FALSE: + RplPrintf0( IDS_WKSTASHARINGFALSE ); + break; + default: + RplPrintf1( IDS_WKSTASHARINGBADFLAGS, (LPWSTR)Info->Flags ); + break; + } + switch( Info->Flags & WKSTA_FLAGS_MASK_DHCP) { + case WKSTA_FLAGS_DHCP_TRUE: + RplPrintf0( IDS_WKSTA_DHCP_TRUE); + break; + case WKSTA_FLAGS_DHCP_FALSE: + RplPrintf0( IDS_WKSTA_DHCP_FALSE); + break; + default: + RplPrintf1( IDS_WKSTA_DHCP_BAD_FLAGS, (LPWSTR)Info->Flags ); + break; + } + switch( Info->Flags & WKSTA_FLAGS_MASK_DELETE) { + case WKSTA_FLAGS_DELETE_TRUE: + RplPrintf0( IDS_WKSTA_DELETE_TRUE); + break; + case WKSTA_FLAGS_DELETE_FALSE: + RplPrintf0( IDS_WKSTA_DELETE_FALSE); + break; + default: + RplPrintf1( IDS_WKSTA_DELETE_BAD_FLAGS, (LPWSTR)Info->Flags ); + break; + } + RplPrintf1( IDS_WKSTAINPROFILE, Info->ProfileName); + if ( Level == 1) { + return( NO_ERROR); + } + RplPrintf1( IDS_BOOTNAME, Info->BootName); + RplPrintf1( IDS_FITFILE, Info->FitFile); + RplPrintf1( IDS_WKSTAADAPTER, Info->AdapterName); + RplPrintf1( IDS_TCPIPADDRESS, (LPWSTR)Info->TcpIpAddress); + RplPrintf1( IDS_TCPIPSUBNET, (LPWSTR)Info->TcpIpSubnet); + RplPrintf1( IDS_TCPIPGATEWAY, (LPWSTR)Info->TcpIpGateway); + return( NO_ERROR); +} + + + +VOID TestWkstaEnum( + IN DWORD Level, + IN PWCHAR ProfileName, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_WKSTA_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_WKSTA_INFO_1); + break; + case 2: + CoreSize = sizeof( RPL_WKSTA_INFO_2); + break; + default: + return; + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nWkstaEnum: Level=%d", Level)); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + RplDbgPrint(( ", PrefMaxLength=%ld", PrefMaxLength)); + } else { + RplDbgPrint(( ", unlimited buffer size")); + } + if ( ProfileName != NULL) { + RplDbgPrint(( ", ProfileName=%ws", ProfileName)); + } + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle=0x%x\n\n", *pResumeHandle)); + } else { + RplDbgPrint(( ", not resumable.\n\n")); + } +#endif + + for ( ; ; ) { + Error = NetRplWkstaEnum( GlobalServerHandle, ProfileName, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + MessagePrint( Error); + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries)); + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle = 0x%x\n", *pResumeHandle)); + } else { + RplDbgPrint(("\n")); + } +#endif + + for ( index = 0; index < EntriesRead; index++) { + WkstaDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + if ( Error != NO_ERROR) { + MessagePrint( Error); + } + break; + } + if ( Error != ERROR_MORE_DATA) { + MessagePrint( Error); + MessagePrint( IDS_UNEXPECTED_RETURN_CODE, Error); + break; + } + } +} + + +DWORD VendorDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_VENDOR_INFO_1 Info = Buffer; + + if ( Level > 1) { + return( ERROR_INVALID_LEVEL); + } + RplPrintf1( IDS_VENDORNAME_NOTAB, Info->VendorName ); + RplPrintf1( IDS_VENDORCOMMENT, Info->VendorComment ); + if ( Level == 0) { + return( NO_ERROR); + } + switch( Info->Flags) { + case 0: + break; + default: + RplPrintf1( IDS_VENDORBADFLAGS, (LPWSTR)Info->Flags); + } + return( NO_ERROR); +} + + + +DWORD BootDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_BOOT_INFO_2 Info = Buffer; + + if ( Level > 2) { + return( ERROR_INVALID_LEVEL); + } + RplPrintf1( IDS_BOOTNAME_NOTAB, Info->BootName); + RplPrintf1( IDS_BOOTCOMMENT, Info->BootComment); + if ( Level == 0) { + return( NO_ERROR); + } + switch( Info->Flags & BOOT_FLAGS_MASK_FINAL_ACKNOWLEDGMENT) { + case BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_TRUE: + RplPrintf0( IDS_BOOTACK_TRUE ); + break; + case BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_FALSE: + RplPrintf0( IDS_BOOTACK_FALSE ); + break; + default: + RplPrintf1( IDS_BOOTBADFLAGS, (LPWSTR)Info->Flags); + break; + } + RplPrintf1( IDS_VENDORNAME, Info->VendorName); + if ( Level == 1) { + return( NO_ERROR); + } + RplPrintf1( IDS_BBCFILE, Info->BbcFile); + RplPrintf1( IDS_WINDOWSIZE, (LPWSTR)Info->WindowSize); + return( NO_ERROR); +} + + + +DWORD AdapterDisplayInfo( + IN DWORD Level, + OUT LPVOID Buffer + ) +{ + LPRPL_ADAPTER_INFO_1 Info = Buffer; + + if ( Level > 1) { + return( ERROR_INVALID_LEVEL); + } + RplPrintf1( IDS_ADAPTERNAME_NOTAB, Info->AdapterName); + RplPrintf1( IDS_ADAPTERCOMMENT, Info->AdapterComment); + if ( Level == 0) { + return( NO_ERROR); + } + switch( Info->Flags) { + case 0: + break; + default: + RplPrintf1( IDS_ADAPTERBADFLAGS, (LPWSTR)Info->Flags); + } + return( NO_ERROR); +} + + + +VOID TestAdapterEnum( + IN DWORD Level, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_ADAPTER_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_ADAPTER_INFO_1); + break; + default: + return; + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nAdapterEnum: Level=%d", Level)); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + RplDbgPrint(( ", PrefMaxLength=%ld", PrefMaxLength)); + } else { + RplDbgPrint(( ", unlimited buffer size")); + } + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle=0x%x\n\n", *pResumeHandle)); + } else { + RplDbgPrint(( ", not resumable.\n\n")); + } +#endif + + for ( ; ; ) { + Error = NetRplAdapterEnum( GlobalServerHandle, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + MessagePrint( Error); + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries)); + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle = 0x%x\n", *pResumeHandle)); + } else { + RplDbgPrint(("\n")); + } +#endif + + for ( index = 0; index < EntriesRead; index++) { + AdapterDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + if ( Error != NO_ERROR) { + MessagePrint( Error); + } + break; + } + if ( Error != ERROR_MORE_DATA) { + MessagePrint( Error); + MessagePrint( IDS_UNEXPECTED_RETURN_CODE, Error); + break; + } + } +} + + +VOID TestAdapterAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestAdapterAdd\n")); + AdapterDisplayInfo( 1, Buffer); +#endif + Error = NetRplAdapterAdd( GlobalServerHandle, 1, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } +} + + +VOID AdapterAdd( VOID) +{ + RPL_ADAPTER_INFO_1 Info; + + if ( !ReadString( IDS_PROMPT_ADAPTERNAME, &Info.AdapterName, TRUE)) { + return; + } + Info.Flags = 0; + RplPrintf0( IDS_PARAMETERSOPTIONAL ); + if ( !ReadString( IDS_PROMPT_ADAPTERCOMMENT, &Info.AdapterComment, FALSE)) { + return; + } + TestAdapterAdd( &Info); +} + + +VOID TestBootAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestBootAdd\n")); + BootDisplayInfo( 2, Buffer); +#endif + Error = NetRplBootAdd( GlobalServerHandle, 2, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } +} + + +VOID BootAdd( VOID) +{ + RPL_BOOT_INFO_2 Info; + + if ( !ReadString( IDS_PROMPT_BOOTNAME, &Info.BootName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_VENDORNAME, &Info.VendorName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_BBCFILE, &Info.BbcFile, TRUE)) { + return; + } + Info.Flags = BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_TRUE; + RplPrintf0( IDS_PARAMETERSOPTIONAL ); + if ( !ReadString( IDS_PROMPT_BOOTCOMMENT, &Info.BootComment, FALSE)) { + return; + } + Info.WindowSize = 0; + if ( !ReadInt( IDS_PROMPT_WINDOWSIZE, &Info.WindowSize, FALSE)) { + return; + } + TestBootAdd( &Info); +} + + +VOID BootDel( VOID) +{ + PWCHAR BootName; + PWCHAR VendorName; + DWORD Error; + + if ( !ReadString( IDS_PROMPT_BOOTNAME, &BootName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_VENDORNAME, &VendorName, TRUE)) { + return; + } + Error = NetRplBootDel( GlobalServerHandle, BootName, VendorName); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } +} + + +VOID TestBootEnum( + IN DWORD Level, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_BOOT_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_BOOT_INFO_1); + break; + case 2: + CoreSize = sizeof( RPL_BOOT_INFO_2); + break; + default: + return; + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestBootEnum: Level=%d", Level)); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + RplDbgPrint(( ", PrefMaxLength=%ld", PrefMaxLength)); + } else { + RplDbgPrint(( ", unlimited buffer size")); + } + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle=0x%x\n\n", *pResumeHandle)); + } else { + RplDbgPrint(( ", not resumable.\n\n")); + } +#endif + + for ( ; ; ) { + Error = NetRplBootEnum( GlobalServerHandle, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + MessagePrint( Error); + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries)); + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle = 0x%x\n", *pResumeHandle)); + } else { + RplDbgPrint(("\n")); + } +#endif + + for ( index = 0; index < EntriesRead; index++) { + BootDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + if ( Error != NO_ERROR) { + MessagePrint( Error); + } + break; + } + if ( Error != ERROR_MORE_DATA) { + MessagePrint( Error); + MessagePrint( IDS_UNEXPECTED_RETURN_CODE, Error); + break; + } + } +} + + +VOID BootEnum( VOID) +{ + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + + if ( !ReadInt( IDS_PROMPT_LEVEL012, &Level, TRUE) || Level > 2) { + return; + } +#ifdef RPL_DEBUG + if ( !ReadInt( IDS_PROMPT_PREFMAXLENGTH_DEBUG, &PrefMaxLength, TRUE)) { + return; + } +#else + PrefMaxLength = RPL_BUFFER_GET_ALL; +#endif + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestBootEnum( Level, PrefMaxLength, &ResumeHandle); + } else { + TestBootEnum( Level, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID TestConfigAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestConfigAdd\n")); + ConfigDisplayInfo( 2, Buffer); +#endif + Error = NetRplConfigAdd( GlobalServerHandle, 2, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + RplDbgPrint(( "ErrorParameter = %d\n", ErrorParameter)); + return; + } +} + + +VOID ConfigAdd( VOID) +{ + RPL_CONFIG_INFO_2 Info; + + if ( !ReadString( IDS_PROMPT_CONFIGNAME, &Info.ConfigName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_BOOTNAME, &Info.BootName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_DIRNAME, &Info.DirName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_DIRNAME2, &Info.DirName2, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_FITSHARED, &Info.FitShared, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_FITPERSONAL, &Info.FitPersonal, TRUE)) { + return; + } + Info.Flags = 0; + RplPrintf0( IDS_PARAMETERSOPTIONAL ); + if ( !ReadString( IDS_PROMPT_CONFIGCOMMENT, &Info.ConfigComment, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_DIRNAME3, &Info.DirName3, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_DIRNAME4, &Info.DirName4, FALSE)) { + return; + } + TestConfigAdd( &Info); +} + + +VOID ConfigDel( VOID) +{ + PWCHAR ConfigName; + DWORD Error; + + if ( !ReadString( IDS_PROMPT_CONFIGNAME, &ConfigName, FALSE)) { + return; + } + Error = NetRplConfigDel( GlobalServerHandle, ConfigName); + if ( Error != 0) { + MessagePrint( Error); + } +} + + +VOID TestVendorAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestVendorAdd\n")); + VendorDisplayInfo( 1, Buffer); +#endif + Error = NetRplVendorAdd( GlobalServerHandle, 1, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + RplDbgPrint(( "ErrorParameter = %d\n", ErrorParameter)); + return; + } +} + + +VOID VendorAdd( VOID) +{ + RPL_VENDOR_INFO_1 Info; + + if ( !ReadString( IDS_PROMPT_VENDORNAME, &Info.VendorName, TRUE)) { + return; + } + Info.Flags = 0; + RplPrintf0( IDS_PARAMETERSOPTIONAL ); + if ( !ReadString( IDS_PROMPT_VENDORCOMMENT, &Info.VendorComment, FALSE)) { + return; + } + TestVendorAdd( &Info); +} + + +VOID VendorDel( VOID) +{ + PWCHAR VendorName; + DWORD Error; + + if ( !ReadString( IDS_PROMPT_VENDORNAME, &VendorName, FALSE)) { + return; + } + Error = NetRplVendorDel( GlobalServerHandle, VendorName); + if ( Error != 0) { + MessagePrint( Error); + } +} + + +VOID TestVendorEnum( + IN DWORD Level, + IN DWORD PrefMaxLength, + IN PDWORD pResumeHandle + ) +{ + LPBYTE Buffer; + DWORD EntriesRead; + DWORD TotalEntries; + DWORD CoreSize; + DWORD index; + DWORD Error; + + switch( Level) { + case 0: + CoreSize = sizeof( RPL_VENDOR_INFO_0); + break; + case 1: + CoreSize = sizeof( RPL_VENDOR_INFO_1); + break; + default: + return; + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestVendorEnum: Level=%d", Level)); + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + RplDbgPrint(( ", PrefMaxLength=%ld", PrefMaxLength)); + } else { + RplDbgPrint(( ", unlimited buffer size")); + } + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle=0x%x\n\n", *pResumeHandle)); + } else { + RplDbgPrint(( ", not resumable.\n\n")); + } +#endif + + for ( ; ; ) { + Error = NetRplVendorEnum( GlobalServerHandle, Level, &Buffer, + PrefMaxLength, &EntriesRead, &TotalEntries, pResumeHandle); + + if ( Error != NO_ERROR && Error != ERROR_MORE_DATA) { + MessagePrint( Error); + break; + } + +#ifdef RPL_DEBUG + RplDbgPrint(( "Buffer = 0x%x, EntriesRead = %d, TotalEntries = %d", Buffer, + EntriesRead, TotalEntries)); + if ( pResumeHandle != NULL) { + RplDbgPrint(( ", ResumeHandle = 0x%x\n", *pResumeHandle)); + } else { + RplDbgPrint(("\n")); + } +#endif + + for ( index = 0; index < EntriesRead; index++) { + VendorDisplayInfo( Level, Buffer + index * CoreSize); + } + NetApiBufferFree( Buffer); // =~ MIDL_user_free() + + if ( pResumeHandle == NULL) { + break; + } + if ( *pResumeHandle == 0) { + if ( Error != NO_ERROR) { + MessagePrint( Error); + } + break; + } + if ( Error != ERROR_MORE_DATA) { + MessagePrint( Error); + MessagePrint( IDS_UNEXPECTED_RETURN_CODE, Error); + break; + } + } +} + + +VOID VendorEnum( VOID) +{ + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + +#ifdef RPL_DEBUG + if ( !ReadInt( IDS_PROMPT_LEVEL01, &Level, TRUE) || Level > 1) { + return; + } + if ( !ReadInt( IDS_PROMPT_PREFMAXLENGTH_DEBUG, &PrefMaxLength, TRUE)) { + return; + } +#else + Level = 0; + PrefMaxLength = RPL_BUFFER_GET_ALL; +#endif + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestVendorEnum( Level, PrefMaxLength, &ResumeHandle); + } else { + TestVendorEnum( Level, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID TestProfileAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestProfileAdd\n")); + ProfileDisplayInfo( FALSE, 2, Buffer); +#endif + Error = NetRplProfileAdd( GlobalServerHandle, 2, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + RplDbgPrint(( "ErrorParameter = %d\n", ErrorParameter)); + return; + } +} + + +VOID TestProfileGetInfo( + IN DWORD Level, + IN PWCHAR ProfileName + ) +{ + LPBYTE Buffer; + DWORD Error; + Error = NetRplProfileGetInfo( GlobalServerHandle, ProfileName, Level, &Buffer); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } + ProfileDisplayInfo( FALSE, Level, Buffer); + NetApiBufferFree( Buffer); // =~ MIDL_user_free() +} + + +VOID TestProfileSetInfo( + IN DWORD Level, + IN PWCHAR ProfileName, + IN LPVOID Buffer + ) +{ + DWORD Error; + DWORD ErrorParameter; +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestProfileSetInfo: Level=%d, ProfileName=%ws\n", Level, ProfileName)); + ProfileDisplayInfo( TRUE, Level, Buffer); +#endif + Error = NetRplProfileSetInfo( GlobalServerHandle, ProfileName, Level, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + RplDbgPrint(( "ErrorParameter = %d\n", ErrorParameter)); + return; + } +} + + +VOID TestWkstaAdd( IN LPVOID Buffer) +{ + DWORD Error; + DWORD ErrorParameter; + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nTestWkstaAdd\n")); + WkstaDisplayInfo( 2, Buffer); +#endif + Error = NetRplWkstaAdd( GlobalServerHandle, 2, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + RplDbgPrint(( "ErrorParameter = %d\n", ErrorParameter)); + return; + } +} + + +VOID TestWkstaGetInfo( + IN DWORD Level, + IN PWCHAR WkstaName + ) +{ + LPBYTE Buffer; + DWORD Error; + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nWkstaGetInfo: Level=%d, WkstaName=%ws\n", Level, WkstaName)); +#endif + Error = NetRplWkstaGetInfo( GlobalServerHandle, WkstaName, Level, &Buffer); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } + WkstaDisplayInfo( Level, Buffer); + NetApiBufferFree( Buffer); // =~ MIDL_user_free() +} + + +VOID TestWkstaSetInfo( + IN DWORD Level, + IN PWCHAR WkstaName, + IN LPVOID Buffer + ) +{ + DWORD Error; + DWORD ErrorParameter; + +#ifdef RPL_DEBUG + RplDbgPrint(( "\nWkstaSetInfo: Level=%d, WkstaName=%ws\n", Level, WkstaName)); + WkstaDisplayInfo( Level, Buffer); +#endif + Error = NetRplWkstaSetInfo( GlobalServerHandle, WkstaName, Level, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + RplDbgPrint(( "ErrorParameter = %d\n", ErrorParameter)); + return; + } +} + + +VOID AdapterDel( VOID) +{ + PWCHAR AdapterName; + DWORD Error; + + if ( !ReadString( IDS_PROMPT_ADAPTERNAME, &AdapterName, FALSE)) { + return; + } + if ( AdapterName == NULL) { + switch ( ReadFromMenu( IDS_PROMPT_MENU_ADAPTERDELETEALL, + IDS_PROMPT_FILTER_YN) ) { + case 0: + break; + case 1: + default: + return; + } + } + + Error = NetRplAdapterDel( GlobalServerHandle, AdapterName); + if ( Error != 0) { + MessagePrint( Error); + } +} + + +VOID AdapterEnum( VOID) +{ + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + +#ifdef RPL_DEBUG + if ( !ReadInt( IDS_PROMPT_LEVEL01, &Level, TRUE) || Level > 1) { + return; + } + if ( !ReadInt( IDS_PROMPT_PREFMAXLENGTH_DEBUG, &PrefMaxLength, TRUE)) { + return; + } +#else + Level = 0; + PrefMaxLength = RPL_BUFFER_GET_ALL; +#endif + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestAdapterEnum( Level, PrefMaxLength, &ResumeHandle); + } else { + TestAdapterEnum( Level, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID ConfigEnum( VOID) +{ + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + PWCHAR AdapterName; + + if ( !ReadInt( IDS_PROMPT_LEVEL012, &Level, TRUE) || Level > 2) { + return; + } +#ifdef RPL_DEBUG + if ( !ReadInt( IDS_PROMPT_PREFMAXLENGTH_DEBUG, &PrefMaxLength, TRUE)) { + return; + } +#else + PrefMaxLength = RPL_BUFFER_GET_ALL; +#endif + if( !ReadString( IDS_PROMPT_ADAPTERNAME_COMPATCONFIG, &AdapterName, FALSE)) { + return; + } + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestConfigEnum( Level, AdapterName, PrefMaxLength, &ResumeHandle); + } else { + TestConfigEnum( Level, AdapterName, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID ProfileAdd( VOID) +{ + RPL_PROFILE_INFO_2 Info; + + if ( !ReadString( IDS_PROMPT_PROFILENAME, &Info.ProfileName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_CONFIGNAME, &Info.ConfigName, TRUE)) { + return; + } + Info.Flags = 0; + RplPrintf0( IDS_PARAMETERSOPTIONAL ); + if ( !ReadString( IDS_PROMPT_PROFILECOMMENT, &Info.ProfileComment, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_BOOTNAME, &Info.BootName, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_FITSHARED, &Info.FitShared, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_FITPERSONAL, &Info.FitPersonal, FALSE)) { + return; + } + TestProfileAdd( &Info); +} + + +VOID ProfileClone( VOID) +{ + PWCHAR SourceProfileName; + PWCHAR TargetProfileName; + PWCHAR TargetProfileComment; + DWORD Error; + + if ( !ReadString( IDS_PROMPT_PROFILENAME_SOURCE, &SourceProfileName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_PROFILENAME_TARGET, &TargetProfileName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_PROFILECOMMENT_TARGET, &TargetProfileComment, FALSE)) { + return; + } + Error = NetRplProfileClone( GlobalServerHandle, SourceProfileName, + TargetProfileName, TargetProfileComment); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } +} + + +VOID ProfileDel( VOID) +{ + PWCHAR ProfileName; + DWORD Error; + + if ( !ReadString( IDS_PROMPT_PROFILENAME, &ProfileName, TRUE)) { + return; + } + Error = NetRplProfileDel( GlobalServerHandle, ProfileName); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } +} + + +VOID ProfileEnum( VOID) +{ + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + PWCHAR AdapterName; + + if ( !ReadInt( IDS_PROMPT_LEVEL012, &Level, TRUE) || Level > 2) { + return; + } +#ifdef RPL_DEBUG + if ( !ReadInt( IDS_PROMPT_PREFMAXLENGTH_DEBUG, &PrefMaxLength, TRUE)) { + return; + } +#else + PrefMaxLength = RPL_BUFFER_GET_ALL; +#endif + if( !ReadString( IDS_PROMPT_ADAPTERNAME_COMPATPROF, &AdapterName, FALSE)) { + return; + } + if ( PrefMaxLength != RPL_BUFFER_GET_ALL) { + ResumeHandle = 0, TestProfileEnum( Level, AdapterName, PrefMaxLength, &ResumeHandle); + } else { + TestProfileEnum( Level, AdapterName, RPL_BUFFER_GET_ALL, NULL); + } +} + + +VOID ProfileGetInfo( VOID) +{ + BYTE Line[ 300]; + WCHAR ProfileName[ 20]; + CHAR ProfileNameA[ 20]; + DWORD Length; + DWORD Count; + DWORD Level; + + RplPrintf0( IDS_PROMPT_PROFILENAME_INFOLEVEL ); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %s", &Level, ProfileNameA); + if ( Count != 2) { + RplPrintf0( IDS_BADARGCOUNT ); + return; + } + Length = MultiByteToWideChar( CP_OEMCP, MB_PRECOMPOSED, ProfileNameA, -1, + ProfileName, sizeof( ProfileName)); + if ( Length == 0) { + RplPrintf1( IDS_INVALIDSTRING_CHARSTRINGA, (LPWSTR)ProfileNameA); + return; + } + TestProfileGetInfo( Level, ProfileName); +} + + +VOID ProfileSetInfo( VOID) +{ + PWCHAR ProfileName; + DWORD Level; + RPL_PROFILE_INFO_2 Info; + LPVOID Buffer; + + Buffer = &Info; + if ( !ReadInt( IDS_PROMPT_LEVEL012, &Level, TRUE) || Level > 2) { + return; + } + if ( !ReadString( IDS_PROMPT_PROFILENAME_INPUT, &ProfileName, TRUE)) { + return; + } + RplPrintf0( IDS_INPUTPROFILEPROPERTIES ); + Info.ProfileName = NULL; + // ReadString( "ProfileName", &Info.ProfileName); + if ( !ReadString( IDS_PROMPT_PROFILECOMMENT, &Info.ProfileComment, FALSE)) { + return; + } + if ( Level == 0) { + goto testit; + } + Info.Flags = 0; + if ( Level == 1) { + goto testit; + } + Info.ConfigName = NULL; + // ReadString( IDS_PROMPT_CONFIGNAME, &Info.ConfigName, FALSE)) { + if ( !ReadString( IDS_PROMPT_BOOTNAME, &Info.BootName, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_FITSHARED, &Info.FitShared, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_FITPERSONAL, &Info.FitPersonal, FALSE)) { + return; + } +testit: + TestProfileSetInfo( Level, ProfileName, Buffer); +} + + +VOID ServiceClose( VOID) +{ + DWORD Error; + + if ( GlobalHaveServerHandle == FALSE) { + RplPrintf0( IDS_NOSERVICEHANDLE ); + return; + } + Error = NetRplClose( GlobalServerHandle); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } + LocalFree( GlobalServerName); // OK if NULL pointer + GlobalHaveServerHandle = FALSE; +} + + +VOID ServiceGetInfo( VOID) +{ + LPBYTE Buffer; + DWORD Error; + Error = NetRplGetInfo( GlobalServerHandle, 0, &Buffer); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } + if ( GlobalServerName == NULL) { + RplPrintf0( IDS_RPLSVC_LOCAL_COMPUTER); + } else { + RplPrintf1( IDS_RPLSVC_COMPUTER, GlobalServerName); + } + ServiceDisplayInfo( 0, Buffer); + NetApiBufferFree( Buffer); // =~ MIDL_user_free() +} + + +VOID ServiceOpen( VOID) +{ + DWORD Error; + + if ( GlobalHaveServerHandle == TRUE) { + RplPrintf0( IDS_MUSTCLOSEHANDLE ); + return; + } + if ( !ReadString( IDS_PROMPT_SERVERNAME, &GlobalServerName, FALSE)) { + return; + } + Error = NetRplOpen( GlobalServerName, &GlobalServerHandle); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } + GlobalHaveServerHandle = TRUE; +} + + +BOOL ReadServiceFlags( + OUT PDWORD pFlags + ) +{ + *pFlags = 0; + + switch( ReadFromMenu( IDS_PROMPT_MENU_SERVICE_SECURITY, + IDS_PROMPT_FILTER_YN)) { + case 0: + *pFlags |= RPL_CHECK_SECURITY; + break; + case 1: + break; + default: + // this really shouldn't happen; fall through + case -1: + return( FALSE); + } + + switch( ReadFromMenu( IDS_PROMPT_MENU_SERVICE_CONFIGS, + IDS_PROMPT_FILTER_YN)) { + case 0: + *pFlags |= RPL_CHECK_CONFIGS; + break; + case 1: + break; + default: + // this really shouldn't happen; fall through + case -1: + return( FALSE); + } + +#ifdef NOT_YET + switch( ReadFromMenu( IDS_PROMPT_MENU_SERVICE_RPLDISK, + IDS_PROMPT_FILTER_SERVICE_RPLDISK )) { + case 0: + *pFlags |= RPL_REPLACE_RPLDISK; + break; + case 1: + break; + default: + // this really shouldn't happen; fall through + case -1: + return( FALSE); + } +#endif + + switch( ReadFromMenu( IDS_PROMPT_MENU_SERVICE_BACKUP, + IDS_PROMPT_FILTER_YN)) { + case 0: + *pFlags |= RPL_BACKUP_DATABASE; + break; + case 1: + break; + default: + // this really shouldn't happen; fall through + case -1: + return( FALSE); + } + + return( TRUE); +} + + + +VOID ServiceSetInfo( VOID) +{ + DWORD Level; + LPVOID Buffer; + DWORD Error; + DWORD ErrorParameter; + + Level = 0; + +#ifdef RPL_DEBUG + if ( !ReadInt( IDS_PROMPT_LEVEL_DEBUG, &Level, FALSE)) { + return; + } +#endif + + switch( Level) { + case 0: { + RPL_INFO_0 Info; + Buffer = &Info; + if ( !ReadServiceFlags( &Info.Flags)) { + return; + } + break; + } + default: + return; + break; + } + Error = NetRplSetInfo( GlobalServerHandle, 0, Buffer, &ErrorParameter); + if ( Error != NO_ERROR) { + MessagePrint( Error); + RplDbgPrint(( "ErrorParameter = %d\n", ErrorParameter)); + return; + } +} + + +VOID WkstaAdd( VOID) +{ + RPL_WKSTA_INFO_2 Info; + + if ( !ReadString( IDS_PROMPT_WKSTANAME, &Info.WkstaName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_PROFILENAME, &Info.ProfileName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_ADAPTERNAME, &Info.AdapterName, TRUE)) { + return; + } + if ( !ReadWkstaFlags( &Info.Flags)) { + return; + } + RplPrintf0( IDS_PARAMETERSOPTIONAL ); + if ( !ReadString( IDS_PROMPT_WKSTACOMMENT, &Info.WkstaComment, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_BOOTNAME, &Info.BootName, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_FITFILE, &Info.FitFile, FALSE)) { + return; + } + Info.TcpIpAddress = (DWORD)-1; + if ( !ReadInt( IDS_PROMPT_TCPIPADDRESS, &Info.TcpIpAddress, FALSE)) { + return; + } + Info.TcpIpSubnet = (DWORD)-1; + if ( !ReadInt( IDS_PROMPT_TCPIPSUBNET, &Info.TcpIpSubnet, FALSE)) { + return; + } + Info.TcpIpGateway = (DWORD)-1; + if ( !ReadInt( IDS_PROMPT_TCPIPGATEWAY, &Info.TcpIpGateway, FALSE)) { + return; + } + TestWkstaAdd( &Info); +} + + +VOID WkstaClone( VOID) +{ + PWCHAR SourceWkstaName; + PWCHAR TargetWkstaName; + PWCHAR TargetWkstaComment; + PWCHAR TargetAdapterName; + DWORD TargetTcpIpAddress; + DWORD Error; + + if ( !ReadString( IDS_PROMPT_WKSTANAME_SOURCE, &SourceWkstaName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_WKSTANAME_TARGET, &TargetWkstaName, TRUE)) { + return; + } + if ( !ReadString( IDS_PROMPT_ADAPTERNAME_TARGET, &TargetAdapterName, TRUE)) { + return; + } + RplPrintf0( IDS_PARAMETERSOPTIONAL ); + if ( !ReadString( IDS_PROMPT_WKSTACOMMENT_TARGET, &TargetWkstaComment, FALSE)) { + return; + } + TargetTcpIpAddress = (DWORD)-1; + if( !ReadInt( IDS_PROMPT_TCPIPADDRESS, &TargetTcpIpAddress, FALSE)) { + return; + } + Error = NetRplWkstaClone( GlobalServerHandle, SourceWkstaName, + TargetWkstaName, TargetWkstaComment, TargetAdapterName, TargetTcpIpAddress); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } +} + + +VOID WkstaDel( VOID) +{ + PWCHAR WkstaName; + DWORD Error; + + if ( !ReadString( IDS_PROMPT_WKSTANAME, &WkstaName, TRUE)) { + return; + } + Error = NetRplWkstaDel( GlobalServerHandle, WkstaName); + if ( Error != NO_ERROR) { + MessagePrint( Error); + return; + } +} + + +VOID WkstaEnum( VOID) +{ + DWORD Level; + DWORD PrefMaxLength; + DWORD ResumeHandle; + PWCHAR ProfileName; + + if ( !ReadInt( IDS_PROMPT_LEVEL012, &Level, TRUE) || Level > 2) { + return; + } +#ifdef RPL_DEBUG + if ( !ReadInt( IDS_PROMPT_PREFMAXLENGTH_DEBUG, &PrefMaxLength, TRUE)) { + return; + } +#else + PrefMaxLength = RPL_BUFFER_GET_ALL; +#endif + if( !ReadString( IDS_PROMPT_PROFILENAME_COMPATWKSTA, &ProfileName, FALSE)) { + return; + } + ResumeHandle = 0, TestWkstaEnum( Level, ProfileName, PrefMaxLength, &ResumeHandle); +} + + +VOID WkstaGetInfo( VOID) +{ + BYTE Line[ 300]; + WCHAR WkstaName[ 20]; + CHAR WkstaNameA[ 20]; + DWORD Length; + DWORD Count; + DWORD Level; + + RplPrintf0( IDS_PROMPT_WKSTANAME_INFOLEVEL ); + if ( gets( Line) == NULL) { + return; + } + Count = sscanf( Line, "%d %s", &Level, WkstaNameA); + if ( Count != 2) { + RplPrintf0( IDS_BADARGCOUNT ); + return; + } + Length = MultiByteToWideChar( CP_OEMCP, MB_PRECOMPOSED, WkstaNameA, -1, + WkstaName, sizeof( WkstaName)); + if ( Length == 0) { + RplPrintf1( IDS_INVALIDSTRING_CHARSTRINGA, (LPWSTR)WkstaNameA); + return; + } + TestWkstaGetInfo( Level, WkstaName); +} + + +VOID WkstaSetInfo( VOID) +{ + PWCHAR WkstaName; + DWORD Level; + LPVOID Buffer; + RPL_WKSTA_INFO_2 Info; + + Buffer = &Info; + if ( !ReadInt( IDS_PROMPT_LEVEL012, &Level, TRUE) || Level > 2) { + return; + } + if ( !ReadString( IDS_PROMPT_WKSTANAME_INPUT, &WkstaName, FALSE)) { + return; + } + RplPrintf0( IDS_INPUTWKSTAPROPERTIES ); + if( !ReadString( IDS_PROMPT_WKSTANAME, &Info.WkstaName, FALSE)) { + return; + } + if( !ReadString( IDS_PROMPT_WKSTACOMMENT, &Info.WkstaComment, FALSE)) { + return; + } + if ( Level == 0) { + goto testit; + } + if ( !ReadWkstaFlags( &Info.Flags)) { + return; + } + if( !ReadString( IDS_PROMPT_PROFILENAME, &Info.ProfileName, FALSE)) { + return; + } + if ( Level == 1) { + goto testit; + } + if ( !ReadString( IDS_PROMPT_BOOTNAME, &Info.BootName, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_FITFILE, &Info.FitFile, FALSE)) { + return; + } + if ( !ReadString( IDS_PROMPT_ADAPTERNAME, &Info.AdapterName, FALSE)) { + return; + } + Info.TcpIpAddress = (DWORD)-1; + if ( !ReadInt( IDS_PROMPT_TCPIPADDRESS, &Info.TcpIpAddress, FALSE)) { + return; + } + Info.TcpIpSubnet = (DWORD)-1; + if ( !ReadInt( IDS_PROMPT_TCPIPSUBNET, &Info.TcpIpSubnet, FALSE)) { + return; + } + Info.TcpIpGateway = (DWORD)-1; + if ( !ReadInt( IDS_PROMPT_TCPIPGATEWAY, &Info.TcpIpGateway, FALSE)) { + return; + } +testit: + TestWkstaSetInfo( Level, WkstaName, Buffer); +} + +// +// BUGBUG INTL: still must deal with char constants +// + + +VOID Worker( VOID) +{ + for ( ; ;) { + switch( ReadFromMenu( IDS_PROMPT_MENU_MAIN_ABCPSVWQ, + IDS_PROMPT_FILTER_MAIN_ABCPSVWQ )) { + case 0: + switch( ReadFromMenu( IDS_PROMPT_MENU_ADAPTER_ADE, + IDS_PROMPT_FILTER_ADAPTER_ADE )) { + case 0: + AdapterAdd(); + break; + case 1: + AdapterDel(); + break; + case 2: + AdapterEnum(); + break; + } + break; + case 1: + switch( ReadFromMenu( IDS_PROMPT_MENU_BOOT_ADE, + IDS_PROMPT_FILTER_BOOT_ADE )) { + case 0: + BootAdd(); + break; + case 1: + BootDel(); + break; + case 2: + BootEnum(); + break; + } + break; + case 2: + switch( ReadFromMenu( IDS_PROMPT_MENU_CONFIG_ADE, + IDS_PROMPT_FILTER_CONFIG_ADE )) { + case 0: + ConfigAdd(); + break; + case 1: + ConfigDel(); + break; + case 2: + ConfigEnum(); + break; + } + break; + case 3: + switch( ReadFromMenu( IDS_PROMPT_MENU_PROFILE_ACDEGS, + IDS_PROMPT_FILTER_PROFILE_ACDEGS )) { + case 0: + ProfileAdd(); + break; + case 1: + ProfileClone(); + break; + case 2: + ProfileDel(); + break; + case 3: + ProfileEnum(); + break; + case 4: + ProfileGetInfo(); + break; + case 5: + ProfileSetInfo(); + break; + } + break; + case 4: + switch( ReadFromMenu( IDS_PROMPT_MENU_SERVICE_CGOS, + IDS_PROMPT_FILTER_SERVICE_CGOS )) { + case 0: + ServiceClose(); + break; + case 1: + ServiceGetInfo(); + break; + case 2: + ServiceOpen(); + break; + case 3: + ServiceSetInfo(); + break; + } + break; + case 5: + switch( ReadFromMenu( IDS_PROMPT_MENU_VENDOR_ADE, + IDS_PROMPT_FILTER_VENDOR_ADE )) { + case 0: + VendorAdd(); + break; + case 1: + VendorDel(); + break; + case 2: + VendorEnum(); + break; + } + break; + case 6: + switch( ReadFromMenu( IDS_PROMPT_MENU_WKSTA_ACDEGS, + IDS_PROMPT_FILTER_WKSTA_ACDEGS )) { + case 0: + WkstaAdd(); + break; + case 1: + WkstaClone(); + break; + case 2: + WkstaDel(); + break; + case 3: + WkstaEnum(); + break; + case 4: + WkstaGetInfo(); + break; + case 5: + WkstaSetInfo(); + break; + } + break; + case 7: + return; + break; + default: + // go back to start of loop + break; + } + } +} + + +DWORD _CRTAPI1 main( int argc, char **argv) +{ + DWORD Error; + DWORD Length; + + GlobalMessageHandle = LoadLibrary( L"netmsg.dll"); + if ( GlobalMessageHandle == NULL) { + MessagePrint( IDS_LOAD_LIBRARY_FAILURE, GetLastError()); + goto ErrorExit; + } + + if ( argc == 1) { + GlobalServerName = NULL; + } else if ( argc == 2) { + Length = (MAX_PATH+1+2) * sizeof(WCHAR); // terminal null + two backslashes + GlobalServerName = LocalAlloc( GMEM_FIXED, Length); + if ( GlobalServerName == NULL) { + RplDbgPrint(( "LocalAlloc failed")); + goto ErrorExit; + } + Length = MultiByteToWideChar( + CP_OEMCP, + MB_PRECOMPOSED, + argv[ 1], + -1, + GlobalServerName, + Length + ); + if ( Length == 0 || !_wcsicmp( GlobalServerName, QUESTION_SW) + || !_wcsicmp( GlobalServerName, QUESTION_SW_TOO)) { + goto ErrorExit; + } +#ifdef RPL_DEBUG + RplPrintf1( IDS_TARGETSERVER, GlobalServerName); +#endif + } else { + goto ErrorExit; + } + + Error = NetRplOpen( GlobalServerName, &GlobalServerHandle); + if ( Error != NO_ERROR) { + MessagePrint( Error); + MessagePrint( IDS_OPEN_SERVICE_HANDLE); + goto ErrorExit; + } + GlobalHaveServerHandle = TRUE; + + Worker(); + + if ( GlobalHaveServerHandle == FALSE) { + return(0); + } + + Error = NetRplClose( GlobalServerHandle); + if ( Error != NO_ERROR) { + MessagePrint( Error); + MessagePrint( IDS_CLOSE_SERVICE_HANDLE); + goto ErrorExit; + } + GlobalHaveServerHandle = FALSE; // in case one adds code below + return(0); + +ErrorExit: + + RplPrintf0( IDS_USAGE ); + return(1); +} + diff --git a/private/net/svcdlls/rpl/command/rplmsg.mc b/private/net/svcdlls/rpl/command/rplmsg.mc new file mode 100644 index 000000000..b2c8d526b --- /dev/null +++ b/private/net/svcdlls/rpl/command/rplmsg.mc @@ -0,0 +1,610 @@ +;/*++ +; +;Copyright (c) 1992 Microsoft Corporation +; +;Module Name: +; +; rplmsg.h +; +;Abstract: +; +; Definitions for Remoteboot command private errors. +; +;Author: +; +; Vladimir Z. Vulovic (vladimv) 06 - November - 1992 +; +;Revision History: +; Jon Newman April - 28 - 1994 +; moved & cleaned up bunch of messages +; +; +;Notes: +; +; This file is generated by the MC tool from the rplmsg.mc file. +; +; +;--*/ + +MessageId=10000 SymbolicName=IDS_LOAD_LIBRARY_FAILURE +Language=English +LoadLibrary() fails with winError = %1!d!%n%0 +. +MessageId=+1 SymbolicName=IDS_UNEXPECTED_RETURN_CODE +Language=English +Remote boot server returned an unexpected error = %1!d!%n%0 +. +MessageId=+1 SymbolicName=IDS_OPEN_SERVICE_HANDLE +Language=English +Failed to open remote boot service handle.%n%0 +. +MessageId=+1 SymbolicName=IDS_CLOSE_SERVICE_HANDLE +Language=English +Failed to close remote boot service handle.%n%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_ADAPTERCOMMENT +Language=English +AdapterComment=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_ADAPTERNAME +Language=English +AdapterName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_ADAPTERNAME_COMPATCONFIG +Language=English +To list only configurations compatible with a given network card, input AdapterName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_ADAPTERNAME_COMPATPROF +Language=English +To list only profiles compatible with a given network card, input AdapterName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_ADAPTERNAME_TARGET +Language=English +TargetAdapterName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_BOOTCOMMENT +Language=English +BootComment=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_BOOTNAME +Language=English +BootName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_CONFIGCOMMENT +Language=English +ConfigComment=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_CONFIGNAME +Language=English +ConfigName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_DIRNAME +Language=English +DirName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_DIRNAME2 +Language=English +DirName2=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_DIRNAME3 +Language=English +DirName3=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_DIRNAME4 +Language=English +DirName4=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FITFILE +Language=English +FitFile=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FITPERSONAL +Language=English +FitPersonal=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FITSHARED +Language=English +FitShared=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_LEVEL_DEBUG +Language=English +Information Level=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_LEVEL01 +Language=English +Information Level (0 or 1)=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_LEVEL012 +Language=English +Information Level (0, 1 or 2)=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_ADAPTER_ADE +Language=English +Add Del Enum: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_ADAPTER_ADE +Language=English +ADE%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_ADAPTER_DE +Language=English +Del Enum: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_ADAPTERDELETEALL +Language=English +Are you sure you wish to delete all adapters? (Y/N)=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_BOOT_ADE +Language=English +Add Del Enum: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_BOOT_ADE +Language=English +ADE%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_CONFIG_ADE +Language=English +Add Del Enum: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_CONFIG_ADE +Language=English +ADE%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_MAIN_ABCPSVWQ +Language=English +Adapter Boot Config Profile Service Vendor Wksta [Quit]: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_MAIN_ABCPSVWQ +Language=English +ABCPSVWQ%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_PROFILE_ACDEGS +Language=English +Add Clone Del Enum GetInfo SetInfo: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_PROFILE_ACDEGS +Language=English +ACDEGS%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_SERVICE_CGOS +Language=English +Close GetInfo Open SetInfo: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_SERVICE_CGOS +Language=English +CGOS%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_SERVICE_CONFIGS +Language=English +Would you like to check for installed configurations [Y,N]=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_SERVICE_RPLDISK +Language=English +Would you like to update client boot files [Y,N]=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_SERVICE_BACKUP +Language=English +Would you backup service database [Y,N]=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_YN +Language=English +YN%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_SERVICE_SECURITY +Language=English +Would you check logon domain for remoteboot workstations [Y,N]=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_VENDOR_ADE +Language=English +Add Del Enum: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_VENDOR_ADE +Language=English +ADE%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_WKSTA_ACDEGS +Language=English +Add Clone Del Enum GetInfo SetInfo: %0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_WKSTA_ACDEGS +Language=English +ACDEGS%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_WKSTA_DELETE +Language=English +Delete corresponding user account when workstation is deleted by Remoteboot Manager [Y,N]=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_WKSTA_DHCP +Language=English +Does RemoteBoot workstation use DHCP [Y,N]=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_WKSTA_LOGON_INPUT +Language=English +Is Remoteboot password Required, Optional or Not solicited [R,O,N]=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_WKSTA_LOGON_INPUT +Language=English +RON%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_MENU_WKSTA_SHAREDORPRIVATE +Language=English +Does RemoteBoot workstation uses shared or private home directory [S,P]=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_FILTER_WKSTA_SHAREDORPRIVATE +Language=English +SP%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PREFMAXLENGTH_DEBUG +Language=English +PrefMaxLength (-1 for all data)=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PROFILECOMMENT +Language=English +ProfileComment=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PROFILECOMMENT_TARGET +Language=English +TargetProfileComment=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PROFILENAME +Language=English +ProfileName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PROFILENAME_COMPATWKSTA +Language=English +To list only workstations using a given profile, input ProfileName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PROFILENAME_INFOLEVEL +Language=English +Input Information Level (0, 1 or 2) and ProfileName%n%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PROFILENAME_INPUT +Language=English +Input ProfileName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PROFILENAME_SOURCE +Language=English +SourceProfileName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_PROFILENAME_TARGET +Language=English +TargetProfileName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_SERVERNAME +Language=English +ServerName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_TCPIPADDRESS +Language=English +TcpIpAddress (when DHCP is disabled)=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_TCPIPGATEWAY +Language=English +TcpIpGateway (when DHCP is disabled)=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_TCPIPSUBNET +Language=English +TcpIpSubnet (when DHCP is disabled)=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_VENDORCOMMENT +Language=English +VendorComment=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_VENDORNAME +Language=English +VendorName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_BBCFILE +Language=English +BbcFile=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_WINDOWSIZE +Language=English +WindowSize=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_WKSTACOMMENT +Language=English +WkstaComment=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_WKSTACOMMENT_TARGET +Language=English +TargetWkstaComment=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_WKSTANAME +Language=English +WkstaName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_WKSTANAME_INFOLEVEL +Language=English +Input Information Level (0, 1 or 2) and WkstaName%n%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_WKSTANAME_INPUT +Language=English +Input WkstaName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_WKSTANAME_SOURCE +Language=English +SourceWkstaName=%0 +. +MessageId=+1 SymbolicName=IDS_PROMPT_WKSTANAME_TARGET +Language=English +TargetWkstaName=%0 +. +MessageId=+1 SymbolicName=IDS_BADARGCOUNT +Language=English +Bad number of arguments.%n%0 +. +MessageId=+1 SymbolicName=IDS_BADMENUSEL +Language=English +Your input "%1!ws!" is invalid. One of "%2!ws!" was expected.%n%0 +. +MessageId=+1 SymbolicName=IDS_INPUTPROFILEPROPERTIES +Language=English +Input new profile properties.%n%0 +. +MessageId=+1 SymbolicName=IDS_INPUTWKSTAPROPERTIES +Language=English +Input new workstation properties.%n%0 +. +MessageId=+1 SymbolicName=IDS_INVALIDSTRING_CHARSTRINGA +Language=English +Invalid string "%1!s!"%n%0 +. +MessageId=+1 SymbolicName=IDS_MUSTCLOSEHANDLE +Language=English +Must close existing RemoteBoot service handle +before opening new RemoteBoot service handle.%n%0 +. +MessageId=+1 SymbolicName=IDS_NOSERVICEHANDLE +Language=English +You do not have an open RemoteBoot service handle.%n%0 +. +MessageId=+1 SymbolicName=IDS_NOTSUPPLIED +Language=English +"%1!ws!" must be supplied%n%0 +. +MessageId=+1 SymbolicName=IDS_INVALID_INPUT +Language=English +No valid input supplied%n%0 +. +MessageId=+1 SymbolicName=IDS_TARGETSERVER +Language=English +ServerName = %1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_USAGE +Language=English +The RPLCMD utility can be used to view and update the Remoteboot service +database. The Remoteboot service must already be running.%n +%n +RPLCMD [\\computername]%n +%n +\\computername Specifies a remote computer where the Remoteboot service%n + is running. If this parameter is omitted, RPLCMD manages%n + the Remoteboot service on the local computer.%n +. +MessageId=+1 SymbolicName=IDS_PARAMETERSOPTIONAL +Language=English +%tAll other parameters are optional%n%0 +. +MessageId=+1 SymbolicName=IDS_ADAPTERBADFLAGS +Language=English +%tBad Adapter flags, Flags=0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_ADAPTERCOMMENT +Language=English +%tAdapterComment=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_BBCFILE +Language=English +%tBbcFile=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_BOOTACK_FALSE +Language=English +%tAcknowledgment of the last RemoteBoot frame is not requested.%n%0 +. +MessageId=+1 SymbolicName=IDS_BOOTACK_TRUE +Language=English +%tAcknowledgment of the last RemoteBoot frame is requested.%n%0 +. +MessageId=+1 SymbolicName=IDS_BOOTBADFLAGS +Language=English +%tBad Boot flags, Flags=0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_BOOTCOMMENT +Language=English +%tBootComment=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_BOOTNAME +Language=English +%tBootName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_CONFIGBADFLAGS +Language=English +%tBad Configuration flags, Flags=0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_CONFIGCOMMENT +Language=English +%tConfigComment=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_CONFIGDISABLED +Language=English +%tConfiguration is disabled.%n%0 +. +MessageId=+1 SymbolicName=IDS_CONFIGENABLED +Language=English +%tConfiguration is enabled.%n%0 +. +MessageId=+1 SymbolicName=IDS_CONFIGNAME +Language=English +%tConfigName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_DIRNAME +Language=English +%tDirName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_DIRNAME2 +Language=English +%tDirName2=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_DIRNAME3 +Language=English +%tDirName3=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_DIRNAME4 +Language=English +%tDirName4=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_FITFILE +Language=English +%tFitFile=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_FITPERSONAL +Language=English +%tFitPersonal=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_FITSHARED +Language=English +%tFitShared=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_PROFILEBADFLAGS +Language=English +%tBad Profile flags, Flags = 0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_PROFILECOMMENT +Language=English +%tProfileComment=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_PROFILENODISKTREE +Language=English +%tDisk tree for this profile may be absent.%n%0 +. +MessageId=+1 SymbolicName=IDS_TCPIPADDRESS +Language=English +%tTcpIpAddress=0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_TCPIPGATEWAY +Language=English +%tTcpIpGateway=0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_TCPIPSUBNET +Language=English +%tTcpIpSubnet=0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_SERVICEBADFLAGS +Language=English +%tBad Service flags, Flags=0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_VENDORBADFLAGS +Language=English +%tBad Vendor flags, Flags = 0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_VENDORCOMMENT +Language=English +%tVendorComment=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_VENDORNAME +Language=English +%tVendorName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_WINDOWSIZE +Language=English +%tWindowSize=0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTAADAPTER +Language=English +%tAdapterName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTACOMMENT +Language=English +%tWkstaComment=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTAINPROFILE +Language=English +%tProfileName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTALOGONBADFLAGS +Language=English +%tBad Remoteboot password flags, Flags = 0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTALOGONNONE +Language=English +%tRemoteBoot password is not solicited%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTALOGONOPT +Language=English +%tRemoteBoot password is optional%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTALOGONREQD +Language=English +%tRemoteBoot password is requred%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTASHARINGBADFLAGS +Language=English +%tBad Remoteboot home directory flags, Flags = 0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTASHARINGFALSE +Language=English +%tUses private home directory%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTASHARINGTRUE +Language=English +%tUses shared home directory%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTA_DELETE_TRUE +Language=English +%tUser will be deleted when workstation is deleted by Remoteboot Manager%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTA_DELETE_FALSE +Language=English +%tUser will be not deleted when workstation is deleted by Remoteboot Manager%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTA_DELETE_BAD_FLAGS +Language=English +%tBad DELETE flags, Flags = 0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTA_DHCP_TRUE +Language=English +%tUses DHCP (when TCP/IP is enabled)%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTA_DHCP_FALSE +Language=English +%tDoes not use DHCP (when TCP/IP is enabled)%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTA_DHCP_BAD_FLAGS +Language=English +%tBad DHCP flags, Flags = 0x%1!x!%n%0 +. +MessageId=+1 SymbolicName=IDS_PROFILENAME_NOTAB +Language=English +ProfileName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_ADAPTERNAME_NOTAB +Language=English +AdapterName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_BOOTNAME_NOTAB +Language=English +BootName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_CONFIGNAME_NOTAB +Language=English +ConfigName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_VENDORNAME_NOTAB +Language=English +VendorName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_WKSTANAME_NOTAB +Language=English +WkstaName=%1!ws!%n%0 +. +MessageId=+1 SymbolicName=IDS_RPLSVC_COMPUTER +Language=English +Managing remoteboot service at computer %1!ws!.%n%0 +. +MessageId=+1 SymbolicName=IDS_RPLSVC_LOCAL_COMPUTER +Language=English +Managing remoteboot service at local computer.%n%0 +. + +
\ No newline at end of file diff --git a/private/net/svcdlls/rpl/command/rplver.rc b/private/net/svcdlls/rpl/command/rplver.rc new file mode 100644 index 000000000..52c98ef82 --- /dev/null +++ b/private/net/svcdlls/rpl/command/rplver.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "RemoteBoot Command-line Utility" +#define VER_INTERNALNAME_STR "RPLCMD.EXE" +#define VER_ORIGINALFILENAME_STR "RPLCMD.EXE" + +#include "common.ver" +#include "rplmsg.rc" diff --git a/private/net/svcdlls/rpl/command/sources b/private/net/svcdlls/rpl/command/sources new file mode 100644 index 000000000..c546b3668 --- /dev/null +++ b/private/net/svcdlls/rpl/command/sources @@ -0,0 +1,65 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Vladimir Z. Vulovic (vladimv) 08 - April - 1994 + + +Revision History: + +!ENDIF + +MAJORCOMP = net +MINORCOMP = rpl +TARGETNAME= rplcmd + + + +TARGETPATH=obj +TARGETTYPE=PROGRAM +TARGETLIBS= \ + ..\lib\obj\*\rpllib.lib \ + +INCLUDES=.;..\inc;..\..\..\inc;..\..\..\..\inc + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + rplcmd.c \ + rplver.rc + + +UMTYPE= console +UMLIBS= \ + $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\Public\Sdk\Lib\*\shell32.lib \ + $(BASEDIR)\public\sdk\lib\*\user32.lib + +C_DEFINES=-DRPC_NO_WINDOWS_H + + +NTTARGETFILE0= \ + rplmsg.h \ + rplmsg.mc + + diff --git a/private/net/svcdlls/rpl/convert/adapter.c b/private/net/svcdlls/rpl/convert/adapter.c new file mode 100644 index 000000000..738dbb67c --- /dev/null +++ b/private/net/svcdlls/rpl/convert/adapter.c @@ -0,0 +1,71 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + adapter.c + +Abstract: + + Creates adapter table to be used with NT rpl service. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#define RPLADAPTER_ALLOCATE +#include "adapter.h" +#undef RPLADAPTER_ALLOCATE + + +DWORD AdapterCreateTable( VOID) +{ + JET_COLUMNDEF ColumnDef; + JET_ERR JetError; + DWORD index; + DWORD Offset; + CHAR IndexKey[ 255]; + + JetError = JetCreateTable( SesId, DbId, ADAPTER_TABLE_NAME, + ADAPTER_TABLE_PAGE_COUNT, ADAPTER_TABLE_DENSITY, &AdapterTableId); + + // + // Create columns. First initalize fields that do not change between + // addition of columns. + // + ColumnDef.cbStruct = sizeof(ColumnDef); + ColumnDef.columnid = 0; + ColumnDef.wCountry = 1; + ColumnDef.langid = 0x0409; // USA english + ColumnDef.cp = 1200; // UNICODE codepage + ColumnDef.wCollate = 0; + ColumnDef.cbMax = 0; + ColumnDef.grbit = 0; // variable length binary and text data. + + for ( index = 0; index < ADAPTER_TABLE_LENGTH; index++) { + + ColumnDef.coltyp = AdapterTable[ index].ColumnType; + + CallM( JetAddColumn( SesId, AdapterTableId, + AdapterTable[ index].ColumnName, &ColumnDef, + NULL, 0, &AdapterTable[ index].ColumnId)); + } + + Offset = AddKey( IndexKey, '+', AdapterTable[ ADAPTER_AdapterName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, AdapterTableId, ADAPTER_INDEX_AdapterName, + JET_bitIndexPrimary, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + return( ERROR_SUCCESS); +} + diff --git a/private/net/svcdlls/rpl/convert/boot.c b/private/net/svcdlls/rpl/convert/boot.c new file mode 100644 index 000000000..e0dacb4ec --- /dev/null +++ b/private/net/svcdlls/rpl/convert/boot.c @@ -0,0 +1,306 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + boot.c + +Abstract: + + Creates boot block table (server record table). Parses old style + RPL.MAP server records and creates corresponding entries in jet + database table. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#define RPLBOOT_ALLOCATE +#include "boot.h" +#undef RPLBOOT_ALLOCATE + + +DWORD BootCreateTable( VOID) +{ + JET_COLUMNDEF ColumnDef; + JET_ERR JetError; + DWORD index; + DWORD Offset; + CHAR IndexKey[ 255]; + + JetError = JetCreateTable( SesId, DbId, BOOT_TABLE_NAME, + BOOT_TABLE_PAGE_COUNT, BOOT_TABLE_DENSITY, &BootTableId); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateTable failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // Create columns. First initalize fields that do not change between + // addition of columns. + // + ColumnDef.cbStruct = sizeof(ColumnDef); + ColumnDef.columnid = 0; + ColumnDef.wCountry = 1; + ColumnDef.langid = 0x0409; // USA english + ColumnDef.cp = 1200; // UNICODE codepage + ColumnDef.wCollate = 0; + ColumnDef.cbMax = 0; + ColumnDef.grbit = 0; // variable length binary and text data. + + for ( index = 0; index < BOOT_TABLE_LENGTH; index++ ) { + + ColumnDef.coltyp = BootTable[ index].ColumnType; + + JetError = JetAddColumn( SesId, BootTableId, + BootTable[ index].ColumnName, &ColumnDef, + NULL, 0, &BootTable[ index].ColumnId); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("AddColumn( %s) failed err=%d", BootTable[ index].ColumnName, JetError)); + return( MapJetError( JetError)); + } + } + + // + // Boot names of DOS boot blocks may be shared by several adapter id + // classes (vendor codes). Therefore, server name (== boot name) + // cannot be a unique index nor a primary index. But you can construct + // a primary index from VendorId & BootName. + // +VendorId+BootName index is used to enumerate all boot names for a + // given vendor id - which is then used to enumerate all profiles & all + // configs compatible with a given vendor id. + // + Offset = AddKey( IndexKey, '+', BootTable[ BOOT_VendorId].ColumnName); + Offset += AddKey( IndexKey + Offset, '+', BootTable[ BOOT_BootName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, BootTableId, BOOT_INDEX_VendorIdBootName, + JET_bitIndexPrimary, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + Offset = AddKey( IndexKey, '+', BootTable[ BOOT_BootName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, BootTableId, BOOT_INDEX_BootName, + 0, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // Make boot name a current index - used to validate configs. + // + JetError = JetSetCurrentIndex( SesId, BootTableId, BOOT_INDEX_BootName); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("SetCurrentIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + return( ERROR_SUCCESS); +} + + +VOID ProcessBoot( PWCHAR * Fields) +{ +// +// Boot block record (server record) defines. +// +#define BOOT_BBCFILE_INDEX 1 // boot block configuration file +#define BOOT_RETRYCOUNT_INDEX 2 // retry count (used with default boot) +#define BOOT_TIMEOUT_INDEX 3 // retry period (used with default boot) +#define BOOT_ACKSTATUS_INDEX 4 // used with acknowledgments +#define BOOT_COMMENT_INDEX 6 // boot block comment +#define BOOT_VENDOR_INDEX 7 // common adapter id digits +#define BOOT_BOOTNAME_INDEX 13 // boot block identifier + +#define BOOT_DEFAULT_RETRYCOUNT 3 +#define BOOT_DEFAULT_TIMEOUT 10 +#define USE_ACK_CHAR L'A' +#define FINAL_ACK_ONLY_CHAR L'F' +#define PARTIAL_ACK_CHAR L'P' +#define NO_ACK_CHAR L'N' +#define ADAPT_WIN_CHAR L'W' + + PWCHAR VendorName; // common adapter id digits + DWORD VendorId; // common adapter id digits + PWCHAR BootName; // id of boot block record + PWCHAR BootComment; + PWCHAR BbcFile; // boot block configuration file relative path +#ifdef RPL_OBSOLETE + DWORD RetryCount; + DWORD RetryPeriod; +#endif + DWORD WindowSize; // used with acknowledgments + // + // SendFileRequest is of type JET_coltypBit, which is of UCHAR size. + // Thus it is declared as BOOLEAN == UCHAR, instead of BOOL == int. + // + BOOLEAN FinalAck; // used with acknowledgments + DWORD Flags; + +#ifdef RPL_OBSOLETE + // + // Initialize retry count & retry period (else use defaults). + // + if ( iswdigit( *Fields[ BOOT_TIMEOUT_INDEX]) && + iswdigit( *Fields[ BOOT_RETRYCOUNT_INDEX])) { + RetryPeriod = wcstoul( Fields[ BOOT_TIMEOUT_INDEX], NULL, 0); + RetryCount = wcstoul( Fields[ BOOT_RETRYCOUNT_INDEX], NULL, 0); + } else { + RetryPeriod = BOOT_DEFAULT_TIMEOUT; + RetryCount = BOOT_DEFAULT_RETRYCOUNT; + } +#endif + + switch( toupper( *Fields[ BOOT_ACKSTATUS_INDEX])) { + case FINAL_ACK_ONLY_CHAR: + WindowSize = MAXWORD; // don't ack any (non-final) packet + FinalAck = TRUE; // ack the final packet + break; + case PARTIAL_ACK_CHAR: + WindowSize = 0; // ack every (non-final) packet + FinalAck = FALSE; // don't ack the final packet + break; + case ADAPT_WIN_CHAR: + if ( Fields[ BOOT_ACKSTATUS_INDEX][ 1] != EQUALS_CHAR) { + WindowSize = 0; // the default is to ack every (non-final) packet + } else { + WindowSize = wcstoul( Fields[BOOT_ACKSTATUS_INDEX] + 2, NULL, 0); + // + // Algorithm adds an extra packet to window, decrement counter + // by one. (Thus window size of 1 is same as USE_ACK_CHAR.) + // + if ( WindowSize) { // avoid underflow + WindowSize--; + } + } // ack every WindowSize-th (non-final) packet + FinalAck = TRUE; // ack the final packet + break; + case NO_ACK_CHAR: + case 0: + WindowSize = MAXWORD; // don't ack any (non-final) packet + FinalAck = FALSE; // don't ack the final packet + break; + default: + DbgUserBreakPoint(); + NOTHING; // fall through to most common case + case USE_ACK_CHAR: + WindowSize = 0; // ack every (non-final) packet + FinalAck = TRUE; // ack the final packet + break; + } + WindowSize = 0; // BUGBUG temporary workaround for RPLSVC bug + + if ( FinalAck == TRUE) { + Flags = BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_TRUE; + } else { + Flags = BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_FALSE; + } + + BootComment = Fields[ BOOT_COMMENT_INDEX]; + if ( RPL_STRING_TOO_LONG( BootComment)) { + BootComment[ RPL_MAX_STRING_LENGTH] = 0; // silently truncate it + } + + + // + // Note that server identifier has leading 'R' (enabled) or 'D' + // (disabled) in wksta record but it always has leading 'R' in server + // record. We do not want to save leading 'R' in server record. + // + BootName = Fields[ BOOT_BOOTNAME_INDEX] + 1; // add 1 to skip leading 'R' + if ( !ValidName( BootName, RPL_MAX_BOOT_NAME_LENGTH, TRUE)) { + RplPrintf1( RPLI_CVT_BootNameTooLong, BootName); + return; + } + + BbcFile = Fields[ BOOT_BBCFILE_INDEX]; + if ( !ValidName( BbcFile, RPL_MAX_STRING_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_BbcFileTooLong, BootName, BbcFile); + return; + } + + // + // LM2.2 introduced multiple vendor codes in the vendor field of a + // boot block record. For each of the vendor codes we create a + // separate jet record. + // + // Store common adapter id digits both as a hex string (VendorName) + // and as a dword (VendorId). + // + for ( VendorName = wcstok( Fields[ BOOT_VENDOR_INDEX], L"|"); + VendorName != NULL; VendorName = wcstok( NULL, L"|")) { + + if ( !ValidHexName( VendorName, RPL_VENDOR_NAME_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_BadVendorName, BootName, VendorName); + continue; + } + + VendorId = wcstoul( VendorName, NULL, 16); // since VendorName must be hex + + Call( JetPrepareUpdate( SesId, BootTableId, JET_prepInsert)); + + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_BootName].ColumnId, + BootName, (wcslen( BootName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_BootComment].ColumnId, + BootComment, (wcslen( BootComment) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_Flags].ColumnId, + &Flags, sizeof( Flags), 0, NULL)); + + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_VendorName].ColumnId, + VendorName, (wcslen( VendorName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_BbcFile].ColumnId, + BbcFile, (wcslen( BbcFile) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_WindowSize].ColumnId, + &WindowSize, sizeof( WindowSize), 0, NULL)); + + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_VendorId].ColumnId, + &VendorId, sizeof( VendorId), 0, NULL)); + +#ifdef RPL_OBSOLETE + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_RetryCount].ColumnId, + &RetryCount, sizeof( RetryCount), 0, NULL)); + + Call( JetSetColumn( SesId, BootTableId, + BootTable[ BOOT_RetryPeriod].ColumnId, + &RetryPeriod, sizeof( RetryPeriod), 0, NULL)); +#endif + + Call( JetUpdate( SesId, BootTableId, NULL, 0, NULL)); + } +} + + +BOOL FindBoot( IN PWCHAR BootName) +{ + return( Find( BootTableId, BootName)); +} + + +VOID BootListTable( VOID) +{ + ListTable( BOOT_TABLE_NAME, BootTable[ BOOT_BootName].ColumnName, + BOOT_INDEX_BootName); +} + + diff --git a/private/net/svcdlls/rpl/convert/config.c b/private/net/svcdlls/rpl/convert/config.c new file mode 100644 index 000000000..99215c4f5 --- /dev/null +++ b/private/net/svcdlls/rpl/convert/config.c @@ -0,0 +1,527 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + config.c + +Abstract: + + Creates config table. Parses old style RPLMGR.INI config records + and creates corresponding entries in jet database table. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#define RPLCONFIG_ALLOCATE +#include "config.h" +#undef RPLCONFIG_ALLOCATE + +PWCHAR RplmgrIniFile = L"rplmgr.ini"; + +#define MAX_RPLMGR_INI_FILE_SIZE 0xFFFF // BUGBUG some arbitrary value + +#define NO_SCRIPT_FIELDS 13 + +#define SECTION_STARTMARK L'[' +#define CONFIG_BEGIN L"[configuration]" + +#define CARRIAGE_RETURN_CHAR L'\r' // 0xD or \015 + +// #define RPL_DEBUG_ALL + + +BOOL GetConfigFieldValue( + IN PWCHAR Cursor, + IN DWORD Index + ) +/*++ + Fields with multiple field values, such as AdapterName, are + not properly parsed here. Howerever, we do not care about + the values of these fields. +--*/ +{ + PWCHAR End; + DWORD Length; + + // + // By default the field is empty. + // + ConfigParseTable[ Index].Value = NULL; + ConfigParseTable[ Index].Size = 0; + + // + // Read to EQUALS_CHAR + // + while ( *Cursor != EQUALS_CHAR && *Cursor != COMMENT_CHAR && + *Cursor != CARRIAGE_RETURN_CHAR) { + Cursor++; + } + + if ( *Cursor == COMMENT_CHAR || *Cursor == CARRIAGE_RETURN_CHAR) { + return( TRUE); + } + + Cursor++; // Skip EQUALS_CHAR + + // + // Read to the beginning of field value. + // + while( *Cursor != CARRIAGE_RETURN_CHAR && iswspace(*Cursor) && + *Cursor != COMMENT_CHAR) { + Cursor++; + } + + if ( *Cursor == COMMENT_CHAR || *Cursor == CARRIAGE_RETURN_CHAR) { + return( TRUE); + } + + // + // Make sure that boot block reference is enabled. + // + if ( Index == CONFIG_BootName) { + if ( *Cursor != L'R') { + RplAssert( TRUE, ("Bad boot block id: %.40ws", Cursor)); + return( FALSE); + } + Cursor++; // skip leading 'R' in boot block name + } + + // + // Find the end point of this field. Since comments may contain spaces, + // space is not used as a separator for CONFIG_ConfigComment field. + // + + End = wcspbrk( Cursor, Index == CONFIG_ConfigComment ? L"\f\n\r\t\v" : L" \f\n\r\t\v"); + if ( End != NULL) { + Length = End - Cursor; + } else { + Length = wcslen( Cursor); + } + + ConfigParseTable[ Index].Value = GlobalAlloc( GMEM_FIXED, (Length+1)*sizeof(WCHAR)); + if ( ConfigParseTable[ Index].Value == NULL) { + DWORD Error = GetLastError(); + RplAssert( TRUE, ("GlobalAlloc: Error = %d", Error)); + return( FALSE); + } + ConfigParseTable[ Index].Size = (Length+1)*sizeof(WCHAR); + memcpy( ConfigParseTable[ Index].Value, Cursor, Length * sizeof(WCHAR)); + ((PWCHAR)ConfigParseTable[ Index].Value)[ Length] = 0; + return( TRUE); +} + + +BOOL StringISpaceEqual( IN PWCHAR str1, IN PWCHAR str2 ) +/*++ + +Routine Description: + + Case insensitive version of StringsSpaceEqual. + +Arguments: + + str1 - first string + str2 - second string + +Return Value: + + TRUE if strings are equal, FALSE otherwise. + +--*/ +{ + WCHAR ch1; + +#ifdef NOT_YET + if ( str1 == NULL || str2 == NULL) { + str1 = (str1 != NULL) ? str1 : str2; + if ( str2 == NULL) { + return( TRUE); // both strings are NULL + } + while ( iswspace( *str1++)) { + NOTHING; // check if not NULL string contains spaces only + } + return( *str1 == 0); + } +#endif // NOT_YET + + // + // Compare strings until the first space or NULL character + // (in the first string) or until we find the first different character. + // + while ( (ch1 = toupper(*str1)) && !iswspace(ch1) && ch1 == toupper(*str2)) { + str1++, str2++; + } + + // + // For strings to be equal, both characters must be NULL or space. + // + if ( (!ch1 || iswspace(ch1)) && (!(ch1 = *str2) || iswspace(ch1))) + { + return( TRUE); + } + + return( FALSE); +} + + +#ifdef RPL_DEBUG_ALL +VOID ProcessConfigDisplay( VOID) +{ + DWORD Index; + + printf( "\tCONFIGURATION\n"); + for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++) { + if ( ConfigParseTable[ Index].Name == NULL) { + continue; + } + printf( "%ws %ws 0x%x\n", ConfigParseTable[ Index].Name, + ConfigParseTable[ Index].Value, ConfigParseTable[ Index].Size); + } +} +#endif + + +PWCHAR ProcessConfig( IN PWCHAR Cursor) +/*++ + +Routine Description: + + We read all the fields in the Config[] array, then use jet apis + to store this config in the database. + +Arguments: + + Cursor - at entry this points to the beginning of the config section + +Return Value: + + Cursor value after we finished processing the current config section. + +--*/ +{ +#define INVALID_ERROR_PARAMETER ((DWORD)(-1)) + DWORD Index; + JET_ERR JetError; + DWORD Flags; + DWORD Offset; + DWORD ErrorParameter; + + for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++) { + if ( ConfigParseTable[ Index].Value != NULL) { + GlobalFree( ConfigParseTable[ Index].Value); + } + ConfigParseTable[ Index].Value = NULL; + } + if ( OffsetAfterComment( Cursor) == 0) { + Flags = CONFIG_FLAGS_ENABLED_TRUE; + } else { + Flags = CONFIG_FLAGS_ENABLED_FALSE; + } + + for ( Cursor=GetNextLine(Cursor), ErrorParameter = INVALID_ERROR_PARAMETER; + *Cursor!=0; Cursor=GetNextLine(Cursor)) { + + Offset = OffsetAfterComment( Cursor); + if ( *(Cursor+Offset) == SECTION_STARTMARK) { + break; // start of a new section, write the current section + } + Cursor += Offset; + + // + // Find value for this name. + // + for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++) { + if ( ConfigParseTable[ Index].Name == NULL) { + continue; // skip this one, not a RPLMGR.INI keyword + } + if ( !StringISpaceEqual( Cursor, ConfigParseTable[ Index].Name)) { + continue; // no match with this keyword + } + if ( !GetConfigFieldValue( Cursor, Index)) { + if ( ErrorParameter == INVALID_ERROR_PARAMETER) { + ErrorParameter = Index; + } + } else if ( Index == CONFIG_FitShared || Index == CONFIG_FitPersonal) { + PWCHAR Value; + Value = AddFileExtension( ConfigParseTable[ Index].Value, + L".FIT", TRUE); + if ( Value == NULL) { + if ( ErrorParameter == INVALID_ERROR_PARAMETER) { + ErrorParameter = Index; + } + } else if ( Value != ConfigParseTable[ Index].Value) { + GlobalFree( ConfigParseTable[ Index].Value); + ConfigParseTable[ Index].Value = Value; + ConfigParseTable[ Index].Size = (wcslen(Value)+1)*sizeof(WCHAR); + } + } + break; + } + } +#ifdef RPL_DEBUG_ALL + ProcessConfigDisplay(); +#endif + + if ( ConfigParseTable[ CONFIG_ConfigName].Value == NULL) { + RplAssert( TRUE, ("Bad config")); + return( Cursor); + } + + // + // Perform same checks as in NetrRplConfigAdd. + // + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + NOTHING; // do not overwrite the first error + } else if ( !ValidName( ConfigParseTable[ CONFIG_FitPersonal].Value, RPL_MAX_STRING_LENGTH, TRUE)) { + ErrorParameter = CONFIG_FitPersonal; + } else if ( !ValidName( ConfigParseTable[ CONFIG_FitShared].Value, RPL_MAX_STRING_LENGTH, TRUE)) { + ErrorParameter = CONFIG_FitShared; + } else if ( !ValidName( ConfigParseTable[ CONFIG_DirName4].Value, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = CONFIG_DirName4; + } else if ( !ValidName( ConfigParseTable[ CONFIG_DirName3].Value, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = CONFIG_DirName3; + } else if ( !ValidName( ConfigParseTable[ CONFIG_DirName2].Value, RPL_MAX_STRING_LENGTH, TRUE)) { + ErrorParameter = CONFIG_DirName2; + } else if ( !ValidName( ConfigParseTable[ CONFIG_DirName].Value, RPL_MAX_STRING_LENGTH, TRUE)) { + ErrorParameter = CONFIG_DirName; + } else if ( !ValidName( ConfigParseTable[ CONFIG_BootName].Value, RPL_MAX_BOOT_NAME_LENGTH, TRUE)) { + ErrorParameter = CONFIG_BootName; + } else if ( !ValidName( ConfigParseTable[ CONFIG_ConfigName].Value, RPL_MAX_CONFIG_NAME_LENGTH, TRUE)) { + ErrorParameter = CONFIG_ConfigName; + } + + if ( ErrorParameter < CONFIG_TABLE_LENGTH) { + RplPrintf2( RPLI_CVT_ConfigInvalid, ConfigParseTable[ CONFIG_ConfigName].Value, ConfigParseTable[ ErrorParameter].Name); + return( Cursor); + } + + if ( ConfigParseTable[ CONFIG_FitPersonal].Value == NULL) { + // + // Ignore default boot configurations. + // + RplPrintf1( RPLI_CVT_ConfigNoPersonalFIT, ConfigParseTable[ CONFIG_ConfigName].Value); + return( Cursor); + } + + if ( !_wcsicmp( L"OS2", ConfigParseTable[ CONFIG_DirName].Value )) { + // + // Ignore OS/2 configurations. + // + RplPrintf1( RPLI_CVT_ConfigNoOS2, ConfigParseTable[ CONFIG_ConfigName].Value); + return( Cursor); + } + + if ( RPL_STRING_TOO_LONG( ConfigParseTable[ CONFIG_ConfigComment].Value)) { + // + // Silently truncate comments that are too long. + // + ((PWCHAR)ConfigParseTable[ CONFIG_ConfigComment].Value)[ RPL_MAX_STRING_LENGTH] = 0; + ConfigParseTable[ CONFIG_ConfigComment].Size = (RPL_MAX_STRING_LENGTH+1)*sizeof(WCHAR); + } + + _wcsupr( (PWCHAR)ConfigParseTable[ CONFIG_BootName].Value); + _wcsupr( (PWCHAR)ConfigParseTable[ CONFIG_ConfigName].Value); + + Call( JetPrepareUpdate( SesId, ConfigTableId, JET_prepInsert)); + + + for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++ ) { + if ( ConfigParseTable[ Index].Name == NULL) { + continue; + } + JetError = JetSetColumn( SesId, ConfigTableId, + ConfigTable[ Index].ColumnId, ConfigParseTable[ Index].Value, + ConfigParseTable[ Index].Size, 0, NULL); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("Index=%d(dec) JetError=%d", Index, JetError)); + } + } + Call( JetSetColumn( SesId, ConfigTableId, + ConfigTable[ CONFIG_Flags].ColumnId, &Flags, sizeof(Flags), 0, NULL)); + + Call( JetUpdate( SesId, ConfigTableId, NULL, 0, NULL)); + return( Cursor); +} + + + +DWORD ProcessRplmgrIni( IN LPWSTR FilePath) +{ + PWCHAR Cursor; + PWCHAR String; + JET_COLUMNDEF ColumnDef; + JET_ERR JetError; + DWORD Index; + DWORD Offset; + CHAR IndexKey[ 255]; + + JetError = JetCreateTable( SesId, DbId, "config", CONFIG_TABLE_PAGE_COUNT, + CONFIG_TABLE_DENSITY, &ConfigTableId); + + ColumnDef.cbStruct = sizeof( ColumnDef); + ColumnDef.columnid = 0; + ColumnDef.coltyp = JET_coltypLong; + ColumnDef.cbMax = 0; + ColumnDef.grbit = 0; + + // + // Create columns. First initialize fields that do not change between + // addition of columns. + // + ColumnDef.cbStruct = sizeof(ColumnDef); + ColumnDef.columnid = 0; + ColumnDef.wCountry = 1; + ColumnDef.langid = 0x0409; // USA english + ColumnDef.cp = 1200; // UNICODE codepage + ColumnDef.wCollate = 0; + ColumnDef.cbMax = 0; + ColumnDef.grbit = 0; // variable length binary and text data. + + for ( Index = 0; Index < CONFIG_TABLE_LENGTH; Index++ ) { + + ColumnDef.coltyp = ConfigTable[ Index].ColumnType; + JetError = JetAddColumn( SesId, ConfigTableId, + ConfigTable[ Index].ColumnName, &ColumnDef, + NULL, 0, &ConfigTable[ Index].ColumnId); + if( JetError != ERROR_SUCCESS ) { + return( MapJetError( JetError)); + } + } + + Offset = AddKey( IndexKey, '+', ConfigTable[ CONFIG_ConfigName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, ConfigTableId, CONFIG_INDEX_ConfigName, + JET_bitIndexPrimary, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // +BootName+ConfigName index is used to enumerate all configurations for + // a given VendorId. + // + Offset = AddKey( IndexKey, '+', ConfigTable[ CONFIG_BootName].ColumnName); + Offset += AddKey( IndexKey + Offset, '+', ConfigTable[ CONFIG_ConfigName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, ConfigTableId, CONFIG_INDEX_BootNameConfigName, + JET_bitIndexUnique, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // Make config name a current index - used to validate profiles. + // + JetError = JetSetCurrentIndex( SesId, ConfigTableId, CONFIG_INDEX_ConfigName); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("SetCurrentIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + String = ReadTextFile( FilePath, RplmgrIniFile, MAX_RPLMGR_INI_FILE_SIZE); + if ( String == NULL) { + return( GetLastError()); + } + + // + // If current line is the beginning of configuration, we process + // that configuration (note that this processing has the side effect of + // advancing the cursor), else we just advance the cursor. + // + for ( Cursor = GetFirstLine( String); *Cursor != 0; NOTHING) { + Offset = OffsetAfterComment( Cursor); + if ( StringISpaceEqual( Cursor+Offset, CONFIG_BEGIN)) { + Cursor = ProcessConfig( Cursor); + } else { + Cursor = GetNextLine( Cursor); + + } + } + + if ( GlobalFree( String) != NULL) { + RplAssert( TRUE, ("GlobalFree: Error=%d", GetLastError())); + } + + return( ERROR_SUCCESS); +} + + +VOID ConfigPruneTable( VOID) +/*++ + Eliminate config records that do not have a corresponding + boot block record defined. +--*/ +{ + WCHAR Name[ 20]; + DWORD NameSize; + JET_ERR ForJetError; + JET_ERR JetError; + + for ( ForJetError = JetMove( SesId, ConfigTableId, JET_MoveFirst, 0); + ForJetError == JET_errSuccess; + ForJetError = JetMove( SesId, ConfigTableId, JET_MoveNext, 0)) { + + JetError = JetRetrieveColumn( SesId, ConfigTableId, + ConfigTable[ CONFIG_BootName].ColumnId, Name, + sizeof( Name), &NameSize, 0, NULL); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("RetriveColumn failed err=%d", JetError)); + Call( JetDelete( SesId, ConfigTableId)); + continue; + } + if ( !FindBoot( Name)) { +#ifdef RPL_DEBUG_ALL + WCHAR Value[ 20]; + JetRetrieveColumn( SesId, ConfigTableId, + ConfigTable[ CONFIG_ConfigName].ColumnId, Value, + sizeof( Value), &NameSize, 0, NULL); + printf("Deleting config %ws since boot %ws was not found\n", + Value, Name); +#endif + Call( JetDelete( SesId, ConfigTableId)); + continue; + } + } +} + + +BOOL FindConfig( IN PWCHAR Name) +{ + JET_ERR JetError; + + JetError = JetMove( SesId, ConfigTableId, JET_MoveFirst, 0); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("JetMove failed err=%d", JetError)); + return( FALSE); + } + JetError = JetMakeKey( SesId, ConfigTableId, Name, + ( wcslen( Name) + 1) * sizeof(WCHAR), JET_bitNewKey); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("MakeKey failed err=%d", JetError)); + return( FALSE); + } + JetError = JetSeek( SesId, ConfigTableId, JET_bitSeekEQ); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("JetSeek for %ws failed err=%d", Name, JetError)); + return( FALSE); + } + return( TRUE); +} + + +VOID ConfigListTable( VOID) +{ + ListTable( CONFIG_TABLE_NAME, ConfigTable[ CONFIG_ConfigName].ColumnName, + CONFIG_INDEX_ConfigName); +} + diff --git a/private/net/svcdlls/rpl/convert/convert.rc b/private/net/svcdlls/rpl/convert/convert.rc new file mode 100644 index 000000000..bec8ec87c --- /dev/null +++ b/private/net/svcdlls/rpl/convert/convert.rc @@ -0,0 +1,12 @@ +#include <windows.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "RemoteBoot Conversion Utility" +#define VER_INTERNALNAME_STR "rplcnv.exe" +#define VER_ORIGINALFILENAME_STR "rplcnv.exe" + +#include "common.ver" + +1 11 MSG00001.bin diff --git a/private/net/svcdlls/rpl/convert/debug.c b/private/net/svcdlls/rpl/convert/debug.c new file mode 100644 index 000000000..918c93752 --- /dev/null +++ b/private/net/svcdlls/rpl/convert/debug.c @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + debug.c + +Abstract: + + Debugging module. + +Author: + + Jon Newman 26 - April - 1994 + +Environment: + + User mode + +Revision History : + + Built from server\debug.c + +--*/ + +#include "local.h" +#include "rpldebug.h" + +#ifdef RPL_DEBUG + +#define RPL_PROMPT "[Rpl] " + +// int RG_DebugLevel = -1; // max debugging +// int RG_DebugLevel = 0; // no debugging, for public use + +int RG_DebugLevel; // needed by other modules +int RG_Assert; // needed by other modules + +char RG_DebugPublicBuffer[ 120]; + +#define RPL_DEFAULT_DEBUG_LEVEL ( RPL_DEBUG_FLOW | \ + RPL_DEBUG_SERVER | \ + RPL_DEBUG_MAJOR ) + +#define RPL_MAXIMUM_DEBUG_LEVEL (-1L) + + + +VOID _CRTAPI1 RplDebugPrint( CONST CHAR * format, ...) +{ + va_list arglist; + + va_start( arglist, format); + + strcpy( RG_DebugPublicBuffer, RPL_PROMPT ); + vsprintf( RG_DebugPublicBuffer + sizeof( RPL_PROMPT) - 1, format, arglist); + DbgPrint( "%s\n", RG_DebugPublicBuffer); // for kernel debugger + printf( "%s\n", RG_DebugPublicBuffer); // for user debugger + + if ( RG_Assert != 0) { + ASSERT( FALSE); // break for checked build + DbgPrint( "[RplSvc] Running checked version of service on a free build.\n"); + printf( "[RplSvc] Running checked version of service on a free build.\n"); + DbgUserBreakPoint(); + } + + va_end( arglist); + +} // RplDebugPrint + + +#endif // RPL_DEBUG + + + diff --git a/private/net/svcdlls/rpl/convert/library.c b/private/net/svcdlls/rpl/convert/library.c new file mode 100644 index 000000000..1014cbef2 --- /dev/null +++ b/private/net/svcdlls/rpl/convert/library.c @@ -0,0 +1,330 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + library.c + +Abstract: + + Common routines used in CONVERT code. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + + Jon Newman (jonn) 06 - June - 1994 + Convert file from OEM code page + +--*/ + +#include "local.h" + + +LPWSTR ReadTextFile( + IN LPWSTR FilePath, + IN LPWSTR FileName, + IN DWORD MaxFileSize + ) +/*++ + +Routine Description: + + Reads text file, converts its content from dbcs to unicode, and returns + a pointer to newly allocate unicode buffer. + +Arguments: + +Return Value: + + Pointer to unicode buffer table if successful, NULL otherwise. + +--*/ +{ + PBYTE DbcsString = NULL; + DWORD DbcsSize; + PWCHAR UnicodeString = NULL; + DWORD UnicodeSize; + int UnicodeStringLength; + HANDLE FileHandle; + DWORD BytesRead; + BOOL success = FALSE; + PWCHAR pWchar; + WCHAR CompleteFilePath[ MAX_PATH+1]; + PWCHAR UseFilePath = FileName; + + CompleteFilePath[0] = L'\0'; + if ( FilePath != NULL && lstrlenW(FilePath) > 0) { + lstrcpyW( CompleteFilePath, FilePath); + if ( CompleteFilePath[ lstrlenW(CompleteFilePath)-1 ] != L'\\') { + lstrcatW( CompleteFilePath, L"\\"); + } + if ( FileName != NULL) { + lstrcatW( CompleteFilePath, FileName ); + } + UseFilePath = CompleteFilePath; + } + + FileHandle = CreateFile( UseFilePath, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0L); + if ( FileHandle == INVALID_HANDLE_VALUE) { + // + // Specifying a bad path (path with missing OS/2 rpl init files) + // is a common user error. Print out something for the user. + // + RplAssert( TRUE, ("CreateFile: Error = %d", GetLastError())); + RplPrintf1( RPLI_CVT_CannotOpenFile, UseFilePath); + goto exit; + } + DbcsSize = GetFileSize( FileHandle, NULL); // does not include 0x1A at the file end + if ( DbcsSize == INVALID_FILE_SIZE || DbcsSize > MaxFileSize) { + RplAssert( TRUE, ("DbcsSize = %d", DbcsSize)); + goto exit; + } + DbcsString = GlobalAlloc( GMEM_FIXED, DbcsSize); + if ( DbcsString == NULL) { + RplAssert( TRUE, ("GlobalAlloc: Error = %d", GetLastError())); + goto exit; + } + + UnicodeSize = ( DbcsSize + 1) * sizeof(WCHAR); // extra 1 for terminating NULL + UnicodeString = GlobalAlloc( GMEM_FIXED, UnicodeSize); + if ( UnicodeString == NULL) { + RplAssert( TRUE, ("GlobalAlloc: Error = %d", GetLastError())); + goto exit; + } + + if ( !ReadFile( FileHandle, DbcsString, DbcsSize, &BytesRead, NULL)) { + RplAssert( TRUE, ("ReadFile: Error = %d", GetLastError())); + goto exit; + } + + if ( BytesRead != DbcsSize) { + RplAssert( TRUE, ("BytesRead = %d, DbcsSize", BytesRead, DbcsSize)); + goto exit; + } + + UnicodeStringLength = MultiByteToWideChar( + CP_OEMCP, // file is in OEM codepage + MB_PRECOMPOSED, DbcsString, DbcsSize, UnicodeString, UnicodeSize); + if ( UnicodeStringLength == 0) { + RplAssert( TRUE, ("MultiByte...: Error = %d", GetLastError())); + goto exit; + } + + // + // If file has END_OF_TEXT_FILE_CHAR, truncate the text there. + // + pWchar = wcschr( UnicodeString, END_OF_TEXT_FILE_CHAR); + if ( pWchar != NULL) { + *pWchar = 0; + } + + success = TRUE; + +exit: + + if ( FileHandle != INVALID_HANDLE_VALUE) { + (VOID)CloseHandle( FileHandle); + } + if ( DbcsString != NULL) { + GlobalFree( DbcsString); + } + + if ( success != TRUE && UnicodeString != NULL) { + GlobalFree( UnicodeString); + UnicodeString = NULL; + } + + return( UnicodeString); + +} // ReadTextFile + + +PWCHAR GetFirstLine( PWCHAR Cursor) +/*++ + Skips all white characters. +--*/ +// +{ + // Read empty chars if there's some. + while( *Cursor != 0 && iswspace(*Cursor)) { + Cursor++; + } + + return( Cursor); +} + + + +PWCHAR GetNextLine( PWCHAR Cursor) +/*++ + Skips to the end of the current line. + Then skips all white characters. +--*/ +// +{ + // Read to end of line. + do { + Cursor++; + } while ( *Cursor != 0 && *Cursor != NEW_LINE_CHAR); + + // Read empty chars if there's some. + while( *Cursor != 0 && iswspace(*Cursor)) { + Cursor++; + } + + return( Cursor); +} + + +DWORD OffsetAfterComment( IN PWCHAR Cursor) +/*++ + Returns the offset of the first non-white non-newline character + after an optional RPL_COMMENT. This routine does not & should + not cross line boundaries (this is reserved for GetNewLine). +--*/ +{ +#define RPL_COMMENT L";*;" +#define RPL_COMMENT_LENGTH (sizeof(RPL_COMMENT)/sizeof(WCHAR) - 1) + + PWCHAR End; + + if ( wcsncmp( Cursor, RPL_COMMENT, RPL_COMMENT_LENGTH)) { + return( 0); // there is no RPL_COMMENT + } + for ( End = Cursor + RPL_COMMENT_LENGTH; + *End != 0 && *End != NEW_LINE_CHAR && iswspace(*End); + End++) { + NOTHING; + } + if ( *End == NEW_LINE_CHAR) { + // + // We went to far. Must decrement end pointer or + // GetNewLine() will advance to the second next line. + // + End--; + } + return( (DWORD)(End - Cursor)); +} + + +BOOL Find( IN JET_TABLEID TableId, IN PWCHAR Name) +{ + JET_ERR JetError; + + JetError = JetMove( SesId, TableId, JET_MoveFirst, 0); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("JetMove failed err=%d", JetError)); + return( FALSE); + } + JetError = JetMakeKey( SesId, TableId, Name, + ( wcslen( Name) + 1) * sizeof(WCHAR), JET_bitNewKey); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("MakeKey failed err=%d", JetError)); + return( FALSE); + } + JetError = JetSeek( SesId, TableId, JET_bitSeekEQ); + if ( JetError != JET_errSuccess) { + if ( JetError == JET_errRecordNotFound) { + // + // This is an expected error => no break for this. + // + RplDbgPrint(("JetSeek for %ws failed with error = %d.\n", Name, JetError)); + } else { + RplAssert( TRUE, ("JetSeek failed err=%d", JetError)); + } + return( FALSE); + } + return( TRUE); +} + + +VOID Enum( IN JET_TABLEID TableId, IN JET_COLUMNID ColumnId, IN PCHAR IndexName) +{ + WCHAR Name[ 20]; + DWORD NameSize; + JET_ERR ForJetError; + JET_ERR JetError; + + Call( JetSetCurrentIndex( SesId, TableId, IndexName)); + + for ( ForJetError = JetMove( SesId, TableId, JET_MoveFirst, 0); + ForJetError == JET_errSuccess; + ForJetError = JetMove( SesId, TableId, JET_MoveNext, 0)) { + + JetError = JetRetrieveColumn( SesId, TableId, + ColumnId, Name, sizeof( Name), &NameSize, 0, NULL); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("RetriveColumn failed err=%d", JetError)); + continue; + } + RplDbgPrint(( "%ws\n", Name)); + } +} + + +VOID ListTable( IN PCHAR TableName, IN PCHAR ColumnName, IN PCHAR IndexName) +{ + JET_TABLEID TableId; + JET_COLUMNDEF ColumnDef; + + Call( JetOpenTable( SesId, DbId, TableName, NULL, 0, + JET_bitTableDenyWrite, &TableId)); + + Call( JetGetTableColumnInfo( SesId, TableId, ColumnName, &ColumnDef, + sizeof( ColumnDef), JET_ColInfo)); + + RplDbgPrint(( "\tTable: %s\n", TableName)); + + Enum( TableId, ColumnDef.columnid, IndexName); + + Call( JetCloseTable( SesId, TableId)); +} + + +PWCHAR AddFileExtension( + IN PWCHAR FilePath, + IN PWCHAR FileExtension, + IN BOOLEAN ExtensionOK + ) +{ +#define DOT_CHAR L'.' +#define BACK_SLASH_CHAR L'\\' + PWCHAR FilePathEx; + PWCHAR pDot; + DWORD Length; + DWORD Error; + + if ( FilePath == NULL) { + RplAssert( TRUE, ("FilePath is NULL")); + return( NULL); + } + + pDot = wcsrchr( FilePath, DOT_CHAR); + if ( pDot != NULL) { + // + // Found a DOT. FilePath may have an extension. + // + if ( wcschr( pDot, BACK_SLASH_CHAR) == NULL) { + // + // There is no backslash after the DOT. FilePath has an extension. + // Return NULL if caller insists that file should have no extension. + // + return( ExtensionOK ? FilePath : NULL); + } + } + Length = wcslen( FilePath) + wcslen( FileExtension); + FilePathEx = GlobalAlloc( GMEM_FIXED, (Length + 1) * sizeof(WCHAR)); + if ( FilePathEx == NULL) { + Error = GetLastError(); + RplAssert( TRUE, ("GlobalAlloc: Error = %d", Error)); + return( NULL); + } + wcscpy( FilePathEx, FilePath); + wcscat( FilePathEx, FileExtension); + return( FilePathEx); +} diff --git a/private/net/svcdlls/rpl/convert/local.h b/private/net/svcdlls/rpl/convert/local.h new file mode 100644 index 000000000..658da46bf --- /dev/null +++ b/private/net/svcdlls/rpl/convert/local.h @@ -0,0 +1,227 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + local.h + +Abstract: + + Main include file for Remote initial Program Load CONVERT program. + This program converts from RPL.MAP & RPLMGR.INI, used in OS/2 + lm2.0 and up, to NT database. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include <nt.h> // ntexapi.h\NtQuerySystemTime +#include <ntrtl.h> // RtlTimeToSecondsSince1970 +#include <nturtl.h> + +#include <windows.h> // DWORD, IN, File APIs, etc. +#include <stdlib.h> +#include <lmcons.h> + +#include <stdio.h> // vsprintf +#include <ctype.h> // isspace + +#include <lmerr.h> // NERR_RplBootStartFailed - used to be here + +// +#include <lmapibuf.h> // NetApiBufferFree +#include <netlib.h> + +#include <lmsvc.h> + +#include <lmalert.h> // STD_ALERT ALERT_OTHER_INFO + +#include <lmerrlog.h> +#include <alertmsg.h> +#include <lmserver.h> +#include <netlib.h> +#include <netlock.h> // Lock data types, functions, and macros. +#include <thread.h> // FORMAT_NET_THREAD_ID, NetpCurrentThread(). + +#include <lmshare.h> // PSHARE_INFO_2 +#include <lmaccess.h> // NetGroupGetInfo +#include <lmconfig.h> // NetConfigGet +#include <nb30.h> // NCB + +#include <lmrpl.h> + +// +// Global types and constants (used in all RPL server files). +// + +#include <riplcons.h> // includes __JET500 flag +#include <jet.h> +#include <rpllib.h> // AddKey(), MapJetError(), FillTcpIpString() + +#include <rpldb.h> +#include "nlstxt.h" // RPLI_CVT manifests + +#define EQUALS_CHAR L'=' + +#define RPL_BUGBUG_ERROR 10999 // need to get rid of these + +#if DBG +#define RPL_DEBUG // used in rpldata.h +#endif + +// +// Declare/Define all global variables. +// + +#include "rpldata.h" // defines/declares global data structures + +// +// jet call macros: +// Call - jet call ignore error +// CallR - jet call RETURN on error +// CallB - jet call return BOOLEAN (false) on error +// CallM - jet call return MAPPED error +// + +#ifdef RPL_DEBUG + +#define RplDbgPrint( _x_) printf( "[DebugPrint] "); printf _x_ + +#define RplBreakPoint() if ( DebugLevel) DbgUserBreakPoint() + +#define RplAssert( DBG_CONDITION, DBG_PRINT_ARGUMENTS) \ + { \ + if ( DBG_CONDITION) { \ + RplDbgPrint( DBG_PRINT_ARGUMENTS); \ + RplDbgPrint((" File %s, Line %d\n", __FILE__, __LINE__)); \ + RplBreakPoint(); \ + } \ + } +#define Call( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + printf("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + RplBreakPoint(); \ + } \ + } \ + } +#define CallR( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + printf("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + RplBreakPoint(); \ + return; \ + } \ + } \ + } + +#define CallB( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + printf("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + RplBreakPoint(); \ + return( FALSE); \ + } \ + } \ + } +#define CallM( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + printf("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + RplBreakPoint(); \ + return( NERR_RplInternal); \ + } \ + } \ + } +#define CallJ( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + printf("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + RplBreakPoint(); \ + Error = NERR_RplInternal; \ + goto cleanup; \ + } \ + } \ + } + +#else +#define RplDbgPrint( _x_) +#define RplBreakPoint() +#define RplAssert( DBG_CONDITION, DBG_PRINT_ARGUMENTS) +#define Call( fn ) { if ( fn < 0) { NOTHING;} } +#define CallR( fn ) { if ( fn < 0) { return;} } +#define CallB( fn ) { if ( fn < 0) { return( FALSE);} } +#define CallM( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError < 0) { \ + return( NERR_RplInternal); \ + } \ + } +#define CallJ( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError < 0) { \ + Error = NERR_RplInternal; \ + goto cleanup; \ + } \ + } +#endif + + +LPWSTR ReadTextFile( IN LPWSTR FilePath, IN LPWSTR FileName, IN DWORD MaxFileSize); +PWCHAR GetFirstLine( PWCHAR Cursor); +PWCHAR GetNextLine( PWCHAR Cursor); +DWORD OffsetAfterComment( IN PWCHAR Cursor); +BOOL Find( IN JET_TABLEID TableId, IN PWCHAR Name); +VOID Enum( IN JET_TABLEID TableId, IN JET_COLUMNID ColumnId, IN PCHAR ndexName); +VOID ListTable( IN PCHAR TableName, IN PCHAR ColumnName, IN PCHAR IndexName); +PWCHAR AddFileExtension( + IN PWCHAR FilePath, + IN PWCHAR FileExtension, + IN BOOLEAN ExtensionOK + ); + +DWORD BootCreateTable( VOID); +VOID ProcessBoot( PWCHAR * Fields); +VOID BootListTable( VOID); +BOOL FindBoot( IN PWCHAR BootName); + +DWORD ProcessRplmgrIni( IN LPWSTR FilePath ); +BOOL FindConfig( IN PWCHAR ConfigName); +VOID ConfigPruneTable( VOID); +VOID ConfigListTable( VOID); +DWORD CloseConfigTable( VOID); + +DWORD ProfileCreateTable( VOID); +BOOL FindProfile( IN PWCHAR ProfileName); +VOID ProfileListTable( VOID); +VOID ProcessProfile( PWCHAR * Fields); +VOID ProfilePruneTable( VOID); + +DWORD WkstaCreateTable( VOID); +VOID ProcessWksta( PWCHAR * Fields); +VOID WkstaPruneTable( VOID); +VOID WkstaListTable( VOID); +BOOL ListWkstaInfo( IN PWCHAR AdapterName); + +DWORD AdapterCreateTable( VOID); + +DWORD VendorCreateTable( VOID); + + diff --git a/private/net/svcdlls/rpl/convert/makefile b/private/net/svcdlls/rpl/convert/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/rpl/convert/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/convert/makefile.inc b/private/net/svcdlls/rpl/convert/makefile.inc new file mode 100644 index 000000000..f28149e83 --- /dev/null +++ b/private/net/svcdlls/rpl/convert/makefile.inc @@ -0,0 +1,4 @@ +nlstxt.rc: msg00001.bin + +nlstxt.h msg00001.bin: nlstxt.mc + mc -v nlstxt.mc diff --git a/private/net/svcdlls/rpl/convert/nlstxt.mc b/private/net/svcdlls/rpl/convert/nlstxt.mc new file mode 100644 index 000000000..8b8e47f8e --- /dev/null +++ b/private/net/svcdlls/rpl/convert/nlstxt.mc @@ -0,0 +1,214 @@ +;/*++ +; +;Copyright (c) 1992 Microsoft Corporation +; +;Module Name: +; +; rplimsg.h +; +;Abstract: +; +; Definitions for RPLCNV command private errors. +; +;Author: +; +; Jon Newman (jonn) 21 - April - 1994 +; +;Revision History: +; +; 21-Apr-1994 jonn +; templated from AT command +; +;Notes: +; +; This file is generated by the MC tool from the lmatmsg.mc file. +; +;--*/ + +MessageId=11000 SymbolicName=RPLI_CVT_NoMDB +Language=English +File system.mdb is absent.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_StopService +Language=English +Remote boot service must be stopped for this program to run.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_InitError +Language=English +Unexpected initialization error.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_CannotOpenFile +Language=English +Cannot open %1!ws!%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_ProfileInvalid +Language=English +Not converting %1!ws! profile because its name is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_ProfileInvalidConfig +Language=English +Not converting %1!ws! profile because its configuration %2!ws! +is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_ProfileInvalidFit +Language=English +Not converting %1!ws! profile because its fit file %2!ws! +is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_ProfileInvalidBoot +Language=English +Not converting %1!ws! profile because its boot block name %2!ws! +is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_USAGE +Language=English +The RPLCNV utility (RemoteBoot conversion program) converts +rpl.map and rplmgr.ini used by OS/2 LANMAN Remoteboot service into system.mdb +and rplsvc.mdb files used by NT Remoteboot service. Install the Remoteboot +service before running the Remoteboot conversion program, and +make sure a copy of the original system.mdb file is in +the root of the RPL file tree as specified during RPL installation.%n +%n +RPLCNV [Path]%n +%n +Path Specifies a fully qualified path to the directory containing the +rpl.map and rplmgr.ini files used by OS/2 LANMAN RemoteBoot service. +If this parameter is omitted it is assumed that these files are in the +current directory or the root of the RPL file tree. +. + +MessageId=+1 SymbolicName=RPLI_CVT_NoMAP_INI +Language=English +Files rpl.map and/or rplmgr.ini are absent.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_NoSystemMdb +Language=English +File system.mdb is absent from the root of the RPL file tree. +RPLCNV cannot convert rpl.map and rplmgr.ini unless a copy +of the original system.mdb file is in the root of the RPL file tree.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_RplsvcMdbExists +Language=English +File rplsvc.mdb already exists in the root of the RPL file tree. +RPLCNV will not create a new one until the existing one is moved, +renamed or deleted.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_OldSystemMdb +Language=English +File system.mdb exists in the root of the RPL file tree but is not +a copy of the original system.mdb file. RPLCNV cannot convert rpl.map +and rplmgr.ini unless a copy of the original system.mdb file is in the +root of the RPL file tree.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_BootNameTooLong +Language=English +Boot block record with name %1!ws! is not converted because +its name is too long or invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_BbcFileTooLong +Language=English +Boot block record with name %1!ws! is not converted because +path to boot block configuration file %2!ws! is too long or +invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_BadVendorName +Language=English +Boot block record with name %1!ws! is not converted because +vendor name %2!ws! is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaInvalid +Language=English +Workstation record with name %1!ws! is not converted because +its name is too long or invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaInvalidAdapter +Language=English +Workstation record with name %1!ws! is not converted because +adapter id %2!ws! is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaInvalidLogon +Language=English +Workstation record with name %1!ws! is not converted because +remoteboot username/password prompting field %2!ws! is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaInvalidFit +Language=English +Workstation record with name %1!ws! is not converted because +fit name %2!ws! is too long or invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaInvalidSharing +Language=English +Workstation record with name %1!ws! is not converted because +sharing type %2!ws! is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaDisabledBoot +Language=English +Workstation record with name %1!ws! is not converted since its +reference to block record %2!ws! is disabled.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaInvalidBoot +Language=English +Workstation record with name %1!ws! is not converted because +boot block name %2!ws! is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaInvalidProfile +Language=English +Workstation record with name %1!ws! is not converted because +profile name %2!ws! is invalid.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaDuplicateName +Language=English +Workstation record is not converted because it uses a duplicate computer name +(%1!ws!) or a duplicate adapter id (%2!ws!).%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_WkstaDefaultProfile +Language=English +Workstation record with computer name %1!ws! is not converted +because it uses the obsolete DEFAULT profile.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_ConfigNoPersonalFIT +Language=English +Not converting %1!ws! configuration because it does not have +a fit file for personal profiles.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_ConfigNoOS2 +Language=English +Not converting %1!ws! configuration because it is an OS/2 +client configuration.%n +. + +MessageId=+1 SymbolicName=RPLI_CVT_ConfigInvalid +Language=English +Not converting %1!ws! configuration because the value of +keyword %2!ws! is absent or invalid.%n +. + + + +
\ No newline at end of file diff --git a/private/net/svcdlls/rpl/convert/profile.c b/private/net/svcdlls/rpl/convert/profile.c new file mode 100644 index 000000000..f8f0c14a8 --- /dev/null +++ b/private/net/svcdlls/rpl/convert/profile.c @@ -0,0 +1,270 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + profile.c + +Abstract: + + Creates profile table. Parses old style RPL.MAP profile records and + creates corresponding entries in jet database table. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#define RPLPROFILE_ALLOCATE +#include "profile.h" +#undef RPLPROFILE_ALLOCATE + + +DWORD ProfileCreateTable( VOID) +{ + JET_COLUMNDEF ColumnDef; + JET_ERR JetError; + DWORD index; + DWORD Offset; + CHAR IndexKey[ 255]; + + JetError = JetCreateTable( SesId, DbId, PROFILE_TABLE_NAME, + PROFILE_TABLE_PAGE_COUNT, PROFILE_TABLE_DENSITY, &ProfileTableId); + + // + // Create columns. First initalize fields that do not change between + // addition of columns. + // + ColumnDef.cbStruct = sizeof(ColumnDef); + ColumnDef.columnid = 0; + ColumnDef.wCountry = 1; + ColumnDef.langid = 0x0409; // USA english + ColumnDef.cp = 1200; // UNICODE codepage + ColumnDef.wCollate = 0; + ColumnDef.cbMax = 0; + ColumnDef.grbit = 0; // variable length binary and text data. + + for ( index = 0; index < PROFILE_TABLE_LENGTH; index++ ) { + + ColumnDef.coltyp = ProfileTable[ index].ColumnType; + + Call( JetAddColumn( SesId, ProfileTableId, + ProfileTable[ index].ColumnName, &ColumnDef, + NULL, 0, &ProfileTable[ index].ColumnId)); + } + + Offset = AddKey( IndexKey, '+', ProfileTable[ PROFILE_ProfileName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, ProfileTableId, PROFILE_INDEX_ProfileName, + JET_bitIndexPrimary, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // +BootName+ProfileName index is used to enumerate all profiles for + // a given VendorId. + // + Offset = AddKey( IndexKey, '+', ProfileTable[ PROFILE_BootName].ColumnName); + Offset += AddKey( IndexKey + Offset, '+', ProfileTable[ PROFILE_ProfileName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, ProfileTableId, PROFILE_INDEX_BootNameProfileName, + JET_bitIndexUnique, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // +ConfigName+ProfileName index is used to find if a there is a + // profile record for a given configuration record + // + Offset = AddKey( IndexKey, '+', ProfileTable[ PROFILE_ConfigName].ColumnName); + Offset += AddKey( IndexKey + Offset, '+', ProfileTable[ PROFILE_ProfileName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, ProfileTableId, PROFILE_INDEX_ConfigNameProfileName, + JET_bitIndexUnique, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // Make profile name a current index - used to validate wkstas. + // + JetError = JetSetCurrentIndex( SesId, ProfileTableId, PROFILE_INDEX_ProfileName); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("SetCurrentIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + return( ERROR_SUCCESS); +} + + +VOID ProcessProfile( PWCHAR * Fields) +{ +// +// PROFILE_COMMENT_INDEX would be equal to 15 if we were to count fields +// from 1 (not 0) and count ",,," as a single field (not 3 fields). +// +#define PROFILE_FITFILE_INDEX 3 // common fit file name +#define PROFILE_CONFIGNAME_INDEX 12 // configuration name +#define PROFILE_BOOTNAME_INDEX 13 // boot block identifier +#define PROFILE_PROFILENAME_INDEX 15 // profile name +#define PROFILE_COMMENT_INDEX 16 // profile comment + + PWCHAR ProfileComment; + PWCHAR ProfileName; + PWCHAR BootName; + PWCHAR ConfigName; + PWCHAR FitShared; + PWCHAR FitPersonal; + DWORD Flags; + + ProfileName = Fields[ PROFILE_PROFILENAME_INDEX]; + if ( !ValidName( ProfileName, RPL_MAX_PROFILE_NAME_LENGTH, TRUE)) { + RplPrintf1( RPLI_CVT_ProfileInvalid, ProfileName); + RplAssert( TRUE, ("Bad profile name %ws", ProfileName)); + return; + } + _wcsupr( ProfileName); + + FitShared = AddFileExtension( Fields[ PROFILE_FITFILE_INDEX], L".FIT", FALSE); + FitPersonal = AddFileExtension( Fields[ PROFILE_FITFILE_INDEX], L"P.FIT", FALSE); + if ( !ValidName( FitShared, RPL_MAX_STRING_LENGTH, TRUE) || + !ValidName( FitPersonal, RPL_MAX_STRING_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_ProfileInvalidFit, ProfileName, Fields[ PROFILE_FITFILE_INDEX]); + RplAssert( TRUE, ("Bad fit name %ws", Fields[ PROFILE_FITFILE_INDEX])); + return; + } + + ConfigName = Fields[ PROFILE_CONFIGNAME_INDEX]; + if ( !ValidName( ConfigName, RPL_MAX_CONFIG_NAME_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_ProfileInvalidConfig, ProfileName, ConfigName); + RplAssert( TRUE, ("Bad config name %ws", ConfigName)); + return; + } + _wcsupr( ConfigName); + + BootName = Fields[ PROFILE_BOOTNAME_INDEX]; + RplAssert( *BootName != L'R', ("BootBlockId=%ws", BootName)); + BootName++; // skip leading 'R' in server name + if ( !ValidName( BootName, RPL_MAX_BOOT_NAME_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_ProfileInvalidBoot, ProfileName, Fields[ PROFILE_BOOTNAME_INDEX]); + RplAssert( TRUE, ("Bad boot name %ws", Fields[ PROFILE_BOOTNAME_INDEX])); + return; + } + _wcsupr( BootName); + + ProfileComment = Fields[ PROFILE_COMMENT_INDEX]; + if ( RPL_STRING_TOO_LONG( ProfileComment)) { + ProfileComment[ RPL_MAX_STRING_LENGTH] = 0; // silently truncate it + } + + Call( JetPrepareUpdate( SesId, ProfileTableId, JET_prepInsert)); + + Call( JetSetColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_ProfileName].ColumnId, ProfileName, + (wcslen( ProfileName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_ProfileComment].ColumnId, ProfileComment, + (wcslen( ProfileComment) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_ConfigName].ColumnId, ConfigName, + (wcslen( ConfigName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_BootName].ColumnId, BootName, + (wcslen( BootName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_FitShared].ColumnId, FitShared, + (wcslen( FitShared) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_FitPersonal].ColumnId, FitPersonal, + (wcslen( FitPersonal) + 1) * sizeof(WCHAR), 0, NULL)); + + Flags = 0; + Call( JetSetColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_Flags].ColumnId, &Flags, sizeof(Flags), 0, NULL)); + + + Call( JetUpdate( SesId, ProfileTableId, NULL, 0, NULL)); +} + + +VOID ProfilePruneTable( VOID) +/*++ + Eliminate profile records that do not have a corresponding config record + defined. +--*/ +{ + WCHAR Name[ 20]; + DWORD NameSize; + JET_ERR ForJetError; + JET_ERR JetError; + + for ( ForJetError = JetMove( SesId, ProfileTableId, JET_MoveFirst, 0); + ForJetError == JET_errSuccess; + ForJetError = JetMove( SesId, ProfileTableId, JET_MoveNext, 0)) { + + JetError = JetRetrieveColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_BootName].ColumnId, Name, + sizeof( Name), &NameSize, 0, NULL); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("RetriveColumn failed err=%d", JetError)); + Call( JetDelete( SesId, ProfileTableId)); + continue; + } + if ( !FindBoot( Name)) { + Call( JetDelete( SesId, ProfileTableId)); + continue; + } + + JetError = JetRetrieveColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_ConfigName].ColumnId, Name, + sizeof( Name), &NameSize, 0, NULL); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("RetriveColumn failed err=%d", JetError)); + Call( JetDelete( SesId, ProfileTableId)); + continue; + } + if ( !FindConfig( Name)) { + WCHAR ProfileName[ 20]; + DWORD ProfileNameSize; + JetError = JetRetrieveColumn( SesId, ProfileTableId, + ProfileTable[ PROFILE_ProfileName].ColumnId, ProfileName, + sizeof( ProfileName), &ProfileNameSize, 0, NULL); + if ( JetError == JET_errSuccess && ProfileNameSize <= sizeof( ProfileName) ) { + RplPrintf2( RPLI_CVT_ProfileInvalidConfig, ProfileName, Name); + } + Call( JetDelete( SesId, ProfileTableId)); + continue; + } + } +} + + + +BOOL FindProfile( IN PWCHAR ProfileName) +{ + return( Find( ProfileTableId, ProfileName)); +} + + + +VOID ProfileListTable( VOID) +{ + ListTable( PROFILE_TABLE_NAME, ProfileTable[ PROFILE_ProfileName].ColumnName, + PROFILE_INDEX_ProfileName); +} diff --git a/private/net/svcdlls/rpl/convert/rpldata.h b/private/net/svcdlls/rpl/convert/rpldata.h new file mode 100644 index 000000000..d62c9b2e5 --- /dev/null +++ b/private/net/svcdlls/rpl/convert/rpldata.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rpldata.h + +Abstract: + + RPL covert global variables (declarations & definitions). + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +// +// rplmain.c will #include this file with RPLDATA_ALLOCATE defined. +// That will cause each of these variables to be allocated. +// +#ifdef RPLDATA_ALLOCATE +#define EXTERN +#define INIT( _x) = _x +#else +#define EXTERN extern +#define INIT( _x) +#endif + +EXTERN JET_SESID SesId; +EXTERN JET_DBID DbId; +EXTERN JET_INSTANCE JetInstance; + +EXTERN CHAR G_ServiceDatabaseA[ MAX_PATH ]; +EXTERN WCHAR G_ServiceDirectoryW[ MAX_PATH ]; + +#ifdef RPL_DEBUG +EXTERN int DebugLevel; +#endif + diff --git a/private/net/svcdlls/rpl/convert/rplmain.c b/private/net/svcdlls/rpl/convert/rplmain.c new file mode 100644 index 000000000..a2643e0b6 --- /dev/null +++ b/private/net/svcdlls/rpl/convert/rplmain.c @@ -0,0 +1,740 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + rplmain.c + +Abstract: + + Converts old style (OS/2) files RPL.MAP & RPLMGR.INI + into a new style database to be used with NT rpl server. + + BUGBUG Should polish and make WIN32 application out of this. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#define RPLDATA_ALLOCATE +#include "local.h" +#undef RPLDATA_ALLOCATE +#include <shellapi.h> +#include "boot.h" +#include "config.h" +#include "profile.h" +#include "wksta.h" +#include "adapter.h" +#include "vendor.h" + +#define COMMA_CHAR L',' +PWCHAR RplMapFile = L"rpl.map"; +WCHAR RG_NulWchar = 0; // used for empty entries in rpl.map +// +// RPL.MAP defines +// +#define MAX_RPL_MAP_FILE_SIZE 0xFFFE // BUGBUG some arbitrary value +typedef enum _MAP_RECORD_TYPE { + RecordTypeComment = 0, // comment line in PRL.MAP file + RecordTypeBoot, // boot block records, documented in os/2 lm2.0 & up + RecordTypePcDosBoot, // boot block records, undocumented but supported + RecordTypeProfile, // profile record + RecordTypeUniqueAdapter,// wksta record containing unique adapter id + RecordTypeWildAdapter, // wksta record containing wildcards in adapter id + RecordTypeUnknown // unknown record +} MAP_RECORD_TYPE; + +#define EXTENDED_BOOT_ENTRIES L"yyyyyyyyyyyy" +#define EXTENDED_BOOT_ENTRIES2 L"RPL~Header~~" +#define PCDOS_BOOT_ENTRIES L"xxxxxxxxxxxx" +#define PCDOS_BOOT_ENTRIES2 L"PCDOS~Header" +#define PROFILE_ADAPTER_ID L"000000000000" // first field of profile record + + + +#define MAX_RPL_FIELD 20 // max number of entries on rpl.map line + + + + +BOOL StringsSpaceEqual( IN PWCHAR str1, IN PWCHAR str2 ) +/*++ + +Routine Description: + + Compare strings up to the first space or NULL character in each + string, returning TRUE if strings are equal, FALSE otherwise. + +Arguments: + + str1 - first string + str2 - second string + +Return Value: + + TRUE if strings are equal, FALSE otherwise. + +--*/ +{ + WCHAR ch1; + +#ifdef NOT_YET + if ( str1 == NULL || str2 == NULL) { + str1 = (str1 != NULL) ? str1 : str2; + if ( str2 == NULL) { + return( TRUE); // both strings are NULL + } + while ( iswspace( *str1++)) { + NOTHING; // check if not NULL string contains spaces only + } + return( *str1 == 0); + } +#endif // NOT_YET + + // + // Compare strings until the first space or NULL character + // (in the first string) or until we find the first different character. + // + while ( (ch1 = *str1) && !iswspace(ch1) && ch1 == *str2) { + str1++, str2++; + } + + // + // For strings to be equal, both characters must be NULL or space. + // + if ( (!ch1 || iswspace(ch1)) && (!(ch1 = *str2) || iswspace(ch1))) + { + return( TRUE); + } + + return( FALSE); +} + + +BOOL IsWildAdapterName( IN PWCHAR Cursor) +/*++ + +Routine Description: + + Returns TRUE if the input string may be the adapter id of a wksta group. + + Adapter id must be terminated with space AND must have exactly + RPL_ADAPTER_NAME_LENGTH hex digits. + +Arguments: + + Cursor - pointer to adapter id string + +Return Value: + Returns TRUE if input string may be a unique adapter id of a client, + else FALSE. + +--*/ +{ + DWORD count = 0; + WCHAR ch; + + for ( count = 0; (ch = *Cursor) == '?' || iswxdigit(ch); count++) { + Cursor++; + } + + if ( !iswspace(ch) || count != RPL_ADAPTER_NAME_LENGTH) { + return( FALSE); + } + + return( TRUE); +} + + +BOOL IsAdapterName( IN PWCHAR Cursor) +/*++ + +Routine Description: + + Returns TRUE if the input string may be the adapter id of a wksta. + + Adapter id must be terminated with space AND must have + exactly RPL_ADAPTER_NAME_LENGTH hex digits + +Arguments: + + Cursor - pointer to adapter id string + +Return Value: + Returns TRUE if input string may be a unique adapter id of a client, + else FALSE. + +--*/ +{ + DWORD count; + + for ( count = 0; iswxdigit(*Cursor); count++) { + Cursor++; + } + + if ( !iswspace(*Cursor) || count != RPL_ADAPTER_NAME_LENGTH) { + return( FALSE); + } + return( TRUE); +} + + +MAP_RECORD_TYPE RplGetRecordType( IN PWCHAR Cursor) +/*++ + +Routine Description: + + Returns the type of a line in RPL.MAP. + +Arguments: + Cursor - pointer to line from RPL.map file + +Return Value: + Returns type of a line in RPL.map file + +--*/ +{ + // strings can be either nul or space terminated + + if ( *Cursor == COMMENT_CHAR) { + + return( RecordTypeComment); + } + + if ( StringsSpaceEqual( Cursor, EXTENDED_BOOT_ENTRIES) || + StringsSpaceEqual( Cursor, EXTENDED_BOOT_ENTRIES2)) { + + return( RecordTypeBoot); + } + + if ( StringsSpaceEqual( Cursor, PCDOS_BOOT_ENTRIES) || + StringsSpaceEqual( Cursor, PCDOS_BOOT_ENTRIES2)) { + + return( RecordTypePcDosBoot); + } + + if ( StringsSpaceEqual( Cursor, PROFILE_ADAPTER_ID)) { + + return( RecordTypeProfile); + } + + if ( IsAdapterName( Cursor)) { + return( RecordTypeUniqueAdapter); + } + + if ( IsWildAdapterName( Cursor)) { + return( RecordTypeWildAdapter); + } + + return( RecordTypeUnknown); +} + + + +PWCHAR ScanChar( + IN PWCHAR String, + IN WCHAR ch + ) +/*++ + +Routine Description: + + Searches for the first desired character in the string. The string + should be NULL terminated. + +Arguments: + String - string which is NULL terminated + ch - character we are searching for + +Return Value: + Pointer to the first desired character (if there is such character), + else pointer to the last character before terminating NULL. + +--*/ +{ + while ( *String && *String != ch) { + String++; + } + return( String); +} + + +PWCHAR ScanNonSpace( IN PWCHAR String) +/*++ + +Routine Description: + Returns pointer to the first non space character in the string. + This may be pointer to NULL if string has no space char. + +Arguments: + string - NULL terminated string to search in + +Return Value: + Pointer of the first non space character in the string. + +--*/ +{ + while( iswspace(*String)) { // iswspace(0) is 0 + String++; + } + return( String); +} + + + +PWCHAR ScanSpace( IN PWCHAR String) +/*++ + +Routine Description: + + Returns pointer to the first space character in the string if it + can find a space character in the string. Else, it returns pointer + to zero character ('\0'). + +Arguments: + String - where we are searching for space character + +Return Value: + Pointer to the first space character (if there is a space char) or + pointer to zero. + +--*/ +{ + while ( *String && !iswspace(*String)) { + String++; + } + return( String); +} + + +BOOL LineToWords( + IN PWCHAR Cursor, + IN PWCHAR * Fields, + IN DWORD FieldsLength + ) +/*++ + +Routine Description: + Breaks the line the words and returns the pointer to a word (string) table. + + Note that we do special line parsing when current table index is 9, 10 + or 11. E.g. field ",,," of RPL.map line will result in three table + entries instead of just one. + +Arguments: + Cursor - ptr to line string + Fields - pointer to string table describing fields in RPL.MAP line + FieldsLength - max number of entries in fields string table, + not counting the terminal NULL entry +Return Value: + None. + +--*/ +{ +#define FIRST_EXTRA_MEM 9 +#define LAST_EXTRA_MEM 11 + PWCHAR str; + DWORD index; + DWORD length; + + + for ( index = 0; index < FieldsLength; index++) { + + if (*Cursor) { + + // + // check if extra mem field(s) + // + + if ( index >= FIRST_EXTRA_MEM && index <= LAST_EXTRA_MEM) { + length = ScanChar( Cursor, COMMA_CHAR) - Cursor; + if ( Cursor[ length] == COMMA_CHAR) { + length++; + } + } else { + length = ScanSpace( Cursor) - Cursor; + } + + if (length == 0 || (length == 1 && *Cursor == TILDE_CHAR)) { + + Fields[ index] = &RG_NulWchar; + + } else { + + str = Fields[ index] = GlobalAlloc( GMEM_FIXED, (length + 1) * sizeof( WCHAR)); + if ( str == NULL) { + return( FALSE); + } + memcpy( str, Cursor, length * sizeof( WCHAR)); + str[ length] = 0; + + // replace all TILDE_CHAR-s in the string + while (*(str = ScanChar( str, TILDE_CHAR )) == TILDE_CHAR) { + *str = SPACE_CHAR; + } + } + Cursor += length; + + } else { + Fields[ index] = &RG_NulWchar; + } + + // + // jump over spaces + // + + Cursor = ScanNonSpace( Cursor); + } + + Fields[ index] = NULL; // terminate the string table + return( TRUE); +} + + +DWORD ProcessRplMap( IN LPWSTR FilePath) +{ + PWCHAR Cursor; + PWCHAR String; + DWORD Error; + LPWSTR Fields[ MAX_RPL_FIELD + 1]; // add 1 for NULL terminator + + Error = BootCreateTable(); + if ( Error != ERROR_SUCCESS) { + return( Error); + } + + Error = ProfileCreateTable(); + if ( Error != ERROR_SUCCESS) { + return( Error); + } + + Error = WkstaCreateTable(); + if ( Error != ERROR_SUCCESS) { + return( Error); + } + + Error = AdapterCreateTable(); + if ( Error != ERROR_SUCCESS) { + return( Error); + } + + String = ReadTextFile( FilePath, RplMapFile, MAX_RPL_MAP_FILE_SIZE); + if ( String == NULL) { + return( GetLastError()); + } + + for ( Cursor = GetFirstLine( String); + *Cursor != 0; + Cursor = GetNextLine( Cursor)) { + + Cursor += OffsetAfterComment( Cursor); + switch( RplGetRecordType( Cursor)) { + case RecordTypePcDosBoot: + NOTHING; + break; + case RecordTypeBoot: // os/2 lm2.0 & higher, boot block record + LineToWords( Cursor, Fields, MAX_RPL_FIELD); + ProcessBoot( Fields); + break; + case RecordTypeProfile: + LineToWords( Cursor, Fields, MAX_RPL_FIELD); + ProcessProfile( Fields); + break; + case RecordTypeUniqueAdapter: + LineToWords( Cursor, Fields, MAX_RPL_FIELD); + ProcessWksta( Fields); + break; + case RecordTypeWildAdapter: + NOTHING; + break; + case RecordTypeComment: + NOTHING; + break; + default: // unexpected line + DbgUserBreakPoint(); + break; + } + } + + if ( GlobalFree( String) != NULL) { + RplAssert( TRUE, ("GlobalFree: Error=%d", GetLastError())); + } + + return( ERROR_SUCCESS); +} + +VOID GlobalInit() +{ +#ifdef RPL_DEBUG + DebugLevel = 0; +#endif + SesId = 0; + DbId = 0; + JetInstance = 0; + BootTableId = 0; + ConfigTableId = 0; + ProfileTableId = 0; + WkstaTableId = 0; + AdapterTableId = 0; +} + + +VOID DbCleanup() +{ + if ( VendorTableId != 0) { + Call( JetCloseTable( SesId, VendorTableId)); + } + if ( BootTableId != 0) { + Call( JetCloseTable( SesId, BootTableId)); + } + if ( ConfigTableId != 0) { + Call( JetCloseTable( SesId, ConfigTableId)); + } + if ( ProfileTableId != 0) { + Call( JetCloseTable( SesId, ProfileTableId)); + } + if ( WkstaTableId != 0) { + Call( JetCloseTable( SesId, WkstaTableId)); + } + if ( AdapterTableId != 0) { + Call( JetCloseTable( SesId, AdapterTableId)); + } + if ( DbId != 0) { + Call( JetCloseDatabase( SesId, DbId, 0)); + Call( JetDetachDatabase( SesId, G_ServiceDatabaseA)); + } + if ( SesId != 0) + Call( JetEndSession( SesId, 0)); + if ( JetInstance != 0) { + Call( JetTerm2( JetInstance, JET_bitTermComplete)); + } +} + + +DWORD SetSystemParameters( VOID) +{ + DWORD DirectoryLengthW = sizeof(G_ServiceDirectoryW)/sizeof(WCHAR); + DWORD DirectoryLengthA; + DWORD Error = RplRegRead( NULL, NULL, NULL, G_ServiceDirectoryW, &DirectoryLengthW ); + if (Error != NO_ERROR) { + return( Error); + } + if ( !WideCharToMultiByte( CP_OEMCP, + 0, + G_ServiceDirectoryW, + DirectoryLengthW, + G_ServiceDatabaseA, + sizeof(G_ServiceDatabaseA)/sizeof(CHAR), + NULL, + NULL ) ) { + return( GetLastError() ); + } + DirectoryLengthA = strlen(G_ServiceDatabaseA); + if ( DirectoryLengthA + wcslen(RPL_SERVICE_DATABASE_W) > MAX_PATH + || DirectoryLengthA + strlen("temp.tmp") > MAX_PATH + || DirectoryLengthA + wcslen(RPL_SYSTEM_DATABASE_W) > MAX_PATH) { + return( NERR_RplBadRegistry); + } + +#ifdef __JET500 + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramSystemPath, 0, G_ServiceDatabaseA)); +#else + strcpy( G_ServiceDatabaseA + DirectoryLengthA, RPL_SYSTEM_DATABASE ); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramSysDbPath, 0, G_ServiceDatabaseA)); +#endif + + strcpy( G_ServiceDatabaseA + DirectoryLengthA, "temp.tmp" ); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramTempPath, 0, G_ServiceDatabaseA)); + + strcpy( G_ServiceDatabaseA + DirectoryLengthA, RPL_SERVICE_DATABASE ); + + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramMaxBuffers, 250, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramBfThrshldLowPrcnt, 0, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramBfThrshldHighPrcnt, 100, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramMaxOpenTables, 30, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramMaxOpenTableIndexes, 105, NULL)) + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramMaxCursors, 100, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramMaxSessions, 10, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramMaxVerPages, 64, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramMaxTemporaryTables, 5, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramLogFilePath, 0, ".")); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramLogBuffers, 41, NULL)); +#ifdef __JET500 + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramLogFileSize, 1000, NULL)); + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramBaseName, 0, "j50")); +#else + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramLogFileSectors, 1000, NULL)); +#endif + CallM( JetSetSystemParameter( &JetInstance, 0, JET_paramLogFlushThreshold, 10, NULL)); + return( NO_ERROR); +} + + +DWORD CheckFile( + PWCHAR FilePath, + PWCHAR FileName + ) +{ + DWORD Error = NO_ERROR; + WCHAR CompleteFilePath[ MAX_PATH+1]; + PWCHAR UseFilePath = FileName; + HANDLE FindHandle; + WIN32_FIND_DATA FindData; + + CompleteFilePath[0] = L'\0'; + if ( FilePath != NULL && lstrlenW(FilePath) > 0) { + lstrcpyW( CompleteFilePath, FilePath); + if ( CompleteFilePath[ lstrlenW(CompleteFilePath)-1 ] != L'\\') { + lstrcatW( CompleteFilePath, L"\\"); + } + if ( FileName != NULL) { + lstrcatW( CompleteFilePath, FileName ); + } + UseFilePath = CompleteFilePath; + } + FindHandle = FindFirstFile( UseFilePath, &FindData); + if (FindHandle == INVALID_HANDLE_VALUE) { + Error = GetLastError(); + } + else + { + FindClose( FindHandle ); + } + + return(Error); +} + + +DWORD _CRTAPI1 main( + int argc, + CHAR ** charArgv + ) +{ + DWORD Error; + JET_ERR JetError; + WCHAR ** argv; + PWCHAR SourceFilePath; + BOOL SpecificDirectory = FALSE; + PWCHAR ThisDirectory = L".\\"; + BOOL RplsvcMdbExists = FALSE; + + GlobalInit(); + Error = SetSystemParameters(); + if ( Error != NO_ERROR) { + goto SkipCleanup; + } + + // Find files rpl.map and rplmgr.ini + argv = CommandLineToArgvW( GetCommandLineW(), &argc); + if ( argv != NULL && argc > 1) { + SourceFilePath = argv[ 1]; + SpecificDirectory = TRUE; + } else { + SourceFilePath = G_ServiceDirectoryW; + } + if ( (Error = CheckFile(SourceFilePath, RplMapFile)) != NO_ERROR + || (Error = CheckFile(SourceFilePath, L"rplmgr.ini")) != NO_ERROR ) + { + if ( (!SpecificDirectory) + && (Error = CheckFile(ThisDirectory, RplMapFile)) == NO_ERROR + && (Error = CheckFile(ThisDirectory, L"rplmgr.ini")) == NO_ERROR ) + { + SourceFilePath = ThisDirectory; + } + } + if (Error != NO_ERROR) { + RplPrintf0( RPLI_CVT_NoMAP_INI); + goto SkipCleanup; + } + +#ifndef __JET500 + // find file system.mdb + if ( (Error = CheckFile(G_ServiceDirectoryW, RPL_SYSTEM_DATABASE_W)) + != NO_ERROR) { + RplPrintf0( RPLI_CVT_NoSystemMdb); + goto SkipCleanup; + } +#endif + + // check for file rplsvc.mdb + RplsvcMdbExists = ((Error = CheckFile(G_ServiceDirectoryW, + RPL_SERVICE_DATABASE_W)) + == NO_ERROR); + if (RplsvcMdbExists) { + RplPrintf0( RPLI_CVT_RplsvcMdbExists); +#ifndef RPL_DEBUG + goto SkipCleanup; +#endif + } + + JetError = JetInit( &JetInstance); + if ( JetError == JET_errInvalidPath) { + RplPrintf0( RPLI_CVT_NoMDB); + Error = MapJetError( Error); + goto SkipCleanup; + } else if ( JetError == JET_errFileNotFound) { + RplPrintf0( RPLI_CVT_StopService); + Error = MapJetError( Error); + goto SkipCleanup; + } else if ( JetError < 0) { + RplPrintf0( RPLI_CVT_InitError); + Error = MapJetError( Error); + goto SkipCleanup; + } + CallJ( JetBeginSession( JetInstance, &SesId, "admin", "")); + JetError = JetCreateDatabase( SesId, G_ServiceDatabaseA, NULL, &DbId, JET_bitDbSingleExclusive); + if ( JetError == JET_errDatabaseDuplicate) { +#ifndef RPL_DEBUG + RplPrintf0( RPLI_CVT_OldSystemMdb); +#endif + Error = MapJetError( Error); +#ifdef RPL_DEBUG + if (RplsvcMdbExists) { + CallJ( JetAttachDatabase( SesId, G_ServiceDatabaseA, 0)); + CallJ( JetOpenDatabase( SesId, G_ServiceDatabaseA, NULL, &DbId, JET_bitDbExclusive)); + BootListTable(); + ConfigListTable(); + ProfileListTable(); + WkstaListTable(); + } +#endif + } else if ( JetError == JET_errSuccess) { + Error = VendorCreateTable(); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + Error = ProcessRplMap( SourceFilePath); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + Error = ProcessRplmgrIni( SourceFilePath); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + ConfigPruneTable(); + ProfilePruneTable(); + WkstaPruneTable(); + } else { + RplAssert( TRUE, ("CreateDatabase: JetError=%d", JetError)); + Error = MapJetError( JetError); + } + +cleanup: + DbCleanup(); + +SkipCleanup: + if ( Error != NO_ERROR) { + RplPrintf0( RPLI_CVT_USAGE); + } + return( Error); +} + diff --git a/private/net/svcdlls/rpl/convert/sources b/private/net/svcdlls/rpl/convert/sources new file mode 100644 index 000000000..2c565a1ea --- /dev/null +++ b/private/net/svcdlls/rpl/convert/sources @@ -0,0 +1,51 @@ +MAJORCOMP=net +MINORCOMP=rplcnv + +TARGETPATH=obj +TARGETNAME=rplcnv +TARGETTYPE=PROGRAM +NTTARGETFILE0=nlstxt.h msg00001.bin + +USE_CRTDLL=1 + +TARGETLIBS= \ + ..\lib\obj\*\rpllib.lib \ + $(BASEDIR)\public\sdk\lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\kernel32.lib \ + $(BASEDIR)\public\sdk\lib\*\advapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\user32.lib \ + $(BASEDIR)\public\sdk\lib\*\gdi32.lib \ + $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \ + $(BASEDIR)\public\sdk\lib\*\samlib.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\wsock32.lib \ + $(BASEDIR)\public\sdk\lib\*\shell32.lib \ + $(BASEDIR)\public\sdk\lib\*\jet500.lib \ + $(BASEDIR)\public\sdk\lib\*\ntdll.lib + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +INCLUDES=.;..\inc;..\..\..\inc;..\..\..\api;..\..\..\..\inc; +WARNING_LEVEL=-W4 + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + rplmain.c \ + vendor.c \ + adapter.c \ + boot.c \ + config.c \ + profile.c \ + wksta.c \ + library.c \ + debug.c \ + convert.rc + + +C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 -DRPL_RPLCNV + +UMTYPE=console diff --git a/private/net/svcdlls/rpl/convert/vendor.c b/private/net/svcdlls/rpl/convert/vendor.c new file mode 100644 index 000000000..7e83f4491 --- /dev/null +++ b/private/net/svcdlls/rpl/convert/vendor.c @@ -0,0 +1,139 @@ +/*++ + +Copyright (c) 1987-1994 Microsoft Corporation + +Module Name: + + vendor.c + +Abstract: + + Creates boot block table (server record table). Parses old style + RPL.MAP server records and creates corresponding entries in jet + database table. + +Author: + + Vladimir Z. Vulovic (vladimv) 16 - March - 1994 + +Revision History: + +--*/ + +#include "local.h" +#define RPLVENDOR_ALLOCATE +#include "vendor.h" +#undef RPLVENDOR_ALLOCATE + +RPL_VENDOR_INFO_0 VendorInfoTable[] + = { + { L"00001B", L"Novell (NE1000, NE2000)"}, + { L"00004B", L"Nokia/ICL (EtherTeam 16)"}, + { L"000062", L"3Com 3Station"}, + { L"0000C0", L"Western Digital/SMC (Ethernet)"}, + { L"0000F6", L"Madge Smart Ringnodes"}, + { L"0020AF", L"3Com (Elnk II, Elnk III, Tokenlink III)"}, + { L"004033", L"NE2000-compatible"}, + { L"004095", L"NE2000-compatible"}, + { L"00608C", L"3Com (Elnk 16, Elnk II, Elnk/MC, Elnk III)"}, + { L"00AA00", L"Intel (EtherExpress 16, EtherExpress PRO)"}, + { L"020701", L"Racal Interlan (NI6510, NI5210)"}, + { L"02608C", L"3Com (3Station, Elnk, Elnk II, Elnk Plus, Elnk/MC)"}, + { L"080009", L"HP (EtherTwist, AM2100)"}, + { L"08005A", L"IBM (Token Ring, Ethernet)"}, + { L"10005A", L"IBM (Token Ring, Ethernet)"}, + { L"42608C", L"3Com (Tokenlink)"} +}; +#define VENDOR_INFO_TABLE_LENGTH (sizeof(VendorInfoTable)/sizeof(VendorInfoTable[0])) + + +VOID ProcessVendor( + IN PWCHAR VendorName, + IN PWCHAR VendorComment + ) +{ + DWORD Flags; + + if ( !ValidHexName( VendorName, RPL_VENDOR_NAME_LENGTH, TRUE)) { + RplAssert( TRUE, ("Invalid VendorName = %ws", VendorName)); + return; + } + + Call( JetPrepareUpdate( SesId, VendorTableId, JET_prepInsert)); + + Call( JetSetColumn( SesId, VendorTableId, + VendorTable[ VENDOR_VendorName].ColumnId, VendorName, + (wcslen( VendorName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, VendorTableId, + VendorTable[ VENDOR_VendorComment].ColumnId, VendorComment, + (wcslen( VendorComment) + 1) * sizeof(WCHAR), 0, NULL)); + + Flags = 0; + Call( JetSetColumn( SesId, VendorTableId, + VendorTable[ VENDOR_Flags].ColumnId, &Flags, + sizeof( Flags), 0, NULL)); + + Call( JetUpdate( SesId, VendorTableId, NULL, 0, NULL)); +} + + + +DWORD VendorCreateTable( VOID) +{ + JET_COLUMNDEF ColumnDef; + JET_ERR JetError; + DWORD index; + DWORD Offset; + CHAR IndexKey[ 255]; + + JetError = JetCreateTable( SesId, DbId, VENDOR_TABLE_NAME, + VENDOR_TABLE_PAGE_COUNT, VENDOR_TABLE_DENSITY, &VendorTableId); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateTable failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // Create columns. First initalize fields that do not change between + // addition of columns. + // + ColumnDef.cbStruct = sizeof(ColumnDef); + ColumnDef.columnid = 0; + ColumnDef.wCountry = 1; + ColumnDef.langid = 0x0409; // USA english + ColumnDef.cp = 1200; // UNICODE codepage + ColumnDef.wCollate = 0; + ColumnDef.cbMax = 0; + ColumnDef.grbit = 0; // variable length binary and text data. + + for ( index = 0; index < VENDOR_TABLE_LENGTH; index++ ) { + + ColumnDef.coltyp = VendorTable[ index].ColumnType; + + JetError = JetAddColumn( SesId, VendorTableId, + VendorTable[ index].ColumnName, &ColumnDef, + NULL, 0, &VendorTable[ index].ColumnId); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("AddColumn( %s) failed err=%d", VendorTable[ index].ColumnName, JetError)); + return( MapJetError( JetError)); + } + } + + Offset = AddKey( IndexKey, '+', VendorTable[ VENDOR_VendorName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, VendorTableId, VENDOR_INDEX_VendorName, + JET_bitIndexPrimary, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + for ( index = 0; index < VENDOR_INFO_TABLE_LENGTH; index++) { + ProcessVendor( VendorInfoTable[ index].VendorName, + VendorInfoTable[ index].VendorComment); + } + + return( ERROR_SUCCESS); +} + diff --git a/private/net/svcdlls/rpl/convert/wksta.c b/private/net/svcdlls/rpl/convert/wksta.c new file mode 100644 index 000000000..96e45683a --- /dev/null +++ b/private/net/svcdlls/rpl/convert/wksta.c @@ -0,0 +1,565 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + wksta.c + +Abstract: + + Creates wksta table. Parses old style RPL.MAP unique adapter id + workstation records and creates corresponding entries in jet + database table. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "winsock.h" // for inet_addr() +#define RPLWKSTA_ALLOCATE +#include "wksta.h" +#undef RPLWKSTA_ALLOCATE + + +DWORD WkstaCreateTable( VOID) +{ + JET_COLUMNDEF ColumnDef; + JET_ERR JetError; + DWORD index; + DWORD Offset; + CHAR IndexKey[ 255]; + + JetError = JetCreateTable( SesId, DbId, WKSTA_TABLE_NAME, + WKSTA_TABLE_PAGE_COUNT, WKSTA_TABLE_DENSITY, &WkstaTableId); + + // + // Create columns. First initalize fields that do not change between + // addition of columns. + // + ColumnDef.cbStruct = sizeof(ColumnDef); + ColumnDef.columnid = 0; + ColumnDef.wCountry = 1; + ColumnDef.langid = 0x0409; // USA english + ColumnDef.cp = 1200; // UNICODE codepage + ColumnDef.wCollate = 0; + ColumnDef.cbMax = 0; + ColumnDef.grbit = 0; // variable length binary and text data. + + for ( index = 0; index < WKSTA_TABLE_LENGTH; index++) { + + ColumnDef.coltyp = WkstaTable[ index].ColumnType; + + CallM( JetAddColumn( SesId, WkstaTableId, + WkstaTable[ index].ColumnName, &ColumnDef, + NULL, 0, &WkstaTable[ index].ColumnId)); + } + + // + // For now, the only reason we define these indices is to make sure + // wksta records have different AdapterName-s and different WkstaName-s. + // BUGBUG We could perhaps do this for TCP/IP address field as well. + // + Offset = AddKey( IndexKey, '+', WkstaTable[ WKSTA_AdapterName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, WkstaTableId, WKSTA_INDEX_AdapterName, + JET_bitIndexPrimary, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + Offset = AddKey( IndexKey, '+', WkstaTable[ WKSTA_WkstaName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, WkstaTableId, WKSTA_INDEX_WkstaName, + JET_bitIndexUnique, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // +ProfileName+WkstaName index is used to enumerate all wkstas attached + // to a given profile. + // + Offset = AddKey( IndexKey, '+', WkstaTable[ WKSTA_ProfileName].ColumnName); + Offset += AddKey( IndexKey + Offset, '+', WkstaTable[ WKSTA_WkstaName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, WkstaTableId, WKSTA_INDEX_ProfileNameWkstaName, + JET_bitIndexUnique, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + // + // +BootName+WkstaName index is used to find if a there is a + // wksta record for a given boot record. + // + Offset = AddKey( IndexKey, '+', WkstaTable[ WKSTA_BootName].ColumnName); + Offset += AddKey( IndexKey + Offset, '+', WkstaTable[ WKSTA_WkstaName].ColumnName); + IndexKey[ Offset++] = '\0'; + JetError = JetCreateIndex( SesId, WkstaTableId, WKSTA_INDEX_BootNameWkstaName, + JET_bitIndexUnique, IndexKey, Offset, 50); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("CreateIndex failed err=%d", JetError)); + return( MapJetError( JetError)); + } + + return( ERROR_SUCCESS); +} + + +DWORD TcpIpAddressToDword( IN PWCHAR UnicodeString) +{ + CHAR DbcsString[ 20]; + DWORD ByteCount; + + if ( *UnicodeString == 0) { + // + // WideCharToMultiByte() would convert this string successfully, + // returning ByteCount equal to 1 and DbcsString[ 0] equal to 0. + // And inet_addr() would then return 0, a valid TCP/IP address. + // + return( INADDR_NONE); + } + ByteCount = WideCharToMultiByte( // counts the terminating null byte + CP_OEMCP, // RonaldM confirms inet_addr() wants OEM string + 0, + UnicodeString, + -1, + DbcsString, // dbcs string + sizeof( DbcsString), + NULL, // no default character + NULL // no default character flag + ); + if ( ByteCount == 0) { + return( INADDR_NONE); // failed to convert to DBCS + } + // + // Convert the string to network byte order, then to host byte order. + // + return( (DWORD)ntohl( inet_addr( DbcsString))); +} + + +VOID ProcessWksta( PWCHAR * Fields) +/*++ + We need to get from here whether wksta record is PERSONAL or SHARED. +--*/ +{ +// +// Wksta record (computer record) defines. +// +#define WKSTA_DISABLED_CH L'D' +#define WKSTA_ENABLED_CH L'R' + +// +// WKSTA_SERVER_INDEX is an index of a boot block record identifier in a string +// table corresponding to a wksta record. This index is 0-based. Note +// that wksta record is parsed so that field ",,," is counted as three +// entries not as one. +// +#define WKSTA_AdapterName_INDEX 0 // wksta adapter id +#define WKSTA_WKSTANAME_INDEX 1 // wksta name +#define WKSTA_LOGONINPUT_INDEX 2 // username/password prompting policy +#define WKSTA_FITFILE_INDEX 3 // fit file name +#define WKSTA_SHARING_INDEX 5 // shared or personal profile +#define WKSTA_BOOTNAME_INDEX 13 // boot block identifier +#define WKSTA_PROFILENAME_INDEX 15 // profile name +#define WKSTA_COMMENT_INDEX 16 // wksta comment +#define WKSTA_TCPIPADDRESS_INDEX 17 // wksta tcpip address +#define WKSTA_TCPIPSUBNET_INDEX 18 // wksta subnet mask +#define WKSTA_TCPIPGATEWAY_INDEX 19 // wksta tcpip gateway address + + PWCHAR WkstaComment; + PWCHAR WkstaName; + PWCHAR AdapterName; + PWCHAR ProfileName; + DWORD TcpIpAddress; + DWORD TcpIpSubnet; + DWORD TcpIpGateway; + PWCHAR Fit; + PWCHAR BootName; + JET_ERR JetError; + DWORD Flags; + + Flags = 0; + + WkstaName = Fields[ WKSTA_WKSTANAME_INDEX]; + if ( !ValidName( WkstaName, RPL_MAX_WKSTA_NAME_LENGTH, TRUE)) { + RplPrintf1( RPLI_CVT_WkstaInvalid, WkstaName); + RplAssert( TRUE, ("Bad wksta name")); + return; + } + _wcsupr( WkstaName); + + AdapterName = Fields[ WKSTA_AdapterName_INDEX]; + if ( !ValidHexName( AdapterName, RPL_ADAPTER_NAME_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_WkstaInvalidAdapter, WkstaName, AdapterName); + RplAssert( TRUE, ("Bad adapter id")); + return; + } + _wcsupr( AdapterName); + + if ( Fields[ WKSTA_LOGONINPUT_INDEX] [1] != 0) { + RplPrintf2( RPLI_CVT_WkstaInvalidLogon, WkstaName, Fields[ WKSTA_LOGONINPUT_INDEX]); + RplAssert( TRUE, ("Bad username/password prompting field.")); + return; + } + switch( Fields[ WKSTA_LOGONINPUT_INDEX] [0]) { + case WKSTA_LOGON_INPUT_REQUIRED: + Flags |= WKSTA_FLAGS_LOGON_INPUT_REQUIRED; + break; + case WKSTA_LOGON_INPUT_OPTIONAL: + Flags |= WKSTA_FLAGS_LOGON_INPUT_OPTIONAL; + break; + case WKSTA_LOGON_INPUT_IMPOSSIBLE: + Flags |= WKSTA_FLAGS_LOGON_INPUT_IMPOSSIBLE; + break; + default: + RplPrintf2( RPLI_CVT_WkstaInvalidLogon, WkstaName, Fields[ WKSTA_LOGONINPUT_INDEX]); + RplAssert( TRUE, ("Bad username/password prompting field.")); + return; + break; + } + + Fit = AddFileExtension( Fields[ WKSTA_FITFILE_INDEX], L".FIT", TRUE); + if ( !ValidName( Fit, RPL_MAX_STRING_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_WkstaInvalidFit, WkstaName, Fields[ WKSTA_FITFILE_INDEX]); + RplAssert( TRUE, ("Bad fit file field %ws.", Fields[ WKSTA_FITFILE_INDEX])); + return; + } + + // + // Find if wksta record is enabled or disabled. + // + switch( Fields[ WKSTA_SHARING_INDEX] [0]) { + case WKSTA_SHARING_TRUE: + Flags |= WKSTA_FLAGS_SHARING_TRUE; + break; + case WKSTA_SHARING_FALSE: + Flags |= WKSTA_FLAGS_SHARING_FALSE; + break; + default: + RplPrintf2( RPLI_CVT_WkstaInvalidSharing, WkstaName, Fields[ WKSTA_SHARING_INDEX]); + RplAssert( TRUE, ("Data sharing not properly set.")); + return; + break; + } + + // + // Find if wksta record is enabled or disabled. + // + switch( *Fields[ WKSTA_BOOTNAME_INDEX]) { + case WKSTA_ENABLED_CH: + break; + case WKSTA_DISABLED_CH: + RplPrintf2( RPLI_CVT_WkstaDisabledBoot, WkstaName, Fields[ WKSTA_BOOTNAME_INDEX]); + return; + break; + default: + RplPrintf2( RPLI_CVT_WkstaInvalidBoot, WkstaName, Fields[ WKSTA_BOOTNAME_INDEX]); + RplAssert( TRUE, ("Bad switch")); + return; + break; + } + + BootName = Fields[ WKSTA_BOOTNAME_INDEX] + 1; // skip leading char + if ( !ValidName( BootName, RPL_MAX_STRING_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_WkstaInvalidBoot, WkstaName, Fields[ WKSTA_BOOTNAME_INDEX]); + RplAssert( TRUE, ("Bad boot name")); + return; + } + + ProfileName = Fields[ WKSTA_PROFILENAME_INDEX]; + if ( !ValidName( ProfileName, RPL_MAX_PROFILE_NAME_LENGTH, TRUE)) { + RplPrintf2( RPLI_CVT_WkstaInvalidProfile, WkstaName, ProfileName); + RplAssert( TRUE, ("Bad profile name")); + return; + } + _wcsupr( ProfileName); + + WkstaComment = Fields[ WKSTA_COMMENT_INDEX]; + if ( RPL_STRING_TOO_LONG( WkstaComment)) { + WkstaComment[ RPL_MAX_STRING_LENGTH] = 0; // silently truncate it + } + + TcpIpAddress = TcpIpAddressToDword( Fields[ WKSTA_TCPIPADDRESS_INDEX]); + TcpIpSubnet = TcpIpAddressToDword( Fields[ WKSTA_TCPIPSUBNET_INDEX]); + TcpIpGateway = TcpIpAddressToDword( Fields[ WKSTA_TCPIPGATEWAY_INDEX]); + + // + // If all addresses are valid assumes this (old style) client does not + // want DHCP to be enabled. In other words, if any addresses is bogus + // this client does not loose anything by trying out DHCP. + // + if ( TcpIpAddress != INADDR_NONE && TcpIpSubnet != INADDR_NONE + && TcpIpGateway != -1) { + Flags |= WKSTA_FLAGS_DHCP_FALSE; + } else { + Flags |= WKSTA_FLAGS_DHCP_TRUE; + } + + // + // Play it safe; assume user accounts are not to be deleted + // + Flags |= WKSTA_FLAGS_DELETE_FALSE; + + Call( JetPrepareUpdate( SesId, WkstaTableId, JET_prepInsert)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_WkstaName].ColumnId, WkstaName, + (wcslen( WkstaName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_WkstaComment].ColumnId, WkstaComment, + (wcslen( WkstaComment) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_ProfileName].ColumnId, ProfileName, + (wcslen( ProfileName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_BootName].ColumnId, BootName, + (wcslen( BootName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_FitFile].ColumnId, Fit, + (wcslen( Fit) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_AdapterName].ColumnId, AdapterName, + (wcslen( AdapterName) + 1) * sizeof(WCHAR), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_TcpIpAddress].ColumnId, &TcpIpAddress, + sizeof( TcpIpAddress), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_TcpIpSubnet].ColumnId, &TcpIpSubnet, + sizeof( TcpIpSubnet), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_TcpIpGateway].ColumnId, &TcpIpGateway, + sizeof( TcpIpGateway), 0, NULL)); + + Call( JetSetColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_Flags].ColumnId, &Flags, + sizeof( Flags), 0, NULL)); + + JetError = JetUpdate( SesId, WkstaTableId, NULL, 0, NULL); + if ( JetError == JET_errKeyDuplicate) { + RplPrintf2( RPLI_CVT_WkstaDuplicateName, WkstaName, AdapterName); + } else if (JetError != JET_errSuccess) { + RplAssert( TRUE,("JetUpdate failed error = %d", JetError)); + } +} + + +VOID WkstaPruneTable( VOID) +/*++ + Eliminate wksta records that do not have a corresponding profile record + defined or do not have a corresponding server record defined. +--*/ +{ + + WCHAR Name[ 20]; // BUGBUG arbitrary size + DWORD NameSize; + JET_ERR ForJetError; + JET_ERR JetError; + + for ( ForJetError = JetMove( SesId, WkstaTableId, JET_MoveFirst, 0); + ForJetError == JET_errSuccess; + ForJetError = JetMove( SesId, WkstaTableId, JET_MoveNext, 0)) { + + JetError = JetRetrieveColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_BootName].ColumnId, Name, + sizeof( Name), &NameSize, 0, NULL); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("RetriveColumn failed err=%d", JetError)); + Call( JetDelete( SesId, WkstaTableId)); + continue; + } + if ( !FindBoot( Name)) { + RplAssert( TRUE, ("FindBoot failed.")); + Call( JetDelete( SesId, WkstaTableId)); + continue; + } + + JetError = JetRetrieveColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_ProfileName].ColumnId, Name, + sizeof( Name), &NameSize, 0, NULL); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("RetriveColumn failed err=%d", JetError)); + Call( JetDelete( SesId, WkstaTableId)); + continue; + } + // + // This will eliminate workstations joined to the DEFAULT profile + // since the DEFAULT profile does not have its profile record in + // RPL.MAP. Note that default boot is not supported under NT. + // Instead of just deleting these workstations, we could also + // add the corresponding AdapterName record to the AdapterName table. + // This may not be worth the effort though. + // + if ( !FindProfile( Name)) { + if ( _wcsicmp( Name, L"DEFAULT") == 0) { + JetError = JetRetrieveColumn( SesId, WkstaTableId, + WkstaTable[ WKSTA_WkstaName].ColumnId, Name, + sizeof( Name), &NameSize, 0, NULL); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("RetriveColumn failed err=%d", JetError)); + } else { + RplPrintf1( RPLI_CVT_WkstaDefaultProfile, Name); + } + } else { + RplAssert( TRUE, ("FindProfile failed.")); + } + Call( JetDelete( SesId, WkstaTableId)); + continue; + } + } + + // + // The error below is the only expected error (end of table error). + // + if ( ForJetError != JET_errNoCurrentRecord) { + RplAssert( TRUE, ("ForJetError = %d", ForJetError)); + } +} + + +VOID WkstaListTable( VOID) +{ + ListTable( WKSTA_TABLE_NAME, WkstaTable[ WKSTA_AdapterName].ColumnName, + WKSTA_INDEX_WkstaName); +} + + + +BOOL RplDbInitTable( IN PCHAR TableName, IN OUT PRPL_COLUMN_INFO Table, + IN DWORD TableLength, IN OUT JET_TABLEID * pTableId) +{ + JET_COLUMNDEF ColumnDef; + DWORD index; + + CallB( JetOpenTable( SesId, DbId, TableName, NULL, 0, + JET_bitTableDenyWrite, pTableId)); + + for ( index = 0; index < TableLength; index++) { + CallB( JetGetTableColumnInfo( SesId, *pTableId, Table[ index].ColumnName, + &ColumnDef, sizeof( ColumnDef), JET_ColInfo)); + Table[ index].ColumnId = ColumnDef.columnid; + Table[ index].ColumnType = ColumnDef.coltyp; + } + return( TRUE); +} + + +BOOL FindWksta( IN LPWSTR AdapterName) +/*++ + Return TRUE if it finds wksta record for input AdapterName. + Returns FALSE otherwise. + + BUGBUG This code is inefficient. I should really make AdapterName a + jet currency data, but even now it is kind of stupid taking wcslen of + AdapterName since it is a fixed length string. +--*/ +{ + JET_ERR JetError; + + JetError = JetSetCurrentIndex( SesId, WkstaTableId, WKSTA_INDEX_AdapterName); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("SetCurrentIndex failed err=%d", JetError)); + return( FALSE); + } + JetError = JetMakeKey( SesId, WkstaTableId, AdapterName, + ( wcslen( AdapterName) + 1) * sizeof(WCHAR), JET_bitNewKey); + if ( JetError != JET_errSuccess) { + RplAssert( TRUE, ("MakeKey failed err=%d", JetError)); + return( FALSE); + } + JetError = JetSeek( SesId, WkstaTableId, JET_bitSeekEQ); + if ( JetError != JET_errSuccess) { + if ( JetError == JET_errRecordNotFound) { + // + // This is an expected error, do not break for this. + // + RplAssert( TRUE, ( "FindWksta( %ws) failed", AdapterName)); + } else { + RplAssert( TRUE, ("JetSeek failed err=%d", JetError)); + } + return( FALSE); + } + return( TRUE); +} + +#ifdef NOT_YET + +VOID Display( IN DWORD index) +{ + BYTE Buffer[ 120]; + DWORD DataSize; + DWORD AddressDword; + + Call( JetRetrieveColumn( SesId, WkstaTableId, + WkstaTable[ index].ColumnId, Buffer, + sizeof( Buffer), &DataSize, 0, NULL)); + + RplDbgPrint(( "%s = ", WkstaTable[ index].ColumnName)); + + switch( index) { + case WKSTA_WkstaName: + case WKSTA_WkstaComment: + case WKSTA_ProfileName: + case WKSTA_FitFile: + case WKSTA_BootName: + RplDbgPrint(( "%ws\n", Buffer)); + break; + case WKSTA_TcpIpAddress: + case WKSTA_TcpIpSubnet: + case WKSTA_TcpIpGateway: + AddressDword = *(PDWORD)Buffer; + FillTcpIpString( Buffer, AddressDword); + RplDbgPrint(( "%s\n", Buffer)); + break; + case WKSTA_Flags: + RplDbgPrint(( "0x%x\n", *(PDWORD)Buffer)); + break; + } +} + + +BOOL ListWkstaInfo( IN PWCHAR AdapterName) +/*++ + Returns TRUE if it can find all the information needed to boot the client. + Returns FALSE otherwise. +--*/ +{ + if ( !RplDbInitTable( WKSTA_TABLE_NAME, WkstaTable, WKSTA_TABLE_LENGTH, + &WkstaTableId)) { + return( FALSE); + } + if ( !FindWksta( AdapterName)) { + RplAssert( TRUE, ("FindWksta( %ws) failed", AdapterName)); + return( FALSE); + } + Display( WKSTA_WkstaName); + Display( WKSTA_WkstaComment); + Display( WKSTA_Flags); + Display( WKSTA_ProfileName); + Display( WKSTA_FitFile); + Display( WKSTA_BootName); + Display( WKSTA_TcpIpAddress); + Display( WKSTA_TcpIpSubnet); + Display( WKSTA_TcpIpGateway); + return( TRUE); +} +#endif + diff --git a/private/net/svcdlls/rpl/dirs b/private/net/svcdlls/rpl/dirs new file mode 100644 index 000000000..4d6610aed --- /dev/null +++ b/private/net/svcdlls/rpl/dirs @@ -0,0 +1,33 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Steve Wood (stevewo) 17-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl + +!ENDIF + + +DIRS= \ + client \ + lib \ + dll \ + server \ + convert \ + command + + +OPTIONAL_DIRS=rplinst diff --git a/private/net/svcdlls/rpl/dll/buffer.c b/private/net/svcdlls/rpl/dll/buffer.c new file mode 100644 index 000000000..0d7336dcb --- /dev/null +++ b/private/net/svcdlls/rpl/dll/buffer.c @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + buffer.c (renamed from rpl2_bfr.c) + +Abstract: + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + +--*/ + +#include "local.h" + + +BOOL RplDlcBufferFree( + BYTE free_type, + PADAPTER_INFO pAdapterInfo + ) +/*++ + +Routine Description: + Frees the DLC buffer. Can be called from more than one thread. + +Arguments: + free_type - do we free SFR or FIND receive buffer + pAdapterInfo - pointer to adapter specific info + +Return Value: + TRUE if success, FALSE otherwise. +--*/ + +{ + DWORD status; + PLLC_CCB pBadCcb; // pointer for AcsLan + PLLC_CCB pCcb; + PLLC_BUFFER_FREE_PARMS pBufferFreeParms; + HANDLE Event; + WORD usStationId; + PLLC_BUFFER pBuffer; + + if (free_type == FIND_FREE) { + pCcb= &pAdapterInfo->find_bf_ccb; + pBufferFreeParms = &pAdapterInfo->find_bf_ccbpt; + pBuffer = pAdapterInfo->u1.r1.pFirstBuffer; + usStationId = pAdapterInfo->u1.r1.usStationId; + Event = pAdapterInfo->findsem; + } else { + pCcb= &pAdapterInfo->sfr_bf_ccb; + pBufferFreeParms = &pAdapterInfo->sfr_bf_ccbpt; + pBuffer = pAdapterInfo->u3.r1.Type.Event.pReceivedFrame; + usStationId = pAdapterInfo->u3.r1.usStationId; + Event = pAdapterInfo->getdata_sem; + } + + // + // clear the blocks first + // + memset( (PVOID)pCcb, '\0', sizeof(LLC_CCB)); + memset( (PVOID)pBufferFreeParms, '\0', sizeof(LLC_BUFFER_FREE_PARMS)); + + pCcb->uchAdapterNumber = pAdapterInfo->adapter_number; + pCcb->uchDlcCommand = LLC_BUFFER_FREE; + pCcb->hCompletionEvent = Event; + pCcb->u.pParameterTable = (PLLC_PARMS)pBufferFreeParms; + + pBufferFreeParms->pFirstBuffer = (PLLC_XMIT_BUFFER)pBuffer; + if ( pBuffer == NULL) { + RplDump( ++RG_Assert, ("pBuffer=0x%x", pBuffer)); + return( TRUE); // a workaround for free build until the bug is found BUGBUG + } + + if ( ResetEvent( Event) == FALSE) { + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + status = GetLastError(); + RplDump( ++RG_Assert, ( "status=0x%x", status)); + RplDlcReportEvent( status, SEM_SET); + return( FALSE); + } + + status = AcsLan( pCcb, &pBadCcb); + if ( pAdapterInfo->Closing == TRUE) { + (VOID)SetEvent( Event); + return( FALSE); + } + + if ( status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + RplDump( ++RG_Assert, ( "status=0x%x", status)); + RplDlcReportEvent( status, LLC_BUFFER_FREE); + (VOID)SetEvent( Event); + return( FALSE); + } + + status = WaitForSingleObject( Event, 3000L); + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + + if ( (status != WAIT_OBJECT_0) || (pCcb->uchDlcStatus)) { + if (status != WAIT_OBJECT_0) { + if ( status == -1) { + status = GetLastError(); + } + RplDlcReportEvent( status, SEM_WAIT); + } else { + RplDlcReportEvent( pCcb->uchDlcStatus, LLC_BUFFER_FREE); + } + RplDump( ++RG_Assert, ( "status=%d, pCcb=0x%x, DlcStatus=0x%x", + status, pCcb, pCcb->uchDlcStatus)); + return( FALSE); + } + return( TRUE); +} diff --git a/private/net/svcdlls/rpl/dll/emulator.c b/private/net/svcdlls/rpl/dll/emulator.c new file mode 100644 index 000000000..6f0110037 --- /dev/null +++ b/private/net/svcdlls/rpl/dll/emulator.c @@ -0,0 +1,110 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + emulator.c (renamed from rplemul.c) + +Abstract: + + Contains RPL emulator for ETHERSTART clients. + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + 08-Jun-1994 vladimv + Updated with lm2.2 fixes for 3Com Etherlink card. + +--*/ + +#include "local.h" + +// +// ripl_rom[] is the x86 code we send to ETHERSTART clients. The source +// code is on \\deficit\lm\src\ripl\rpldll\rplemul.asm. +// +// BUGBUG We should really check in & compile the actual x86 assembly code +// BUGBUG rather than collecting sniff traces of what MS Lan Manager server +// BUGBUG sends to the client. +// +BYTE ripl_rom[] = { + 0xFA ,0xB8 ,0x90 ,0x00 +,0x8E ,0xD0 ,0xBC ,0x00 ,0x02 ,0xCD ,0x12 ,0xB1 ,0x06 ,0xD3 ,0xE0 ,0x8D ,0x0E ,0x53 ,0x0B ,0x83 +,0xC1 ,0x0F ,0x51 ,0xD1 ,0xE9 ,0xD1 ,0xE9 ,0xD1 ,0xE9 ,0xD1 ,0xE9 ,0x2B ,0xC1 ,0x59 ,0x8E ,0xC0 +,0x8D ,0x36 ,0x35 ,0x01 ,0x8B ,0xFE ,0x2B ,0xCE ,0xE8 ,0x56 ,0x02 ,0x50 ,0xB8 ,0x35 ,0x01 ,0x50 +,0xCB ,0x0E ,0x1F ,0xB4 ,0xFB ,0xB2 ,0x80 ,0x8D ,0x1E ,0x76 ,0x04 ,0xCD ,0x13 ,0x8B ,0xF3 ,0x8D +,0x3E ,0xA1 ,0x04 ,0xA5 ,0xA5 ,0xA5 ,0x8B ,0xF3 ,0x8D ,0x3E ,0xDE ,0x04 ,0xA5 ,0xA5 ,0xA5 ,0x8B +,0xF3 ,0x8D ,0x3E ,0x09 ,0x05 ,0xA5 ,0xA5 ,0xA5 ,0xB4 ,0x03 ,0x32 ,0xFF ,0xCD ,0x10 ,0x32 ,0xD2 +,0x01 ,0x16 ,0x04 ,0x04 ,0x01 ,0x16 ,0x39 ,0x04 ,0x01 ,0x16 ,0x6E ,0x04 ,0xBE ,0xDA ,0x03 ,0x8B +,0x16 ,0x04 ,0x04 ,0xBB ,0x24 ,0x00 ,0x90 ,0xE8 ,0x26 ,0x02 ,0xA1 ,0x04 ,0x04 ,0x05 ,0x24 ,0x00 +,0x90 ,0xA3 ,0x04 ,0x04 ,0xBE ,0xFE ,0x03 ,0x8B ,0x16 ,0x04 ,0x04 ,0xBB ,0x06 ,0x00 ,0x90 ,0xE8 +,0x0E ,0x02 ,0xBE ,0x68 ,0x00 ,0x90 ,0x8D ,0x1E ,0x70 ,0x04 ,0xE8 ,0xF5 ,0x01 ,0xBE ,0xBE ,0x05 +,0x8D ,0x1E ,0x42 ,0x05 ,0xE8 ,0xF2 ,0x01 ,0x73 ,0x13 ,0x0B ,0xC0 ,0x74 ,0x03 ,0xE9 ,0x8D ,0x00 +,0xBE ,0xFE ,0x03 ,0xBB ,0x06 ,0x00 ,0x90 ,0xE8 ,0xFE ,0x01 ,0xEB ,0xC8 ,0x8D ,0x36 ,0x72 ,0x05 +,0x8D ,0x3E ,0xD8 ,0x04 ,0xA5 ,0xA5 ,0xA5 ,0xBE ,0x06 ,0x04 ,0x8B ,0x16 ,0x39 ,0x04 ,0xBB ,0x2F +,0x00 ,0x90 ,0xE8 ,0xCB ,0x01 ,0xBE ,0x3B ,0x04 ,0x8B ,0x16 ,0x6E ,0x04 ,0xBB ,0x2D ,0x00 ,0x90 +,0xE8 ,0xBD ,0x01 ,0xA1 ,0x39 ,0x04 ,0x05 ,0x2F ,0x00 ,0x90 ,0xA3 ,0x39 ,0x04 ,0xA1 ,0x6E ,0x04 +,0x05 ,0x2D ,0x00 ,0x90 ,0xA3 ,0x6E ,0x04 ,0xB9 ,0x50 ,0x00 ,0xBE ,0x35 ,0x04 ,0x8B ,0x16 ,0x39 +,0x04 ,0xBB ,0x04 ,0x00 ,0x90 ,0xE8 ,0x98 ,0x01 ,0xBE ,0x68 ,0x00 ,0x90 ,0x8D ,0x1E ,0xD8 ,0x04 +,0xE8 ,0x7F ,0x01 ,0xBE ,0x68 ,0x04 ,0x8B ,0x16 ,0x6E ,0x04 ,0xBB ,0x06 ,0x00 ,0x90 ,0xE8 ,0x7F +,0x01 ,0xBE ,0xBE ,0x05 ,0x8D ,0x1E ,0x8D ,0x05 ,0xE8 ,0x6E ,0x01 ,0x73 ,0x28 ,0x0B ,0xC0 ,0x75 +,0x0C ,0xBE ,0x35 ,0x04 ,0xBB ,0x04 ,0x00 ,0x90 ,0xE8 ,0x7D ,0x01 ,0xE2 ,0xBD ,0xE8 ,0xF6 ,0x00 +,0xB8 ,0x40 ,0x00 ,0x8E ,0xD8 ,0xC7 ,0x06 ,0x72 ,0x00 ,0x34 ,0x12 ,0xEA ,0x00 ,0x00 ,0xFF ,0xFF +,0xB9 ,0x50 ,0x00 ,0xEB ,0xBE ,0x80 ,0x3E ,0x9B ,0x05 ,0xFC ,0x75 ,0xF4 ,0x81 ,0x3E ,0xA0 ,0x05 +,0x00 ,0x20 ,0x75 ,0xEC ,0xA1 ,0xF3 ,0x04 ,0x39 ,0x06 ,0xA8 ,0x05 ,0x74 ,0x02 ,0xEB ,0x88 ,0x8B +,0x16 ,0xF1 ,0x04 ,0x39 ,0x16 ,0xA6 ,0x05 ,0x74 ,0x03 ,0xE9 ,0x7B ,0xFF ,0x86 ,0xC4 ,0x86 ,0xD6 +,0x40 ,0x83 ,0xD2 ,0x00 ,0x86 ,0xC4 ,0x86 ,0xD6 ,0xA3 ,0xF3 ,0x04 ,0x89 ,0x16 ,0xF1 ,0x04 ,0xBE +,0x68 ,0x04 ,0xBB ,0x06 ,0x00 ,0x90 ,0xE8 ,0x1F ,0x01 ,0x8A ,0x1E ,0xB6 ,0x05 ,0xF6 ,0xC3 ,0x10 +,0x74 ,0x0D ,0x53 ,0xBE ,0x68 ,0x00 ,0x90 ,0x8D ,0x1E ,0xD8 ,0x04 ,0xE8 ,0xE4 ,0x00 ,0x5B ,0xF6 +,0xC3 ,0x20 ,0x74 ,0x10 ,0xA1 ,0xB0 ,0x05 ,0x86 ,0xE0 ,0xA3 ,0x4B ,0x0B ,0xA1 ,0xAE ,0x05 ,0x86 +,0xE0 ,0xA3 ,0x4D ,0x0B ,0x8B ,0x0E ,0xB7 ,0x05 ,0x86 ,0xCD ,0x83 ,0xE9 ,0x04 ,0x0B ,0xC9 ,0x74 +,0x37 ,0x33 ,0xD2 ,0xA1 ,0x4B ,0x0B ,0xBF ,0x10 ,0x00 ,0xF7 ,0xF7 ,0x8B ,0xFA ,0x03 ,0x06 ,0x4D +,0x0B ,0x75 ,0x09 ,0x81 ,0xFA ,0x00 ,0x0C ,0x73 ,0x03 ,0xE9 ,0x51 ,0xFF ,0x03 ,0xD1 ,0x89 ,0x16 +,0x4B ,0x0B ,0xA3 ,0x4D ,0x0B ,0x3D ,0x00 ,0xA0 ,0x72 ,0x03 ,0xE9 ,0x40 + ,0xFF ,0x06 ,0x8E ,0xC0 +,0x8D ,0x36 ,0xBB ,0x05 ,0xE8 ,0x7A ,0x00 ,0x07 ,0xF6 ,0xC3 ,0x80 ,0x75 ,0x03 ,0xE9 ,0x40 ,0xFF +,0xA1 ,0x4F ,0x0B ,0x8B ,0x0E ,0x51 ,0x0B ,0xF6 ,0xC3 ,0x40 ,0x74 ,0x0B ,0xA1 ,0xB4 ,0x05 ,0x86 +,0xC4 ,0x8B ,0x0E ,0xB2 ,0x05 ,0x86 ,0xCD ,0x33 ,0xD2 ,0xBB ,0x10 ,0x00 ,0xF7 ,0xF3 ,0x03 ,0xC1 +,0x50 ,0x52 ,0xE8 ,0x01 ,0x00 ,0xCB ,0x06 ,0x1E ,0x33 ,0xC0 ,0x8E ,0xC0 ,0xB8 ,0x70 ,0x00 ,0x8E +,0xD8 ,0xA1 ,0x02 ,0x00 ,0x0B ,0x06 ,0x04 ,0x00 ,0x75 ,0x12 ,0x26 ,0xA1 ,0x00 ,0x01 ,0x26 ,0xA3 +,0x4C ,0x00 ,0x26 ,0xA1 ,0x02 ,0x01 ,0x26 ,0xA3 ,0x4E ,0x00 ,0xEB ,0x0E ,0xA1 ,0x02 ,0x00 ,0x26 +,0xA3 ,0x4C ,0x00 ,0xA1 ,0x04 ,0x00 ,0x26 ,0xA3 ,0x4E ,0x00 ,0xA1 ,0x06 ,0x00 ,0x26 ,0xA3 ,0x64 +,0x00 ,0xA1 ,0x08 ,0x00 ,0x26 ,0xA3 ,0x66 ,0x00 ,0x26 ,0xC6 ,0x06 ,0xD0 ,0x04 ,0x01 ,0x1F ,0x07 +,0xC3 ,0xF7 ,0xC6 ,0x01 ,0x00 ,0x74 ,0x01 ,0xA4 ,0xD1 ,0xE9 ,0x9C ,0xF3 ,0xA5 ,0x9D ,0x73 ,0x01 +,0xA4 ,0xC3 ,0xB4 ,0xFE ,0xB2 ,0x80 ,0xCD ,0x13 ,0xC3 ,0xB4 ,0xFF ,0xB2 ,0x80 ,0xCD ,0x13 ,0xC3 +,0x50 ,0x51 ,0x53 ,0x8B ,0xCB ,0x32 ,0xFF ,0xB4 ,0x02 ,0xCD ,0x10 ,0xAC ,0x33 ,0xDB ,0xB4 ,0x0E +,0xCD ,0x10 ,0xE2 ,0xF7 ,0x5B ,0x59 ,0x58 ,0xC3 ,0x50 ,0x51 ,0x8D ,0x70 ,0xFF ,0x8B ,0xCB ,0x8A +,0x04 ,0x3C ,0x39 ,0x7C ,0x0A ,0xB0 ,0x30 ,0x88 ,0x04 ,0x4E ,0xE2 ,0xF3 ,0xEB ,0x05 ,0x90 ,0xFE +,0xC0 ,0x88 ,0x04 ,0x59 ,0x58 ,0xC3 ,0x53 ,0x65 ,0x61 ,0x72 ,0x63 ,0x68 ,0x69 ,0x6E ,0x67 ,0x20 +,0x66 ,0x6F ,0x72 ,0x20 ,0x52 ,0x50 ,0x4C ,0x20 ,0x53 ,0x65 ,0x72 ,0x76 ,0x65 ,0x72 ,0x2C ,0x20 +,0x52 ,0x65 ,0x74 ,0x72 ,0x69 ,0x65 ,0x73 ,0x20 ,0x3D ,0x20 ,0x30 ,0x30 ,0x30 ,0x30 ,0x30 ,0x30 +,0x00 ,0x01 ,0x53 ,0x65 ,0x6E ,0x64 ,0x69 ,0x6E ,0x67 ,0x20 ,0x46 ,0x69 ,0x6C ,0x65 ,0x20 ,0x52 +,0x65 ,0x71 ,0x75 ,0x65 ,0x73 ,0x74 ,0x73 ,0x20 ,0x74 ,0x6F ,0x20 ,0x52 ,0x50 ,0x4C ,0x20 ,0x53 +,0x65 ,0x72 ,0x76 ,0x65 ,0x72 ,0x2C ,0x20 ,0x52 ,0x65 ,0x74 ,0x72 ,0x69 ,0x65 ,0x73 ,0x20 ,0x3D +,0x20 ,0x30 ,0x30 ,0x30 ,0x30 ,0x00 ,0x03 ,0x57 ,0x61 ,0x69 ,0x74 ,0x69 ,0x6E ,0x67 ,0x20 ,0x66 +,0x6F ,0x72 ,0x20 ,0x44 ,0x61 ,0x74 ,0x61 ,0x20 ,0x46 ,0x72 ,0x61 ,0x6D ,0x65 ,0x20 ,0x77 ,0x69 +,0x74 ,0x68 ,0x20 ,0x53 ,0x65 ,0x71 ,0x75 ,0x65 ,0x6E ,0x63 ,0x65 ,0x20 ,0x4E ,0x75 ,0x6D ,0x62 +,0x65 ,0x72 ,0x3A ,0x20 ,0x30 ,0x30 ,0x30 ,0x30 ,0x30 ,0x30 ,0x00 ,0x04 ,0x03 ,0x00 ,0x02 ,0x00 +,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x5A ,0xFC ,0xFC ,0x03 ,0x00 ,0x57 ,0x00 +,0x01 ,0x00 ,0x08 ,0x40 ,0x03 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x10 ,0x00 ,0x08 ,0x00 ,0x06 ,0x40 +,0x09 ,0x05 ,0xBE ,0x00 ,0x06 ,0x40 ,0x0A ,0x00 ,0x01 ,0x00 ,0x0A ,0x40 ,0x06 ,0x00 ,0x00 ,0x00 +,0x00 ,0x00 ,0x00 ,0x00 ,0x05 ,0x40 ,0x07 ,0xFC ,0x00 ,0x2C ,0x00 ,0x04 ,0x00 ,0x24 ,0xC0 ,0x05 +,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 +,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 +,0x00 ,0x04 ,0x40 ,0x13 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 +,0x00 ,0x5A ,0xF8 ,0xFC ,0x03 ,0x00 ,0x57 ,0x00 ,0x10 ,0x00 ,0x08 ,0x40 ,0x11 ,0x00 ,0x00 ,0x00 +,0x00 ,0x00 ,0x10 ,0x00 ,0x08 ,0x00 ,0x06 ,0x40 ,0x09 ,0x05 ,0xBE ,0x00 + ,0x06 ,0x40 ,0x0A ,0x00 +,0x01 ,0x00 ,0x0A ,0x40 ,0x06 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x05 ,0x40 ,0x07 ,0xFC +,0x00 ,0x2C ,0x00 ,0x04 ,0x00 ,0x24 ,0xC0 ,0x05 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 +,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 +,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x04 ,0x40 ,0x13 +}; +WORD sizeof_ripl_rom = sizeof( ripl_rom); + diff --git a/private/net/svcdlls/rpl/dll/ether.c b/private/net/svcdlls/rpl/dll/ether.c new file mode 100644 index 000000000..bd8cb05f7 --- /dev/null +++ b/private/net/svcdlls/rpl/dll/ether.c @@ -0,0 +1,498 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + ether.c + +Abstract: + + Contains EtherStartThread() + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + 16-Aug-1995 jonn + Extensions to allow EtherStart clients bridged to FDDI + to boot from FDDI adapters. FDDI adapters use a SAP station + rather than a DIRECT station. + +--*/ + +#include "local.h" +#include <jet.h> // need to include because rpllib.h depends on JET +#include <rpllib.h> // RplReportEvent() + +// +// The following are XNS packet definitions used to crack EtherStart +// packets. +// + +#include <packon.h> // pack EtherStart structures + +struct sockaddr_ns { + DWORD net; + BYTE host[ NODE_ADDRESS_LENGTH]; + WORD socket; +}; + +#define ETHERSTART_SOCKET 0x0104 // After swapping bytes + +#define SNAP_SAP 0xAA; // SAP used for SNAP packets + +struct _IDP { + WORD chksum; + WORD len; + BYTE xport_cntl; + BYTE packet_type; + struct sockaddr_ns dest; + struct sockaddr_ns src; +}; + +#define XNS_NO_CHKSUM 0xffff // XNS checksum +#define PEX_TYPE 0x4 // packet exchange type + +struct _PEX { + DWORD pex_id; + WORD pex_client; +}; + +#define ETHERSERIES_CLIENT 0x0080 // After swapping bytes + +struct _ETHERSTART { + WORD ethershare_ver; + BYTE unit; + BYTE fill; + WORD block; + BYTE func; + BYTE error; + WORD bytes; +}; + +#define ETHERSHARE_VER 0 +#define FUNC_RESPONSE 0x80 +#define FUNC_READFILEREQ 0x20 +#define FUNC_READFILERESP (FUNC_READFILEREQ | FUNC_RESPONSE) + +typedef struct _ETHERSTART_REQ { // EtherStart Read File Request + struct _IDP idp; + struct _PEX pex; + struct _ETHERSTART es; + BYTE filename[64]; + WORD start; + WORD count; +} ETHERSTART_REQ; + +typedef struct _ETHERSTART_RESP { // EtherStart Read File Response + struct _IDP idp; + struct _PEX pex; + struct _ETHERSTART es; + BYTE data[0x200]; +} ETHERSTART_RESP; + +typedef struct _SNAP_FRAME { // SNAP packet + struct { + BYTE orgcode[3]; + BYTE etype[2]; + } header; + union { + ETHERSTART_REQ request; + ETHERSTART_RESP response; + } data; +} SNAP_FRAME; + +// +// RECEIVE case: DLC oddity in MS-unique DIRECT extension. +// In case of a direct open auchLanHeader[] returned by DLC contains +// LAN_HEADER structure without physical control fields. (I.e. +// it contains LAN_HEADER_TOO structure defined below.). Therefore +// 3Com 3Station address begins at offset 6 instead of at offset 8. +// +#define RPLDLC_DIRECT_SOURCE_OFFSET 6 // WARNING not 8 +#define RPLDLC_SAP_SOURCE_OFFSET 8 + +// +// TRANSMIT case: possible DLC bug +// If LAN_HEADER is used then DLC sends only the first 4 bytes of +// destination address ( and the first byte of destination address is +// at offset 2 instead of 0). But if we use LAN_HEADER_TOO then this +// problem goes away. +// +typedef struct _LAN_HEADER_TOO { + BYTE dest_addr[ NODE_ADDRESS_LENGTH]; // Destination address + BYTE source_addr[ NODE_ADDRESS_LENGTH]; // Source address + BYTE routing_info_header[2]; // Routing information hdr +} LAN_HEADER_TOO; // BUGBUG not LAN_HEADER due to a DLC bug + +#include <packoff.h> // restore default packing (done with EtherStart structures) + + + +#ifdef RPL_DEBUG +VOID RplCopy( PVOID destination, PVOID source, DWORD length) { + memcpy( destination, source, length); +} +#else +#define RplCopy( _a0, _a1, _a2) memcpy( _a0, _a1, _a2) +#endif + + +BOOL EtherAcsLan( + PADAPTER_INFO pAdapterInfo, + PLLC_CCB pCcb, + BYTE Command + ) +{ + PLLC_CCB pBadCcb; + DWORD status; + DWORD retry_count; + + pCcb->uchDlcCommand = Command; + retry_count = 0; + +transmit_retry: + status = AcsLan( pCcb, &pBadCcb); + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + + if ( status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + RplDump( ++RG_Assert,( "status=0x%x", status)); + RplDlcReportEvent( status, Command); + return( FALSE); + } + + status = WaitForSingleObject( pCcb->hCompletionEvent, INFINITE); + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + + if ( status != WAIT_OBJECT_0 || pCcb->uchDlcStatus) { + if ( status == WAIT_FAILED) { + status = GetLastError(); + RplDlcReportEvent( status, SEM_WAIT); + } + if ( retry_count++ < MAXRETRY) { + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( + "EtherAcslan(0x%x): retry_count=%d, status=%d, DlcStatus=0x%x", + Command, retry_count, status, pCcb->uchDlcStatus)); + Sleep( 100L * retry_count); // wait for NETWORK to recover + goto transmit_retry; + } + RplDump( ++RG_Assert,( "pBadCcb=0x%x status=%d DlcStatus=0x%x", + pBadCcb, status, pCcb->uchDlcStatus)); + if ( status) { + RplDlcReportEvent( status, SEM_WAIT); + } else { + RplDlcReportEvent( pCcb->uchDlcStatus, Command); + } + return( FALSE); + } + + // + // Due to a DLC bug "pNext" field is trashed even on success + // code path. Until the bug is fix we must reinstate NULL. + // + pCcb->pNext = NULL; + return( TRUE); +} + + +// +// RG_EtherFileName[] contains names of all legal boot request types. +// We will do a case insensitive search since file name may arrive +// either in uppercase or lowercase depending on 3Station. +// RG_EtherFileName[] should be initialized during dll init time. BUGBUG +// + +PCHAR RG_EtherFileName[] = { // names of all legal boot request types + "BOOTPC.COM", + "BOOTSTAT.COM", + NULL + }; + +BOOL RplCrack( ETHERSTART_REQ * pEtherstartReq) +{ + PCHAR pFileName; + DWORD index; + + if ( pEtherstartReq->idp.packet_type != PEX_TYPE || + pEtherstartReq->pex.pex_client != ETHERSERIES_CLIENT || + pEtherstartReq->es.func != FUNC_READFILEREQ) { + return( FALSE); + } + + // + // Make sure this is a legal file request. + // + for ( index = 0, pFileName = RG_EtherFileName[ index]; + pFileName != NULL; + pFileName = RG_EtherFileName[ ++index] ) { + if ( _stricmp( pEtherstartReq->filename, pFileName)) { + return( TRUE); + } + } + return( FALSE); +} + + +VOID EtherStartThread( POPEN_INFO pOpenInfo) +{ + PADAPTER_INFO pAdapterInfo; + LLC_CCB ccb; + BOOL BufferFree; + ETHERSTART_REQ * pEtherstartReq; + PRCVBUF pRcvbuf; + struct { + XMIT_BUFFER XmitBuffer; // see comment for XMIT_BUFFER + LAN_HEADER_TOO LanHeader; + } XmitQueue; // first send buffer. + SNAP_FRAME SnapResp; // second & last send buffer + union { + LLC_DIR_OPEN_DIRECT_PARMS DirOpenDirectParms; + LLC_DLC_OPEN_SAP_PARMS DlcOpenSapParms; + LLC_RECEIVE_PARMS ReceiveParms; + LLC_TRANSMIT_PARMS TransmitParms; + LLC_BUFFER_FREE_PARMS BufferFreeParms; + } Parms; + BOOL fIsFDDI = FALSE; + USHORT usFDDIStationId = 0; + INT source_offset = RPLDLC_DIRECT_SOURCE_OFFSET; + + + RplDump( RG_DebugLevel & RPL_DEBUG_ETHER,( + "++EtherStartThread: pOpenInfo=0x%x", pOpenInfo)); + + pAdapterInfo = (PADAPTER_INFO)pOpenInfo->adapt_info_ptr; + BufferFree = FALSE; + + if ( pAdapterInfo->network_type == RPL_ADAPTER_FDDI ) { + fIsFDDI = TRUE; + source_offset = RPLDLC_SAP_SOURCE_OFFSET; + RplDump( RG_DebugLevel & RPL_DEBUG_ETHER,( + "EtherStartThread: fIsFDDI==TRUE")); + } + // + + // + // Initialize fixed fields in ccb. + // + memset( &ccb, '\0', sizeof(ccb)); + ccb.hCompletionEvent = CreateEvent( + NULL, // no security attributes + FALSE, // automatic reset + FALSE, // initial state is NOT signalled + NULL // no name + ); + if ( ccb.hCompletionEvent == NULL) { + DWORD status = GetLastError(); + RplDump( ++RG_Assert, ( "error=%d", status)); + RplDlcReportEvent( status, SEM_CREATE); + RplReportEvent( NELOG_RplXnsBoot, NULL, 0, NULL); + return; + } + ccb.uchAdapterNumber = pAdapterInfo->adapter_number; + ccb.u.pParameterTable = (PLLC_PARMS)&Parms; + + // + // Initialize fixed fields in XmitQueue. + // + memset( (PVOID)&XmitQueue, '\0', sizeof( XmitQueue.XmitBuffer)); + XmitQueue.XmitBuffer.cbBuffer = sizeof( XmitQueue.LanHeader); + RplCopy( XmitQueue.LanHeader.source_addr, pOpenInfo->NodeAddress, NODE_ADDRESS_LENGTH); + // + // Routing info header fields should be important for token ring already. + // However DLC may want to use these fields to set the XNS identifier. + // For now, 0x0600 word is hardcoded in DLCAPI.DLL // BUGBUG + // + XmitQueue.LanHeader.routing_info_header[0] = 0x06; + XmitQueue.LanHeader.routing_info_header[1] = 0x00; + + // + // Initialize fixed fields in SnapResp.data.response. + // + memset( &SnapResp.data.response, '\0', sizeof(SnapResp.data.response)); + SnapResp.data.response.idp.chksum = XNS_NO_CHKSUM; + SnapResp.data.response.idp.packet_type = PEX_TYPE; + SnapResp.data.response.idp.dest.socket = ETHERSTART_SOCKET; + RplCopy( SnapResp.data.response.idp.src.host, pOpenInfo->NodeAddress, NODE_ADDRESS_LENGTH); + SnapResp.data.response.idp.src.socket = ETHERSTART_SOCKET; + SnapResp.data.response.pex.pex_client = ETHERSERIES_CLIENT; + SnapResp.data.response.es.func = FUNC_READFILERESP; + + memset( &Parms, '\0', sizeof(Parms)); + if (fIsFDDI) { + // + // Prepare for DLC_OPEN_SAP. + // + // Parms.DlcOpenSapParms.usStationId= + // Parms.DlcOpenSapParms.usUserStatValue= + // Parms.DlcOpenSapParms.uchT1= + // Parms.DlcOpenSapParms.uchT2= + // Parms.DlcOpenSapParms.uchTi= + // Parms.DlcOpenSapParms.uchMaxOut= + // Parms.DlcOpenSapParms.uchMaxIn= + // Parms.DlcOpenSapParms.uchMaxOutIncr= + // Parms.DlcOpenSapParms.uchMaxRetryCnt= + // Parms.DlcOpenSapParms.uchMaxMembers= + // Parms.DlcOpenSapParms.usMaxI_Field= + Parms.DlcOpenSapParms.uchSapValue=SNAP_SAP; + Parms.DlcOpenSapParms.uchOptionsPriority=LLC_INDIVIDUAL_SAP; + Parms.DlcOpenSapParms.uchcStationCount=1; + // Parms.DlcOpenSapParms.uchReserved2[2]= + // Parms.DlcOpenSapParms.cGroupCount= + // Parms.DlcOpenSapParms.pGroupList= + // Parms.DlcOpenSapParms.DlcStatusFlags= + // Parms.DlcOpenSapParms.uchReserved3[8]= + // Parms.DlcOpenSapParms.cLinkStationsAvail= + } else { + // + // Prepare for DIR_OPEN_DIRECT. + // + Parms.DirOpenDirectParms.usOpenOptions = LLC_DIRECT_OPTIONS_ALL_MACS; + Parms.DirOpenDirectParms.usEthernetType = 0x0600; // XNS identifier + Parms.DirOpenDirectParms.ulProtocolTypeMask = 0xFFFFFFFF; + Parms.DirOpenDirectParms.ulProtocolTypeMatch = 0x7200FFFF; + Parms.DirOpenDirectParms.usProtocolTypeOffset = 14; // where FFFF0072 of client begins + } + if ( !EtherAcsLan( pAdapterInfo, + &ccb, + (BYTE)((fIsFDDI) ? LLC_DLC_OPEN_SAP + : LLC_DIR_OPEN_DIRECT ))) { + RplReportEvent( NELOG_RplXnsBoot, NULL, 0, NULL); + CloseHandle( ccb.hCompletionEvent); + return; + } + if (fIsFDDI) { + usFDDIStationId = Parms.DlcOpenSapParms.usStationId; + } + + for (;;) { + extern BYTE ripl_rom[]; + extern WORD sizeof_ripl_rom; + WORD Temp; + SNAP_FRAME * psnapreq; + + if ( BufferFree == TRUE) { + BufferFree = FALSE; + memset( &Parms, '\0', sizeof( Parms)); + Parms.BufferFreeParms.pFirstBuffer = (PLLC_XMIT_BUFFER)pRcvbuf; + if ( !EtherAcsLan( pAdapterInfo, &ccb, LLC_BUFFER_FREE)) { + break; + } + } + + // + // Prepare for RECEIVE. + // + // ReceiveParms.usStationId==0 means receive MAC & non-MAC frames. + // + memset( &Parms, '\0', sizeof(Parms)); + if (fIsFDDI) { + Parms.ReceiveParms.usStationId = usFDDIStationId; + } + if ( !EtherAcsLan( pAdapterInfo, &ccb, LLC_RECEIVE)) { + break; + } + BufferFree = TRUE; + + pRcvbuf = (PRCVBUF)Parms.ReceiveParms.pFirstBuffer; + if ( fIsFDDI ) { + psnapreq = (SNAP_FRAME *)&pRcvbuf->u; + if ( psnapreq->header.etype[0] != 0x06 + || psnapreq->header.etype[1] != 0x00 ) { + continue; + } + pEtherstartReq = &(psnapreq->data.request); + } + else + { + pEtherstartReq = (ETHERSTART_REQ *)&pRcvbuf->u; + } + + // + // Make sure this request is for us. + // + if ( !RplCrack( pEtherstartReq)) { + continue; // this request is not for us, ignore it + } + + // + // Prepare for TRANSMIT_DIR_FRAME. + // + memset( &Parms, '\0', sizeof(Parms)); + Parms.TransmitParms.uchXmitReadOption = DLC_DO_NOT_CHAIN_XMIT; + Parms.TransmitParms.pXmitQueue1 = (LLC_XMIT_BUFFER *)&XmitQueue; + Parms.TransmitParms.pBuffer1 = (fIsFDDI) + ? (PVOID)&SnapResp + : (PVOID)&SnapResp.data.response; + + // + // Initialize variable fields in XmitQueue. + // + // We don't want to reverse bits here. + // CODEWORK The +2 here is probably made necessary by a DLC bug. + // + RplCopy( ((PBYTE)XmitQueue.LanHeader.dest_addr) + + ((fIsFDDI) ? 2 : 0), + &pRcvbuf->b.auchLanHeader[ source_offset], + NODE_ADDRESS_LENGTH); + + // + // Initialize variable fields in SnapResp.data.response. + // For FDDI we use all of SnapResp. + // + Temp = min( pEtherstartReq->count, + (WORD)(sizeof_ripl_rom - pEtherstartReq->start)); + Parms.TransmitParms.cbBuffer1 = (WORD)( sizeof(SnapResp.data.response) - + sizeof( SnapResp.data.response.data) + Temp ); + if (fIsFDDI) { + Parms.TransmitParms.cbBuffer1 += sizeof(SnapResp.header); + Parms.TransmitParms.usStationId = usFDDIStationId; + Parms.TransmitParms.uchRemoteSap=SNAP_SAP; + RplCopy( &SnapResp.header, + &psnapreq->header, + sizeof(SnapResp.header) ); + } + SnapResp.data.response.idp.len = HILO( Parms.TransmitParms.cbBuffer1); + RplCopy( SnapResp.data.response.idp.dest.host, + &pRcvbuf->b.auchLanHeader[ source_offset], + NODE_ADDRESS_LENGTH); + if (fIsFDDI) { + ReverseBits( SnapResp.data.response.idp.dest.host ); + } + SnapResp.data.response.pex.pex_id = pEtherstartReq->pex.pex_id; + SnapResp.data.response.es.bytes = Temp; // stays intel ordered + // CODEWORK why do we need to copy every time? + RplCopy( SnapResp.data.response.data, &ripl_rom[ pEtherstartReq->start], Temp); + + if ( !EtherAcsLan( pAdapterInfo, &ccb, + (BYTE)((fIsFDDI) ? LLC_TRANSMIT_UI_FRAME + : LLC_TRANSMIT_DIR_FRAME ))) { + break; + } + } + + if ( pAdapterInfo->Closing == FALSE) { + RplDump(++RG_Assert, ( + "pInfo=0x%x &ccb=0x%x pReq=0x%x pRcvbuf=0x%x pXmitQueue=0x%x pResp=0x%x &Parms=0x%x", + pAdapterInfo, &ccb, pEtherstartReq, pRcvbuf, &XmitQueue, + (fIsFDDI) ? (PVOID)&SnapResp : (PVOID)&SnapResp.data.response, &Parms)); + RplReportEvent( NELOG_RplXnsBoot, NULL, 0, NULL); + } + if ( BufferFree == TRUE) { + memset( &Parms, '\0', sizeof( Parms)); + Parms.BufferFreeParms.pFirstBuffer = (PLLC_XMIT_BUFFER)pRcvbuf; + (VOID)EtherAcsLan( pAdapterInfo, &ccb, LLC_BUFFER_FREE); + } + CloseHandle( ccb.hCompletionEvent); + + RplDump( RG_DebugLevel & RPL_DEBUG_ETHER,( + "--EtherStartThread: pOpenInfo=0x%x", pOpenInfo)); +} diff --git a/private/net/svcdlls/rpl/dll/fdr.c b/private/net/svcdlls/rpl/dll/fdr.c new file mode 100644 index 000000000..dc7f53078 --- /dev/null +++ b/private/net/svcdlls/rpl/dll/fdr.c @@ -0,0 +1,181 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + fdr.c + +Abstract: + + Contains RpldFileDataResponse() entry point. + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + +--*/ + +#include "local.h" + +BOOL RplDlcFdr( + POPEN_INFO pOpenInfo, + PRCB pRcb, + PBYTE data_ptr, + WORD length, + DWORD locate_addr, + DWORD start_addr + ) +/*++ + +Routine Description: + This function sends FILE.DATA.RESPONSE frames to the workstation. + +Arguments: + pOpenInfo pointer to the OPEN_INFO structure + pRcb pointer to the RESOURCE CONTROL BLOCK structure + data_ptr pointer to the data to be send + length length of the data + xfer_addr addr to place data on workstation + start_addr addr to start execution at + +Return Value: + ERROR_SUCCESS if success, else failure. + +--*/ +{ + DWORD status; + PFDR pFrame; + PLLC_CCB pBadCcb; + PLAN_RESOURCE pLanResource; + PADAPTER_INFO pAdapterInfo; + + pAdapterInfo = (PADAPTER_INFO)pOpenInfo->adapt_info_ptr; + pLanResource = (PLAN_RESOURCE)pRcb->lan_rcb_ptr; + + pFrame = (PFDR)pLanResource->frame; + + pLanResource->xmit_error_cnt = 0; // Zero consecutive xmit error counter + pLanResource->retry_count = 0; // allow retries + +transmit_retry: + (void)memset( (LPVOID)&pLanResource->ccb, '\0', sizeof( pLanResource->ccb)); + + pLanResource->TransmitParms.cbBuffer2 = length; + pLanResource->TransmitParms.pBuffer2 = data_ptr; + + // len = 0x1d + len data bit + pFrame->program_length = HILO(length + (sizeof (*pFrame))); + + pFrame->data_hdr = HILO(length + 4); // set len part of data hdr +// #define RPL_ELNK +#ifdef RPL_ELNK + if ( length < 0x544) { + pFrame->data_hdr |= 0xFFFF0000; + } +#endif + pFrame->seq_num = HILO2(pRcb->fdr_seq_number); + pFrame->flags = *((PBYTE)&pRcb->send_flags); + pFrame->locate_addr = HILO2(locate_addr); + pFrame->xfer_addr = HILO2(start_addr); + + + if ( !ResetEvent( pRcb->txsemhdl)) { + status = GetLastError(); + RplDump( ++RG_Assert,( "status=%d", status)); + RplDlcReportEvent( status, SEM_SET); + return( FALSE); + } + + pLanResource->ccb.hCompletionEvent = pRcb->txsemhdl; + pLanResource->ccb.uchAdapterNumber = pAdapterInfo->adapter_number; + pLanResource->ccb.uchDlcCommand = LLC_TRANSMIT_UI_FRAME; + pLanResource->ccb.u.pParameterTable = (PLLC_PARMS)&pLanResource->TransmitParms; + + if ( !ResetEvent( pRcb->SF_wakeup)) { + status = GetLastError(); + RplDump( ++RG_Assert,( "status=%d", status)); + RplDlcReportEvent( status, SEM_SET); + pRcb->RcbIsBad = TRUE; + return( FALSE); + } + + status = AcsLan( &pLanResource->ccb, &pBadCcb); + if ( pAdapterInfo->Closing == TRUE) { + (VOID)SetEvent( pRcb->txsemhdl); + return( FALSE); + } + + if ( status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + RplDump( ++RG_Assert,( "pCcb=0x%x pBadCcb=0x%x status=%d", + &pLanResource->ccb, pBadCcb, status)); + RplDlcReportEvent( status, LLC_TRANSMIT_UI_FRAME); + (VOID)SetEvent( pRcb->txsemhdl); + return( FALSE); + } + + status = WaitForSingleObject( pRcb->txsemhdl, INFINITE); + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + + if ((status != WAIT_OBJECT_0) || (pLanResource->ccb.uchDlcStatus)) { + if ( status != WAIT_OBJECT_0) { + if ( status == WAIT_FAILED) { + status = GetLastError(); + } + RplDlcReportEvent( status, SEM_WAIT); + } + if ( pLanResource->retry_count++ < MAXRETRY) { + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( + "FDR(%ws): retry_count=%d, status=%d, DlcStatus=0x%x", + pRcb->AdapterName, pLanResource->retry_count, status, + pLanResource->ccb.uchDlcStatus)); + Sleep( 100L * pLanResource->retry_count); // for NETWORK to recover + goto transmit_retry; + } + RplDump( ++RG_Assert,( + "pCcb=0x%x pBadCcb=0x%x AdapterName=%ws status=%d DlcStatus=0x%x", + &pLanResource->ccb, pBadCcb, pRcb->AdapterName, status, pLanResource->ccb.uchDlcStatus)); + + pLanResource->retry_count = 0; // no more attempts, reset retry count + + if ( status != ERROR_SUCCESS) { + RplDlcReportEvent( status, SEM_WAIT); + (void)SetEvent( pRcb->txsemhdl); + return( FALSE); + + } + + if ( pLanResource->ccb.uchDlcStatus == LLC_STATUS_TRANSMIT_ERROR_FS + || + pLanResource->ccb.uchDlcStatus == LLC_STATUS_TRANSMIT_ERROR) { + // + // Workstation is not receiving anymore. ?? Rebooted + // during boot, power failure or etc. OR real transmit + // failure ?? + + if ( pLanResource->xmit_error_cnt++ <= MAX_CONSECUTIVE_ERROR) { + return( FALSE); + } + + // + // Too many consecutive transmit errors. Tell that there is a + // problem with transmitting. + // + + RplDlcReportEvent( pLanResource->ccb.uchDlcStatus, LLC_TRANSMIT_UI_FRAME); + return( FALSE); + } + + RplDlcReportEvent( pLanResource->ccb.uchDlcStatus, LLC_TRANSMIT_UI_FRAME); + return( FALSE); + } + + return( TRUE); +} diff --git a/private/net/svcdlls/rpl/dll/find.c b/private/net/svcdlls/rpl/dll/find.c new file mode 100644 index 000000000..0527aa668 --- /dev/null +++ b/private/net/svcdlls/rpl/dll/find.c @@ -0,0 +1,312 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + find.c + +Abstract: + + Contains RplDlcFind() entry point. + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + +Notes: + + June 21, 1990 Olli Visamo + If RplDlcFind() gets error LLC_STATUS_LOST_DATA_NO_BUFFERS or + LLC_STATUS_LOST_DATA_INADEQUATE_SPACE from LLC_RECEIVE, go back to + receive loop since these errors are recoverable. + + July 30, 1990 Olli Visamo + If there is VolumeId in FIND frame, it is copied to RCB structure. +--*/ + +#include "local.h" + +DBGSTATIC VOID BinaryToUnicode( + OUT LPWSTR UnicodeString, + IN PBYTE BinaryArray, + IN DWORD BinaryArrayLength + ) +{ + BYTE byte; + DWORD index; + + for ( index=0; index < BinaryArrayLength; index++) { + byte = BinaryArray[ index]; + UnicodeString[ 2*index] = L"0123456789ABCDEF"[ byte / 0x10]; + UnicodeString[ 2*index+1] = L"0123456789ABCDEF"[ byte & 0x0F]; + } + UnicodeString[ 2*index] = 0; +} + + +BOOL RplDlcFind( + POPEN_INFO pOpenInfo, + PRCB pRcb + ) +/*++ +Routine Description: + + Activates DLC receive to pick up FIND frames. FIND frames arrive on + FIND_SAP sid. + + We do not log any events if we encounter errors while service is in + the closing state. But we have to return FALSE even in that case + else the caller would keep calling us in a tight loop. + +Arguments: + pOpenInfo pointer to the OPEN_INFO structure + pRcb pointer to the RESOURCE CONTROL BLOCK structure + +Return Value: + TRUE if a valid FIND request was received + FALSE otherwise + +--*/ +{ + DWORD status; + PLLC_CCB pBadCcb; + PRCVBUF pRcvbuf; + PADAPTER_INFO pAdapterInfo; + PLAN_RESOURCE pLanResource; + PFOUND_FRAME pFoundFrame; + WORD frame_size; + WORD volid_len; + WORD prog_len; + WORD i; + + + pAdapterInfo = (PADAPTER_INFO)pOpenInfo->adapt_info_ptr; + + memset( (PVOID)&pAdapterInfo->u1, '\0', sizeof(pAdapterInfo->u1)); + pAdapterInfo->u1.r.uchAdapterNumber = pAdapterInfo->adapter_number; + pAdapterInfo->u1.r.uchDlcCommand = LLC_RECEIVE; + pAdapterInfo->u1.r.hCompletionEvent = pAdapterInfo->findsem; + pAdapterInfo->u1.r.u.pParameterTable = (PLLC_PARMS)&pAdapterInfo->u1.r1; + + pAdapterInfo->u1.r1.usStationId = pAdapterInfo->findsid; + +rcvloop: + if ( !ResetEvent( pAdapterInfo->findsem)) { + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + status = GetLastError(); + RplDump( ++RG_Assert,( "pAdapterInfo=0x%x, status=%d", pAdapterInfo, status)); + RplDlcReportEvent( status, SEM_SET); + return( FALSE); + } + + status = AcsLan( &pAdapterInfo->u1.r, &pBadCcb); + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + + if ( status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + RplDump( ++RG_Assert,( "pAdapterInfo=0x%x, status=%d", pAdapterInfo, status)); + RplDlcReportEvent( status, LLC_RECEIVE); + return( FALSE); + } + + status = WaitForSingleObject( pAdapterInfo->findsem, INFINITE); + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + + if ( (status != WAIT_OBJECT_0) || (pAdapterInfo->u1.r.uchDlcStatus)) { + if ( status != WAIT_OBJECT_0) { + if ( status == -1) { + status = GetLastError(); + } + RplDlcReportEvent( status, SEM_WAIT); + } else if ( pAdapterInfo->u1.r.uchDlcStatus + == LLC_STATUS_LOST_DATA_NO_BUFFERS) { + goto rcvloop; // recoverable error + } else if ( pAdapterInfo->u1.r.uchDlcStatus + == LLC_STATUS_LOST_DATA_INADEQUATE_SPACE) { + // + // Release the buffer first. We do not expect an error here. + // + if ( !RplDlcBufferFree( FIND_FREE, pAdapterInfo)) { + return( FALSE); + } + goto rcvloop; + } else { + RplDlcReportEvent( pAdapterInfo->u1.r.uchDlcStatus, LLC_RECEIVE); + } + RplDump( ++RG_Assert,( "status=%d, DlcStatus=0x%x", + status, pAdapterInfo->u1.r.uchDlcStatus)); + return( FALSE); + } + + pRcvbuf = (PRCVBUF) (pAdapterInfo->u1.r1.pFirstBuffer); + + if ( pRcvbuf->u.Find.program_command != FIND_CMD) { + // + // NOT a FIND frame, ignore it. And of course, release the buffer. + // + if ( !RplDlcBufferFree( FIND_FREE, pAdapterInfo)) { + return( FALSE); + } + goto rcvloop; // Issue new receive + } + + // + // Save burned in address first in binary then in hex-ascii representation. + // + memcpy( pRcb->NodeAddress, pRcvbuf->u.Find.source_addr, NODE_ADDRESS_LENGTH); + BinaryToUnicode( pRcb->AdapterName, pRcb->NodeAddress, NODE_ADDRESS_LENGTH); + + // Volume id option and default boot bit are not necessarily used + pRcb->volume_id[0] ='\0'; + pRcb->flags.defboot = 0; + + // Check if volumeid is passed (Nokia option) + prog_len = HILO(pRcvbuf->u.Find.program_length); + if (prog_len > FIND_LEN) { + // + // To get volume id length, we subtract 6 (4 for FILE_HDR length + // plus 2 for identifier bytes) + // + volid_len = (WORD)((HIBYTE((LOWORD(pRcvbuf->u.Find.file_hdr)))) - 6); + + if (volid_len <= MAX_VOLID_LEN && volid_len >= 0) { + if (pRcvbuf->u.Find.file_name[0] == VOLID_FIELD1 && + pRcvbuf->u.Find.file_name[1] == VOLID_FIELD2) { + // IT IS VOLUME ID + for (i = 0; i < volid_len; i++) { + pRcb->volume_id[i] = pRcvbuf->u.Find.file_name[i+2]; + } + } + } + } + + // + // PREPARE LAN HEADER AND TRANSMIT BUFFERS IN LAN RCB FOR + // FOUND FRAME TRANSMISSION + // + + pLanResource = (PLAN_RESOURCE)pRcb->lan_rcb_ptr; + + memcpy( (PVOID)pLanResource->LanHeader.dest_addr, + (PBYTE)&pRcvbuf->b.auchLanHeader[ 8], NODE_ADDRESS_LENGTH); + + // + // Set routing stuff for TokenRing only. + // + if ( pAdapterInfo->network_type == RPL_ADAPTER_TOKEN_RING) { + // + // Clear msb in first byte to avoid GROUP address + // + pLanResource->LanHeader.dest_addr[0] &= 0x7F; + // + // Send it using limited broadcast. + // + pLanResource->LanHeader.routing_info_header[0] = BRDCST; + pLanResource->LanHeader.routing_info_header[1] = UNSPEC_FRM_SIZE; + // + // Set routing info indication bit + // + pLanResource->LanHeader.source_addr[0] |= 0x80; + } + + // + // Setup LLC_TRANSMIT_PARMS (transmit parameter table). + // + pLanResource->TransmitParms.usStationId = pAdapterInfo->findsid; // our, send Sid + pLanResource->TransmitParms.uchTransmitFs = 0; + pLanResource->TransmitParms.uchRemoteSap = FIND_SAP; // their, receive SAP + pLanResource->TransmitParms.pXmitQueue1 = + (PLLC_XMIT_BUFFER)&pLanResource->XmitBuffer; + pLanResource->TransmitParms.pXmitQueue2 = NULL; + // + // Buffer 1 is FOUND_FRAME. There is no buffer 2. + // + pLanResource->TransmitParms.cbBuffer1 = sizeof( FOUND_FRAME); + pLanResource->TransmitParms.pBuffer1 = (PVOID)pLanResource->frame; + pLanResource->TransmitParms.cbBuffer2 = 0; + pLanResource->TransmitParms.pBuffer2 = NULL; + // + // Do not chain on completion. + // + pLanResource->TransmitParms.uchXmitReadOption = DLC_DO_NOT_CHAIN_XMIT; + + + // + // Setup LLC_XMIT_BUFFER used for "pXmitQueue1" above. Note that in + // LAN_RESOURCE data structure LanHeader field is right behind + // XmitBuffer field. Alignment should cause no problems (for now) + // since TransmitParms size is 0xc. + // + pLanResource->XmitBuffer.pNext = NULL; + pLanResource->XmitBuffer.cbBuffer = sizeof( pLanResource->LanHeader); + pLanResource->XmitBuffer.cbUserData = 0; + + // Prepare FOUND frame, there is space for it in LAN RCB + + // + // Choose frame_size as smaller of our frame size & client's + // frame size. + // + + frame_size = HILO(pRcvbuf->u.Find.max_frame); // in Intel format + + if ( frame_size > pAdapterInfo->max_xmit_buff_size) { + // + // Our frame size is smaller than client's frame size. + // + frame_size = pAdapterInfo->max_xmit_buff_size; + } + + pFoundFrame = (PFOUND_FRAME)pLanResource->frame; // frame area of rcb + pFoundFrame->max_frame = HILO( frame_size); // in LAN format + pFoundFrame->program_length = FL; // 00 3A + pFoundFrame->program_command = FOUND_CMD; // 00 02 + pFoundFrame->corr_header = CORR_HDR; // 00 08 40 03 + pFoundFrame->correlator = 0; // 00 00 00 00 + pFoundFrame->resp_hdr = RESP_HDR; // 00 05 40 0B + pFoundFrame->resp_code = 0; // 00 + pFoundFrame->dest_hdr = DEST_HDR; // 00 0a 40 0c + pFoundFrame->source_hdr = SOURCE_HDR; // 00 0a 40 06 + pFoundFrame->info_hdr = INFO_HDR; // 00 10 00 08 + pFoundFrame->frame_hdr = FRAME_HDR; // 00 06 40 09 + pFoundFrame->class_hdr = CLASS_HDR; // 00 06 40 0a + pFoundFrame->conn_class = CLASS1; // 00 01 + pFoundFrame->lsap_hdr = LSAP_HDR; // 00 05 40 07 + pFoundFrame->rsap = LOAD_SAP; // F8 + + // + // Put our card-ID in frame we're transmitting. Remote boot client + // will use this address as a destination address for sending its + // SEND.FILE.REQUEST frames. + // + memcpy( (PVOID)pFoundFrame->source_addr, + pOpenInfo->NodeAddress, NODE_ADDRESS_LENGTH); + + // + // put wrksta-id in frame they're RECEIVING + // + memcpy( (PVOID)pFoundFrame->dest_addr, + pRcvbuf->u.Find.source_addr, NODE_ADDRESS_LENGTH); + + // + // release the buffer + // + if ( !RplDlcBufferFree( FIND_FREE, pAdapterInfo)) { + return( FALSE); + } + return( TRUE); +} + + + diff --git a/private/net/svcdlls/rpl/dll/found.c b/private/net/svcdlls/rpl/dll/found.c new file mode 100644 index 000000000..d9e4469a8 --- /dev/null +++ b/private/net/svcdlls/rpl/dll/found.c @@ -0,0 +1,159 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + found.c + +Abstract: + + Contains RpldFound() entry point. + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + +--*/ + +#include "local.h" + + + +BOOL RplDlcFound( + POPEN_INFO pOpenInfo, + PRCB pRcb + ) +/*++ + +Routine Description: + This function sends FOUND frame to the workstation. + +Arguments: + pOpenInfo pointer to the OPEN_INFO structure + pRcb pointer to the RESOURCE CONTROL BLOCK structure + +Return Value: + ERROR_SUCCESS if success, else failure. + +--*/ +{ + DWORD status; + PLLC_CCB pBadCcb; + PLAN_RESOURCE pLanResource; + PADAPTER_INFO pAdapterInfo; + + pAdapterInfo = (PADAPTER_INFO)pOpenInfo->adapt_info_ptr; + pLanResource = (PLAN_RESOURCE)pRcb->lan_rcb_ptr; + + pLanResource->xmit_error_cnt = 0; // Zero consecutive xmit error counter + pLanResource->retry_count = 0; // allow retries + +transmit_retry: + (void)memset( (LPVOID)&pLanResource->ccb, '\0', sizeof( pLanResource->ccb)); + // + // Most of other FOUND_FRAME data have been already set in RpldFind() code. + // + pLanResource->TransmitParms.cbBuffer2 = 0; + pLanResource->TransmitParms.pBuffer2 = NULL; + + if ( !ResetEvent( pRcb->txsemhdl)) { + status = GetLastError(); + RplDump( ++RG_Assert,( "status=%d", status)); + RplDlcReportEvent( status, SEM_SET); + return( FALSE); + } + + pLanResource->ccb.hCompletionEvent = pRcb->txsemhdl; + pLanResource->ccb.uchAdapterNumber = pAdapterInfo->adapter_number; + pLanResource->ccb.uchDlcCommand = LLC_TRANSMIT_UI_FRAME; + pLanResource->ccb.u.pParameterTable = (PLLC_PARMS)&pLanResource->TransmitParms; + + if ( !ResetEvent( pRcb->SF_wakeup)) { + status = GetLastError(); + RplDump( ++RG_Assert,( "status=%d", status)); + RplDlcReportEvent( status, SEM_SET); + pRcb->RcbIsBad = TRUE; + return( FALSE); + } + + status = AcsLan( &pLanResource->ccb, &pBadCcb); + if ( pAdapterInfo->Closing == TRUE) { + (VOID)SetEvent( pRcb->txsemhdl); + return( FALSE); + } + + if ( status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + RplDump( ++RG_Assert,( "pCcb=0x%x pBadCcb=0x%x status=%d", + &pLanResource->ccb, pBadCcb, status)); + RplDlcReportEvent( status, LLC_TRANSMIT_UI_FRAME); + (VOID)SetEvent( pRcb->txsemhdl); + return( FALSE); + } + + status = WaitForSingleObject( pRcb->txsemhdl, INFINITE); + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + + if ( (status != WAIT_OBJECT_0) || (pLanResource->ccb.uchDlcStatus)) { + if ( status != WAIT_OBJECT_0) { + if ( status == WAIT_FAILED) { + status = GetLastError(); + } + RplDlcReportEvent( status, SEM_WAIT); + } + if ( pLanResource->retry_count++ < MAXRETRY) { + RplDump( RG_DebugLevel & RPL_DEBUG_FOUND,( + "FDR(%ws): retry_count=%d, status=%d, DlcStatus=0x%x", + pRcb->AdapterName, pLanResource->retry_count, status, + pLanResource->ccb.uchDlcStatus)); + Sleep( 100L * pLanResource->retry_count); // for NETWORK to recover + goto transmit_retry; + } + RplDump( ++RG_Assert,( + "pCcb=0x%x pBadCcb=0x%x AdapterName=%ws status=%d DlcStatus=0x%x", + &pLanResource->ccb, pBadCcb, pRcb->AdapterName, status, pLanResource->ccb.uchDlcStatus)); + + pLanResource->retry_count = 0; // no more attempts, reset retry count + + if ( status != ERROR_SUCCESS) { + RplDlcReportEvent( status, SEM_WAIT); + (VOID)SetEvent( pRcb->txsemhdl); + return( FALSE); + + } + + if ( pLanResource->ccb.uchDlcStatus == LLC_STATUS_TRANSMIT_ERROR_FS + || + pLanResource->ccb.uchDlcStatus == LLC_STATUS_TRANSMIT_ERROR) { + // + // Workstation is not receiving anymore. ?? Rebooted + // during boot, power failure or etc. OR real transmit + // failure ?? + + if ( pLanResource->xmit_error_cnt++ <= MAX_CONSECUTIVE_ERROR) { + return( FALSE); + } + + // + // Too many consecutive transmit errors. Tell that there is a + // problem with transmitting. + // + + RplDlcReportEvent( pLanResource->ccb.uchDlcStatus, LLC_TRANSMIT_UI_FRAME); + return( FALSE); + } + + RplDlcReportEvent( pLanResource->ccb.uchDlcStatus, LLC_TRANSMIT_UI_FRAME); + return( FALSE); + } + + return( TRUE); +} + diff --git a/private/net/svcdlls/rpl/dll/init.c b/private/net/svcdlls/rpl/dll/init.c new file mode 100644 index 000000000..0550b158f --- /dev/null +++ b/private/net/svcdlls/rpl/dll/init.c @@ -0,0 +1,545 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + init.c + +Abstract: + + Contains RplDlcInit() and RplDlcTerm() entry points. + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + +--*/ + +#include "local.h" + +// +// Routines imported from ether.c +// +VOID EtherStartThread( POPEN_INFO pOpenInfo); + +// Some definitions for EtherStart +#define ETHERSTART_STACK_SIZE 0x1400 // 5k + +BYTE Swap[256] = +{ +0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, +0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, +0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, +0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, +0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, +0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, +0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, +0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, +0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, +0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, +0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, +0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, +0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, +0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, +0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, +0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +}; + +VOID ReverseBits( PBYTE NodeAddress) { + DWORD i; + for ( i = 0; i < NODE_ADDRESS_LENGTH; i++) { + NodeAddress[ i] = Swap[ NodeAddress[ i] ]; + } +} + +DBGSTATIC BOOL AdapterInit( + POPEN_INFO pOpenInfo, + BYTE command, + BYTE sapval + ) +/*++ +Routine Description: + + Contains functions used to prepare network adapter to serve remote boot. + Following DLC calls (ACSLAN) are used + + - DIR.OPEN.ADAPTER + - DIR.STATUS + - DLC.OPEN.SAP + - DIR.SET.FUNCTIONAL.ADDRESS + + Setup parameters for command (CCB and parameter tables). + We do not use an application-ID to lock our DLC resources. + Call ACSLAN. + Check immediate return code, quit on error, no retry. + Wait on the semaphore for command completion. check status. + Parse result of command when necessary. + - OPEN_ADAPTER + Record the Appl-ID value for future DLC calls. + Get max. transmit buffer size. + - STATUS + Place adapter-ID in the openinfo structure. + Place adapter-type in the openinfo structure. + - OPEN_SAP + Place station ids in the adapter_info structure + - SET_FUNCTIONAL_ADDRESS (TokenRing) or + SET_GROUP_ADDRESS (Ethernet) + +Return Value: + TRUE if success, FALSE otherwise. +--*/ +{ + DWORD status; + PLLC_CCB pBadCcb; // unused pointer for ACSLAN + PADAPTER_INFO pAdapterInfo; + + pAdapterInfo = (PADAPTER_INFO)pOpenInfo->adapt_info_ptr; + + if ( !ResetEvent( pAdapterInfo->gen_sem)) { + status = GetLastError(); + RplDump( ++RG_Assert,( "status=%d", status)); + RplDlcReportEvent( status, SEM_SET); + return( FALSE); + } + + // + // An early check - compare dwords - do not subtract - to avoid wrapping. + // + if ( pOpenInfo->adapt_info_size <= sizeof( ADAPTER_INFO)) { + RplDump( ++RG_Assert,( "adapt_info_size=%d", pOpenInfo->adapt_info_size)); + return( FALSE); // no space for DLC buffer pool + } + + // + // Zero parameter blocks (this will zero "pNext" field in LLC_CCB) + // and do the common parameter initializion. + // + (VOID)memset((PVOID)&pAdapterInfo->s,'\0',sizeof(pAdapterInfo->s)); + pAdapterInfo->s.ccb.uchAdapterNumber = pAdapterInfo->adapter_number; + pAdapterInfo->s.ccb.uchDlcCommand = command; + pAdapterInfo->s.ccb.hCompletionEvent = pAdapterInfo->gen_sem; + + // + // Initialize command specific parameters in the input LLC_CCB. + // + switch( command) { + case LLC_BUFFER_CREATE: + pAdapterInfo->s.ccb.u.pParameterTable = + (PLLC_PARMS)&pAdapterInfo->s.u.s0.bcp; + pAdapterInfo->s.u.s0.bcp.pBuffer = + pOpenInfo->adapt_info_ptr + sizeof( ADAPTER_INFO); + pAdapterInfo->s.u.s0.bcp.cbBufferSize = + pOpenInfo->adapt_info_size - sizeof( ADAPTER_INFO); + pAdapterInfo->s.u.s0.bcp.cbMinimumSizeThreshold = 0x2000; + break; + + case LLC_DIR_CLOSE_ADAPTER: + NOTHING; // there is nothing to initialize here + break; + case LLC_DIR_OPEN_ADAPTER: + pAdapterInfo->s.ccb.u.pParameterTable = + (PLLC_PARMS)&pAdapterInfo->s.u.s1.cpo; + pAdapterInfo->s.u.s1.cpo.pAdapterParms = &pAdapterInfo->s.u.s1.oap; + pAdapterInfo->s.u.s1.cpo.pExtendedParms = &pAdapterInfo->s.u.s1.oep; + pAdapterInfo->s.u.s1.oep.pSecurityDescriptor = NULL; + // + // With LLC_ETHERNET_TYPE_DEFAULT rpl server on build 392 did not + // detect an 802.3 client FIND frame. + // +#ifdef NOT_YET + // Antti's email + pAdapterInfo->s.u.s1.oep.LlcEthernetType = LLC_ETHERNET_TYPE_DIX; +#else + // Old stuff + pAdapterInfo->s.u.s1.oep.LlcEthernetType = LLC_ETHERNET_TYPE_802_3; +#endif + pAdapterInfo->s.u.s1.oep.hBufferPool = NULL; // for first open + pAdapterInfo->s.u.s1.cpo.pDlcParms = &pAdapterInfo->s.u.s1.odp; + break; + + case LLC_DIR_STATUS: + pAdapterInfo->s.ccb.u.pParameterTable = + (PLLC_PARMS)&pAdapterInfo->s.u.s2.dsp; + break; + + case LLC_DLC_OPEN_SAP: + pAdapterInfo->s.ccb.u.pParameterTable = + (PLLC_PARMS)&pAdapterInfo->s.u.s3.cpo; + pAdapterInfo->s.u.s3.cpo.uchOptionsPriority = (BYTE ) 0x04; // individual sap + pAdapterInfo->s.u.s3.cpo.uchSapValue = sapval; // the SAP number to open + break; + + case LLC_DIR_SET_FUNCTIONAL_ADDRESS: // TokenRing + // + // This works correctly for Ethernet medium as well. I.e. in Ethernet + // case bits within every byte are inverted by DLC. We keep the code + // for SET_GROUP_ADDRESS in case DLC gets changed not to support this. + // + pAdapterInfo->s.ccb.u.ulParameter = 0x00000040; // accept FIND frames + break; + + case LLC_DIR_SET_GROUP_ADDRESS: // Ethernet + // + // Use TokenRing FUNCTIONAL_ADDRESS given above, but with bits + // inverted in every single byte (order of bytes is unchanged). + // + pAdapterInfo->s.ccb.u.ulParameter = 0x00000002; // accept FIND frames + break; + default: + RplDump( ++RG_Assert, ("command=0x%x", command)); + return( FALSE); + break; + } + + status = AcsLan( &pAdapterInfo->s.ccb, &pBadCcb); + RplDump( RG_DebugLevel & RPL_DEBUG_INIT,( "Adapter: AcsLan(0x%x), status=%d", command, status)); + + if ( status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + + // + // We do not write an event log if we fail to open an adapter. + // We assume we may be trying to open an adapter that does not even exist. + // + if ( command == LLC_DIR_OPEN_ADAPTER) { + RplDump( RG_DebugLevel & RPL_DEBUG_INIT,( + "Adapter: AcsLan( DIR_OPEN_ADAPTER) fails, status=0x%x, adapterNumber=%d", + status, pAdapterInfo->adapter_number)); + } else { + // Look up ACSLAN_STATUS errors. + RplDump( ++RG_Assert,( "AcsLan: command=0x%x, status=0x%x, adapterNumber=%d", + command, status, pAdapterInfo->adapter_number)); + RplDlcReportEvent( status, command); + } + (VOID)SetEvent( pAdapterInfo->gen_sem); + return( FALSE); + } + + // + // await command completion for few seconds + // + status = WaitForSingleObject( pAdapterInfo->gen_sem, 3000L); + + if (status != WAIT_OBJECT_0) { + if ( status == -1) { + status = GetLastError(); + } + RplDump( ++RG_Assert,( "Adapter: Wait(), status=%d", status)); + RplDlcReportEvent( status, SEM_WAIT); + (VOID)SetEvent( pAdapterInfo->gen_sem); + return( FALSE); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_INIT,( + "Adapter: AcsLan( command=0x%x), DlcStatus=0x%x", + command, pAdapterInfo->s.ccb.uchDlcStatus)); + + if ( pAdapterInfo->s.ccb.uchDlcStatus) { + RplDump( ++RG_Assert,( "Adapter: DlcStatus=0x%x", pAdapterInfo->s.ccb.uchDlcStatus)); + RplDlcReportEvent( pAdapterInfo->s.ccb.uchDlcStatus, command); + return( FALSE); + } + + switch( command) { + case LLC_BUFFER_CREATE: + pAdapterInfo->hBufferPool = pAdapterInfo->s.u.s0.bcp.hBufferPool; + RPL_ASSERT( pAdapterInfo->hBufferPool != NULL); + break; + + case LLC_DIR_OPEN_ADAPTER: + // + // Save our maximum frame size for transmit buffers. + // + pAdapterInfo->max_xmit_buff_size = + pAdapterInfo->s.u.s1.oap.usMaxFrameSize; + + // + // OS/2 dlc uses smaller size, thus if uncomment the definition + // of OS2_MAX_FRAME_SIZE below we can repro OS/2 RPL behavior + // byte by byte. Useful for debugging. + // +#define OS2_MAX_FRAME_SIZE 1508 + +#ifdef OS2_MAX_FRAME_SIZE + if (pAdapterInfo->max_xmit_buff_size > OS2_MAX_FRAME_SIZE) { + pAdapterInfo->max_xmit_buff_size = OS2_MAX_FRAME_SIZE; + } +#endif + + if ( pAdapterInfo->max_xmit_buff_size < OVRHD + 100) { + RplDump( ++RG_Assert,( "Adapter: max_xmit_buff_size=0x%x", + pAdapterInfo->max_xmit_buff_size)); + RplDlcReportEvent( TOO_SMALL_XMIT_BUFF, RPLDLL_NO_ERROR); + return( FALSE); + } + + // Tell the size of LAN_RCB, server allocates space for it. + pOpenInfo->lan_rcb_size = sizeof(LAN_RESOURCE); + break; + + case LLC_DIR_STATUS: + pAdapterInfo->network_type = pAdapterInfo->s.u.s2.dsp.usAdapterType; + if ( pAdapterInfo->network_type != RPL_ADAPTER_ETHERNET && + pAdapterInfo->network_type != RPL_ADAPTER_FDDI && + pAdapterInfo->network_type != RPL_ADAPTER_TOKEN_RING) { + RplDump( ++RG_Assert,( "Adapter: network_type=0x%x", + pAdapterInfo->network_type)); + return( FALSE); // unknown adapter type + } + + memcpy( pOpenInfo->NodeAddress, + pAdapterInfo->s.u.s2.dsp.auchNodeAddress, NODE_ADDRESS_LENGTH); +#ifndef NOT_YET + // + // In Ethernet (FDDI) case "auchNodeAddress" returned by DLC has + // wrong order of bits within a byte. Until DLC gets fixed + // we need to reverse the bit order. Without this the source + // address in FOUND frame is wrong, thus remote boot client + // uses wrong address in LAN_HEADER of its SEND_FILE_REQUEST. + // + + if ( pAdapterInfo->network_type != RPL_ADAPTER_TOKEN_RING) { + ReverseBits( pOpenInfo->NodeAddress); + } +#endif + break; + + case LLC_DLC_OPEN_SAP: + // + // Save station ids for future use + // + if (sapval == LOAD_SAP) { + pAdapterInfo->loadsid = pAdapterInfo->s.u.s3.cpo.usStationId; + RplDump( RG_DebugLevel & RPL_DEBUG_INIT,( + "Adapter: loadsid = 0x%x", pAdapterInfo->loadsid)); + } else { + pAdapterInfo->findsid = pAdapterInfo->s.u.s3.cpo.usStationId; + RplDump( RG_DebugLevel & RPL_DEBUG_INIT,( + "Adapter: findsid = 0x%x", pAdapterInfo->findsid)); + } + break; + + case LLC_DIR_CLOSE_ADAPTER: + // + // Close events that are no longer needed. + // + (VOID)CloseHandle( pAdapterInfo->gen_sem); + (VOID)CloseHandle( pAdapterInfo->sfrsem); + (VOID)CloseHandle( pAdapterInfo->findsem); + (VOID)CloseHandle( pAdapterInfo->getdata_sem); + break; + } + + return( TRUE); +} + +BOOL RplDlcInit( + POPEN_INFO pOpenInfo, + DWORD rpl_adapter + ) +/*++ + +Routine Description: + + Prepares DLL and adapter to serve Remote Boot clients. + + Create system events, open adapter logically and get adapter status, + open architected SAPs (F8 and FC), then set architected functional address. + This last operation succeeds in case of Tokenring. It fails in case of + Ethernet, so there we set group address. + + In case of errors we write an event log and return. + +Arguments: + pOpenInfo pointer to the OPEN_INFO structure + rpl_adapter adapter number + +Return Value: + TRUE if success, FALSE otherwise. + +--*/ +{ + DWORD status; + PADAPTER_INFO pAdapterInfo; + DWORD index; + HANDLE Handle; + + // + // Memory for pAdapterInfo was allocated in rpl server code. + // + pAdapterInfo = (PADAPTER_INFO)pOpenInfo->adapt_info_ptr; + + // + // Initialize ADAPTER_INFO structure. + // + + // + // Service is just starting => Closing is FALSE. + // + pAdapterInfo->Closing = FALSE; + + // + // Typecast below reflects mismatch between RplDlc* & DLC interface. + // + pAdapterInfo->adapter_number = (BYTE)rpl_adapter; + + // + // SFR receive thread is not yet created, init status variables + // + pAdapterInfo->SfrReceiveThreadHandle = NULL; + pAdapterInfo->SfrReturn = FALSE; + + for ( status = ERROR_SUCCESS, index=0; index<4; index++) { + BOOL ManualReset; + BOOL InitialStateSignalled; + // + // There are four events to create and save handles to proper places + // for future use. Note that "sfrsem" is different. + // + if ( index != 1) { + ManualReset = TRUE; + InitialStateSignalled = TRUE; + } else { + ManualReset = FALSE; + InitialStateSignalled = FALSE; + } + Handle = CreateEvent( NULL, ManualReset, InitialStateSignalled, NULL); + if ( Handle == NULL) { + status = GetLastError(); + RplDump( ++RG_Assert,( "status=%d", status)); + break; + } + switch( index) { + case 0: + pAdapterInfo->gen_sem = Handle; + break; + case 1: + pAdapterInfo->sfrsem = Handle; + break; + case 2: + pAdapterInfo->findsem = Handle; + break; + case 3: + pAdapterInfo->getdata_sem = Handle; + break; + } + } + + if ( status != ERROR_SUCCESS) { // failed to create events + RplDlcReportEvent( status, SEM_CREATE); + return( FALSE); + } + if ( !AdapterInit( pOpenInfo, LLC_DIR_OPEN_ADAPTER, 0)) { + return( FALSE); + } + if ( !AdapterInit( pOpenInfo, LLC_BUFFER_CREATE, 0)) { + return( FALSE); + } + if ( !AdapterInit( pOpenInfo, LLC_DIR_STATUS, 0)) { + return( FALSE); + } + if ( !AdapterInit( pOpenInfo, LLC_DLC_OPEN_SAP, LOAD_SAP)) { + return( FALSE); + } + if ( !AdapterInit( pOpenInfo, LLC_DLC_OPEN_SAP, FIND_SAP)) { + return( FALSE); + } + + // + // For now LLC_DIR_SET_FUNCTIONAL_ADDRESS does the correct thing both + // in case of Ethernet & TokenRing. If due to unforeseen changes in + // DLC this code stops working on Ethernet case, we should call + // LLC_DIR_SET_GROUP_ADDRESS in Ethernet case below. + // + if ( !AdapterInit( + pOpenInfo, +#ifdef NOT_YET + pAdapterInfo->network_type == RPL_ADAPTER_TOKEN_RING + ? LLC_DIR_SET_FUNCTIONAL_ADDRESS + || LLC_DIR_SET_GROUP_ADDRESS, +#else + LLC_DIR_SET_FUNCTIONAL_ADDRESS, +#endif + 0)) { + + return( FALSE); + } + + if ( pAdapterInfo->network_type == RPL_ADAPTER_ETHERNET + || pAdapterInfo->network_type == RPL_ADAPTER_FDDI ) { + + DWORD tid; + + pAdapterInfo->EtherStartThreadHandle = CreateThread( + NULL, // lpThreadAttribute + 0, // dwStackSize - same as first thread + (LPTHREAD_START_ROUTINE)EtherStartThread, // lpStartAddress + (LPVOID)pOpenInfo, // lpParameter + 0, // dwCreationFlags + &tid // lpThreadId + ); + if ( pAdapterInfo->EtherStartThreadHandle == NULL) { + status = GetLastError(); + RplDump( ++RG_Assert,( "CreateThread(), status=%d", status)); + RplDlcReportEvent( status, THREAD_CREATE); + return( FALSE); + } + } + + return( TRUE); +} + +BOOL RplDlcTerm( POPEN_INFO pOpenInfo) +/*++ + +Routine Description: + Releases adapter and other resources that have been allocated for RPLDLL. + + This thread must wait for internally created RPLDLL threads to die. + RPLSRV does not know about this threads. If we do not wait here, then + RPLSRV may clean up all resources (e.g. debug buffer) before RPLDLL + internal threads manage to die (=>access violations). + +Arguments + pOpenInfo pointer to the OPEN_INFO structure + +--*/ +{ + DWORD status; + PADAPTER_INFO pAdapterInfo; + + pAdapterInfo = (PADAPTER_INFO )pOpenInfo->adapt_info_ptr; + pAdapterInfo->Closing = TRUE; + + // + // Close adapter, release resources + // + if ( !AdapterInit( pOpenInfo, LLC_DIR_CLOSE_ADAPTER, 0)) { + return( FALSE); + } + + if ( pAdapterInfo->SfrReceiveThreadHandle != NULL) { + RplDump( RG_DebugLevel & RPL_DEBUG_INIT,( "RplDlcTerm: Wait( Sfr)")); + status = WaitForSingleObject( pAdapterInfo->SfrReceiveThreadHandle, INFINITE); + if ( status != WAIT_OBJECT_0) { + RplDump( ++RG_Assert,( "status=%d", status==WAIT_FAILED ? GetLastError() : status)); + } + } + + if ( pAdapterInfo->EtherStartThreadHandle != NULL) { + RplDump( RG_DebugLevel & RPL_DEBUG_INIT,( "RplDlcTerm: Wait( Ether)")); + status = WaitForSingleObject( pAdapterInfo->EtherStartThreadHandle, INFINITE); + if ( status != WAIT_OBJECT_0) { + RplDump( ++RG_Assert,( "status=%d", status==WAIT_FAILED ? GetLastError() : status)); + } + } + + return( TRUE); +} + + diff --git a/private/net/svcdlls/rpl/dll/local.h b/private/net/svcdlls/rpl/dll/local.h new file mode 100644 index 000000000..48bfb1539 --- /dev/null +++ b/private/net/svcdlls/rpl/dll/local.h @@ -0,0 +1,498 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + local.h + +Abstract: + + Main include file used by rpldll & rploem code. + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + 19-Nov-1993 vladimv + rpldll.h -> local.h + cleanup & face-lift + +--*/ + +#define NOTHING // same def in ntdef.h which is not included here + +#include <nt.h> // NT definitions +#include <ntrtl.h> // NT runtime library definitions +#include <nturtl.h> + +#include <windows.h> // DWORD, IN, File APIs, etc. +#include <stdlib.h> +#include <lmcons.h> + +#include <stdio.h> // vsprintf +#include <ctype.h> // isspace + + +//#include <lmcons.h> // LAN Manager common definitions +#include <lmerr.h> // LAN Manager network error definitions +#include <lmsname.h> // LAN Manager service names +#include <lmapibuf.h> // NetApiBufferFree + +#include <netlib.h> // LAN Man utility routines +#include <netlibnt.h> // NetpNtStatusToApiStatus +#include <netdebug.h> // NetpDbgPrint +#include <tstring.h> // Transitional string functions +#include <icanon.h> // I_Net canonicalize functions +#include <align.h> // ROUND_UP_COUNT macro + +#include <services.h> // LMSVCS_GLOBAL_DATA +#include <apperr.h> // APE_AT_ID_NOT_FOUND + +#include <dlcapi.h> // - LLC_CCB +#include <dlcio.h> // - DLC_DO_NOT_CHAIN_XMIT +#include <lmerrlog.h> // - ERRLOG_BASE NELOG_OEM_Code + +// +// Global types and constants (used in all RPL server files). +// + +#include <rpldebug.h> +#include <rpldll.h> // rplnet.dll entry points & return codes +#include <riplcons.h> +#include <ripltyps.h> + + +// +// BUGBUG For Ethernet, DLC driver returns 0x100 while LLC_ADAPTER_ETHERNET +// BUGBUG is 0x10. One or the other should be changed. The following +// BUGBUG defines & "<<4" are introduced as a workaround. +// +#define RPL_ADAPTER_ETHERNET (LLC_ADAPTER_ETHERNET<<4) +#define RPL_ADAPTER_TOKEN_RING LLC_ADAPTER_TOKEN_RING +// +// BUGBUG -- DLC uses a "currently free value" to indicate FDDI. +// +#define RPL_ADAPTER_FDDI 0x0200 + + +#define LOAD_SAP 0xF8 // Receive SAP for SEND.FILE.REQUEST frames +#define FIND_SAP 0xFC // Receice SAP for FIND frames + +// +// Error handler definitions and return codes to server +// + + +// +// Non DLC causing error. Note that these do NOT and should NOT overlap +// with dlcapi.h command codes. +// +#define RPLDLL_NO_ERROR (0xFF) +#define SEM_SET (RPLDLL_NO_ERROR - 1) // ResetEvent +#define SEM_WAIT (RPLDLL_NO_ERROR - 2) // WaitForSingle +#define SEM_CREATE (RPLDLL_NO_ERROR - 3) // CreateEvent +#define THREAD_CREATE (RPLDLL_NO_ERROR - 5) // CreateThread + +// Message number definitions. See RMTDLL.MSG file + +// SEM_ , ACSLAN_, MEMORY_, THREAD_ERROR +#define FAIL_MSG 110 // RMT0110I: RMTNET2.DLL: %1 failed. + +// SEM_ , MEMORY_, and THREAD_ERROR +#define DOS_ERROR 111 // RMT0111I: The error code is the data. + +#define TOO_SMALL_XMIT_BUFF 120 + +// RMTNET1.DLL errors + +#define CANNOT_LOAD_MOD 125 +#define PROC_NOT_FOUND 126 +#define VERSION_MISMATCH 127 + + +#define MSG_FILENAME "RPLDLL.MSG" + + +// BYTE => BYTE +// INT => SHORT +// UINT => WORD + +// +// COMPLETE_BY_READ is used for LLL_RECEIVE in "ulReceivedFlag". +// Apparently, any other non-zero value would do equally well. +// +#define COMPLETE_BY_READ 1 + +// +// Version number returned to server == +// Version number returned by RPL2_Init +// +#define VERSION2_00 0x0200 + +// +// Helper Macros +// + +// Swap bytes of word: (B1-B0) -> (B0-B1) +// +#define HILO(w) ((WORD)(((w<<8) | (w>>8)))) + + +// Swap bytes and words of dword: (B3-B2-B1-B0) -> (B0-B1-B2-B3) +// +#define HILO2(_x) ((((DWORD)HILO(HIWORD(_x))) | (((DWORD)HILO(LOWORD(_x)))<<16))) + + +// SAP receive buffer pool values +#define SAP_BUFFER_SIZE 240 +#define FIND_POOL_SIZE SAP_BUFFER_SIZE +#define LOAD_POOL_SIZE (20*SAP_BUFFER_SIZE) // 20 rcv buffers for load SAP +#define PARAGRAPH 16 +#define LOAD_POOL_SIZE_PARA (LOAD_POOL_SIZE/PARAGRAPH) +#define FIND_POOL_SIZE_PARA (FIND_POOL_SIZE/PARAGRAPH) + +// Type of buffer for BUFFER.FREE +#define FIND_FREE 0 +#define SFR_FREE 1 + +// RMT2 internal data structures and RIPL frame formats +// Size of ADAPTER_INFO structure MUST NOT exceed 2 kbytes + + +typedef struct _ADAPTER_INFO { + BYTE Closing; // TRUE if adapter has been closed + BYTE adapter_number; // number of adapter to be used 0,1... + WORD network_type; // TokenRing or Ethernet + WORD loadsid; // Station ID for LOAD SAP + WORD findsid; // Station ID for FIND SAP + WORD max_xmit_buff_size; // Upper limit for buffers to xmit + HANDLE gen_sem; // event for DLC general work + HANDLE findsem; // event for FIND_SAP RECEIVE and BUFFER.FREE + HANDLE sfrsem; // event for LOAD_SAP RECEIVE + HANDLE getdata_sem;// event for LOAD_SAP READ and BUFFER.FREE + + HANDLE hBufferPool;// DLC handle used for buffer supplied to DLC + + // + // Following data is not actual adapter info, + // but this is only place to hide it to make + // these DLLs HANDLE-CALLABLE ie. RPL_Init must be made to + // every network adapter that is used. Adapter_info is + // so called handle, that must be used on subsequent calls + // to that adapter. + // + + // + // SfrReceiveThread is used to keep receive posted for SFR. + // SfrReceiveThreadHandle is NULL if & only this thread exists. + // + HANDLE SfrReceiveThreadHandle; + + // + // EtherStartThread is used to send DLC to 3Com 3Station clients. + // EtherStartThreadHandle is non-NULL if & only this thread exists. + // + HANDLE EtherStartThreadHandle; + + // + // Used by SfrReceiveThread to let DlcSfr thread it is time to exit. + // + BOOL SfrReturn; + + // + // Command control block and parameter tables for open adapter, open sap, + // set functional address, get status and close adapter commands. + // + + // Note: re-used data space + struct { + LLC_CCB ccb; // the base ccb + union { + struct { + LLC_BUFFER_CREATE_PARMS bcp; // Buffer Create Parms + } s0; + struct { + LLC_DIR_OPEN_ADAPTER_PARMS cpo; // Ccb Parms Open + LLC_ADAPTER_OPEN_PARMS oap; // Open Adapter Parms + LLC_EXTENDED_ADAPTER_PARMS oep; // Open Extended Parms + LLC_DLC_PARMS odp; // Open Dlc Parms + } s1; + struct { + LLC_DIR_STATUS_PARMS dsp; // Dir Status Parms + } s2; + struct { + LLC_DLC_OPEN_SAP_PARMS cpo; // Ccb ??? + } s3; + } u; + } s; + // CCBs and parameter tables for RECEIVEs, READ and BUFFER_FREE + struct { + LLC_CCB r; // RECEIVE ccb for find + LLC_RECEIVE_PARMS r1; // parameter table 17 bytes + BYTE pad; // alignment + } u1; + + struct { + LLC_CCB r; // RECEIVE ccb for sfr + LLC_RECEIVE_PARMS r1; // parameter table 17 bytes*/ + BYTE pad; // alignment + } u2; + + struct { + LLC_CCB r; // READ ccb for sfr + LLC_READ_PARMS r1; // parameter table + } u3; + + // + // BUFFER.FREE CCB and parameter table for freeing received buffer, + // SEND.FILE.REQUEST frames + // + LLC_CCB sfr_bf_ccb; + LLC_BUFFER_FREE_PARMS sfr_bf_ccbpt; + + // + // BUFFER.FREE CCB and parameter table for freeing received buffer, + // FIND frames + // + LLC_CCB find_bf_ccb; + LLC_BUFFER_FREE_PARMS find_bf_ccbpt; + +} ADAPTER_INFO, *PADAPTER_INFO; + + +typedef struct _LAN_HEADER { + BYTE pcf0; // Physical control field 0 + BYTE pcf1; // Physical control field 1 + BYTE dest_addr[ NODE_ADDRESS_LENGTH]; // Destination address + BYTE source_addr[ NODE_ADDRESS_LENGTH]; // Source address + BYTE routing_info_header[2]; // Routing information hdr +} LAN_HEADER; + +// +// In LAN_RESOURCE structure below it is essential that LanHeader field +// is right behind XmitBuffer field. LLC_XMIT_BUFFER structure used to have +// a trailing auchData[1] which would give a wrong offset for LAN_RESOURCE. +// Now it has a trailing auchData[0] so compiler complains if it is not the +// the last element in a tructure. Both problems are solved by defining +// XMIT_BUFFER which has no auchData[] field. +// + +typedef struct _XMIT_BUFFER { + struct _XMIT_BUFFER * pNext; // next buffer (or NULL) + WORD usReserved1; // + WORD cbBuffer; // length of transmitted data + WORD usReserved2; // + WORD cbUserData; // length of optional header +} XMIT_BUFFER, *PXMIT_BUFFER; + +typedef struct _LAN_RESOURCE { + BYTE xmit_error_cnt; // consecutive xmit error count + BYTE retry_count; // xmit retries on current frame + LLC_CCB ccb; // for RECEIVE ,TRANSMIT frames + LLC_TRANSMIT_PARMS TransmitParms; // parameter block for TRANSMIT + XMIT_BUFFER XmitBuffer; // buffer one header + LAN_HEADER LanHeader; // for TRANSMIT.UI.FRAME + BYTE rest_of_routing[16]; // lan hdr defines 2 bytes routing + BYTE frame[110]; // the frame itself +} LAN_RESOURCE, *PLAN_RESOURCE; + + +// +// Remote boot structures cannot use default packing. Thus: +// + +#include <packon.h> // Pack structures: #pragma pack(1) + +// The find frame structure is defined below. + +typedef struct _FIND_FRAME { + WORD program_length; // 0x53 + value in first 2 bytes of file_hdr + WORD program_command; // must be FIND_CMD + DWORD corr_hdr; + DWORD correlator; + DWORD info_hdr; + DWORD frame_hdr; + WORD max_frame; + DWORD class_hdr; + WORD conn_class; + DWORD source_hdr; + BYTE source_addr[ NODE_ADDRESS_LENGTH]; + DWORD lsap_hdr; + BYTE rsap; + DWORD search_hdr; + DWORD loader_hdr; + BYTE mach_conf[8]; + WORD equip_flags; + WORD memory_size; + BYTE rpl_ec[8]; + WORD adapter_id; + BYTE adapter_ec[10]; + DWORD file_hdr; + BYTE file_name[1]; +} FIND_FRAME, *PFIND_FRAME; + +#define FIND_LEN 0x53 + +// +// The following structure defines the FOUND frame, +// RMT2 transmits the FOUND frame in response to a FIND +// frame from a workstation already configured to RIPL. +// + +typedef struct _FOUND_FRAME { + WORD program_length; + WORD program_command; + DWORD corr_header; + DWORD correlator; + DWORD resp_hdr; + BYTE resp_code; + DWORD dest_hdr; // NOTE 4 bytes! not 6 + BYTE dest_addr[ NODE_ADDRESS_LENGTH]; + DWORD source_hdr; + BYTE source_addr[ NODE_ADDRESS_LENGTH]; + DWORD info_hdr; + DWORD frame_hdr; + WORD max_frame; + DWORD class_hdr; + WORD conn_class; + DWORD lsap_hdr; + BYTE rsap; +} FOUND_FRAME, *PFOUND_FRAME; + + +// +// +// The fdr structure defines the FILE.DATA.RESPONSE frame transmitted by RMT2 +// in response to a validated SEND.FILE.DATA frame already received by RMT2. +// + + +typedef struct _FDR { // FILE.DATA.RESPONSE + WORD program_length; + WORD program_command; + DWORD seq_hdr; + DWORD seq_num; + DWORD loader_hdr; + DWORD locate_addr; + DWORD xfer_addr; + BYTE flags; + DWORD data_hdr; // the data follows this +} FDR, *PFDR; + + +// +// The sfr structure defines the SEND.FILE.REQUEST frame transmitted by +// the remote workstation after reception of the FOUND frame. +// + +typedef struct _SFR { // SEND.FILE.REQUEST + WORD program_length; + WORD program_command; + DWORD seq_header; // sequence number vector + DWORD seq_num; // starting sequence number + DWORD info_hdr; + DWORD frame_hdr; + WORD max_frame; + DWORD class_hdr; + WORD conn_class; + DWORD source_hdr; + BYTE source_addr[ NODE_ADDRESS_LENGTH]; + DWORD lsap_hdr; + BYTE rsap; + DWORD search_hdr; + DWORD loader_hdr; + BYTE mach_conf[8]; + WORD equip_flags; +} SFR, *PSFR; + +#include <packoff.h> // Restore default packing, #pragma pack() + +// +// The following structure defines the Receive frame from a requesting +// device seeking a RIPL server. The find_frame occupies the second +// half of the structure (or the SEND.FILE.REQUEST frame, or ALERT frame). +// The only field used by RMT2 to determine the +// frame type is the "program_command" field of the frame. +// + + +typedef struct _RCVBUF { + LLC_NOT_CONTIGUOUS_BUFFER b; // buffer one header + union { + FIND_FRAME Find; // the data (find frame) + SFR SendFileRequest; // or a SEND.FILE.REQUEST + } u; +} RCVBUF, *PRCVBUF; + + +#define RCB_ALERT 0xff // rcb was alerted +#define RCB_ALERTED 0x1 // bit set for ALERT frame +#define RCB_ERROR 0x1 // bit for tx-rx error + +// +// The following #defines relate to the values of the program_command +// field in the frame structures above +// + +#define FIND_CMD 0x0100 // FIND frame +#define SEND_CMD 0x1000 // SEND command +#define FDR_CMD 0x2000 // FILE.DATA.RESPONSE cmd +#define ALERT_CMD 0x3000 // ALERT frame +#define FOUND_CMD 0x0200 // FOUND frame + +// +// The following #defines relate the the values of various fields in +// the FOUND frame structure. +// + +#define OVRHD 123 // overhead on a FOUND frame +#define CLASS1 0x100 // class 1 provided by RJS +#define FL 0x3A00 // sizeof found frame +#define CORR_HDR 0x03400800 // NOT intel format +#define RESP_HDR 0x0b400500 // ditto +#define DEST_HDR 0x0c400a00 // ditto +#define SOURCE_HDR 0x06400a00 // ditto +#define INFO_HDR 0x08001000 // NOT intel format +#define FRAME_HDR 0x09400600 // LAN format +#define CLASS_HDR 0x0a400600 // LAN format +#define LSAP_HDR 0x07400500 // LAN format +#define BRDCST 0x82 // routing for broadcast +#define UNSPEC_FRM_SIZE 0x70 // (DFFF rrrr) FFF frm size bits ON +#define SEQ_HDR 0x11400800 +#define LDR_HDR 0x14c00d00 +#define DATA_HDR 0x18400000 +#define MAXRETRY 5 // retry TRANSMIT this much + +// +// We do not write to Net error log until there is at least +// MAX_CONSECUTIVE_ERROR transmit errors. +// +#define MAX_CONSECUTIVE_ERROR 3 + +// Definitions for volume_id handling +#define MAX_VOLID_LEN 17 +#define VOLID_FIELD1 0xFF +#define VOLID_FIELD2 0xB0 + + +// +// Routines exported by report.c +// +VOID RplDlcReportEvent( + DWORD ErrorCode, + DWORD Command + ); + +// +// Routines exported by buffer.c +// +BOOL RplDlcBufferFree( + BYTE free_type, + PADAPTER_INFO pAdapterInfo + ); + +VOID ReverseBits( PBYTE NodeAddress ); diff --git a/private/net/svcdlls/rpl/dll/makefile b/private/net/svcdlls/rpl/dll/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/rpl/dll/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/dll/report.c b/private/net/svcdlls/rpl/dll/report.c new file mode 100644 index 000000000..3eb7520e2 --- /dev/null +++ b/private/net/svcdlls/rpl/dll/report.c @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + report.c + +Abstract: + + Event log writing function used in rpl "dll". + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + +--*/ + +#include "local.h" +#include <jet.h> // need to include because rpllib.h depends on JET +#include <rpllib.h> // RplReportEvent() + +VOID RplDlcReportEvent( + DWORD ErrorCode, + DWORD Command + ) +/*++ + +Routine Description: + Composes an error message and writes it to a LAN Manager error log file. + +Arguments: + ErrorCode actual error code + command failed Dos- or ACSLAN command + +Return Value: + None. + +--*/ +{ + DWORD RawDataBuffer[ 2]; + + RawDataBuffer[ 0] = Command; // dlc command or internal rpl command + RawDataBuffer[ 1] = ErrorCode; // dlc error code or win32 error code + + RplReportEvent( + NELOG_System_Error, + NULL, + sizeof( RawDataBuffer), + (PBYTE)RawDataBuffer + ); +} + + + diff --git a/private/net/svcdlls/rpl/dll/sfr.c b/private/net/svcdlls/rpl/dll/sfr.c new file mode 100644 index 000000000..0084f297c --- /dev/null +++ b/private/net/svcdlls/rpl/dll/sfr.c @@ -0,0 +1,499 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + sfr.c + +Abstract: + + Contains RplDlcSfr() entry point. + Contains RplFindRcb() function which is also used by server\request.c\RequestThread(). + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + +--*/ + +#include "local.h" + + +VOID SfrReceiveThread( PADAPTER_INFO pAdapterInfo) +/*++ + +Routine Description: + + Created from RplDlcSfr(). Keeps RECEIVE posted on LOAD_SAP. + Received data is read by RpldSendFileRequest() function using AcsLan + READ command. The RECEIVE call will complete if ... + +--*/ +{ + PLLC_CCB pBadCcb; + DWORD status; + BYTE command; // failed command + + RplDump( RG_DebugLevel & RPL_DEBUG_SFR, ( + "++SfrReceiveThread: pAdapterInfo=0x%x", pAdapterInfo)); + + memset( (PVOID)&pAdapterInfo->u2, '\0', sizeof(pAdapterInfo->u2)); + pAdapterInfo->u2.r.uchAdapterNumber = pAdapterInfo->adapter_number; + pAdapterInfo->u2.r.uchDlcCommand = LLC_RECEIVE; + pAdapterInfo->u2.r.hCompletionEvent = pAdapterInfo->sfrsem; + pAdapterInfo->u2.r.u.pParameterTable = (PLLC_PARMS)&pAdapterInfo->u2.r1; + pAdapterInfo->u2.r1.ulReceiveFlag = COMPLETE_BY_READ; + pAdapterInfo->u2.r1.usStationId = pAdapterInfo->loadsid; + + for ( ; ;) { + status = AcsLan(&pAdapterInfo->u2.r, &pBadCcb); + if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + command = LLC_RECEIVE; + break; + } + // + // Waiting for SEND.FILE.REQUEST + // + status = WaitForSingleObject( pAdapterInfo->sfrsem, INFINITE); + if ( status != WAIT_OBJECT_0) { + if ( status == WAIT_FAILED) { + status = GetLastError(); + } + command = SEM_WAIT; + break; + } + if ( pAdapterInfo->u2.r.uchDlcStatus + != LLC_STATUS_LOST_DATA_NO_BUFFERS + && pAdapterInfo->u2.r.uchDlcStatus + != LLC_STATUS_LOST_DATA_INADEQUATE_SPACE) { + status = pAdapterInfo->u2.r.uchDlcStatus; + command = LLC_RECEIVE; + break; + } + } + + if ( pAdapterInfo->Closing == TRUE) { + RplDump( RG_DebugLevel & RPL_DEBUG_SFR, ( + "--SfrReceiveThread: pAdapterInfo=0x%x", pAdapterInfo)); + return; + } + + RplDump( ++RG_Assert,( "status=%d, command=0x%x", status, command)); + + // + // We come here in case of unrecoverable errors. RPL service will + // be terminated. We also set getdata_sem event to unblock + // RpldSendFileRequest() thread. + // + RplDlcReportEvent( status, command); + pAdapterInfo->SfrReturn = TRUE; + (VOID)SetEvent( pAdapterInfo->getdata_sem); +} + + +VOID set_fdr_fixed( + PLAN_RESOURCE pLanResource, + WORD usStationId + ) +/*++ +Routine Description: + set_fdr_fixed() initializes the fixed parts of the FILE.DATA.RESPONSE + frame and the TRANSMIT.UI parameter block. It takes a pointer to the + LAN RCB containing the frame and transmit parameters to be initialized + and usStationId for architected FIND SAP. +--*/ + +{ + PFDR pFdr; // point to frame + LLC_TRANSMIT_PARMS *tpp; // point to xmit parms + + pFdr = (PFDR)pLanResource->frame; // generate frame here + tpp = &pLanResource->TransmitParms; // locate xmit parms + // setup fixed part of frame + // program length varies + pFdr->program_command = FDR_CMD; // 00 20 + pFdr->seq_hdr = SEQ_HDR; // 00 08 40 11 + // seq num varies + pFdr->loader_hdr = LDR_HDR; // 00 0d c0 14 + pFdr->locate_addr = 0; // 00 00 00 00 + pFdr->xfer_addr = 0; // 00 00 00 00 + pFdr->flags = 0; // flags zero = no FDR ack + // data_hdr varies + pFdr->data_hdr = DATA_HDR; // 00 ?? 40 18 + // setup transmit parm block + tpp->usStationId = usStationId; + tpp->uchTransmitFs = 0; // 00 + tpp->uchRemoteSap = FIND_SAP; // FC + // Queue #1 is 1st buffer + tpp->pXmitQueue1 = (PLLC_XMIT_BUFFER)&pLanResource->XmitBuffer; + tpp->pXmitQueue2 = NULL; // 00 00 00 00 + tpp->cbBuffer1 = (sizeof *pFdr); // 00 1D + tpp->pBuffer1 = (PCH)pLanResource->frame; + tpp->uchXmitReadOption = DLC_DO_NOT_CHAIN_XMIT; // don't chain on completion +} + + +VOID ProcessSfr( + PRCB pRcb, + PADAPTER_INFO pAdapterInfo, + PRCVBUF pRcvbuf + ) +{ + + PLAN_RESOURCE pLanResource; + WORD tempword; + + pLanResource = (PLAN_RESOURCE)pRcb->lan_rcb_ptr; + pLanResource->retry_count = 0; + tempword = HILO(pRcvbuf->u.SendFileRequest.max_frame); + // + // Both protocol data and boot block data must fit in + // transmit buffer frame (OVRHD == size of protocol data). + // + if (tempword <= pAdapterInfo->max_xmit_buff_size) { + tempword -= OVRHD; + } else { + tempword = (WORD)( pAdapterInfo->max_xmit_buff_size - OVRHD); + } + + // + // "max_frame" is used by rpl server to determine the size of boot + // block data frames. + // + pRcb->max_frame = tempword; + + memcpy( pLanResource->LanHeader.dest_addr, + &(pRcvbuf->b.auchLanHeader[ 8]), NODE_ADDRESS_LENGTH); + + // mask off routing info indication bit + pLanResource->LanHeader.dest_addr[0] &= 0x7F; + // note: byte to word xlate + pLanResource->XmitBuffer.cbBuffer = pRcvbuf->b.cbLanHeader; + + + if (pAdapterInfo->network_type == RPL_ADAPTER_TOKEN_RING) { + if ( pRcvbuf->b.cbLanHeader > 14) { + // + // There is routing info, we have TokenRing case. Inherit + // the routing from received frame. Note memcpy length! Also, + // we "and" with 0x1f for "non broadcast" and "xor" with 0x80 + // for "direction interpreted from right to left". + // + memcpy( pLanResource->LanHeader.routing_info_header, + &pRcvbuf->b.auchLanHeader[14], pRcvbuf->b.cbLanHeader -14); + pLanResource->LanHeader.routing_info_header[0] &= 0x1f; + pLanResource->LanHeader.routing_info_header[1] ^= 0x80; + } else { + // + // There is no routing info, we have Etherner case. We just + // clear the indication bit. + // + pLanResource->LanHeader.source_addr[0] &= 0x7f; + } + } + + // set FILE.DATA.RESPONSE + set_fdr_fixed( pLanResource, pAdapterInfo->findsid); +} + + +PRCB RplFindRcb( + PPRCB HeadRcbList, + PBYTE NodeAddress + ) +/*++ +Routine Description: + + Finds matching rcb from rcbs in use chain. + +Arguments: + HeadRcbList pointer to the variable, which contains pointer to the + first RCB in chain + NodeAddress pointer to the hex adapter-id to scan for + +Return Value: + Pointer to matching RCB if success, NULL otherwise. + +--*/ +{ + PRCB pRcb; + + DebugCheckList( HeadRcbList, NULL, 0); + + for ( pRcb = *HeadRcbList; pRcb != NULL; pRcb = pRcb->next_rcb) { + if ( !memcmp( pRcb->NodeAddress, NodeAddress, + sizeof( pRcb->NodeAddress) )) { + break; + } + } + return( pRcb); + +} + + +BOOL RplDlcSfr( + POPEN_INFO pOpenInfo, + PPRCB HeadRcbList, + PCRITICAL_SECTION ProtectRcbList + ) +/*++ + +Routine Description: + Receives SEND.FILE.REQUEST frames. Creates a thread to keep a receive + command outstanding on the opened LOAD_SAP in order to pick up + SEND.FILE.REQUEST frames from workstations. Uses AcsLan READ-function + to get notification for received data. + + It validates the frame and places the requested sequence number, + lan header, transmit buffer header and parameters into the RCB + associated with the workstation and clears RAM semaphore (in RCB) + to wake up the service thread for the workstation. + It then frees the buffer containing the frame and waits for the next one. + +Arguments: + pOpenInfo pointer to the OPEN_INFO structure + HeadRcbList pointer to the variable, which contains pointer to the + first RCB in chain. The chain contains RCB-s of all clients this + server is interested in getting SEND.FILE.REQUEST frames from. + ProtectRcbList for serialising access to rcb list + +Return Value: + ERROR_SUCCESS if success, non-zero otherwise +--*/ +{ + DWORD status; + PLLC_CCB pBadCcb; + PRCB pRcb; + PRCVBUF pRcvbuf; + DWORD sfr_seq_number; // in the incoming SFR frame + DWORD fdr_seq_number; // of what worker already sent + PADAPTER_INFO pAdapterInfo; + DWORD ThreadId; + + pAdapterInfo = (PADAPTER_INFO)pOpenInfo->adapt_info_ptr; + + RplDump( RG_DebugLevel & RPL_DEBUG_SFR, ( + "++SendFileRequest: pAdapterInfo=0x%x", pAdapterInfo)); + + // + // Create thread to keep receive posted. + // + pAdapterInfo->SfrReceiveThreadHandle = CreateThread( + NULL, // lpThreadAttribute + 0, // dwStackSize - same as first thread + (LPTHREAD_START_ROUTINE)SfrReceiveThread, // lpStartAddress + (LPVOID)pAdapterInfo, // lpParameter + 0, // dwCreationFlags + &ThreadId // lpThreadId + ); + if ( pAdapterInfo->SfrReceiveThreadHandle == NULL) { + status = GetLastError(); + RplDump( ++RG_Assert,( "pAdapterInfo=0x%x, status=%d", pAdapterInfo, status)); + RplDlcReportEvent( status, THREAD_CREATE); + return( FALSE); + } + + // + // Setup CCB for LLC_READ, then setup LLC_READ_PARMS to wake up + // only when data arrives. + // + memset( (PVOID)&pAdapterInfo->u3, '\0', sizeof(pAdapterInfo->u3)); + pAdapterInfo->u3.r.uchAdapterNumber = pAdapterInfo->adapter_number; + pAdapterInfo->u3.r.uchDlcCommand = LLC_READ; + pAdapterInfo->u3.r.hCompletionEvent = pAdapterInfo->getdata_sem; + pAdapterInfo->u3.r.u.pParameterTable = (PLLC_PARMS)&pAdapterInfo->u3.r1; + + pAdapterInfo->u3.r1.usStationId = pAdapterInfo->loadsid; + pAdapterInfo->u3.r1.uchOptionIndicator = LLC_OPTION_READ_SAP; + pAdapterInfo->u3.r1.uchEventSet = LLC_EVENT_RECEIVE_DATA; + + // + // Loop for ever processing SendFileRequest frames arriving to this + // adapter. + // + for ( ; ;) { + + // + // Reset event to be cleared later on by AcsLan. + // + if ( !ResetEvent( pAdapterInfo->getdata_sem)) { + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + status = GetLastError(); + RplDump( ++RG_Assert,( "pAdapterInfo=0x%x, status=%d", pAdapterInfo, status)); + RplDlcReportEvent( status, SEM_SET); + return( FALSE); + } + + status = AcsLan( &pAdapterInfo->u3.r, &pBadCcb); + if ( pAdapterInfo->Closing == TRUE) { + (VOID)SetEvent( pAdapterInfo->getdata_sem); + return( FALSE); + } + + if (status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + RplDump( ++RG_Assert,( " r=0x%x, status=%d", &pAdapterInfo->u3.r, status)); + RplDlcReportEvent( status, LLC_READ); // failed to READ + (VOID)SetEvent( pAdapterInfo->getdata_sem); + return( FALSE); + } + + status = WaitForSingleObject( pAdapterInfo->getdata_sem, INFINITE); + if ( pAdapterInfo->Closing == TRUE) { + return( FALSE); + } + + if ( ( status != WAIT_OBJECT_0) || (pAdapterInfo->u3.r.uchDlcStatus)) { + if ( status != WAIT_OBJECT_0) { + if ( status == WAIT_FAILED) { + status = GetLastError(); + } + RplDlcReportEvent( status, SEM_WAIT); + } else { + RplDlcReportEvent( pAdapterInfo->u3.r.uchDlcStatus, LLC_READ); + } + RplDump( ++RG_Assert,( " pAdapterInfo=0x%x, status=%d, DlcStatus=0x%x", + pAdapterInfo, status, pAdapterInfo->u3.r.uchDlcStatus)); + return( FALSE); + } + + if ( pAdapterInfo->SfrReturn) { // Check sfr receive + // + // SfrReceiveThreadHandle is being waited in DlcTerm() call. + // + return( TRUE); // event was written by sfr receive + } + + // + // Point to receive buffer. + // + pRcvbuf = (PRCVBUF)(pAdapterInfo->u3.r1.Type.Event.pReceivedFrame); + RplDump( TRUE, ("pRcvbuf=0x%x", pRcvbuf)); + + + // + // Whenever we find a matching RCB we set SFR flag so that worker + // thread does not move this RCB while we are working on it. Note + // that this means that SFR must be cleared once we are done with + // this RCB. + // + + EnterCriticalSection( ProtectRcbList); + + pRcb = RplFindRcb( HeadRcbList, (PBYTE)pRcvbuf->u.SendFileRequest.source_addr); + if ( pRcb != NULL) { + if ( pRcb->Pending == TRUE) { + pRcb = NULL; // pretend we did not see this RCB + } else { + pRcb->SFR = TRUE; // hold this RCB + } + } + + LeaveCriticalSection( ProtectRcbList); + + if ( pRcb == NULL + || pRcvbuf->u.SendFileRequest.program_command == ALERT_CMD + || pRcvbuf->u.SendFileRequest.program_command != SEND_CMD + || pRcvbuf->u.SendFileRequest.conn_class != CLASS1) { + // + // Calling adapter was not found, or we received an alert frame, + // or we received an unknown frame, or request class was wrong. + // + + if ( pRcb != NULL && status == 0 + && pRcvbuf->u.SendFileRequest.program_command == ALERT_CMD) { + // + // Got an alert frame on LOAD_SAP and RCB is found. + // + pRcb->flags.alerted = RCB_ALERTED;// yes: signal + // + // Instead of ACK or rexmit request, we have Alert frame. + // Wake up worker. + // + if ( !SetEvent( pRcb->SF_wakeup)) { + RplDump( ++RG_Assert,("pRcb=0x%x error=%d", pRcb, GetLastError())); + } + } + if ( pRcb != NULL) { + pRcb->SFR = FALSE; // release RCB + } + if ( !RplDlcBufferFree( SFR_FREE, pAdapterInfo)) { + return( FALSE); + } + continue; + } + + // + // Get SFR sequence number (in intel format) & validate it. + // + sfr_seq_number = HILO2(pRcvbuf->u.SendFileRequest.seq_num); + fdr_seq_number = pRcb->fdr_seq_number; + if ( sfr_seq_number > fdr_seq_number + 1) { + RplDump( ++RG_Assert, ( + "pRcb=0x%x, sfr_seq_number=%d, fdr_seq_number=%d", + pRcb, sfr_seq_number, fdr_seq_number)); + pRcb->SFR = FALSE; // release RCB + if ( !RplDlcBufferFree( SFR_FREE, pAdapterInfo)) { + return( FALSE); + } + continue; + } + + // + // We received a meaningful SFR frame. Initialize data if this is + // the first SFR frame. Then update clients sequence number & unblock + // worker thread. + // + + if ( pRcb->ReceivedSfr == FALSE) { + pRcb->ReceivedSfr = TRUE; + ProcessSfr( pRcb, pAdapterInfo, pRcvbuf); + } + pRcb->sfr_seq_number = sfr_seq_number; + + if ( !SetEvent( pRcb->SF_wakeup)) { + RplDump( ++RG_Assert,( "pRcb=0x%x error=%d", pRcb, GetLastError())); + } + + pRcb->SFR = FALSE; // release RCB + + if ( !RplDlcBufferFree( SFR_FREE, pAdapterInfo)) { + return( FALSE); + } + } // end of big loop +} + + +#ifdef RPL_DEBUG +VOID DebugCheckList( PPRCB HeadList, PRCB pInputRcb, DWORD Operation) +{ + PRCB pRcb; + DWORD count; + DWORD found; + + for ( pRcb = *HeadList, count = 0, found = FALSE; pRcb != NULL; + pRcb = pRcb->next_rcb, count++) { + if ( count > 20) { + RplDump( ++RG_Assert,("Circular list")); + } + if ( pRcb == pInputRcb) { + found = TRUE; + } + } + if ( pInputRcb != NULL) { + if ( Operation == RPL_MUST_FIND && found == FALSE) { + RplDump( ++RG_Assert,("Element not present")); + } else if ( Operation == RPL_MUST_NOT_FIND && found == TRUE) { + RplDump( ++RG_Assert,("Element already present")); + } + } +} +#endif + diff --git a/private/net/svcdlls/rpl/dll/sizeof.c b/private/net/svcdlls/rpl/dll/sizeof.c new file mode 100644 index 000000000..501dba2cf --- /dev/null +++ b/private/net/svcdlls/rpl/dll/sizeof.c @@ -0,0 +1,174 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + sizeof.c + +Abstract: + + Prints offsets of more commonly used fields in RPL data structures. + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Created + +--*/ + +#include "local.h" +#include <ntcsrsrv.h> +#include <stdio.h> + +typedef struct _HEAP_ENTRY { + // + // This field gives the size of the current block in allocation + // granularity units. (i.e. Size << HEAP_GRANULARITY_SHIFT + // equals the size in bytes). + // + + USHORT Size; + + // + // This field gives the size of the previous block in allocation + // granularity units. (i.e. PreviousSize << HEAP_GRANULARITY_SHIFT + // equals the size of the previous block in bytes). + // + + USHORT PreviousSize; + + // + // This field contains the index into the segment that controls + // the memory for this block. + // + + UCHAR SegmentIndex; + + // + // This field contains various flag bits associated with this block. + // Currently these are: + // + // 0x01 - block is busy + // 0x02 - allocated with VirtualAlloc + // 0x04 - busy block contains tail fill/free block contains free fill + // 0x08 - last block before uncommitted memory + // 0x10 - caller settable + // 0x20 - caller settable + // 0x40 - caller settable + // 0x80 - caller settable + // + // The high order 4 bits are settable by higher level heap interfaces. + // For example, the Win32 heap calls remember the DDESHARE and DISCARDABLE + // flags here. The pool manager remembers the pool type here. + // + + UCHAR Flags; + + // + // This field is for debugging purposes. It will normally contain a + // stack back trace index of the allocator for x86 systems. + // + + union { + USHORT AllocatorBackTraceIndex; + struct { + UCHAR Index; + UCHAR Mask; + } FreeListBitIndex; + } u0; + + // + // Format of the remaining fields depends on whether this is an + // busy or free block. + // + + union { + struct { + // + // This field contains the number of unused bytes at the end of this + // block that were not actually allocated. Used to compute exact + // size requested prior to rounding requested size to allocation + // granularity. Also used for tail checking purposes. + // + + ULONG UnusedBytes : 8; + + // + // This field is currently unused, but is intended for storing + // any encoded value that will give the that gives the type of object + // allocated. + // + + ULONG Type : 24; + + // + // This field is a 32-bit settable value that a higher level heap package + // can use. The Win32 heap manager stores handle values in this field. + // + + ULONG Settable; + } BusyBlock; + + struct { + // + // Free blocks use these two words for linking together free blocks + // of the same size on a doubly linked list. + // + LIST_ENTRY FreeList; + } FreeBlock; + } u; + +} HEAP_ENTRY, *PHEAP_ENTRY; + +void _CRTAPI1 main( void) { + printf("FIELD_OFFSET( RCVBUF, u.SendFileRequest.seq_num) == %d == 0x%x\n", + FIELD_OFFSET( RCVBUF, u.SendFileRequest.seq_num), + FIELD_OFFSET( RCVBUF, u.SendFileRequest.seq_num)); + + printf("FIELD_OFFSET( OPEN_INFO, adapt_info_ptr) == %d == 0x%x\n", + FIELD_OFFSET( OPEN_INFO, adapt_info_ptr), + FIELD_OFFSET( OPEN_INFO, adapt_info_ptr)); + + printf("sizeof( ADAPTER_INFO) == %d == 0x%x\n", + sizeof( ADAPTER_INFO), + sizeof( ADAPTER_INFO)); + printf("FIELD_OFFSET( ADAPTER_INFO, u1.r1.pFirstBuffer) == %d == 0x%x\n", + FIELD_OFFSET( ADAPTER_INFO, u1.r1.pFirstBuffer), + FIELD_OFFSET( ADAPTER_INFO, u1.r1.pFirstBuffer)); + printf("FIELD_OFFSET( ADAPTER_INFO, u3.r1.Type.Event.pReceivedFrame) == %d == 0x%x\n", + FIELD_OFFSET( ADAPTER_INFO, u3.r1.Type.Event.pReceivedFrame), + FIELD_OFFSET( ADAPTER_INFO, u3.r1.Type.Event.pReceivedFrame)); + + + printf("FIELD_OFFSET( FIND_FRAME, source_addr) == %d == 0x%x\n", + FIELD_OFFSET( FIND_FRAME, source_addr), + FIELD_OFFSET( FIND_FRAME, source_addr)); + + printf("FIELD_OFFSET( RCB, AdapterName) == %d == 0x%x\n", + FIELD_OFFSET( RCB, AdapterName), + FIELD_OFFSET( RCB, AdapterName)); + printf("FIELD_OFFSET( RCB, lan_rcb_ptr) == %d == 0x%x\n", + FIELD_OFFSET( RCB, lan_rcb_ptr), + FIELD_OFFSET( RCB, lan_rcb_ptr)); + + printf("FIELD_OFFSET( LLC_NOT_CONTIGUOUS_BUFFER, auchLanHeader) == %d == 0x%x\n", + FIELD_OFFSET( LLC_NOT_CONTIGUOUS_BUFFER, auchLanHeader), + FIELD_OFFSET( LLC_NOT_CONTIGUOUS_BUFFER, auchLanHeader)); + + printf("FIELD_OFFSET( LLC_CCB, u.pParameterTable) == %d == 0x%x\n", + FIELD_OFFSET( LLC_CCB, u.pParameterTable), + FIELD_OFFSET( LLC_CCB, u.pParameterTable)); + + printf("FIELD_OFFSET( CSR_PROCESS, ProcessHandle) == %d == 0x%x\n", + FIELD_OFFSET( CSR_PROCESS, ProcessHandle), + FIELD_OFFSET( CSR_PROCESS, ProcessHandle)); + + printf("sizeof( HEAP_ENTRY) == %d == 0x%x\n", + sizeof( HEAP_ENTRY), + sizeof( HEAP_ENTRY)); +} diff --git a/private/net/svcdlls/rpl/dll/sources b/private/net/svcdlls/rpl/dll/sources new file mode 100644 index 000000000..f79e2d95d --- /dev/null +++ b/private/net/svcdlls/rpl/dll/sources @@ -0,0 +1,37 @@ +MAJORCOMP=net +MINORCOMP=rplnet + +TARGETPATH=obj +TARGETNAME=rplnet +TARGETTYPE=LIBRARY + +TARGETLIBS= \ + $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\kernel32.lib \ + $(BASEDIR)\public\sdk\lib\*\advapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \ + $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib + +INCLUDES=.;..\inc;..\..\..\inc;..\..\..\api;..\..\..\..\inc; + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + init.c \ + ether.c \ + emulator.c \ + buffer.c \ + fdr.c \ + find.c \ + found.c \ + sfr.c \ + report.c + +USE_CRTDLL=1 +C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 + +UMTYPE=console +UMTEST=sizeof +UMLIBS= \ + $(BASEDIR)\Public\Sdk\Lib\*\dlcapi.lib + diff --git a/private/net/svcdlls/rpl/dll/xns.c b/private/net/svcdlls/rpl/dll/xns.c new file mode 100644 index 000000000..e0b878e20 --- /dev/null +++ b/private/net/svcdlls/rpl/dll/xns.c @@ -0,0 +1,520 @@ +/*++ + +Copyright (c) 1987-93 Microsoft Corporation + +Module Name: + + xns.c + +Abstract: + + Test program to help debug DIR_OPEN_DIRECT path in DLC driver & RPL service. + +Author: + + Vladimir Z. Vulovic (vladimv) 03 - February - 1993 + +Revision History: + + 03-Feb-1993 vladimv + Ported to NT + +--*/ + +#include "local.h" +#define PRINTF( _args) printf _args + +// +// ripl_rom[] is the x86 code we send to ETHERSTART clients. Currently it +// is exactly 0x429 bytes long. +// +BYTE ripl_rom[] = { +0xFA,0xB8,0x90,0x00,0xBC,0x00,0x02,0x8E,0xD0,0xCD,0x12,0x86,0xC4,0x86,0xC4,0xB1, +0x06,0xD3,0xE0,0x8D,0x0E,0x3C,0x0B,0x83,0xC1,0x0F,0x51,0xD1,0xE9,0xD1,0xE9,0xD1, +0xE9,0xD1,0xE9,0x2B,0xC1,0x59,0x8E,0xC0,0x8D,0x36,0x39,0x01,0x8B,0xFE,0x2B,0xCE, +0xE8,0x3B,0x02,0x50,0xB8,0x39,0x01,0x50,0xCB,0x0E,0x1F,0xB4,0xFB,0xB2,0x80,0x8D, +0x1E,0x5F,0x04,0xCD,0x13,0x8B,0xF3,0x8D,0x3E,0x8A,0x04,0xA5,0xA5,0xA5,0x8B,0xF3, +0x8D,0x3E,0xC7,0x04,0xA5,0xA5,0xA5,0x8B,0xF3,0x8D,0x3E,0xF2,0x04,0xA5,0xA5,0xA5, +0xB4,0x03,0x32,0xFF,0xCD,0x10,0x32,0xD2,0x01,0x16,0xED,0x03,0x01,0x16,0x22,0x04, +0x01,0x16,0x57,0x04,0xBE,0xC3,0x03,0x8B,0x16,0xED,0x03,0xBB,0x24,0x00,0x90,0xE8, +0x0B,0x02,0xA1,0xED,0x03,0x05,0x24,0x00,0x90,0xA3,0xED,0x03,0xBE,0xE7,0x03,0x8B, +0x16,0xED,0x03,0xBB,0x06,0x00,0x90,0xE8,0xF3,0x01,0xBE,0x68,0x00,0x90,0x8D,0x1E, +0x59,0x04,0xE8,0xDA,0x01,0xBE,0xBE,0x05,0x8D,0x1E,0x2B,0x05,0xE8,0xD7,0x01,0x73, +0x13,0x0B,0xC0,0x74,0x03,0xE9,0x8D,0x00,0xBE,0xE7,0x03,0xBB,0x06,0x00,0x90,0xE8, +0xE3,0x01,0xEB,0xC8,0x8D,0x36,0x5B,0x05,0x8D,0x3E,0xC1,0x04,0xA5,0xA5,0xA5,0xBE, +0xEF,0x03,0x8B,0x16,0x22,0x04,0xBB,0x2F,0x00,0x90,0xE8,0xB0,0x01,0xBE,0x24,0x04, +0x8B,0x16,0x57,0x04,0xBB,0x2D,0x00,0x90,0xE8,0xA2,0x01,0xA1,0x22,0x04,0x05,0x2F, +0x00,0x90,0xA3,0x22,0x04,0xA1,0x57,0x04,0x05,0x2D,0x00,0x90,0xA3,0x57,0x04,0xB9, +0x50,0x00,0xBE,0x1E,0x04,0x8B,0x16,0x22,0x04,0xBB,0x04,0x00,0x90,0xE8,0x7D,0x01, +0xBE,0x68,0x00,0x90,0x8D,0x1E,0xC1,0x04,0xE8,0x64,0x01,0xBE,0x51,0x04,0x8B,0x16, +0x57,0x04,0xBB,0x06,0x00,0x90,0xE8,0x64,0x01,0xBE,0xBE,0x05,0x8D,0x1E,0x76,0x05, +0xE8,0x53,0x01,0x73,0x28,0x0B,0xC0,0x75,0x0C,0xBE,0x1E,0x04,0xBB,0x04,0x00,0x90, +0xE8,0x62,0x01,0xE2,0xBD,0xE8,0xF6,0x00,0xB8,0x40,0x00,0x8E,0xD8,0xC7,0x06,0x72, +0x00,0x34,0x12,0xEA,0x00,0x00,0xFF,0xFF,0xB9,0x50,0x00,0xEB,0xBE,0x80,0x3E,0x84, +0x05,0xFC,0x75,0xF4,0x81,0x3E,0x89,0x05,0x00,0x20,0x75,0xEC,0xA1,0xDC,0x04,0x39, +0x06,0x91,0x05,0x74,0x02,0xEB,0x88,0x8B,0x16,0xDA,0x04,0x39,0x16,0x8F,0x05,0x74, +0x03,0xE9,0x7B,0xFF,0x86,0xC4,0x86,0xD6,0x40,0x83,0xD2,0x00,0x86,0xC4,0x86,0xD6, +0xA3,0xDC,0x04,0x89,0x16,0xDA,0x04,0xBE,0x51,0x04,0xBB,0x06,0x00,0x90,0xE8,0x04, +0x01,0x8A,0x1E,0x9F,0x05,0xF6,0xC3,0x10,0x74,0x0D,0x53,0xBE,0x68,0x00,0x90,0x8D, +0x1E,0xC1,0x04,0xE8,0xC9,0x00,0x5B,0xF6,0xC3,0x20,0x74,0x10,0xA1,0x99,0x05,0x86, +0xE0,0xA3,0x34,0x0B,0xA1,0x97,0x05,0x86,0xE0,0xA3,0x36,0x0B,0x8B,0x0E,0xA0,0x05, +0x86,0xCD,0x83,0xE9,0x04,0x0B,0xC9,0x74,0x37,0x33,0xD2,0xA1,0x34,0x0B,0xBF,0x10, +0x00,0xF7,0xF7,0x8B,0xFA,0x03,0x06,0x36,0x0B,0x75,0x09,0x81,0xFA,0x00,0x0C,0x73, +0x03,0xE9,0x51,0xFF,0x03,0xD1,0x89,0x16,0x34,0x0B,0xA3,0x36,0x0B,0x3D,0x00,0xA0, +0x72,0x03,0xE9,0x40,0xFF,0x06,0x8E,0xC0,0x8D,0x36,0xA4,0x05,0xE8,0x5F,0x00,0x07, +0xF6,0xC3,0x80,0x75,0x03,0xE9,0x40,0xFF,0xA1,0x38,0x0B,0x8B,0x0E,0x3A,0x0B,0xF6, +0xC3,0x40,0x74,0x0B,0xA1,0x9D,0x05,0x86,0xC4,0x8B,0x0E,0x9B,0x05,0x86,0xCD,0x33, +0xD2,0xBB,0x10,0x00,0xF7,0xF3,0x03,0xC1,0x50,0x52,0xE8,0x01,0x00,0xCB,0x06,0x1E, +0x33,0xC0,0x8E,0xC0,0xB8,0x70,0x00,0x8E,0xD8,0xA1,0x02,0x00,0x26,0xA3,0x4C,0x00, +0xA1,0x04,0x00,0x26,0xA3,0x4E,0x00,0xA1,0x06,0x00,0x26,0xA3,0x64,0x00,0xA1,0x08, +0x00,0x26,0xA3,0x66,0x00,0x26,0xC6,0x06,0xD0,0x04,0x01,0x1F,0x07,0xC3,0xF7,0xC6, +0x01,0x00,0x74,0x01,0xA4,0xD1,0xE9,0x9C,0xF3,0xA5,0x9D,0x73,0x01,0xA4,0xC3,0xB4, +0xFE,0xB2,0x80,0xCD,0x13,0xC3,0xB4,0xFF,0xB2,0x80,0xCD,0x13,0xC3,0x50,0x51,0x53, +0x8B,0xCB,0x32,0xFF,0xB4,0x02,0xCD,0x10,0xAC,0x33,0xDB,0xB4,0x0E,0xCD,0x10,0xE2, +0xF7,0x5B,0x59,0x58,0xC3,0x50,0x51,0x8D,0x70,0xFF,0x8B,0xCB,0x8A,0x04,0x3C,0x39, +0x7C,0x0A,0xB0,0x30,0x88,0x04,0x4E,0xE2,0xF3,0xEB,0x05,0x90,0xFE,0xC0,0x88,0x04, +0x59,0x58,0xC3,0x53,0x65,0x61,0x72,0x63,0x68,0x69,0x6E,0x67,0x20,0x66,0x6F,0x72, +0x20,0x52,0x50,0x4C,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x2C,0x20,0x52,0x65,0x74, +0x72,0x69,0x65,0x73,0x20,0x3D,0x20,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x01,0x53, +0x65,0x6E,0x64,0x69,0x6E,0x67,0x20,0x46,0x69,0x6C,0x65,0x20,0x52,0x65,0x71,0x75, +0x65,0x73,0x74,0x73,0x20,0x74,0x6F,0x20,0x52,0x50,0x4C,0x20,0x53,0x65,0x72,0x76, +0x65,0x72,0x2C,0x20,0x52,0x65,0x74,0x72,0x69,0x65,0x73,0x20,0x3D,0x20,0x30,0x30, +0x30,0x30,0x00,0x03,0x57,0x61,0x69,0x74,0x69,0x6E,0x67,0x20,0x66,0x6F,0x72,0x20, +0x44,0x61,0x74,0x61,0x20,0x46,0x72,0x61,0x6D,0x65,0x20,0x77,0x69,0x74,0x68,0x20, +0x53,0x65,0x71,0x75,0x65,0x6E,0x63,0x65,0x20,0x4E,0x75,0x6D,0x62,0x65,0x72,0x3A, +0x20,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x04,0x03,0x00,0x02,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x5A,0xFC,0xFC,0x03,0x00,0x57,0x00,0x01,0x00,0x08, +0x40,0x03,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x08,0x00,0x06,0x40,0x09,0x05,0xBE, +0x00,0x06,0x40,0x0A,0x00,0x01,0x00,0x0A,0x40,0x06,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x05,0x40,0x07,0xFC,0x00,0x2C,0x00,0x04,0x00,0x24,0xC0,0x05,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x40, +0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5A,0xF8, +0xFC,0x03,0x00,0x57,0x00,0x10,0x00,0x08,0x40,0x11,0x00,0x00,0x00,0x00,0x00,0x10, +0x00,0x08,0x00,0x06,0x40,0x09,0x05,0xBE,0x00,0x06,0x40,0x0A,0x00,0x01,0x00,0x0A, +0x40,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x40,0x07,0xFC,0x00,0x2C,0x00, +0x04,0x00,0x24,0xC0,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x40,0x13}; +WORD sizeof_ripl_rom = sizeof( ripl_rom); // equal to 0x429 + +BYTE Swap[256] = +{ +0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, +0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, +0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, +0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, +0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, +0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, +0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, +0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, +0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, +0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, +0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, +0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, +0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, +0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, +0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, +0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +}; + +void ReverseBits( PBYTE NodeAddress) { + DWORD i; + static CHAR Hex[] = "0123456789ABCDEF"; + for ( i = 0; i < NODE_ADDRESS_LENGTH; i++) { + NodeAddress[ i] = Swap[ NodeAddress[ i] ]; + PRINTF(( "%c", Hex[ NodeAddress[i]>>4])); + PRINTF(( "%c", Hex[ NodeAddress[i] & 0x0F])); + } + PRINTF(( "\n")); +} + +HANDLE hCompletionEvent; +LLC_CCB Ccb; +PLLC_CCB pBadCcb; +PLLC_CCB pCcb; + +LLC_DIR_OPEN_ADAPTER_PARMS DirOpenAdapterParms; +LLC_ADAPTER_OPEN_PARMS AdapterOpenParms; +LLC_EXTENDED_ADAPTER_PARMS ExtendedAdapterParms; +LLC_DLC_PARMS DlcParms; + +LLC_BUFFER_CREATE_PARMS BufferCreate; +PVOID pBuffer; +DWORD cbBufferSize; + +LLC_DIR_STATUS_PARMS DirStatusParms; +LLC_DIR_OPEN_DIRECT_PARMS DirOpenDirectParms; +LLC_RECEIVE_PARMS ReceiveParms; + +LLC_TRANSMIT_PARMS TransmitParms; + +BOOL EtherAcsLan( VOID) +{ + DWORD Status; + + pCcb->hCompletionEvent = hCompletionEvent; + if ( !ResetEvent( pCcb->hCompletionEvent)) { + PRINTF(("EtherAcsLan: Reset(), Status=%d\n", GetLastError())); + return( FALSE); + } + Status = AcsLan( pCcb, &pBadCcb); + if ( Status != ACSLAN_STATUS_COMMAND_ACCEPTED) { + PRINTF(("EtherAcsLan: Acslan, Status=0x%x\n", Status)); + return( FALSE); + } + Status = WaitForSingleObject( pCcb->hCompletionEvent, INFINITE); + PRINTF(("EtherAcsLan: DlcCommand=0x%x\n", Ccb.uchDlcCommand)); + if ( Status != WAIT_OBJECT_0 || pCcb->uchDlcStatus) { + if ( Status == -1) { + Status = GetLastError(); + } + PRINTF(("EtherAcsLan: Acslan, Status=0x%x, DlcStatus=0x%x\n", Status, pCcb->uchDlcStatus)); + return( FALSE); + } + + // + // Due to a DLC bug "pNext" field is trashed even on success + // code path. Until the bug is fix we must reinstate NULL. + // + pCcb->pNext = NULL; + return( TRUE); +} + +BOOL RplDirCloseAdapter( VOID) { + (VOID)memset((PVOID)&Ccb, '\0', sizeof(Ccb)); + Ccb.uchDlcCommand = LLC_DIR_CLOSE_ADAPTER; + return( EtherAcsLan()); +} + +BOOL RplDirOpenAdapter( VOID) { + (VOID)memset((PVOID)&Ccb, '\0', sizeof(Ccb)); + Ccb.uchDlcCommand = LLC_DIR_OPEN_ADAPTER; + Ccb.u.pParameterTable = (PLLC_PARMS)&DirOpenAdapterParms; + DirOpenAdapterParms.pAdapterParms = &AdapterOpenParms; + DirOpenAdapterParms.pExtendedParms = &ExtendedAdapterParms; + ExtendedAdapterParms.pSecurityDescriptor = NULL; + // + // With LLC_ETHERNET_TYPE_DEFAULT rpl server on build 392 did not + // detect an 802.3 client FIND frame. + // +#define OLD_STUFF +#ifdef OLD_STUFF + // Old stuff + ExtendedAdapterParms.LlcEthernetType = LLC_ETHERNET_TYPE_802_3; +#else + // Antti's email + ExtendedAdapterParms.LlcEthernetType = LLC_ETHERNET_TYPE_DIX; +#endif + ExtendedAdapterParms.hBufferPool = NULL; // for first open + DirOpenAdapterParms.pDlcParms = &DlcParms; + return( EtherAcsLan()); +} + +BOOL RplBufferCreate( VOID) { + (VOID)memset((PVOID)&Ccb, '\0', sizeof(Ccb)); + Ccb.uchDlcCommand = LLC_BUFFER_CREATE; + Ccb.u.pParameterTable = (PLLC_PARMS)&BufferCreate; + BufferCreate.pBuffer = pBuffer; + BufferCreate.cbBufferSize = cbBufferSize; + BufferCreate.cbMinimumSizeThreshold = 0x2000; + return( EtherAcsLan()); +} + +BOOL RplDirStatus( VOID) { + USHORT network_type; + (VOID)memset((PVOID)&Ccb, '\0', sizeof(Ccb)); + Ccb.uchDlcCommand = LLC_DIR_STATUS; + Ccb.u.pParameterTable = (PLLC_PARMS)&DirStatusParms; + if ( !EtherAcsLan()) { + return( FALSE); + } + network_type = DirStatusParms.usAdapterType; + if ( network_type != RPL_ADAPTER_ETHERNET) { + PRINTF(( "network_type=0x%x\n", network_type)); + return( FALSE); + } + ReverseBits( DirStatusParms.auchNodeAddress); + return( TRUE); +} + +BOOL RplDirOpenDirect( VOID) { + (VOID)memset((PVOID)&Ccb, '\0', sizeof(Ccb)); + Ccb.uchDlcCommand = LLC_DIR_OPEN_DIRECT; + Ccb.uchAdapterNumber = 0; + Ccb.u.pParameterTable = (PLLC_PARMS)&DirOpenDirectParms; + memset((PCH)&DirOpenDirectParms, '\0', sizeof(DirOpenDirectParms)); + DirOpenDirectParms.usOpenOptions = LLC_DIRECT_OPTIONS_ALL_MACS; // BUGBUG ?? + DirOpenDirectParms.usEthernetType = 0x0600; // XNS identifier + DirOpenDirectParms.ulProtocolTypeMask = 0xFFFFFFFF; + DirOpenDirectParms.ulProtocolTypeMatch = 0x7200FFFF; + DirOpenDirectParms.usProtocolTypeOffset = 14; // where FFFF0072 of client begins + return( EtherAcsLan()); +} + +BOOL RplReceive( VOID) { + (VOID)memset( (PVOID)&Ccb, '\0', sizeof(Ccb)); + (VOID)memset( (PVOID)&ReceiveParms, '\0', sizeof(ReceiveParms)); + Ccb.uchDlcCommand = LLC_RECEIVE; + Ccb.u.pParameterTable = (PLLC_PARMS)&ReceiveParms; + ReceiveParms.usStationId = 0; // receive MAC & non-MAC frames + return( EtherAcsLan()); +} + + +// +// The following are XNS packet definitions used to crack EtherStart +// packets. +// + +#include <packon.h> // pack EtherStart structures + +struct sockaddr_ns { + DWORD net; + BYTE host[ NODE_ADDRESS_LENGTH]; + WORD socket; +}; + +#define ETHERSTART_SOCKET 0x0104 // After swapping bytes + +struct _IDP { + WORD chksum; + WORD len; + BYTE xport_cntl; + BYTE packet_type; + struct sockaddr_ns dest; + struct sockaddr_ns src; +}; + +#define XNS_NO_CHKSUM 0xffff // XNS checksum +#define PEX_TYPE 0x4 // packet exchange type + +struct _PEX { + DWORD pex_id; + WORD pex_client; +}; + +#define ETHERSERIES_CLIENT 0x0080 // After swapping bytes + +struct _ETHERSTART { + WORD ethershare_ver; + BYTE unit; + BYTE fill; + WORD block; + BYTE func; + BYTE error; + WORD bytes; +}; + +#define ETHERSHARE_VER 0 +#define FUNC_RESPONSE 0x80 +#define FUNC_READFILEREQ 0x20 +#define FUNC_READFILERESP (FUNC_READFILEREQ | FUNC_RESPONSE) + +typedef struct _ETHERSTART_REQ { // EtherStart Read File Request + struct _IDP idp; + struct _PEX pex; + struct _ETHERSTART es; + BYTE filename[64]; + WORD start; + WORD count; +} ETHERSTART_REQ; + +typedef struct _ETHERSTART_RESP { // EtherStart Read File Response + struct _IDP idp; + struct _PEX pex; + struct _ETHERSTART es; + BYTE data[0x200]; +} ETHERSTART_RESP; + + +PRCVBUF pRcvbuf; +ETHERSTART_REQ * EtherstartReq; +ETHERSTART_RESP EtherstartResp; +// +// When we use LAN_HEADER then destination address begins at offset +// 14 of XmitData, while source address begins at offset 20. +// However, DLC scrambles the data so that destination address begins +// at offset 0 (instead of 2) - while source address still begins at +// offset 6 - which is correct. LAN_HEADER_TOO is meant as yet another +// DLC workaround. +// +typedef struct _LAN_HEADER_TOO { + BYTE dest_addr[ NODE_ADDRESS_LENGTH]; // Destination address + BYTE source_addr[ NODE_ADDRESS_LENGTH]; // Source address + BYTE routing_info_header[2]; // Routing information hdr +} LAN_HEADER_TOO; + +struct { + XMIT_BUFFER XmitBuffer; // see comment for XMIT_BUFFER + LAN_HEADER_TOO LanHeader; // BUGBUG replaces LAN_HEADER +} XmitQueue; + +#include <packoff.h> // restore default packing (done with EtherStart structures) + +VOID RplCopy( PVOID destination, PVOID source, DWORD length) { + memcpy( destination, source, length); +} + + +BOOL RplSend( VOID) +{ + WORD Temp; + + (VOID)memset( (PVOID)&Ccb, '\0', sizeof(Ccb)); + Ccb.uchDlcCommand = LLC_TRANSMIT_DIR_FRAME; + + Ccb.u.pParameterTable = (PLLC_PARMS)&TransmitParms; + memset( (PVOID)&TransmitParms, '\0', sizeof(TransmitParms)); + TransmitParms.uchXmitReadOption = DLC_DO_NOT_CHAIN_XMIT; + + // + // Initialize XmitQueue which contains the first send buffer. + // + TransmitParms.pXmitQueue1 = (LLC_XMIT_BUFFER *)&XmitQueue; + memset( (PVOID)&XmitQueue, '\0', sizeof( XmitQueue.XmitBuffer)); + XmitQueue.XmitBuffer.cbBuffer = sizeof( XmitQueue.LanHeader); + // + // In case of a direct open auchLanHeader[] returned by DLC contains + // LAN_HEADER structure without physical control fields. For now + // we work around this DLC bug by using offset 6 instead of 8 as a + // source address offset in auchLanHeader[]. + // +#define RPLDLC_SOURCE_OFFSET 6 // BUGBUG not 8 due to dlc bug + RplCopy( XmitQueue.LanHeader.dest_addr, + (PBYTE)&pRcvbuf->b.auchLanHeader[ RPLDLC_SOURCE_OFFSET], + NODE_ADDRESS_LENGTH); + RplCopy( XmitQueue.LanHeader.source_addr, + DirStatusParms.auchNodeAddress, + NODE_ADDRESS_LENGTH); + // + // These two are important for token ring already. + // I was hoping they will set XNS identifier field itself. + // + XmitQueue.LanHeader.routing_info_header[0] = 0x06; + XmitQueue.LanHeader.routing_info_header[1] = 0x00; + + // + // Initialize EtherstartResp which contains the second & the last + // send buffer. + // + TransmitParms.pBuffer1 = (PVOID)&EtherstartResp; + Temp = min( EtherstartReq->count, + (WORD)(sizeof_ripl_rom - EtherstartReq->start)); + TransmitParms.cbBuffer1 = (WORD)( sizeof(EtherstartResp) - + sizeof( EtherstartResp.data) + Temp); + EtherstartResp.idp.chksum = XNS_NO_CHKSUM; + EtherstartResp.idp.len = HILO( TransmitParms.cbBuffer1); + EtherstartResp.idp.packet_type = PEX_TYPE; + RplCopy( EtherstartResp.idp.dest.host, + (PBYTE)&pRcvbuf->b.auchLanHeader[ RPLDLC_SOURCE_OFFSET], + NODE_ADDRESS_LENGTH); + EtherstartResp.idp.dest.socket = ETHERSTART_SOCKET; + RplCopy( EtherstartResp.idp.src.host, DirStatusParms.auchNodeAddress, + NODE_ADDRESS_LENGTH); + EtherstartResp.idp.src.socket = ETHERSTART_SOCKET; + EtherstartResp.pex.pex_id = EtherstartReq->pex.pex_id; + EtherstartResp.pex.pex_client = ETHERSERIES_CLIENT; + EtherstartResp.es.func = FUNC_READFILERESP; + EtherstartResp.es.bytes = Temp; // stays intel ordered + RplCopy( EtherstartResp.data, &ripl_rom[ EtherstartReq->start], Temp); + return( EtherAcsLan()); +} + +PCHAR RG_EtherFileName[] = { // names of all legal boot request types + "BOOTPC.COM", + "BOOTSTAT.COM", + NULL + }; +int RG_EtherFileNameLength[] = { // strlen of the above strings + 10, + 12, + 0 + }; + +BOOL RplCrack( VOID) +{ + DWORD index; + PCHAR pFileName; + + pRcvbuf = (PRCVBUF)ReceiveParms.pFirstBuffer; + EtherstartReq = (ETHERSTART_REQ *)&pRcvbuf->u; + // + // Make sure this request is for us. + // + if ( EtherstartReq->idp.packet_type != PEX_TYPE || + EtherstartReq->pex.pex_client != ETHERSERIES_CLIENT || + EtherstartReq->es.func != FUNC_READFILEREQ) { + return( FALSE); // this request is not for us + } + + // + // Make sure this is a legal file request. + // + for ( index = 0, pFileName = RG_EtherFileName[ index]; + pFileName != NULL; + pFileName = RG_EtherFileName[ ++index] ) { + if ( !memcmp( EtherstartReq->filename, pFileName, + RG_EtherFileNameLength[ index])) { + break; + } + } + if ( pFileName == NULL) { + return( FALSE); // this is not a legal file name request + } + return( TRUE); +} + +BOOL Worker( VOID) { + if ( !RplBufferCreate()) { + return( FALSE); + } + if ( !RplDirStatus()) { + return( FALSE); + } + if ( !RplDirOpenDirect()) { + return( FALSE); + } + for ( ; ; ) { + if ( !RplReceive()) { + return( FALSE); + } + if ( !RplCrack()) { + return( FALSE); + } + if ( !RplSend()) { + return( FALSE); + } + } + return( TRUE); +} + + +BOOL _CRTAPI1 main( void) { + BOOL success; + pCcb = &Ccb; + hCompletionEvent = CreateEvent( + NULL, // no security attributes + TRUE, // use manual reset + TRUE, // initial state is signalled + NULL // no name + ); + if ( hCompletionEvent == NULL) { + PRINTF(( "CreateEvent() error\n", GetLastError())); + return( FALSE); + } + cbBufferSize = 0xA000; + pBuffer = GlobalAlloc( GMEM_FIXED, cbBufferSize); + if ( pBuffer == NULL) { + PRINTF(( "GlobalAlloc() error\n", GetLastError())); + return( FALSE); + } + if ( !RplDirOpenAdapter()) { + return( FALSE); + } + success = Worker(); + RplDirCloseAdapter(); + return( success); +} + + diff --git a/private/net/svcdlls/rpl/doc/lm21ddk.doc b/private/net/svcdlls/rpl/doc/lm21ddk.doc Binary files differnew file mode 100644 index 000000000..1a7bb04e4 --- /dev/null +++ b/private/net/svcdlls/rpl/doc/lm21ddk.doc diff --git a/private/net/svcdlls/rpl/doc/rpl.doc b/private/net/svcdlls/rpl/doc/rpl.doc Binary files differnew file mode 100644 index 000000000..cb3be7592 --- /dev/null +++ b/private/net/svcdlls/rpl/doc/rpl.doc diff --git a/private/net/svcdlls/rpl/exe/makefile b/private/net/svcdlls/rpl/exe/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/rpl/exe/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/exe/rplsvc.c b/private/net/svcdlls/rpl/exe/rplsvc.c new file mode 100644 index 000000000..953cd8a8e --- /dev/null +++ b/private/net/svcdlls/rpl/exe/rplsvc.c @@ -0,0 +1,146 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + rplsvc.c + +Abstract: + + This is the main routine for the Remote Program Load Service. + +Notes: + + BUGBUG For now rplsvc.exe is built in ..\server directory + since building it in ..\server is more convenient. + The code here may be out of date compared to ..\server\rplsvc.c. + + You must modify ..\server to build rplsvc.lib (instead of rplsvc.exe) + in order for this code to link. + +Author: + + Vladimir Z. Vulovic (vladimv) 10 - Februrary - 1993 + +Environment: + + User Mode - Win32 + +Revision History: + + 10-Feb-1993 vladimv + created + +--*/ + +// +// INCLUDES +// + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <winsvc.h> // Service control APIs + +#include <lmcons.h> +#include <lmerr.h> // NERR_ and ERROR_ equates. +#include <lmsname.h> + +#include <rpcutil.h> // NetpInitRpcServer() +#include <netdebug.h> // NetpKdPrint(()) +#include <secobj.h> // NetpCreateWellKnownSids() + + +// +// Function Prototypes. +// + +VOID +RPL_main( + DWORD argc, + LPWSTR * argv + ); + +// +// Dispatch table for all services. Passed to NetServiceStartCtrlDispatcher. +// +// Add new service entries here. +// + +SERVICE_TABLE_ENTRY RPLServiceDispatchTable[] = { + { SERVICE_RIPL, RPL_main }, + { NULL, NULL } +}; + + + +VOID _CRTAPI1 +main ( + VOID + ) + +/*++ + +Routine Description: + + This is a main routine for the LANMan Remote Program Load Services. + + It basically sets up the ControlDispatcher and, on return, exits from + this main thread. The call to NetServiceStartCtrlDispatcher does + not return until all services have terminated, and this process can + go away. + + It will be up to the ControlDispatcher thread to start/stop/pause/continue + any services. If a service is to be started, it will create a thread + and then call the main routine of that service. + + +Arguments: + + Anything passed in from the "command line". Currently, NOTHING. + +Return Value: + + NONE + +Note: + + +--*/ +{ + NTSTATUS ntstatus; + + // + // Create well-known SIDs + // + if (! NT_SUCCESS (ntstatus = NetpCreateWellKnownSids(NULL))) { + NetpKdPrint(("[RplSvc] Failed to create well-known SIDs %08lx\n", + ntstatus)); + return; + } + + + // + // Initialize the RpcServer Locks. + // + + NetpInitRpcServer(); + + // + // Call StartServiceCtrlDispatcher to set up the control interface. + // The API won't return until all services have been terminated. At that + // point, we just exit. + // + + if (! StartServiceCtrlDispatcher ( RPLServiceDispatchTable)) { + // + // BUGBUG: Log an event for failing to start control dispatcher + // + NetpKdPrint(("[RplSvc] Failed to start control dispatcher %lu\n", + GetLastError())); + } + + ExitProcess(0); +} diff --git a/private/net/svcdlls/rpl/exe/rplsvc.rc b/private/net/svcdlls/rpl/exe/rplsvc.rc new file mode 100644 index 000000000..b2fc29e3c --- /dev/null +++ b/private/net/svcdlls/rpl/exe/rplsvc.rc @@ -0,0 +1,11 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Net Remote Program Load Service App" +#define VER_INTERNALNAME_STR "atrpl.exe" + +#include "common.ver" + diff --git a/private/net/svcdlls/rpl/exe/sources b/private/net/svcdlls/rpl/exe/sources new file mode 100644 index 000000000..eaac46918 --- /dev/null +++ b/private/net/svcdlls/rpl/exe/sources @@ -0,0 +1,97 @@ +!IF 0 + +Copyright (c) 1989-92 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1989 + + +Revision History: + +!ENDIF + +# +# The TARGETNAME variable is defined by the developer. It is the name of +# the target (component) that is being built by this makefile. It +# should NOT include any path or file extension information. +# + +MAJORCOMP =net +MINORCOMP =rplsvc +TARGETNAME=rplsvc + +# +# The TARGETPATH and TARGETTYPE varialbes are defined by the developer. +# The first specifies where the target is to be build. The second specifies +# the type of target (either PROGRAM, DYNLINK or LIBRARY) +# + +TARGETPATH=obj + +TARGETTYPE=PROGRAM + +TARGETLIBS= \ + ..\server\obj\*\rplsvc.lib \ + ..\dll\obj\*\rplnet.lib \ + $(BASEDIR)\Public\Sdk\Lib\*\dlcapi.lib \ + $(BASEDIR)\public\sdk\lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \ + $(BASEDIR)\public\sdk\lib\*\rpcutil.lib \ + $(BASEDIR)\public\sdk\lib\*\rpcndr.lib + +# +# The INCLUDES variable specifies any include paths that are specific to +# this source directory. Separate multiple directory paths with single +# semicolons. Relative path specifications are okay. +# + +INCLUDES=..\..\..\inc;..\..\..\..\inc;$(BASEDIR)\public\sdk\inc + +# +# The SOURCES variable is defined by the developer. It is a list of all the +# source files for this component. Each source file should be on a separate +# line using the line continuation character. This will minimize merge +# conflicts if two developers adding source files to the same component. +# + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +# +# BUGBUG Messages are not bound properly with RplSvc.exe if it +# BUGBUG built from within the exe directory. +# + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= rplsvc.c rplsvc.rc + +UMTYPE=console +UMLIBS=$(BASEDIR)\public\sdk\lib\*\netapi32.lib + + +# +# Defining the NTTARGETFILES variable causes MAKEFILE.DEF to attempt to +# include .\makefile.inc immediately after it specifies the top +# level targets (all, clean and loc) and their dependencies. MAKEFILE.DEF +# also expands the value of the NTTARGETFILES variable at the end of the +# list of dependencies for the all target. Useful for specifying additional +# targets and dependencies that don't fit the general case covered by +# MAKEFILE.DEF +# diff --git a/private/net/svcdlls/rpl/imports.idl b/private/net/svcdlls/rpl/imports.idl new file mode 100644 index 000000000..3cca04e23 --- /dev/null +++ b/private/net/svcdlls/rpl/imports.idl @@ -0,0 +1,63 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + imports.idl + +Abstract: + + This file is useful for creating RPC interfaces that require the use + of windef types. The .idl file for the RPC product should contain a + line in the interface body that imports this file. For example: + + import "imports.h"; + + Doing this causes the MIDL generated header file to contain the + following line: + + #include "imports.h" + + If this technique is not used, and instead the .idl file for the RPC + product simply contains #include <importsf.h>, then the contents of + imports.h will be expanded in the MIDL generated header file. This + can lead to duplicate definition problems later when the RPC client + or RPC server code needs to include both the MIDL generated header file + and a file that is included in imports.h. + +Author: + + Dan Lafferty (danl) 20-Mar-1991 + +Environment: + + User Mode - Win32 - for use with the MIDL compiler + + +Revision History: + + 03-Apr-1991 danl + created + +--*/ + +[ + uuid(12345678-1234-ABCD-EF00-9948756789AB), +#ifdef __midl + ms_union, +#endif // __midl + version(1.0) +] +interface imports + +{ +#define MIDL_PASS +#include "imports.h" + +// +// All .idl files need to contain at least one function prototype +// + +DWORD Dummy( [in] DWORD DummyParm); +} diff --git a/private/net/svcdlls/rpl/inc/adapter.h b/private/net/svcdlls/rpl/inc/adapter.h new file mode 100644 index 000000000..744173cad --- /dev/null +++ b/private/net/svcdlls/rpl/inc/adapter.h @@ -0,0 +1,52 @@ +/*++ + +Module Name: + + adapter.h + +Abstract: + + Describes layout of JET database table used for ADAPTER structures. + +--*/ + +#ifdef RPLADAPTER_ALLOCATE +#define EXTERN_ADAPTER +#define INIT_ADAPTER( _x) = _x +#else +#define EXTERN_ADAPTER extern +#define INIT_ADAPTER( _x) +#endif + +// +// Indices of entries in AdapterTable[] - server column array. +// +#define ADAPTER_AdapterName 0 +#define ADAPTER_AdapterComment 1 +#define ADAPTER_Flags 2 +#define ADAPTER_TABLE_LENGTH 3 + +RPL_COLUMN_INFO AdapterTable[] +#ifdef RPLADAPTER_ALLOCATE + = { + { "AdapterName", JET_coltypBinary, 0}, // address of unknown rpl client + { "AdapterComment", JET_coltypBinary, 0}, // default comment + { "Flags", JET_coltypLong, 0} +} +#endif // RPLADAPTER_ALLOCATE +; + +// +// This definition gives wrong result when RPLADAPTER_ALLOCATE is not defined +//#define ADAPTER_TABLE_LENGTH (sizeof(AdapterTable)/sizeof(AdapterTable[0])) +// + +#define ADAPTER_INDEX_AdapterName "foo" // + AdapterName + +#define ADAPTER_TABLE_NAME "Adapter" +#define ADAPTER_TABLE_PAGE_COUNT 5 // initial number of 4K pages +#define ADAPTER_TABLE_DENSITY 100 // initial density + +#ifdef RPL_RPLCNV +EXTERN_ADAPTER JET_TABLEID AdapterTableId; +#endif // RPL_RPLCNV diff --git a/private/net/svcdlls/rpl/inc/boot.h b/private/net/svcdlls/rpl/inc/boot.h new file mode 100644 index 000000000..2abb4babb --- /dev/null +++ b/private/net/svcdlls/rpl/inc/boot.h @@ -0,0 +1,59 @@ +/*++ + +Module Name: + + boot.h + +Abstract: + + Describes layout of JET database table used for BOOT structures. + +--*/ + +#ifdef RPLBOOT_ALLOCATE +#define EXTERN_BOOT +#define INIT_BOOT( _x) = _x +#else +#define EXTERN_BOOT extern +#define INIT_BOOT( _x) +#endif + +// +// Indices of entries in BootTable[] - server column array. +// +#define BOOT_BootName 0 +#define BOOT_BootComment 1 +#define BOOT_Flags 2 +#define BOOT_VendorName 3 +#define BOOT_BbcFile 4 +#define BOOT_WindowSize 5 +#define BOOT_VendorId 6 +#define BOOT_TABLE_LENGTH 7 + +RPL_COLUMN_INFO BootTable[] +#ifdef RPLBOOT_ALLOCATE + = { + { "BootName", JET_coltypBinary, 0}, // id of boot block record + { "BootComment", JET_coltypBinary, 0}, // comment for boot block record + { "Flags", JET_coltypLong, 0}, + { "VendorName", JET_coltypBinary, 0}, // VendorId as hex unicode string + { "BbcFile", JET_coltypBinary, 0}, // BBC file name + { "WindowSize", JET_coltypLong, 0}, // used with acknowledgments + { "VendorId", JET_coltypLong, 0} // common adapter id digits +} +#endif // RPLBOOT_ALLOCATE +; + +// +// This definition gives wrong result when RPLBOOT_ALLOCATE is not defined +//#define BOOT_TABLE_LENGTH (sizeof(BootTable)/sizeof(BootTable[0])) +// + +#define BOOT_INDEX_VendorIdBootName "foo" // + VendorId + BootName +#define BOOT_INDEX_BootName "goo" // + BootName + +#define BOOT_TABLE_NAME "Boot" +#define BOOT_TABLE_PAGE_COUNT 5 // initial number of 4K pages +#define BOOT_TABLE_DENSITY 100 // initial density + +EXTERN_BOOT JET_TABLEID BootTableId; diff --git a/private/net/svcdlls/rpl/inc/config.h b/private/net/svcdlls/rpl/inc/config.h new file mode 100644 index 000000000..6cb135433 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/config.h @@ -0,0 +1,95 @@ +/*++ + +Module Name: + + config.h + +Abstract: + + Describes layout of JET database table used for CONFIG structures. + +--*/ + +#ifdef RPLCONFIG_ALLOCATE +#define EXTERN_CONFIG +#define INIT_CONFIG( _x) = _x +#else +#define EXTERN_CONFIG extern +#define INIT_CONFIG( _x) +#endif + +#define CONFIG_ConfigName 0 +#define CONFIG_ConfigComment 1 +#define CONFIG_Flags 2 +#define CONFIG_BootName 3 +#define CONFIG_DirName 4 +#define CONFIG_DirName2 5 +#define CONFIG_DirName3 6 +#define CONFIG_DirName4 7 +#define CONFIG_FitShared 8 +#define CONFIG_FitPersonal 9 +#define CONFIG_TABLE_LENGTH 10 + +EXTERN_CONFIG RPL_COLUMN_INFO ConfigTable[ CONFIG_TABLE_LENGTH] +#ifdef RPLCONFIG_ALLOCATE + = { + { "ConfigName", JET_coltypBinary, 0}, + { "ConfigComment", JET_coltypBinary, 0}, + { "Flags", JET_coltypLong, 0}, + { "BootName", JET_coltypBinary, 0}, + { "DirName", JET_coltypBinary, 0}, + { "DirName2", JET_coltypBinary, 0}, + { "DirName3", JET_coltypBinary, 0}, + { "DirName4", JET_coltypBinary, 0}, + { "FitShared", JET_coltypBinary, 0}, + { "FitPersonal", JET_coltypBinary, 0} +} +#endif // RPLCONFIG_ALLOCATE +; + +// +// The block below is needed by RPLCNV.EXE only. We include it here +// because it is essential that order of elements and lengths of +// ConfigTable and ConfigParseTable arrays are kept in sync. +// +#ifdef RPL_RPLCNV +typedef struct _CONFIG_PARSE_INFO { + PWCHAR Name; // RPLMGR.INI name - NULL for new entries + PVOID Value; // RPLMGR.INI value + DWORD Size; // size in bytes of the above value +} CONFIG_PARSE_INFO, *PCONFIG_PARSE_INFO; +EXTERN_CONFIG CONFIG_PARSE_INFO ConfigParseTable[ CONFIG_TABLE_LENGTH] +#ifdef RPLCONFIG_ALLOCATE + = { + { L"name", NULL, 0}, + { L"comment", NULL, 0}, + { NULL, NULL, 0}, // a placeholder for Flags fields + { L"bblink", NULL, 0}, + { L"dirname", NULL, 0}, + { L"dirname2", NULL, 0}, + { L"dirname3", NULL, 0}, + { L"dirname4", NULL, 0}, + { L"fitfileshared", NULL, 0}, + { L"fitfilepersonal", NULL, 0} +} +#endif // RPLCONFIG_ALLOCATE +; +#endif // RPL_RPLCNV + + +// +// This definition gives wrong result when RPLCONFIG_ALLOCATE is not defined +//#define CONFIG_TABLE_LENGTH (sizeof(ConfigTable)/sizeof(ConfigTable[0])) +// + +#define CONFIG_INDEX_ConfigName "foo" // +ConfigName +#define CONFIG_INDEX_BootNameConfigName "goo" // +BootName+ConfigName + +#define CONFIG_TABLE_NAME "Config" +#define CONFIG_TABLE_PAGE_COUNT 10 // initial number of 4K pages +#define CONFIG_TABLE_DENSITY 80 // initial density + +#ifdef RPL_RPLCNV +EXTERN_CONFIG JET_TABLEID ConfigTableId; +#endif // RPL_RPLCNV + diff --git a/private/net/svcdlls/rpl/inc/i_lmrpl.h b/private/net/svcdlls/rpl/inc/i_lmrpl.h new file mode 100644 index 000000000..1cbde89b6 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/i_lmrpl.h @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + i_lmrpl.h + +Abstract: + + This file desribes hidden structures used with RPL service apis. + It is a private complement of lmrpl.h public file. + + Currently structures defined in this file are mostly used as + placeholders for future extensions, and to suppress MIDL warnings + and to make sure code is already set to support different levels. + +Author: + + Vladimir Z. Vulovic (vladimv) 18-Nov-1993 + +--*/ + +typedef struct _RPL_INFO_1 { + DWORD AdapterPolicy; // bitmask +} RPL_INFO_1, *PRPL_INFO_1, *LPRPL_INFO_1; diff --git a/private/net/svcdlls/rpl/inc/imports.h b/private/net/svcdlls/rpl/inc/imports.h new file mode 100644 index 000000000..5b2991ab0 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/imports.h @@ -0,0 +1,45 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + imports.h + +Abstract: + + This file allows us to include standard system header files in the + .idl file. The main .idl file imports a file called import.idl. + This allows the .idl file to use the types defined in these header + files. It also causes the following line to be added in the + MIDL generated header file: + + #include "imports.h" + + Thus these types are available to the RPC stub routines as well. + +Author: + + Dan Lafferty (danl) 07-May-1991 + +Revision History: + + +--*/ + + +#include <windef.h> +#include <lmcons.h> + +#ifdef MIDL_PASS +#ifdef UNICODE +#define LPTSTR [string] wchar_t* +#else +#define LPTSTR [string] LPTSTR +#endif +#define LPSTR [string] LPSTR +#define BOOL DWORD +#endif + +#include <lmrpl.h> // public definitions +#include "i_lmrpl.h" // internal definitions diff --git a/private/net/svcdlls/rpl/inc/profile.h b/private/net/svcdlls/rpl/inc/profile.h new file mode 100644 index 000000000..a012ec86c --- /dev/null +++ b/private/net/svcdlls/rpl/inc/profile.h @@ -0,0 +1,62 @@ +/*++ + +Module Name: + + profile.h + +Abstract: + + Describes layout of JET database table used for PROFILE structures. + +--*/ + +#ifdef RPLPROFILE_ALLOCATE +#define EXTERN_PROFILE +#define INIT_PROFILE( _x) = _x +#else +#define EXTERN_PROFILE extern +#define INIT_PROFILE( _x) +#endif + +// +// Indices of entries in ProfileTable[] - profile column array. +// +#define PROFILE_ProfileName 0 +#define PROFILE_ProfileComment 1 +#define PROFILE_ConfigName 2 +#define PROFILE_BootName 3 +#define PROFILE_FitShared 4 +#define PROFILE_FitPersonal 5 +#define PROFILE_Flags 6 +#define PROFILE_TABLE_LENGTH 7 + +EXTERN_PROFILE RPL_COLUMN_INFO ProfileTable[ PROFILE_TABLE_LENGTH] +#ifdef RPLPROFILE_ALLOCATE + = { + { "ProfileName", JET_coltypBinary, 0}, // profile name + { "ProfileComment", JET_coltypBinary, 0}, // profile comment + { "ConfigName", JET_coltypBinary, 0}, // configuration name + { "BootName", JET_coltypBinary, 0}, // boot block id + { "FitShared", JET_coltypBinary, 0}, // fit file for wksta sharing + { "FitPersonal", JET_coltypBinary, 0}, // fit file for wksta exclusive + { "Flags", JET_coltypLong, 0} +} +#endif // RPLPROFILE_ALLOCATE +; +// +// This definition gives wrong result when RPLPROFILE_ALLOCATE is not defined +//#define PROFILE_TABLE_LENGTH (sizeof(ProfileTable)/sizeof(ProfileTable[0])) +// + +#define PROFILE_INDEX_ProfileName "foo" // +ProfileName +#define PROFILE_INDEX_BootNameProfileName "goo" // +BootName+ProfileName +#define PROFILE_INDEX_ConfigNameProfileName "hoo" // +ConfigName+ProfileName + +#define PROFILE_TABLE_NAME "Profile" +#define PROFILE_TABLE_PAGE_COUNT 5 // initial number of 4K pages +#define PROFILE_TABLE_DENSITY 100 // initial density + +#ifdef RPL_RPLCNV +EXTERN_PROFILE JET_TABLEID ProfileTableId; +#endif // RPL_RPLCNV + diff --git a/private/net/svcdlls/rpl/inc/riplcons.h b/private/net/svcdlls/rpl/inc/riplcons.h new file mode 100644 index 000000000..cfa6674cf --- /dev/null +++ b/private/net/svcdlls/rpl/inc/riplcons.h @@ -0,0 +1,130 @@ +/*++ + +Module Name: + + riplcons.h + +Abstract: + + RPL constants + +--*/ + +#define RPL_SUCCESS NO_ERROR // defined to be ZERO (LONG). + +#define INVALID_FILE_OFFSET ((DWORD)(-1L)) // for use with SetFilePointer() + +#define BITSET( i, mask) ( (mask & (1<<i)) != 0) + + +// +// Bits and values of type file in file map +// Bits 0 - 3 are reserved for the types of data files and +// special cases. Bits 4 - 7 are boolean bits of executable and sys +// files. When bits 0 - 3 are used, bits 4 - 7 bust be reset. + +// IS_EXE_SYS bit is set for exe-s and device drivers that have exe-format + +#define IS_BIN_SYS 0x0000 +#define IS_EXE_SYS 0x0100 // set if loadable file has exe-format +#define IS_COM_FILE 0x0200 +#define IS_EXE_FILE 0x0300 +#define IS_MOVEABLE 0x0400 +#define EXEC_IN_LOW_MEM 0x0800 +#define EXEC_IN_FREE_MEM 0x1000 +#define OTHER_FILES_MASK 0x00FF +#define BINARY_LOADER 15 +#define DATA_FILE 14 +#define BINARY_LOADER_DATA 13 +#define LOADER_PARAM 12 +#define RPL_BOOT_TYPE 11 +#define IS_EXE_FORMAT 0x0100 +#define IS_EXECUTABLE_FILE 0x0200 + +#define DRV_TYPE 0x0000 +#define EXE_TYPE 0x0200 +#define ORG_TYPE 1 +#define BASE_TYPE 6 +#define UNKNOWN_CONFIG_TYPE 7 + +// +// work station types of returned in parameter wksta_type +// + +#define PCDOS_WKSTA 0 +#define OS2_WKSTA 1 + +// +// The patched offsets of RPLBOOT.SYS +// + +#define BBLOCK_BASE_INDEX 8 +#define MAX_NLS_NUM 5 +#define NLS_BASE_INDEX 10 +#define NLS_INCREMENT 8 +#define NO_CHKSUM_USED 1963 + +// +// Misc conts +// + +#define LM20_WKSTA_LINE 257 // max rpl.map wksta line len supported by rplmfsd.sys (of lm 2.0?) + + +// +// these constants are used only rplservr, not in rplboot.asm, sorry +// + +#define OFFSET_RPLBOOT_HDR 16 +#define NLS_VERSION_10 1 // 1st version number of NLS +#define BBVERSION_10 3 // Boot block format V2.1(Free type) + + +// +// Parameter substitution strings for TCPIP protocol.ini parameters +// used by RPLBOOT.SYS +// + +#define TEMPLATESIZE 15 +#define TCPIP_PREFIX "(TCPIP" +#define TCPIP_ADDRESS "(TCPIP_ADDRESS)" +#define TCPIP_SUBMASK "(TCPIP_SUBMASK)" +#define TCPIP_GATEWAY "(TCPIP_GATEWAY)" + +#define TILDE_CHAR L'~' +#define SPACE_CHAR L' ' +#define COMMENT_CHAR L';' +#define LINE_FEED_CHAR L'\n' // 0xA or \012 +#define NEW_LINE_CHAR LINE_FEED_CHAR + +#define MAXWORD ((WORD)-1) // it is not safe to compare WORDs with -1 + +#define END_OF_TEXT_FILE_CHAR ((WCHAR)0x1a) // ctrl-Z == 'Z' - 0x40 + +#define RPL_MAX_PROFILE_NAME_SIZE ((RPL_MAX_PROFILE_NAME_LENGTH + 1) * sizeof(WCHAR)) +#define RPL_MAX_WKSTA_NAME_SIZE ((RPL_MAX_WKSTA_NAME_LENGTH + 1) * sizeof(WCHAR)) +#define RPL_MAX_CONFIG_NAME_SIZE ((RPL_MAX_CONFIG_NAME_LENGTH + 1) * sizeof(WCHAR)) +#define RPL_MAX_BOOT_NAME_SIZE ((RPL_MAX_BOOT_NAME_LENGTH + 1) * sizeof(WCHAR)) + +#define RPL_MAX_ADAPTER_NAME_LENGTH RPL_ADAPTER_NAME_LENGTH +#define RPL_MAX_ADAPTER_NAME_SIZE ((RPL_MAX_ADAPTER_NAME_LENGTH + 1) * sizeof(WCHAR)) + +#define RPL_MAX_VENDOR_NAME_LENGTH RPL_VENDOR_NAME_LENGTH +#define RPL_MAX_VENDOR_NAME_SIZE ((RPL_MAX_VENDOR_NAME_LENGTH + 1) * sizeof(WCHAR)) + + + +// +// RPL_EVENTLOG_NAME is the name of registry key (under EventLog service) +// used to interpret events for RPL service. +// + +#define RPL_EVENTLOG_NAME TEXT( "RemoteBoot") + + +// +// Define this flag to move to JET500 +// Note that the "sources" files must be updated seperately to refer to +// JET.LIB or JET500.LIB. +// +#define __JET500 1 diff --git a/private/net/svcdlls/rpl/inc/ripltyps.h b/private/net/svcdlls/rpl/inc/ripltyps.h new file mode 100644 index 000000000..bd62bf9e9 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/ripltyps.h @@ -0,0 +1,137 @@ +/*++ + +Module Name: ripltyps.h + +--*/ + +struct _PARAGRAPH { + union { + DWORD dwords[4]; + WORD words[8]; + BYTE bytes[16]; + } t; +} PARAGRAPH, *PPARAGRAPH; + +//**************************************************************** +// +// The boot block structure is totally redefined in LM 2.1, because +// the extending of the LM 2.0 generated too complicated code. +// +// All these data structures are in the boot block header. Thus +// they are common for RPLSERVR and RPLBOOT. The boot data is the +// parameter block of RPL MiniFSD and the resource table is for +// OS/2 1.2 Loader. There must be something other for OS/2 2.0 because +// paragraph addresses can't be used (kernel > 640 kB). +// +// Boot block is a file list including a header. There +// are also the standard dos parameters and some special RIPL data +// stuctures in the header. +// +// The boot block root is actually the header of RPLBOOT.SYS file +// (that can be anywhere in the boot block). +// Remote IPL ROM is requested to jump to there. RPLBOOT finds +// the boot block base address in its header (patched by RPLSERVR). +// All pointers (except the file 32 bit physical pointers) in boot +// block headers are offsets relative to the boot block base address. +// +//**************************************************************** + +// data structure used in RPLBOOT offset 16, +typedef struct rplboot_header { + BYTE achIdStamp[3]; // "RPL" string for identification + BYTE bNul; // terminator + BYTE bBbVersion; // version number of boot block format + BYTE bNlsVersion; // version number of NLS patches (1 = make) + WORD usNlsPatchOff; // offset from file start of NLS patch files + DWORD phBootBlockHeader; // 32 bits physical address +} RPLBOOT_HEADER, *PRPLBOOT_HEADER; + +// +// The segment of parameter and name pointers is the segment of +// file list table. The parameter block of executable files +// will be copied to the PSP offset 80H (Program Segment Prefix). +// The handle I/O and the error messages of rplboot requires +// file names. The check sum is not calculated, if the chk_sum +// field is 1963 ('magic number'). +// + +// +// It may not be required to pack structures below, but for testing +// purposes it is useful since this should give us 1-1 correspondence +// with OS/2 rpl server. +// +// FILE_DATA packed size is 0x16 => unpacked is 0x18 +// BOOT_BLOCK_HDR packed size is 0x12 => unpacked is 0x14 +// +#include <packon.h> // pack structures in boot block + +typedef struct _FILE_DATA { + DWORD file_addr; // 32 bit physical address of file + DWORD file_len; // file length (bytes) + DWORD extra_mem; // extra memory (bytes) + WORD name_offset; // offset of name string + WORD param_offset; // offset of parameter block + WORD chk_sum; // 16 bit add checksum of the file + WORD file_type; // type of file + BYTE param_len; // length of params block + BYTE pad1; // pad this to next even byte +} FILE_DATA, *PFILE_DATA; + +// new boot block header structure used in LAN Manager 2.1 (and later) +// the offsets are relative from the boot block base address + +typedef struct _BOOT_BLOCK_HDR { + WORD id_stamp; // if 0x18cd (int 18H) => extended structure + WORD usInfoLevel; // info level of this structure + WORD cbSize; // size of boot block header struct (and data) + WORD file_list_len; // length of file list table + WORD offRplWkstaLine; // offset ASCIZ rpl.map wksta line (any length) + WORD offResourceTbl; // pointer of IFS resource table + WORD cbResourceTbl; // size of resource table struct + WORD offBootData; // offset of LM 2.0 level boot structure + WORD offMBootData; // offset of the buffer used in the multi boot + FILE_DATA aFileData[1]; // dynamic array for file data +} BOOT_BLOCK_HDR, *PBOOT_BLOCK_HDR; + +// DON't MODIFY, the structures fixed in 1.2 LDR spec + +typedef struct _RESOURCE { + WORD pos_in_paras; // paragraph of the file in PC memory + DWORD file_len; // length of file in bytes +} RESOURCE; + +typedef struct _RESOURCE_TABLE { + WORD entries; // number of entries 4 (or 3 if no BootData) + RESOURCE file_tbl[4]; +} RESOURCE_TBL, *PRESOURCE_TBL; + + +// +// BootData structure is fixed in RPL MFSD, +// negotiate with Randy before any changes +// All offsets are relative from the beginning of the structure. +// + +typedef struct _BOOT_DATA { + WORD cbSize; // size of the whole structure + DWORD int_5c; // netbios interrupt saved by rplboot.sys + WORD cbWkstaLine; // size of wksta line + WORD offWkstaLine; // offset of ASCIIZ wksta line + WORD cbFit; // size of the FIT file + WORD offFit; // offset of ASCIIZ FIT file + WORD cbCodePage; // size of NLS Code Page + WORD offCodePage; // offset of Code Page Table Dynamic data area for the buffers +} BOOT_DATA, *PBOOT_DATA; + +// +// Defines the structure of the element in a variable len multiboot +// info table +// +typedef struct _MBOOTDATA { + WORD cbSize; // size of the dynamic structure + BYTE achProfile[16]; // profile name + BYTE achProfileComment[1]; // variable len comment +} MBOOTDATA, *PMBOOTDATA; + +#include <packoff.h> // restore default packing (done with boot block) + diff --git a/private/net/svcdlls/rpl/inc/rpldb.h b/private/net/svcdlls/rpl/inc/rpldb.h new file mode 100644 index 000000000..3990ced31 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/rpldb.h @@ -0,0 +1,30 @@ +/*++ + +Module Name: + + rpldb.h + +Abstract: + + Main include file for JET database portion of RPL service & RPL convert + program. + + + Auxiliary include files (adapter.h , boot.h, config.h, profile.h & + wksta.h) are JET table specific. + +--*/ + +#define RPL_SERVICE_DATABASE "rplsvc.mdb" +#define RPL_SERVICE_DATABASE_W L"rplsvc.mdb" +#define RPL_SYSTEM_DATABASE "system.mdb" +#define RPL_SYSTEM_DATABASE_W L"system.mdb" +#define RPL_TEMP_DATABASE "temp.mdb" +#define RPL_TEMP_DATABASE_W L"temp.mdb" + +typedef struct _RPL_COLUMN_INFO { + CHAR * ColumnName; + JET_COLTYP ColumnType; + JET_COLUMNID ColumnId; +} RPL_COLUMN_INFO, *PRPL_COLUMN_INFO; + diff --git a/private/net/svcdlls/rpl/inc/rpldebug.h b/private/net/svcdlls/rpl/inc/rpldebug.h new file mode 100644 index 000000000..d1a0a6ec7 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/rpldebug.h @@ -0,0 +1,88 @@ +/*++ + +Module: + + rpldebug.h + +Abstract: + + Definitions of debug data structures. + +--*/ + +#if DBG +#define RPL_DEBUG +#endif // DBG + +#define NODE_ADDRESS_LENGTH 6 + +#ifdef RPL_DEBUG + +extern int RG_DebugLevel; // needed by other modules +extern int RG_Assert; // needed by other modules + +VOID _CRTAPI1 RplDebugPrint( CONST CHAR * format, ...); + +#define RplDump( DBG_CONDITION, DBG_PRINT_ARGUMENTS) \ + { \ + if ( DBG_CONDITION) { \ + if ( RG_Assert!= 0) { \ + RplDebugPrint( "File %s, Line %d\n", __FILE__, __LINE__); \ + } \ + RplDebugPrint DBG_PRINT_ARGUMENTS; \ + } \ + } + +#define RPL_RETURN( arg) RplDump(++RG_Assert,("File %s, Line %d\n", __FILE__, __LINE__)); return( arg) + +// +// We do not define +// +// #define RPL_ASSERT( condition) ASSERT( condition) +// +// because we want to break even on a free build and in user mode +// (when rplsvc runs under ntsd). +// +#define RPL_ASSERT( condition) \ + { \ + if ( !( condition)) { \ + ++RG_Assert; \ + RplDebugPrint( "File %s, Line %d\n", __FILE__, __LINE__); \ + } \ + } + +#define RPL_DEBUG_MEMALLOC ((DWORD)0x00000001) // memory allocations +#define RPL_DEBUG_INIT ((DWORD)0x00000002) +#define RPL_DEBUG_FDR ((DWORD)0x00000004) // file data response +#define RPL_DEBUG_FIND ((DWORD)0x00000008) // find +#define RPL_DEBUG_FOUND ((DWORD)0x00000010) // found +#define RPL_DEBUG_SFR ((DWORD)0x00000020) // send file request +#define RPL_DEBUG_MISC ((DWORD)0x00000040) // miscelaneous +#define RPL_DEBUG_REQUEST ((DWORD)0x00000080) // request thread +#define RPL_DEBUG_SERVICE ((DWORD)0x00000100) +#define RPL_DEBUG_WORKER ((DWORD)0x00000200) // worker thread +#define RPL_DEBUG_MEMORY ((DWORD)0x00000400) // other memory +#define RPL_DEBUG_FLOW ((DWORD)0x00000800) // other flow +#define RPL_DEBUG_FLOWINIT ((DWORD)0x00001000) // init flow +#define RPL_DEBUG_ETHER ((DWORD)0x00002000) // EtherStart +#define RPL_DEBUG_DB ((DWORD)0x00004000) // misc database +#define RPL_DEBUG_CONFIG ((DWORD)0X00008000) // Config apis +#define RPL_DEBUG_RESUME ((DWORD)0X00010000) // Resume key usage +#define RPL_DEBUG_PROFILE ((DWORD)0X00020000) // Profile apis +#define RPL_DEBUG_WKSTA ((DWORD)0X00040000) // Wksta apis +#define RPL_DEBUG_ADAPTER ((DWORD)0X00080000) // Adapter apis +#define RPL_DEBUG_BOOT ((DWORD)0X00100000) // Boot record usage +#define RPL_DEBUG_VENDOR ((DWORD)0X00200000) // Vendor record usage +#define RPL_DEBUG_SPECIAL ((DWORD)0X00400000) // for one time bugs + +#else // RPL_DEBUG + +#define RPL_RETURN( arg) return( arg) +#define RPL_RETURN( arg) return( arg) +#define RPL_ASSERT( condition) + +#define RplDump( DBG_CONDITION, DBG_PRINT_ARGUMENTS) \ + do {NOTHING;} while (0) + +#endif // RPL_DEBUG + diff --git a/private/net/svcdlls/rpl/inc/rpldll.h b/private/net/svcdlls/rpl/inc/rpldll.h new file mode 100644 index 000000000..4a606f487 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/rpldll.h @@ -0,0 +1,144 @@ +/*++ + +Module: + + rpldll.h + +Abstract: + + DLL interface: return codes, data structures & function declarations. + +--*/ + +// +// Data structures used in the DLL function declarations. +// + +typedef struct _OPEN_INFO { + // + // Adapter info buffer should be large enough to hold private adapter + // info and the maximum amount of memory needed for DLC buffer pool. + // + PBYTE adapt_info_ptr; // Buffer for adapter private information. + DWORD adapt_info_size; // Size of above buffer. + BYTE NodeAddress[ NODE_ADDRESS_LENGTH]; // burned-in adapter num + DWORD lan_rcb_size; // size of the network specific RCB +} OPEN_INFO, *POPEN_INFO; + +typedef struct _RCB { // Resource Control Block + struct _RCB * next_rcb; // the next rcb + PBYTE lan_rcb_ptr; // ptr to the network specific resource block + DWORD sfr_seq_number; // number of requested packet, set by RPL ROM + DWORD fdr_seq_number; // number of the next packet to be sent + + DWORD max_frame; // size of data block + + BYTE ReceivedSfr; // have we received an SFR's from this client + + struct { // bitfield + + BYTE alerted: 1; // SAP F8 got an ALERT frame + BYTE spframe: 2; // special frame is last one + BYTE rcberr:1; // RECEIVE on SAP F8 got an error + BYTE defboot:1; // If DLL supports default boot, DLL sets this + // to ask server to use default boot + } flags; + + // + // "send_flags" is used for FLAGS field in FileDataResponse frame. + // In OS/2 days RPL service pretended not to know about the DLC layer, + // but even then it manipulated "send_flags" defined here. + // + struct { // bitfield + BYTE reserved :4; + BYTE ack_request :1; + BYTE locate_enable :1; + BYTE xfer_enable :1; + BYTE end_of_file :1; + } send_flags; + + // + // SF_wakeup is an EVENT created in RplGetRcbFromList. + // + HANDLE SF_wakeup; // event for wakeup + + // + // thxsemhdl is an EVENT created in RplWorkerThread. + // + HANDLE txsemhdl; // event used for transmitting data + + BYTE NodeAddress[ NODE_ADDRESS_LENGTH]; // of remote client + WCHAR AdapterName[ 2 * NODE_ADDRESS_LENGTH + 1]; // above in hex UNICODE + + // + // volume_id is ASCIIZ string of chosen boot. It is set by the DLL + // if protocol supports it. + // + CHAR volume_id[ 17]; + + BOOL SFR; // is SFR thread working on this RCB + BOOL Pending; // is RCB in a transient state + BOOL RcbIsBad; // if we should get rid of this RCB +} RCB, *PRCB, **PPRCB; + + +// +// Functions exported by ..\dll\init.c +// +BOOL RplDlcInit( + POPEN_INFO pOpenInfo, + DWORD rpl_adapter + ); +BOOL RplDlcTerm( POPEN_INFO pOpenInfo); + +// +// Functions exported by ..\dll\find.c +// +BOOL RplDlcFind( + POPEN_INFO pOpenInfo, + PRCB pRcb + ); + +// +// Functions exported by ..\dll\found.c +// +BOOL RplDlcFound( + POPEN_INFO pOpenInfo, + PRCB pRcb + ); + +// +// Functions exported by ..\dll\fdr.c +// +BOOL RplDlcFdr( + POPEN_INFO pOpenInfo, + PRCB pRcb, + PBYTE data_ptr, + WORD length, + DWORD locate_addr, + DWORD start_addr + ); + + +// +// Functions exported by ..\dll\sfr.c +// +BOOL RplDlcSfr( + POPEN_INFO pOpenInfo, + PPRCB HeadRcbList, + PCRITICAL_SECTION ProtectRcbList + ); +PRCB RplFindRcb( + PPRCB HeadRcbList, + PBYTE NodeAddress + ); +#ifdef RPL_DEBUG +#define RPL_MUST_FIND 1 +#define RPL_MUST_NOT_FIND 2 +VOID DebugCheckList( PPRCB HeadList, PRCB pInputRcb, DWORD Operation); +#else +#define DebugCheckList( HeadList, pInputRcb, Operation) +#endif + + + diff --git a/private/net/svcdlls/rpl/inc/rpllib.h b/private/net/svcdlls/rpl/inc/rpllib.h new file mode 100644 index 000000000..b3361878b --- /dev/null +++ b/private/net/svcdlls/rpl/inc/rpllib.h @@ -0,0 +1,94 @@ +/*++ + +Module Name: + + rpllib.h + +Abstract: + + Desribes exports from lib subirectory. + + Also used for macros used by several RPL subdirectories - because + all of them include this file. + +--*/ + +#define RPL_STRING_TOO_LONG(_x_) (_x_!=NULL && wcslen(_x_)>RPL_MAX_STRING_LENGTH) + +// +// Exports from ..\lib\adapter.c +// +BOOL ValidHexName( IN PWCHAR Name, IN DWORD NameLength, IN BOOL MustHaveInput); +BOOL ValidName( IN PWCHAR Name, IN DWORD MaxNameLength, IN BOOL MustHaveInput); + +// +// Exports from ..\lib\tcpip.c +// +DWORD FillTcpIpString( OUT PCHAR Buffer, IN DWORD AddressDword); + +// +// Exports from ..\lib\addkey.c +// +DWORD AddKey( OUT PCHAR Target, IN CHAR Prefix, IN PCHAR Source); + +// +// Exports from ..\lib\jeterror.c +// +DWORD MapJetError( IN JET_ERR JetError); + +// +// Exports from ..\lib\report.c +// +VOID RplReportEvent( + IN DWORD MessageId, + IN LPWSTR InsertionString, + IN DWORD RawDataBufferLength OPTIONAL, + IN LPVOID RawDataBuffer + ); + +// +// Exports from ..\lib\cmdline.c +// + +VOID RplPrintf0( + IN DWORD MessageId + ); +VOID RplPrintf1( + IN DWORD MessageId, + IN PWCHAR InsertionString + ); +VOID RplPrintf2( + IN DWORD MessageId, + IN PWCHAR InsertionString1, + IN PWCHAR InsertionString2 + ); +VOID RplPrintfN( + IN DWORD MessageId, + IN PWCHAR * Parameters, + IN DWORD NumParameters + ); +VOID RplPrintfID( + IN DWORD MessageId, + IN DWORD MessageIdInsertion + ); +VOID RplSPrintfN( + IN DWORD MessageId, + IN PWCHAR * Parameters, + IN DWORD NumParameters, + OUT PWCHAR * MessageStringPtr + ); + +// +// Exports from ..\lib\reg.c +// + +DWORD RplRegRead( + OUT DWORD * pAdapterPolicy, + OUT DWORD * pBackupInterval, + OUT DWORD * pMaxThreadCount, + OUT PWCHAR DirectoryBuffer, + IN OUT DWORD * pDirectoryBufferSize + ); +DWORD RplRegSetPolicy( + IN DWORD NewAdapterPolicy + ); diff --git a/private/net/svcdlls/rpl/inc/rplnames.h b/private/net/svcdlls/rpl/inc/rplnames.h new file mode 100644 index 000000000..454ccf6a4 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/rplnames.h @@ -0,0 +1,24 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rplnames.h + +Abstract: + + Private header file which defines the RPL service names. + +Author: + + Vladimir Z. Vulovic (vladimv) 22 - November - 1993 + +Revision History: + + 22-Nov-1993 vladimv + Created + +--*/ + +#define RPL_INTERFACE_NAME TEXT("rplsvc") diff --git a/private/net/svcdlls/rpl/inc/vendor.h b/private/net/svcdlls/rpl/inc/vendor.h new file mode 100644 index 000000000..39516f572 --- /dev/null +++ b/private/net/svcdlls/rpl/inc/vendor.h @@ -0,0 +1,53 @@ +/*++ + +Module Name: + + vendor.h + +Abstract: + + Describes layout of JET database table used for VENDOR structures. + +--*/ + +#ifdef RPLVENDOR_ALLOCATE +#define EXTERN_VENDOR +#define INIT_VENDOR( _x) = _x +#else +#define EXTERN_VENDOR extern +#define INIT_VENDOR( _x) +#endif + +// +// Indices of entries in VendorTable[] - used to describe vendor codes +// +#define VENDOR_VendorName 0 +#define VENDOR_VendorComment 1 +#define VENDOR_Flags 2 +#define VENDOR_TABLE_LENGTH 3 + +RPL_COLUMN_INFO VendorTable[] +#ifdef RPLVENDOR_ALLOCATE + = { + { "VendorName", JET_coltypBinary, 0}, // first 6 digits of adapter id + { "VendorComment", JET_coltypBinary, 0}, // vendor comment + { "Flags", JET_coltypLong, 0} +} +#endif // RPLVENDOR_ALLOCATE +; + +// +// This definition gives wrong result when RPLVENDOR_ALLOCATE is not defined +//#define VENDOR_TABLE_LENGTH (sizeof(VendorTable)/sizeof(VendorTable[0])) +// + +#define VENDOR_INDEX_VendorName "foo" // + VendorName + +#define VENDOR_TABLE_NAME "Vendor" +#define VENDOR_TABLE_PAGE_COUNT 5 // initial number of 4K pages +#define VENDOR_TABLE_DENSITY 100 // initial density + +#ifdef RPL_RPLCNV +EXTERN_VENDOR JET_TABLEID VendorTableId; +#endif // RPL_RPLCNV + diff --git a/private/net/svcdlls/rpl/inc/wksta.h b/private/net/svcdlls/rpl/inc/wksta.h new file mode 100644 index 000000000..49f58401b --- /dev/null +++ b/private/net/svcdlls/rpl/inc/wksta.h @@ -0,0 +1,105 @@ +/*++ + +Module Name: + + wksta.h + +Abstract: + + Describes layout of JET database table used for WKSTA structures. + +--*/ + +#ifdef RPLWKSTA_ALLOCATE +#define EXTERN_WKSTA +#define INIT_WKSTA( _x) = _x +#else +#define EXTERN_WKSTA extern +#define INIT_WKSTA( _x) +#endif + +// +// WKSTA_LOGON_INPUT_* describe username/password policy during rpl logon +// on the client side. Depending on the value of this field, user input for +// username/password during RPL logon will be: +// +#define WKSTA_LOGON_INPUT_REQUIRED L'P' // user input is required +#define WKSTA_LOGON_INPUT_OPTIONAL L'N' // user input is optional +#define WKSTA_LOGON_INPUT_IMPOSSIBLE L'D' // user input is not solicited +// +// WKSTA_SHARING_* describe whether workstation shares or does not share its +// remote boot disk (i.e. "does it have shared or personal profile"). +// +#define WKSTA_SHARING_TRUE L'S' // shares remote boot disk +#define WKSTA_SHARING_FALSE L'P' // does not share remote boot disk + +// +// WKSTA_SHARING_* describe whether workstation shares or does not share its +// remote boot disk (i.e. "does it have shared or personal profile"). +// +#define WKSTA_SHARING_TRUE L'S' // shares remote boot disk +#define WKSTA_SHARING_FALSE L'P' // does not share remote boot disk + +// +// WKSTA_DISABLE_DHCP_* describe whether workstation uses DHCP or not. Note +// that these flags are relevant only if TCP/IP itself is enabled (i.e. changes +// to boot block configuration file, config.sys & autoexec.bat have been made). +// + +#define WKSTA_DISABLE_DHCP_FALSE '0' // use DHCP +#define WKSTA_DISABLE_DHCP_TRUE '1' // do not use DHCP + +// +// Indices of entries in WkstaTable[] - wksta column array. +// +#define WKSTA_WkstaName 0 +#define WKSTA_WkstaComment 1 +#define WKSTA_ProfileName 2 +#define WKSTA_BootName 3 +#define WKSTA_FitFile 4 +#define WKSTA_AdapterName 5 +#define WKSTA_TcpIpAddress 6 +#define WKSTA_TcpIpSubnet 7 +#define WKSTA_TcpIpGateway 8 +#define WKSTA_Flags 9 +#define WKSTA_TABLE_LENGTH 10 + +// +// We could speed things up by defining AdapterName as JET_coltypCurrency +// + +EXTERN_WKSTA RPL_COLUMN_INFO WkstaTable[ WKSTA_TABLE_LENGTH] +#ifdef RPLWKSTA_ALLOCATE + = { + { "WkstaName", JET_coltypBinary, 0}, // wksta name + { "WkstaComment", JET_coltypBinary, 0}, // wksta comment + { "ProfileName", JET_coltypBinary, 0}, // profile name + { "BootName", JET_coltypBinary, 0}, // boot block id - if NULL => consult profile + { "FitFile", JET_coltypBinary, 0}, // fit file - if NULL => consult profile + { "AdapterName", JET_coltypBinary, 0}, // network address, hex string + { "TcpIpAddress", JET_coltypLong, 0}, // tcp/ip address + { "TcpIpSubnet", JET_coltypLong, 0}, // subnet tcp/ip address + { "TcpIpGateway", JET_coltypLong, 0}, // gateway tcp/ip address + { "Flags", JET_coltypLong, 0} +} +#endif // RPLWKSTA_ALLOCATE +; +// +// This definition gives wrong result when RPLWKSTA_ALLOCATE is not defined +//#define WKSTA_TABLE_LENGTH (sizeof(WkstaTable)/sizeof(WkstaTable[0])) +// + +#define WKSTA_INDEX_AdapterName "foo" // + AdapterName +#define WKSTA_INDEX_WkstaName "goo" // + WkstaName +#define WKSTA_INDEX_ProfileNameWkstaName "hoo" // + ProfileName + WkstaName +#define WKSTA_INDEX_BootNameWkstaName "joo" // + BootName + WkstaName + +#define WKSTA_TABLE_NAME "Wksta" +#define WKSTA_TABLE_PAGE_COUNT 5 // initial number of 4K pages +#define WKSTA_TABLE_DENSITY 100 // initial density + +#ifdef RPL_RPLCNV +EXTERN_WKSTA JET_TABLEID WkstaTableId; +#endif // RPL_RPLCNV + + diff --git a/private/net/svcdlls/rpl/lib/adapter.c b/private/net/svcdlls/rpl/lib/adapter.c new file mode 100644 index 000000000..ff83481eb --- /dev/null +++ b/private/net/svcdlls/rpl/lib/adapter.c @@ -0,0 +1,120 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + adapter.c + +Abstract: + + Contains: + BOOL ValidHexName( IN PWCHAR Name, IN DWORD Length) + BOOL ValidName( IN PWCHAR Name, IN DWORD MaxNameLength) + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "rpllib.h" +#include "icanon.h" // I_NetPathType + + + +BOOL ValidHexName( + IN PWCHAR Name, + IN DWORD NameLength, + IN BOOL MustHaveInput + ) +/*++ + +Routine Description: + + Returns TRUE if the input string is a hex string of a + desired length. + +Arguments: + + Name - NULL or NULL terminated hexadecimal string + NameLength - meaningfull only if Name is provided + MustHaveInput - TRUE if null Name input is not allowed + +Return Value: + TRUE if success, FALSE otherwise + +--*/ +{ + DWORD count; + + if ( Name == NULL) { + return( !MustHaveInput); // null Name is OK only if MustHaveInput is FALSE + } + for ( count = 0; iswxdigit(*Name); count++) { + Name++; + } + if ( *Name != 0 || count != NameLength) { + return( FALSE); + } + return( TRUE); +} + + + +BOOL ValidName( + IN PWCHAR Name, + IN DWORD MaxNameLength, + IN BOOL MustHaveInput + ) +/*++ + +Routine Description: + + Returns TRUE if Name is valid. When Name is not NULL, + then is must be a valid path component for RPL purposes. + +Arguments: + + Name - NULL or NULL terminated RPL path string + MaxNameLength - meaningfull only if Name is provided + MustHaveInput - TRUE if null Name input is not allowed + +Return Value: + TRUE if success, FALSE otherwise + +--*/ +{ + DWORD Length; + DWORD PathType = 0; + + if ( Name == NULL) { + return( !MustHaveInput); // null Name is OK only if MustHaveInput is FALSE + } + + Length = wcslen( Name); + + if ( Length == 0 || Length > MaxNameLength) { + return( FALSE); + } + // + // Do not allow leading spaces nor "." or ".." (according to old rplmgr + // code these are all very bad). + // + if ( iswspace( *Name) || *Name==L'.') { + return( FALSE); + } + if ( wcsspn( Name, L"\f\n\r\t\v\\ ") != 0) { + return( FALSE); + } + if ( I_NetPathType( NULL, Name, &PathType, 0) != NO_ERROR + || PathType != ITYPE_PATH_RELND ) { + return( FALSE); + } + return( TRUE); +} + + diff --git a/private/net/svcdlls/rpl/lib/addkey.c b/private/net/svcdlls/rpl/lib/addkey.c new file mode 100644 index 000000000..681be066e --- /dev/null +++ b/private/net/svcdlls/rpl/lib/addkey.c @@ -0,0 +1,31 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + addkey.c + +Abstract: + + Contains: + DWORD AddKey( OUT PCHAR Target, IN CHAR Prefix, IN PCHAR Source) + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" + +DWORD AddKey( OUT PCHAR Target, IN CHAR Prefix, IN PCHAR Source) +{ + DWORD Size; + Target[ 0] = Prefix; + Size = 1 + strlen( Source); // copy terminating null + memcpy( Target + sizeof( Prefix), Source, Size); + return( Size + sizeof( Prefix)); +} diff --git a/private/net/svcdlls/rpl/lib/cmdline.c b/private/net/svcdlls/rpl/lib/cmdline.c new file mode 100644 index 000000000..875883bcb --- /dev/null +++ b/private/net/svcdlls/rpl/lib/cmdline.c @@ -0,0 +1,249 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + cmdline.c + +Abstract: + + Contains: + VOID RplPrintfXXX() + +Author: + + Jon Newman (jonn) 20 - April - 1994 + +Revision History: + +--*/ + +#include "local.h" + +// +// Must fit within FORMAT_MESSAGE_MAX_WIDTH_MASK +// +#define MAX_LINE_WIDTH 80 + + +VOID RplPrintf0( + IN DWORD MessageId + ) +/*++ + +Routine Description: + + Writes a message to STDOUT. + +Arguments: + + MessageId - Message ID + +Return Value: + + None. + +--*/ +{ + RplPrintfN( MessageId, NULL, 0 ); +} + +VOID RplPrintf1( + IN DWORD MessageId, + IN PWCHAR InsertionString // note: Unicode + ) +/*++ + +Routine Description: + + Writes a message to STDOUT. + +Arguments: + + MessageId - Message ID + InsertionString - asciiz string (may be NULL) + +Return Value: + + None. + +--*/ +{ + RplPrintfN( MessageId, &InsertionString, 1 ); +} + + +VOID RplPrintf2( + IN DWORD MessageId, + IN PWCHAR InsertionString1, // note: Unicode + IN PWCHAR InsertionString2 // note: Unicode + ) +/*++ + +Routine Description: + + Writes a message to STDOUT. + +Arguments: + + MessageId - Message ID + + InsertionString1 - asciiz string (may be NULL) + InsertionString2 - asciiz string (may be NULL) + +Return Value: + + None. + +--*/ +{ + PWCHAR ParamArray[2]; + ParamArray[0] = InsertionString1; + ParamArray[1] = InsertionString2; + RplPrintfN( MessageId, ParamArray, 2 ); +} + + +VOID RplPrintfN( + IN DWORD MessageId, + IN PWCHAR * Parameters, // note: Unicode + IN DWORD NumParameters + ) +/*++ + +Routine Description: + + Writes a message to STDOUT. + +Arguments: + + MessageId - Message ID + + Parameters - array of pointers to parameters + + NumParameters - number of parameters in array + +Return Value: + + None. + +--*/ +{ + PWCHAR MessageString = NULL; + DWORD Error = NO_ERROR; + + (void) RplSPrintfN( MessageId, + Parameters, + NumParameters, + &MessageString ); + + if (MessageString != NULL) { + wprintf( MessageString ); + } + + if (MessageString != NULL) { + LocalFree( MessageString ); + MessageString = NULL; + } +} + + +VOID RplPrintfID( + IN DWORD MessageId, + IN DWORD MessageIdInsertion + ) +/*++ + +Routine Description: + + Writes a message to STDOUT. + +Arguments: + + MessageId - Message ID + + MessageIdInsertion - Message ID to be inserted as %1 into MessageId + +Return Value: + + None. + +--*/ +{ + PWCHAR MessageString = NULL; + + RplSPrintfN( MessageIdInsertion, NULL, 0, &MessageString ); + + if (MessageString != NULL) { + RplPrintf1( MessageId, MessageString ); + } + + if (MessageString != NULL) { + LocalFree( MessageString ); + MessageString = NULL; + } +} + + +VOID RplSPrintfN( + IN DWORD MessageId, + IN PWCHAR * Parameters, // note: Unicode + IN DWORD NumParameters, + OUT PWCHAR * MessageStringPtr + ) +/*++ + +Routine Description: + + Retrieves a message + +Arguments: + + MessageId - Message ID + + Parameters - array of pointers to parameters + + NumParameters - number of parameters in array + + MessageStringPtr - message returned, must be LocalFree'd by caller + +Return Value: + + None. + +--*/ +{ + DWORD Error = NO_ERROR; + + if (MessageStringPtr == NULL) { +#ifdef RPL_DEBUG + wprintf( L"RplSPrintfN: bad parameter\n" ); +#endif + return; + } + + if ( 0 == FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_HMODULE + | FORMAT_MESSAGE_ARGUMENT_ARRAY + | MAX_LINE_WIDTH, + NULL, + MessageId, + 0, + (LPTSTR)(MessageStringPtr), // ALLOCATE_BUFFER + NumParameters, + (va_list *)Parameters) ) { // ARGUMENT_ARRAY +#ifdef RPL_DEBUG + Error = GetLastError(); + wprintf( L"RplSPrintfN: FormatMessage error %d\n", Error ); +#endif + goto cleanup; + } + +cleanup: + + if (Error != NO_ERROR && *MessageStringPtr != NULL) { + LocalFree( *MessageStringPtr ); + *MessageStringPtr = NULL; + } +} diff --git a/private/net/svcdlls/rpl/lib/jeterror.c b/private/net/svcdlls/rpl/lib/jeterror.c new file mode 100644 index 000000000..70bb8f1a1 --- /dev/null +++ b/private/net/svcdlls/rpl/lib/jeterror.c @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + jeterror.c + +Abstract: + + Contains: + DWORD MapJetError( IN JET_ERR JetError) + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" + +// +// BUGBUG ERROR_RPL_JET_ERROR should be a part of winerr.h +// Although RPL apis follow NET convention, they really use WINDOWS error +// codes. This is somewhat inconsistent. +// +#define ERROR_RPL_JET_ERROR 0x7777 // BUGBUG arbitrary value for now + + +DWORD MapJetError( IN JET_ERR JetError) +/*++ + +Routine Description: + + This function maps the Jet database errors to Windows error. + +Arguments: + + JetError - an error JET function call. + +Return Value: + + Windows Error. + +--*/ +{ + if( JetError == JET_errSuccess ) { + return( ERROR_SUCCESS); + } else if ( JetError < 0) { + DWORD Error; + switch( JetError ) { + case JET_errNoCurrentRecord: + Error = ERROR_NO_MORE_ITEMS; + break; + + case JET_errRecordNotFound: // record not found + default: + Error = ERROR_RPL_JET_ERROR; + } + return(Error); + } else { + return( ERROR_SUCCESS); + } +} diff --git a/private/net/svcdlls/rpl/lib/local.h b/private/net/svcdlls/rpl/lib/local.h new file mode 100644 index 000000000..927f8d163 --- /dev/null +++ b/private/net/svcdlls/rpl/lib/local.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + local.h + +Abstract: + + Main include file for Remote initial Program Load library. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include <nt.h> // ntexapi.h\NtQuerySystemTime +#include <ntrtl.h> // RtlTimeToSecondsSince1970 +#include <nturtl.h> + +#include <windows.h> // DWORD, IN, File APIs, etc. +#include <stdlib.h> +#include <lmcons.h> + +#include <stdio.h> // vsprintf +#include <ctype.h> // isspace + +#include <lmerr.h> // NERR_RplBootStartFailed - used to be here + +#include <lmsvc.h> + +#include <lmalert.h> // STD_ALERT ALERT_OTHER_INFO + +#include <lmerrlog.h> +#include <alertmsg.h> +#include <lmserver.h> +#include <netlib.h> +#include <netlock.h> // Lock data types, functions, and macros. +#include <thread.h> // FORMAT_NET_THREAD_ID, NetpCurrentThread(). + +#include <lmshare.h> // PSHARE_lsINFO_2 +#include <lmaccess.h> // NetGroupGetInfo +#include <lmconfig.h> // NetConfigGet +#include <nb30.h> // NCB + +#include <riplcons.h> // includes __JET500 flag +#include <jet.h> // JET_ERR + +#include "rpldebug.h" +#include "rpllib.h" diff --git a/private/net/svcdlls/rpl/lib/makefile b/private/net/svcdlls/rpl/lib/makefile new file mode 100644 index 000000000..f0db8e4a7 --- /dev/null +++ b/private/net/svcdlls/rpl/lib/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS LINE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/lib/reg.c b/private/net/svcdlls/rpl/lib/reg.c new file mode 100644 index 000000000..181fd207b --- /dev/null +++ b/private/net/svcdlls/rpl/lib/reg.c @@ -0,0 +1,271 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + reg.c + +Abstract: + + Registry _access routines for RPL server and related components + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + + Moved from server by Jon Newman 26 - April - 1994 + +--*/ + +#include "local.h" + +#define RPL_REGISTRY_PARAMETERS L"System\\CurrentControlSet\\Services\\RemoteBoot\\Parameters" +#define RPL_REGISTRY_DIRECTORY L"Directory" +#define RPL_REGISTRY_STARTUP L"Startup" +#define RPL_DEFAULT_DIRECTORY L"%SystemRoot%\\rpl\\" +#define RPL_DEFAULT_STARTUP 0 +#define RPL_DEFAULT_BACKUP_INTERVAL 24 +#define RPL_DEFAULT_MAX_WORKER_COUNT 10 +#define RPL_REGISTRY_BACKUP_INTERVAL L"BackupInterval" +#define RPL_REGISTRY_THREAD_COUNT L"maxthreads" + + +DWORD RplRegReadValue( + IN HKEY Key, + IN DWORD DefaultValue, + IN PWCHAR Name, + OUT DWORD * pValue + ) +{ + DWORD Size; + DWORD Type; + DWORD Error; + + Size = sizeof( DWORD); + Error = RegQueryValueEx( Key, Name, NULL, + &Type, (PBYTE)pValue, &Size); + if ( Error == NO_ERROR) { + if ( Type != REG_DWORD || Size != sizeof( DWORD)) { + Error = NERR_RplBadRegistry; + RplDump( ++RG_Assert, ("Type = 0x%x, Value = 0x%x, Size=%d", + Type, *pValue, Size)); + } + } else if (Error == ERROR_FILE_NOT_FOUND) { + Error = NO_ERROR; + *pValue = DefaultValue; + } else { + RplDump( ++RG_Assert, ("Error = %d", Error)); + } + return( Error); +} + + + +DWORD RplRegReadDirectory( + IN HKEY Key, + IN PWCHAR DefaultValue, + OUT PWCHAR DirectoryBuffer, + IN OUT DWORD * pDirectoryBufferSize + ) +{ + WCHAR Buffer[ MAX_PATH]; + PWCHAR Value; + DWORD Length; + DWORD Error; + DWORD Size; + DWORD Type; + + Size = sizeof( Buffer); + Error = RegQueryValueEx( Key, RPL_REGISTRY_DIRECTORY, NULL, + &Type, (PBYTE)Buffer, &Size); + if ( Error == NO_ERROR) { + // + // We have the data. First validate the data, then append the + // backslash if needed. + // + Value = Buffer; + if ( Type != REG_EXPAND_SZ || (Size&1) != 0 || Size < sizeof(L"c:")) { + Error = NERR_RplBadRegistry; + RplDump( ++RG_Assert, ("Type2 = 0x%x, Value = 0x%x, Size=%d", + Type, Value, Size)); + return( Error); + } + Length = Size / sizeof(WCHAR) - 1; + if ( Value[ Length] != 0 || Length != wcslen(Value)) { + Error = NERR_RplBadRegistry; + RplDump( ++RG_Assert, ("Length = %d, Value = 0x%x, Size=%d", + Length, Value, Size)); + return( Error); + } + if ( Value[ Length - 1] != L'\\') { + // + // Need to append the backslash. + // + if ( ( Length + 1) >= MAX_PATH) { + Error = NERR_RplBadRegistry; + RplDump( ++RG_Assert, ("Length = %d, Value = 0x%x, Size=%d", + Length, Value, Size)); + return( Error); // not enough space + } + Value[ Length] = L'\\'; + Value[ ++Length] = 0; + } + } else if ( Error == ERROR_FILE_NOT_FOUND ) { + Value = DefaultValue; + } else { + RplDump( ++RG_Assert, ("Error = %d", Error)); + return( Error); + } + + // + // Length returned by ExpandEnvironmentalStrings includes terminating + // NULL byte. + // + Length = ExpandEnvironmentStrings( Value, DirectoryBuffer, *pDirectoryBufferSize); + if ( Length == 0) { + Error = GetLastError(); + RplDump( ++RG_Assert, ("Error = %d", Error)); + return( Error); + } + if ( Length > (*pDirectoryBufferSize) + || Length > MAX_PATH || Length != wcslen(DirectoryBuffer) + 1) { + Error = NERR_RplBadRegistry; + RplDump( ++RG_Assert, ("Length = %d", Length)); + return( Error); + } + *pDirectoryBufferSize = (DWORD)(Length - 1); + return( NO_ERROR); +} + + + +DWORD RplRegRead( + OUT DWORD * pStartup, + OUT DWORD * pBackupInterval, + OUT DWORD * pMaxThreadCount, + OUT PWCHAR DirectoryBuffer, + IN OUT DWORD * pDirectoryBufferSize + ) +{ + DWORD Error; + HKEY Key; + BOOL HaveKey = FALSE; + + // + // First open the RPL service parameters registry tree. + // + // This will fail if the RPL registry tree is absent, that is, + // if RPL is not installed. + // + Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RPL_REGISTRY_PARAMETERS, + 0, KEY_READ, &Key); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ("Error = %d", Error)); + goto cleanup; + } + HaveKey = TRUE; + + // + // It is OK if values in parameters subtree are absent, but present + // values should be valid. This is why each read routine receives + // default value as the second parameter. + // + + if ( pStartup != NULL) { + Error = RplRegReadValue( Key, RPL_DEFAULT_STARTUP, RPL_REGISTRY_STARTUP, + pStartup); + if ( Error != NO_ERROR) { + goto cleanup; + } + } + + if ( pBackupInterval != NULL) { + Error = RplRegReadValue( Key, RPL_DEFAULT_BACKUP_INTERVAL, + RPL_REGISTRY_BACKUP_INTERVAL, pBackupInterval); + if ( Error != NO_ERROR) { + goto cleanup; + } + // + // Registry contains backup interval in hours, convert it to + // + // + } + + if ( pMaxThreadCount != NULL) { + Error = RplRegReadValue( Key, RPL_DEFAULT_MAX_WORKER_COUNT, + RPL_REGISTRY_THREAD_COUNT, pMaxThreadCount); + if ( Error != NO_ERROR) { + goto cleanup; + } + } + + if ( DirectoryBuffer != NULL && pDirectoryBufferSize != NULL + && (*pDirectoryBufferSize) != 0 ) { + Error = RplRegReadDirectory( Key, RPL_DEFAULT_DIRECTORY, + DirectoryBuffer, pDirectoryBufferSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + } + +cleanup: + if ( HaveKey == TRUE) { + (VOID)RegCloseKey( Key); + } + if ( Error != NO_ERROR) { + RplReportEvent( NELOG_RplRegistry, NULL, sizeof(DWORD), &Error ); + } + return( Error); +} + + +DWORD RplRegSetPolicy( DWORD NewStartup) +{ + DWORD Error; + HKEY Key; + BOOL HaveKey = FALSE; + + // + // First open the RPL service parameters registry tree. + // + // This will fail if the RPL registry tree is absent, that is, + // if RPL is not installed. + // + Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RPL_REGISTRY_PARAMETERS, + 0, KEY_SET_VALUE, &Key); + if ( Error != NO_ERROR){ + RplDump( ++RG_Assert, ("Error = %d", Error)); + goto cleanup; + } + HaveKey = TRUE; + + // + // Now set the Startup value + // + Error = RegSetValueEx( Key, RPL_REGISTRY_STARTUP, 0, + REG_DWORD, (PBYTE)&NewStartup, sizeof(NewStartup)); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ("Error = %d", Error)); + goto cleanup; + } + +cleanup: + if ( HaveKey == TRUE) { + (VOID)RegCloseKey( Key); + } + + if ( Error != NO_ERROR) { + RplReportEvent( NELOG_RplRegistry, NULL, sizeof(DWORD), &Error ); + } + + return( Error); +} + + diff --git a/private/net/svcdlls/rpl/lib/report.c b/private/net/svcdlls/rpl/lib/report.c new file mode 100644 index 000000000..2364ed2e0 --- /dev/null +++ b/private/net/svcdlls/rpl/lib/report.c @@ -0,0 +1,111 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + report.c + +Abstract: + + Contains: + VOID RplReportEvent( + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" + + +VOID RplReportEvent( + IN DWORD MessageId, + IN LPWSTR InsertionString, + IN DWORD RawDataBufferLength OPTIONAL, + IN LPVOID RawDataBuffer + ) +/*++ + +Routine Description: + + Writes an error message and ascii string to the error log. Also, + writes the data in the data buf if there are any. + +Arguments: + + MessageId - Message ID + + InsertionString - at most one asciiz string (may be NULL) + + RawDataBufferLength - size of data to be printed from the auxiliary data + buffer. May be zero, in which case the actual value depends on + "RawDataBuffer". It is 0 if "RawDataBuffer" is NULL, else it is + "sizeof( wchar) * wcslen( RawDataBuffer)". + + RawDataBuffer - data buffer containing secondary error code & some + other useful info. Must be NULL terminated string or NULL if + "RawDataBufferLength" is zero. + +Return Value: + + None. + +--*/ +{ + WORD NumberOfStrings; + LPWSTR InsertionStringArray[ 1]; + LPWSTR * PointerToStrings; + HANDLE logHandle; + + logHandle = RegisterEventSource( NULL, RPL_EVENTLOG_NAME); + + // If the event log cannot be opened, just return. + + if ( logHandle == NULL) { +#ifdef NOT_YET + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( + "ReportEvent: RegisterEventSource() failed with error %d", + GetLastError())); +#endif // NOT_YET + return; + } + + if ( InsertionString == NULL) { + PointerToStrings = NULL; + NumberOfStrings = 0; + } else { + InsertionStringArray[ 0] = InsertionString; + PointerToStrings = InsertionStringArray; + NumberOfStrings = 1; + } + + // + // Use default for RawDataBufferLength if caller requested us so. + // + if ( RawDataBufferLength == 0 && RawDataBuffer != NULL) { + RawDataBufferLength = sizeof( TCHAR) * wcslen( (LPWSTR)RawDataBuffer); + } + + if ( !ReportEvent( + logHandle, + EVENTLOG_ERROR_TYPE, + 0, // event category + MessageId, // event id + NULL, // user SID. We're local system - uninteresting + NumberOfStrings, // number of strings + RawDataBufferLength, // raw data size + PointerToStrings, // string array + RawDataBuffer // raw data buffer + )) { +#ifdef NOT_YET + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( + "ReportEvent: fails with error %d", GetLastError())); +#endif // NOT_YET + } + + DeregisterEventSource( logHandle); +} diff --git a/private/net/svcdlls/rpl/lib/sources b/private/net/svcdlls/rpl/lib/sources new file mode 100644 index 000000000..2be59e4ef --- /dev/null +++ b/private/net/svcdlls/rpl/lib/sources @@ -0,0 +1,36 @@ +MAJORCOMP=net +MINORCOMP=rpllib + +TARGETPATH=obj +TARGETNAME=rpllib +TARGETTYPE=LIBRARY + +TARGETLIBS= \ + $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\wsock32.lib + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +INCLUDES=.;..\inc;..\..\..\inc;..\..\..\api;..\..\..\..\inc; + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + report.c \ + cmdline.c \ + adapter.c \ + tcpip.c \ + jeterror.c \ + reg.c \ + addkey.c + + +C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 + +UMTYPE=console + + diff --git a/private/net/svcdlls/rpl/lib/tcpip.c b/private/net/svcdlls/rpl/lib/tcpip.c new file mode 100644 index 000000000..b45b2f8d3 --- /dev/null +++ b/private/net/svcdlls/rpl/lib/tcpip.c @@ -0,0 +1,68 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tcpip.c + +Abstract: + + Contains: + DWORD FillTcpIpString( OUT PCHAR Buffer, IN DWORD AddressDword) + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "rpllib.h" +#include "winsock.h" // for INADDR_NONE + +DWORD FillTcpIpString( + OUT PCHAR Buffer, + IN DWORD AddressDword + ) +/*++ + AddressDword is in a host byte order. E.g. dword 0x11223344 + corresponds to 11.22.33.44 string. +--*/ +{ + if ( AddressDword == INADDR_NONE) { + strcpy( Buffer, "~ "); + } else { +#ifdef NOT_YET + PBYTE p = (PBYTE)&AddressDword; + // + // For dword 0x11223344 we have p[0] = 44, etc. + // + // We do not do: + // + // ipaddr.s_addr = htonl( AddressDword) + // string = inet_ntoa( ipaddr) + // strcpy( Buffer, string) + // + // because inet_ntoa() allocates buffer for string. + // + sprintf( Buffer, "%d.%d.%d.%d ", p[3], p[2], p[1], p[0]); +#else + struct in_addr InAddr; // Internet address structure + PCHAR String; + + // Convert the host address to network byte order + InAddr.s_addr = htonl( AddressDword); + + // Convert the IP address value to a string + String = inet_ntoa( InAddr) ; + + // Copy the string to our buffer & append a space. + strcpy( Buffer, String); + strcat( Buffer, " "); +#endif + } + return( strlen( Buffer)); +} diff --git a/private/net/svcdlls/rpl/makefil0 b/private/net/svcdlls/rpl/makefil0 new file mode 100644 index 000000000..fc6bb29d7 --- /dev/null +++ b/private/net/svcdlls/rpl/makefil0 @@ -0,0 +1,73 @@ +# +# This is the MIDL compile phase of the build process. +# +# The following is where you put the name of your .idl file without +# the .idl extension: +# + +!INCLUDE $(NTMAKEENV)\makefile.plt + +IDL_NAME = rplsvc +CLIENT_H = rplsvc_c.h +SERVER_H = rplsvc_s.h +CLIENT_ACF = rplsvc_c.acf +SERVER_ACF = rplsvc_s.acf + +!IFNDEF BASEDIR +BASEDIR=\nt +!ENDIF + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +SDKINC = $(BASEDIR)\public\sdk\inc +NETINC = $(BASEDIR)\private\net\inc +SDKCRTINC = $(BASEDIR)\public\sdk\inc\crt +PRIVINC = $(BASEDIR)\private\inc +RPLINC = inc +INCS = -I$(SDKINC) -I$(SDKCRTINC) -I$(PRIVINC) -I$(NETINC) -I$(RPLINC) + +CLIENT_TARGETS = client\$(IDL_NAME)_c.c client\$(CLIENT_H) +SERVER_TARGETS = server\$(IDL_NAME)_s.c server\$(SERVER_H) +TARGETS = $(CLIENT_TARGETS) $(SERVER_TARGETS) + +EXTRN_DEPENDS = $(SDKINC)\lmcons.h \ + $(SDKINC)\windef.h \ + $(SDKINC)\lmrpl.h \ + inc\i_lmrpl.h \ + inc\imports.h + +CLIENT_FLAGS = -acf $(CLIENT_ACF) -header $(CLIENT_H) -oldnames +SERVER_FLAGS = -acf $(SERVER_ACF) -header $(SERVER_H) -oldnames + +CPP = -cpp_cmd "$(MIDL_CPP)" $(MIDL_FLAGS) $(C_DEFINES) $(NET_C_DEFINES) + +# +# Define Products and Dependencies +# + +all: $(TARGETS) $(EXTRN_DEPENDS) +!IF "$(BUILDMSG)" != "" + @ech ; $(BUILDMSG) ; +!ENDIF + +clean: delsrc all + +delsrc: + erase $(CLIENT_TARGETS) $(SERVER_TARGETS) + +# +# MIDL COMPILE +# + +$(CLIENT_TARGETS) : .\$(IDL_NAME).idl $(EXTRN_DEPENDS) .\$(CLIENT_ACF) + midl -Oi -server none -error allocation -error ref -ms_ext -c_ext $(CPP) $(CLIENT_FLAGS) .\$(IDL_NAME).idl $(INCS) + IF EXIST $(IDL_NAME)_c.c copy $(IDL_NAME)_c.c .\client & del $(IDL_NAME)_c.c + IF EXIST $(CLIENT_H) copy $(CLIENT_H) .\client & del $(CLIENT_H) + +$(SERVER_TARGETS) : .\$(IDL_NAME).idl $(EXTRN_DEPENDS) .\$(SERVER_ACF) + midl -client none -error stub_data -error allocation -error ref -ms_ext -c_ext $(CPP) $(SERVER_FLAGS) .\$(IDL_NAME).idl $(INCS) + IF EXIST $(IDL_NAME)_s.c copy $(IDL_NAME)_s.c .\server & del $(IDL_NAME)_s.c + IF EXIST $(SERVER_H) copy $(SERVER_H) .\server & del $(SERVER_H) diff --git a/private/net/svcdlls/rpl/makefile b/private/net/svcdlls/rpl/makefile new file mode 100644 index 000000000..d30e64184 --- /dev/null +++ b/private/net/svcdlls/rpl/makefile @@ -0,0 +1,12 @@ +# BUGBUG This makefile is needed so that build.exe would not report an +# BUGBUG a bogus error. There is probably a better way to achieve this. +# ( The bogus error is reported when linking rpl directory: +# NMAKE U1064: MAKEFILE not found & no target specified ) +# + +all: +!IF "$(BUILDMSG)" != "" + @ech ; $(BUILDMSG) ; +!ENDIF + +clean: all diff --git a/private/net/svcdlls/rpl/rplcnv/local.h b/private/net/svcdlls/rpl/rplcnv/local.h new file mode 100644 index 000000000..b5e032c06 --- /dev/null +++ b/private/net/svcdlls/rpl/rplcnv/local.h @@ -0,0 +1,64 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + local.h + +Abstract: + + Main include file for RPLSTART + +Author: + + Jon Newman (jonn) 12 - January - 1994 + +Revision History: + +--*/ + +#include <nt.h> // ntexapi.h\NtQuerySystemTime +#include <ntrtl.h> // RtlTimeToSecondsSince1970 +#include <nturtl.h> + +#include <windows.h> // DWORD, IN, File APIs, etc. +#include <stdlib.h> +#include <lmcons.h> + +#include <stdio.h> // vsprintf +#include <ctype.h> // isspace + +#include <lmerr.h> // NERR_RplBootStartFailed - used to be here + +// +#include <lmapibuf.h> // NetApiBufferFree +#include <netlib.h> + +#include <lmsvc.h> + +#include <lmalert.h> // STD_ALERT ALERT_OTHER_INFO + +#include <lmerrlog.h> +#include <alertmsg.h> +#include <lmserver.h> +#include <netlib.h> +#include <netlock.h> // Lock data types, functions, and macros. +#include <thread.h> // FORMAT_NET_THREAD_ID, NetpCurrentThread(). + +#include <lmshare.h> // PSHARE_INFO_2 +#include <lmaccess.h> // NetGroupGetInfo +#include <lmconfig.h> // NetConfigGet +#include <nb30.h> // NCB + +// +// Global types and constants (used in all RPL server files). +// + +#include <riplcons.h> // includes __JET500 flag +#include <jet.h> +#include <rpllib.h> // AddKey(), MapJetError(), FillTcpIpString() + +#include <rpldb.h> + +#include "rplmgrd.h" diff --git a/private/net/svcdlls/rpl/rplcnv/makefile b/private/net/svcdlls/rpl/rplcnv/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/rpl/rplcnv/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/rplcnv/rplcnv.c b/private/net/svcdlls/rpl/rplcnv/rplcnv.c new file mode 100644 index 000000000..218f90581 --- /dev/null +++ b/private/net/svcdlls/rpl/rplcnv/rplcnv.c @@ -0,0 +1,37 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + rplcnv.c + +Abstract: + + Converts old style (OS/2) files RPL.MAP & RPLMGR.INI + into a new style database to be used with NT rpl server. + +Author: + + Jon Newman (jonn) 02 - February - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#define RPLDATA_ALLOCATE +#include "local.h" +#undef RPLDATA_ALLOCATE + + +DWORD _CRTAPI1 main ( VOID) +{ + I_NetRplCmd_ConvertDatabase( NULL); + + return( ERROR_SUCCESS); +} + diff --git a/private/net/svcdlls/rpl/rplcnv/sources b/private/net/svcdlls/rpl/rplcnv/sources new file mode 100644 index 000000000..c298a8272 --- /dev/null +++ b/private/net/svcdlls/rpl/rplcnv/sources @@ -0,0 +1,27 @@ +MAJORCOMP=net +MINORCOMP=rplcnv + +TARGETPATH=obj +TARGETNAME=rplcnv +TARGETTYPE=PROGRAM + +TARGETLIBS= \ + ..\convert\obj\*\rplmgrd.lib + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +INCLUDES=.;..\inc;..\..\..\inc;..\..\..\api;..\..\..\..\inc; + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + rplcnv.c + + +C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 -DRPL_RPLCNV + +UMTYPE=console + diff --git a/private/net/svcdlls/rpl/rplinst/debug.c b/private/net/svcdlls/rpl/rplinst/debug.c new file mode 100644 index 000000000..468b04969 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/debug.c @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + debug.c + +Abstract: + + Debugging module. RpldDebugPrint() was adapted from TelnetDebugPrint() + in net\sockets\tcpcmd\telnet\debug.c. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "debug.h" + +#ifdef RPL_DEBUG + +#define RPL_PROMPT "[Rpl] " +#define DEBUG_RECORD_SIZE 0x80 +#define DEBUG_BUFFER_SIZE 0x20000 // 2*64k, must be a power of 2 +#define DEBUG_BUFFER_MASK (DEBUG_BUFFER_SIZE - 1) + +// int RG_DebugLevel = -1; // max debugging +// int RG_DebugLevel = 0; // no debugging, for public use + +int RG_DebugLevel; // needed by other modules +int RG_Assert; // needed by other modules + +PCHAR RG_DebugBuffer; +CRITICAL_SECTION RG_ProtectDebug; +DWORD RG_DebugOffset; +// +// This buffer is used even when RG_DebugBuffer is not NULL. +// +char RG_DebugPublicBuffer[ 120]; + + +VOID RplDebugDelete( VOID) +{ + if ( RG_DebugBuffer != NULL) { + (VOID)GlobalFree( RG_DebugBuffer); + } + DeleteCriticalSection( &RG_ProtectDebug); +} + +#define RPL_DEFAULT_DEBUG_LEVEL ( RPL_DEBUG_FLOW | \ + RPL_DEBUG_SERVER | \ + RPL_DEBUG_MAJOR ) + +#define RPL_MAXIMUM_DEBUG_LEVEL (-1L) + + + +VOID RplDebugInitialize( VOID) +{ + // + // Set RG_Assert to 0. Without this the very first use of + // RplDump() will lead to an assert. + // + RG_Assert = 0; + +// RG_DebugLevel = RPL_DEFAULT_DEBUG_LEVEL; + RG_DebugLevel = RPL_MAXIMUM_DEBUG_LEVEL & ~RPL_DEBUG_MEMALLOC + & ~RPL_DEBUG_FLOWINIT & ~RPL_DEBUG_FDR & ~RPL_DEBUG_SFR; +// RG_DebugLevel = RPL_MAXIMUM_DEBUG_LEVEL; + + + RG_DebugBuffer = (PCHAR)GlobalAlloc( + GMEM_FIXED, + DEBUG_BUFFER_SIZE + DEBUG_RECORD_SIZE + ); + if ( RG_DebugBuffer != NULL) { + RtlFillMemory( + RG_DebugBuffer, + DEBUG_BUFFER_SIZE + DEBUG_RECORD_SIZE, + '*' + ); + RG_DebugOffset = 0; + } + memcpy( RG_DebugPublicBuffer, RPL_PROMPT, sizeof( RPL_PROMPT) -1); + + InitializeCriticalSection( &RG_ProtectDebug); +} + + +VOID _CRTAPI1 RplDebugPrint( CONST CHAR * format, ...) +{ + va_list arglist; + + va_start( arglist, format); + + EnterCriticalSection( &RG_ProtectDebug); + + if ( RG_Assert == 0 && RG_DebugBuffer != NULL) { + RtlZeroMemory( RG_DebugBuffer + RG_DebugOffset, DEBUG_RECORD_SIZE); + vsprintf( RG_DebugBuffer + RG_DebugOffset, format, arglist); + RG_DebugOffset += DEBUG_RECORD_SIZE; + RG_DebugOffset &= DEBUG_BUFFER_MASK; + } else { + vsprintf( RG_DebugPublicBuffer + sizeof( RPL_PROMPT) - 1, format, arglist); + DbgPrint( "%s\n", RG_DebugPublicBuffer); + } + + if ( RG_Assert != 0) { + ASSERT( FALSE); // break for checked build + KdPrint(( "[RplSvc] Running checked version of service on a free build.\n")); + } + while ( RG_Assert != 0) { + KdPrint(( "[RplSvc] Debug, then reset RG_Assert to 0.\n")); + DbgUserBreakPoint(); + Sleep( RG_Assert * 30000); // sleep for 30 seconds + } + + LeaveCriticalSection( &RG_ProtectDebug); + + va_end( arglist); + +} // RplDebugPrint + + +#endif // RPL_DEBUG + + + diff --git a/private/net/svcdlls/rpl/rplinst/debug.h b/private/net/svcdlls/rpl/rplinst/debug.h new file mode 100644 index 000000000..31706c1fe --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/debug.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + debug.h + +Abstract: + + Exports from debug.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#ifdef RPL_DEBUG +VOID RplDebugInitialize( VOID); +VOID RplDebugDelete( VOID); +#endif // RPL_DEBUG diff --git a/private/net/svcdlls/rpl/rplinst/local.h b/private/net/svcdlls/rpl/rplinst/local.h new file mode 100644 index 000000000..ebdc7068b --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/local.h @@ -0,0 +1,77 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + local.h + +Abstract: + + Main include file for RPLINST + +Author: + + Jon Newman (jonn) 12 - January - 1994 + +Revision History: + +--*/ + +#include <nt.h> // ntexapi.h\NtQuerySystemTime +#include <ntrtl.h> // RtlTimeToSecondsSince1970 +#include <nturtl.h> + +#include <windows.h> // DWORD, IN, File APIs, etc. +#include <stdlib.h> +#include <lmcons.h> + +#include <stdio.h> // vsprintf +#include <ctype.h> // isspace + +#include <lmerr.h> // NERR_RplBootStartFailed - used to be here + +// +#include <lmapibuf.h> // NetApiBufferFree +#include <netlib.h> + +#include <lmsvc.h> + +#include <lmalert.h> // STD_ALERT ALERT_OTHER_INFO + +#include <lmerrlog.h> +#include <alertmsg.h> +#include <lmserver.h> +#include <netlib.h> +#include <netlock.h> // Lock data types, functions, and macros. +#include <thread.h> // FORMAT_NET_THREAD_ID, NetpCurrentThread(). + +#include <lmshare.h> // PSHARE_INFO_2 +#include <lmaccess.h> // NetGroupGetInfo +#include <lmconfig.h> // NetConfigGet +#include <nb30.h> // NCB + +// +// Global types and constants (used in all RPL server files). +// + +#include <riplcons.h> // includes __JET500 flag +#include <jet.h> +#include <rpllib.h> // AddKey(), MapJetError(), FillTcpIpString() + +#include <rpldb.h> +#include <rpldebug.h> + +#include "rplmgrd.h" +#include "nlstxt.h" + +#include <lmshare.h> + +#define RPLFILES_STRING L"RPLFILES" +#define RPL_SERVICE_NAME L"RemoteBoot" +#define RPL_REMARK L"RemoteBoot service share" + +#define RPL_BUGBUG_ERROR 10999 // need to get rid of these + +WCHAR RG_Directory[ PATHLEN+1]; // path to rpl service disk data +DWORD RG_DirectoryLength; // length of the above path diff --git a/private/net/svcdlls/rpl/rplinst/makefile b/private/net/svcdlls/rpl/rplinst/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/rplinst/makefile.inc b/private/net/svcdlls/rpl/rplinst/makefile.inc new file mode 100644 index 000000000..f1d8b42fd --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/makefile.inc @@ -0,0 +1,8 @@ +# templated from portuas JonN 1/14/94 +nlstxt.mc: rplimsg.h + mapmsg -p RPLI RPLI_BASE rplimsg.h > nlstxt.mc + +rplinst.rc: nlstxt.rc msg00001.bin + +nlstxt.h nlstxt.rc msg00001.bin: nlstxt.mc + mc -v nlstxt.mc diff --git a/private/net/svcdlls/rpl/rplinst/querydir.c b/private/net/svcdlls/rpl/rplinst/querydir.c new file mode 100644 index 000000000..64e9596c1 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/querydir.c @@ -0,0 +1,136 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + querydir.c + +Abstract: + + Contains I_NetRpl_QueryDirectory + +Author: + + Jon Newman 13 - January - 1994 + +Environment: + + User mode + +Revision History : + +--*/ + +#define RPLDATA_ALLOCATE +#include "local.h" +#undef RPLDATA_ALLOCATE + + +#define RPL_REGISTRY_PARAMETERS L"System\\CurrentControlSet\\Services\\RemoteBoot\\Parameters" +#define RPL_REGISTRY_DIRECTORY L"Directory" +#define RPL_DEFAULT_DIRECTORY L"%SystemRoot%\\rpl\\" + +// BUGBUG server\rplmain.c should call this routine + + +DWORD I_NetRpl_QueryDirectory( OUT LPWSTR pchFilePath, + OUT LPDWORD pcchFilePathLength) +{ + DWORD Error; + BYTE Buffer[ (PATHLEN + 1) * sizeof(WCHAR)]; + PWCHAR Value; + HKEY Key; + DWORD Length; + DWORD Type; + DWORD Size; + + // RPL_ASSERT( pchFilePath != NULL); + + // + // First open the RPL service parameters registry tree. + // + Error = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + RPL_REGISTRY_PARAMETERS, + 0, + KEY_READ, + &Key + ); + if (Error != ERROR_SUCCESS){ + // RplDump( ++RG_Assert, ("Error = %d", Error)); + return( Error); + } + // Length = sizeof( Buffer); This is totally wrong! Has Rl Server been + // using the default value this whole time? + // Length = sizeof( Buffer); + Size = sizeof( Buffer); + Error = RegQueryValueEx( + Key, + RPL_REGISTRY_DIRECTORY, + NULL, + &Type, + Buffer, + &Size + ); + (VOID)RegCloseKey( Key); + if ( Error == NO_ERROR) { + // + // We have the data. First validate the data, then append the + // backslash if needed. + // + Value = (PWCHAR)Buffer; + if ( Type != REG_EXPAND_SZ || (Size&1) != 0 || Size < sizeof(L"c:")) { + // RplDump( ++RG_Assert, ("Type = 0x%x, Value = 0x%x, Size=%d", + // Type, Value, Size)); + return( RPL_BUGBUG_ERROR); + } + Length = Size / sizeof(WCHAR) - 1; + if ( Value[ Length] != 0 || Length != wcslen(Value)) { + // RplDump( ++RG_Assert, ("Length = %d, Value = 0x%x, Size=%d", + // Length, Value, Size)); + return( RPL_BUGBUG_ERROR); + } + if ( Value[ Length - 1] != L'\\') { + // + // Need to append the backslash. + // + if ( Length >= PATHLEN) { + // RplDump( ++RG_Assert, ("Length = %d, Value = 0x%x, Size=%d", + // Length, Value, Size)); + return( RPL_BUGBUG_ERROR); // not enough space + } + Value[ Length] = L'\\'; + Value[ ++Length] = 0; + } + } else { + Value = RPL_DEFAULT_DIRECTORY; + } + + // + // Length returned by ExpandEnvironmentalStrings includes terminating + // NULL byte. + // + // This code was wrong!! The third parameter to ExpandEnvironmentStrings + // should be a character count, not a byte count. + // + // Length = ExpandEnvironmentStrings( Value, RG_Directory, sizeof( RG_Directory)); + Length = ExpandEnvironmentStrings( Value, pchFilePath, PATHLEN+1); + if ( Length == 0) { + Error = GetLastError(); + // RplDump( ++RG_Assert, ("Error = %d", Error)); + return( Error); + } + if ( Length > PATHLEN+1) { + // RplDump( ++RG_Assert, ("Length = %d", Length)); + return( RPL_BUGBUG_ERROR); + } + if ( Length != wcslen( pchFilePath) + 1) { + // RplDump( ++RG_Assert, ("Length = %d", Length)); + return( RPL_BUGBUG_ERROR); + } + if (pcchFilePathLength != NULL) { + *pcchFilePathLength = (DWORD)(Length - 1); + } + return( NO_ERROR); +} diff --git a/private/net/svcdlls/rpl/rplinst/rplimsg.h b/private/net/svcdlls/rpl/rplinst/rplimsg.h new file mode 100644 index 000000000..f66f2c940 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/rplimsg.h @@ -0,0 +1,55 @@ +#define RPLI_BASE 11000 /* RPLI Messages start here */ +#define RPLI_MAX 11999 /* RPLI Messages end here */ + +#define RPLI_CreatingShare (RPLI_BASE + 0) + /* + *Creating RPLFILES share... + */ +#define RPLI_ErrorCreatingShare (RPLI_BASE + 1) + /* + *Error creating RPLFILES share:%n%1!ls! + */ +#define RPLI_ConfiguringService (RPLI_BASE + 2) + /* + *Making RPL service autostart... + */ +#define RPLI_ErrorConfiguringService (RPLI_BASE + 3) + /* + *Error making RPL service autostart:%n%1!ls! + */ +#define RPLI_RPLINSTcomplete (RPLI_BASE + 4) + /* + *RPLINST completed successfully! + */ +#define RPLI_ErrorReadingRPLDirectory (RPLI_BASE + 5) + /* + *The registry key RPL\\Parameters value Directory could not be read due to the following error:%n%1!ls! + */ +#define RPLI_ErrorReadingString (RPLI_BASE + 6) + /* + *Could not read string + */ +#define RPLI_SettingPermissions (RPLI_BASE + 7) + /* + *Making RPL service autostart... + */ +#define RPLI_ErrorSettingPermissions (RPLI_BASE + 8) + /* + *The file permissions on the RPL file tree could not be set due to the following error:%n%1!ls! + */ +#define RPLI_CreatingRPLUSER (RPLI_BASE + 9) + /* + *Creating the RPLUSER group... + */ +#define RPLI_ErrorCreatingRPLUSER (RPLI_BASE + 10) + /* + *The RPLUSER group could not be created due to the following error:%n%1!ls! + */ +#define RPLI_CheckingWkstaAccts (RPLI_BASE + 11) + /* + *Checking the workstation accounts... + */ +#define RPLI_ErrorCheckingWkstaAccts (RPLI_BASE + 12) + /* + *The following error occurred checking the workstation accounts:%n%1!ls! + */ diff --git a/private/net/svcdlls/rpl/rplinst/rplinst.c b/private/net/svcdlls/rpl/rplinst/rplinst.c new file mode 100644 index 000000000..38c018a30 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/rplinst.c @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + rplinst.c + +Abstract: + + Secondary setup activity, including + + Establish RPLFILES share + + Set up permissions on RPLFILES tree + + BUGBUG Should polish and make WIN32 application out of this. + +Author: + + Jon Newman (jonn) 13 - January - 1994 + +Environment: + + User mode + +Revision History : + +--*/ + +#define RPLDATA_ALLOCATE +#include "local.h" +#undef RPLDATA_ALLOCATE + +#include "security.h" + +WCHAR RG_Directory[ PATHLEN+1]; +DWORD RG_DirectoryLength; + + +DWORD _CRTAPI1 main ( VOID) +{ + DWORD dwErr = NO_ERROR; + RPL_HANDLE hRpl = NULL; + WCHAR awchBase[ MAX_PATH ]; + + dwErr = I_NetRpl_QueryDirectory( RG_Directory, &RG_DirectoryLength); + if ( dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorReadingRPLDirectory, dwErr); + goto cleanup; + } + + I_NetRplCmd_WriteMessage( STDOUT, RPLI_CreatingRPLUSER); + + dwErr = RplAddRPLUSERGroup(); + if (dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorCreatingRPLUSER, dwErr); + goto cleanup; + } + + dwErr = NetRplOpen( NULL, &hRpl ); + if (dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorCheckingWkstaAccts, dwErr); + goto cleanup; + } + + I_NetRplCmd_WriteMessage( STDOUT, RPLI_CheckingWkstaAccts); + + dwErr = RplCheckWkstaAccounts( hRpl ); + if (dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorCheckingWkstaAccts, dwErr); + goto cleanup; + } + + I_NetRplCmd_WriteMessage( STDOUT, RPLI_SettingPermissions); + + ASSERT( RG_DirectoryLength < MAX_PATH ); + ASSERT( RG_DirectoryLength == lstrlenW(RG_DirectoryLength) ); + ASSERT( RG_Directory[ RG_DirectoryLength-1 ] == L'\\' ); + lstrcpyW( awchBase, RG_Directory ); + awchBase[ RG_DirectoryLength-1 ] = L'\0'; + + dwErr = RplSetPermsOnTree( awchBase ); + if (dwErr != NO_ERROR) { + I_NetRplCmd_WriteError( STDERR, RPLI_ErrorSettingPermissions, dwErr); + goto cleanup; + } + + I_NetRplCmd_WriteMessage( STDOUT, RPLI_RPLINSTcomplete); + +cleanup: + + if (hRpl != NULL) { + NetRplClose( hRpl ); + } + + return( dwErr); +} + + +// +// allows us to use original security.c code +// +NET_API_STATUS NET_API_FUNCTION +MyNetrRplWkstaEnum( + IN RPL_HANDLE ServerHandle, + IN LPWSTR ProfileName, + IN OUT LPRPL_WKSTA_ENUM WkstaEnum, + IN DWORD PrefMaxLength, + OUT LPDWORD TotalEntries, + OUT LPDWORD pResumeHandle OPTIONAL + ) +/*++ + For more extensive comments see related code in NetrConfigEnum. +--*/ +{ + DWORD EntriesRead = 0; + LPBYTE Buffer = NULL; + DWORD Error = NO_ERROR; + // Error = NetApiBufferAllocate( 4096, &Buffer); + + Error = NetRplWkstaEnum( ServerHandle, + ProfileName, + WkstaEnum->Level, + (LPBYTE *)&(WkstaEnum->WkstaInfo.Level0->Buffer), + PrefMaxLength, + &(WkstaEnum->WkstaInfo.Level0->EntriesRead), + TotalEntries, + pResumeHandle ); + + return( Error); +} + +void __RPC_API MyMIDL_user_free( void __RPC_FAR * pv ) +{ + NetApiBufferFree( pv ); +} diff --git a/private/net/svcdlls/rpl/rplinst/rplinst.rc b/private/net/svcdlls/rpl/rplinst/rplinst.rc new file mode 100644 index 000000000..dbaf0b6f0 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/rplinst.rc @@ -0,0 +1,14 @@ +/* templated from portuas JonN 1/14/94 */ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "RPLINST Utility" +#define VER_INTERNALNAME_STR "rplinst.exe" +#define VER_ORIGINALFILENAME_STR "rplinst.exe" + +#include "common.ver" + +1 11 MSG00001.bin diff --git a/private/net/svcdlls/rpl/rplinst/security.c b/private/net/svcdlls/rpl/rplinst/security.c new file mode 100644 index 000000000..a064309f9 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/security.c @@ -0,0 +1,1567 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + security.c + +Abstract: + + Security addons to the tree-manipulation module + for the RPL service. + +Author: + + Jon Newman (jonn) 16 - February - 1994 + +Revision History: + + Jon Newman (jonn) 16 - February - 1994 + Added RplGrant*Perms primitives + + CODEWORK: Should have more sophisticated error handling + +--*/ + + +#include "local.h" +#include "tree.h" +#include "treei.h" +#include "security.h" +#include <ntseapi.h> +#include <ntrtl.h> // RtlAllocateAndInitializeSid +#include <ntlsa.h> +#include <ntsam.h> +#include <nturtl.h> // see IsNTFS + + +typedef enum _RPL_SD_BLOCK_TYPE { + + RPL_SD_BLOCK_TYPE_ADMINONLY = 0,// Only RPLADMIN gets access + + RPL_SD_BLOCK_TYPE_ALLUSERS, // RPLADMIN gets full access, RPLUSER + // gets RX access + + RPL_SD_BLOCK_TYPE_ONEUSER, // RPLADMIN gets full access, one + // wksta account gets RWXCDA access + + RPL_SD_BLOCK_TYPE_BADUSER // Skip setting permissions on this user +} RPL_SD_BLOCK_TYPE; + +/* + * This is the block of information which is retained between the recursive + * calls in a single RplDoTree run. It remembers the SECURITY_DESCRIPTOR + * which was assigned to the last file/directory, so if the next + * file/directory wants the same permissions (as is usually the case) + * we do not have to fetch everything all over again. It also contains + * some information about what kind of SECURITY_DESCRIPTOR is currently + * stored, plus items needed to get a different SECURITY_DESCRIPTOR. + */ +typedef struct _RPL_SD_BLOCK { + PSECURITY_DESCRIPTOR psd; + RPL_SD_BLOCK_TYPE nChangeableAceType; + PSID psidSystem; + PSID psidAdministrators; + PSID psidSystemOperators; + PSID psidRPLUSER; + PSID psidGrantTo; // SID of account with name pwszGrantToName + PWCHAR pwszGrantToName; + // Name of account for BLOCK_TYPE_ONEUSER + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain; + SAM_HANDLE hsamAccountDomain; +} RPL_SD_BLOCK, *PRPL_SD_BLOCK; + +// +// The DACL we assign to files has 3 or 4 ACEs. +// +#define RPL_INDEX_SYSTEM_ACE 0 +#define RPL_INDEX_ADMINS_ACE 1 +#define RPL_INDEX_RPLADMIN_ACE 2 +#define RPL_INDEX_CHANGEABLE_ACE 3 + + +// +// Forward declarations +// + +DWORD SetRplPerms( + IN PWCHAR pwszPath, + IN OUT PVOID * ppv); + +DWORD GetSdForFile( + OUT PSECURITY_DESCRIPTOR * ppsd, + IN OUT RPL_SD_BLOCK ** ppsdblock, + IN PWCHAR pwszFile, + OUT BOOL * pfSkipPermsOnFile + ); + +DWORD GetSd( + OUT PSECURITY_DESCRIPTOR * ppsd, + IN OUT RPL_SD_BLOCK ** ppsdblock, + IN RPL_SD_BLOCK_TYPE nChangeableAceType, + IN PWCHAR pwszGrantTo + ); + +DWORD AddInheritableAce( + IN OUT ACL * pacl, + IN ACCESS_MASK mask, + IN SID * psid ); + +DWORD InitSdBlock( + OUT RPL_SD_BLOCK ** ppsdblock + ); + +VOID FreeSdBlock( + IN RPL_SD_BLOCK ** ppsdblock + ); + +DWORD GetAccountDomain( + OUT SAM_HANDLE * phsamAccountDomain, + OUT POLICY_ACCOUNT_DOMAIN_INFO ** ppinfoAccountDomain, + IN ACCESS_MASK DesiredAccess + ); + +DWORD GetAccountSid( + IN SAM_HANDLE hsamAccountDomain, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN WCHAR * pwszAccountName, + OUT PSID * ppsidAccountSid, + IN BOOL fIsLocalgroup, + OUT DWORD * pulRid OPTIONAL + ); + +DWORD IsNTFS( + IN WCHAR * pszResource, + OUT BOOL * pfIsNTFS ); + +DWORD RplAddWkstaAccount( LPWSTR pszWkstaName, + SAM_HANDLE hsamAccountDomain, + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + SAM_HANDLE hsamRPLUSER ); + +VOID FillUnicodeString( PUNICODE_STRING punistr, + LPWSTR lpwsz ); + +DWORD MyBuildSid( OUT PSID * ppsidAccountSid, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN ULONG ulRid ); + +VOID MyFreeSid( IN OUT PSID * ppsid ); + + +/* + * Like RplTreeCopy, but also sets permissions on target files/directories. + * Target must be in %RplRoot% subtree. + * + * CODEWORK do something with error buffer + */ +DWORD RplTreeCopyAndSetPerms( + IN PWCHAR pwszSource, + IN PWCHAR pwszTarget ) +{ + WCHAR Buffer[ 300]; + DWORD Error = NO_ERROR; + PVOID pv = NULL; + DWORD Flags = RPL_TREE_COPY | RPL_TREE_AUXILIARY; + BOOL fIsNTFS = TRUE; + + // + // Check if volume is NTFS, if so never mind about ACLs + // + + Error = IsNTFS( pwszTarget, &fIsNTFS ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } else if (!fIsNTFS) { + Flags &= ~RPL_TREE_AUXILIARY; + } + + Buffer[ 0] = 0; + Error = RplDoTree( pwszSource, pwszTarget, + Flags, + Buffer, sizeof(Buffer), + SetRplPerms, &pv); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( pv != NULL) { + FreeSdBlock( (RPL_SD_BLOCK **)(&pv) ); + } + + return( Error); +} + + +/* + * Sets permissions on a file tree. + * Target must be in %RplRoot% subtree. + * + * CODEWORK do something with error buffer + */ +DWORD RplSetPermsOnTree( + IN PWCHAR pwszSource ) +{ + WCHAR Buffer[ 300]; + DWORD Error = NO_ERROR; + PVOID pv = NULL; + BOOL fIsNTFS = TRUE; + + // + // Check if volume is NTFS, if so do nothing + // + + Error = IsNTFS( pwszSource, &fIsNTFS ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } else if (!fIsNTFS) { + goto cleanup; + } + + Buffer[ 0] = 0; + Error = RplDoTree( pwszSource, NULL, + RPL_TREE_AUXILIARY, + Buffer, sizeof(Buffer), + SetRplPerms, &pv); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( pv != NULL) { + FreeSdBlock( (RPL_SD_BLOCK **)(&pv) ); + } + + return( Error); +} + + +/* + * This is the callback routine called by RplDoTree to set permissions + * on a specific file/directory. + */ +DWORD SetRplPerms( + IN PWCHAR pwszPath, + IN OUT PVOID * ppv) +{ + DWORD Error = NO_ERROR; + RPL_SD_BLOCK ** ppsdblock = (RPL_SD_BLOCK **)ppv; + PSECURITY_DESCRIPTOR psd = NULL; + BOOL fSkipPermsOnFile = FALSE; + + RPL_ASSERT( pwszPath != NULL ); + RPL_ASSERT( ppv != NULL ); + + Error = GetSdForFile( &psd, ppsdblock, pwszPath, &fSkipPermsOnFile ); + if (Error != NO_ERROR || fSkipPermsOnFile) { + goto cleanup; + } + + RPL_ASSERT( psd != NULL ); + + // + // Set the actual file security. Note that this call will succeed + // even if the volume is not NTFS, thus we must check for + // partition type elsewhere. + // + + if ( !SetFileSecurity( pwszPath, DACL_SECURITY_INFORMATION, psd)) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + return( Error); +} + + +/* + * Get the SECURITY_DESCRIPTOR which is appropriate for a file/directory + * at this position in %RplRoot%. First we determine what kind of + * SECURITY_DESCRIPTOR we want, then we call GetSd() to build it. + */ +DWORD GetSdForFile( + OUT PSECURITY_DESCRIPTOR * ppsd, + IN OUT RPL_SD_BLOCK ** ppsdblock, + IN PWCHAR pwszFile, + OUT BOOL * pfSkipPermsOnFile + ) +{ + DWORD Error = NO_ERROR; + PWCHAR pwszRelativeFile = NULL; + PWCHAR pwszWkstaNameStart = NULL; + PWCHAR pwszWkstaNameEnd = NULL; + RPL_SD_BLOCK_TYPE blocktype = RPL_SD_BLOCK_TYPE_ADMINONLY; + WCHAR awchFile[MAX_PATH]; + WCHAR wchSave, wchSave2; + DWORD cch; + + RPL_ASSERT( ppsd != NULL ); + RPL_ASSERT( ppsdblock != NULL ); + RPL_ASSERT( pwszFile != NULL ); + RPL_ASSERT( pfSkipPermsOnFile != NULL ); + RPL_ASSERT( lstrlenW(pwszFile) >= (INT)RG_DirectoryLength ); + RPL_ASSERT( lstrlenW(pwszFile) < MAX_PATH ); + RPL_ASSERT( RG_DirectoryLength > 0 && RG_DirectoryLength < MAX_PATH ); + + *pfSkipPermsOnFile = FALSE; + + // + // Make working copy of pwszFile + // + if (NULL == lstrcpy(awchFile,pwszFile)) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Ensure that awchFile starts with RG_Directory + // + // RG_Directory always ends with L'\\'. awchFile might be equal to + // RG_Directory without the L'\\', we must handle this. + // + wchSave = awchFile[RG_DirectoryLength]; + wchSave2 = awchFile[RG_DirectoryLength-1]; + if (lstrlenW(awchFile) == (int)RG_DirectoryLength-1) { + awchFile[RG_DirectoryLength-1] = L'\\'; + } + awchFile[RG_DirectoryLength] = L'\0'; + if ( 0 != lstrcmpi( awchFile, + RG_Directory )) { + RPL_ASSERT( FALSE ); + Error = ERROR_INVALID_PARAMETER; + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + awchFile[RG_DirectoryLength] = wchSave; + awchFile[RG_DirectoryLength-1] = wchSave2; + + pwszRelativeFile = awchFile + RG_DirectoryLength; + + // + // If the path is in rplfiles\binfiles or rplfiles\profiles, + // set the changeable ACE to RPLUSER + // + + cch = lstrlenW(L"RPLFILES\\BINFILES"); + wchSave = pwszRelativeFile[ cch ]; + pwszRelativeFile[ cch ] = L'\0'; + if ( 0 == lstrcmpi( pwszRelativeFile, L"RPLFILES\\BINFILES") ) { + blocktype = RPL_SD_BLOCK_TYPE_ALLUSERS; + goto cleanup; + } + pwszRelativeFile[ cch ] = wchSave; + + cch = lstrlenW(L"RPLFILES\\PROFILES"); + wchSave = pwszRelativeFile[ cch ]; + pwszRelativeFile[ cch ] = L'\0'; + if ( 0 == lstrcmpi( pwszRelativeFile, L"RPLFILES\\PROFILES") ) { + blocktype = RPL_SD_BLOCK_TYPE_ALLUSERS; + goto cleanup; + } + pwszRelativeFile[ cch ] = wchSave; + + // + // If the path is in rplfiles\machines\* or rplfiles\tmpfiles\*, + // set the changeable ACE to the individual workstation account + // + cch = lstrlenW(L"RPLFILES\\MACHINES\\"); + wchSave = pwszRelativeFile[ cch ]; + pwszRelativeFile[ cch ] = L'\0'; + if ( 0 == lstrcmpi( pwszRelativeFile, L"RPLFILES\\MACHINES\\") ) { + pwszRelativeFile[ cch ] = wchSave; + blocktype = RPL_SD_BLOCK_TYPE_ONEUSER; + pwszWkstaNameStart = pwszWkstaNameEnd = pwszRelativeFile + cch; + while (*pwszWkstaNameEnd != L'\\' && *pwszWkstaNameEnd != L'\0') { + pwszWkstaNameEnd++; + } + *pwszWkstaNameEnd = L'\0'; + goto cleanup; + } + pwszRelativeFile[ cch ] = wchSave; + + cch = lstrlenW(L"RPLFILES\\TMPFILES\\"); + wchSave = pwszRelativeFile[ cch ]; + pwszRelativeFile[ cch ] = L'\0'; + if ( 0 == lstrcmpi( pwszRelativeFile, L"RPLFILES\\TMPFILES\\") ) { + pwszRelativeFile[ cch ] = wchSave; + blocktype = RPL_SD_BLOCK_TYPE_ONEUSER; + pwszWkstaNameStart = pwszWkstaNameEnd = pwszRelativeFile + cch; + while (*pwszWkstaNameEnd != L'\\' && *pwszWkstaNameEnd != L'\0') { + pwszWkstaNameEnd++; + } + *pwszWkstaNameEnd = L'\0'; + goto cleanup; + } + pwszRelativeFile[ cch ] = wchSave; + +cleanup: + + // + // We now know what kind of SECURITY_DESCRIPTOR we want, so get it. + // + if (Error == NO_ERROR && !(*pfSkipPermsOnFile)) { + Error = GetSd( ppsd, ppsdblock, blocktype, pwszWkstaNameStart ); + } + + return( Error); +} + + +/* + * This call gets an actual security descriptor which corresponds to + * nChangeableAceType and pwszGrantTo. The security descriptor + * is only valid until next call to GetSd(). + * + * The caller has to free *ppsdblock eventually, but should not free + * *ppsd. + */ +DWORD GetSd( + OUT PSECURITY_DESCRIPTOR * ppsd, + IN OUT RPL_SD_BLOCK ** ppsdblock, + IN RPL_SD_BLOCK_TYPE nChangeableAceType, + IN PWCHAR pwszGrantTo + ) +{ + DWORD Error = NO_ERROR; + PACL paclDacl = NULL; + BOOL fDaclPresent = FALSE; + BOOL fDaclDefaulted = FALSE; + + RPL_ASSERT( ppsd != NULL); + RPL_ASSERT( ppsdblock != NULL); + + // + // Create the RPL_SD_BLOCK if it does not yet exist + // + if ( *ppsdblock == NULL ) + { + Error = InitSdBlock( ppsdblock ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + } + RPL_ASSERT( *ppsdblock != NULL ); + + // + // If the RPL_SD_BLOCK is already configured correctly, return success + // + if ( ( (*ppsdblock)->nChangeableAceType == nChangeableAceType ) + && ( (*ppsdblock)->nChangeableAceType != RPL_SD_BLOCK_TYPE_ONEUSER + || (0 == lstrcmpW((*ppsdblock)->pwszGrantToName, pwszGrantTo)) ) + && ( (*ppsdblock)->nChangeableAceType != RPL_SD_BLOCK_TYPE_BADUSER + || (0 == lstrcmpW((*ppsdblock)->pwszGrantToName, pwszGrantTo)) ) + ) + { + goto cleanup; + } + // + // Extract the DACL + // + if ( !GetSecurityDescriptorDacl( (*ppsdblock)->psd, + &fDaclPresent, + &paclDacl, + &fDaclDefaulted + )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + RPL_ASSERT( fDaclPresent && !fDaclDefaulted ); + + // + // Clear the changeable ACE if present + // + if ( (*ppsdblock)->nChangeableAceType != RPL_SD_BLOCK_TYPE_ADMINONLY + && (*ppsdblock)->nChangeableAceType != RPL_SD_BLOCK_TYPE_BADUSER ) + { + if ( !DeleteAce( paclDacl, RPL_INDEX_CHANGEABLE_ACE )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + // CODEWORK do we need to decrement ACE count here? + (*ppsdblock)->nChangeableAceType = RPL_SD_BLOCK_TYPE_ADMINONLY; + } + + // + // Clear and rewrite psidGrantTo if necessary + // + if ( nChangeableAceType == RPL_SD_BLOCK_TYPE_ONEUSER + || nChangeableAceType == RPL_SD_BLOCK_TYPE_BADUSER ) + { + if ( (*ppsdblock)->psidGrantTo != NULL) { + MyFreeSid( &((*ppsdblock)->psidGrantTo) ); + TREE_FREE( (*ppsdblock)->pwszGrantToName ); + (*ppsdblock)->pwszGrantToName = NULL; + } + if (lstrlenW(pwszGrantTo) > RPL_MAX_WKSTA_NAME_LENGTH) + { + TREE_ASSERT( ( "Bad user %ws", pwszGrantTo)); + nChangeableAceType = RPL_SD_BLOCK_TYPE_BADUSER; + } + else + { + Error = GetAccountSid( (*ppsdblock)->hsamAccountDomain, + (*ppsdblock)->pinfoAccountDomain, + pwszGrantTo, + &((*ppsdblock)->psidGrantTo), + FALSE, + NULL ); + // CODEWORK trap error here? + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + } + + (*ppsdblock)->pwszGrantToName = + TREE_ALLOC( (lstrlenW(pwszGrantTo)+1) * sizeof(WCHAR) ); + if ( (*ppsdblock)->pwszGrantToName == NULL ) + { + Error = ERROR_NOT_ENOUGH_MEMORY; + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + lstrcpyW( (*ppsdblock)->pwszGrantToName, pwszGrantTo ); + } + + // + // Add changeable ACE if desired + // + RPL_ASSERT( (*ppsdblock)->nChangeableAceType = RPL_SD_BLOCK_TYPE_ADMINONLY ); + switch (nChangeableAceType) { + case RPL_SD_BLOCK_TYPE_ADMINONLY: + case RPL_SD_BLOCK_TYPE_BADUSER: + break; + case RPL_SD_BLOCK_TYPE_ALLUSERS: + Error = AddInheritableAce( paclDacl, + GENERIC_READ | GENERIC_EXECUTE, + (*ppsdblock)->psidRPLUSER ); + break; + case RPL_SD_BLOCK_TYPE_ONEUSER: + Error = AddInheritableAce( paclDacl, + GENERIC_READ + | GENERIC_WRITE + | GENERIC_EXECUTE + | DELETE, + (*ppsdblock)->psidGrantTo ); + break; + default: + ASSERT(FALSE); + break; + } + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + (*ppsdblock)->nChangeableAceType = nChangeableAceType; + + // + // Save the upgraded ACL into the security descriptor + // + // CODEWORK is this needed? + // + if ( !SetSecurityDescriptorDacl( (*ppsdblock)->psd, + TRUE, + paclDacl, + FALSE + )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if (Error == NO_ERROR) { + *ppsd = (*ppsdblock)->psd; + } + + return( Error); +} + + +SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY; + +/* + * Create a new RPL_SD_BLOCK + */ +DWORD InitSdBlock( + OUT RPL_SD_BLOCK ** ppsdblock + ) +{ + DWORD Error = 0; + DWORD cbNewDacl = 0; + PACL paclDacl = NULL; + + RPL_ASSERT( ppsdblock != NULL ); + RPL_ASSERT( *ppsdblock == NULL ); + + // + // Allocate memory for the RPL_SD_BLOCK + // + *ppsdblock = TREE_ALLOC( sizeof(RPL_SD_BLOCK) ); + if ( *ppsdblock == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + ZeroMemory( (*ppsdblock), sizeof(RPL_SD_BLOCK) ); + + // + // Get System SID + // + Error = RtlAllocateAndInitializeSid( + &IDAuthorityNT, + 1, + SECURITY_LOCAL_SYSTEM_RID, + 0, 0, 0, 0, 0, 0, 0, + &((*ppsdblock)->psidSystem) + ); + if (Error != NO_ERROR) { + goto cleanup; + } + + // + // Get Administrators SID + // + Error = RtlAllocateAndInitializeSid( + &IDAuthorityNT, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &((*ppsdblock)->psidAdministrators) + ); + if (Error != NO_ERROR) { + goto cleanup; + } + + // + // Get System Operators SID + // + Error = RtlAllocateAndInitializeSid( + &IDAuthorityNT, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_SYSTEM_OPS, + 0, 0, 0, 0, 0, 0, + &((*ppsdblock)->psidSystemOperators) + ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Get information about account domain + // + Error = GetAccountDomain( &((*ppsdblock)->hsamAccountDomain), + &((*ppsdblock)->pinfoAccountDomain), + GENERIC_EXECUTE ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Get RPLUSER SID + // + Error = GetAccountSid( (*ppsdblock)->hsamAccountDomain, + (*ppsdblock)->pinfoAccountDomain, + RPL_GROUP_RPLUSER, + &((*ppsdblock)->psidRPLUSER), + TRUE, + NULL ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Start assembling DACL + // + cbNewDacl = sizeof(ACL) + (3*sizeof(ACCESS_ALLOWED_ACE)) + + (3*GetSidLengthRequired(SID_MAX_SUB_AUTHORITIES)) + - sizeof(DWORD); + paclDacl = (PACL) TREE_ALLOC( cbNewDacl); + if ( paclDacl == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + if ( !InitializeAcl( paclDacl, cbNewDacl, ACL_REVISION )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Add System ACE + // + Error = AddInheritableAce( paclDacl, + GENERIC_ALL, + (*ppsdblock)->psidSystem ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + // CODEWORK do we still want to free psidSystem? + + // + // Add Administrators ACE + // + Error = AddInheritableAce( paclDacl, + GENERIC_ALL, + (*ppsdblock)->psidAdministrators ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + // CODEWORK do we still want to free psidAdministrators? + + // + // Add System Operators ACE + // + Error = AddInheritableAce( paclDacl, + GENERIC_ALL, + (*ppsdblock)->psidSystemOperators ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + // BUGBUG shouldn't add this for WINNT machines! + // CODEWORK do we still want to free psidSystemOperators? + + // + // Build security descriptor + // + (*ppsdblock)->psd = TREE_ALLOC( sizeof(SECURITY_DESCRIPTOR) ); + if ( (*ppsdblock)->psd == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + if ( !InitializeSecurityDescriptor( (*ppsdblock)->psd, + SECURITY_DESCRIPTOR_REVISION )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + if ( !SetSecurityDescriptorDacl( (*ppsdblock)->psd, + TRUE, + paclDacl, + FALSE )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Set nChangeableAceType in RPL_SD_BLOCK + // + (*ppsdblock)->nChangeableAceType = RPL_SD_BLOCK_TYPE_ADMINONLY; + +cleanup: + + if (Error != NO_ERROR) + { + FreeSdBlock( ppsdblock ); + + if (paclDacl != NULL) { + TREE_FREE( paclDacl ); + paclDacl = NULL; + } + } + + return(Error); +} + +/* + * Add an ACCESS_ALLOWED_ACE to the ACL, with all inheritance flags set + */ +DWORD AddInheritableAce( + IN OUT ACL * pacl, + IN ACCESS_MASK mask, + IN SID * psid ) +{ + DWORD Error = NO_ERROR; + ACCESS_ALLOWED_ACE * pace = NULL; + + if ( !AddAccessAllowedAce( pacl, + ACL_REVISION, + mask, + psid )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // new ACE should be the last ACE + // + if ( !GetAce( pacl, (pacl->AceCount) - 1, &pace )) { + Error = GetLastError(); + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + RPL_ASSERT( EqualSid( psid, &(pace->SidStart)) ); + + (pace->Header.AceFlags) |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE); + +cleanup: + + return( Error); +} + + +/* + * The RplDoTree run is over, free the RPL_SD_BLOCK + */ +VOID FreeSdBlock( + IN RPL_SD_BLOCK ** ppsdblock + ) +{ + RPL_ASSERT( ppsdblock != NULL ); + + if (*ppsdblock != NULL) + { + if ((*ppsdblock)->psd != NULL) { + TREE_FREE( (*ppsdblock)->psd ); + } + if ((*ppsdblock)->pwszGrantToName != NULL) { + TREE_FREE( (*ppsdblock)->pwszGrantToName ); + } + if ((*ppsdblock)->psidSystem != NULL) { + RtlFreeSid( (*ppsdblock)->psidSystem ); + } + if ((*ppsdblock)->psidAdministrators != NULL) { + RtlFreeSid( (*ppsdblock)->psidAdministrators ); + } + if ((*ppsdblock)->psidSystemOperators != NULL) { + RtlFreeSid( (*ppsdblock)->psidSystemOperators); + } + MyFreeSid( &((*ppsdblock)->psidRPLUSER) ); + MyFreeSid( &((*ppsdblock)->psidGrantTo) ); + if ( (*ppsdblock)->pinfoAccountDomain != NULL) { + LsaFreeMemory( (*ppsdblock)->pinfoAccountDomain); + } + if ((*ppsdblock)->hsamAccountDomain != NULL) { + SamCloseHandle( (*ppsdblock)->hsamAccountDomain); + } + } + TREE_FREE( *ppsdblock ); + *ppsdblock = NULL; +} + + +/* + * Get a SAM_HANDLE to the account domain, and other information about + * the account domain. This routine uses SAM and LSA directly. + */ +DWORD GetAccountDomain( + OUT SAM_HANDLE * phsamAccountDomain, + OUT POLICY_ACCOUNT_DOMAIN_INFO ** ppinfoAccountDomain, + IN ACCESS_MASK DesiredAccess + ) +{ + DWORD Error = NO_ERROR; + SAM_HANDLE hsamServer = NULL; + LSA_HANDLE hlsa = NULL; + OBJECT_ATTRIBUTES oa; + POLICY_ACCOUNT_DOMAIN_INFO * pacctdominfo = NULL; + SECURITY_QUALITY_OF_SERVICE sqos; + + RPL_ASSERT( phsamAccountDomain != NULL ); + RPL_ASSERT( ppinfoAccountDomain != NULL ); + + // + // Get server handle + // + + Error = SamConnect( NULL, + &hsamServer, + SAM_SERVER_LOOKUP_DOMAIN, + NULL ); + if ( Error != NERR_Success) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Set up object attributes (borrowed from uintlsa.cxx) + // + + sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); + sqos.ImpersonationLevel = SecurityImpersonation; + sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + sqos.EffectiveOnly = FALSE; + + InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL ); + oa.SecurityQualityOfService = &sqos; + + // + // Get LSA handle + // + + Error = LsaOpenPolicy( NULL, + &oa, + GENERIC_EXECUTE, + &hlsa ); + if ( Error != NERR_Success) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Get primary domain information + // + + Error = LsaQueryInformationPolicy( hlsa, + PolicyAccountDomainInformation, + ppinfoAccountDomain ); + if ( Error != NERR_Success) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + // + // Open account domain handle + // + + Error = SamOpenDomain( hsamServer, + DesiredAccess, + (*ppinfoAccountDomain)->DomainSid, + phsamAccountDomain ); + if ( Error != NERR_Success) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( hsamServer != NULL) { + SamCloseHandle( hsamServer); + } + + if ( hlsa != NULL) { + LsaClose( hlsa); + } + + if ( Error != NO_ERROR && (*ppinfoAccountDomain) != NULL) { + LsaFreeMemory( (*ppinfoAccountDomain)); + *ppinfoAccountDomain = NULL; + } + + if ( Error != NO_ERROR && phsamAccountDomain != NULL) { + SamCloseHandle( *phsamAccountDomain); + *phsamAccountDomain = NULL; + } + + return( Error); +} + + +/* + * Get the SID for an account in the account domain. This method + * uses SAM directly to do the lookup, this is why we need to keep + * around a SAM domain handle. + * + * Returns NERR_RplWkstaNeedsUserAcct if the account is not found and + * !fIsLocalgroup, NERR_RplNeedsRPLUSERAcct if fIsLocalgroup + * + * Use MyFreeSid to free the SID returned in **ppsidAccountSid + */ +DWORD GetAccountSid( + IN SAM_HANDLE hsamAccountDomain, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN WCHAR * pwszAccountName, + OUT PSID * ppsidAccountSid, + IN BOOL fIsLocalgroup, + OUT DWORD * pulRid OPTIONAL + ) +{ + DWORD Error = NO_ERROR; + UNICODE_STRING unistr; + PULONG RelativeIds = NULL; + PSID_NAME_USE Use = NULL; + DWORD cbNewSid = 0; + PUCHAR pcSubAuthorityCount = NULL; + PDWORD pdwLastSubAuthority = NULL; + + RPL_ASSERT( hsamAccountDomain != NULL ); + RPL_ASSERT( pinfoAccountDomain != NULL ); + RPL_ASSERT( pwszAccountName != NULL ); + RPL_ASSERT( ppsidAccountSid != NULL && *ppsidAccountSid == NULL ); + + // + // Lookup name + // + + FillUnicodeString( &unistr, pwszAccountName ); + + Error = SamLookupNamesInDomain( hsamAccountDomain, + 1, + &unistr, + &RelativeIds, + &Use ); + if (Error != NO_ERROR) { + if (Error == STATUS_NONE_MAPPED) { + Error = (fIsLocalgroup) ? NERR_RplNeedsRPLUSERAcct + : NERR_RplWkstaNeedsUserAcct; + } + // TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + RPL_ASSERT( RelativeIds != NULL && Use != NULL ); + + if ( Use[0] != ((fIsLocalgroup) ? SidTypeAlias : SidTypeUser) ) { + Error = (fIsLocalgroup) ? NERR_RplNeedsRPLUSERAcct + : NERR_RplWkstaNeedsUserAcct; + goto cleanup; + } + + // + // Construct account SID from RID and domain SID + // + + Error = MyBuildSid( ppsidAccountSid, pinfoAccountDomain, RelativeIds[0] ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( Error == NO_ERROR && pulRid != NULL) { + *pulRid = RelativeIds[0]; + } + + if (RelativeIds != NULL) { + SamFreeMemory( RelativeIds); + } + if (Use != NULL) { + SamFreeMemory( Use); + } + if ( Error != NO_ERROR ) { + MyFreeSid( ppsidAccountSid ); + } + + return( Error); +} + + +/******************************************************************* + + NAME: IsNTFS + + SYNOPSIS: This function checks the given file resource and attempts to + determine if it is on an NTFS partition. + + ENTRY: pwszResource - Pointer to file/directory name in the form + "X:\aaa\bbb\ccc + pfIsNTFS - Pointer to BOOL that will receive the results + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 23-Feb-1994 Copied from acledit\ntfsacl.cxx + +********************************************************************/ + +DWORD IsNTFS( + IN WCHAR * pwszResource, + OUT BOOL * pfIsNTFS ) +{ + DWORD Error = NO_ERROR ; + HANDLE hDrive = NULL ; + WCHAR awchDosDriveName[4]; + WCHAR awchNtDriveName[40]; + UNICODE_STRING unistrNtDriveName; + BYTE buffFsInfo[ sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 200 ] ; + PFILE_FS_ATTRIBUTE_INFORMATION FsInfo = + (PFILE_FS_ATTRIBUTE_INFORMATION)buffFsInfo ; + OBJECT_ATTRIBUTES oa ; + IO_STATUS_BLOCK StatusBlock ; + + RPL_ASSERT( pwszResource != NULL + && lstrlen(pwszResource) >= 3 + && pfIsNTFS != NULL ) ; + + *pfIsNTFS = FALSE ; + + // + // Determine the NT drive name + // + + awchDosDriveName[0] = pwszResource[0]; + awchDosDriveName[1] = pwszResource[1]; + awchDosDriveName[2] = pwszResource[2]; + awchDosDriveName[3] = L'\0'; + RPL_ASSERT( awchDosDriveName[1] == L':' + && awchDosDriveName[2] == L'\\' ); + + unistrNtDriveName.Buffer = awchNtDriveName; + unistrNtDriveName.Length = sizeof(awchNtDriveName); + unistrNtDriveName.MaximumLength = sizeof(awchNtDriveName); + + if (!RtlDosPathNameToNtPathName_U( awchDosDriveName, + &unistrNtDriveName, + NULL, + NULL)) + { + RPL_ASSERT( FALSE ) ; + Error = ERROR_NOT_ENOUGH_MEMORY ; + goto cleanup; + } + RPL_ASSERT( unistrNtDriveName.Length < unistrNtDriveName.MaximumLength ); + unistrNtDriveName.Buffer[unistrNtDriveName.Length/sizeof(WCHAR)] = L'\0'; + + // + // Open the NT volume and query volume information + // + + InitializeObjectAttributes( &oa, + &unistrNtDriveName, + OBJ_CASE_INSENSITIVE, + 0, + 0 ); + Error = NtOpenFile( &hDrive, + SYNCHRONIZE | FILE_READ_DATA, + &oa, + &StatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_ALERT); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + Error = NtQueryVolumeInformationFile( + hDrive, + &StatusBlock, + (PVOID) FsInfo, + sizeof(buffFsInfo), + FileFsAttributeInformation ); + if (Error != NO_ERROR) { + if (Error == ERROR_ACCESS_DENIED) { + TREE_ASSERT( ( +"IsNTFS - Unable to determine volume information (access denied) assuming the file system is NTFS" + ) ) ; + Error = NO_ERROR ; + *pfIsNTFS = TRUE ; + } else { + TREE_ASSERT( ( "Error=%d", Error)); + } + goto cleanup; + } + + if ( FsInfo->FileSystemAttributes & FILE_PERSISTENT_ACLS ) + { + *pfIsNTFS = TRUE ; + } + +cleanup: + + /* Close the volume if we ever opened it + */ + if ( hDrive != NULL ) + { + NtClose( hDrive ); + } + + return( Error) ; +} + + +/******************************************************************* + + NAME: RplCreateWkstaAccounts + + SYNOPSIS: This function checks whether a user account exists for + each RPL workstation, and creates one if not. It also + adds all of these accounts to the RPLUSER local group. + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 04-Mar-1994 Created + +********************************************************************/ + +DWORD RplCheckWkstaAccounts( RPL_RPC_HANDLE ServerHandle ) +{ + DWORD Error = 0; + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain = NULL; + SAM_HANDLE hsamAccountDomain = NULL; + PSID psidRPLUSER = NULL; + ULONG ulRidRPLUSER = 0; + SAM_HANDLE hsamRPLUSER = NULL; + DWORD ErrorEnum = NO_ERROR; + RPL_WKSTA_ENUM rplwkstaenum; + RPL_WKSTA_INFO_0_CONTAINER rplwksta0container; + DWORD cEntries = 0; + DWORD hResumeHandle = 0; + DWORD i; + + rplwkstaenum.Level = 0; + rplwkstaenum.WkstaInfo.Level0 = &rplwksta0container; + rplwkstaenum.WkstaInfo.Level0->EntriesRead = 0; + rplwkstaenum.WkstaInfo.Level0->Buffer = NULL; + + Error = GetAccountDomain( &hsamAccountDomain, + &pinfoAccountDomain, + GENERIC_EXECUTE | DOMAIN_CREATE_USER ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + Error = GetAccountSid( hsamAccountDomain, + pinfoAccountDomain, + RPL_GROUP_RPLUSER, + &psidRPLUSER, + TRUE, + &ulRidRPLUSER ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + Error = SamOpenAlias( hsamAccountDomain, + ALIAS_ADD_MEMBER, + ulRidRPLUSER, + &hsamRPLUSER ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + do { + ErrorEnum = NetrRplWkstaEnum( ServerHandle, + NULL, + &rplwkstaenum, + (ULONG)-1, + &cEntries, + &hResumeHandle ); + switch (ErrorEnum) { + case STATUS_MORE_ENTRIES: + case ERROR_MORE_DATA: + case NO_ERROR: + case STATUS_NO_MORE_ENTRIES: + + if (rplwkstaenum.WkstaInfo.Level0->Buffer == NULL) { + // no workstations + break; + } + for ( i = 0; + (Error == NO_ERROR) + && (i < rplwkstaenum.WkstaInfo.Level0->EntriesRead); + i++ ) { + Error = RplAddWkstaAccount( + rplwkstaenum.WkstaInfo.Level0->Buffer[i].WkstaName, + hsamAccountDomain, + pinfoAccountDomain, + hsamRPLUSER ); + } + + MIDL_user_free( rplwkstaenum.WkstaInfo.Level0->Buffer ); + rplwkstaenum.WkstaInfo.Level0->Buffer = NULL; + break; + + default: + Error = ErrorEnum; + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + } while ( Error == STATUS_MORE_ENTRIES || Error == ERROR_MORE_DATA ); + +cleanup: + + /* + * We have no way to free the resume handle + */ + + if ( rplwkstaenum.WkstaInfo.Level0->Buffer != NULL ) { + MIDL_user_free( rplwkstaenum.WkstaInfo.Level0->Buffer ); + } + + if ( pinfoAccountDomain != NULL) { + LsaFreeMemory( pinfoAccountDomain); + } + if (hsamAccountDomain != NULL) { + SamCloseHandle( hsamAccountDomain); + } + + if (hsamRPLUSER != NULL) { + SamCloseHandle( hsamRPLUSER); + } + + if (hsamRPLUSER != NULL) { + SamCloseHandle( hsamRPLUSER); + } + + MyFreeSid( &psidRPLUSER ); + + return( Error); +} + + +/******************************************************************* + + NAME: RplAddWkstaAccount + + SYNOPSIS: This function checks whether a user account exists for + a single workstation, and creates one if not. It also + adds the account to the RPLUSER local group. + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 04-Mar-1994 Created + +********************************************************************/ + +DWORD RplAddWkstaAccount( LPWSTR pszWkstaName, + SAM_HANDLE hsamAccountDomain, + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + SAM_HANDLE hsamRPLUSER ) +{ + DWORD Error = 0; + UNICODE_STRING unistr; + PSID psidUser = NULL; + ULONG ulRidUser = 0; + SAM_HANDLE hsamUser = NULL; + + RPL_ASSERT( pszWkstaName != NULL + && hsamAccountDomain != NULL + && pinfoAccountDomain != NULL + && hsamRPLUSER != NULL ); + + /* + * Get SID of existing account. It would be more efficient to look + * up all the accounts at once. + */ + + Error = GetAccountSid( hsamAccountDomain, + pinfoAccountDomain, + pszWkstaName, + &psidUser, + FALSE, + &ulRidUser ); + if ( Error == NERR_RplWkstaNeedsUserAcct ) + { + /* + * Account doesn't exist, add it + * + * Note that this will fail unless user is administrator or + * at least account operator + */ + + FillUnicodeString( &unistr, pszWkstaName ); + + Error = SamCreateUserInDomain( hsamAccountDomain, + &unistr, + 0x0, + &hsamUser, + &ulRidUser ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + Error = MyBuildSid( &psidUser, pinfoAccountDomain, ulRidUser ); + if (Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + } + + /* + * Add account to RPLUSER alias + * + * Note that this will fail unless user is administrator or + * at least account operator + */ + + Error = SamAddMemberToAlias( hsamRPLUSER, psidUser ); + switch (Error) { + case STATUS_MEMBER_IN_ALIAS: + Error = NO_ERROR; + // fall through + case NO_ERROR: + break; + default: + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + +cleanup: + + MyFreeSid( &psidUser ); + + if (hsamUser != NULL) { + SamCloseHandle( hsamUser); + } + + return( Error); +} + + +/******************************************************************* + + NAME: RplAddRPLUSERGroup + + SYNOPSIS: This function checks whether the RPLUSER local group + exists, and creates it if it doesn't. + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 03-Mar-1994 Created + +********************************************************************/ + +DWORD RplAddRPLUSERGroup( VOID ) +{ + DWORD Error = 0; + POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain = NULL; + SAM_HANDLE hsamAccountDomain = NULL; + PSID psidRPLUSER = NULL; + UNICODE_STRING unistr; + SAM_HANDLE hsamRPLUSER = NULL; + ULONG ulRidRPLUSER = 0; + + Error = GetAccountDomain( &hsamAccountDomain, + &pinfoAccountDomain, + GENERIC_EXECUTE | DOMAIN_CREATE_ALIAS ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + Error = GetAccountSid( hsamAccountDomain, + pinfoAccountDomain, + RPL_GROUP_RPLUSER, + &psidRPLUSER, + TRUE, + NULL ); + if ( Error == NO_ERROR) { + // RPLUSER already exists + goto cleanup; + } else if (Error != NERR_RplNeedsRPLUSERAcct) + { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + + FillUnicodeString( &unistr, RPL_GROUP_RPLUSER ); + + Error = SamCreateAliasInDomain( hsamAccountDomain, + &unistr, + 0x0, + &hsamRPLUSER, + &ulRidRPLUSER ); + if ( Error != NO_ERROR) { + TREE_ASSERT( ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if ( pinfoAccountDomain != NULL) { + LsaFreeMemory( pinfoAccountDomain); + } + if (hsamAccountDomain != NULL) { + SamCloseHandle( hsamAccountDomain); + } + + if (hsamRPLUSER != NULL) { + SamCloseHandle( hsamRPLUSER); + } + + MyFreeSid( &psidRPLUSER ); + + return( Error); +} + +VOID FillUnicodeString( PUNICODE_STRING punistr, + LPWSTR lpwsz ) +{ + ASSERT( punistr != NULL && lpwsz == NULL ); + punistr->Buffer = lpwsz; + punistr->Length = lstrlenW(lpwsz) * sizeof(WCHAR); + punistr->MaximumLength = punistr->Length + sizeof(WCHAR); +} + +DWORD MyBuildSid( OUT PSID * ppsidAccountSid, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN ULONG ulRid ) +{ + DWORD Error = 0; + DWORD cbNewSid = 0; + PUCHAR pcSubAuthorityCount = NULL; + PDWORD pdwLastSubAuthority = NULL; + + ASSERT( ppsidAccountSid != NULL && pinfoAccountDomain != NULL && ulRid != 0 ); + + cbNewSid = GetLengthSid(pinfoAccountDomain->DomainSid) + sizeof(DWORD); + *ppsidAccountSid = TREE_ALLOC( cbNewSid ); + if ( *ppsidAccountSid == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + if ( !CopySid( cbNewSid, *ppsidAccountSid, pinfoAccountDomain->DomainSid)) { + Error = GetLastError(); + goto cleanup; + } + + pcSubAuthorityCount = GetSidSubAuthorityCount( *ppsidAccountSid ); + RPL_ASSERT( pcSubAuthorityCount != NULL ); + (*pcSubAuthorityCount)++; + pdwLastSubAuthority = GetSidSubAuthority( + *ppsidAccountSid, (DWORD)((*pcSubAuthorityCount)-1) ); + RPL_ASSERT( pdwLastSubAuthority != NULL ); + *pdwLastSubAuthority = ulRid; + +cleanup: + + if (Error != NO_ERROR) { + MyFreeSid( ppsidAccountSid ); + } + + return( Error); +} + +VOID MyFreeSid( IN OUT PSID * ppsid ) +{ + RPL_ASSERT( ppsid != NULL ); + + if ( *ppsid != NULL) { + TREE_FREE( *ppsid ); + *ppsid = NULL; + } +} diff --git a/private/net/svcdlls/rpl/rplinst/security.h b/private/net/svcdlls/rpl/rplinst/security.h new file mode 100644 index 000000000..403aa7fd1 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/security.h @@ -0,0 +1,17 @@ +// +// #define RPL_RPC_HANDLE RPL_HANDLE +// + +#define NetrRplWkstaEnum MyNetrRplWkstaEnum +#define MIDL_user_free MyMIDL_user_free + +#include <rplsvc_s.h> // RPL_WKSTA_ENUM + +#include "..\server\security.h" + +#undef TREE_ALLOC +#undef TREE_FREE +#undef TREE_ASSERT +#define TREE_ALLOC(x) (malloc( (x) )) +#define TREE_FREE(x) (free( (x) )) +#define TREE_ASSERT( x ) ASSERT(FALSE) diff --git a/private/net/svcdlls/rpl/rplinst/sources b/private/net/svcdlls/rpl/rplinst/sources new file mode 100644 index 000000000..60cf3e52f --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/sources @@ -0,0 +1,38 @@ +MAJORCOMP=net +MINORCOMP=rplinst + +TARGETPATH=obj +TARGETNAME=rplinst +TARGETTYPE=PROGRAM +NTTARGETFILE0=nlstxt.h nlstxt.mc nlstxt.rc + +TARGETLIBS= \ + ..\lib\obj\*\rpllib.lib \ + $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\samlib.lib \ + $(BASEDIR)\public\sdk\lib\*\wsock32.lib \ + $(BASEDIR)\public\sdk\lib\*\jet500.lib + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +INCLUDES=.;..\inc;..\server;..\..\..\inc;..\..\..\api;..\..\..\..\inc; + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + rplinst.rc \ + rplinst.c \ + security.c \ + tree.c \ + debug.c \ + querydir.c + + +C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 -DRPL_RPLCNV + +UMTYPE=console + diff --git a/private/net/svcdlls/rpl/rplinst/tree.c b/private/net/svcdlls/rpl/rplinst/tree.c new file mode 100644 index 000000000..08b3a942c --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/tree.c @@ -0,0 +1,2 @@ + +#include "..\server\tree.c" diff --git a/private/net/svcdlls/rpl/rplinst/tree.h b/private/net/svcdlls/rpl/rplinst/tree.h new file mode 100644 index 000000000..d68d34917 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/tree.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tree.h + +Abstract: + + Exports from tree.c + +Author: + + Jon Newman (jonn) 23 - November - 1993 + +Revision History: + + Vladimir Z. Vulovic (vladimv) 02 - December - 1993 + Integrated with the rest of RPL service code. + +--*/ + +DWORD RplTreeCopy( IN PWCHAR Source, IN PWCHAR Target); +DWORD RplTreeDelete( IN PWCHAR Target); +DWORD RplMakeDir( IN PWCHAR Target); + + diff --git a/private/net/svcdlls/rpl/rplinst/treei.h b/private/net/svcdlls/rpl/rplinst/treei.h new file mode 100644 index 000000000..3489cd759 --- /dev/null +++ b/private/net/svcdlls/rpl/rplinst/treei.h @@ -0,0 +1,51 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tree.h + +Abstract: + + Internal definitions from tree.c + +Author: + + Jon Newman (jonn) 16 - February - 1994 + +Revision History: + + Jon Newman (jonn) 16 - February - 1994 + Added RplGrant*Perms primitives + +--*/ + +typedef DWORD (RPL_TREE_CALLBACK)( PWCHAR pszPath, PVOID * ppv); + +#define RPL_TREE_COPY_DACL 0x1 // not yet implemented +#define RPL_TREE_COPY_SACL 0x2 // not yet implemented +#define RPL_TREE_AUXILIARY 0x2000 // perform callback action +#define RPL_TREE_COPY 0x4000 +#define RPL_TREE_DELETE 0x8000 + +// +// Forward declarations +// + +DWORD RplDoTree( + PWCHAR Source, + PWCHAR Target, + DWORD Flags, + PWCHAR Buffer, + DWORD BufferSize, + RPL_TREE_CALLBACK AuxiliaryCallback, + PVOID AuxiliaryBlock + ); + +VOID LoadError( + PWCHAR FilePath, + LPVOID Buffer, + DWORD BufferSize + ); + diff --git a/private/net/svcdlls/rpl/rplstart/local.h b/private/net/svcdlls/rpl/rplstart/local.h new file mode 100644 index 000000000..85977e516 --- /dev/null +++ b/private/net/svcdlls/rpl/rplstart/local.h @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + local.h + +Abstract: + + Main include file for RPLSTART + +Author: + + Jon Newman (jonn) 12 - January - 1994 + +Revision History: + +--*/ + +#include <nt.h> // ntexapi.h\NtQuerySystemTime +#include <ntrtl.h> // RtlTimeToSecondsSince1970 +#include <nturtl.h> + +#include <windows.h> // DWORD, IN, File APIs, etc. +#include <stdlib.h> +#include <lmcons.h> + +#include <stdio.h> // vsprintf +#include <ctype.h> // isspace + +#include <lmerr.h> // NERR_RplBootStartFailed - used to be here + +// +#include <lmapibuf.h> // NetApiBufferFree +#include <netlib.h> + +#include <lmsvc.h> + +#include <lmalert.h> // STD_ALERT ALERT_OTHER_INFO + +#include <lmerrlog.h> +#include <alertmsg.h> +#include <lmserver.h> +#include <netlib.h> +#include <netlock.h> // Lock data types, functions, and macros. +#include <thread.h> // FORMAT_NET_THREAD_ID, NetpCurrentThread(). + +#include <lmshare.h> // PSHARE_INFO_2 +#include <lmaccess.h> // NetGroupGetInfo +#include <lmconfig.h> // NetConfigGet +#include <nb30.h> // NCB + +// +// Global types and constants (used in all RPL server files). +// + +#include <riplcons.h> // includes __JET500 flag +#include <jet.h> +#include <rpllib.h> // AddKey(), MapJetError(), FillTcpIpString() + +#include <rpldb.h> + +#include "rplmgrd.h" + +#define RPL_BUGBUG_ERROR ((DWORD)-1) // need to get rid of these diff --git a/private/net/svcdlls/rpl/rplstart/makefile b/private/net/svcdlls/rpl/rplstart/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/rpl/rplstart/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/rplstart/rplstart.c b/private/net/svcdlls/rpl/rplstart/rplstart.c new file mode 100644 index 000000000..1903c25a5 --- /dev/null +++ b/private/net/svcdlls/rpl/rplstart/rplstart.c @@ -0,0 +1,139 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + rplstart.c + +Abstract: + + Copies fresh RPL database and files. + + BUGBUG Should polish and make WIN32 application out of this. + +Author: + + Jon Newman (jonn) 12 - January - 1994 + +Environment: + + User mode + +Revision History : + +--*/ + +#define RPLDATA_ALLOCATE +#include "local.h" +#undef RPLDATA_ALLOCATE + +#define RPL_INSTALL_FILES L"\\INSTALL" + + +DWORD _CRTAPI1 main ( VOID) +{ + + WCHAR awchConvertPath[ PATHLEN+1]; + DWORD dwErr; + + dwErr = I_NetRpl_QueryDirectory( awchConvertPath, NULL); + if ( dwErr != NO_ERROR) { + return( dwErr); + } + + if ( lstrlenW(awchConvertPath) + lstrlenW(RPL_INSTALL_FILES) > PATHLEN) { + return( RPL_BUGBUG_ERROR); + } + + (void) lstrcatW( awchConvertPath, RPL_INSTALL_FILES); + + dwErr = I_NetRplCmd_ConvertDatabase( awchConvertPath); + +// BUGBUG proper error reporting +// BUGBUG print final message + + return( dwErr); + +#if 0 + + DWORD Error; + JET_ERR JetError; + + Assert = 0; +#ifdef __JET500 + CallM( JetSetSystemParameter( 0, JET_paramSystemPath, 0, ".")); +#else + CallM( JetSetSystemParameter( 0, JET_paramSysDbPath, 0, "system.mdb")); +#endif + CallM( JetSetSystemParameter( 0, JET_paramTempPath, 0, "temp.tmp")); + CallM( JetSetSystemParameter( 0, JET_paramMaxBuffers, 250, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramBfThrshldLowPrcnt, 0, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramBfThrshldHighPrcnt, 100, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramMaxOpenTables, 30, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramMaxOpenTableIndexes, 105, NULL)) + CallM( JetSetSystemParameter( 0, JET_paramMaxCursors, 100, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramMaxSessions, 10, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramMaxVerPages, 64, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramMaxTemporaryTables, 5, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramLogFilePath, 0, ".")); + CallM( JetSetSystemParameter( 0, JET_paramLogBuffers, 41, NULL)); +#ifdef __JET500 + CallM( JetSetSystemParameter( 0, JET_paramLogFileSize, 1000, NULL)); + CallM( JetSetSystemParameter( 0, JET_paramBaseName, "j50", NULL)); +#else + CallM( JetSetSystemParameter( 0, JET_paramLogFileSectors, 1000, NULL)); +#endif + CallM( JetSetSystemParameter( 0, JET_paramLogFlushThreshold, 10, NULL)); + + CallM( JetInit()); + CallM( JetBeginSession( &SesId, "admin", "")); + JetError = JetCreateDatabase( SesId, RPL_SERVICE_DATABASE, NULL, &DbId, JET_bitDbSingleExclusive); + + if ( JetError == JET_errDatabaseDuplicate) { + CallM( JetAttachDatabase( SesId, RPL_SERVICE_DATABASE, 0)); + CallM( JetOpenDatabase( SesId, RPL_SERVICE_DATABASE, NULL, &DbId, JET_bitDbExclusive)); + BootListTable(); + ConfigListTable(); + ProfileListTable(); + WkstaListTable(); + ListWkstaInfo( L"02608C1B87A5"); + } else if ( JetError == JET_errSuccess) { + Error = ProcessRplMap(); + if ( Error != ERROR_SUCCESS) { + return( Error); + } + Error = ProcessRplmgrIni(); + if ( Error != ERROR_SUCCESS) { + return( Error); + } + ConfigPruneTable(); + ProfilePruneTable(); + WkstaPruneTable(); + // + // If we were to return here, database would be left in an unusable + // state and any further app calling JetInit() for this database + // would fail. + // + BootCloseTable(); + ConfigCloseTable(); + ProfileCloseTable(); + WkstaCloseTable(); + AdapterCloseTable(); + } else { + RplDump( ++Assert, ("CreateDatabase: JetError=%d", JetError)); + CallM( JetEndSession( SesId, 0)); + CallM( JetTerm2( BUGBUG, JET_bitTermComplete)); + return( MapJetError( JetError)); + } + + CallM( JetCloseDatabase( SesId, DbId, 0)); + CallM( JetDetachDatabase( SesId, RPL_SERVICE_DATABASE)); + CallM( JetEndSession( SesId, 0)); + CallM( JetTerm2( BUGBUG, JET_bitTermComplete)); + +#endif + + return( ERROR_SUCCESS); +} + diff --git a/private/net/svcdlls/rpl/rplstart/sources b/private/net/svcdlls/rpl/rplstart/sources new file mode 100644 index 000000000..5f4748061 --- /dev/null +++ b/private/net/svcdlls/rpl/rplstart/sources @@ -0,0 +1,32 @@ +MAJORCOMP=net +MINORCOMP=rplstart + +TARGETPATH=obj +TARGETNAME=rplstart +TARGETTYPE=PROGRAM + +TARGETLIBS= \ + ..\obj\*\jet.lib \ + ..\lib\obj\*\rpllib.lib \ + ..\convert\obj\*\rplmgrd.lib \ + $(BASEDIR)\Public\Sdk\Lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib \ + $(BASEDIR)\public\sdk\lib\*\wsock32.lib + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +INCLUDES=.;..\inc;..\..\..\inc;..\..\..\api;..\..\..\..\inc; + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + rplstart.c + + +C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 -DRPL_RPLCNV + +UMTYPE=console + diff --git a/private/net/svcdlls/rpl/rplsvc.idl b/private/net/svcdlls/rpl/rplsvc.idl new file mode 100644 index 000000000..aa8b41d8b --- /dev/null +++ b/private/net/svcdlls/rpl/rplsvc.idl @@ -0,0 +1,543 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rplsvc.idl + +Abstract: + + This is the IDL file that describes the RPC interface for the + remotable NetRpl APIs that reside in the messenger service. + +Author: + + Vladimir Z. Vulovic (vladimv) 27-July-1993 + +Environment: + + User Mode -Win32 + +Revision History: + + 27-July-1993 vladimv + Created + +--*/ + +// +// Interface Attributes +// + +[ + uuid(28607FF1-15A0-8E03-D670-B89EEC8EB047), + version(1.0), +#ifdef __midl + ms_union, +#endif // __midl + pointer_default(unique) +] + +// +// Interface Keyword +// + +interface rplsvc + +// +// Interface Body +// + +{ + +import "imports.idl"; +#include <lmcons.h> + +// +// BUGBUG - take this definition out when midl understands LPWSTR etc +// + +#ifdef UNICODE +#define LPTSTR wchar_t* +#endif + +// +// Generic Handle used to bind from client to server. +// + +typedef [handle] LPTSTR RPL_NAME; +typedef RPL_NAME * PRPL_NAME; +typedef PRPL_NAME LPRPL_NAME; + +// +// Context Handle (internal definition) +// + +typedef [context_handle] PVOID RPL_RPC_HANDLE; +typedef RPL_RPC_HANDLE * PRPL_RPC_HANDLE; +typedef PRPL_RPC_HANDLE LPRPL_RPC_HANDLE; + + +// +// Data Structures +// + +// +// SERVICE data - used by Get & Set +// + +typedef [switch_type(DWORD)] union _RPL_INFO_STRUCT { + [case(0)] LPRPL_INFO_0 RplInfo0; + [case(1)] LPRPL_INFO_1 RplInfo1; +} RPL_INFO_STRUCT, *PRPL_INFO_STRUCT, *LPRPL_INFO_STRUCT; + + +// +// BOOT data - used by Enum +// + +typedef struct _RPL_BOOT_INFO_0_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_BOOT_INFO_0 Buffer; +} RPL_BOOT_INFO_0_CONTAINER, *PRPL_BOOT_INFO_0_CONTAINER, *LPRPL_BOOT_INFO_0_CONTAINER; + +typedef struct _RPL_BOOT_INFO_1_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_BOOT_INFO_1 Buffer; +} RPL_BOOT_INFO_1_CONTAINER, *PRPL_BOOT_INFO_1_CONTAINER, *LPRPL_BOOT_INFO_1_CONTAINER; + +typedef struct _RPL_BOOT_INFO_2_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_BOOT_INFO_2 Buffer; +} RPL_BOOT_INFO_2_CONTAINER, *PRPL_BOOT_INFO_2_CONTAINER, *LPRPL_BOOT_INFO_2_CONTAINER; + +typedef struct _RPL_BOOT_ENUM { + DWORD Level; + [switch_is(Level)] union _RPL_BOOT_ENUM_UNION { + [case(0)] LPRPL_BOOT_INFO_0_CONTAINER Level0; + [case(1)] LPRPL_BOOT_INFO_1_CONTAINER Level1; + [case(2)] LPRPL_BOOT_INFO_2_CONTAINER Level2; + } BootInfo; +} RPL_BOOT_ENUM, *PRPL_BOOT_ENUM, *LPRPL_BOOT_ENUM; + +typedef [switch_type(DWORD)] union _RPL_BOOT_INFO_STRUCT { + [case(0)] LPRPL_BOOT_INFO_0 BootInfo0; + [case(1)] LPRPL_BOOT_INFO_1 BootInfo1; + [case(2)] LPRPL_BOOT_INFO_2 BootInfo2; +} RPL_BOOT_INFO_STRUCT, *PRPL_BOOT_INFO_STRUCT, *LPRPL_BOOT_INFO_STRUCT; + + + +// +// CONFIG data - used by Enum +// + +typedef struct _RPL_CONFIG_INFO_0_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_CONFIG_INFO_0 Buffer; +} RPL_CONFIG_INFO_0_CONTAINER, *PRPL_CONFIG_INFO_0_CONTAINER, *LPRPL_CONFIG_INFO_0_CONTAINER; + +typedef struct _RPL_CONFIG_INFO_1_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_CONFIG_INFO_1 Buffer; +} RPL_CONFIG_INFO_1_CONTAINER, *PRPL_CONFIG_INFO_1_CONTAINER, *LPRPL_CONFIG_INFO_1_CONTAINER; + +typedef struct _RPL_CONFIG_INFO_2_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_CONFIG_INFO_2 Buffer; +} RPL_CONFIG_INFO_2_CONTAINER, *PRPL_CONFIG_INFO_2_CONTAINER, *LPRPL_CONFIG_INFO_2_CONTAINER; + +typedef struct _RPL_CONFIG_ENUM { + DWORD Level; + [switch_is(Level)] union _RPL_CONFIG_ENUM_UNION { + [case(0)] LPRPL_CONFIG_INFO_0_CONTAINER Level0; + [case(1)] LPRPL_CONFIG_INFO_1_CONTAINER Level1; + [case(2)] LPRPL_CONFIG_INFO_2_CONTAINER Level2; + } ConfigInfo; +} RPL_CONFIG_ENUM, *PRPL_CONFIG_ENUM, *LPRPL_CONFIG_ENUM; + +typedef [switch_type(DWORD)] union _RPL_CONFIG_INFO_STRUCT { + [case(0)] LPRPL_CONFIG_INFO_0 ConfigInfo0; + [case(1)] LPRPL_CONFIG_INFO_1 ConfigInfo1; + [case(2)] LPRPL_CONFIG_INFO_2 ConfigInfo2; +} RPL_CONFIG_INFO_STRUCT, *PRPL_CONFIG_INFO_STRUCT, *LPRPL_CONFIG_INFO_STRUCT; + + + +// +// PROFILE data - used by Enum, Get, Set & Add +// + +typedef struct _RPL_PROFILE_INFO_0_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_PROFILE_INFO_0 Buffer; +} RPL_PROFILE_INFO_0_CONTAINER, *PRPL_PROFILE_INFO_0_CONTAINER, *LPRPL_PROFILE_INFO_0_CONTAINER; + +typedef struct _RPL_PROFILE_INFO_1_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_PROFILE_INFO_1 Buffer; +} RPL_PROFILE_INFO_1_CONTAINER, *PRPL_PROFILE_INFO_1_CONTAINER, *LPRPL_PROFILE_INFO_1_CONTAINER; + +typedef struct _RPL_PROFILE_INFO_2_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_PROFILE_INFO_2 Buffer; +} RPL_PROFILE_INFO_2_CONTAINER, *PRPL_PROFILE_INFO_2_CONTAINER, *LPRPL_PROFILE_INFO_2_CONTAINER; + + +typedef struct _RPL_PROFILE_ENUM { + DWORD Level; + [switch_is(Level)] union _RPL_PROFILE_ENUM_UNION { + [case(0)] LPRPL_PROFILE_INFO_0_CONTAINER Level0; + [case(1)] LPRPL_PROFILE_INFO_1_CONTAINER Level1; + [case(2)] LPRPL_PROFILE_INFO_2_CONTAINER Level2; + } ProfileInfo; +} RPL_PROFILE_ENUM, *PRPL_PROFILE_ENUM, *LPRPL_PROFILE_ENUM; + + +typedef [switch_type(DWORD)] union _RPL_PROFILE_INFO_STRUCT { + [case(0)] LPRPL_PROFILE_INFO_0 ProfileInfo0; + [case(1)] LPRPL_PROFILE_INFO_1 ProfileInfo1; + [case(2)] LPRPL_PROFILE_INFO_2 ProfileInfo2; +} RPL_PROFILE_INFO_STRUCT, *PRPL_PROFILE_INFO_STRUCT, *LPRPL_PROFILE_INFO_STRUCT, PRPL_PROFILE_INFO, LPRPL_PROFILE_INFO; + + +// +// VENDOR data - used by Enum +// + +typedef struct _RPL_VENDOR_INFO_0_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_VENDOR_INFO_0 Buffer; +} RPL_VENDOR_INFO_0_CONTAINER, *PRPL_VENDOR_INFO_0_CONTAINER, *LPRPL_VENDOR_INFO_0_CONTAINER; + +typedef struct _RPL_VENDOR_INFO_1_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_VENDOR_INFO_1 Buffer; +} RPL_VENDOR_INFO_1_CONTAINER, *PRPL_VENDOR_INFO_1_CONTAINER, *LPRPL_VENDOR_INFO_1_CONTAINER; + +typedef struct _RPL_VENDOR_ENUM { + DWORD Level; + [switch_is(Level)] union _RPL_VENDOR_ENUM_UNION { + [case(0)] LPRPL_VENDOR_INFO_0_CONTAINER Level0; + [case(1)] LPRPL_VENDOR_INFO_1_CONTAINER Level1; + } VendorInfo; +} RPL_VENDOR_ENUM, *PRPL_VENDOR_ENUM, *LPRPL_VENDOR_ENUM; + +typedef [switch_type(DWORD)] union _RPL_VENDOR_INFO_STRUCT { + [case(0)] LPRPL_VENDOR_INFO_0 VendorInfo0; + [case(1)] LPRPL_VENDOR_INFO_1 VendorInfo1; +} RPL_VENDOR_INFO_STRUCT, *PRPL_VENDOR_INFO_STRUCT, *LPRPL_VENDOR_INFO_STRUCT; + + +// +// ADAPTER data - used by Enum +// + +typedef struct _RPL_ADAPTER_INFO_0_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_ADAPTER_INFO_0 Buffer; +} RPL_ADAPTER_INFO_0_CONTAINER, *PRPL_ADAPTER_INFO_0_CONTAINER, *LPRPL_ADAPTER_INFO_0_CONTAINER; + +typedef struct _RPL_ADAPTER_INFO_1_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_ADAPTER_INFO_1 Buffer; +} RPL_ADAPTER_INFO_1_CONTAINER, *PRPL_ADAPTER_INFO_1_CONTAINER, *LPRPL_ADAPTER_INFO_1_CONTAINER; + +typedef struct _RPL_ADAPTER_ENUM { + DWORD Level; + [switch_is(Level)] union _RPL_ADAPTER_ENUM_UNION { + [case(0)] LPRPL_ADAPTER_INFO_0_CONTAINER Level0; + [case(1)] LPRPL_ADAPTER_INFO_1_CONTAINER Level1; + } AdapterInfo; +} RPL_ADAPTER_ENUM, *PRPL_ADAPTER_ENUM, *LPRPL_ADAPTER_ENUM; + +typedef [switch_type(DWORD)] union _RPL_ADAPTER_INFO_STRUCT { + [case(0)] LPRPL_ADAPTER_INFO_0 AdapterInfo0; + [case(1)] LPRPL_ADAPTER_INFO_1 AdapterInfo1; +} RPL_ADAPTER_INFO_STRUCT, *PRPL_ADAPTER_INFO_STRUCT, *LPRPL_ADAPTER_INFO_STRUCT; + + +// +// WKSTA data - used by Enum, Get, Set & Add +// + +typedef struct _RPL_WKSTA_INFO_0_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_WKSTA_INFO_0 Buffer; +} RPL_WKSTA_INFO_0_CONTAINER, *PRPL_WKSTA_INFO_0_CONTAINER, *LPRPL_WKSTA_INFO_0_CONTAINER; + +typedef struct _RPL_WKSTA_INFO_1_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_WKSTA_INFO_1 Buffer; +} RPL_WKSTA_INFO_1_CONTAINER, *PRPL_WKSTA_INFO_1_CONTAINER, *LPRPL_WKSTA_INFO_1_CONTAINER; + +typedef struct _RPL_WKSTA_INFO_2_CONTAINER { + DWORD EntriesRead; + [size_is(EntriesRead)] LPRPL_WKSTA_INFO_2 Buffer; +} RPL_WKSTA_INFO_2_CONTAINER, *PRPL_WKSTA_INFO_2_CONTAINER, *LPRPL_WKSTA_INFO_2_CONTAINER; + + +typedef struct _RPL_WKSTA_ENUM { + DWORD Level; + [switch_is(Level)] union _RPL_WKSTA_ENUM_UNION { + [case(0)] LPRPL_WKSTA_INFO_0_CONTAINER Level0; + [case(1)] LPRPL_WKSTA_INFO_1_CONTAINER Level1; + [case(2)] LPRPL_WKSTA_INFO_2_CONTAINER Level2; + } WkstaInfo; +} RPL_WKSTA_ENUM, *PRPL_WKSTA_ENUM, *LPRPL_WKSTA_ENUM; + + +typedef [switch_type(DWORD)] union _RPL_WKSTA_INFO_STRUCT { + [case(0)] LPRPL_WKSTA_INFO_0 WkstaInfo0; + [case(1)] LPRPL_WKSTA_INFO_1 WkstaInfo1; + [case(2)] LPRPL_WKSTA_INFO_2 WkstaInfo2; +} RPL_WKSTA_INFO_STRUCT, *PRPL_WKSTA_INFO_STRUCT, *LPRPL_WKSTA_INFO_STRUCT; + +// +// Function Prototypes +// + +// +// Service apis +// + +NET_API_STATUS NET_API_FUNCTION +NetrRplOpen( + [in,string,unique] RPL_NAME ServerName, + [out] LPRPL_RPC_HANDLE ServerHandle + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplClose( + [in,out] LPRPL_RPC_HANDLE ServerHandle + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplGetInfo( + [in] RPL_RPC_HANDLE ServerHandle, + [in] DWORD Level, + [out, switch_is(Level)] LPRPL_INFO_STRUCT InfoStruct + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplSetInfo( + [in] RPL_RPC_HANDLE ServerHandle, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_INFO_STRUCT InfoStruct, + [in,out,unique] LPDWORD ErrorParameter + ); + +// +// ADAPTER apis +// + +NET_API_STATUS NET_API_FUNCTION +NetrRplAdapterAdd( + [in] RPL_RPC_HANDLE ServerHandle, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_ADAPTER_INFO_STRUCT AdapterInfoStruct, + [in,out,unique] LPDWORD ErrorParameter + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplAdapterDel( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string,unique] LPTSTR AdapterName + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplAdapterEnum( + [in] RPL_RPC_HANDLE ServerHandle, + [in,out] LPRPL_ADAPTER_ENUM AdapterEnum, + [in] DWORD PrefMaxLength, + [out] LPDWORD TotalEntries, + [in,out,unique] LPDWORD ResumeHandle + ); + + +// +// BOOT apis +// + +NET_API_STATUS NET_API_FUNCTION +NetrRplBootAdd( + [in] RPL_RPC_HANDLE ServerHandle, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_BOOT_INFO_STRUCT BootInfoStruct, + [in,out,unique] LPDWORD ErrorParameter + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplBootDel( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR BootName, + [in,string] LPTSTR VendorName + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplBootEnum( + [in] RPL_RPC_HANDLE ServerHandle, + [in,out] LPRPL_BOOT_ENUM BootEnum, + [in] DWORD PrefMaxLength, + [out] LPDWORD TotalEntries, + [in,out,unique] LPDWORD ResumeHandle + ); + +// +// CONFIG apis +// + +NET_API_STATUS NET_API_FUNCTION +NetrRplConfigAdd( + [in] RPL_RPC_HANDLE ServerHandle, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_CONFIG_INFO_STRUCT ConfigInfoStruct, + [in,out,unique] LPDWORD ErrorParameter + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplConfigDel( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR ConfigName + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplConfigEnum( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string,unique] LPTSTR AdapterName, + [in,out] LPRPL_CONFIG_ENUM ConfigEnum, + [in] DWORD PrefMaxLength, + [out] LPDWORD TotalEntries, + [in,out,unique] LPDWORD ResumeHandle + ); + +// +// PROFILE apis +// + +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileAdd( + [in] RPL_RPC_HANDLE ServerHandle, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_PROFILE_INFO_STRUCT ProfileInfoStruct, + [in,out,unique] LPDWORD ErrorParameter + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileClone( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR SourceProfileName, + [in,string] LPTSTR TargetProfileName, + [in,string,unique] LPTSTR TargetProfileComment + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileDel( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR ProfileName + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileEnum( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string,unique] LPTSTR AdapterName, + [in,out] LPRPL_PROFILE_ENUM ProfileEnum, + [in] DWORD PrefMaxLength, + [out] LPDWORD TotalEntries, + [in,out,unique] LPDWORD ResumeHandle + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileGetInfo( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR ProfileName, + [in] DWORD Level, + [out, switch_is(Level)] LPRPL_PROFILE_INFO_STRUCT ProfileInfoStruct + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileSetInfo( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR ProfileName, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_PROFILE_INFO_STRUCT ProfileInfoStruct, + [in,out,unique] LPDWORD ErrorParameter + ); + +// +// VENDOR apis +// + +NET_API_STATUS NET_API_FUNCTION +NetrRplVendorAdd( + [in] RPL_RPC_HANDLE ServerHandle, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_VENDOR_INFO_STRUCT VendorInfoStruct, + [in,out,unique] LPDWORD ErrorParameter + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplVendorDel( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR VendorName + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplVendorEnum( + [in] RPL_RPC_HANDLE ServerHandle, + [in,out] LPRPL_VENDOR_ENUM VendorEnum, + [in] DWORD PrefMaxLength, + [out] LPDWORD TotalEntries, + [in,out,unique] LPDWORD ResumeHandle + ); + +// +// WKSTA apis +// + +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaAdd( + [in] RPL_RPC_HANDLE ServerHandle, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_WKSTA_INFO_STRUCT WkstaInfo, + [in,out,unique] LPDWORD ErrorParameter + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaClone( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR SourceWkstaName, + [in,string] LPTSTR TargetWkstaName, + [in,string,unique] LPTSTR TargetWkstaComment, + [in,string] LPTSTR TargetAdapterName, + [in] DWORD TargetWkstaIpAddress + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaDel( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR WkstaName + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaEnum( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string,unique] LPTSTR ProfileName, + [in,out] LPRPL_WKSTA_ENUM WkstaEnum, + [in] DWORD PrefMaxLength, + [out] LPDWORD TotalEntries, + [in,out,unique] LPDWORD ResumeHandle + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaGetInfo( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR WkstaName, + [in] DWORD Level, + [out, switch_is(Level)] LPRPL_WKSTA_INFO_STRUCT WkstaInfoStruct + ); +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaSetInfo( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string] LPTSTR WkstaName, + [in] DWORD Level, + [in, switch_is(Level)] LPRPL_WKSTA_INFO_STRUCT WkstaInfoStruct, + [in,out,unique] LPDWORD ErrorParameter + ); + +// +// SECURITY api +// +NET_API_STATUS NET_API_FUNCTION +NetrRplSetSecurity( + [in] RPL_RPC_HANDLE ServerHandle, + [in,string,unique] LPTSTR WkstaName, + [in] DWORD WkstaRid, + [in] DWORD RplUserRid + ); + + +} + +
\ No newline at end of file diff --git a/private/net/svcdlls/rpl/rplsvc_c.acf b/private/net/svcdlls/rpl/rplsvc_c.acf new file mode 100644 index 000000000..a1e493fb0 --- /dev/null +++ b/private/net/svcdlls/rpl/rplsvc_c.acf @@ -0,0 +1,33 @@ +[implicit_handle (handle_t rplsvc_handle)] + +interface rplsvc + +{ + +typedef [allocate(all_nodes)] LPRPL_INFO_0; +typedef [allocate(all_nodes)] LPRPL_INFO_1; + +typedef [allocate(all_nodes)] LPRPL_BOOT_INFO_0; +typedef [allocate(all_nodes)] LPRPL_BOOT_INFO_1; +typedef [allocate(all_nodes)] LPRPL_BOOT_INFO_2; + +typedef [allocate(all_nodes)] LPRPL_CONFIG_INFO_0; +typedef [allocate(all_nodes)] LPRPL_CONFIG_INFO_1; +typedef [allocate(all_nodes)] LPRPL_CONFIG_INFO_2; + +typedef [allocate(all_nodes)] LPRPL_PROFILE_INFO_0; +typedef [allocate(all_nodes)] LPRPL_PROFILE_INFO_1; +typedef [allocate(all_nodes)] LPRPL_PROFILE_INFO_2; + +typedef [allocate(all_nodes)] LPRPL_VENDOR_INFO_0; +typedef [allocate(all_nodes)] LPRPL_VENDOR_INFO_1; + +typedef [allocate(all_nodes)] LPRPL_ADAPTER_INFO_0; +typedef [allocate(all_nodes)] LPRPL_ADAPTER_INFO_1; + +typedef [allocate(all_nodes)] LPRPL_WKSTA_INFO_0; +typedef [allocate(all_nodes)] LPRPL_WKSTA_INFO_1; +typedef [allocate(all_nodes)] LPRPL_WKSTA_INFO_2; + +} +
\ No newline at end of file diff --git a/private/net/svcdlls/rpl/rplsvc_s.acf b/private/net/svcdlls/rpl/rplsvc_s.acf new file mode 100644 index 000000000..157ff2912 --- /dev/null +++ b/private/net/svcdlls/rpl/rplsvc_s.acf @@ -0,0 +1,7 @@ +[implicit_handle (handle_t rplsvc_handle)] + +interface rplsvc + +{ +} +
\ No newline at end of file diff --git a/private/net/svcdlls/rpl/server/adapter.c b/private/net/svcdlls/rpl/server/adapter.c new file mode 100644 index 000000000..95756c78c --- /dev/null +++ b/private/net/svcdlls/rpl/server/adapter.c @@ -0,0 +1,502 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + adapter.c + +Abstract: + + Adapter APIs. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "db.h" +#include "dblib.h" +#define RPLADAPTER_ALLOCATE +#include "adapter.h" +#undef RPLADAPTER_ALLOCATE +#include "database.h" + + + +DWORD AdapterGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + IN OUT LPINT pSpaceLeft + ) +{ + BYTE LocalBuffer[ 300]; + PBYTE Buffer; + DWORD DataSize; + DWORD BufferSize; + JET_ERR JetError; + + switch( FieldIndex) { + case ADAPTER_Flags: + Buffer = (PBYTE)pData; + BufferSize = sizeof( DWORD); + break; + default: + Buffer = LocalBuffer; + BufferSize = sizeof( LocalBuffer); + break; + } + JetError = JetRetrieveColumn( pSession->SesId, pSession->AdapterTableId, + AdapterTable[ FieldIndex].ColumnId, LocalBuffer, + sizeof( LocalBuffer), &DataSize, 0, NULL); + if ( JetError < 0) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + return( NERR_RplAdapterInfoCorrupted); + } + if ( Buffer != LocalBuffer) { + if ( BufferSize == DataSize) { + return( NO_ERROR); + } else { + RplDump( ++RG_Assert, ("Bad DataSize=0x%x", DataSize)); + return( NERR_RplAdapterInfoCorrupted); + } + } + // + // We have done with fixed data. From here on we deal with unicode + // strings only. + // + if ( DataSize > sizeof( LocalBuffer)) { + RplDump( ++RG_Assert, ( "Too big DataSize=0x%x", DataSize)); + return( NERR_RplAdapterInfoCorrupted); + } + if ( DataSize == 0) { + if ( JetError != JET_wrnColumnNull) { + RplDump( ++RG_Assert, ( "JetError=%d", JetError)); + return( NERR_RplAdapterInfoCorrupted); + } else { + *pData = NULL; // so RPC rpcrt4!_tree_size_ndr() does not bomb here + return( NO_ERROR); + } + } + if ( DataSize & 1 != 0 || wcslen((PWCHAR)LocalBuffer) + 1 != DataSize/2) { + RplDump( ++RG_Assert, ("LocalBuffer=0x%x, DataSize=0x%x", LocalBuffer, DataSize)); + return( NERR_RplAdapterInfoCorrupted); + } + *pData = MIDL_user_allocate( DataSize); + if ( *pData == NULL) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + return( ERROR_NOT_ENOUGH_MEMORY); + } + memcpy( *pData, LocalBuffer, DataSize); + *pSpaceLeft -= DataSize; + return( NO_ERROR); +} + + +DWORD AdapterGetInfo( + IN PRPL_SESSION pSession, + IN LPWSTR AdapterName, + IN DWORD Level, + OUT LPVOID Buffer, + OUT PINT pSpaceLeft + ) +{ + DWORD Error; + LPRPL_ADAPTER_INFO_1 Info = Buffer; + + switch( Level) { + case 1: + Error = AdapterGetField( pSession, ADAPTER_Flags, (LPVOID *)&Info->Flags, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 0: + Error = AdapterGetField( pSession, ADAPTER_AdapterComment, &Info->AdapterComment, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + if ( AdapterName == NULL) { + Error = AdapterGetField( pSession, ADAPTER_AdapterName, &Info->AdapterName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + } else { + DWORD DataSize = (wcslen( AdapterName) + 1) * sizeof(WCHAR); + Info->AdapterName = MIDL_user_allocate( DataSize); + if ( Info->AdapterName == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_ADAPTER, ( "AdapterName=0x%x", Info->AdapterName)); + memcpy( Info->AdapterName, AdapterName, DataSize); + *pSpaceLeft -= DataSize; + } + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + return( NO_ERROR); +} + + + +VOID AdapterGetInfoCleanup( + IN DWORD Level, + IN OUT LPVOID Buffer + ) +{ + switch( Level) { + case 0: { + LPRPL_ADAPTER_INFO_0 Info = Buffer; + if ( Info->AdapterName != NULL) { + MIDL_user_free( Info->AdapterName); + } + if ( Info->AdapterComment != NULL) { + MIDL_user_free( Info->AdapterComment); + } + break; + } + } +} + + +DWORD AdapterSetInfo( + IN PRPL_SESSION pSession, + IN DWORD Level, + OUT LPVOID Buffer, + OUT LPDWORD pErrorParameter + ) +{ + LPRPL_ADAPTER_INFO_1 Info = Buffer; + switch( Level) { + case 1: + // + // Must initialize Flags - or will trap in GetField. + // + { + *pErrorParameter = ADAPTER_Flags; + CallM( JetSetColumn( pSession->SesId, pSession->AdapterTableId, + AdapterTable[ ADAPTER_Flags].ColumnId, + &Info->Flags, sizeof( Info->Flags), 0, NULL)); + } + NOTHING; // fall through + case 0: + if ( Info->AdapterComment != NULL) { + *pErrorParameter = ADAPTER_AdapterComment; + CallM( JetSetColumn( pSession->SesId, pSession->AdapterTableId, + AdapterTable[ ADAPTER_AdapterComment].ColumnId, + Info->AdapterComment, + ( wcslen( Info->AdapterComment) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->AdapterName != NULL) { + *pErrorParameter = ADAPTER_AdapterName; + CallM( JetSetColumn( pSession->SesId, pSession->AdapterTableId, + AdapterTable[ ADAPTER_AdapterName].ColumnId, + Info->AdapterName, + ( wcslen( Info->AdapterName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + break; + } + return( NO_ERROR); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplAdapterAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD Level, + IN LPRPL_ADAPTER_INFO_STRUCT AdapterInfoStruct, + OUT LPDWORD pErrorParameter OPTIONAL + ) +{ + LPRPL_ADAPTER_INFO_1 Info; + LPVOID Buffer; + DWORD Error; + DWORD ErrorParameter; + PRPL_SESSION pSession = &RG_ApiSession; + + ErrorParameter = INVALID_ERROR_PARAMETER; + + Buffer = Info = AdapterInfoStruct->AdapterInfo1; + switch( Level) { + case 1: + if ( Info->Flags != 0) { + ErrorParameter = ADAPTER_Flags; + break; + } + if ( RPL_STRING_TOO_LONG( Info->AdapterComment)) { + ErrorParameter = ADAPTER_AdapterComment; + break; + } + if ( !ValidHexName( Info->AdapterName, RPL_ADAPTER_NAME_LENGTH, TRUE)) { + ErrorParameter = ADAPTER_AdapterName; + break; + } + _wcsupr( Info->AdapterName); + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + return( ERROR_INVALID_PARAMETER); + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + // + // Verify that AdapterName is available in the database. + // + if ( RplFind( pSession, ADAPTER_TABLE_TAG, Info->AdapterName)) { + Error = NERR_RplAdapterNameUnavailable; + goto cleanup; + } + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->AdapterTableId, JET_prepInsert)); + + Error = AdapterSetInfo( pSession, Level, Buffer, &ErrorParameter); + if ( Error == ERROR_SUCCESS) { + ErrorParameter = 0; + CallJ( JetUpdate( pSession->SesId, pSession->AdapterTableId, NULL, 0, NULL)); + } + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( Error != ERROR_SUCCESS) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + } + return( Error); +} + + + +NET_API_STATUS NET_API_FUNCTION +NetrRplAdapterDel( + IN RPL_HANDLE ServerHandle, + IN LPWSTR AdapterName + ) +/*++ + If AdapterName is provided then delete matching record, else delete all + adapter records. +--*/ +{ + JET_ERR JetError; + DWORD Error = NO_ERROR; + PRPL_SESSION pSession = &RG_ApiSession; + + if ( !ValidHexName( AdapterName, RPL_ADAPTER_NAME_LENGTH, FALSE)) { + return( ERROR_INVALID_PARAMETER); + } + if ( AdapterName != NULL) { + _wcsupr( AdapterName); + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( AdapterName != NULL) { + if ( !RplFind( pSession, ADAPTER_TABLE_TAG, AdapterName)) { + Error = NERR_RplAdapterNotFound; + goto cleanup; + } + CallJ( JetDelete( pSession->SesId, pSession->AdapterTableId)); + } else { + CallJ( JetSetCurrentIndex( pSession->SesId, pSession->AdapterTableId, ADAPTER_INDEX_AdapterName)); + // + // The call to move to the beginning of the table is not redundant. + // E.g. JET_errNoCurrentRecord will be returned in case of empty table. + // + JetError = JetMove( pSession->SesId, pSession->AdapterTableId, JET_MoveFirst, 0); + if ( JetError < 0) { + if ( JetError != JET_errRecordNotFound + && JetError != JET_errNoCurrentRecord) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + Error = NERR_RplInternal; + } + goto cleanup; + } + do { + CallJ( JetDelete( pSession->SesId, pSession->AdapterTableId)); + JetError = JetMove( pSession->SesId, pSession->AdapterTableId, JET_MoveNext, 0); + } while ( JetError == JET_errSuccess); + } + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplAdapterEnum( + IN RPL_HANDLE ServerHandle, + IN OUT LPRPL_ADAPTER_ENUM AdapterEnum, + IN DWORD PrefMaxLength, + OUT LPDWORD TotalEntries, + OUT LPDWORD pResumeHandle OPTIONAL + ) +/*++ + For more extensive comments see related code in NetrAdapterEnum. +--*/ +{ + LPBYTE Buffer; + DWORD TypicalSize; + DWORD CoreSize; + DWORD Error; + INT SpaceLeft; + DWORD ArrayLength; + DWORD EntriesRead; + JET_ERR JetError; + BOOL InfoError; + BOOL TableEnd; + PRPL_SESSION pSession = &RG_ApiSession; + + // + // For now we here we disallow all levels but 0 level. All other code + // would work for levels 0 and 1. + // + switch( AdapterEnum->Level) { + case 1: + TypicalSize = CoreSize = sizeof( RPL_ADAPTER_INFO_1); + NOTHING; // fall through + case 0: + if ( AdapterEnum->Level == 0) { + TypicalSize = CoreSize = sizeof( RPL_ADAPTER_INFO_0); + } + TypicalSize += 8 * sizeof( WCHAR); // typical size of AdapterName + TypicalSize += 20 * sizeof( WCHAR); // typical size of AdapterComment + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( PrefMaxLength == -1) { + SpaceLeft = DEFAULT_BUFFER_SIZE; + } else { + SpaceLeft = PrefMaxLength; + } + + ArrayLength = SpaceLeft / TypicalSize; + if ( ArrayLength == 0) { + ArrayLength = 1; // try to return at least one element + } + + Buffer = MIDL_user_allocate( ArrayLength * CoreSize); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_ADAPTER, ( + "AdapterEnum: Buffer=0x%x, ArrayLength=0x%x", Buffer, ArrayLength)); + + AdapterEnum->AdapterInfo.Level0->Buffer = (LPRPL_ADAPTER_INFO_0)Buffer; + + EntriesRead = 0; + InfoError = FALSE; + Error = NO_ERROR; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFilterFirst( pSession, ADAPTER_TABLE_TAG, NULL, pResumeHandle, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + for ( ; ; ) { + memset( Buffer, 0, CoreSize); // for cleanup to work properly + Error = AdapterGetInfo( pSession, NULL, AdapterEnum->Level, Buffer, &SpaceLeft); + if ( Error != NO_ERROR) { + InfoError = TRUE; // clean things up without holding crit sec + break; + } + EntriesRead++; + Buffer += CoreSize; + SpaceLeft -= CoreSize; + JetError = JetMove( pSession->SesId, pSession->AdapterTableId, JET_MoveNext, 0); + if ( JetError != JET_errSuccess) { + break; // assume end of table + } + if ( SpaceLeft <= 0) { + Error = ERROR_MORE_DATA; + break; + } + if ( EntriesRead >= ArrayLength) { + Error = ERROR_MORE_DATA; + break; + } + } +cleanup: + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + if ( InfoError == TRUE) { + AdapterGetInfoCleanup( AdapterEnum->Level, Buffer); + } + if ( Error == NO_ERROR) { + *TotalEntries = EntriesRead; + } else if ( Error == ERROR_MORE_DATA) { + *TotalEntries = EntriesRead * 2; // we cheat here + } else { + // + // Cleanup in case of "bad" errors. + // + while ( EntriesRead > 0) { + EntriesRead--; + Buffer -= CoreSize; + AdapterGetInfoCleanup( AdapterEnum->Level, Buffer); + } + MIDL_user_free( Buffer); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_ADAPTER, ("AdapterEnum: EntriesRead = 0x%x", EntriesRead)); + + AdapterEnum->AdapterInfo.Level0->EntriesRead = EntriesRead; + if ( EntriesRead == 0) { + AdapterEnum->AdapterInfo.Level0->Buffer = NULL; + } + + if ( ARGUMENT_PRESENT( pResumeHandle)) { + if ( Error == ERROR_MORE_DATA && EntriesRead > 0) { + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + RplFilterSave( pSession, (DWORD)ServerHandle, NULL, + ((LPRPL_ADAPTER_INFO_0)(Buffer-CoreSize))->AdapterName, + pResumeHandle); + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + LeaveCriticalSection( &RG_ProtectDatabase); + } else { + *pResumeHandle = 0; // resume from beginning + } + } + return( Error); +} + diff --git a/private/net/svcdlls/rpl/server/apisec.c b/private/net/svcdlls/rpl/server/apisec.c new file mode 100644 index 000000000..7fbd8184d --- /dev/null +++ b/private/net/svcdlls/rpl/server/apisec.c @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + rplsec.c + +Abstract: + + This module contains the remote boot service support routines + that create security objects and enforce security _access checking. + +Author: + + Vladimir Z. Vulovic (vladimv) 06 - November - 1992 + +Revision History: + + 06-Nov-1992 vladimv + Created + +--*/ + +#include "local.h" +#include "apisec.h" +#include <netlibnt.h> // NetpNtStatusToApiStatus +#include <secobj.h> // ACE_DATA + +// +// Structure that describes the mapping of Generic access rights to +// object specific access rights for the remote boot service security object. +// +GENERIC_MAPPING RG_SecurityMapping = { + STANDARD_RIGHTS_READ | // Generic read + RPL_RECORD_ENUM | + RPL_RECORD_GET_INFO, + STANDARD_RIGHTS_WRITE | // Generic write + RPL_RECORD_ADD | + RPL_RECORD_SET_INFO | + RPL_RECORD_DEL, + STANDARD_RIGHTS_EXECUTE, // Generic execute + RPL_RECORD_ALL_ACCESS | // Generic all + RPL_RECORD_CLONE + }; + +PSECURITY_DESCRIPTOR RG_SecurityDescriptor; + + +NET_API_STATUS RplCreateSecurityObject( VOID) +/*++ + +Routine Description: + + This function creates the remote bootr user-mode configuration + information object which is represented by a security descriptors. + +Arguments: + + None. + +Return Value: + + NET_API_STATUS code + +--*/ +{ + NTSTATUS status; + + // + // Order matters! These ACEs are inserted into the DACL in the + // following order. Security access is granted or denied based on + // the order of the ACEs in the DACL. + // + // LocalGroupAdmins are fow now allowed to perform all remote boot + // Service operations. Everybody else is denied. + // + + ACE_DATA aceData[] = { + {ACCESS_ALLOWED_ACE_TYPE, 0, 0, GENERIC_ALL, &AliasAdminsSid} + }; + + + status = NetpCreateSecurityObject( + aceData, // pAceData + sizeof(aceData) / sizeof(aceData[0]), // countAceData + NULL, // OwnerSid + NULL, // PrimaryGroupSid + &RG_SecurityMapping, // GenericToSpecificMapping + &RG_SecurityDescriptor // ppNewDescriptor + ); + + if ( ! NT_SUCCESS (status)) { + RplDump( ++RG_Assert, ( "status = 0x%x", status)); + return NetpNtStatusToApiStatus( status); + } + + return( NO_ERROR); +} + + + +DWORD RplDeleteSecurityObject( VOID) +/*++ + +Routine Description: + + This function destroys the remote boot service user-mode configuration + information object which is represented by a security descriptors. + +Arguments: + + None. + +Return Value: + + NET_API_STATUS code + +--*/ +{ + return( NetpDeleteSecurityObject( &RG_SecurityDescriptor)); +} + + diff --git a/private/net/svcdlls/rpl/server/apisec.h b/private/net/svcdlls/rpl/server/apisec.h new file mode 100644 index 000000000..4393620e3 --- /dev/null +++ b/private/net/svcdlls/rpl/server/apisec.h @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) 1987-94 Microsoft Corporation + +Module Name: + + rplsec.h + +Abstract: + + Functions exported by rplsec.c + +Author: + + Vladimir Z. Vulovic (vladimv) 05 - April - 1994 + +Revision History: + + 05-Apr-1994 vladimv + Created + +--*/ + +NET_API_STATUS RplCheckSecurity( ACCESS_MASK DesiredAccess); +NET_API_STATUS RplCreateSecurityObject( VOID); +NET_API_STATUS RplDeleteSecurityObject( VOID); + +// +// Object specific access masks +// + +#define RPL_RECORD_ADD 0x0001 +#define RPL_RECORD_CLONE 0x0002 +#define RPL_RECORD_DEL 0x0004 +#define RPL_RECORD_ENUM 0x0008 +#define RPL_RECORD_GET_INFO 0x0010 +#define RPL_RECORD_SET_INFO 0x0020 + +#define RPL_RECORD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + RPL_RECORD_ADD | \ + RPL_RECORD_DEL | \ + RPL_RECORD_ENUM | \ + RPL_RECORD_CLONE | \ + RPL_RECORD_SET_INFO | \ + RPL_RECORD_GET_INFO ) + + +#define SECURITY_OBJECT L"RplSecurityObject" + +extern PSECURITY_DESCRIPTOR RG_SecurityDescriptor; +extern GENERIC_MAPPING RG_SecurityMapping; + diff --git a/private/net/svcdlls/rpl/server/bbcfile.c b/private/net/svcdlls/rpl/server/bbcfile.c new file mode 100644 index 000000000..6344ceb93 --- /dev/null +++ b/private/net/svcdlls/rpl/server/bbcfile.c @@ -0,0 +1,1059 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + bbcfile.c + +Abstract: + + Processes boot block configuration file. + + Provides bbcfile functionality similar to that contained in init.c + & patch.c of LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + + + +#include "local.h" +#include "bbcfile.h" + +// +// Checksum buffer size is chosen to be a multiple of 8 * sizeof( DWORD). +// to speed up checksum algorithm below. This is not a requirement though. +// +#define CHK_SUM_BUF_SIZE ( 8 * sizeof( DWORD) * 256) // 8K + +#define NO_PATCH_OFFSET ((DWORD)-1) + +#define PARAM_INDEX 2 // index of parameters in sys/com/exe line +// +// PARAM_INDEX string when expressed in DBCS should not exceed 0xFF bytes. +// +#define MAX_SIZE_DBCS_PARAMS (0xFF+1) + +#define MEM_INDEX 3 // index of extra memory in sys/com/exe line +#define MOVEABLE_INDEX 4 // set if driver can be moved after init + +// +// MOVABLE_INDEX string may be take one of the following two values. +// +#define MOVEABLE_SWITCH L'M' +#define EXEC_IN_LOW_MEM_SWITCH L'L' // undocumented switch value + +#define MAX_FLIST_LEN 255 + +// +// Indices used for parsing of lines in boot block configuration files. +// + +#define CONF_LINE_ID 0 // index of line type +#define CONF_LINE_FILE 1 // index of file (rel path) in config line +#define CONF_LINE_BASE_ADDRESS 1 // index of file (rel path) in config line +#define FIRST_FILE_NAME 3 // index of the first file name in LDR line + +#define MAX_CONFIG_FIELDS 8 // maximum number of fields in config line + +#define MIN_BBLOCK_BASE_SEG 0xc0 +#define TILDE_STRING L"~" +#define SPACE_STRING L" " + + + +DWORD StringToDword( IN PWCHAR String) +/*++ + We would like to use generic base (0) but it does not work for + strings like "D0H". That is the reason why we first check if + the last character is 'H' or 'h'. +--*/ +{ + DWORD Length; + + Length = wcslen( String); + if ( Length == 0) { + return( 0); + } + if ( String[ Length-1] == L'H' || String[ Length-1] == L'h') { + return( wcstoul( String, NULL, 16)); + } else { + return( wcstoul( String, NULL, 0)); + } +} + + +BOOL RplInitExeOrSys( + IN PRPL_WORKER_DATA pWorkerData, + IN OUT PFLIST_TBL pFlist + ) +/*++ + +Routine Description: + Retreives the file type of a binary (exe/com/sys) file. + +Arguments: + pFlist - pointer to FLIST_TBL element + +Return Value: + TRUE if successful, else FALSE. + +--*/ +{ + BYTE id_tbl[2]; + HANDLE FileHandle; + DWORD bytes_read; + DWORD DbcsSize; + LPSTR DbcsString; + PWCHAR * WordTable; + + FileHandle = RplFileOpen( pFlist->path_name); + if ( FileHandle == INVALID_HANDLE_VALUE) { + RplDump( ++RG_Assert, ( "path_name=%ws", pFlist->path_name)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pFlist->path_name; + pWorkerData->EventId = NELOG_RplWkstaFileOpen; + return( FALSE); + } + + if ( !ReadFile( FileHandle, id_tbl, 2, &bytes_read, NULL)) { + RplDump( ++RG_Assert, ( "Error = %d", GetLastError())); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pFlist->path_name; + pWorkerData->EventId = NELOG_RplWkstaFileRead; + (VOID)CloseHandle( FileHandle); + return( FALSE); + } + (VOID)CloseHandle( FileHandle); + + if ( bytes_read == 2 && id_tbl[0] == 0x4d && id_tbl[1] == 0x5a) { + // + // Driver or executable file is in exe-format, set the bit in + // the type field. This info will be used on the client side. + // + pFlist->FileData.file_type |= IS_EXE_SYS; + } + + WordTable = pWorkerData->WordTable; + + if ( *WordTable[ PARAM_INDEX] == 0) { + pFlist->FileData.param_len = 0; + pFlist->param_list = (LPSTR)&RG_Null; + } else { + DbcsSize = RplUnicodeToDbcs( + pWorkerData->MemoryHandle, + WordTable[ PARAM_INDEX], + -1, // UNICODE string length not available + MAX_SIZE_DBCS_PARAMS, + &DbcsString + ); + if ( DbcsSize == 0) { + RplDump( ++RG_Assert, ("WordTable=0x%x, string=%ws", + WordTable, WordTable[ PARAM_INDEX])); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pFlist->path_name; + pWorkerData->EventId = NELOG_RplWkstaFileSize; + return( FALSE); + } + pFlist->FileData.param_len = (BYTE)(DbcsSize - 1); + pFlist->param_list = DbcsString; + } + + pFlist->FileData.extra_mem = StringToDword( WordTable[ MEM_INDEX]); + + if ( *WordTable[ MOVEABLE_INDEX] == MOVEABLE_SWITCH) { + pFlist->FileData.file_type |= IS_MOVEABLE; + } else if ( *WordTable[ MOVEABLE_INDEX] == EXEC_IN_LOW_MEM_SWITCH) { + pFlist->FileData.file_type |= EXEC_IN_LOW_MEM; + } + return( TRUE); +} + + +BOOL RplChecksum( + IN OUT PRPL_WORKER_DATA pWorkerData, + IN HANDLE FileHandle, + OUT PWORD pChecksum + ) +/*++ +Routine Description: + If successful returns sum of all words in a file. + +Arguments: + FileHandle - handle of file to checksum + pChecksum - pointer to calculated checksum + +Return Value: + TRUE if success, FALSE otherwise +--*/ +{ + DWORD Checksum; + DWORD BytesRead; + PDWORD pDword; + DWORD Length; + + if ( pWorkerData->ChecksumBuffer == NULL) { + pWorkerData->ChecksumBuffer = RplMemAlloc( pWorkerData->MemoryHandle, + CHK_SUM_BUF_SIZE); + if ( pWorkerData->ChecksumBuffer == NULL) { + return( FALSE); + } + } + + Checksum = 0; + + do { + // + // These are usually binary files so there are no DBCS/UNICODE + // issues. But even if we had a text file here, we should read + // it & checksum it raw (i.e. no conversion from DBCS to UNICODE) + // since it is the raw data that gets shipped to the client. + // + if ( !ReadFile( FileHandle, + pWorkerData->ChecksumBuffer, + CHK_SUM_BUF_SIZE, + &BytesRead, + NULL)) { + RplDump( ++RG_Assert, ( "Error = %d", GetLastError())); + return( FALSE); + } + + // + // Round up to make it divisible by 4 == sizeof( *pDword). + // Note that extra bytes are set zero in the 'boot' block, + // the files are always on the boundary of paragraph. + // + if ( BytesRead & 1) { // make it divisible by 2 + pWorkerData->ChecksumBuffer[ BytesRead++] = 0; + } + if ( BytesRead & 2) { // make it divisible by 4 + pWorkerData->ChecksumBuffer[ BytesRead++] = 0; + pWorkerData->ChecksumBuffer[ BytesRead++] = 0; + } + + // + // Checksum in chunks of 8, for speed. + // + for ( Length = BytesRead / 4, + pDword = (PDWORD)pWorkerData->ChecksumBuffer + Length; + Length > 8; Length -= 8) { + pDword -= 8; + Checksum += pDword[ 0]; + Checksum += pDword[ 1]; + Checksum += pDword[ 2]; + Checksum += pDword[ 3]; + Checksum += pDword[ 4]; + Checksum += pDword[ 5]; + Checksum += pDword[ 6]; + Checksum += pDword[ 7]; + } + // Then finish the checksum. + // + for ( ; Length > 0; Length--) { + Checksum += *(--pDword); + } + } while (BytesRead == CHK_SUM_BUF_SIZE); // exit read loop when all read + + *pChecksum = LOWORD( Checksum) + HIWORD( Checksum); + return( TRUE); +} + + +BOOL RplInitFileList( + IN PRPL_WORKER_DATA pWorkerData, + IN LPWSTR rel_path, + IN OUT PFLIST_TBL pFlist, + IN OUT PDWORD cur_para_ptr, + IN DWORD file_type + ) +/*++ + +Routine Description: + + Opens a file and initalizes the parameter item of the file list table. + It reads the file only if checksum is required and file is not of + RPL_BOOT_TYPE. + +Arguments: + + rel_path - relative path name of file + pFlist - pointer to current element in file list table + cur_para_ptr - current paragraph + file_type - file type + +Return Value: + TRUE if success, FALSE otherwise. + +--*/ +{ + HANDLE FileHandle; + LPSTR DbcsFileName; + DWORD DbcsFileNameSize; + DWORD Size; + BOOL Success; + + Success = FALSE; + FileHandle = INVALID_HANDLE_VALUE; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++InitFileList(0x%x)", pWorkerData)); + + // + // get the full path name and the actual file name + // + + Size = ( RG_DirectoryLength + wcslen( rel_path) + 1) * sizeof(WCHAR); + pFlist->path_name = RplMemAlloc( pWorkerData->MemoryHandle, Size); + if ( pFlist->path_name == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + goto cleanup; + } + wcscpy( pFlist->path_name, RG_Directory); + wcscat( pFlist->path_name, rel_path); + + // + // Open the BBC file and get its length. + // + + FileHandle = RplFileOpen( pFlist->path_name); + if ( FileHandle == INVALID_HANDLE_VALUE) { + RplDump( ++RG_Assert, ("path_name=%ws", pFlist->path_name)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pFlist->path_name; + pWorkerData->EventId = NELOG_RplWkstaFileOpen; + goto cleanup; + } + Size = GetFileSize( FileHandle, NULL); + if ( Size == INVALID_FILE_SIZE) { + RplDump( ++RG_Assert, ( "Error=%d, path_name=%ws", + GetLastError(), pFlist->path_name)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pFlist->path_name; + pWorkerData->EventId = NELOG_RplWkstaFileSize; + goto cleanup; + } + pFlist->FileData.file_len = Size; + + // + // Calculate checksum for the file, if cheksums are done. Note that + // RPLBOOT.SYS is never checksummed because it modifies its own code + // before the checking the checksum. + // + + if ( RG_ReadChecksum && file_type != RPL_BOOT_TYPE) { + if ( !RplChecksum( pWorkerData, FileHandle, &pFlist->FileData.chk_sum)) { + pFlist->FileData.chk_sum = NO_CHKSUM_USED; // for RPLBOOT to ingore checksum + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pFlist->path_name; + pWorkerData->EventId = NELOG_RplWkstaFileChecksum; + } + } else { + pFlist->FileData.chk_sum = NO_CHKSUM_USED; // RPLBOOT is never checksummed + } + + // + // Note that FileName is UNICODE, while client needs to receive a DBCS + // version of this name + // + pFlist->FileName = RplGetLastPathComponent( pFlist->path_name); + + DbcsFileNameSize = RplUnicodeToDbcs( + pWorkerData->MemoryHandle, + pFlist->FileName, // UNICODE string to convert + -1, // UNICODE string length not available + MAX_SIZEOF_DBCS_PATH, + &DbcsFileName + ); + if ( DbcsFileNameSize == 0) { + RplDump( ++RG_Assert, ("FileName=%ws", pFlist->FileName)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pFlist->path_name; + pWorkerData->EventId = NELOG_RplWkstaFileSize; + goto cleanup; + } + + pFlist->DbcsFileName = DbcsFileName; + pFlist->DbcsFileNameSize = DbcsFileNameSize; + + // + // Length of file in paragraphs, rounded up to the next paragraph. + // The maximum length could be checked, but let it be. + // Set the relative position of file from the start of file block + // + pFlist->FileData.file_len = (pFlist->FileData.file_len + 15) & 0xfffffff0L; + + pFlist->FileData.file_type = (WORD)file_type; + pFlist->FileData.param_len = 0; + pFlist->FileData.extra_mem = 0; + pFlist->FileData.param_offset = 0; + pFlist->FileData.name_offset = 0; + pFlist->param_list = NULL; + + // + // There may be several instances of the same file in the boot block. + // For example, Nokia NetStation memory extender LOADHI.SYS can load + // device drivers to memory between C000 - FFFF. PROTMAN.SYS, NDIS and + // NETBEUI may all be loaded to there. These boot block lines + // load the whole DOS NDIS stack to the memory above C000 + // DAT NETBEUI.DOS + // DRV LOADHI.SYS NETBEUI.DOS ~ + // DAT IBMTOK.DOS + // DRV LOADHI.SYS IBMTOK.DOS ~ + // DAT PROTMAN.DOS + // DRV LOADHI.SYS PROTMAN.DOS~I:\ ~ + // + // The code to send LOADHI.SYS once (instead of three times) in the boot + // block, is not worth of effort, since LOADHI.SYS is small (~4kB). + // + + pFlist->FileData.file_addr = *cur_para_ptr * 16; + *cur_para_ptr += (pFlist->FileData.file_len / 16); + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--InitFileList(0x%x)", pWorkerData)); + Success = TRUE; + +cleanup: + if ( FileHandle != INVALID_HANDLE_VALUE) { + (VOID)CloseHandle( FileHandle); + } + return( Success); +} + + +LPWSTR * RplBbcFileToTable( IN OUT PRPL_WORKER_DATA pWorkerData) +/*++ + +Routine Description: + Reads boot block file to a buffer. Skips comment lines and copies + non-comment lines to the string buffer. Returns pointer to the array + of pointers to lines, and the length of table. + +Arguments: + +Return Value: + Pointer to line table if successful, NULL otherwise. + +--*/ +{ +#define RPL_LINE_END L"\n\r" + DWORD index; + LPWSTR * Table; + PWCHAR UnicodeString; + PWCHAR pWchar; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++BbcFileToTable(0x%x)", pWorkerData)); + + UnicodeString = RplReadTextFile( pWorkerData->MemoryHandle, + pWorkerData->BbcFile, MAX_BBC_FILE_SIZE); + if ( UnicodeString == NULL) { + RplDump( ++RG_Assert, ( "BbcFile=%ws", pWorkerData->BbcFile)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventId = NELOG_RplWkstaFileRead; + return( NULL); + } + + Table = RplMemAlloc( pWorkerData->MemoryHandle, (MAX_FLIST_LEN+1)* sizeof( LPWSTR)); + if ( Table == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( NULL); + } + + for ( pWchar = wcstok( UnicodeString, RPL_LINE_END), index = 0; + pWchar != NULL && index < MAX_FLIST_LEN; + pWchar = wcstok( NULL, RPL_LINE_END)) { + + while( iswspace( *pWchar)) { // skip empty chars at the beginning + pWchar++; + } + if ( *pWchar == 0 || *pWchar == L';') { + continue; // don't save blank or comment lines + } + + Table[ index++] = pWchar; + } + + if ( pWchar != NULL) { + // + // Error case. Too many lines in the file. + // + RplDump( ++RG_Assert, ( "pWchar=0x%x", pWchar)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventId = NELOG_RplWkstaFileLineCount; + Table = NULL; + } else { + Table[ index] = NULL; // terminate the table + } + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--BbcFileToTable(0x%x)", pWorkerData)); + return( Table); + +} // RplBbcFileToTable() + + + +BOOL RplBbcLineToTable( + IN OUT PRPL_WORKER_DATA pWorkerData, + IN LPWSTR Line + ) +/*++ + +Routine Description: + + Copies a line into a buffer. Breaks the copy into "words" (substrings). + Makes an array of pointers to "words". The original line string is kept + unchanged because it is needed for error reporting in the caller. + +Arguments: + Line - ptr to line string + +Return Value: + TRUE if success, FALSE otherwise. + FALSE is returned if we ran out of memory, or if line has too many words. + +--*/ +{ + DWORD index; + DWORD BufferSize; + LPWSTR Cursor; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++BbcLineToTable(0x%x):%ws", pWorkerData, Line)); + + BufferSize = (wcslen( Line) + 1) * sizeof( WCHAR); + + if ( pWorkerData->LineBuffer == NULL) { + + pWorkerData->LineBuffer = RplMemAlloc( pWorkerData->MemoryHandle, BufferSize); + if ( pWorkerData->LineBuffer == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + pWorkerData->LineBufferSize = BufferSize; + + } else if ( BufferSize > pWorkerData->LineBufferSize) { + + RplMemFree( pWorkerData->MemoryHandle, pWorkerData->LineBuffer); + pWorkerData->LineBuffer = RplMemAlloc( pWorkerData->MemoryHandle, BufferSize); + if ( pWorkerData->LineBuffer == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + pWorkerData->LineBufferSize = BufferSize; + } + + if ( pWorkerData->WordTable == NULL) { + pWorkerData->WordTable = RplMemAlloc( + pWorkerData->MemoryHandle, + (MAX_CONFIG_FIELDS + 1) * sizeof(LPWSTR) + ); + if ( pWorkerData->WordTable == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + } + + memcpy( pWorkerData->LineBuffer, Line, BufferSize); + + for ( index = 0, Cursor = wcstok( pWorkerData->LineBuffer, SPACE_STRING); + index < MAX_CONFIG_FIELDS && Cursor != NULL; + index++, Cursor = wcstok( NULL, SPACE_STRING)) { + + if ( wcscmp( Cursor, TILDE_STRING) == 0) { + // + // Single tilda is just an empty placeholder. + // + pWorkerData->WordTable[ index] = (LPWSTR)&RG_Null; + + } else { + pWorkerData->WordTable[ index] = Cursor; + // + // In unlikely case there are tildas embedded with a filename + // (e.g. driver with its parameters), replace them tildas with spaces. + // + while ( (Cursor = wcsrchr( Cursor, TILDE_CHAR)) != NULL) { + *Cursor++ = SPACE_CHAR; + } + } + } + + if ( Cursor != NULL) { + // + // Boot block config line has too many items. + // + RplDump( ++RG_Assert, ( "Cursor=0x%x", Cursor)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventStrings[ 2] = Line; + pWorkerData->EventId = NELOG_Invalid_Config_Line; + return( FALSE); + } + + while ( index < MAX_CONFIG_FIELDS) { + pWorkerData->WordTable[ index++] = (LPWSTR)&RG_Null; // fill in the rest + } + pWorkerData->WordTable[ index] = NULL; // then null terminate + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--BbcLineToTable(0x%x):%ws", pWorkerData, Line)); + return( TRUE); +} + + +CONFIG_TYPE ConfigTypeTable[] = { + { L"RPL", RPL_BOOT_TYPE}, + { L"ORG", ORG_TYPE}, + { L"DAT", DATA_FILE}, + { L"LDR", BINARY_LOADER}, + { L"DRV", DRV_TYPE}, + { L"EXE", EXE_TYPE}, + { L"BASE", BASE_TYPE}, + { NULL, UNKNOWN_CONFIG_TYPE} +}; + +DWORD RplConfigLineType( IN LPWSTR ConfigLineId) +/*++ + +Routine Description: + + Returns the type of the current line in boot block config file. + +Arguments: + + Pointer to identifier for the current line. + +Return Value: + + Config line type. + +--*/ +{ + DWORD Type; + PCONFIG_TYPE pConfigType; + + for ( Type = UNKNOWN_CONFIG_TYPE, pConfigType = ConfigTypeTable; + pConfigType->id != 0; + pConfigType++) { + if ( !wcscmp( ConfigLineId, pConfigType->id )) { + Type = pConfigType->type; + break; + } + } + return( Type); +} + + +BOOL RplCheckBootHeader( + IN PRPL_WORKER_DATA pWorkerData, + IN LPWSTR FilePath, + OUT PDWORD pFirstOffset + ) +/*++ + +Routine Description: + Reads patch offsets from the start of DLCLOADR.COM file. + +Arguments: + FilePath - path name of DLCLOADR.COM + pFirstOffset - ptr to first NLS patch offset + +Return Value: + TRUE if successful, FALSE otherwise. + +--*/ +{ + HANDLE FileHandle; + DWORD read_len; + WORD offset_buf[ OFFSET_BUF_LEN]; + PRPLBOOT_HEADER pRplbootHdr; + BOOL Success; + + Success = FALSE; + + FileHandle = RplFileOpen( FilePath); + if ( FileHandle == INVALID_HANDLE_VALUE) { + RplDump( ++RG_Assert, ( "FilePath=%ws", FilePath)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = FilePath; + pWorkerData->EventId = NELOG_RplWkstaFileOpen; + goto cleanup; + } + + if ( !ReadFile( FileHandle, (PBYTE)offset_buf, + OFFSET_BUF_LEN * sizeof(WORD), &read_len, NULL)) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = FilePath; + pWorkerData->EventId = NELOG_RplWkstaFileRead; + goto cleanup; + } + + pRplbootHdr = (PRPLBOOT_HEADER)((PBYTE)offset_buf + OFFSET_RPLBOOT_HDR); + + if ( !strcmp( pRplbootHdr->achIdStamp, "RPL" ) && // BUGBUG hardcoded constants + pRplbootHdr->bBbVersion == BBVERSION_10 ) { + // + // check that rplboot.sys nls patch version match or + // it does not require NLS patching at all + // + if (pRplbootHdr->bNlsVersion == NLS_VERSION_10) { + // + // get the offset of NLS patches in RPLBOOT.SYS + // + *pFirstOffset = pRplbootHdr->usNlsPatchOff; + } else if (pRplbootHdr->bNlsVersion == 0) { + // + // No NLS patching, if version number is 0, that's OK. + // + *pFirstOffset = NO_PATCH_OFFSET; + } else { + // + // Configuration error: RPLBOOT.SYS expects to get a + // different NLS patching from one that RPLSERVR can provide, + // the versions are incompatible. + // + RplDump( ++RG_Assert, ( "FilePath=%ws", FilePath)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = FilePath; + pWorkerData->EventId = NELOG_RplWkstaWrongVersion; + goto cleanup; + } + } else { + // + // Configuration error: the header is missing, this is an old + // (or wrong) RPLBOOT.sys. + // + RplDump( ++RG_Assert, ( "FilePath=%ws", FilePath)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = FilePath; + pWorkerData->EventId = NELOG_RplWkstaWrongVersion; + goto cleanup; + } + Success = TRUE; + +cleanup: + if ( FileHandle != INVALID_HANDLE_VALUE) { + (VOID)CloseHandle( FileHandle); + } + return( Success); +} + + +BOOL RplBbcFile( IN OUT PRPL_WORKER_DATA pWorkerData) +/*++ + +Routine Description: + + Processes the boot block configuration file. Initializes file list table. + +Arguments: + +Return Value: + TRUE if success, FALSE otherwise + +--*/ +{ + LPWSTR * LineTable; // ptr to array of line-strings for BBC file + DWORD LoaderLineIndex; // index of a loader line in BBC file + LPWSTR * LoaderWordTable; // ptr to array of word-strings for loader line + LPWSTR LoaderBuffer; // buffer for LoaderWordTable + PRESOURCE_TBL resource_tbl; + DWORD resource_tbl_size; + DWORD resource_tbl_len; + LPWSTR String; + DWORD Index; + DWORD org_addr; + DWORD cur_para; // current length of boot block image in paragraphs + DWORD fblock_base; + DWORD bblock_base; // no default base address + PFLIST_TBL flist_tbl; // file list array + DWORD flist_tbl_len; // # of elements in flist_tbl[] + DWORD flist_tbl_size; // size in bytes of flist_tbl[] + DWORD FileIndex; // index entries in flist_tbl[] + BOOL org_is_set; + DWORD line_type; + DWORD PatchOffset; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++BbcFile(0x%x)", pWorkerData)); + + pWorkerData->loader_i = pWorkerData->rplboot_i = MAXWORD; + fblock_base = bblock_base = 0; + resource_tbl_size = resource_tbl_len = 0; + org_is_set = FALSE; + cur_para = 0; + + // + // Read boot block configuration file to a UNICODE string table, where + // each string from this table contains a single line from BBC file. + // This table is null terminated. + // + LineTable = RplBbcFileToTable( pWorkerData); + if ( LineTable == NULL) { + return( FALSE); + } + + flist_tbl = RplMemAlloc( pWorkerData->MemoryHandle, sizeof(FLIST_TBL) * MAX_FLIST_LEN); + if ( flist_tbl == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + + // + // Process lines in the boot block configuration file and + // insert data to file list + // + for ( Index = FileIndex = 0; (String = LineTable[ Index]) != NULL; Index++) { + // + // Break up single line from boot block config file into word table. + // + if ( !RplBbcLineToTable( pWorkerData, String)) { + return( FALSE); + } + + line_type = RplConfigLineType( pWorkerData->WordTable[ CONF_LINE_ID]); + + switch ( line_type) { + + case RPL_BOOT_TYPE: // There must be a single entry like this. + if ( pWorkerData->rplboot_i != MAXWORD) { + RplDump( ++RG_Assert, ( "BbcFile=%ws, String=%ws", pWorkerData->BbcFile, String)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventStrings[ 2] = String; + pWorkerData->EventId = NELOG_Invalid_Config_Line; + return( FALSE); + } + pWorkerData->rplboot_i = FileIndex; // fall through !! + + case BINARY_LOADER: // There must be a single entry like this. + if (line_type == BINARY_LOADER) { + if ( pWorkerData->loader_i != MAXWORD) { + RplDump( ++RG_Assert, ( "BbcFile=%ws, String=%ws, loader_i=0x%x", + pWorkerData->BbcFile, String, pWorkerData->loader_i)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventStrings[ 2] = String; + pWorkerData->EventId = NELOG_Invalid_Config_Line; + return( FALSE); + } + pWorkerData->loader_i = FileIndex; + } // fall through !! + + case EXE_TYPE: + case DRV_TYPE: + case DATA_FILE: + if ( !RplInitFileList( pWorkerData, + pWorkerData->WordTable[ CONF_LINE_FILE], + &flist_tbl[ FileIndex], &cur_para, line_type)) { + return( FALSE); + } + if ( line_type == DRV_TYPE || line_type == EXE_TYPE) { + if ( !RplInitExeOrSys( pWorkerData, &flist_tbl[ FileIndex])) { + return( FALSE ); + } + } + + // + // Update the minimum size of header. + // Reserve space for 0xa 0xd in the end of param list + // + if ( flist_tbl[ FileIndex].FileData.param_len) { + pWorkerData->min_wksta_buf += (flist_tbl[ FileIndex].FileData.param_len + 2); + } + pWorkerData->min_wksta_buf += flist_tbl[ FileIndex].DbcsFileNameSize; + FileIndex++; + break; + + case ORG_TYPE: + org_addr = StringToDword( pWorkerData->WordTable[ CONF_LINE_FILE]); + // + // file block base must be above 0C0 (paras) + // + fblock_base = org_addr - cur_para - bblock_base; + org_is_set = TRUE; + if ( cur_para + bblock_base > org_addr) { + RplDump( ++RG_Assert, ( "BbcFile=%ws, cur_para=0x%x," + " bblock_base=0x%x, org_addr=0x%x", + pWorkerData->BbcFile, cur_para, bblock_base, org_addr)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventId = NELOG_Files_Dont_Fit; + return( FALSE); + } + break; + + case BASE_TYPE: + bblock_base = StringToDword( pWorkerData->WordTable[ CONF_LINE_BASE_ADDRESS]); + if ( org_is_set || bblock_base < MIN_BBLOCK_BASE_SEG) { + // + // Origin has been set to a wrong address or + // boot block base address is too low. + // + RplDump( ++RG_Assert, ( "BbcFile=%ws, org_is_set=%d, bblock_base=0x%x", + pWorkerData->BbcFile, org_is_set, bblock_base)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventId = NELOG_Files_Dont_Fit; + return( FALSE); + } + break; + + default: + RplDump( ++RG_Assert, ( "BbcFile=%ws, String=%ws", pWorkerData->BbcFile, String)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventStrings[ 2] = String; + pWorkerData->EventId = NELOG_Invalid_Config_Line; + return( FALSE); + } // switch( line_type) + + if ( line_type == BINARY_LOADER) { + // + // We have to save loader line data for processing below. + // + LoaderWordTable = pWorkerData->WordTable; + LoaderBuffer = pWorkerData->LineBuffer; + pWorkerData->LineBuffer = NULL; + pWorkerData->WordTable = NULL; + LoaderLineIndex = Index; + } + } + + // + // Boot block configuration file must contain a boot line (RPLBOOT.SYS) + // and a loader line (RPLSTART.COM or OS2LDR). + // + + if ( pWorkerData->rplboot_i == MAXWORD || pWorkerData->loader_i == MAXWORD) { + RplDump( ++RG_Assert, ( "BbcFile=%ws, rplboot_i=0x%x, loader_i=0x%x\n", + pWorkerData->BbcFile, pWorkerData->rplboot_i, pWorkerData->loader_i)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventId = NELOG_RplWkstaBbcFile; + return( FALSE); + } + + // + // Do not bother to resize file list table - it will be freed shortly + // anyway, just save the relevant size of table for later use. + // + flist_tbl_len = FileIndex; + flist_tbl_size = flist_tbl_len * sizeof(FLIST_TBL); + + // + // Check the loader parameters. This code does real work for OS/2 only. + // For DOS it just fills the null table entry. + // + + // + // Count number of items in the resource table. + // + for ( resource_tbl_len = 0; + *LoaderWordTable[ FIRST_FILE_NAME + resource_tbl_len]; resource_tbl_len++) { + NOTHING; + } + resource_tbl_len++; // leave space for terminating null + resource_tbl_size = resource_tbl_len * sizeof( RESOURCE) + sizeof( WORD); + resource_tbl = RplMemAlloc( pWorkerData->MemoryHandle, resource_tbl_size); + if ( resource_tbl == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + if ( resource_tbl_len > MAXWORD) { + RplDump( ++RG_Assert, ( "resource_tbl_len=%d", resource_tbl_len)); + return( FALSE); + } + resource_tbl->entries = (WORD)resource_tbl_len; + + // + // get the file names in the reource table of OS2LDR + // + for ( Index = 0; *(String = LoaderWordTable[ FIRST_FILE_NAME + Index]) != 0; Index++) { + + String = RplGetLastPathComponent( String); // convert file path to file name + + // + // Verify that resource file is a part of a boot block. + // + for ( FileIndex = 0; + FileIndex < flist_tbl_len + && _wcsicmp( String, flist_tbl[ FileIndex].FileName); + FileIndex++) { + NOTHING; + } + if ( FileIndex == flist_tbl_len) { + // + // resource file is not a part of a boot block + // + RplDump( ++RG_Assert, ( "BbcFile=%ws, Line=%ws", + pWorkerData->BbcFile, LineTable[ LoaderLineIndex])); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventStrings[ 2] = LineTable[ LoaderLineIndex]; + pWorkerData->EventId = NELOG_Invalid_Config_Line; + return( FALSE); + } + // + // initialize the next item in resource table + // + resource_tbl->file_tbl[ Index].pos_in_paras = (WORD)( flist_tbl[ FileIndex].FileData.file_addr >> 4); + resource_tbl->file_tbl[ Index].file_len = flist_tbl[ FileIndex].FileData.file_len; + } + resource_tbl->file_tbl[ Index].pos_in_paras = 0; + resource_tbl->file_tbl[ Index].file_len = 0L; + + // + // Clean up. + // + RplMemFree( pWorkerData->MemoryHandle, LoaderWordTable); + RplMemFree( pWorkerData->MemoryHandle, LoaderBuffer); + + // + // Get the minimum size of workstation specific data + // + pWorkerData->min_wksta_buf += flist_tbl_size + resource_tbl_size; + + pWorkerData->file_block_base = fblock_base << 4; + pWorkerData->boot_block_base = bblock_base << 4; + pWorkerData->flist_tbl = flist_tbl; + pWorkerData->flist_tbl_len = flist_tbl_len; + pWorkerData->resource_tbl = resource_tbl; + pWorkerData->resource_tbl_size = resource_tbl_size; + + // + // Check header of RPLBOOT.SYS. + // + if( !RplCheckBootHeader( pWorkerData, flist_tbl->path_name, &PatchOffset)) { + return( FALSE); + } + + // + // RPLBOOT.SYS has a good header, see if it requires patching. + // + if ( PatchOffset == NO_PATCH_OFFSET) { + pWorkerData->MakePatch = FALSE; // RPLBOOT.SYS requires no patching. + } else { + pWorkerData->MakePatch = TRUE; + pWorkerData->PatchOffset = flist_tbl[ pWorkerData->rplboot_i].FileData.file_addr + PatchOffset; + flist_tbl[ pWorkerData->rplboot_i].FileData.chk_sum = NO_CHKSUM_USED; + } + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--BbcFile(0x%x)", pWorkerData)); + return( TRUE); + +} // RplBbcFile() + + + diff --git a/private/net/svcdlls/rpl/server/bbcfile.h b/private/net/svcdlls/rpl/server/bbcfile.h new file mode 100644 index 000000000..2c3486709 --- /dev/null +++ b/private/net/svcdlls/rpl/server/bbcfile.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + bbcfile.h + +Abstract: + + Exports from bbcfile.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +BOOL RplBbcFile( IN OUT PRPL_WORKER_DATA pWorkerData); + + + diff --git a/private/net/svcdlls/rpl/server/boot.c b/private/net/svcdlls/rpl/server/boot.c new file mode 100644 index 000000000..3c8bed16b --- /dev/null +++ b/private/net/svcdlls/rpl/server/boot.c @@ -0,0 +1,832 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + boot.c + +Abstract: + + This module contains RPL boot apis: - internal routines only. + +Author: + + Vladimir Z. Vulovic (vladimv) 10 - November - 1993 + +Revision History: + + 10-Nov-1993 vladimv + Created + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "db.h" +#include "dblib.h" +#include "config.h" +#include "profile.h" +#include "wksta.h" +#define RPLBOOT_ALLOCATE +#include "boot.h" +#undef RPLBOOT_ALLOCATE +#include "database.h" + + + +DWORD BootGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + IN OUT LPINT pSpaceLeft + ) +{ + BYTE LocalBuffer[ 300]; + PBYTE Buffer; + DWORD DataSize; + DWORD BufferSize; + JET_ERR JetError; + + switch( FieldIndex) { + case BOOT_WindowSize: + case BOOT_Flags: + case BOOT_VendorId: + Buffer = (PBYTE)pData; + BufferSize = sizeof( DWORD); + break; + default: + Buffer = LocalBuffer; + BufferSize = sizeof( LocalBuffer); + break; + } + JetError = JetRetrieveColumn( pSession->SesId, pSession->BootTableId, + BootTable[ FieldIndex].ColumnId, Buffer, + BufferSize, &DataSize, 0, NULL); + if ( JetError < 0) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + return( NERR_RplBootInfoCorrupted); + } + if ( Buffer != LocalBuffer) { + if ( BufferSize == DataSize) { + return( NO_ERROR); + } else { + RplDump( ++RG_Assert, ("Bad DataSize=0x%x", DataSize)); + return( NERR_RplBootInfoCorrupted); + } + } + // + // We have done with fixed data. From here on we deal with unicode + // strings only. + // + if ( DataSize > sizeof( LocalBuffer)) { + RplDump( ++RG_Assert, ( "Too big DataSize=0x%x", DataSize)); + return( NERR_RplBootInfoCorrupted); + } + if ( DataSize == 0) { + if ( JetError != JET_wrnColumnNull) { + RplDump( ++RG_Assert, ( "JetError=%d", JetError)); + return( NERR_RplBootInfoCorrupted); + } else { + *pData = NULL; // so RPC rpcrt4!_tree_size_ndr() does not bomb here + return( NO_ERROR); + } + } + if ( DataSize & 1 != 0 || wcslen((PWCHAR)LocalBuffer) + 1 != DataSize/2) { + RplDump( ++RG_Assert, ("LocalBuffer=0x%x, DataSize=0x%x", LocalBuffer, DataSize)); + return( NERR_RplBootInfoCorrupted); + } + *pData = MIDL_user_allocate( DataSize); + if ( *pData == NULL) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + RPL_RETURN( ERROR_NOT_ENOUGH_MEMORY); + } + memcpy( *pData, LocalBuffer, DataSize); + *pSpaceLeft -= DataSize; + return( NO_ERROR); +} + + +BOOL BootResumeFirst( + IN PRPL_SESSION pSession, + IN LPDWORD pResumeHandle, + OUT PBOOL pTableEnd + ) +/*++ + Set currency to the first boot record following the boot record + described by the resume handle. +--*/ +{ + BYTE ResumeValue[ RPL_MAX_VENDOR_NAME_SIZE + RPL_MAX_WKSTA_NAME_SIZE]; + PWCHAR BootName; + DWORD BootNameSize; + DWORD ResumeSize; + JET_ERR JetError; + + *pTableEnd = FALSE; + + CallB( JetSetCurrentIndex( pSession->SesId, pSession->BootTableId, BOOT_INDEX_VendorIdBootName)); + // + // The call to move to the beginning of the table is not redundant. + // E.g. JET_errNoCurrentRecord will be returned in case of empty table. + // + JetError = JetMove( pSession->SesId, pSession->BootTableId, JET_MoveFirst, 0); + if ( JetError < 0) { + if ( JetError == JET_errRecordNotFound + || JetError == JET_errNoCurrentRecord) { + *pTableEnd = TRUE; + return( TRUE); + } else { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + return( FALSE); + } + } + if ( !(ARGUMENT_PRESENT( pResumeHandle)) || *pResumeHandle == 0) { + return( TRUE); // not resuming, all done + } + ResumeSize = sizeof( ResumeValue); + if ( !ResumeKeyGet( pSession, *pResumeHandle, ResumeValue, &ResumeSize)) { + return( FALSE); + } + CallB( JetMakeKey( pSession->SesId, pSession->BootTableId, ResumeValue, sizeof( DWORD), JET_bitNewKey)); + BootName = (PWCHAR)( ResumeValue + sizeof(DWORD)); + BootNameSize = (DWORD)( ResumeSize - sizeof(DWORD)); + if ( BootNameSize != (wcslen( BootName) + 1) * sizeof( WCHAR)) { + RplDump( ++RG_Assert, ("ResumeValue=0x%x, ResumeSize=0x%x", ResumeValue, ResumeSize)); + return( FALSE); + } + CallB( JetMakeKey( pSession->SesId, pSession->BootTableId, BootName, BootNameSize, 0)); + CallB( JetSeek( pSession->SesId, pSession->BootTableId, JET_bitSeekGT)); + return( TRUE); +} + + +VOID BootResumeSave( + IN PRPL_SESSION pSession, + IN DWORD ServerHandle, + IN DWORD VendorId, + IN PWCHAR BootName, + IN PDWORD pResumeHandle + ) +/*++ + This all other other functions that save resume keys is void, because there + is no documented way of returning error cannot resume to the client. +--*/ +{ + BYTE ResumeBuffer[ 30 * sizeof(WCHAR)]; + DWORD BootSize; + + memcpy( ResumeBuffer, &VendorId, sizeof( VendorId)); + BootSize = ( wcslen( BootName) + 1) * sizeof(WCHAR); + memcpy( ResumeBuffer + sizeof(VendorId), BootName, BootSize); + (VOID)ResumeKeySet( pSession, (DWORD)ServerHandle, ResumeBuffer, BootSize+sizeof(VendorId), pResumeHandle); +} + + +DWORD BootFilterFind( + IN PRPL_SESSION pSession, + IN OUT PRPL_FILTER pFilter, + IN OUT PBOOL pTableEnd + ) +/*++ + Returns name of the the first/next BOOT structure supporting a given + VendorId. + The "first" BOOT does not have to be absolutely first, but first behind + the BOOT specified by RPL_FILTER. + In case such BOOT structure cannot be found, returns some kind of error. + +Arguments: + + pFilter - pointer to RPL_FILTER structure with the following fields + FindFirst : find first (TRUE) or find next (FALSE) + VendorId : vendor id to be suppored (input only) + BootName : buffer large enough to hold the longest + BootName string. When input value of + BootNameSize is non-zero, this contains the + previous value of BootName string. + output value is NOT valid if error or end of table + BootNameSize : at input this contains the size of the previous + BootName string. If this size is zero/non-zero, + it means we are looking for the first/next + BOOT structure. + at output this cotains the size of BootName string + output value is NOT valid if error or end of table + + pTableEnd - pointer to boolean (input value is FALSE) which will be set + to TRUE if we reach end of boot table +-**/ +{ + DWORD CheckVendorId; + DWORD DataSize; + JET_ERR JetError; + + if ( pFilter->FindFirst == FALSE) { + JetError = JetMove( pSession->SesId, pSession->BootTableId, JET_MoveNext, 0); + if ( JetError != JET_errSuccess) { + if ( JetError == JET_errNoCurrentRecord) { + RplDump( RG_DebugLevel & RPL_DEBUG_BOOT, ("JetError=%d", JetError)); + } else { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + } + goto cleanup; + } + } else { + pFilter->FindFirst = FALSE; + CallM( JetSetCurrentIndex( pSession->SesId, pSession->BootTableId, BOOT_INDEX_VendorIdBootName)); + CallM( JetMakeKey( pSession->SesId, pSession->BootTableId, &pFilter->VendorId, sizeof( pFilter->VendorId), JET_bitNewKey)); + if ( pFilter->BootNameSize != 0) { + // + // We are continuing the search from the previous BOOT structure. + // + CallM( JetMakeKey( pSession->SesId, pSession->BootTableId, pFilter->BootName, pFilter->BootNameSize, 0)); + } + // + // In case of seek errors assume we have reached end of table. + // + JetError = JetSeek( pSession->SesId, pSession->BootTableId, JET_bitSeekGT); + if ( JetError != JET_errSuccess) { + RplDump( RG_DebugLevel & RPL_DEBUG_BOOT, ("BootFilterFind: Seek(0x%x) => JetError=%d", + pFilter->VendorId, JetError)); + goto cleanup; + } + // + // Verify that element we seeked to has the proper vendor id. + // + CallM( JetMakeKey( pSession->SesId, pSession->BootTableId, &pFilter->VendorId, sizeof( pFilter->VendorId), JET_bitNewKey)); + JetError = JetSetIndexRange( pSession->SesId, pSession->BootTableId, + JET_bitRangeInclusive | JET_bitRangeUpperLimit); + if ( JetError != JET_errSuccess) { + RplDump( RG_DebugLevel & RPL_DEBUG_BOOT, ("BootFilterFind: SetIndexRange(0x%x) => JetError=%d", + pFilter->VendorId, JetError)); + goto cleanup; + } + } +#ifdef RPL_DEBUG + CallM( JetRetrieveColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_VendorId].ColumnId, &CheckVendorId, + sizeof( CheckVendorId), &DataSize, 0, NULL)); + if ( CheckVendorId != pFilter->VendorId) { + RplDump( ++RG_Assert, ( "CheckVendorId=0x%x")); + } +#endif // RPL_DEBUG + CallM( JetRetrieveColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_BootName].ColumnId, pFilter->BootName, + RPL_MAX_BOOT_NAME_SIZE, &pFilter->BootNameSize, 0, NULL)); +cleanup: + if ( JetError < 0) { + *pTableEnd = TRUE; // pretend it is end of table + } + return( NO_ERROR); +} + + +DWORD BootSetInfo( + IN PRPL_SESSION pSession, + IN DWORD Level, + IN LPVOID Buffer, + OUT LPDWORD pErrorParameter + ) +{ + LPRPL_BOOT_INFO_2 Info = Buffer; + switch( Level) { + case 2: + if ( Info->WindowSize != -1) { + *pErrorParameter = BOOT_WindowSize; + CallM( JetSetColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_WindowSize].ColumnId, + &Info->WindowSize, sizeof( Info->WindowSize), 0, NULL)); + } + if ( Info->BbcFile != NULL) { + *pErrorParameter = BOOT_BbcFile; + CallM( JetSetColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_BbcFile].ColumnId, + Info->BbcFile, + ( wcslen( Info->BbcFile) + 1) * sizeof(WCHAR), + 0, NULL)); + } + NOTHING; // fall through + case 1: + if ( Info->VendorName != NULL) { + DWORD VendorId; + *pErrorParameter = BOOT_VendorName; + CallM( JetSetColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_VendorName].ColumnId, + Info->VendorName, + ( wcslen( Info->VendorName) + 1) * sizeof(WCHAR), + 0, NULL)); + VendorId = wcstoul( Info->VendorName, NULL, 16); + CallM( JetSetColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_VendorId].ColumnId, + &VendorId, sizeof( VendorId), 0, NULL)); + } + if ( Info->Flags != 0) { + *pErrorParameter = BOOT_Flags; + CallM( JetSetColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_Flags].ColumnId, + &Info->Flags, sizeof( Info->Flags), 0, NULL)); + } + NOTHING; // fall through + case 0: + if ( Info->BootComment != NULL) { + *pErrorParameter = BOOT_BootComment; + CallM( JetSetColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_BootComment].ColumnId, + Info->BootComment, + ( wcslen( Info->BootComment) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->BootName != NULL) { + *pErrorParameter = BOOT_BootName; + CallM( JetSetColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_BootName].ColumnId, + Info->BootName, + ( wcslen( Info->BootName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + break; + } + return( NO_ERROR); +} + + +DWORD BootGetInfo( + IN PRPL_SESSION pSession, + OUT PDWORD pVendorId, + IN DWORD Level, + OUT LPVOID Buffer, + IN OUT PINT pSpaceLeft + ) +{ + DWORD Error; + DWORD WhoCares; + LPRPL_BOOT_INFO_2 Info = Buffer; + + switch( Level) { + case 2: + Error = BootGetField( pSession, BOOT_WindowSize, (LPVOID *)&Info->WindowSize, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = BootGetField( pSession, BOOT_BbcFile, &Info->BbcFile, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 1: + Error = BootGetField( pSession, BOOT_Flags, (LPVOID *)&Info->Flags, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = BootGetField( pSession, BOOT_VendorName, &Info->VendorName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 0: + Error = BootGetField( pSession, BOOT_BootComment, &Info->BootComment, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = BootGetField( pSession, BOOT_BootName, &Info->BootName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = BootGetField( pSession, BOOT_VendorId, (LPVOID *)pVendorId, &WhoCares); + if ( Error != NO_ERROR) { + return( Error); + } + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + return( NO_ERROR); +} + + + +VOID BootGetInfoCleanup( + IN DWORD Level, + IN OUT LPVOID Buffer + ) +{ + LPRPL_BOOT_INFO_2 Info = Buffer; + + switch( Level) { + case 2: + if ( Info->BbcFile != NULL) { + MIDL_user_free( Info->BbcFile); + } + NOTHING; // fall through + case 1: + if ( Info->VendorName != NULL) { + MIDL_user_free( Info->VendorName); + } + NOTHING; // fall through + case 0: + if ( Info->BootComment != NULL) { + MIDL_user_free( Info->BootComment); + } + if ( Info->BootName != NULL) { + MIDL_user_free( Info->BootName); + } + break; + } +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplBootAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD Level, + OUT LPRPL_BOOT_INFO_STRUCT BootInfoStruct, + OUT LPDWORD pErrorParameter OPTIONAL + ) +{ + LPRPL_BOOT_INFO_2 Info; + LPVOID Buffer; + DWORD Error; + DWORD ErrorParameter; + DWORD VendorId; + PRPL_SESSION pSession = &RG_ApiSession; + + ErrorParameter = INVALID_ERROR_PARAMETER; + Buffer = Info = BootInfoStruct->BootInfo2; + + switch( Level) { + case 2: + if ( Info->BbcFile == NULL || RPL_STRING_TOO_LONG( Info->BootComment)) { + ErrorParameter = BOOT_BbcFile; + break; + } + if ( !ValidHexName( Info->VendorName, RPL_VENDOR_NAME_LENGTH, TRUE)) { + ErrorParameter = BOOT_VendorName; + break; + } + _wcsupr( Info->VendorName); + VendorId = wcstoul( Info->VendorName, NULL, 16); + switch( Info->Flags) { + case BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_TRUE: + case BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_FALSE: + break; + default: + ErrorParameter = BOOT_Flags; + break; + } + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + break; + } + if ( RPL_STRING_TOO_LONG( Info->BootComment)) { + ErrorParameter = BOOT_BootComment; + break; + } + if ( !ValidName( Info->BootName, RPL_MAX_BOOT_NAME_LENGTH, TRUE)) { + ErrorParameter = BOOT_BootName; + break; + } + _wcsupr( Info->BootName); + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + return( ERROR_INVALID_PARAMETER); + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + // + // Verify that BootName + VendorId is available in the database. + // + if ( BootFind( pSession, Info->BootName, VendorId)) { + Error = NERR_RplBootNameUnavailable; + goto cleanup; + } + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->BootTableId, JET_prepInsert)); + + Error = BootSetInfo( pSession, Level, Buffer, &ErrorParameter); + if ( Error == ERROR_SUCCESS) { + ErrorParameter = 0; + CallJ( JetUpdate( pSession->SesId, pSession->BootTableId, NULL, 0, NULL)); + } + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( Error != ERROR_SUCCESS) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + } + return( Error); +} + + + +BOOL BootFind( + IN PRPL_SESSION pSession, + IN PWCHAR BootName, + IN DWORD VendorId + ) +{ + JET_ERR JetError; + CallB( JetSetCurrentIndex( pSession->SesId, pSession->BootTableId, BOOT_INDEX_VendorIdBootName)); + CallB( JetMakeKey( pSession->SesId, pSession->BootTableId, &VendorId, sizeof(VendorId), JET_bitNewKey)); + CallB( JetMakeKey( pSession->SesId, pSession->BootTableId, BootName, ( wcslen( BootName) + 1) * sizeof(WCHAR), 0)); + JetError = JetSeek( pSession->SesId, pSession->BootTableId, JET_bitSeekEQ); + if ( JetError < 0) { +#ifdef RPL_DEBUG + // + // JET_errNoCurrentRecord will be returned in case of empty table. + // + if ( JetError != JET_errRecordNotFound + && JetError != JET_errNoCurrentRecord) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + } +#endif + return( FALSE); + } + return( TRUE); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplBootDel( + IN RPL_HANDLE ServerHandle, + IN LPWSTR BootName, + IN LPWSTR VendorName + ) +/*++ + If VendorName is NULL we should delete all records with input BootName. + But for now we insist on valid input for VendorName. +--*/ +{ + DWORD Error; + DWORD VendorId; + PRPL_SESSION pSession = &RG_ApiSession; + + if ( !ValidName( BootName, RPL_MAX_BOOT_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + _wcsupr( BootName); + if ( !ValidHexName( VendorName, RPL_VENDOR_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + VendorId = wcstoul( VendorName, NULL, 16); + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( RplFindByField( pSession, CONFIG_TABLE_TAG, + CONFIG_INDEX_BootNameConfigName, BootName)) { + // + // We found a CONFIG record which uses this BOOT. + // + Error = NERR_RplBootInUse; + goto cleanup; + } + if ( RplFindByField( pSession, PROFILE_TABLE_TAG, + PROFILE_INDEX_BootNameProfileName, BootName)) { + // + // We found a PROFILE record which uses this BOOT. + // + Error = NERR_RplBootInUse; + goto cleanup; + } + if ( RplFindByField( pSession, WKSTA_TABLE_TAG, + WKSTA_INDEX_BootNameWkstaName, BootName)) { + // + // We found a WKSTA record which uses this BOOT. + // + Error = NERR_RplBootInUse; + goto cleanup; + } + if ( !BootFind( pSession, BootName, VendorId)) { + Error = NERR_RplBootNotFound; + goto cleanup; + } + CallJ( JetDelete( pSession->SesId, pSession->BootTableId)); + Error = NO_ERROR; + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplBootEnum( + IN RPL_RPC_HANDLE ServerHandle, + IN OUT LPRPL_BOOT_ENUM BootEnum, + IN DWORD PrefMaxLength, + OUT LPDWORD TotalEntries, + IN OUT LPDWORD pResumeHandle OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + + pServerHandle - ptr to RPL_HANDLE + + InfoStruct - Pointer to a structure that contains the information that + RPC needs about the returned data. This structure contains the + following information: + Level - The desired information level - indicates how to + interpret the structure of the returned buffer. + EntriesRead - Indicates how many elements are returned in the + array of structures that are returned. + BufferPointer - Location for the pointer to the array of + structures that are being returned. + + PrefMaxLen - Indicates a maximum size limit that the caller will allow + for (the return buffer. + + TotalEntries - Pointer to a value that upon return indicates the total + number of entries in the "active" database. + + pResumeHandle - Inidcates where to restart the enumeration. This is an + optional parameter and can be NULL. + +Return Value: + NO_ERROR if success. + +--*/ +{ + LPBYTE Buffer; + DWORD TypicalSize; + DWORD CoreSize; + DWORD Error; + INT SpaceLeft; + DWORD ArrayLength; + DWORD EntriesRead; + JET_ERR JetError; + BOOL InfoError; + BOOL TableEnd; + DWORD VendorId; + PRPL_SESSION pSession = &RG_ApiSession; + + switch( BootEnum->Level) { + case 2: + TypicalSize = CoreSize = sizeof( RPL_BOOT_INFO_2); + TypicalSize += 40 * sizeof( WCHAR); // typical size of BbcFile + NOTHING; // fall through + case 1: + if ( BootEnum->Level == 1) { + TypicalSize = CoreSize = sizeof( RPL_BOOT_INFO_1); + } + TypicalSize += 8 * sizeof( WCHAR); // typical size of VendorName + NOTHING; // fall through + case 0: + if ( BootEnum->Level == 0) { + TypicalSize = CoreSize = sizeof( RPL_BOOT_INFO_0); + } + TypicalSize += 20 * sizeof( WCHAR); // typical size of BootComment + TypicalSize += 8 * sizeof( WCHAR); // typical size of BootName + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( PrefMaxLength == -1) { + // + // If the caller has not specified a size, calculate a size + // that will hold the entire enumeration. + // + SpaceLeft = DEFAULT_BUFFER_SIZE; + } else { + SpaceLeft = PrefMaxLength; + } + + // + // Buffer space is shared by the array and by strings pointed at + // by the elements in this array. We need to decide up front how much + // space is allocated for array and how much for the strings. + // + ArrayLength = SpaceLeft / TypicalSize; + if ( ArrayLength == 0) { + ArrayLength = 1; // try to return at least one element + } + + // + // Note that MIDL_user_allocate() returns memory which is NOT initialized + // to zero. Since we do NOT use allocate all nodes, this means that all + // fields, especially pointers, in array elements must be properly set. + // + Buffer = MIDL_user_allocate( ArrayLength * CoreSize); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_BOOT, ( + "BootEnum: Buffer=0x%x, ArrayLength=0x%x", Buffer, ArrayLength)); + + BootEnum->BootInfo.Level0->Buffer = (LPRPL_BOOT_INFO_0)Buffer; + + EntriesRead = 0; + InfoError = FALSE; + Error = NO_ERROR; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !BootResumeFirst( pSession, pResumeHandle, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + for ( ; ; ) { + memset( Buffer, 0, CoreSize); // for cleanup to work properly + Error = BootGetInfo( pSession, &VendorId, BootEnum->Level, Buffer, &SpaceLeft); + if ( Error != NO_ERROR) { + InfoError = TRUE; // clean things up without holding crit sec + break; + } + EntriesRead++; + Buffer += CoreSize; + SpaceLeft -= CoreSize; + JetError = JetMove( pSession->SesId, pSession->BootTableId, JET_MoveNext, 0); + if ( JetError != JET_errSuccess) { + break; // assume end of table + } + if ( SpaceLeft <= 0) { + Error = ERROR_MORE_DATA; + break; + } + if ( EntriesRead >= ArrayLength) { + // + // We have space available but allocated array is not big enough. + // This should NOT happen often as our intent (see above) is to + // overestimate array length. When it happens we can still try + // to reallocate array to a larger size here. This is not done + // for now (too cumbersome) & we just stop the enumeration. + // + Error = ERROR_MORE_DATA; + break; + } + } +cleanup: + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + if ( InfoError == TRUE) { + BootGetInfoCleanup( BootEnum->Level, Buffer); + } + if ( Error == NO_ERROR) { + *TotalEntries = EntriesRead; + } else if ( Error == ERROR_MORE_DATA) { + *TotalEntries = EntriesRead * 2; // we cheat here + } else { + // + // Cleanup in case of "bad" errors. + // + while ( EntriesRead > 0) { + EntriesRead--; + Buffer -= CoreSize; + BootGetInfoCleanup( BootEnum->Level, Buffer); + } + MIDL_user_free( Buffer); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_BOOT, ("BootEnum: EntriesRead = 0x%x", EntriesRead)); + + BootEnum->BootInfo.Level0->EntriesRead = EntriesRead; + if ( EntriesRead == 0) { + BootEnum->BootInfo.Level0->Buffer = NULL; + } + + if ( ARGUMENT_PRESENT( pResumeHandle)) { + if ( Error == ERROR_MORE_DATA && EntriesRead > 0) { + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + BootResumeSave( pSession, (DWORD)ServerHandle, VendorId, + ((LPRPL_BOOT_INFO_0)(Buffer-CoreSize))->BootName, + pResumeHandle); + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + LeaveCriticalSection( &RG_ProtectDatabase); + } else { + *pResumeHandle = 0; // resume from beginning + } + } + return( Error); +} + diff --git a/private/net/svcdlls/rpl/server/config.c b/private/net/svcdlls/rpl/server/config.c new file mode 100644 index 000000000..698cb962e --- /dev/null +++ b/private/net/svcdlls/rpl/server/config.c @@ -0,0 +1,711 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + config.c + +Abstract: + + This module contains RPL config apis: ConfigEnum. + +Author: + + Vladimir Z. Vulovic (vladimv) 05 - November - 1993 + +Revision History: + + 05-Nov-1993 vladimv + Created + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "db.h" +#include "dblib.h" +#include "boot.h" +#include "profile.h" +#define RPLCONFIG_ALLOCATE +#include "config.h" +#undef RPLCONFIG_ALLOCATE +#include "setup.h" // IsConfigEnabled() + + + +DWORD ConfigSetInfo( + IN PRPL_SESSION pSession, + IN DWORD Level, + IN LPVOID Buffer, + OUT LPDWORD pErrorParameter + ) +{ + LPRPL_CONFIG_INFO_2 Info = Buffer; + switch( Level) { + case 2: + if ( Info->FitPersonal != NULL) { + *pErrorParameter = CONFIG_FitPersonal; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_FitPersonal].ColumnId, + Info->FitPersonal, + ( wcslen( Info->FitPersonal) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->FitShared != NULL) { + *pErrorParameter = CONFIG_FitShared; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_FitShared].ColumnId, + Info->FitShared, + ( wcslen( Info->FitShared) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->DirName4 != NULL) { + *pErrorParameter = CONFIG_DirName4; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_DirName4].ColumnId, + Info->DirName4, + ( wcslen( Info->DirName4) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->DirName3 != NULL) { + *pErrorParameter = CONFIG_DirName3; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_DirName3].ColumnId, + Info->DirName3, + ( wcslen( Info->DirName3) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->DirName2 != NULL) { + *pErrorParameter = CONFIG_DirName2; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_DirName2].ColumnId, + Info->DirName2, + ( wcslen( Info->DirName2) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->DirName != NULL) { + *pErrorParameter = CONFIG_DirName; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_DirName].ColumnId, + Info->DirName, + ( wcslen( Info->DirName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->BootName != NULL) { + *pErrorParameter = CONFIG_BootName; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_BootName].ColumnId, + Info->BootName, + ( wcslen( Info->BootName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + NOTHING; // fall through + case 1: + if ( Info->Flags != 0) { + *pErrorParameter = CONFIG_Flags; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_Flags].ColumnId, + &Info->Flags, sizeof( Info->Flags), 0, NULL)); + } + NOTHING; // fall through + case 0: + if ( Info->ConfigComment != NULL) { + *pErrorParameter = CONFIG_ConfigComment; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_ConfigComment].ColumnId, + Info->ConfigComment, + ( wcslen( Info->ConfigComment) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->ConfigName != NULL) { + *pErrorParameter = CONFIG_ConfigName; + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_ConfigName].ColumnId, + Info->ConfigName, + ( wcslen( Info->ConfigName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + break; + } + return( NO_ERROR); +} + + +DWORD ConfigGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + IN OUT LPINT pSpaceLeft + ) +{ + BYTE LocalBuffer[ 300]; + PBYTE Buffer; + DWORD DataSize; + DWORD BufferSize; + JET_ERR JetError; + + switch( FieldIndex) { + case CONFIG_Flags: + Buffer = (PBYTE)pData; + BufferSize = sizeof( DWORD); + break; + default: + Buffer = LocalBuffer; + BufferSize = sizeof( LocalBuffer); + break; + } + JetError = JetRetrieveColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ FieldIndex].ColumnId, Buffer, + BufferSize, &DataSize, 0, NULL); + if ( JetError < 0) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + return( NERR_RplConfigInfoCorrupted); + } + if ( Buffer != LocalBuffer) { + if ( BufferSize == DataSize) { + return( NO_ERROR); + } else { + RplDump( ++RG_Assert, ("Bad DataSize=0x%x", DataSize)); + return( NERR_RplConfigInfoCorrupted); + } + } + // + // We have done with fixed data. From here on we deal with unicode + // strings only. + // + if ( DataSize > sizeof( LocalBuffer)) { + RplDump( ++RG_Assert, ( "Too big DataSize=0x%x", DataSize)); + return( NERR_RplConfigInfoCorrupted); + } + if ( DataSize == 0) { + if ( JetError != JET_wrnColumnNull) { + RplDump( ++RG_Assert, ( "JetError=%d", JetError)); + return( NERR_RplConfigInfoCorrupted); + } else { + *pData = NULL; // so RPC rpcrt4!_tree_size_ndr() does not bomb here + return( NO_ERROR); + } + } + if ( DataSize & 1 != 0 || wcslen((PWCHAR)LocalBuffer) + 1 != DataSize/2) { + RplDump( ++RG_Assert, ("LocalBuffer=0x%x, DataSize=0x%x", LocalBuffer, DataSize)); + return( NERR_RplConfigInfoCorrupted); + } + *pData = MIDL_user_allocate( DataSize); + if ( *pData == NULL) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + RPL_RETURN( ERROR_NOT_ENOUGH_MEMORY); + } + memcpy( *pData, LocalBuffer, DataSize); + *pSpaceLeft -= DataSize; // BUGBUG might become negative? + return( NO_ERROR); +} + + +DWORD ConfigGetInfo( + IN PRPL_SESSION pSession, + IN LPWSTR ConfigName, + IN DWORD Level, + OUT LPVOID Buffer, + IN OUT LPINT pSpaceLeft + ) +{ + DWORD Error; + LPRPL_CONFIG_INFO_2 Info = Buffer; + + switch( Level) { + case 2: + Error = ConfigGetField( pSession, CONFIG_FitPersonal, &Info->FitPersonal, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ConfigGetField( pSession, CONFIG_FitShared, &Info->FitShared, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ConfigGetField( pSession, CONFIG_DirName4, &Info->DirName4, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ConfigGetField( pSession, CONFIG_DirName3, &Info->DirName3, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ConfigGetField( pSession, CONFIG_DirName2, &Info->DirName2, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ConfigGetField( pSession, CONFIG_DirName, &Info->DirName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ConfigGetField( pSession, CONFIG_BootName, &Info->BootName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 1: + Error = ConfigGetField( pSession, CONFIG_Flags, (LPVOID *)&Info->Flags, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + case 0: + Error = ConfigGetField( pSession, CONFIG_ConfigComment, &Info->ConfigComment, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + if ( ConfigName == NULL) { + Error = ConfigGetField( pSession, CONFIG_ConfigName, &Info->ConfigName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + } else { + DWORD DataSize = (wcslen( ConfigName) + 1) * sizeof(WCHAR); + Info->ConfigName = MIDL_user_allocate( DataSize); + if ( Info->ConfigName == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_CONFIG, ( "ConfigName=0x%x", Info->ConfigName)); + memcpy( Info->ConfigName, ConfigName, DataSize); + *pSpaceLeft -= DataSize; + } + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + return( NO_ERROR); +} + + + +VOID ConfigGetInfoCleanup( + IN DWORD Level, + IN OUT LPVOID Buffer + ) +{ + LPRPL_CONFIG_INFO_2 Info = Buffer; + + switch( Level) { + case 2: + if ( Info->FitPersonal != NULL) { + MIDL_user_free( Info->FitPersonal); + } + if ( Info->FitShared != NULL) { + MIDL_user_free( Info->FitShared); + } + if ( Info->DirName4 != NULL) { + MIDL_user_free( Info->DirName4); + } + if ( Info->DirName3 != NULL) { + MIDL_user_free( Info->DirName3); + } + if ( Info->DirName2 != NULL) { + MIDL_user_free( Info->DirName2); + } + if ( Info->DirName != NULL) { + MIDL_user_free( Info->DirName); + } + if ( Info->BootName != NULL) { + MIDL_user_free( Info->BootName); + } + NOTHING; // fall through + case 1: + NOTHING; // fall through + case 0: + if ( Info->ConfigComment != NULL) { + MIDL_user_free( Info->ConfigComment); + } + if ( Info->ConfigName != NULL) { + MIDL_user_free( Info->ConfigName); + } + break; + } +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplConfigAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD Level, + OUT LPRPL_CONFIG_INFO_STRUCT ConfigInfoStruct, + OUT LPDWORD pErrorParameter OPTIONAL + ) +{ + LPRPL_CONFIG_INFO_2 Info; + LPVOID Buffer; + DWORD Error; + DWORD ErrorParameter; + PRPL_SESSION pSession = &RG_ApiSession; + + ErrorParameter = INVALID_ERROR_PARAMETER; + Buffer = Info = ConfigInfoStruct->ConfigInfo2; + + switch( Level) { + case 2: + if ( !ValidName( Info->FitPersonal, RPL_MAX_STRING_LENGTH, TRUE)) { + ErrorParameter = CONFIG_FitPersonal; + break; + } + if ( !ValidName( Info->FitShared, RPL_MAX_STRING_LENGTH, TRUE)) { + ErrorParameter = CONFIG_FitShared; + break; + } + if ( !ValidName( Info->DirName4, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = CONFIG_DirName4; + break; + } + if ( !ValidName( Info->DirName3, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = CONFIG_DirName3; + break; + } + if ( !ValidName( Info->DirName2, RPL_MAX_STRING_LENGTH, TRUE)) { + ErrorParameter = CONFIG_DirName2; + break; + } + if ( !ValidName( Info->DirName, RPL_MAX_STRING_LENGTH, TRUE)) { + ErrorParameter = CONFIG_DirName; + break; + } + if ( !ValidName( Info->BootName, RPL_MAX_BOOT_NAME_LENGTH, TRUE)) { + ErrorParameter = CONFIG_BootName; + break; + } + _wcsupr( Info->BootName); + if ( Info->Flags & ~CONFIG_FLAGS_MASK_ENABLED) { + ErrorParameter = CONFIG_Flags; + break; + } + switch ( Info->Flags) { + case 0: + Info->Flags = RplConfigEnabled( Info->DirName2) == TRUE ? + CONFIG_FLAGS_ENABLED_TRUE : CONFIG_FLAGS_ENABLED_FALSE; + break; + case CONFIG_FLAGS_ENABLED_TRUE: + case CONFIG_FLAGS_ENABLED_FALSE: + break; + default: + ErrorParameter = CONFIG_Flags; + break; + } + if ( RPL_STRING_TOO_LONG( Info->ConfigComment)) { + ErrorParameter = CONFIG_ConfigComment; + break; + } + if ( !ValidName( Info->ConfigName, RPL_MAX_CONFIG_NAME_LENGTH, TRUE)) { + ErrorParameter = CONFIG_ConfigName; + break; + } + _wcsupr( Info->ConfigName); + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + return( ERROR_INVALID_PARAMETER); + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + // + // Verify that ConfigName is available in the database. + // + if ( RplFind( pSession, CONFIG_TABLE_TAG, Info->ConfigName)) { + Error = NERR_RplConfigNameUnavailable; + goto cleanup; + } + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->ConfigTableId, JET_prepInsert)); + + Error = ConfigSetInfo( pSession, Level, Buffer, &ErrorParameter); + if ( Error == ERROR_SUCCESS) { + ErrorParameter = 0; + CallJ( JetUpdate( pSession->SesId, pSession->ConfigTableId, NULL, 0, NULL)); + } + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( Error != ERROR_SUCCESS) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + } + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplConfigDel( + IN RPL_HANDLE ServerHandle, + IN LPWSTR ConfigName + ) +/*++ +--*/ +{ + DWORD Error; + PRPL_SESSION pSession = &RG_ApiSession; + + _wcsupr( ConfigName); + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( RplFindByField( pSession, PROFILE_TABLE_TAG, + PROFILE_INDEX_ConfigNameProfileName, ConfigName)) { + // + // We found a PROFILE record which uses this CONFIG. + // + Error = NERR_RplConfigNotEmpty; + goto cleanup; + } + if ( !RplFind( pSession, CONFIG_TABLE_TAG, ConfigName)) { + Error = NERR_RplConfigNotFound; + goto cleanup; + } + CallJ( JetDelete( pSession->SesId, pSession->ConfigTableId)); + Error = NO_ERROR; + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplConfigEnum( + IN RPL_RPC_HANDLE ServerHandle, + IN PWCHAR AdapterName, + IN OUT LPRPL_CONFIG_ENUM ConfigEnum, + IN DWORD PrefMaxLength, + OUT LPDWORD TotalEntries, + IN OUT LPDWORD pResumeHandle OPTIONAL + ) +/*++ + +Routine Description: + + If AdapterName is null, enumerate all configurations. + If AdapterName is not null, enumerate all configurations that can support + this adapter id. + +Arguments: + + pServerHandle - ptr to RPL_HANDLE + + InfoStruct - Pointer to a structure that contains the information that + RPC needs about the returned data. This structure contains the + following information: + Level - The desired information level - indicates how to + interpret the structure of the returned buffer. + EntriesRead - Indicates how many elements are returned in the + array of structures that are returned. + BufferPointer - Location for the pointer to the array of + structures that are being returned. + + PrefMaxLen - Indicates a maximum size limit that the caller will allow + for (the return buffer. + + TotalEntries - Pointer to a value that upon return indicates the total + number of entries in the "active" database. + + pResumeHandle - Inidcates where to restart the enumeration. This is an + optional parameter and can be NULL. + +Return Value: + NO_ERROR if success. + +--*/ +{ + LPBYTE Buffer; + DWORD TypicalSize; + DWORD CoreSize; + DWORD Error; + INT SpaceLeft; + DWORD ArrayLength; + DWORD EntriesRead; + BOOL InfoError; + BOOL TableEnd; + RPL_FILTER Filter; + PRPL_FILTER pFilter; + PRPL_SESSION pSession = &RG_ApiSession; + + switch( ConfigEnum->Level) { + case 2: + TypicalSize = CoreSize = sizeof( RPL_CONFIG_INFO_2); + TypicalSize += 20 * sizeof( WCHAR); // typical size of FitPersonal + TypicalSize += 20 * sizeof( WCHAR); // typical size of FitShared + TypicalSize += 12 * sizeof( WCHAR); // typical size of DirName4 + TypicalSize += 12 * sizeof( WCHAR); // typical size of DirName3 + TypicalSize += 12 * sizeof( WCHAR); // typical size of DirName2 + TypicalSize += 12 * sizeof( WCHAR); // typical size of DirName + TypicalSize += 8 * sizeof( WCHAR); // typical size of BootName + NOTHING; // fall through + case 1: + if ( ConfigEnum->Level == 1) { + TypicalSize = CoreSize = sizeof( RPL_CONFIG_INFO_1); + } + NOTHING; // fall through + case 0: + if ( ConfigEnum->Level == 0) { + TypicalSize = CoreSize = sizeof( RPL_CONFIG_INFO_0); + } + TypicalSize += 20 * sizeof( WCHAR); // typical size of ConfigComment + TypicalSize += 8 * sizeof( WCHAR); // typical size of ConfigName + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( AdapterName != NULL) { + pFilter = &Filter; + if ( !ValidHexName( AdapterName, RPL_ADAPTER_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + pFilter->VendorId = AdapterNameToVendorId( AdapterName); + pFilter->FindFirst = TRUE; + } else { + pFilter = NULL; + } + + if ( PrefMaxLength == -1) { + // + // If the caller has not specified a size, calculate a size + // that will hold the entire enumeration. + // + SpaceLeft = DEFAULT_BUFFER_SIZE; + } else { + SpaceLeft = PrefMaxLength; + } + + // + // Buffer space is shared by the array and by strings pointed at + // by the elements in this array. We need to decide up front how much + // space is allocated for array and how much for the strings. + // + ArrayLength = SpaceLeft / TypicalSize; + if ( ArrayLength == 0) { + ArrayLength = 1; // try to return at least one element + } + + // + // Note that MIDL_user_allocate() returns memory which is NOT initialized + // to zero. Since we do NOT use allocate all nodes, this means that all + // fields, especially pointers, in array elements must be properly set. + // + Buffer = MIDL_user_allocate( ArrayLength * CoreSize); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_CONFIG, ( + "ConfigEnum: Buffer=0x%x, ArrayLength=0x%x", Buffer, ArrayLength)); + ConfigEnum->ConfigInfo.Level0->Buffer = (LPRPL_CONFIG_INFO_0)Buffer; + + EntriesRead = 0; + InfoError = FALSE; + Error = NO_ERROR; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFilterFirst( pSession, CONFIG_TABLE_TAG, pFilter, pResumeHandle, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + for ( ; ; ) { + memset( Buffer, 0, CoreSize); // for cleanup to work properly + Error = ConfigGetInfo( pSession, NULL, ConfigEnum->Level, Buffer, &SpaceLeft); + if ( Error != NO_ERROR) { + InfoError = TRUE; // clean things up without holding crit sec + break; + } + EntriesRead++; + Buffer += CoreSize; + SpaceLeft -= CoreSize; + if ( !RplFilterNext( pSession, pSession->ConfigTableId, pFilter, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + if ( SpaceLeft <= 0) { + Error = ERROR_MORE_DATA; + break; + } + if ( EntriesRead >= ArrayLength) { + // + // We have space available but allocated array is not big enough. + // This should NOT happen often as our intent (see above) is to + // overestimate array length. When it happens we can still try + // to reallocate array to a larger size here. This is not done + // for now (too cumbersome) & we just stop the enumeration. + // + Error = ERROR_MORE_DATA; + break; + } + } +cleanup: + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + if ( InfoError == TRUE) { + ConfigGetInfoCleanup( ConfigEnum->Level, Buffer); + } + if ( Error == NO_ERROR) { + *TotalEntries = EntriesRead; + } else if ( Error == ERROR_MORE_DATA) { + *TotalEntries = EntriesRead * 2; // we cheat here + } else { + // + // Cleanup in case of "bad" errors. + // + while ( EntriesRead > 0) { + EntriesRead--; + Buffer -= CoreSize; + ConfigGetInfoCleanup( ConfigEnum->Level, Buffer); + } + MIDL_user_free( Buffer); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_CONFIG, ("ConfigEnum: EntriesRead = 0x%x", EntriesRead)); + + ConfigEnum->ConfigInfo.Level0->EntriesRead = EntriesRead; + if ( EntriesRead == 0) { + ConfigEnum->ConfigInfo.Level0->Buffer = NULL; + } + + if ( ARGUMENT_PRESENT( pResumeHandle)) { + if ( Error == ERROR_MORE_DATA && EntriesRead > 0) { + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + RplFilterSave( pSession, (DWORD)ServerHandle, pFilter, + ((LPRPL_CONFIG_INFO_0)(Buffer-CoreSize))->ConfigName, + pResumeHandle); + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + LeaveCriticalSection( &RG_ProtectDatabase); + } else { + *pResumeHandle = 0; // resume from beginning + } + } + return( Error); +} diff --git a/private/net/svcdlls/rpl/server/database.c b/private/net/svcdlls/rpl/server/database.c new file mode 100644 index 000000000..aa96fc767 --- /dev/null +++ b/private/net/svcdlls/rpl/server/database.c @@ -0,0 +1,998 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + database.c + +Abstract: + + Routines for non-api _access to the database. This includes initialization + and shutdown code on the database. + + Exports: + +BOOL RplDbInit( VOID) +VOID RplDbTerm( VOID) +BOOL RplDbFindWksta( +BOOL RplDbFillWksta( +BOOL RplDbHaveWksta( + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "database.h" +#include "db.h" +#include "dblib.h" +#include "adapter.h" +#include "boot.h" +#include "config.h" +#include "profile.h" +#include "resume.h" +#include "vendor.h" +#include "wksta.h" +#include "report.h" // for RplReportEventEx +#include "winsock.h" // for INADDR_NONE + +DWORD RplStartJet500Conversion(); + +#define RPL_BACKUP_SUBDIR L"BACKUP" + +// +// File names must be complete, i.e. extensions are not optional. (This is unlike +// the OS/2 behavior where we would append ".FIT" if extension is absent). +// + + + +BOOL RplDbInitColumnInfo( + IN PCHAR TableName, + IN OUT PRPL_COLUMN_INFO ColumnInfoTable, + IN DWORD ColumnInfoTableLength, + IN JET_TABLEID TableId, + IN JET_SESID SesId + ) +{ + JET_COLUMNDEF ColumnDef; + DWORD index; + + for ( index = 0; index < ColumnInfoTableLength; index++) { + CallB( JetGetTableColumnInfo( SesId, TableId, + ColumnInfoTable[ index].ColumnName, &ColumnDef, + sizeof( ColumnDef), JET_ColInfo)); + RPL_ASSERT( ColumnInfoTable[ index].ColumnType == ColumnDef.coltyp); + ColumnInfoTable[ index].ColumnId = ColumnDef.columnid; + } + return( TRUE); +} + + +// +// Code templated from WINS:WinMscDelFiles(). JonN 8/7/94 +// +VOID RplDeleteLogFiles() +{ + WCHAR Path[ MAX_PATH]; // must hold terminating NULL char too + WIN32_FIND_DATA FileInfo; + HANDLE SearchHandle = INVALID_HANDLE_VALUE; + DWORD ErrCode = NO_ERROR; + + memcpy( Path, RG_Directory, RG_DirectoryLength * sizeof(WCHAR)); + memcpy( Path+RG_DirectoryLength, L"jet*.log", 9*sizeof(WCHAR)); + + SearchHandle = FindFirstFile(Path, &FileInfo); + if (SearchHandle == INVALID_HANDLE_VALUE) + { + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( + "RplDeleteLogFiles: FindFirstFile( %ws) returned %d", + Path, GetLastError())); + goto cleanup; + } + + do { + memcpy( Path + RG_DirectoryLength, + FileInfo.cFileName, + (wcslen(FileInfo.cFileName)+1) * sizeof(WCHAR) ); + if (!DeleteFile(Path)) + { + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( + "RplDeleteLogFiles: DeleteFile( %ws) returned %d", + Path, GetLastError())); + goto cleanup; + } + + } while(FindNextFile(SearchHandle, &FileInfo)); + if ((ErrCode = GetLastError()) != ERROR_NO_MORE_FILES) + { + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( + "RplDeleteLogFiles: FindNextFile() returned %d", + ErrCode)); + + } + +cleanup: + if ( SearchHandle != INVALID_HANDLE_VALUE && !FindClose(SearchHandle)) + { + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( + "RplDeleteLogFiles: FindClose() returned %d", + GetLastError())); + } + + return; +} + + +BOOL RplDbInitPath( + IN OUT PWCHAR Path, + IN PWCHAR Name, + OUT PCHAR * pDbcsPath + ) +/*++ + +Routine Description: + Allocates DBCS string corresponding to a UNICODE string obtained via + concatenation of Path & Name strings. + +Arguments: + Path - first UNICODE string + Name - second UNICODE string + pDbcsPath - pointer to a DBCS string corresponding to a concatenation + of above two UNICODE strings + +Return Value: + TRUE if success, FALSE otherwise. + +--*/ +{ + DWORD NameLength; + DWORD PathLength; // not count terminating NULL char + + NameLength = wcslen( Name); + PathLength = RG_DirectoryLength + NameLength; + if ( PathLength >= MAX_PATH) { + RPL_RETURN( FALSE); + } + memcpy( Path + RG_DirectoryLength, Name, (NameLength+1)*sizeof(WCHAR)); + NameLength = RplUnicodeToDbcs( RG_MemoryHandle, Path, PathLength, + MAX_PATH * sizeof(WCHAR), pDbcsPath); + if ( NameLength == 0) { + RPL_RETURN( FALSE); + } + return( TRUE); +} + + +BOOL RplDbSessionInit( + IN BOOL MainSession, + OUT PRPL_SESSION pSession, + OUT BOOL * pErrorReported + ) +{ + + CallB( JetBeginSession( RG_Instance, &pSession->SesId, "admin", "")); + if ( MainSession) { + JET_ERR err = JetAttachDatabase( pSession->SesId, RG_Mdb, 0); + if ( err == JET_errSuccess ) { + // + // JonN 6/16/95 This code works around a JET bug in cases + // where the JET database has moved. The code fragment was + // suggested by Ian Jose. JetAttachDatabase will return + // JET_wrnDatabaseAttached under normal circumstances. + // + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( + "RplDbSessionInit: JetAttachDatabase returned JET_errSuccess, engaging workaround" )); + // Detach(NULL) detached all databases, new to NT 3.51 and up + Call( JetDetachDatabase( pSession->SesId, NULL)); + // + // It is OK if this call returns JET_errSuccess since + // we explicitly detached. Note that we do not normally + // detach at all. + // + CallB( JetAttachDatabase( pSession->SesId, RG_Mdb, 0)); + } + else if ( err == JET_errDatabase200Format ) { + // + // JetInit will succeed if no 200-series logs exist, and the + // problem will not be caught until here. + // + DWORD converr; + converr = RplStartJet500Conversion(); + RplReportEvent( NELOG_RplUpgradeDBTo40, NULL, sizeof(DWORD), &converr); + *pErrorReported = TRUE; + return( FALSE); + } + else + { + CallB( err ); + } + RG_DetachDatabase = TRUE; + } + + CallB( JetOpenDatabase( pSession->SesId, RG_Mdb, NULL, &pSession->DbId, 0)); + CallB( JetOpenTable( pSession->SesId, pSession->DbId, ADAPTER_TABLE_NAME, NULL, 0, + 0, &pSession->AdapterTableId)); + CallB( JetOpenTable( pSession->SesId, pSession->DbId, BOOT_TABLE_NAME, NULL, 0, + 0, &pSession->BootTableId)); + CallB( JetOpenTable( pSession->SesId, pSession->DbId, CONFIG_TABLE_NAME, NULL, 0, + 0, &pSession->ConfigTableId)); + CallB( JetOpenTable( pSession->SesId, pSession->DbId, PROFILE_TABLE_NAME, NULL, 0, + 0, &pSession->ProfileTableId)); + if ( MainSession) { + DWORD Error; + Error = ResumeCreateTable( pSession); // initializes ResumeTable also + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert,( "Error=%d", Error)); + return( FALSE); + } + } + CallB( JetOpenTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME, NULL, 0, + 0, &pSession->ResumeTableId)); + CallB( JetOpenTable( pSession->SesId, pSession->DbId, VENDOR_TABLE_NAME, NULL, 0, + 0, &pSession->VendorTableId)); + CallB( JetOpenTable( pSession->SesId, pSession->DbId, WKSTA_TABLE_NAME, NULL, 0, + 0, &pSession->WkstaTableId)); + + if ( MainSession) { + if ( !RplDbInitColumnInfo( ADAPTER_TABLE_NAME, AdapterTable, + ADAPTER_TABLE_LENGTH, pSession->AdapterTableId, pSession->SesId)) { + return( FALSE); + } + if ( !RplDbInitColumnInfo( BOOT_TABLE_NAME, BootTable, + BOOT_TABLE_LENGTH, pSession->BootTableId, pSession->SesId)) { + return( FALSE); + } + if ( !RplDbInitColumnInfo( CONFIG_TABLE_NAME, ConfigTable, + CONFIG_TABLE_LENGTH, pSession->ConfigTableId, pSession->SesId)) { + return( FALSE); + } + if ( !RplDbInitColumnInfo( PROFILE_TABLE_NAME, ProfileTable, + PROFILE_TABLE_LENGTH, pSession->ProfileTableId, pSession->SesId)) { + return( FALSE); + } + // + // ColumnInfo for resume table has been initialized already. + // + if ( !RplDbInitColumnInfo( VENDOR_TABLE_NAME, VendorTable, + VENDOR_TABLE_LENGTH, pSession->VendorTableId, pSession->SesId)) { + return( FALSE); + } + if ( !RplDbInitColumnInfo( WKSTA_TABLE_NAME, WkstaTable, + WKSTA_TABLE_LENGTH, pSession->WkstaTableId, pSession->SesId)) { + return( FALSE); + } + } + return( TRUE); +} + + +VOID RplDbSessionTerm( + IN BOOL MainSession, + IN PRPL_SESSION pSession + ) +{ + if ( pSession->AdapterTableId != 0) { + Call( JetCloseTable( pSession->SesId, pSession->AdapterTableId)); + } + if ( pSession->BootTableId != 0) { + Call( JetCloseTable( pSession->SesId, pSession->BootTableId)); + } + if ( pSession->ConfigTableId != 0) { + Call( JetCloseTable( pSession->SesId, pSession->ConfigTableId)); + } + if ( pSession->ProfileTableId != 0) { + Call( JetCloseTable( pSession->SesId, pSession->ProfileTableId)); + } + if ( pSession->ResumeTableId != 0) { + Call( JetCloseTable( pSession->SesId, pSession->ResumeTableId)); + if ( MainSession) { + Call( JetDeleteTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME)); + } + } + if ( pSession->VendorTableId != 0) { + Call( JetCloseTable( pSession->SesId, pSession->VendorTableId)); + } + if ( pSession->WkstaTableId != 0) { + Call( JetCloseTable( pSession->SesId, pSession->WkstaTableId)); + } + if ( pSession->DbId != 0) { + Call( JetCloseDatabase( pSession->SesId, pSession->DbId, 0)); + } + if ( pSession->SesId != 0) { + if ( MainSession && RG_DetachDatabase) { +#if 0 + // + // Because of JET restore bugs we are advised NOT TO + // detach database ever. + // + Call( JetDetachDatabase( pSession->SesId, RG_Mdb)); +#endif + RG_DetachDatabase = FALSE; + } + Call( JetEndSession( pSession->SesId, 0)); + } +} + + +BOOL RplDbFindBoot( + IN PRPL_SESSION pSession, + IN PWCHAR BootName, + IN PWCHAR AdapterName + ) +/*++ + Return TRUE if it finds server record for input BootName & AdapterName. + Returns FALSE otherwise. + + Same comment as for RplDbFindWksta. +--*/ +{ + JET_ERR JetError; + DWORD Vendor; + WCHAR SaveChar; + + JetError = JetSetCurrentIndex( pSession->SesId, pSession->BootTableId, BOOT_INDEX_VendorIdBootName); + if ( JetError != JET_errSuccess) { + RplDump( ++RG_Assert, ("SetCurrentIndex failed err=%d", JetError)); + return( FALSE); + } + SaveChar = AdapterName[ RPL_VENDOR_NAME_LENGTH]; + AdapterName[ RPL_VENDOR_NAME_LENGTH] = 0; + Vendor = wcstoul( AdapterName, NULL, 16); + AdapterName[ RPL_VENDOR_NAME_LENGTH] = SaveChar; + JetError = JetMakeKey( pSession->SesId, pSession->BootTableId, &Vendor, sizeof( Vendor), JET_bitNewKey); + if ( JetError != JET_errSuccess) { + RplDump( ++RG_Assert, ("MakeKey failed err=%d", JetError)); + return( FALSE); + } + JetError = JetMakeKey( pSession->SesId, pSession->BootTableId, BootName, ( wcslen( BootName) + 1) * sizeof(WCHAR), 0); + if ( JetError != JET_errSuccess) { + RplDump( ++RG_Assert, ("MakeKey failed err=%d", JetError)); + return( FALSE); + } + JetError = JetSeek( pSession->SesId, pSession->BootTableId, JET_bitSeekEQ); + if ( JetError != JET_errSuccess) { + if ( JetError == JET_errRecordNotFound) { + // + // This is an expected error, do not break for this. + // + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( + "DbFindWksta( %ws) failed", AdapterName)); + } else { + RplDump( ++RG_Assert, ("JetSeek failed err=%d", JetError)); + } + return( FALSE); + } + return( TRUE); +} + + +BOOL RplDbAddAdapterName( + IN PRPL_SESSION pSession, + IN LPWSTR AdapterName + ) +/*++ + Try to add the adapter record for input AdapterName. + + CODEWORK Should use different comments for different VendorName-s. + +Return Value: + TRUE if adapter record for input AdapterName was added + FALSE otherwise + +--*/ +{ +#define ADAPTER_GENERIC_COMMENT L"An unknown client network adapter id." + JET_ERR JetError; + DWORD Flags = 0; + BYTE LocalBuffer[ 300]; + DWORD DataSize; + PWCHAR AdapterComment; + WCHAR VendorName[ RPL_VENDOR_NAME_LENGTH + 1]; + + if ( RplFind( pSession, ADAPTER_TABLE_TAG, AdapterName)) { + return( FALSE); // adapter record is already present + } + + memcpy( VendorName, AdapterName, RPL_VENDOR_NAME_LENGTH*sizeof(WCHAR)); + VendorName[ RPL_VENDOR_NAME_LENGTH] = 0; + + if ( RplFind( pSession, VENDOR_TABLE_TAG, VendorName)) { + CallB( JetRetrieveColumn( pSession->SesId, pSession->VendorTableId, + VendorTable[ VENDOR_VendorComment].ColumnId, LocalBuffer, + sizeof( LocalBuffer), &DataSize, 0, NULL)); + if ( DataSize > sizeof( LocalBuffer)) { + AdapterComment = ADAPTER_GENERIC_COMMENT; + } else { + AdapterComment = (PWCHAR)LocalBuffer; + } + } else { + AdapterComment = ADAPTER_GENERIC_COMMENT; + } + + CallB( JetPrepareUpdate( pSession->SesId, pSession->AdapterTableId, + JET_prepInsert)); + CallB( JetSetColumn( pSession->SesId, pSession->AdapterTableId, + AdapterTable[ ADAPTER_AdapterName].ColumnId, AdapterName, + ( wcslen( AdapterName) + 1) * sizeof(WCHAR), 0, NULL)); + CallB( JetSetColumn( pSession->SesId, pSession->AdapterTableId, + AdapterTable[ ADAPTER_AdapterComment].ColumnId, AdapterComment, + ( wcslen( AdapterComment) + 1) * sizeof(WCHAR), 0, NULL)); + CallB( JetSetColumn( pSession->SesId, pSession->AdapterTableId, + AdapterTable[ ADAPTER_Flags].ColumnId, &Flags, + sizeof(Flags), 0, NULL)); + JetError = JetUpdate( pSession->SesId, pSession->AdapterTableId, NULL, 0, NULL); + if ( JetError < 0) { + if ( JetError != JET_errKeyDuplicate) { + RplDump( ++RG_Assert, ( "JetError=%d", JetError)); + } + return( FALSE); + } + return( TRUE); +} + + +VOID RplDbInstanceTerm( VOID) +{ + if ( !RG_InstanceAllocated) { + return; + } + RplDbSessionTerm( FALSE, &RG_ApiSession); + RplDbSessionTerm( FALSE, &RG_WorkerSession); + RplDbSessionTerm( TRUE, &RG_RequestSession); + Call( JetTerm2( RG_Instance, JET_bitTermComplete)); + RG_InstanceAllocated = FALSE; +} + + +BOOL RplDbInstanceInit( + PCHAR SystemMdb, + PCHAR TempMdb, + PCHAR LogFilePath, + BOOL * pErrorReported + ) +{ + RG_InstanceAllocated = FALSE; + RG_DetachDatabase = FALSE; + memset( &RG_RequestSession, 0, sizeof( RG_RequestSession)); + memset( &RG_WorkerSession, 0, sizeof( RG_WorkerSession)); + memset( &RG_ApiSession, 0, sizeof( RG_ApiSession)); + +#ifdef __JET500 + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramSystemPath, 0, LogFilePath)); +#else + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramSysDbPath, 0, SystemMdb)); +#endif + RG_InstanceAllocated = TRUE; + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramTempPath, 0, TempMdb)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogFilePath, 0, LogFilePath)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxBuffers, 250, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramBfThrshldLowPrcnt, 0, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramBfThrshldHighPrcnt, 100, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxOpenTables, 30, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxOpenTableIndexes, 105, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxCursors, 100, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxSessions, 10, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxVerPages, 64, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramMaxTemporaryTables, 5, NULL)); + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogBuffers, 41, NULL)); +#ifdef __JET500 + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogFileSize, 1000, NULL)); +#else + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogFileSectors, 1000, NULL)); +#endif + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramLogFlushThreshold, 10, NULL)); +#ifdef __JET500 + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramBaseName, 0, "j50")); + { + JET_ERR JetError = JetInit( &RG_Instance); + // + // JetInit will fail if 200-series logs exist. + // + if ( JetError == JET_errDatabase200Format ) { + DWORD converr; + converr = RplStartJet500Conversion(); + RplReportEvent( NELOG_RplUpgradeDBTo40, NULL, sizeof(DWORD), &converr); + *pErrorReported = TRUE; + return( FALSE); + } + else + { + CallB( JetError ); + } + } +#else + CallB( JetSetSystemParameter( &RG_Instance, 0, JET_paramRecovery, 0, "on")); + CallB( JetInit( &RG_Instance)); +#endif + + if ( !RplDbSessionInit( TRUE, &RG_RequestSession, pErrorReported)) { + return( FALSE); + } + if ( !RplDbSessionInit( FALSE, &RG_WorkerSession, pErrorReported)) { + return( FALSE); + } + if ( !RplDbSessionInit( FALSE, &RG_ApiSession, pErrorReported)) { + return( FALSE); + } + return( TRUE); +} + + + +BOOL RplDbInit() +{ + WCHAR Path[ MAX_PATH]; // must hold terminating NULL char too + JET_ERR JetError; + PCHAR SystemMdb = NULL; // needed for cleanup below + PCHAR TempMdb = NULL; // needed for cleanup below + PCHAR LogFilePath = NULL; // needed for cleanup below + BOOL Success = FALSE; + BOOL ErrorReported = FALSE; + + memcpy( Path, RG_Directory, RG_DirectoryLength * sizeof(WCHAR)); + + if ( !RplDbInitPath( Path, RPL_BACKUP_SUBDIR, &RG_BackupPath)) { + goto cleanup; + } + if ( !RplDbInitPath( Path, RPL_SERVICE_DATABASE_W, &RG_Mdb)) { + goto cleanup; + } + if ( !RplDbInitPath( Path, RPL_SYSTEM_DATABASE_W, &SystemMdb)) { + goto cleanup; + } + if ( !RplDbInitPath( Path, RPL_TEMP_DATABASE_W, &TempMdb)) { + goto cleanup; + } + if ( !RplDbInitPath( Path, L"", &LogFilePath)) { + goto cleanup; + } + +#if 1 + if ( !RplDbInstanceInit( SystemMdb, TempMdb, LogFilePath, &ErrorReported)) { + if (ErrorReported) { + goto cleanup; + } + RplReportEvent( NELOG_RplInitDatabase, NULL, 0, NULL); + RplDbInstanceTerm(); +#else + // + // Used only for testing purposes (to restore without attempt to init first) + // + if ( TRUE) { +#endif +#ifdef __JET500 + JetError = JetRestore( RG_BackupPath, 0); +#else + JetError = JetRestore( RG_BackupPath, 0, NULL, 0); +#endif + if ( JetError == JET_errBadLogVersion +// +// JonN 11/28/95 According to JLiem, the old BadNextLogVersion is broken up +// into two errors and two warnings in JET500. If we get either of the +// warnings (558 or 559) then JET took care of deleting the old log files +// and we can continue. We handle the errors as we handled BadNextLogVersion. +// +#ifdef __JET500 + || JetError == JET_errGivenLogFileHasBadSignature + || JetError == JET_errGivenLogFileIsNotContiguous +#else + || JetError == JET_errBadNextLogVersion +#endif + ) { + RplDeleteLogFiles(); +#ifdef __JET500 + JetError = JetRestore( RG_BackupPath, 0); +#else + JetError = JetRestore( RG_BackupPath, 0, NULL, 0); +#endif + } +#ifdef __JET500 +#ifndef JET_ATTACH_CATCHES_ERROR + if ( JetError == JET_errDatabase200Format ) { + RplReportEvent( NELOG_RplUpgradeDBTo40, NULL, sizeof(DWORD), &JetError); + RplDump( ++RG_Assert,( "200-fmt from JetRestore" )); + goto cleanup; + } +#endif +#endif + if ( JetError < 0) { + RplDump( ++RG_Assert, ("JetRestore( %s) failed err=%d", RG_BackupPath, JetError)); + RplReportEvent( NELOG_RplRestoreDatabaseFailure, NULL, sizeof(DWORD), &JetError); + goto cleanup; + } + RplReportEvent( NELOG_RplRestoreDatabaseSuccess, NULL, 0, NULL); + if ( !RplDbInstanceInit( SystemMdb, TempMdb, LogFilePath, &ErrorReported)) { + if (ErrorReported) { + goto cleanup; + } + RplReportEvent( NELOG_RplInitRestoredDatabase, NULL, 0, NULL); + goto cleanup; + } + } + Success = TRUE; + +cleanup: + if ( SystemMdb != NULL) { + RplMemFree( RG_MemoryHandle, SystemMdb); + } + if ( TempMdb != NULL) { + RplMemFree( RG_MemoryHandle, TempMdb); + } + if ( LogFilePath != NULL) { + RplMemFree( RG_MemoryHandle, LogFilePath); + } + return( Success); +} + + +VOID RplDbTerm( VOID) +/*++ + + Save changes that may have been made to the database. Without this + the database may be left in an unusable state where any subsequent + attempt of calling JetInit() for this database would fail. + +--*/ +{ + RplDbInstanceTerm(); + RplMemFree( RG_MemoryHandle, RG_Mdb); + RplMemFree( RG_MemoryHandle, RG_BackupPath); +} + + +BOOL RplDbFindWksta( + IN PRPL_SESSION pSession, + IN LPWSTR AdapterName + ) +/*++ + Return TRUE if it finds wksta record for input AdapterName. + Returns FALSE otherwise. + + This code could be make more efficient by defining AdapterName + to be jet currency data (it is silly now taking wcslen of + AdapterName since it is a fixed length string. + + It is ASSUMED that the caller of this function will ensure transaction + processing. + +--*/ +{ + JET_ERR JetError; + + JetError = JetSetCurrentIndex( pSession->SesId, pSession->WkstaTableId, WKSTA_INDEX_AdapterName); + if ( JetError != JET_errSuccess) { + RplDump( ++RG_Assert, ("SetCurrentIndex failed err=%d", JetError)); + return( FALSE); + } + JetError = JetMakeKey( pSession->SesId, pSession->WkstaTableId, AdapterName, ( wcslen( AdapterName) + 1) * sizeof(WCHAR), JET_bitNewKey); + if ( JetError != JET_errSuccess) { + RplDump( ++RG_Assert, ("MakeKey failed err=%d", JetError)); + return( FALSE); + } + JetError = JetSeek( pSession->SesId, pSession->WkstaTableId, JET_bitSeekEQ); + if ( JetError != JET_errSuccess) { +#ifdef RPL_DEBUG + // + // Do not assert for expected errors ( empty table or + // failure to find a record). + // + if ( JetError == JET_errNoCurrentRecord + || JetError == JET_errRecordNotFound) { + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( + "DbFindWksta( %ws) failed", AdapterName)); + } else { + RplDump( ++RG_Assert, ("JetSeek failed err=%d", JetError)); + } +#endif + return( FALSE); + } + return( TRUE); +} + + +BOOL RplDbFillWksta( + IN PRPL_SESSION pSession, + IN OUT PRPL_WORKER_DATA pWorkerData + ) +/*++ + Returns TRUE if it can find all the information needed to boot the client. + Returns FALSE otherwise. + + This routine should be modified to use ConfigGetInfo() - but without the + penalty of memory allocations. +--*/ +{ + DWORD DataSize; + PWCHAR AdapterName; + WCHAR BootName[ RPL_MAX_BOOT_NAME_LENGTH + 1]; + WCHAR FilePath[ MAX_PATH]; + DWORD Length; + DWORD Flags; + + AdapterName = pWorkerData->pRcb->AdapterName; + + if ( !RplDbFindWksta( pSession, AdapterName)) { + RplDump( ++RG_Assert, ("FindWksta( %ws) failed", AdapterName)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NERR_RplWkstaNotFound; + return( FALSE); + } + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_WkstaName].ColumnId, pWorkerData->WkstaName, + sizeof( pWorkerData->WkstaName), &DataSize, 0, NULL)); + + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_ProfileName].ColumnId, pWorkerData->ProfileName, + sizeof( pWorkerData->ProfileName), &DataSize, 0, NULL)); + + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_FitFile].ColumnId, FilePath, + sizeof( FilePath), &DataSize, 0, NULL)); + Length = DataSize / sizeof( WCHAR) - 1; + if ( DataSize > sizeof( FilePath) || FilePath[ Length] != 0) { + RplDump( ++RG_Assert, ( "FitFile is bad %ws", FilePath)); + return( FALSE); + } + pWorkerData->FitFile = RplMemAlloc( pWorkerData->MemoryHandle, + RG_DirectoryLength * sizeof(WCHAR) + DataSize); + if ( pWorkerData->FitFile == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + memcpy( pWorkerData->FitFile, RG_Directory, RG_DirectoryLength * sizeof(WCHAR)); + memcpy( pWorkerData->FitFile + RG_DirectoryLength, FilePath, DataSize); + + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_BootName].ColumnId, BootName, + sizeof( BootName), &DataSize, 0, NULL)); + + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_Flags].ColumnId, &Flags, + sizeof( Flags), &DataSize, 0, NULL)); + + switch ( Flags & WKSTA_FLAGS_MASK_LOGON_INPUT) { + case WKSTA_FLAGS_LOGON_INPUT_REQUIRED: + pWorkerData->LogonInput = WKSTA_LOGON_INPUT_REQUIRED; + break; + case WKSTA_FLAGS_LOGON_INPUT_OPTIONAL: + pWorkerData->LogonInput = WKSTA_LOGON_INPUT_OPTIONAL; + break; + case WKSTA_FLAGS_LOGON_INPUT_IMPOSSIBLE: + pWorkerData->LogonInput = WKSTA_LOGON_INPUT_IMPOSSIBLE; + break; + default: + RplDump( ++RG_Assert, ("Flags=0x%x", Flags)); + return( FALSE); + break; + } + switch ( Flags & WKSTA_FLAGS_MASK_DHCP) { + default: + case WKSTA_FLAGS_DHCP_TRUE: + pWorkerData->TcpIpAddress = INADDR_NONE; + pWorkerData->TcpIpSubnet = INADDR_NONE; + pWorkerData->TcpIpGateway = INADDR_NONE; + pWorkerData->DisableDhcp = WKSTA_DISABLE_DHCP_FALSE; + break; + case WKSTA_FLAGS_DHCP_FALSE: + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpAddress].ColumnId, &pWorkerData->TcpIpAddress, + sizeof( pWorkerData->TcpIpAddress), &DataSize, 0, NULL)); + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpSubnet].ColumnId, &pWorkerData->TcpIpSubnet, + sizeof( pWorkerData->TcpIpSubnet), &DataSize, 0, NULL)); + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpGateway].ColumnId, &pWorkerData->TcpIpGateway, + sizeof( pWorkerData->TcpIpGateway), &DataSize, 0, NULL)); + pWorkerData->DisableDhcp = WKSTA_DISABLE_DHCP_TRUE; + break; +#if 0 // to help testing with old style records this is commented out + default: + RplDump( ++RG_Assert, ("Flags=0x%x", Flags)); + return( FALSE); + break; +#endif + } + + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpAddress].ColumnId, &pWorkerData->TcpIpAddress, + sizeof( pWorkerData->TcpIpAddress), &DataSize, 0, NULL)); + + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpSubnet].ColumnId, &pWorkerData->TcpIpSubnet, + sizeof( pWorkerData->TcpIpSubnet), &DataSize, 0, NULL)); + + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpGateway].ColumnId, &pWorkerData->TcpIpGateway, + sizeof( pWorkerData->TcpIpGateway), &DataSize, 0, NULL)); + + if ( !RplDbFindBoot( pSession, BootName, AdapterName)) { + RplDump( ++RG_Assert, ("FindBoot failed")); + return( FALSE); + } + CallB( JetRetrieveColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_BbcFile].ColumnId, FilePath, + sizeof( FilePath), &DataSize, 0, NULL)); + Length = DataSize / sizeof( WCHAR) - 1; + if ( DataSize > sizeof( FilePath) || FilePath[ Length] != 0) { + RplDump( ++RG_Assert, ( "BbcFile is bad %ws", FilePath)); + return( FALSE); + } + pWorkerData->BbcFile = RplMemAlloc( pWorkerData->MemoryHandle, + RG_DirectoryLength * sizeof(WCHAR) + DataSize); + if ( pWorkerData->BbcFile == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + memcpy( pWorkerData->BbcFile, RG_Directory, RG_DirectoryLength * sizeof(WCHAR)); + memcpy( pWorkerData->BbcFile + RG_DirectoryLength, FilePath, DataSize); + + CallB( JetRetrieveColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_WindowSize].ColumnId, &pWorkerData->WindowSize, + sizeof( pWorkerData->WindowSize), &DataSize, 0, NULL)); + CallB( JetRetrieveColumn( pSession->SesId, pSession->BootTableId, + BootTable[ BOOT_Flags].ColumnId, &Flags, + sizeof( Flags), &DataSize, 0, NULL)); + switch( Flags & BOOT_FLAGS_MASK_FINAL_ACKNOWLEDGMENT) { + case BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_TRUE: + pWorkerData->FinalAck = TRUE; + break; + case BOOT_FLAGS_FINAL_ACKNOWLEDGMENT_FALSE: + pWorkerData->FinalAck = FALSE; + break; + default: + RplDump( ++RG_Assert, ("Flags=0x%x", Flags)); + return( FALSE); + break; + } + return( TRUE); +} + + +BOOL RplWorkerFillWksta( IN OUT PRPL_WORKER_DATA pWorkerData) +{ + PRPL_SESSION pSession = &RG_WorkerSession; + BOOL Success; + + EnterCriticalSection( &RG_ProtectWorkerSession); + Call( JetBeginTransaction( pSession->SesId)); + Success = RplDbFillWksta( pSession, pWorkerData); + JetCommitTransaction( pSession->SesId, 0); + LeaveCriticalSection( &RG_ProtectWorkerSession); + return( Success); +} + + +BOOL RplRequestHaveWksta( IN LPWSTR AdapterName) +/*++ + +Routine Description: + + If it finds wksta record for input AdapterName then it returns TRUE. + Else, it tries to add the adapter record for input AdapterName, then + returns FALSE. + + This code could be make more efficient by defining AdapterName + to be jet currency data (it is silly now taking wcslen of + AdapterName since it is a fixed length string. + +Return Value: + TRUE if wksta record for input AdapterName is found + FALSE otherwise + +--*/ +{ + PRPL_SESSION pSession = &RG_RequestSession; + BOOL WkstaFound; + BOOL AdapterAdded; + + EnterCriticalSection( &RG_ProtectRequestSession); + Call( JetBeginTransaction( pSession->SesId)); + + WkstaFound = RplDbFindWksta( pSession, AdapterName); + + if ( !WkstaFound) { + // + // Failed to find it. Try to add adapter record then. + // + AdapterAdded = RplDbAddAdapterName( pSession, AdapterName); + } else { + AdapterAdded = FALSE; + } + + if ( AdapterAdded) { + // + // We do not flush newly added adapter records since we do + // not want to slow down request threads. + // + Call( JetCommitTransaction( pSession->SesId, 0)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectRequestSession); + return( WkstaFound); +} + + +// +// Trmplated from DHCP's database.c 12/13/95 JonN +// +DWORD +RplStartJet500Conversion( + ) +/*++ + +Routine Description: + + This function starts the process to convert the jet200 version + database to jet500 version database. The Dhcp will terminate + after starting this process. When the conversion completes, + the dhcp service would be restarted by the convert process itself. + +Arguments: + + +Return Value: + + Windows Error. + +--*/ +{ + DWORD ExLen; + STARTUPINFOA StartupInfo = {0}; + PROCESS_INFORMATION ProcessInfo = {0}; + CHAR szCmdLine[MAX_PATH]; + +#define JET_CONV_MODULE_NAME "%SystemRoot%\\system32\\jetconv REMOTEBOOT /@" + + ExLen = ExpandEnvironmentStringsA( JET_CONV_MODULE_NAME, szCmdLine, MAX_PATH ); + + if( (ExLen == 0) || (ExLen > MAX_PATH) ) { + + if( ExLen == 0 ) { + return GetLastError(); + } + else { + return ERROR_META_EXPANSION_TOO_LONG; + } + + } + + + StartupInfo.cb = sizeof(STARTUPINFOA); + + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST, ( "Calling %s\n",szCmdLine )); + + if ( !CreateProcessA( + NULL, + szCmdLine, + NULL, + NULL, + FALSE, + DETACHED_PROCESS, +// CREATE_NEW_CONSOLE, + NULL, + NULL, + &StartupInfo, + &ProcessInfo) + ) { + + return GetLastError(); + + + } + + return ERROR_SUCCESS; +} diff --git a/private/net/svcdlls/rpl/server/database.h b/private/net/svcdlls/rpl/server/database.h new file mode 100644 index 000000000..91811d5ff --- /dev/null +++ b/private/net/svcdlls/rpl/server/database.h @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + database.h + +Abstract: + + Exports from database.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +BOOL RplDbInit( VOID); +VOID RplDbTerm( VOID); +BOOL RplDbFindWksta( + IN PRPL_SESSION pSession, + IN LPWSTR AdapterName + ); +BOOL RplWorkerFillWksta( IN OUT PRPL_WORKER_DATA pWorkerData); +BOOL RplRequestHaveWksta( IN LPWSTR AdapterName); + diff --git a/private/net/svcdlls/rpl/server/db.h b/private/net/svcdlls/rpl/server/db.h new file mode 100644 index 000000000..572dc9f6b --- /dev/null +++ b/private/net/svcdlls/rpl/server/db.h @@ -0,0 +1,263 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + db.h + +Abstract: + + Main include file for JET database portion of RPL service. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + + +// +// jet call macros: +// Call - jet call ignore error +// CallR - jet call RETURN on error +// CallB - jet call return BOOLEAN (false) on error +// CallM - jet call return MAPPED error +// + +#ifdef RPL_DEBUG +#define Call( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + if ( _JetError < 0) { \ + ++RG_Assert; \ + } \ + RplDebugPrint("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + } \ + } + +#define CallR( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + if ( _JetError < 0) { \ + ++RG_Assert; \ + } \ + RplDebugPrint("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + return; \ + } \ + } \ + } + +#define CallB( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + if ( _JetError < 0) { \ + ++RG_Assert; \ + } \ + RplDebugPrint("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + return( FALSE); \ + } \ + } \ + } +#define CallM( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + if ( _JetError < 0) { \ + ++RG_Assert; \ + } \ + RplDebugPrint("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + return( NERR_RplInternal); \ + } \ + } \ + } +#define CallJ( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError != JET_errSuccess) { \ + if ( _JetError < 0) { \ + ++RG_Assert; \ + } \ + RplDebugPrint("File = %s, Line = %d, _JetError = %d\n", __FILE__, __LINE__, _JetError); \ + if ( _JetError < 0) { \ + Error = NERR_RplInternal; \ + goto cleanup; \ + } \ + } \ + } + +#else +#define Call( fn ) { if ( fn < 0) { NOTHING;} } +#define CallR( fn ) { if ( fn < 0) { return;} } +#define CallB( fn ) { if ( fn < 0) { return( FALSE);} } +#define CallM( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError < 0) { \ + return( NERR_RplInternal); \ + } \ + } +#define CallJ( fn ) \ + { \ + int _JetError = fn; \ + if ( _JetError < 0) { \ + Error = NERR_RplInternal; \ + goto cleanup; \ + } \ + } +#endif + + +#define DEFAULT_BUFFER_SIZE (64 * 1024) // arbitrary choice + +typedef enum _RPL_TABLE_TAG { + ADAPTER_TABLE_TAG = 0, + BOOT_TABLE_TAG, + CONFIG_TABLE_TAG, + PROFILE_TABLE_TAG, + RESUME_TABLE_TAG, + VENDOR_TABLE_TAG, + WKSTA_TABLE_TAG +} RPL_TABLE_TAG, *PRPL_TABLE_TAG; + +typedef struct _RPL_FILTER { + BOOL FindFirst; + DWORD VendorId; + DWORD BootNameSize; + WCHAR BootName[ 16]; +} RPL_FILTER, *PRPL_FILTER; + + +// +// Exports from resume.c +// +DWORD ResumeCreateTable( OUT PRPL_SESSION pSession); +BOOL ResumeKeyGet( + IN PRPL_SESSION pSession, + IN DWORD ResumeHandle, + OUT PVOID ResumeValue, + IN OUT PDWORD pResumeSize + ); +BOOL ResumeKeySet( + IN PRPL_SESSION pSession, + IN DWORD ServerHandle, + IN PVOID ResumeValue, + IN DWORD ResumeSize, + OUT PDWORD pResumeHandle + ); +VOID ResumePrune( + IN PRPL_SESSION pSession, + IN DWORD ServerHandle + ); + +// +// Exports from boot.c +// +DWORD BootFilterFind( + IN PRPL_SESSION pSession, + IN OUT PRPL_FILTER pFilter, + IN OUT PBOOL pTableEnd + ); +BOOL BootFind( + IN PRPL_SESSION pSession, + IN PWCHAR BootName, + IN DWORD VendorId + ); + +// +// Exports from config.c +// +DWORD ConfigGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + IN OUT LPINT pSpaceLeft + ); + +DWORD ConfigSetInfo( + IN PRPL_SESSION pSession, + IN DWORD Level, + IN LPVOID Buffer, + OUT LPDWORD pErrorParameter + ); + +// +// Exports from profile.c +// +DWORD ProfileGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + OUT LPINT pDataSize + ); + +// +// Exports from wksta.c +// +DWORD WkstaGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + IN OUT LPINT pSpaceLeft + ); + +BOOL WkstaFindFirst( + IN PRPL_SESSION pSession, + IN PWCHAR ProfileName + ); + +// +// Exports from disk.c +// +#define ADD_NEW_BRANCHES 0 +#define DEL_NEW_BRANCHES 1 +#define DEL_OLD_BRANCHES 2 +DWORD RplTreeCopy( IN PWCHAR Source, IN PWCHAR Target); +DWORD RplTreeDelete( IN PWCHAR Target); +DWORD RplMakeDir( IN PWCHAR Target); +DWORD WkstaDiskAdd( + IN BOOL Doit, + IN PWCHAR WkstaName, + IN PWCHAR ProfileName, + IN DWORD Sharing + ); +DWORD WkstaDiskClone( + IN BOOL Doit, + IN PWCHAR SourceWkstaName, + IN PWCHAR TargetWkstaName + ); +DWORD WkstaDiskSet( + IN DWORD Action, + IN PWCHAR WkstaName, + IN PWCHAR ProfileName, + IN DWORD Sharing, + IN PWCHAR TargetWkstaName, + IN PWCHAR TargetProfileName, + IN DWORD TargetSharing + ); +DWORD ProfileDiskAdd( + IN BOOL Doit, + IN PWCHAR ProfileName, + IN PWCHAR DirName, + IN PWCHAR DirName2, + IN PWCHAR DirName3, + IN PWCHAR DirName4 + ); +DWORD ProfileDiskClone( + IN BOOL Doit, + IN PWCHAR SourceProfileName, + IN PWCHAR TargetProfileName + ); + diff --git a/private/net/svcdlls/rpl/server/dblib.c b/private/net/svcdlls/rpl/server/dblib.c new file mode 100644 index 000000000..b95f88f90 --- /dev/null +++ b/private/net/svcdlls/rpl/server/dblib.c @@ -0,0 +1,386 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + dblib.c + +Abstract: + + Common api worker routines. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "db.h" +#include "adapter.h" +#include "boot.h" +#include "config.h" +#include "profile.h" +#include "vendor.h" +#include "wksta.h" +#include "dblib.h" + + +BOOL RplScan( + IN PRPL_SESSION pSession, + IN JET_TABLEID TableId, + IN BOOL FindNextBoot, + IN OUT PRPL_FILTER pFilter, + IN OUT PBOOL pTableEnd + ) +/*++ + Set currency to the next profile or config. +--*/ +{ + DWORD Error; + JET_ERR JetError; + + for ( ; ;) { + if ( FindNextBoot == TRUE) { + Error = BootFilterFind( pSession, pFilter, pTableEnd); + if ( Error != NO_ERROR) { + return( FALSE); + } + if ( *pTableEnd == TRUE) { + return( TRUE); + } + CallB( JetMakeKey( pSession->SesId, TableId, pFilter->BootName, pFilter->BootNameSize, JET_bitNewKey)); + } + JetError = JetSeek( pSession->SesId, TableId, JET_bitSeekGT); + if ( JetError != JET_errSuccess) { + *pTableEnd = TRUE; + return( TRUE); + } + // + // Verify that current record has the desired boot block & at the + // same time set index range to be used with JetMove( Next). + // + CallB( JetMakeKey( pSession->SesId, TableId, pFilter->BootName, pFilter->BootNameSize, JET_bitNewKey)); + JetError = JetSetIndexRange( pSession->SesId, TableId, + JET_bitRangeInclusive | JET_bitRangeUpperLimit); + if ( JetError == JET_errSuccess) { + return( TRUE); + } + // + // There are no records for current BootName. + // Get next BootName for VendorId. + // + FindNextBoot = TRUE; + } +} + + +BOOL RplFilterFirst( + IN PRPL_SESSION pSession, + IN RPL_TABLE_TAG TableTag, + IN OUT PRPL_FILTER pFilter OPTIONAL, + IN LPDWORD pResumeHandle, + OUT PBOOL pTableEnd + ) +/*++ + Set currency to the first record for given vendor id, following + the record described by the resume handle. +--*/ +{ +#define MAX_RESUME_VALUE_SIZE \ + (RPL_MAX_BOOT_NAME_SIZE + \ + max( RPL_MAX_PROFILE_NAME_SIZE, RPL_MAX_CONFIG_NAME_SIZE)) +#define MAX_NAME_LENGTH \ + (JETBUG_STRING_LENGTH + \ + max( RPL_MAX_PROFILE_NAME_LENGTH, RPL_MAX_CONFIG_NAME_LENGTH)) + BYTE ResumeValue[ MAX_RESUME_VALUE_SIZE]; + DWORD ResumeSize; + DWORD Error; + JET_ERR JetError; + DWORD NameSize; + WCHAR Name[ MAX_NAME_LENGTH + 1]; + PCHAR Index; + JET_TABLEID TableId; + + *pTableEnd = FALSE; + + switch ( TableTag) { + case ADAPTER_TABLE_TAG: + TableId = pSession->AdapterTableId; + Index = ADAPTER_INDEX_AdapterName; + break; + case BOOT_TABLE_TAG: + TableId = pSession->BootTableId; + Index = BOOT_INDEX_BootName; + break; + case CONFIG_TABLE_TAG: + TableId = pSession->ConfigTableId; + Index = pFilter == NULL ? CONFIG_INDEX_ConfigName : CONFIG_INDEX_BootNameConfigName; + break; + case PROFILE_TABLE_TAG: + TableId = pSession->ProfileTableId; + Index = pFilter == NULL ? PROFILE_INDEX_ProfileName : PROFILE_INDEX_BootNameProfileName; + break; + case VENDOR_TABLE_TAG: + TableId = pSession->VendorTableId; + Index = VENDOR_INDEX_VendorName; + break; + case WKSTA_TABLE_TAG: + TableId = pSession->WkstaTableId; + Index = WKSTA_INDEX_WkstaName; + break; + default: + RPL_ASSERT( FALSE); + } + + CallB( JetSetCurrentIndex( pSession->SesId, TableId, Index)); + + // + // The call to move to the beginning of the table is not redundant. + // E.g. JET_errNoCurrentRecord will be returned in case of empty table. + // + JetError = JetMove( pSession->SesId, TableId, JET_MoveFirst, 0); + if ( JetError < 0) { + if ( JetError == JET_errNoCurrentRecord) { + *pTableEnd = TRUE; + return( TRUE); + } else { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + return( FALSE); + } + } + + if ( (ARGUMENT_PRESENT( pResumeHandle)) && *pResumeHandle != 0) { + ResumeSize = sizeof( ResumeValue); + if ( !ResumeKeyGet( pSession, *pResumeHandle, ResumeValue, &ResumeSize)) { + return( FALSE); + } + if ( pFilter == NULL) { + CallB( JetMakeKey( pSession->SesId, TableId, ResumeValue, ResumeSize, JET_bitNewKey)); + CallB( JetSeek( pSession->SesId, TableId, JET_bitSeekGT)); + return( TRUE); + } + pFilter->BootNameSize = (wcslen( (PWCHAR)ResumeValue) + 1) * sizeof(WCHAR); + memcpy( pFilter->BootName, ResumeValue, pFilter->BootNameSize); + NameSize = (wcslen( (PWCHAR)(ResumeValue + pFilter->BootNameSize)) + 1) + * sizeof(WCHAR); + memcpy( Name, ResumeValue + pFilter->BootNameSize, NameSize); + RPL_ASSERT( ResumeSize == pFilter->BootNameSize + NameSize); + } else { + if ( pFilter == NULL) { + return( TRUE); + } + pFilter->BootNameSize = 0; // scan from the beginning + Error = BootFilterFind( pSession, pFilter, pTableEnd); + if ( Error != NO_ERROR) { + return( FALSE); + } + if ( *pTableEnd == TRUE) { + return( TRUE); + } + NameSize = 0; + } + CallB( JetMakeKey( pSession->SesId, TableId, pFilter->BootName, pFilter->BootNameSize, JET_bitNewKey)); + if ( NameSize != 0) { +#ifdef RPL_JETBUG + memcpy( (PBYTE)Name + NameSize, JETBUG_STRING, JETBUG_STRING_SIZE); + NameSize += JETBUG_STRING_LENGTH * sizeof(WCHAR); +#endif + CallB( JetMakeKey( pSession->SesId, TableId, Name, NameSize, 0)); + } + return( RplScan( pSession, TableId, FALSE, pFilter, pTableEnd)); +} + + +VOID RplFilterSave( + IN PRPL_SESSION pSession, + IN DWORD ServerHandle, + IN PRPL_FILTER pFilter, + IN PWCHAR Name, + IN PDWORD pResumeHandle + ) +{ + BYTE ResumeBuffer[ 30 * sizeof(WCHAR)]; // BUGBUG hardcoding + DWORD ResumeSize; + DWORD NameSize; + if ( pFilter != NULL) { + ResumeSize = pFilter->BootNameSize; + memcpy( ResumeBuffer, pFilter->BootName, ResumeSize); + } else { + ResumeSize = 0; + } + NameSize = ( wcslen( Name) + 1) * sizeof(WCHAR); + memcpy( ResumeBuffer + ResumeSize, Name, NameSize); + ResumeSize += NameSize; + (VOID)ResumeKeySet( pSession, ServerHandle, ResumeBuffer, ResumeSize, pResumeHandle); +} + + +BOOL RplFilterNext( + IN PRPL_SESSION pSession, + IN JET_TABLEID TableId, + IN OUT PRPL_FILTER pFilter, + OUT PBOOL pTableEnd + ) +{ + JET_ERR JetError; + + JetError = JetMove( pSession->SesId, TableId, JET_MoveNext, 0); + if ( JetError == JET_errSuccess) { + return( TRUE); + } + if ( pFilter == NULL) { + RplDump( RG_DebugLevel & RPL_DEBUG_DB, ( + "FilterNext: TableId=0x%x, JetError=%d", TableId, JetError)); + *pTableEnd = TRUE; + return( TRUE); // assume end of table + } else { + RplDump( RG_DebugLevel & RPL_DEBUG_DB, ( + "FilterNext: TableId=0x%x, BootName=%ws, JetError=%d", + TableId, pFilter->BootName, JetError)); + return( RplScan( pSession, TableId, TRUE, pFilter, pTableEnd)); + } +} + + +BOOL RplFind( + IN PRPL_SESSION pSession, + IN RPL_TABLE_TAG TableTag, + IN PWCHAR Name + ) +{ + JET_ERR JetError; + PCHAR Index; + JET_TABLEID TableId; + + switch ( TableTag) { + case ADAPTER_TABLE_TAG: + TableId = pSession->AdapterTableId; + Index = ADAPTER_INDEX_AdapterName; + break; + case CONFIG_TABLE_TAG: + TableId = pSession->ConfigTableId; + Index = CONFIG_INDEX_ConfigName; + break; + case PROFILE_TABLE_TAG: + TableId = pSession->ProfileTableId; + Index = PROFILE_INDEX_ProfileName; + break; + case VENDOR_TABLE_TAG: + TableId = pSession->VendorTableId; + Index = VENDOR_INDEX_VendorName; + break; + case WKSTA_TABLE_TAG: + TableId = pSession->WkstaTableId; + Index = WKSTA_INDEX_WkstaName; + break; + default: + RPL_RETURN( FALSE); + } + CallB( JetSetCurrentIndex( pSession->SesId, TableId, Index)); + CallB( JetMakeKey( pSession->SesId, TableId, Name, ( wcslen( Name) + 1) * sizeof(WCHAR), JET_bitNewKey)); + JetError = JetSeek( pSession->SesId, TableId, JET_bitSeekEQ); + if ( JetError < 0) { +#ifdef RPL_DEBUG + // + // JET_errNoCurrentRecord will be returned in case of empty table. + // + if ( JetError != JET_errRecordNotFound + && JetError != JET_errNoCurrentRecord) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + } +#endif + return( FALSE); + } + return( TRUE); +} + + +BOOL RplFindByField( + IN PRPL_SESSION pSession, + IN RPL_TABLE_TAG TableTag, + IN PCHAR IndexName, + IN PWCHAR FieldName + ) +/*++ + Returns TRUE if it can find a record (the first record) that has + FieldName as a value. Returns FALSE otherwise. + + We cannot use SetIndexRange technique here because FieldName is only + the first part of an index & we would never find a match. +--*/ +{ + DWORD FieldNameSize; + JET_ERR JetError; + BYTE Data[ 300]; + DWORD DataSize; + JET_TABLEID TableId; + JET_COLUMNID ColumnId; + + switch ( TableTag) { + case CONFIG_TABLE_TAG: + TableId = pSession->ConfigTableId; + if ( strcmp( IndexName, CONFIG_INDEX_BootNameConfigName) == 0) { + ColumnId = ProfileTable[ CONFIG_BootName].ColumnId; + } else { + RPL_RETURN( FALSE); + } + break; + case PROFILE_TABLE_TAG: + TableId = pSession->ProfileTableId; + if ( strcmp( IndexName, PROFILE_INDEX_ConfigNameProfileName) == 0) { + ColumnId = ProfileTable[ PROFILE_ConfigName].ColumnId; + } else if ( strcmp( IndexName, PROFILE_INDEX_BootNameProfileName) == 0) { + ColumnId = ProfileTable[ PROFILE_BootName].ColumnId; + } else { + RPL_RETURN( FALSE); + } + break; + case WKSTA_TABLE_TAG: + TableId = pSession->WkstaTableId; + if ( strcmp( IndexName, WKSTA_INDEX_ProfileNameWkstaName) == 0) { + ColumnId = WkstaTable[ WKSTA_ProfileName].ColumnId; + } else if ( strcmp( IndexName, WKSTA_INDEX_BootNameWkstaName) == 0) { + ColumnId = WkstaTable[ WKSTA_BootName].ColumnId; + } else { + RPL_RETURN( FALSE); + } + break; + default: + RPL_RETURN( FALSE); + } + + CallB( JetSetCurrentIndex( pSession->SesId, TableId, IndexName)); + FieldNameSize = ( wcslen( FieldName) + 1) * sizeof(WCHAR); + CallB( JetMakeKey( pSession->SesId, TableId, FieldName, FieldNameSize, JET_bitNewKey)); + JetError = JetSeek( pSession->SesId, TableId, JET_bitSeekGE); + if ( JetError < 0) { + return( FALSE); + } + CallB( JetRetrieveColumn( pSession->SesId, TableId, ColumnId, Data, + sizeof( Data), &DataSize, 0, NULL)); + if ( FieldNameSize != DataSize) { + return( FALSE); + } + if ( memcmp( FieldName, Data, DataSize) != 0) { + return( FALSE); + } + return( TRUE); // we found record using this field +} + + +DWORD AdapterNameToVendorId( IN PWCHAR AdapterName) +{ + WCHAR VendorName[ RPL_VENDOR_NAME_LENGTH + 1]; + // + // Yes, we could zero the char in AdapterName, calculate VendorId, + // then restore char. But this is more robust though. + // + memcpy( VendorName, AdapterName, RPL_VENDOR_NAME_LENGTH*sizeof(WCHAR)); + VendorName[ RPL_VENDOR_NAME_LENGTH] = 0; + return( wcstoul( VendorName, NULL, 16)); +} diff --git a/private/net/svcdlls/rpl/server/dblib.h b/private/net/svcdlls/rpl/server/dblib.h new file mode 100644 index 000000000..463a4dea3 --- /dev/null +++ b/private/net/svcdlls/rpl/server/dblib.h @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + dblib.h + +Abstract: + + Exports from dblib.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + + +BOOL RplScan( + IN PRPL_SESSION pSession, + IN JET_TABLEID TableId, + IN BOOL FindNextBoot, + IN OUT PRPL_FILTER pFilter, + IN OUT PBOOL pTableEnd + ); +BOOL RplFilterFirst( + IN PRPL_SESSION pSession, + IN RPL_TABLE_TAG TableTag, + IN OUT PRPL_FILTER pFilter, + IN LPDWORD pResumeHandle, + OUT PBOOL pTableEnd + ); +BOOL RplFilterNext( + IN PRPL_SESSION pSession, + IN JET_TABLEID TableId, + IN OUT PRPL_FILTER pFilter, + OUT PBOOL pTableEnd + ); +VOID RplFilterSave( + IN PRPL_SESSION pSession, + IN DWORD ServerHandle, + IN PRPL_FILTER pFilter, + IN PWCHAR Name, + IN PDWORD pResumeHandle + ); +BOOL RplFind( + IN PRPL_SESSION pSession, + IN RPL_TABLE_TAG TableTag, + IN PWCHAR Name + ); +BOOL RplFindByField( + IN PRPL_SESSION pSession, + IN RPL_TABLE_TAG TableTag, + IN PCHAR IndexName, + IN PWCHAR FieldName + ); +DWORD AdapterNameToVendorId( IN PWCHAR AdapterName); + + diff --git a/private/net/svcdlls/rpl/server/debug.c b/private/net/svcdlls/rpl/server/debug.c new file mode 100644 index 000000000..e27c49bd7 --- /dev/null +++ b/private/net/svcdlls/rpl/server/debug.c @@ -0,0 +1,141 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + debug.c + +Abstract: + + Debugging module. RpldDebugPrint() was adapted from TelnetDebugPrint() + in net\sockets\tcpcmd\telnet\debug.c. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "debug.h" + +#ifdef RPL_DEBUG + +#define RPL_PROMPT "[Rpl] " +#define DEBUG_RECORD_SIZE 0x80 +#define DEBUG_BUFFER_SIZE 0x20000 // 2*64k, must be a power of 2 +#define DEBUG_BUFFER_MASK (DEBUG_BUFFER_SIZE - 1) + +// int RG_DebugLevel = -1; // max debugging +// int RG_DebugLevel = 0; // no debugging, for public use + +int RG_DebugLevel; // needed by other modules +int RG_Assert; // needed by other modules + +PCHAR RG_DebugBuffer; +CRITICAL_SECTION RG_ProtectDebug; +DWORD RG_DebugOffset; +// +// This buffer is used even when RG_DebugBuffer is not NULL. +// +char RG_DebugPublicBuffer[ 120]; + + +VOID RplDebugDelete( VOID) +{ + if ( RG_DebugBuffer != NULL) { + (VOID)GlobalFree( RG_DebugBuffer); + } + DeleteCriticalSection( &RG_ProtectDebug); +} + +#define RPL_DEFAULT_DEBUG_LEVEL ( RPL_DEBUG_FLOW | \ + RPL_DEBUG_SERVER | \ + RPL_DEBUG_MAJOR ) + +#define RPL_MAXIMUM_DEBUG_LEVEL (-1L) + + + +VOID RplDebugInitialize( VOID) +{ + // + // Set RG_Assert to 0. Without this the very first use of + // RplDump() will lead to an assert. + // + RG_Assert = 0; + +// RG_DebugLevel = RPL_DEFAULT_DEBUG_LEVEL; + RG_DebugLevel = RPL_MAXIMUM_DEBUG_LEVEL & ~RPL_DEBUG_MEMALLOC + & ~RPL_DEBUG_FLOWINIT & ~RPL_DEBUG_MISC; +// RG_DebugLevel = RPL_MAXIMUM_DEBUG_LEVEL; +// RG_DebugLevel = RPL_DEBUG_MISC; + + + RG_DebugBuffer = (PCHAR)GlobalAlloc( + GMEM_FIXED, + DEBUG_BUFFER_SIZE + DEBUG_RECORD_SIZE + ); + if ( RG_DebugBuffer != NULL) { + RtlFillMemory( + RG_DebugBuffer, + DEBUG_BUFFER_SIZE + DEBUG_RECORD_SIZE, + '*' + ); + RG_DebugOffset = 0; + } + memcpy( RG_DebugPublicBuffer, RPL_PROMPT, sizeof( RPL_PROMPT) -1); + + InitializeCriticalSection( &RG_ProtectDebug); +} + + +VOID _CRTAPI1 RplDebugPrint( CONST CHAR * format, ...) +{ + va_list arglist; + + va_start( arglist, format); + + EnterCriticalSection( &RG_ProtectDebug); + + if ( RG_Assert == 0 && RG_DebugBuffer != NULL) { + RtlZeroMemory( RG_DebugBuffer + RG_DebugOffset, DEBUG_RECORD_SIZE); + vsprintf( RG_DebugBuffer + RG_DebugOffset, format, arglist); + RG_DebugOffset += DEBUG_RECORD_SIZE; + RG_DebugOffset &= DEBUG_BUFFER_MASK; + } else { + vsprintf( RG_DebugPublicBuffer + sizeof( RPL_PROMPT) - 1, format, arglist); + DbgPrint( "%s\n", RG_DebugPublicBuffer); // for kernel debugger + printf( "%s\n", RG_DebugPublicBuffer); // for user debugger + } + + if ( RG_Assert != 0) { + ASSERT( FALSE); // break for checked build + DbgPrint( "[RplSvc] Running checked version of service on a free build.\n"); + printf( "[RplSvc] Running checked version of service on a free build.\n"); + } + while ( RG_Assert != 0) { + DbgPrint( "[RplSvc] Debug, then reset RG_Assert to 0.\n"); + printf( "[RplSvc] Debug, then reset RG_Assert to 0.\n"); + DbgUserBreakPoint(); + Sleep( RG_Assert * 30000); // sleep for 30 seconds + } + + LeaveCriticalSection( &RG_ProtectDebug); + + va_end( arglist); + +} // RplDebugPrint + + +#endif // RPL_DEBUG + + + diff --git a/private/net/svcdlls/rpl/server/debug.h b/private/net/svcdlls/rpl/server/debug.h new file mode 100644 index 000000000..31706c1fe --- /dev/null +++ b/private/net/svcdlls/rpl/server/debug.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + debug.h + +Abstract: + + Exports from debug.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#ifdef RPL_DEBUG +VOID RplDebugInitialize( VOID); +VOID RplDebugDelete( VOID); +#endif // RPL_DEBUG diff --git a/private/net/svcdlls/rpl/server/disk.c b/private/net/svcdlls/rpl/server/disk.c new file mode 100644 index 000000000..1c53f8c52 --- /dev/null +++ b/private/net/svcdlls/rpl/server/disk.c @@ -0,0 +1,318 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + disk.c + +Abstract: + + Routines changing disk files (other than the database). + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "db.h" + + +DWORD WkstaDiskSet( + IN DWORD Action, + IN PWCHAR WkstaName, + IN PWCHAR ProfileName, + IN DWORD Sharing, + IN PWCHAR TargetWkstaName, + IN PWCHAR TargetProfileName, + IN DWORD TargetSharing + ) +{ + WCHAR Target[ MAX_PATH + 1]; + WCHAR Source[ MAX_PATH + 1]; + DWORD Error; + + if ( TargetWkstaName != NULL) { + if ( TargetSharing = 0) { + TargetSharing = Sharing; + } + if ( TargetProfileName == NULL) { + TargetProfileName = ProfileName; + } + Error = WkstaDiskAdd( Action == ADD_NEW_BRANCHES, + Action == DEL_OLD_BRANCHES ? WkstaName : TargetWkstaName, + TargetProfileName, TargetSharing); + if ( Action != ADD_NEW_BRANCHES) { + return( Error); + } + swprintf( Target, L"%ws\\TMPFILES\\%ws", RG_DiskRplfiles, TargetWkstaName); + swprintf( Source, L"%ws\\TMPFILES\\%ws", RG_DiskRplfiles, WkstaName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + swprintf( Target, L"%ws\\MACHINES\\%ws\\DATA", RG_DiskRplfiles, TargetWkstaName); + swprintf( Source, L"%ws\\MACHINES\\%ws\\DATA", RG_DiskRplfiles, WkstaName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + swprintf( Target, L"%ws\\MACHINES\\%ws\\LOGS", RG_DiskRplfiles, TargetWkstaName); + swprintf( Source, L"%ws\\MACHINES\\%ws\\LOGS", RG_DiskRplfiles, WkstaName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + } else if ( TargetProfileName != NULL) { + DWORD Length; + if ( TargetSharing == 0) { + TargetSharing = Sharing; + } + swprintf( Target, L"%ws\\MACHINES\\%ws\\%ws", RG_DiskRplfiles, + WkstaName, + Action == DEL_OLD_BRANCHES ? ProfileName : TargetProfileName); + Error = RplTreeDelete( Target); + if ( Action != ADD_NEW_BRANCHES) { + return( Error); + } + Error = RplMakeDir( Target); + if ( Error != NO_ERROR) { + return( Error); + } + Length = wcslen( Target); + wcscat( Target + Length, L"\\WKSTA"); + swprintf( Source, L"%ws\\PROFILES\\%ws\\WKSTA.PRO", RG_DiskRplfiles, TargetProfileName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + if ( TargetSharing == WKSTA_FLAGS_SHARING_TRUE) { + return( Error); + } + swprintf( Target + Length, L"\\PRO"); + swprintf( Source, L"%ws\\PROFILES\\%ws", RG_DiskRplfiles, ProfileName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + } else if ( TargetSharing != 0) { + BOOL DeletePro; + BOOL CreatePro; // FALSE whenever DeletePro is FALSE + switch( Action) { + case ADD_NEW_BRANCHES: + DeletePro = TRUE; + CreatePro = (TargetSharing == WKSTA_FLAGS_SHARING_FALSE); + break; + case DEL_NEW_BRANCHES: + DeletePro = (TargetSharing == WKSTA_FLAGS_SHARING_FALSE); + CreatePro = FALSE; + break; + case DEL_OLD_BRANCHES: + DeletePro = (Sharing ==WKSTA_FLAGS_SHARING_FALSE); + CreatePro = FALSE; + } + if ( DeletePro == FALSE) { + RPL_ASSERT( CreatePro == FALSE); + return( NO_ERROR); + } + swprintf( Target, L"%ws\\MACHINES\\%ws\\%ws\\PRO", RG_DiskRplfiles, + WkstaName, ProfileName); + Error = RplTreeDelete( Target); + if ( Error != NO_ERROR) { + return( Error); + } + if ( CreatePro == FALSE) { + return( NO_ERROR); + } + swprintf( Source, L"%ws\\PROFILES\\%ws", RG_DiskRplfiles, ProfileName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + } + return( NO_ERROR); +} + + +DWORD WkstaDiskAdd( + IN BOOL Doit, + IN PWCHAR WkstaName, + IN PWCHAR ProfileName, + IN DWORD Sharing + ) +{ + WCHAR Target[ MAX_PATH + 1]; + WCHAR Source[ MAX_PATH + 1]; + DWORD Error; + + swprintf( Target, L"%ws\\TMPFILES\\%ws", RG_DiskRplfiles, WkstaName); + RplTreeDelete( Target); + if ( Doit) { + Error = RplMakeDir( Target); + if ( Error != NO_ERROR) { + return( Error); + } + } + swprintf( Target, L"%ws\\MACHINES\\%ws", RG_DiskRplfiles, WkstaName); + RplTreeDelete( Target); + if ( Doit) { + DWORD Length = wcslen( Target); + Error = RplMakeDir( Target); + if ( Error != NO_ERROR) { + return( Error); + } + // + // Note that here we have "MACHINE" - unlike "MACHINES" above. What a fun! + // + swprintf( Source, L"%ws\\CONFIGS\\MACHINE", RG_DiskRplfiles); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + // + // Currently RplTreeCopy fails on missing links. Therefore, + // we must first create directory below before RplTreeCopy + // can be called. + // + swprintf( Target + Length, L"\\%ws", ProfileName); + Error = RplMakeDir( Target); + if ( Error != NO_ERROR) { + return( Error); + } + wcscat( Target + Length, L"\\WKSTA"); + swprintf( Source, L"%ws\\PROFILES\\%ws\\WKSTA.PRO", RG_DiskRplfiles, ProfileName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + if ( Sharing == WKSTA_FLAGS_SHARING_TRUE) { + return( Error); + } + swprintf( Target + Length, L"\\%ws\\PRO", ProfileName); + swprintf( Source, L"%ws\\PROFILES\\%ws", RG_DiskRplfiles, ProfileName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + } + return( NO_ERROR); +} + + +DWORD WkstaDiskClone( + IN BOOL Doit, + IN PWCHAR SourceWkstaName, + IN PWCHAR TargetWkstaName + ) +{ + WCHAR Target[ MAX_PATH + 1]; + WCHAR Source[ MAX_PATH + 1]; + DWORD Error; + + // + // TMPFILES tree is never cloned + // + swprintf( Target, L"%ws\\TMPFILES\\%ws", RG_DiskRplfiles, TargetWkstaName); + RplTreeDelete( Target); + if ( Doit) { + Error = RplMakeDir( Target); + if ( Error != NO_ERROR) { + return( Error); + } + } + + // + // MACHINES tree is cloned except for the DATA subtree + // + swprintf( Target, L"%ws\\MACHINES\\%ws", RG_DiskRplfiles, TargetWkstaName); + RplTreeDelete( Target); + if ( Doit) { + swprintf( Source, L"%ws\\MACHINES\\%ws", RG_DiskRplfiles, SourceWkstaName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + wcscat( Target, L"\\DATA"); + RplTreeDelete( Target); + Error = RplMakeDir( Target); + if ( Error != NO_ERROR) { + return( Error); + } + } + return( NO_ERROR); +} + + + +DWORD ProfileDiskAdd( + IN BOOL Doit, + IN PWCHAR ProfileName, + IN PWCHAR DirName, + IN PWCHAR DirName2, + IN PWCHAR DirName3, + IN PWCHAR DirName4 + ) +{ + WCHAR Target[ MAX_PATH + 1]; + WCHAR Source[ MAX_PATH + 1]; + DWORD Error; + + swprintf( Target, L"%ws\\PROFILES\\%ws", RG_DiskRplfiles, ProfileName); + RplTreeDelete( Target); + if ( Doit) { + swprintf( Source, L"%ws\\CONFIGS\\%ws", RG_DiskRplfiles, DirName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR || DirName2 == NULL || *DirName2 == 0) { + return( Error); + } + swprintf( Source, L"%ws\\CONFIGS\\%ws", RG_DiskRplfiles, DirName2); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR || DirName3 == NULL || *DirName3 == 0) { + return( Error); + } + swprintf( Source, L"%ws\\CONFIGS\\%ws", RG_DiskRplfiles, DirName3); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR || DirName4 == NULL || *DirName4 == 0) { + return( Error); + } + swprintf( Source, L"%ws\\CONFIGS\\%ws", RG_DiskRplfiles, DirName4); + Error = RplTreeCopy( Source, Target); + return( Error); + } + return( NO_ERROR); +} + + + +DWORD ProfileDiskClone( + IN BOOL Doit, + IN PWCHAR SourceProfileName, + IN PWCHAR TargetProfileName + ) +{ + WCHAR Target[ MAX_PATH + 1]; + WCHAR Source[ MAX_PATH + 1]; + DWORD Error; + + swprintf( Target, L"%ws\\PROFILES\\%ws", RG_DiskRplfiles, TargetProfileName); + RplTreeDelete( Target); + if ( Doit) { + Error = RplMakeDir( Target); + if ( Error != NO_ERROR) { + return( Error); + } + swprintf( Source, L"%ws\\PROFILES\\%ws", RG_DiskRplfiles, SourceProfileName); + Error = RplTreeCopy( Source, Target); + if ( Error != NO_ERROR) { + return( Error); + } + } + return( NO_ERROR); +} + + + diff --git a/private/net/svcdlls/rpl/server/fitfile.c b/private/net/svcdlls/rpl/server/fitfile.c new file mode 100644 index 000000000..9aa421920 --- /dev/null +++ b/private/net/svcdlls/rpl/server/fitfile.c @@ -0,0 +1,442 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + fitfile.c + +Abstract: + + Processes the FIT file referenced in workstation record, eliminating + the following keywords: + + (DOSFIT) defines the UNC path of the temporary files used + by the new DOS boot (this will probably be removed very soon). + + (CNAME) the netbios cname of the workstation + + (PROFILE) a directory tree for the the shareable config files + + (RPLFILES) share for the configuration and per workstation files + + (SWAPPATH) share for the swap and tmp files, (== (RPLFILES) by default) + + (RPLBINS) share for all executable files, (== (RPLFILES) by default) + + (SRVNAME) the name of RPL server, by default the current netbios name. + The server name is usually replaced by the share names. + + The keywords are replaced by the actual parameters. CNAME and PROFILES + are defined in the workstation line of RPL.map and the last parameters + are optional lanman.ini parameters. (RPLFILES) is by default + \\CurrentServer\RPLFILE and (SWAPPATH) and (RPLBINS) are the same share, + if they have not been defined in lanman.ini. + Procedure supports the tilde replacement (e.g: ~~~~~~~~~~2) similar to + the old IBM RIPL. OEMs may define their own tilde fileds in the + rpl.map workstation lines, if they really want to. The default system + uses the tilde replacement only for per workstation (PROFILE) and (CNAME). + The alias keys are first translated to tildes and then they are + translated to wksta line fields. + + Also removes all extra comments and spaces from the fit to save DOS and + OS/2 memory. + + Provides fitfile functionality similar to that contained in rmapopen.c + of LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "fitfile.h" + +#define TAB_CHAR L'\t' +#define LEFT_BRACKET_CHAR L'(' +#define BACK_SLASH_CHAR L'\\' + + +INT RplEatSpaces( IN OUT LPWSTR Source) +/*++ + +Routine Description: + + Deletes the extra white space characters in the fit string. + Only one white space or tabulator is necessary. + +Arguments: + + Source - string to process + +Return Value: + + Length in characters of the modified string (not counting the + terminating NULL character). + +--*/ +{ + LPWSTR Origin = Source; + LPWSTR Target = Source; + WCHAR ch; + + for (;;) { + + while ( (ch = *Target++ = *Source++)!=0 && ch!=SPACE_CHAR + && ch!=TAB_CHAR) { + NOTHING; // copy characters until nul, tab or space character is found + } + + if ( ch == 0) { + break; // end of string + } + + if (ch == TAB_CHAR) { + *(Target - 1) = SPACE_CHAR; // replace tab with a space + } + + while (*Source == SPACE_CHAR || *Source == TAB_CHAR) { + Source++; // skip extra tabs & spaces + } + + // + // If the next character is a space character (e.g. newline) + // then this space is unnecessary, write on it in the next time. + // + if ( iswspace(*Source)) { + Target--; + } + } + return( Target-Origin - 1); // no casts are needed + +} // EatSpaces() + + +VOID RplFitAliasInit( IN OUT PRPL_WORKER_DATA pWorkerData) +/*++ + Must make sure number of these entries equals FIT_ALIAS_ARRAY_LENGTH +--*/ +{ + DWORD Index; + PFIT_ALIAS pFitAlias; + PFIT_ALIAS FitAliasArray; + + pFitAlias = FitAliasArray = &( pWorkerData->FitAliasArray[0]); + + pFitAlias->Key = L"(PROFILE)"; // profile name of RPL wksta + pFitAlias->Value = pWorkerData->ProfileName; + + (++pFitAlias)->Key = L"(CNAME)"; // computer name of RPL wksta + pFitAlias->Value = pWorkerData->WkstaName; + +// +// (RPL_SERVER_NAME) is not documented by us nor used in our FIT files. +// We should probably remove this entry. +// + (++pFitAlias)->Key = L"(RPL_SERVER_NAME)"; // computer name of RPL server + pFitAlias->Value = RG_ComputerName; + +// +// (RPLFILES) must be the FIRST SHARE in the array, because it is the +// default used in (TMPFILES) and (BINFILES) if they are not defined! +// + (++pFitAlias)->Key = L"(RPLFILES)"; + pFitAlias->Value = RG_UncRplfiles; + + (++pFitAlias)->Key = L"(TMPFILES)"; + pFitAlias->Value = L"TMPFILES"; + + (++pFitAlias)->Key = L"(BINFILES)"; + pFitAlias->Value = L"BINFILES"; + +// +// (COMPUTER_NAME) is not documented by us nor used in our FIT files. +// It has the same purpose as (CNAME) and was kept for compatibility +// with some old NOKIA FIT files. We should probably remove this entry. +// + (++pFitAlias)->Key = L"(COMPUTER_NAME)"; + pFitAlias->Value = RG_ComputerName; + + RPL_ASSERT( FitAliasArray + FIT_ALIAS_ARRAY_LENGTH == ++pFitAlias); + + for ( Index = 0; Index < FIT_ALIAS_ARRAY_LENGTH; Index++) { + FitAliasArray[ Index].KeyLength = wcslen( FitAliasArray[ Index].Key); + FitAliasArray[ Index].ValueLength = wcslen( FitAliasArray[ Index].Value); + } +} + + +PFIT_ALIAS RplFitFind( IN PFIT_ALIAS FitAliasArray, IN LPWSTR Key) +/*++ + +Routine Description: + Looks for FIT_ALIAS containing input key string. + +Arguments: + Key - ptr to key string + +Return Value: + Returns the pointer of a FIT alias structure or NULL if the the key was not found. + +--*/ +{ + DWORD index; + + for ( index = 0; index < FIT_ALIAS_ARRAY_LENGTH; index++) { + if ( !wcsncmp( FitAliasArray[ index].Key, Key, FitAliasArray[ index].KeyLength)) { + return &(FitAliasArray[ index]); + } + } + return( NULL); +} + + +DWORD RplFitNewLength( IN LPWSTR pFitImage, IN PFIT_ALIAS FitAliasArray) +{ + PWCHAR Cursor; + PFIT_ALIAS pFitAlias; + INT Length; + + // + // Calculate the length of the new fit file. Some key replacements + // will increase the total length, the other decrease it. + // + for ( Cursor = pFitImage, Length = wcslen( pFitImage); + ( Cursor = wcschr( Cursor, LEFT_BRACKET_CHAR)) != NULL; + Cursor++) { + + if ( (pFitAlias = RplFitFind( FitAliasArray, Cursor)) != NULL) { + // + // We found a keyword, replacement should be made, see how this + // would change the total length of FIT data. + // + Length += (INT)pFitAlias->ValueLength - (INT)pFitAlias->KeyLength; + } + } + return( Length); +} + + +VOID RplFitReplaceKeys( + OUT PWCHAR Target, + IN PWCHAR Source, + IN PFIT_ALIAS FitAliasArray + ) +/*++ + Replace keywords. + +--*/ +{ + PFIT_ALIAS pFitAlias; + PWCHAR Cursor; + INT Length; + + Cursor = Source; // Initailize + + while ( (Cursor = wcschr( Cursor, LEFT_BRACKET_CHAR)) != NULL) { + + if ( (pFitAlias = RplFitFind( FitAliasArray, Cursor)) != NULL) { + // + // Copy stuff before the keyword, then copy the replacement string. + // + Length = Cursor - Source; // no casts are needed + memcpy( Target, Source, Length * sizeof( WCHAR)); + memcpy( Target + Length, pFitAlias->Value, pFitAlias->ValueLength * sizeof( WCHAR)); + Source += Length + pFitAlias->KeyLength; + Target += Length + pFitAlias->ValueLength; + Cursor += pFitAlias->KeyLength; // skip entire key + } else { + Cursor++; // skip LEFT_BRACKET_CHAR + } + } + // + // Here LEFT_BRACKET is NULL and we still need to copy from Source to the end of the + // string, including the terminal zero. + // + wcscpy( Target, Source); +} + + +VOID RplStripComments( IN OUT LPWSTR buffer) +/*++ + +Routine Description: + Skips leading spaces in each line and removes all comments lines + from a buffer containing FIT file. + +Arguments: + buffer - pointer to buffer containing FIT file, the buffer is NULL + terminated. + +Return Value: + None. + +--*/ +{ + PWCHAR Cursor; // running cursor + PWCHAR LineEnd; // pointer to NEW_LINE_CHAR + + Cursor = buffer; + for ( ; ;) { + // + // We are at the beginning of a line, skip leading white space characters. + // + Cursor += wcsspn( Cursor, L" \f\n\r\t\v"); + if ( *Cursor == 0) { + break; // we reached the end of a string + } + + LineEnd = wcschr( Cursor, NEW_LINE_CHAR); + if ( LineEnd == NULL) { + break; // ignore stuff without end of line + } + LineEnd++; // make it point beyond NEW_LINE_CHAR we just found + + // + // Copy only the non comment lines. Memmove below works even + // for overlapping memory regions. + // + if ( *Cursor != COMMENT_CHAR) { + INT Length = LineEnd - Cursor; + buffer = (PWCHAR)memmove( buffer, Cursor, Length * sizeof(WCHAR)) + Length; + } + Cursor = LineEnd; + } + *buffer = 0; // null terminate +} + + + +VOID RplFitStripRplfiles( IN OUT LPWSTR Buffer) +/*++ + The first line in a FIT file is a special case, it must contain the + default UNC share used in a FIT file. This UNC name need not be + anywhere else in a FIT file, so remove all other references. + + BUGBUG: should we insist FIT file contains UNC name in the first line ?? + +--*/ +{ + PWCHAR Cursor; + INT Length; + + if ( Buffer[0] == BACK_SLASH_CHAR && Buffer[1] == BACK_SLASH_CHAR) { + // + // First line contains UNC name, remember its length. + // + Cursor = wcspbrk( Buffer, L" \f\n\r\t\v"); + Length = Cursor - Buffer; // no casts are needed + + while ( (Cursor = wcsstr( Cursor, DOUBLE_BACK_SLASH_STRING)) != NULL) { + if ( !wcsncmp( Buffer, Cursor, Length) && Cursor[ Length] == BACK_SLASH_CHAR) { + memset( Cursor, SPACE_CHAR, (Length + 1) * sizeof( WCHAR)); + Cursor += Length + 1; + } else { + Cursor += (sizeof(DOUBLE_BACK_SLASH_STRING)/sizeof(WCHAR) - 1); + } + } + } +} + + +BOOL RplFitFile( IN OUT PRPL_WORKER_DATA pWorkerData) +{ + PFIT_ALIAS FitAliasArray; + LPWSTR UnicodeString; // UNICODE content of FIT file + PWCHAR Target; + INT UnicodeStringLength; + BOOL Success; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++FitFile")); + + Success = FALSE; + FitAliasArray = &( pWorkerData->FitAliasArray[ 0]); + + // + // Initalize FIT_ALIAS[] array since it will be used in calculations below. + // + RplFitAliasInit( pWorkerData); + + // + // Read FIT file data as a UNICODE string. + // + UnicodeString = RplReadTextFile( pWorkerData->MemoryHandle, + pWorkerData->FitFile, MAX_FIT_FILE_SIZE); + if ( UnicodeString == NULL) { + RplDump( ++RG_Assert, ( "FitFile=%ws", pWorkerData->FitFile)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->FitFile; + pWorkerData->EventId = NELOG_RplWkstaFileRead; + return( FALSE); + } + + // + // Remove the comments and all unnecessary spaces. There should be not + // extra characters in FIT, because they eat both DOS and OS/2 memory. + // + RplStripComments( UnicodeString); + + // + // Calculate space needed for a UNICODE version of FIT file after we make + // all key replacements. + // + UnicodeStringLength = RplFitNewLength( UnicodeString, FitAliasArray); + + // + // Allocate space for UNICODE version of FIT file. + // + Target = RplMemAlloc( pWorkerData->MemoryHandle, (UnicodeStringLength+1) * sizeof( WCHAR)); + if ( Target == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + goto cleanup; + } + + RplFitReplaceKeys( Target, UnicodeString, FitAliasArray); + RplMemFree( pWorkerData->MemoryHandle, UnicodeString); + UnicodeString = Target; + + // + // Get rid of RPLFILES duplicates. + // + RplFitStripRplfiles( UnicodeString); + + UnicodeStringLength = RplEatSpaces( UnicodeString); // compactify + _wcsupr( UnicodeString); // upppercase + + // + // Convert UNICODE fit string into DBCS fit string. + // + pWorkerData->ClientFitSize = RplUnicodeToDbcs( + pWorkerData->MemoryHandle, + UnicodeString, + UnicodeStringLength, + MAX_FIT_FILE_SIZE, + &(pWorkerData->ClientFit) + ); + if ( pWorkerData->ClientFitSize == 0) { + RplDump( ++RG_Assert, ( "UnicodeString=0x%x, UnicodeString=%ws", + UnicodeString, UnicodeString)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->FitFile; + pWorkerData->EventId = NELOG_RplWkstaFileSize; + goto cleanup; + } + + Success = TRUE; + +cleanup: + if ( UnicodeString != NULL) { + RplMemFree( pWorkerData->MemoryHandle, UnicodeString); + } + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--FitFile")); + return( Success); +} diff --git a/private/net/svcdlls/rpl/server/fitfile.h b/private/net/svcdlls/rpl/server/fitfile.h new file mode 100644 index 000000000..4ccb4fc01 --- /dev/null +++ b/private/net/svcdlls/rpl/server/fitfile.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + fitfile.h + +Abstract: + + Exports from fitfile.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +BOOL RplFitFile( IN OUT PRPL_WORKER_DATA pWorkerData); + + diff --git a/private/net/svcdlls/rpl/server/library.c b/private/net/svcdlls/rpl/server/library.c new file mode 100644 index 000000000..414c85fc2 --- /dev/null +++ b/private/net/svcdlls/rpl/server/library.c @@ -0,0 +1,273 @@ +/*++ + +Copyright (c) 1987 - 1993 Microsoft Corporation + +Module Name: + + library.c + + Provides similar functionality to rpllib.c in LANMAN 2.1 code. + +Abstract: + + Common library routines. + +Author: + + Vladimir Z. Vulovic 25 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" + + + +LPWSTR RplGetLastPathComponent( IN LPWSTR path_str) +/*++ + +Routine Description: + Returns the last component of the path. + +Arguments: + path_str - pointer to path string + +Return Value: + Pointer to the last component of the path. + +--*/ +{ + LPWSTR ret_str; + WCHAR ch; + + for( ch = *( ret_str = path_str); ch != 0; ch = *(++path_str)) { + if ( ch == '\\' || ch == '/') { + ret_str = path_str + 1; // remember most recent component + } + } + return( ret_str); +} + + + +HANDLE RplFileOpen( IN LPWSTR FilePath) +/*++ + +Routine Description: + + Open existing file for reading, at the same time denying write + access to others. Note that WIN32 errors are basically identical + to OS/2 errors! + + In case of special errors we may try a number of times to open the + requested file. + +Arguments: + + FilePath - of file to open + +Return Value: + + A valid file handle if successful, else INVALID_HANDLE_VALUE if + unsuccessful. + +--*/ +{ + DWORD status; + DWORD retry_count; + HANDLE handle; + + // + // If file is being used by another process, we make up to 40 retries + // each one lasting 0.750 seconds (for a max total of 30 seconds) before + // we resign. Configuration programs may lock the files temporarily, + // but if somebody locks a file for a long time, then we must die. + // + for ( retry_count = 0; retry_count < MAX_OPEN_RETRY; retry_count++) { + + handle = CreateFile( FilePath, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0L); + if ( handle != INVALID_HANDLE_VALUE) { + return( handle); // success, all done + } + + status = GetLastError(); + + if ( status != ERROR_SHARING_VIOLATION) { + break; // bad, unexpected case + } + + Sleep( 750L ); + } + RplReportEvent( NELOG_Init_OpenCreate_Err, FilePath, sizeof(WORD), (PBYTE)&status); + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( "FileOpen(%ws) failed, status = %d", FilePath, status)); + return( INVALID_HANDLE_VALUE); +} + + + +LPWSTR RplReadTextFile( + IN HANDLE MemoryHandle, + IN LPWSTR FileName, + IN DWORD MaxFileSize + ) +/*++ + +Routine Description: + + Reads text file, converts its content from dbcs to unicode, and returns + a pointer to newly allocated unicode buffer. + +Arguments: + +Return Value: + + Pointer to unicode buffer table if successful, NULL otherwise. + +--*/ +{ + PBYTE DbcsString = NULL; + DWORD DbcsSize; + PWCHAR UnicodeString; + DWORD UnicodeSize; + int UnicodeStringLength; + HANDLE FileHandle; + DWORD BytesRead; + BOOL success = FALSE; + PWCHAR pWchar; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++ReadTextFile:0x%x,%ws", MemoryHandle, FileName)); + + FileHandle = RplFileOpen( FileName); + if ( FileHandle == INVALID_HANDLE_VALUE) { + goto exit; + } + DbcsSize = GetFileSize( FileHandle, NULL); // does not include 0x1A at the file end + if ( DbcsSize == INVALID_FILE_SIZE || DbcsSize > MaxFileSize) { + goto exit; + } + DbcsString = RplMemAlloc( MemoryHandle, DbcsSize); + if ( DbcsString == NULL) { + goto exit; + } + + UnicodeSize = ( DbcsSize + 1) * sizeof(WCHAR); // extra 1 for terminating NULL + UnicodeString = RplMemAlloc( MemoryHandle, UnicodeSize); + if ( UnicodeString == NULL) { + goto exit; + } + + if ( !ReadFile( FileHandle, DbcsString, DbcsSize, &BytesRead, NULL)) { + goto exit; + } + + if ( BytesRead != DbcsSize) { + goto exit; + } + + UnicodeStringLength = MultiByteToWideChar( + CP_OEMCP, // text files stored in OEM + MB_PRECOMPOSED, DbcsString, DbcsSize, UnicodeString, + UnicodeSize); + if ( UnicodeStringLength == 0) { + goto exit; + } + + // + // Null-terminate string! JonN 8/7/94 + // + UnicodeString[ UnicodeStringLength] = 0; + + // + // If file has END_OF_TEXT_FILE_CHAR, truncate the text there. + // + pWchar = wcschr( UnicodeString, END_OF_TEXT_FILE_CHAR); + if ( pWchar != NULL) { + *pWchar = 0; + } + + success = TRUE; + +exit: + + if ( FileHandle != INVALID_HANDLE_VALUE) { + (VOID)CloseHandle( FileHandle); + } + if ( DbcsString != NULL) { + RplMemFree( MemoryHandle, DbcsString); + } + + if ( success != TRUE) { + RplMemFree( MemoryHandle, UnicodeString); + UnicodeString = NULL; + } + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--ReadTextFile:0x%x,%ws", MemoryHandle, FileName)); + return( UnicodeString); + +} // RplReadTextFile + + +DWORD RplUnicodeToDbcs( + IN HANDLE MemoryHandle, + IN LPWSTR UnicodeString, + IN INT UnicodeStringLength, + IN DWORD MaxDbcsStringSize, + OUT LPSTR * pDbcsString + ) +/*++ + Allocates DBCS string corresponding to a UNICODE string. + + Returns size of buffer needed for DbcsString, counting space needed for + the terminal null byte. +--*/ +{ + LPSTR DbcsString; + DWORD ByteCount; + + if ( UnicodeStringLength == -1) { + UnicodeStringLength = wcslen( UnicodeString); + } + + // + // Assumed the worst case where every UNICODE char maps to a double + // byte DBCS char (except for DBCS terminating null char). + // + ByteCount = UnicodeStringLength * sizeof(WCHAR) + sizeof(CHAR); + + // + // If caller's limit is more stringent, use it. + // + if ( ByteCount > MaxDbcsStringSize) { + ByteCount = MaxDbcsStringSize; + } + + DbcsString = RplMemAlloc( MemoryHandle, ByteCount); + if ( DbcsString == NULL) { + RPL_RETURN( 0); + } + + ByteCount = WideCharToMultiByte( // not counting terminal null byte + CP_OEMCP, // always use OEM + 0, + UnicodeString, + UnicodeStringLength, + DbcsString, // dbcs string + ByteCount, + NULL, // no default character + NULL // no default character flag + ); + if ( ByteCount == 0) { + RplMemFree( MemoryHandle, DbcsString); + RPL_RETURN( 0); + } + DbcsString[ ByteCount] = 0; // this may be redundant + *pDbcsString = DbcsString; + return( ByteCount + 1); // caller expects terminal null byte to be counted +} + diff --git a/private/net/svcdlls/rpl/server/local.h b/private/net/svcdlls/rpl/server/local.h new file mode 100644 index 000000000..b21ddac9e --- /dev/null +++ b/private/net/svcdlls/rpl/server/local.h @@ -0,0 +1,556 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + local.h + +Abstract: + + Main include file for Remote initial Program Load service. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include <nt.h> // ntexapi.h\NtQuerySystemTime +#include <ntrtl.h> // RtlTimeToSecondsSince1970 +#include <nturtl.h> + +#include <windows.h> // DWORD, IN, File APIs, etc. +#include <stdlib.h> +#include <lmcons.h> + +#include <stdio.h> // vsprintf +#include <ctype.h> // isspace + +#include <lmerr.h> // NERR_RplBootStartFailed - used to be here +#include <lmapibuf.h> // NetApiBufferFree +#include <netlib.h> + +#include <lmsvc.h> + +#include <lmalert.h> // STD_ALERT ALERT_OTHER_INFO + +#include <lmerrlog.h> +#include <alertmsg.h> +#include <lmserver.h> +#include <netlib.h> +#include <netlock.h> // Lock data types, functions, and macros. +#include <thread.h> // FORMAT_NET_THREAD_ID, NetpCurrentThread(). + +#include <lmshare.h> // PSHARE_INFO_2 +#include <lmaccess.h> // NetGroupGetInfo +#include <lmconfig.h> // NetConfigGet +#include <nb30.h> // NCB + + +// +// Global types and constants (used in all RPL server files). +// + +#include <riplcons.h> // includes __JET500 flag +#include <jet.h> +#include <rpldebug.h> +#include <rpldll.h> // rplnet.dll entry points & return codes +#include <rpllib.h> // AddKey(), MapJetError(), FillTcpIpString() +#include <ripltyps.h> + +#include <rpc.h> // DataTypes and runtime APIs +#include <rpcutil.h> // Prototypes for MIDL user functions +// +// rplsvc_s.h includes imports.h which includes lmrpl.h. This allows us +// to use API-related DS in the rest of the service code. +// +#include <rplsvc_s.h> // Generated by the MIDL complier + + +// +// Other defines +// + +#define DOUBLE_BACK_SLASH_STRING L"\\\\" + +// +// BITMASK to be used with Flags field in RPL_WKSTA data structure +// +#define RPL_WKSTA_PERSONAL 0x01 + +#define MAX_ADAPTERS 12 // "rpl1" through "rpl12" + + +#define MIN_BBLOCK_BASE 0xc00 + +// +// All BBC files are very small, typically around 1K. +// Use 32K as the absolute maximum on BBC file size. +// +#define MAX_BBC_FILE_SIZE 0x8000 // for no compelling reason + +#define MAX_FIT_FILE_SIZE 0xF000 // some arbitrary value +#define MAX_SIZEOF_DBCS_PATH (PATHLEN *sizeof(WCHAR)+sizeof(CHAR)) + +#define SERVER_LINE_ID_LEN 12 + +#define DEFAULT_RETRY_COUNT 3 +#define DEFAULT_RETRY_TIMEOUT 10 +#define DEFAULT_WINDOW_SIZE MAXWORD +#define DEFAULT_SEND_FINAL_REQ FALSE + +#define MAX_XMIT_ERRORS 30 // max contiguous fatal xmit failures + +// +// status bits of main_action_status +// + +#define TERMINATE_SERVICE 1 +#define REINITIALIZE_SERVICE 2 +#define REINITIALIZATION_PENDING 4 +#define TERMINATION_PENDING 8 + +#define ERROR_HANDLING (DWORD)(-1) +#define NO_ERROR_HANDLING 0 +#define MAX_OPEN_RETRY 40 +#define MAX_OEM_NAME 7 + +// +// Constants of the actual ripl server +// + +#define RPL_DLL_SKELETON "rpl" +#define WORKER_THREAD_MIN 2 +#define MAX_FRAME_SIZE 0x1000 // exactly 1 page, or 4KB +#define MAX_SUB_SEGMENT_SIZE 0xffe0 +#define SEND_BUF_SEG_SIZE 17000 +// +// MAX_ADAPTER_INFO_SIZE is now defined to be the sum of upper size +// estimates for DLC buffer (0xA000) and private adapter info (2000). +// +#define MAX_ADAPTER_INFO_SIZE (0xA000 + 2000) + +#define LAN_ADAPTER0 0 +#define CHECK_SUM_ERROR 9676 +#define SF_REQ_TIMEOUT 7 //IBM waits 3s for lost frame & (ACK lost) +#define MAX_FILE_HANDLES_INC 20 // increment of max fhs +#define UNINSTALL_TIME 100 // 10 seconds, actually: (1 - 150) + +#define RPL_KEYBOARD_DCP L"KEYBOARD.DCP" +#define RIPL_CHECK_SUM L"rplchecksum" +#define RPLDIR_DEF L"rpldir" +#define RPL_DIR_1 L"rpl1" +#define YES L"yes" +#define RPL_LOGON_KBD L"rpllogonkbd" +#define LANMAN_INI L"lanman.ini" +#define RPL_REMARK L"Remoteboot service share" +#define RPLUSER_GROUP L"RPLUSER" + +// +// JETBUG entries are needed for workaround for JetMakeKey-JetSeek bug. +// If this bug gets ever fixed, they should be removed (undef RPL_JETBUG) +// +#define RPL_JETBUG +#ifdef RPL_JETBUG +#define JETBUG_STRING L" " +#define JETBUG_STRING_SIZE sizeof( JETBUG_STRING) +#define JETBUG_STRING_LENGTH ((DWORD)(sizeof( JETBUG_STRING)/sizeof(WCHAR) - 1)) +#else +#define JETBUG_STRING_LENGTH 0 +#endif + +// +// TIMEOUTS +// + +#define GET_SF_REQUEST_TIMEOUT 6000L // not error and quite common + +// implement this with fast retries +#define LONG_WAIT_ACK_TIMEOUT 30000L // wksta sent no resend requests! +#define WAIT_ACK_TIMEOUT 1000L // short wait for the lost frames + +#define MAX_ERR_COUNT 4 +#define MAX_RETRIES 5 // retry count before termination + +#define OFFSET_BUF_LEN 64 // space for the whole RPLBoot hdr + +/*++ + RPL service must send NLS (DBCS ??) messages in a layout expected by RPL client + (from rplboot\rplboot.asm): + + ;------------------------------------------------------------------------ + ; NLS messages structure - used in RPLOADR and DLCBOOT + ;------------------------------------------------------------------------ + nlsmsglen equ 80 ;max number of bytes per msg + nlsmsg struc + db nlsmsglen dup(' '); ;<space fill> + db 0dh ;<cr> + db 0ah ;<lr> + db '$' ;<terminator> + nlsmsg ends +--*/ + +#define DBCS_SINGLE_MESSAGE_BUFFER_SIZE 83 + +// +// Typedefs +// + +typedef struct _FLIST_TBL { + // + // UNICODE name. Used for work on the server. + // + LPWSTR FileName; + // + // Same file name but without path and in DBCS. Sent to client. + // + LPSTR DbcsFileName; + DWORD DbcsFileNameSize; + + // + // + // Size of memory needed for "param_list", not counting terminating null + // byte, is kept in FILE_DATA.param_len entry. + // + LPSTR param_list; // a DBCS string, UNICODE version not needed + LPWSTR path_name; + FILE_DATA FileData; // structure to be saved to dump_tbl +} FLIST_TBL, *PFLIST_TBL; + +typedef struct _CONFIG_TYPE { + LPWSTR id; + DWORD type; +} CONFIG_TYPE, *PCONFIG_TYPE; + +#define FIT_ALIAS_ARRAY_LENGTH 7 // poor initialization + +typedef struct _FIT_ALIAS { + LPWSTR Key; // keyword, or macro + LPWSTR Value; // replacement value for the keyword + DWORD KeyLength; // length of keyword, or macro + DWORD ValueLength; // length of replacement value for the keyword +} FIT_ALIAS, *PFIT_ALIAS; + + +// +// parameters sent to worker thread +// +// thread_id should be initialized somewhere via GetCurrentThreadId() +// + +struct _RPL_REQUEST_PARAMS; +typedef struct _RPL_REQUEST_PARAMS RPL_REQUEST_PARAMS, *PRPL_REQUEST_PARAMS; + +struct _RPL_WORKER_PARAMS; +typedef struct _RPL_WORKER_PARAMS RPL_WORKER_PARAMS, *PRPL_WORKER_PARAMS; + +typedef struct _RPL_REQUEST_PARAMS { + PRPL_REQUEST_PARAMS pRequestParams; // next in a queue of request threads + HANDLE ThreadHandle; + DWORD ThreadId; + PRPL_WORKER_PARAMS pWorkerParams; // first in a queue of worker threads + POPEN_INFO pOpenInfo; // generic rpl DLL info + PRCB FreeRcbList; // list of free rcb blocks + PRCB BusyRcbList; // list of reserved RCBs + BOOL Exiting; +} RPL_REQUEST_PARAMS , *PRPL_REQUEST_PARAMS; + +typedef struct _RPL_WORKER_PARAMS { // worker thread parameters + PRPL_WORKER_PARAMS pWorkerParams; // next in a queue of worker threads + HANDLE ThreadHandle; + DWORD ThreadId; + PRPL_REQUEST_PARAMS pRequestParams; + PRCB pRcb; + BOOL Exiting; +} RPL_WORKER_PARAMS, *PRPL_WORKER_PARAMS; + +typedef struct _RPL_WORKER_DATA { + // + // These are addresses of on the stack variables from the Request thread. + // + PPRCB pFreeRcbList; // base of free rcb list + PPRCB pBusyRcbList; // base of reserved rcbs + // + // The following three pointers are allocated via RG_MemoryHandle. + // Everything else in this data structure, including the structure itself + // is allocated via WORKER_DATA.MemoryHandle == WORKER_PARAMS.MemoryHandle. + // + PRCB pRcb; // resource control block + PRPL_REQUEST_PARAMS pRequestParams; // ptr to request threads parm block + POPEN_INFO pOpenInfo; // open info of the cur RPL DLL + // + // The following are the entries read from database. + // WkstaName & TcpIp* are sent to the client in wksta line. + // WkstaName & ProfileName are used to make changes in fit file. + // + WCHAR WkstaName[ RPL_MAX_WKSTA_NAME_LENGTH + 1]; + WCHAR ProfileName[ RPL_MAX_PROFILE_NAME_LENGTH + 1]; + DWORD TcpIpAddress; + DWORD TcpIpSubnet; + DWORD TcpIpGateway; + WCHAR LogonInput; + CHAR DisableDhcp; // '1' ('0') if DHCP is disabled (enabled) + DWORD WindowSize; + BOOL FinalAck; // SendFinalRequest; + + HANDLE MemoryHandle; // for worker thread + LPBYTE WkstaLine; // old style, RPL.MAP line + + // + // Fields describing the boot block configuration file. + // + LPWSTR BbcFile; // full path to BBC file + PFLIST_TBL flist_tbl; // files sent to RPLBOOT + BOOL MakePatch; // TRUE if patch to RPLBOOT.SYS is needed + DWORD PatchOffset; // relevant if MakePatch is TRUE + PRESOURCE_TBL resource_tbl; // file list given to the loader + PBYTE id_str; // id string of the server + DWORD min_wksta_buf; // min size of wksta specific data + DWORD file_block_base; // relative addr of file block in boot block + DWORD boot_block_base; // base phys addr of boot block + DWORD flist_tbl_len; + DWORD loader_i; // index of OS/2 loader in flist_tbl + DWORD rplboot_i; // index of rplboot.sys in file list + DWORD resource_tbl_size; // size of the table (in bytes) + LPWSTR LineBuffer; // used for parsing a line into words + DWORD LineBufferSize; // size of LineBuffer + LPWSTR * WordTable; // used for parsing a line into words + + // + // Fields describing the file index table file. + // + // In order to get full path to fit file we need to check wksta flags + // to find out profile type (personal or shared) then read the + // corresponding file path from profile record. + // + LPWSTR FitFile; // full path to FIT file + LPSTR ClientFit; // string with DBCS content of FIT file sent to client + DWORD ClientFitSize; // size of above string + FIT_ALIAS FitAliasArray[ FIT_ALIAS_ARRAY_LENGTH]; + + + // + // Fields initalized (wksta_buf also created) in RplMakeWkstaBuf() + // + // + // wksta_buf contains BOOT_DATA, old RPL.MAP workstation line, processed FIT file, + // BOOT_BLOCK_HDR and multiboot array. + // + // It does not contain files mentioned in boot block configuration file. + // + PBYTE wksta_buf; // ptr to wksta specific data + + // + // size of wksta_buf + // + DWORD wksta_buf_len; // size in bytes of wksta specific data + + // + // + // + DWORD base_address; // start address of buffer, first send + DWORD jump_address; // start address of program, last send + DWORD fblock_base_offset; // base offset (from 0) of file block + + DWORD send_buf_len; // length of network send buffer + + // + // The following group of fields is used while reading data from + // files mentioned in the boot block configuration file. These + // fields are initialized in RplOpenData() + // + + // + // "pDataBuffer" is used to read data from disk files, then to send this + // data to a remote client. + // + PBYTE pDataBuffer; // read data here, then send it out + DWORD cur_flist_i; // current index for FLIST_TBL array + DWORD cur_offset; // current offset of boot block + DWORD cur_file_base_offset; // base offset of the current file + BOOL is_end_of_bblock; // set if end of boot block + HANDLE hFile; // current file handle + // + // ChecksumBuffer - buffer used to checksum files, when checksums are needed. + // + PBYTE ChecksumBuffer; // used to checksum files when + DWORD EventId; + PWCHAR EventStrings[ 5]; // null terminated +} RPL_WORKER_DATA, *PRPL_WORKER_DATA; + + +#define NOTIFY_WKSTA_RECORD 0 // disabled wksta record for main thread to write to RPL.map + +typedef struct _ADMIN_ALERT_DATA{ + DWORD alrtad_errcode; + DWORD alrtad_numstrings; +} ADMIN_ALERT_DATA; + +typedef struct _ADAPTER_STATUS_BUFFER { + DWORD id_low; + DWORD id_mid; + DWORD id_high; + BYTE jumper_status; + BYTE self_test; + DWORD sw_version; + BYTE error_statistics[48]; + DWORD name_tbl_len; + BYTE name1[18]; + BYTE name2[18]; + BYTE name3[18]; + BYTE name4[18]; + BYTE name5[18]; + BYTE name6[18]; + BYTE name7[18]; + BYTE name8[18]; + BYTE name9[18]; + BYTE name10[18]; + BYTE name11[18]; + BYTE name12[18]; + BYTE name13[18]; + BYTE name14[18]; + BYTE name15[18]; + BYTE name16[18]; +} ADAPTER_STATUS_BUFFER; + +typedef enum {IMMEDIATE_ERROR, WAIT_RESOURCES} BLOCKTYPE; + +#ifdef UNICODE + +#define RPL_TO_UNICODE( arg) arg +#define RPL_FREE_UNICODE( arg) + +#else // UNICODE + +WCHAR * RplAsciizToUnicodez( IN CHAR * Asciiz); +VOID RplFreeUnicodez( IN WCHAR * Unicodez); +#define RPL_TO_UNICODE( arg) RplAsciizToUnicodez( arg) +#define RPL_FREE_UNICODE( arg) RplFreeUnicodez( arg) + +#endif // UNICODE + + +#define ALERT_LONG_WAIT 10000L // used to be in alert.h + +// +// Bitmask used with RG_Tasks. They describe outstanding tasks to be +// done by the main rpl service thread once it wakes up. +// + +#define RPL_SERVICE_SHUTDOWN 0x0004 + + +#define RPL_WAIT_HINT_TIME 15000L // 15 seconds for now + + + + +#define TMPFILES_IDX 4 +#define BINFILES_IDX 5 + + +// +// termination addresses of all rpl DLLs have been saved to this list +// + +typedef DWORD ( * TERMINATION_ADDRESS)( POPEN_INFO); + +typedef struct _TERM_LIST { + struct _TERM_LIST * next; + POPEN_INFO pOpenInfo; +} TERM_LIST, *PTERM_LIST; + + +#define INVALID_ERROR_PARAMETER ((DWORD)(-1)) // internal usage in api code + +typedef struct _RPL_SESSION { + JET_SESID SesId; // jet session identifier + JET_DBID DbId; // jet database identifier + JET_TABLEID AdapterTableId; + JET_TABLEID BootTableId; + JET_TABLEID ConfigTableId; + JET_TABLEID ProfileTableId; + JET_TABLEID ResumeTableId; + JET_TABLEID VendorTableId; + JET_TABLEID WkstaTableId; +} RPL_SESSION, *PRPL_SESSION; + + +// +// Function Prototypes +// + +// +// memory.c +// + +DWORD RplMemInit( PHANDLE pMemoryHandle); + +PVOID RplMemAlloc( + IN HANDLE MemoryHandle, + IN DWORD size + ); + +VOID RplMemFree( + IN HANDLE MemoryHandle, + IN PVOID mem_ptr + ); + +VOID RplMemClose( IN HANDLE MemoryHandle); + +PVOID RplMemReAlloc( + IN HANDLE MemoryHandle, + IN DWORD Flags, + IN PVOID old_ptr, + IN DWORD new_size + ); + + +// +// library.c +// + +LPWSTR RplGetLastPathComponent( IN LPWSTR FilePath); +HANDLE RplFileOpen( IN LPWSTR FilePath); + +LPWSTR RplReadTextFile( + IN HANDLE MemoryHandle, + IN LPWSTR FileName, + IN DWORD MaxFileSize + ); +DWORD RplUnicodeToDbcs( + IN HANDLE MemoryHandle, + IN LPWSTR UnicodeString, + IN INT UnicodeStringLength, + IN DWORD MaxDbcsStringSize, + OUT LPSTR * pDbcsString + ); + +// +// rplmain.c +// + +VOID RPL_main( + IN DWORD argc, + IN LPWSTR argv[] + ); +VOID RplInitError( + DWORD ErrorCode, + PCHAR ErrorIdString + ); +BOOL RplServiceAttemptStop( VOID); +DWORD RplUpdateStatus( VOID); + + +// +// Declare/Define all global variables. +// + +#include "rpldata.h" // defines/declares global data structures diff --git a/private/net/svcdlls/rpl/server/makefile b/private/net/svcdlls/rpl/server/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/net/svcdlls/rpl/server/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/net/svcdlls/rpl/server/memory.c b/private/net/svcdlls/rpl/server/memory.c new file mode 100644 index 000000000..15b9dc34a --- /dev/null +++ b/private/net/svcdlls/rpl/server/memory.c @@ -0,0 +1,188 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + memory.c + +Abstract: + + Memory management routines. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" + +#define DEFAULT_HEAP_INITIAL_SIZE (4*1024L) // 4K or one page, should be 0 ?? +#define DEFAULT_HEAP_MAXIMUM_SIZE (64*1024L) // upper limit taken from Init_submalloc, better value would be 0 ?? + + +DWORD RplMemInit( PHANDLE pMemoryHandle) +/*++ + +Routine Description: + Initializes memory management + +Arguments: + pMemoryHandle - pointer to memory handle, in PRIVATE case it means something, + in SHARED case it is just initialized to NULL + +Return Value: + ERROR_SUCCESS if success, else last error + +--*/ +{ + *pMemoryHandle = HeapCreate( + 0L, + 64 * 1024, // make it large due to shoddy code in Rtl routines + 0 // Let it grow without limit ! + ); + + if ( *pMemoryHandle == NULL) { + DWORD status = GetLastError(); + RplDump( ++RG_Assert,( "status=%d", status)); + return( status); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_MEMORY,( + "MemInit: HeapCreate => handle=0x%x", *pMemoryHandle)); + + return( ERROR_SUCCESS); +} + + + +PVOID RplMemAlloc( + IN HANDLE MemoryHandle, + IN DWORD size + ) +/*++ + +Routine Description: + Alocates memory object from a memory heap. Memory heap must have a valid handle. + +Arguments: + MemoryHandle - memory handle (relevant in PRIVATE case only) + size - size of memory object + +Return Value: + Pointer to newly allocated memory if successful, else NULL. + +--*/ +{ + PVOID ptr; + ptr = HeapAlloc( MemoryHandle, 0, size); + if ( ptr == NULL) { + RplDump( ++RG_Assert,( "Error=%d", GetLastError())); + } else { + RplDump( RG_DebugLevel & RPL_DEBUG_MEMALLOC,( + "MemAlloc( 0x%x, %d) => 0x%x", MemoryHandle, size, ptr)); + } + return( ptr); +} + + + +VOID RplMemFree( + HANDLE MemoryHandle, + PVOID pMemoryObject + ) +/*++ + +Routine Description: + Memory object must have been allocated via MemFree() or MemReAlloc(). + Memory object is freed. + +Arguments: + MemoryHandle - memory handle (relevant in PRIVATE case only) + pMemoryObject - pointer to memory object + +Return Value: + None. + +--*/ +{ + if ( !HeapFree( MemoryHandle, 0, pMemoryObject)) { + RplDump( ++RG_Assert,( "Error=%d", GetLastError())); + } else { + RplDump( RG_DebugLevel & RPL_DEBUG_MEMORY,( + "MemFree( 0x%x) <= 0x%x", MemoryHandle, pMemoryObject)); + } +} + + + +VOID RplMemClose( HANDLE MemoryHandle) +/*++ + +Routine Description: + Destroys the heap thus releasing all the memory allocated with this handle. + HeapDestroy() is BOOL, here we just hide dirt under the rug! + See more extensive comments under MemFree(). + +Arguments: + MemoryHandle - heap handle + +Return Value: + None. + +--*/ +{ + if ( !HeapDestroy( MemoryHandle)) { + RplDump( ++RG_Assert, ,( "Error=%d", GetLastError())); + } +} + + + +PVOID RplMemReAlloc( + IN HANDLE MemoryHandle, + IN DWORD Flags, + IN PVOID old_ptr, + IN DWORD new_size + ) +/*++ + +Routine Description: + + Reallocates data to a new size, preserving the content. + +Arguments: + + MemoryHandle - memory handle (relevant in PRIVATE case only) + old_ptr - pointer to memory object (before this call) + Flags - + new_size - desired new size of memory object + + +Return Value: + + If successful, returns pointer to memory object whose size is (at least) + equal to "new_size" and whose first MIN( old_size, new_size) bytes + are unchanged compared to corresponding bytes at "old_ptr". + + If unsuccessful, returns NULL. + +--*/ +{ + PVOID ptr; + ptr = HeapReAlloc( MemoryHandle, Flags, old_ptr, new_size); + if ( ptr == NULL) { + RplDump( ++RG_Assert,( "Error=%d", GetLastError())); + } else { + RplDump( RG_DebugLevel & RPL_DEBUG_MEMALLOC,( + "MemReAlloc( 0x%x, 0x%x, %d) => 0x%x", MemoryHandle, old_ptr, new_size, ptr)); + } + return( ptr); +} diff --git a/private/net/svcdlls/rpl/server/open.c b/private/net/svcdlls/rpl/server/open.c new file mode 100644 index 000000000..eb4b1c4e0 --- /dev/null +++ b/private/net/svcdlls/rpl/server/open.c @@ -0,0 +1,600 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + _open.c + +Abstract: + + Initializes workstation specific data structures and returns the handle. + + Provides similar functionality to rmapopen.c in LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "database.h" +#include "bbcfile.h" +#include "fitfile.h" +#include "open.h" + +// translates 32 bit physical address to 16-bit paragraphs +#define PHYS_TO_PARA( physaddr) ((WORD)((physaddr) >> 4)) + +#define MAX_WKSTA_PROFILES 10 // rplmgr supports now only 2! +#define PROF_DATA_SIZE (sizeof(MBOOTDATA)+80) // include comment size! +#define MAX_WKSTA_BUF ((DWORD)0xff00) + + + +DWORD FillString( OUT PCHAR Buffer, IN PCHAR String) +{ + strcpy( Buffer, String); + return( strlen( Buffer)); +} + + +BOOL RplCreateWkstaLine( + IN OUT PRPL_WORKER_DATA pWorkerData, + OUT PDWORD pWkstaLineSize + ) +/*++ + LANMAN 2.1 wksta record in RPL.MAP contained the following information: + + Field 1: AdapterId - NO + Field 2: WkstaName + Field 3: Username/Password prompting field. + Field 4: Fit file name. - NO + Field 5: Name of server used to access files for booting. - NO (DLC server) + Field 6: Shared or Personal profile. - NO + Field 7: '~' + Field 8: '~' + Field 9: '~' + Field 10: ',,,' + Field 11: '~' + Field 12: Tag of associated LANMAN 2.1 boot block configuration (server) record. - NO + Field 13: '~' (but see below) + Field 14: Name of associtated profile. - NO + Field 15: Descriptive comment. - NO + Field 16: Optional IP address of a workstation. + Field 17: Optional TCP/IP subnet mask. + Field 18: Optional TCP/IP gateway address. + + Out of the above, client side only needs Fields # 2, 3, 15, 16, 17 & 18. + All the other fields can be replaced with tildas. And of course if this + does not work we can always go back to the original wksta line & send him + all then cut back on the amount of info. + + All of these lines worked fine for VLADIMV7 client. Checked "dir c:", + logging as vladimv on Redmond, treeconnecting & dir on remote drives. + +#define RPLTEST_WKSTALINE "02608C1B87A5 VLADIMV7 N fits\\dos500 VLADIMV3 S ~ ~ ~ ,,, ~ RDOST ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~" +#define RPLTEST_WKSTALINE "~ VLADIMV7 N fits\\dos500 VLADIMV3 S ~ ~ ~ ,,, ~ RDOST ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~" +#define RPLTEST_WKSTALINE "~ VLADIMV7 N fits\\dos500 VLADIMV3 S ~ ~ ~ ,,, ~ ~ ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~" +#define RPLTEST_WKSTALINE "~ VLADIMV7 N ~ VLADIMV3 S ~ ~ ~ ,,, ~ ~ ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~" +#define RPLTEST_WKSTALINE "~ VLADIMV7 N ~ ~ S ~ ~ ~ ,,, ~ ~ ~ d5elnk2 VLADIMV1~=>~shared~dos~profile ~ ~ ~" +#define RPLTEST_WKSTALINE "~ VLADIMV7 N ~ ~ S ~ ~ ~ ,,, ~ ~ ~ d5elnk2 ~ ~ ~ ~" +#define RPLTEST_WKSTALINE "~ VLADIMV7 N ~ ~ ~ ~ ~ ~ ,,, ~ ~ ~ d5elnk2 ~ ~ ~ ~" +#define RPLTEST_WKSTALINE "~ VLADIMV7 N ~ ~ ~ ~ ~ ~ ,,, ~ ~ ~ ~ ~ ~ ~ ~" +#define RPLTEST_WKSTALINE "~ VLADIMV7 N ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~" +Field 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 + +More changes: + Client side software RPLBOOT.SYS has been changed to receive value for + TCPIP_NO_DHCP macro in Field 13 above. Sending value 1 will disable DHCP + on the client. Sending value 0 will enable DCHP on the client. But the + value of this field matters only if TCPIP is enabled for this client by + appropriate changes in boot block configuration file, config.sys and + autoexec.bat that this client uses. +--*/ +{ +#define BLANK_FIELD "~ " +#define COMMON_FIELD_LENGTH 2 // except for WkstaName & TcpIp strings +#define MAX_TCPIP_ADDRESS_LENGTH 15 + + CHAR Buffer[ 14 * COMMON_FIELD_LENGTH + MAX_COMPUTERNAME_LENGTH + 1 + + 3 * (MAX_TCPIP_ADDRESS_LENGTH + 1) + 1]; + DWORD Length; + DWORD ByteCount; + DWORD Index; + + // + // Field 1: + // + Length = FillString( Buffer, BLANK_FIELD); + + // + // Field 2: + // + ByteCount = WideCharToMultiByte( // this counts the terminal null byte + CP_OEMCP, + 0, + pWorkerData->WkstaName, + -1, // WkstaName is null terminated + Buffer + Length, // output buffer + MAX_COMPUTERNAME_LENGTH + 1, // output buffer size + NULL, // no default character + NULL // no default character flag + ); + if ( ByteCount == 0) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaInternal; + return( FALSE); + } + Length += ByteCount - 1; + Buffer[ Length++] = ' '; + + // + // Field 3: + // + Buffer[ Length++] = (char)pWorkerData->LogonInput; + Buffer[ Length++] = ' '; + + // + // Fields 4-12: + // + for ( Index = 4; Index <= 12; Index++) { + Length += FillString( Buffer + Length, BLANK_FIELD); + } + + // + // Field 13: + // + Buffer[ Length++] = pWorkerData->DisableDhcp; + Buffer[ Length++] = ' '; + + // + // Fields 14-15: + // + for ( Index = 14; Index <= 15; Index++) { + Length += FillString( Buffer + Length, BLANK_FIELD); + } + + Length += FillTcpIpString( Buffer + Length, pWorkerData->TcpIpAddress); + Length += FillTcpIpString( Buffer + Length, pWorkerData->TcpIpSubnet); + Length += FillTcpIpString( Buffer + Length, pWorkerData->TcpIpGateway); + + Buffer[ --Length] = 0; // overwrite last space + +//#define RPL_ELNK +#ifdef RPL_ELNK + if ( !wcscmp( pWorkerData->pRcb->AdapterName, L"02608C0A9B37")) { + strcpy( Buffer, "02608C0A9B37 ELNK N fits\\dos500 VLADIMV3 S ~ ~ ~ ,,, ~ RDOSL ~ DOS500L ~ ~ ~ ~ "); + Length = strlen( Buffer); + } +#endif + + pWorkerData->WkstaLine = RplMemAlloc( pWorkerData->MemoryHandle, Length + 1); + if ( pWorkerData->WkstaLine == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + memcpy( pWorkerData->WkstaLine, Buffer, Length + 1); + *pWkstaLineSize = Length + 1; + return( TRUE); +} + + +BOOL RplMakeWkstaBuf( IN OUT PRPL_WORKER_DATA pWorkerData) +/*++ + +Routine Description: + + Procedure allocates and initializes bblock header and wksta specific + data. pWorkerData->wksta_buf will be set to point to this buffer. + + Procedure: + - allocates and shrinks the file index table + - setup the boot block header and saves its static parameters + - makes the file list table and saves the parameters of DOS EXE/SYS/COMs + - builds the boot data for RPL MFSD + - fixes up the 32 bits physical boot block base and file block base addr + - copies and binds the resource table to the memory + - binds the files in the files list to the PC memory + +Arguments: + +Return Value: + TRUE if successful. + FALSE if unsuccessful (then we usually set termination event also). + +--*/ +{ + DWORD index; + PBOOT_DATA pBootData; // ptr to boot data structure used by RPL MFSD + PRESOURCE_TBL resource_tbl; // OS2LDR parameters + PBOOT_BLOCK_HDR pBBH; // ptr to boot block header + DWORD wbuf_i; // running offset from boot block header + PBYTE pBuf; // a misc string + DWORD resource_tbl_len; // + DWORD WkstaLineSize; // for old style rpl.map wksta line + PBYTE wksta_buf; // space for the wksta specific data + DWORD wksta_buf_len; // length of wksta specific data + DWORD offData; + DWORD cbBootDataSize; + // + // boot_block_base is offset to the boottom of the lowest file in memory + // + DWORD boot_block_base = pWorkerData->boot_block_base; + DWORD file_block_base = pWorkerData->file_block_base; + PFLIST_TBL pFlistTbl = pWorkerData->flist_tbl; + DWORD lenFlistTbl = pWorkerData->flist_tbl_len; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++MakeWkstaBuf(0x%x", pWorkerData)); + + if ( !RplFitFile( pWorkerData)) { + return( FALSE); + } + + // + // Clients still expect old style (rpl.map) wksta line. + // + if ( !RplCreateWkstaLine( pWorkerData, &WkstaLineSize)) { + return( FALSE); + } + + cbBootDataSize = + sizeof(BOOT_DATA) + // size of RPL MiniFSD parameters + WkstaLineSize + // wksta record size, DBCS data + pWorkerData->ClientFitSize + // FIT file image size, DBCS data +#ifdef RPL_ELNK +#define RPL_ELNK_7_SPACES " " + sizeof( RPL_ELNK_7_SPACES) + // Pad with spaces after wksta line. + 1 + // Include 0x1A at the end of fit file. +#endif + RG_CodePageSize; // code page size + + wksta_buf_len = + cbBootDataSize + + pWorkerData->min_wksta_buf + + sizeof(BOOT_BLOCK_HDR) + // size of standard header structure + PATHLEN + 1 + // space for UNC name of DOS FAT hdr + MAX_WKSTA_PROFILES * PROF_DATA_SIZE; // max size of multiboot data + + + if ( wksta_buf_len > MAX_WKSTA_BUF) { + RplDump( ++RG_Assert, ( "wksta_buf_len=%d", wksta_buf_len)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventId = NELOG_Files_Dont_Fit; + return( FALSE); + } + + // + // allocate wksta specific data, set the header base pointer and + // the base offset of dynamic data (wbuf_i) + // + + // DbgUserBreakPoint(); // for debugging + + pBBH = RplMemAlloc( pWorkerData->MemoryHandle, wksta_buf_len ); + if( pBBH == NULL) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaMemory; + return( FALSE); + } + + wksta_buf = (PBYTE)pBBH; + memset( wksta_buf, 0, wksta_buf_len); + wbuf_i = sizeof(BOOT_BLOCK_HDR) + (lenFlistTbl - 1) * sizeof(FILE_DATA); + // + // "id_stamp" is the first byte of boot block sent to the client + // + pBBH->id_stamp = 0x18cd; // reboot with int 18, if called + pBBH->usInfoLevel = 1; // version number of boot block + pBBH->file_list_len = (BYTE)lenFlistTbl; + + // + // Copy the file names and parameters of the files in the boot block. + // + + for ( index = 0; index < lenFlistTbl; index++) { + + pBBH->aFileData[ index] = pFlistTbl[ index].FileData; + // + // Copy the file names that were saved in pFlistTbl element. + // + pBBH->aFileData[ index].name_offset = (WORD)wbuf_i; + + memcpy( wksta_buf + wbuf_i, pFlistTbl[ index].DbcsFileName, pFlistTbl[ index].DbcsFileNameSize); + wbuf_i += pFlistTbl[ index].DbcsFileNameSize; + + // Copy data from Boot Block Configuration file. + + pBBH->aFileData[ index].param_offset = (WORD)wbuf_i; + + // + // exe/com/sys files must have MS-DOS parameter format + // + if ((pFlistTbl[ index].FileData.file_type & OTHER_FILES_MASK) == 0) { + // + // Get length of EXE/SYS/COM DOS parameters. + // + BYTE length = pFlistTbl[ index].FileData.param_len; + + if ( length) { + wksta_buf[ wbuf_i++] = (BYTE)( length + 1); + wksta_buf[ wbuf_i++] = ' '; // space before params + memcpy( wksta_buf + wbuf_i, pFlistTbl[ index].param_list, length); + wbuf_i += length; + wksta_buf[ wbuf_i++] = 0xD; + wksta_buf[ wbuf_i++] = 0xA; + wksta_buf[ wbuf_i++] = 0; // null terminated + pBBH->aFileData[ index].param_len = (BYTE)( length + 4); + } else { + wksta_buf[ wbuf_i++] = 0; + if ( pFlistTbl[ index].FileData.file_type & IS_EXECUTABLE_FILE) { + // + // For device drivers with no parameters, the parameter + // line is terminated by 0xA not 0xD,0xA + // BUGBUG Should param_len for them below be 2 instead of 3 ? + // + wksta_buf[ wbuf_i++] = 0xD; + } + wksta_buf[ wbuf_i++] = 0xA; + wksta_buf[ wbuf_i++] = 0; // null terminated + pBBH->aFileData[ index].param_len = 3; + } + } + } + + // + // Set up the resource table. Here we copy data that describes the + // loader line in Boot Block Configuration file. + // + resource_tbl = (PRESOURCE_TBL)(wksta_buf + wbuf_i); + pBBH->offResourceTbl = (WORD)wbuf_i; + pBBH->cbResourceTbl = (WORD)pWorkerData->resource_tbl_size; + wbuf_i += pWorkerData->resource_tbl_size; + memcpy( resource_tbl, pWorkerData->resource_tbl, pWorkerData->resource_tbl_size); + + // + // Round up the boot data offset (resource table format requires it). + // + wbuf_i = (wbuf_i + 15) & 0xfff0; + pBBH->offBootData = (WORD)wbuf_i; + pBootData = (PBOOT_DATA)(wksta_buf + wbuf_i); + pBootData->cbSize = (WORD)cbBootDataSize; // alignment OK + pBuf = wksta_buf + wbuf_i; + + // offData will be used to walk & copy data structures mentioned + // in cbBootDataSize formula above. + + offData = sizeof( BOOT_DATA); // initialize + + // + // Copy the wksta record line from RPL.map (dbcs string). + // + strcpy( pBuf + offData, pWorkerData->WkstaLine); + + pBootData->offWkstaLine = (WORD)offData; + pBootData->cbWkstaLine = (WORD)WkstaLineSize; + pBBH->offRplWkstaLine = (WORD)(wbuf_i + offData); + offData += WkstaLineSize; + +#ifdef RPL_ELNK + // + // Pad with spaces after wksta line. + // + memcpy( pBuf + offData, RPL_ELNK_7_SPACES, sizeof( RPL_ELNK_7_SPACES)); + offData += sizeof( RPL_ELNK_7_SPACES); + pBootData->cbWkstaLine += sizeof( RPL_ELNK_7_SPACES); +#endif + + // Copy the FIT file image. + + memcpy( pBuf + offData, pWorkerData->ClientFit, pWorkerData->ClientFitSize); + pBootData->offFit = (WORD)offData; + pBootData->cbFit = (WORD)pWorkerData->ClientFitSize; + offData += pWorkerData->ClientFitSize; +#ifdef RPL_ELNK + // + // Append 0x1A at the end of fit file. + // + *( pBuf + offData - 1) = 0x1A; + *( pBuf + offData) = 0; + offData++; + pBootData->cbFit++; +#endif + + // Copy the code page. + + memcpy( pBuf + offData, RG_CodePageBuffer, RG_CodePageSize); + pBootData->cbCodePage = (WORD)RG_CodePageSize; + pBootData->offCodePage = (WORD)offData; + + wbuf_i += cbBootDataSize; + pBBH->offMBootData = (WORD)wbuf_i; + + // + // Send no multiboot data - i.e. send NULL multiboot data by setting the + // size field of the first record to zero. + +#ifdef RPL_ELNK + if ( !wcscmp( pWorkerData->pRcb->AdapterName, L"02608C0A9B37")) { + MBOOTDATA UNALIGNED * pMbootData = (wksta_buf + wbuf_i); + pMbootData->cbSize = 0x2a; + strcpy( pMbootData->achProfile, "DOS500L"); + strcpy( pMbootData->achProfileComment, "DOS 5.00 3Com Etherlink"); + wbuf_i += 0x2a; + wbuf_i++; // or RPLBOOT.SYS would begin at 24e + } else { + *(WORD UNALIGNED *)(wksta_buf + wbuf_i) = 0; + wbuf_i += sizeof(WORD); + } +#else + *(WORD UNALIGNED *)(wksta_buf + wbuf_i) = 0; + wbuf_i += sizeof(WORD); +#endif + + + // + // DON'T SAVE ANY MORE DATA TO WKSTA BUFFER, WE MAY BE OUT OF MEMORY + // (do it before RplBuildMultiBootData) + // + + // + // Set up the final size. + // + wksta_buf_len = (wbuf_i + 15) & 0xfff0; + pBBH->cbSize = (WORD)wksta_buf_len; + + // + // FIX UP AND CHECK THE BOOT BLOCK TO THE WORKSTATION MEMORY !!! + // get the base address of the file list and boot block + // + + if ( file_block_base == 0) { + + // no ORG type line in BB.CFG file + + if (boot_block_base == 0) { + + // no BASE type line in BB.CFG file + + boot_block_base = MIN_BBLOCK_BASE; + } + file_block_base = boot_block_base + wksta_buf_len; + + } else if (boot_block_base == 0) { + + boot_block_base = file_block_base - wksta_buf_len; + } + + // Verify that the boot block is valid: + // - there must be space for wksta specific data in the boot block + // - boot block base must be above or equal the minimum value + + if ( file_block_base < boot_block_base + wksta_buf_len + || boot_block_base < MIN_BBLOCK_BASE) { + RplDump( ++RG_Assert, ( + "file_block_base=%d boot_block_base=%d wksta_buf_len=%d", + file_block_base, boot_block_base, wksta_buf_len)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = pWorkerData->BbcFile; + pWorkerData->EventId = NELOG_Files_Dont_Fit; + return( FALSE); + } + + // + // Get the resource table pointer (table is in wksta specific data), + // decrement length, because BootData is not included + + if ( pWorkerData->loader_i != INVALID_FILE_OFFSET) { + + // locate segments of resource table + + resource_tbl_len = resource_tbl->entries - 1; + for ( index = 0; index < resource_tbl_len; index++) { + + resource_tbl->file_tbl[ index].pos_in_paras + += PHYS_TO_PARA( file_block_base); + } + + // the boot data must be in the resource table, + + resource_tbl->file_tbl[ index].pos_in_paras + = PHYS_TO_PARA( boot_block_base + pBBH->offBootData); + resource_tbl->file_tbl[ index].file_len = cbBootDataSize; + } + + // locate the boot block files to the PC memory + + for ( index = 0; index < lenFlistTbl; index++) { + pBBH->aFileData[ index].file_addr += file_block_base; + } + + // + // Do not bother to reallocate wksta_buf to its new smaller size. + // This would be a waste of time since wksta_buf will be freed + // when we are done with booting this client. + // + + pWorkerData->wksta_buf = wksta_buf; + pWorkerData->wksta_buf_len = (WORD)wksta_buf_len; + + // + // get file block base offset relative from the base of the boot block + // + + pWorkerData->fblock_base_offset = file_block_base - boot_block_base; + + pWorkerData->base_address = boot_block_base; + pWorkerData->jump_address = pBBH->aFileData[pWorkerData->rplboot_i].file_addr; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--MakeWkstaBuf(0x%x", pWorkerData)); + return( TRUE); + +} // RplMakeWkstaBuf + + + +BOOL RplOpenData( IN OUT PRPL_WORKER_DATA pWorkerData) +/*++ + +Routine Description: + Opens rpl.map data for reading by a workstation thread. + +Arguments: + pWorkerData - worker data + +Return Value: + TRUE if success, else FALSE. + +--*/ +{ + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++OpenData(0x%x", pWorkerData)); + + // + // Retrive wksta database info. + // + if ( !RplWorkerFillWksta( pWorkerData)) { + if ( pWorkerData->EventId == NO_ERROR) { + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NERR_RplWkstaInfoCorrupted; + } + return( FALSE); + } + + // + // Process boot block configuration file. + // + if ( !RplBbcFile( pWorkerData)) { + return( FALSE); + } + + // + // Make wksta specific data buffer. + // + if ( !RplMakeWkstaBuf( pWorkerData)) { + return( FALSE); + } + + // + // Initialize file list table (includes all downloaded files) + // + + pWorkerData->pDataBuffer = NULL; + pWorkerData->cur_flist_i = 0; + pWorkerData->cur_offset = INVALID_FILE_OFFSET; + pWorkerData->cur_file_base_offset = INVALID_FILE_OFFSET; + pWorkerData->is_end_of_bblock = FALSE; + pWorkerData->hFile = INVALID_HANDLE_VALUE; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--OpenData(0x%x", pWorkerData)); + return( TRUE); +} diff --git a/private/net/svcdlls/rpl/server/open.h b/private/net/svcdlls/rpl/server/open.h new file mode 100644 index 000000000..f9cd7e545 --- /dev/null +++ b/private/net/svcdlls/rpl/server/open.h @@ -0,0 +1,27 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + open.h + +Abstract: + + Exports from open.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +BOOL RplOpenData( IN OUT PRPL_WORKER_DATA pWorkerData); + + diff --git a/private/net/svcdlls/rpl/server/profile.c b/private/net/svcdlls/rpl/server/profile.c new file mode 100644 index 000000000..7cc782f29 --- /dev/null +++ b/private/net/svcdlls/rpl/server/profile.c @@ -0,0 +1,1139 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + profile.c + +Abstract: + + Profile APIs. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "db.h" +#include "dblib.h" +#include "config.h" +#include "wksta.h" +#define RPLPROFILE_ALLOCATE +#include "profile.h" +#undef RPLPROFILE_ALLOCATE + +#define PROFILE_FLAGS_DISK_PRESENT_TRUE ((DWORD)0x00000001) +#define PROFILE_FLAGS_DISK_PRESENT_FALSE ((DWORD)0x00000002) +#define PROFILE_FLAGS_MASK_DISK_PRESENT \ + ( PROFILE_FLAGS_DISK_PRESENT_FALSE | \ + PROFILE_FLAGS_DISK_PRESENT_TRUE ) + + + +DWORD ProfileGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + IN OUT LPINT pSpaceLeft + ) +{ + BYTE LocalBuffer[ 300]; + PBYTE Buffer; + DWORD DataSize; + DWORD BufferSize; + JET_ERR JetError; + + switch( FieldIndex) { + case PROFILE_Flags: + Buffer = (PBYTE)pData; + BufferSize = sizeof( DWORD); + break; + default: + Buffer = LocalBuffer; + BufferSize = sizeof( LocalBuffer); + break; + } + JetError = JetRetrieveColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ FieldIndex].ColumnId, Buffer, + BufferSize, &DataSize, 0, NULL); + if ( JetError < 0) { + RplDump( ++RG_Assert, ( "JetError=%d", JetError)); + return( NERR_RplProfileInfoCorrupted); + } + if ( Buffer != LocalBuffer) { + if ( BufferSize == DataSize) { + return( NO_ERROR); + } else { + RplDump( ++RG_Assert, ("Bad DataSize=0x%x", DataSize)); + return( NERR_RplProfileInfoCorrupted); + } + } + // + // We have done with fixed data. From here on we deal with unicode + // strings only. + // + if ( DataSize > sizeof( LocalBuffer)) { + RplDump( ++RG_Assert, ( "Too big DataSize=0x%x", DataSize)); + return( NERR_RplProfileInfoCorrupted); + } + if ( DataSize == 0) { + if ( JetError != JET_wrnColumnNull) { + RplDump( ++RG_Assert, ( "JetError=%d", JetError)); + return( NERR_RplProfileInfoCorrupted); + } else { + *pData = NULL; // so RPC rpcrt4!_tree_size_ndr() does not bomb here + return( NO_ERROR); + } + } + if ( DataSize & 1 != 0 || wcslen((PWCHAR)LocalBuffer) + 1 != DataSize/2) { + RplDump( ++RG_Assert, ("LocalBuffer=0x%x, DataSize=0x%x", LocalBuffer, DataSize)); + return( NERR_RplProfileInfoCorrupted); + } + *pData = MIDL_user_allocate( DataSize); + if ( *pData == NULL) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + return( ERROR_NOT_ENOUGH_MEMORY); + } + memcpy( *pData, LocalBuffer, DataSize); + *pSpaceLeft -= DataSize; + return( NO_ERROR); +} + + +DWORD ProfileGetInfo( + IN PRPL_SESSION pSession, + IN LPWSTR ProfileName, + IN DWORD Level, + OUT LPVOID Buffer, + OUT PINT pSpaceLeft + ) +{ + DWORD Error; + LPRPL_PROFILE_INFO_2 Info = Buffer; + + switch( Level) { + case 2: + Error = ProfileGetField( pSession, PROFILE_FitPersonal, &Info->FitPersonal, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ProfileGetField( pSession, PROFILE_FitShared, &Info->FitShared, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ProfileGetField( pSession, PROFILE_BootName, &Info->BootName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = ProfileGetField( pSession, PROFILE_ConfigName, &Info->ConfigName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 1: + Error = ProfileGetField( pSession, PROFILE_Flags, (LPVOID *)&Info->Flags, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 0: + Error = ProfileGetField( pSession, PROFILE_ProfileComment, &Info->ProfileComment, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + if ( ProfileName == NULL) { + Error = ProfileGetField( pSession, PROFILE_ProfileName, &Info->ProfileName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + } else { + DWORD DataSize = (wcslen( ProfileName) + 1) * sizeof(WCHAR); + Info->ProfileName = MIDL_user_allocate( DataSize); + if ( Info->ProfileName == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_PROFILE, ( "ProfileName=0x%x", Info->ProfileName)); + memcpy( Info->ProfileName, ProfileName, DataSize); + *pSpaceLeft -= DataSize; + } + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + return( NO_ERROR); +} + + + +VOID ProfileGetInfoCleanup( + IN DWORD Level, + IN OUT LPVOID Buffer + ) +{ + LPRPL_PROFILE_INFO_2 Info = Buffer; + + if ( Info == NULL) { + return; + } + switch( Level) { + case 2: + if ( Info->FitPersonal != NULL) { + MIDL_user_free( Info->FitPersonal); + } + if ( Info->FitShared != NULL) { + MIDL_user_free( Info->FitShared); + } + if ( Info->BootName != NULL) { + MIDL_user_free( Info->BootName); + } + if ( Info->ConfigName != NULL) { + MIDL_user_free( Info->ConfigName); + } + NOTHING; // fall through + case 1: + NOTHING; // fall through + case 0: + if ( Info->ProfileComment != NULL) { + MIDL_user_free( Info->ProfileComment); + } + if ( Info->ProfileName != NULL) { + MIDL_user_free( Info->ProfileName); + } + break; + } +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileEnum( + IN RPL_HANDLE ServerHandle, + IN LPWSTR AdapterName, + IN OUT LPRPL_PROFILE_ENUM ProfileEnum, + IN DWORD PrefMaxLength, + OUT LPDWORD TotalEntries, + IN OUT LPDWORD pResumeHandle OPTIONAL + ) +/*++ + For more extensive comments see related code in NetrConfigEnum. +--*/ +{ + LPBYTE Buffer; + DWORD TypicalSize; + DWORD CoreSize; + DWORD Error; + INT SpaceLeft; + DWORD ArrayLength; + DWORD EntriesRead; + BOOL InfoError; + BOOL TableEnd; + RPL_FILTER Filter; + PRPL_FILTER pFilter; + PRPL_SESSION pSession = &RG_ApiSession; + + switch( ProfileEnum->Level) { + case 2: + TypicalSize = CoreSize = sizeof( RPL_PROFILE_INFO_2); + TypicalSize += 20 * sizeof( WCHAR); // typical size of FitPersonal + TypicalSize += 20 * sizeof( WCHAR); // typical size of FitShared + TypicalSize += 8 * sizeof( WCHAR); // typical size of BootName + TypicalSize += 8 * sizeof( WCHAR); // typical size of ConfigName + NOTHING; // fall through + case 1: + if ( ProfileEnum->Level == 1) { + TypicalSize = CoreSize = sizeof( RPL_PROFILE_INFO_1); + } + NOTHING; // fall through + case 0: + if ( ProfileEnum->Level == 0) { + TypicalSize = CoreSize = sizeof( RPL_PROFILE_INFO_0); + } + TypicalSize += 20 * sizeof( WCHAR); // typical size of ProfileComment + TypicalSize += 8 * sizeof( WCHAR); // typical size of ProfileName + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( AdapterName != NULL) { + pFilter = &Filter; + if ( !ValidHexName( AdapterName, RPL_ADAPTER_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + AdapterName[ 6] = 0; // truncate all but first 6 digits + pFilter->VendorId = wcstoul( AdapterName, NULL, 16); + pFilter->FindFirst = TRUE; + } else { + pFilter = NULL; + } + + if ( PrefMaxLength == -1) { + SpaceLeft = DEFAULT_BUFFER_SIZE; + } else { + SpaceLeft = PrefMaxLength; + } + + ArrayLength = SpaceLeft / TypicalSize; + if ( ArrayLength == 0) { + ArrayLength = 1; // try to return at least one element + } + + Buffer = MIDL_user_allocate( ArrayLength * CoreSize); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_PROFILE, ( + "ProfileEnum: Buffer=0x%x, ArrayLength=0x%x", Buffer, ArrayLength)); + + ProfileEnum->ProfileInfo.Level0->Buffer = (LPRPL_PROFILE_INFO_0)Buffer; + + EntriesRead = 0; + InfoError = FALSE; + Error = NO_ERROR; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFilterFirst( pSession, PROFILE_TABLE_TAG, pFilter, pResumeHandle, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + for ( ; ; ) { + memset( Buffer, 0, CoreSize); // for cleanup to work properly + Error = ProfileGetInfo( pSession, NULL, ProfileEnum->Level, Buffer, &SpaceLeft); + if ( Error != NO_ERROR) { + InfoError = TRUE; // clean things up without holding crit sec + break; + } + EntriesRead++; + Buffer += CoreSize; + SpaceLeft -= CoreSize; + if ( !RplFilterNext( pSession, pSession->ProfileTableId, pFilter, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + if ( SpaceLeft <= 0) { + Error = ERROR_MORE_DATA; + break; + } + if ( EntriesRead >= ArrayLength) { + Error = ERROR_MORE_DATA; + break; + } + } +cleanup: + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + if ( InfoError == TRUE) { + ProfileGetInfoCleanup( ProfileEnum->Level, Buffer); + } + if ( Error == NO_ERROR) { + *TotalEntries = EntriesRead; + } else if ( Error == ERROR_MORE_DATA) { + *TotalEntries = EntriesRead * 2; // we cheat here + } else { + // + // Cleanup in case of "bad" errors. + // + while ( EntriesRead > 0) { + EntriesRead--; + Buffer -= CoreSize; + ProfileGetInfoCleanup( ProfileEnum->Level, Buffer); + } + MIDL_user_free( Buffer); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_PROFILE, ("ProfileEnum: EntriesRead = 0x%x", EntriesRead)); + + ProfileEnum->ProfileInfo.Level0->EntriesRead = EntriesRead; + if ( EntriesRead == 0) { + ProfileEnum->ProfileInfo.Level0->Buffer = NULL; + } + + if ( ARGUMENT_PRESENT( pResumeHandle)) { + if ( Error == ERROR_MORE_DATA && EntriesRead > 0) { + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + RplFilterSave( pSession, (DWORD)ServerHandle, pFilter, + ((LPRPL_PROFILE_INFO_0)(Buffer-CoreSize))->ProfileName, + pResumeHandle); + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + } else { + *pResumeHandle = 0; // resume from beginning + } + } + + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileGetInfo( + IN RPL_HANDLE ServerHandle, + IN LPWSTR ProfileName, + IN DWORD Level, + OUT LPRPL_PROFILE_INFO_STRUCT ProfileInfoStruct + ) +{ + DWORD Error; + LPBYTE Buffer; + INT SpaceLeft; + PRPL_SESSION pSession = &RG_ApiSession; + + _wcsupr( ProfileName); + + switch( Level) { + case 0: + Buffer = MIDL_user_allocate( sizeof( RPL_PROFILE_INFO_0)); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + memset( Buffer, 0, sizeof( RPL_PROFILE_INFO_0)); + ProfileInfoStruct->ProfileInfo0 = (LPRPL_PROFILE_INFO_0)Buffer; + break; + case 1: + Buffer = MIDL_user_allocate( sizeof( RPL_PROFILE_INFO_1)); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + memset( Buffer, 0, sizeof( RPL_PROFILE_INFO_1)); + ProfileInfoStruct->ProfileInfo1 = (LPRPL_PROFILE_INFO_1)Buffer; + break; + case 2: + Buffer = MIDL_user_allocate( sizeof( RPL_PROFILE_INFO_2)); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + memset( Buffer, 0, sizeof( RPL_PROFILE_INFO_2)); + ProfileInfoStruct->ProfileInfo2 = (LPRPL_PROFILE_INFO_2)Buffer; + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFind( pSession, PROFILE_TABLE_TAG, ProfileName)) { + Error = NERR_RplProfileNotFound; + } else { + Error = ProfileGetInfo( pSession, ProfileName, Level, Buffer, &SpaceLeft); + } + + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( Error != NO_ERROR) { + ProfileGetInfoCleanup( Level, Buffer); + switch( Level) { + case 0: + MIDL_user_free( Buffer); + ProfileInfoStruct->ProfileInfo0 = NULL; + break; + case 1: + MIDL_user_free( Buffer); + ProfileInfoStruct->ProfileInfo1 = NULL; + break; + } + } + return( Error); +} + + +DWORD ProfileSetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + IN LPVOID Data, + IN DWORD DataSize + ) +{ + CallM( JetSetColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ FieldIndex].ColumnId, Data, DataSize, 0, NULL)); + return( NO_ERROR); +} + + +DWORD ProfileSetInfo( + IN PRPL_SESSION pSession, + IN DWORD Level, + OUT LPVOID Buffer, + OUT LPDWORD pErrorParameter + ) +{ + LPRPL_PROFILE_INFO_2 Info = Buffer; + switch( Level) { + case 2: + if ( Info->FitPersonal != NULL) { + *pErrorParameter = PROFILE_FitPersonal; + CallM( JetSetColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ PROFILE_FitPersonal].ColumnId, + Info->FitPersonal, + ( wcslen( Info->FitPersonal) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->FitShared != NULL) { + *pErrorParameter = PROFILE_FitShared; + CallM( JetSetColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ PROFILE_FitShared].ColumnId, + Info->FitShared, + ( wcslen( Info->FitShared) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->BootName != NULL) { + *pErrorParameter = PROFILE_BootName; + CallM( JetSetColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ PROFILE_BootName].ColumnId, + Info->BootName, + ( wcslen( Info->BootName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->ConfigName != NULL) { + *pErrorParameter = PROFILE_ConfigName; + CallM( JetSetColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ PROFILE_ConfigName].ColumnId, + Info->ConfigName, + ( wcslen( Info->ConfigName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + NOTHING; // fall through + case 1: + if ( Info->Flags != 0) { + *pErrorParameter = PROFILE_Flags; + CallM( JetSetColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ PROFILE_Flags].ColumnId, + &Info->Flags, sizeof( Info->Flags), 0, NULL)); + } + NOTHING; // fall through + case 0: + if ( Info->ProfileComment != NULL) { + *pErrorParameter = PROFILE_ProfileComment; + CallM( JetSetColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ PROFILE_ProfileComment].ColumnId, + Info->ProfileComment, + ( wcslen( Info->ProfileComment) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->ProfileName != NULL) { + *pErrorParameter = PROFILE_ProfileName; + CallM( JetSetColumn( pSession->SesId, pSession->ProfileTableId, + ProfileTable[ PROFILE_ProfileName].ColumnId, + Info->ProfileName, + ( wcslen( Info->ProfileName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + break; + } + return( NO_ERROR); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileSetInfo( + IN RPL_HANDLE ServerHandle, + IN LPWSTR ProfileName, + IN DWORD Level, + IN LPRPL_PROFILE_INFO_STRUCT ProfileInfoStruct, + OUT LPDWORD pErrorParameter OPTIONAL + ) +/*++ + If parameter pointer is NULL, then we do not change such parameters. + If parameter non-pointer has a special value, then we do not change + such parameters. + + Some parameters cannot be changed for now. If caller deos not specify + a no-change value for such a parameter, we print a warning message & + pretend we received a no change value. +--*/ +{ + DWORD Error; + DWORD SpaceLeft; + DWORD ErrorParameter; + LPVOID Buffer; + LPRPL_PROFILE_INFO_2 Info; + PWCHAR ConfigName; + PRPL_SESSION pSession = &RG_ApiSession; + + ErrorParameter = INVALID_ERROR_PARAMETER; + ConfigName = NULL; + _wcsupr( ProfileName); + + Info = Buffer = ProfileInfoStruct->ProfileInfo2; + switch( Level) { + case 2: + if ( !ValidName( Info->FitPersonal, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = PROFILE_FitPersonal; + break; + } + if ( !ValidName( Info->FitShared, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = PROFILE_FitShared; + break; + } + if ( !ValidName( Info->BootName, RPL_MAX_BOOT_NAME_LENGTH, FALSE)) { + ErrorParameter = PROFILE_BootName; + break; + } + if ( Info->BootName != NULL) { + _wcsupr( Info->BootName); + } + if ( !ValidName( Info->ConfigName, RPL_MAX_CONFIG_NAME_LENGTH, FALSE)) { + ErrorParameter = PROFILE_ConfigName; + break; + } + if ( Info->ConfigName != NULL) { + _wcsupr( Info->ConfigName); + } + NOTHING; // fall through + case 1: + switch( Info->Flags) { + case PROFILE_FLAGS_DISK_PRESENT_TRUE: + case PROFILE_FLAGS_DISK_PRESENT_FALSE: + Info->Flags = 0; + NOTHING; // fall through + case 0: + break; + default: + ErrorParameter = PROFILE_Flags; + break; + } + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + break; + } + NOTHING; // fall through + case 0: + if ( RPL_STRING_TOO_LONG( Info->ProfileComment)) { + ErrorParameter = PROFILE_ProfileComment; + break; + } + if ( Info->ProfileName != NULL) { + _wcsupr( Info->ProfileName); + if ( wcscmp( Info->ProfileName, ProfileName)) { + RplDump( ++RG_Assert, ("Change of ProfileName not supported yet.")); + ErrorParameter = PROFILE_ProfileName; + break; + } + MIDL_user_free( Info->ProfileName); + Info->ProfileName = NULL; + } + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + return( ERROR_INVALID_PARAMETER); + } + ErrorParameter = 0; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFind( pSession, PROFILE_TABLE_TAG, ProfileName)) { + Error = NERR_RplProfileNotFound; + goto cleanup; + } + + if ( Info->ConfigName != NULL) { + Error = ProfileGetField( pSession, PROFILE_ConfigName, &ConfigName, &SpaceLeft); + if ( Error != NO_ERROR) { + goto cleanup; + } + if ( wcscmp( Info->ConfigName, ConfigName)) { + RplDump( ++RG_Assert, ("Change of ConfigName not supported yet.")); + ErrorParameter = PROFILE_ConfigName; + Error = ERROR_INVALID_PARAMETER; + goto cleanup; + } + MIDL_user_free( Info->ConfigName); + Info->ConfigName = NULL; + } + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->ProfileTableId, JET_prepReplace)); + + Error = ProfileSetInfo( pSession, Level, Buffer, &ErrorParameter); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + + ErrorParameter = 0; + CallJ( JetUpdate( pSession->SesId, pSession->ProfileTableId, NULL, 0, NULL)); + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( ConfigName != NULL) { + MIDL_user_free( ConfigName); + } + if ( Error != ERROR_SUCCESS) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + } + return( Error); +} + + +DWORD AddFileExtension( + IN PWCHAR * pFilePath, + IN PWCHAR FileExtension, + IN BOOLEAN ExtensionOK + ) +{ +#define DOT_CHAR L'.' +#define BACK_SLASH_CHAR L'\\' + PWCHAR FilePathEx; + PWCHAR pDot; + DWORD Length; + + if ( *pFilePath == NULL) { + RPL_RETURN( NERR_RplConfigInfoCorrupted); + } + + pDot = wcsrchr( *pFilePath, DOT_CHAR); + if ( pDot != NULL) { + // + // Found a DOT. FilePath may have an extension. + // + if ( wcschr( pDot, BACK_SLASH_CHAR) == NULL) { + // + // There is no backslash after the DOT. FilePath has an + // extension. Return error if caller insists that file + // should have no extension. + // + if ( !ExtensionOK) { + RPL_RETURN( NERR_RplConfigInfoCorrupted); + } + return( NO_ERROR); + } + } + Length = wcslen( *pFilePath) + wcslen( FileExtension); + FilePathEx = MIDL_user_allocate( (Length + 1) * sizeof(WCHAR)); + if ( FilePathEx == NULL) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + return( ERROR_NOT_ENOUGH_MEMORY); + } + wcscpy( FilePathEx, *pFilePath); + wcscat( FilePathEx, FileExtension); + MIDL_user_free( *pFilePath); + *pFilePath = FilePathEx; + return( NO_ERROR); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD Level, + OUT LPRPL_PROFILE_INFO_STRUCT ProfileInfoStruct, + OUT LPDWORD pErrorParameter OPTIONAL + ) +{ + LPRPL_PROFILE_INFO_2 Info; + LPVOID Buffer; + DWORD Error; + DWORD ErrorParameter; + DWORD DataSize; + BOOL FreeBootName = FALSE; + BOOL FreeFitShared = FALSE; + BOOL FreeFitPersonal = FALSE; + PWCHAR DirName = NULL; + PWCHAR DirName2 = NULL; + PWCHAR DirName3 = NULL; + PWCHAR DirName4 = NULL; + JET_ERR JetError; + BOOL DiskDelete = FALSE; + PRPL_SESSION pSession = &RG_ApiSession; + + ErrorParameter = INVALID_ERROR_PARAMETER; + Buffer = Info = ProfileInfoStruct->ProfileInfo2; + switch( Level) { + case 2: + if ( !ValidName( Info->FitPersonal, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = PROFILE_FitPersonal; + break; + } + if ( !ValidName( Info->FitShared, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = PROFILE_FitShared; + break; + } + if ( !ValidName( Info->BootName, RPL_MAX_BOOT_NAME_LENGTH, FALSE)) { + ErrorParameter = PROFILE_BootName; + break; + } + if ( Info->BootName != NULL) { + _wcsupr( Info->BootName); + } + if ( !ValidName( Info->ConfigName, RPL_MAX_CONFIG_NAME_LENGTH, TRUE)) { + ErrorParameter = PROFILE_ConfigName; + break; + } + _wcsupr( Info->ConfigName); + if ( Info->Flags != 0) { + ErrorParameter = PROFILE_Flags; + break; + } + if ( RPL_STRING_TOO_LONG( Info->ProfileComment)) { + ErrorParameter = PROFILE_ProfileComment; + break; + } + if ( !ValidName( Info->ProfileName, RPL_MAX_PROFILE_NAME_LENGTH, TRUE)) { + ErrorParameter = PROFILE_ProfileName; + break; + } + _wcsupr( Info->ProfileName); + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + return( ERROR_INVALID_PARAMETER); + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFind( pSession, CONFIG_TABLE_TAG, Info->ConfigName)) { + Error = NERR_RplConfigNotFound; + goto cleanup; + } + // BUGBUG Should make sure CONFIG is enabled + if ( Info->BootName == NULL) { + Error = ConfigGetField( pSession, CONFIG_BootName, &Info->BootName, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + FreeBootName = TRUE; + } + if ( Info->FitShared == NULL) { + Error = ConfigGetField( pSession, CONFIG_FitShared, &Info->FitShared, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + FreeFitShared = TRUE; + Error = AddFileExtension( &Info->FitShared, L".FIT", TRUE); + if ( Error != NO_ERROR) { + goto cleanup; + } + } + if ( Info->FitPersonal == NULL) { + Error = ConfigGetField( pSession, CONFIG_FitPersonal, &Info->FitPersonal, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + FreeFitPersonal = TRUE; + Error = AddFileExtension( &Info->FitPersonal, L".FIT", TRUE); + if ( Error != NO_ERROR) { + goto cleanup; + } + } + Error = ConfigGetField( pSession, CONFIG_DirName, &DirName, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + Error = ConfigGetField( pSession, CONFIG_DirName2, &DirName2, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + Error = ConfigGetField( pSession, CONFIG_DirName3, &DirName3, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + Error = ConfigGetField( pSession, CONFIG_DirName4, &DirName4, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + // + // The call to ProfileSetInfo() will add PROFILE record to the database. + // The call may succeed but we may still fail to do the treecopy + // operations below. We can detect this situation any time later on + // by the value of the Flags bit. + // + Info->Flags = PROFILE_FLAGS_DISK_PRESENT_FALSE; + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->ProfileTableId, JET_prepInsert)); + + Error = ProfileSetInfo( pSession, 2, Buffer, &ErrorParameter); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + ErrorParameter = 0; + JetError = JetUpdate( pSession->SesId, pSession->ProfileTableId, NULL, 0, NULL); + if ( JetError < 0) { + if ( JetError == JET_errKeyDuplicate) { + Error = NERR_RplProfileNameUnavailable; + } else { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + Error = NERR_RplInternal; + } + goto cleanup; + } + + DiskDelete = TRUE; // just in case we fail before we are done + Error = ProfileDiskAdd( TRUE, Info->ProfileName, DirName, DirName2, + DirName3, DirName4); + if ( Error != NO_ERROR) { + goto cleanup; + } + if ( !RplFind( pSession, PROFILE_TABLE_TAG, Info->ProfileName)) { + Error = NERR_RplInternal; + goto cleanup; + } + CallJ( JetPrepareUpdate( pSession->SesId, pSession->ProfileTableId, JET_prepReplace)); + Info->Flags = PROFILE_FLAGS_DISK_PRESENT_TRUE; + Error = ProfileSetField( pSession, PROFILE_Flags, &Info->Flags, sizeof(Info->Flags)); + if ( Error != NO_ERROR) { + goto cleanup; + } + JetError = JetUpdate( pSession->SesId, pSession->ProfileTableId, NULL, 0, NULL); + if ( JetError < 0) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + Error = NERR_RplInternal; + goto cleanup; + } + DiskDelete = FALSE; // success, make sure we do not delete disk data + +cleanup: + if ( DiskDelete == TRUE) { + // + // ProfileDiskAdd deletion code does not care about DirName* + // + ProfileDiskAdd( FALSE, Info->ProfileName, NULL, NULL, NULL, NULL); + } + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( FreeBootName == TRUE) { + MIDL_user_free( Info->BootName); + Info->BootName = NULL; + } + if ( FreeFitShared == TRUE) { + MIDL_user_free( Info->FitShared); + Info->FitShared = NULL; + } + if ( FreeFitPersonal == TRUE) { + MIDL_user_free( Info->FitPersonal); + Info->FitPersonal = NULL; + } + if ( DirName != NULL) { + MIDL_user_free( DirName); + } + if ( DirName2 != NULL) { + MIDL_user_free( DirName2); + } + if ( DirName3 != NULL) { + MIDL_user_free( DirName3); + } + if ( DirName4 != NULL) { + MIDL_user_free( DirName4); + } + if ( Error != ERROR_SUCCESS) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + } + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileDel( + IN RPL_HANDLE ServerHandle, + IN LPWSTR ProfileName + ) +{ + DWORD Error; + PRPL_SESSION pSession = &RG_ApiSession; + + _wcsupr( ProfileName); + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( RplFindByField( pSession, WKSTA_TABLE_TAG, + WKSTA_INDEX_ProfileNameWkstaName, ProfileName)) { + // + // We found a WKSTA record which uses this PROFILE. + // + Error = NERR_RplProfileNotEmpty; + goto cleanup; + } + if ( !RplFind( pSession, PROFILE_TABLE_TAG, ProfileName)) { + Error = NERR_RplProfileNotFound; + goto cleanup; + } + CallJ( JetDelete( pSession->SesId, pSession->ProfileTableId)); + ProfileDiskAdd( FALSE, ProfileName, NULL, NULL, NULL, NULL); + Error = NO_ERROR; + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplProfileClone( + IN RPL_HANDLE ServerHandle, + IN LPWSTR SourceProfileName, + IN LPWSTR TargetProfileName, + IN LPWSTR TargetProfileComment + ) +{ + RPL_PROFILE_INFO_2 Info; + DWORD Error; + DWORD ErrorParameter; + DWORD DataSize; + PWCHAR SaveProfileName; + PWCHAR SaveProfileComment; + JET_ERR JetError; + BOOL DiskDelete = FALSE; + PRPL_SESSION pSession = &RG_ApiSession; + + if ( !ValidName( SourceProfileName, RPL_MAX_PROFILE_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + _wcsupr( SourceProfileName); + if ( !ValidName( TargetProfileName, RPL_MAX_PROFILE_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + _wcsupr( TargetProfileName); + if ( RPL_STRING_TOO_LONG( TargetProfileComment)) { + return( ERROR_INVALID_PARAMETER); + } + + // + // Zero all the pointers so we can safely call ProfileGetInfoCleanup(). + // in all the cases. + // + memset( &Info, 0, sizeof( Info)); + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFind( pSession, PROFILE_TABLE_TAG, SourceProfileName)) { + Error = NERR_RplProfileNotFound; + goto cleanup; + } + Error = ProfileGetInfo( pSession, SourceProfileName, 2, &Info, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + // + // Save source data, then overload target data. + // + SaveProfileName = Info.ProfileName; + SaveProfileComment = Info.ProfileComment; + Info.ProfileName = TargetProfileName; + Info.ProfileComment = TargetProfileComment; + + // + // The call to ProfileSetInfo() will add PROFILE record to the database. + // The call may succeed but we may still fail to do the treecopy + // operations below. We can detect this situation any time later on + // by the value of the Flags bit. + // + Info.Flags = PROFILE_FLAGS_DISK_PRESENT_FALSE; + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->ProfileTableId, JET_prepInsert)); + + Error = ProfileSetInfo( pSession, 2, &Info, &ErrorParameter); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + ErrorParameter = 0; + JetError = JetUpdate( pSession->SesId, pSession->ProfileTableId, NULL, 0, NULL); + if ( JetError < 0) { + if ( JetError == JET_errKeyDuplicate) { + Error = NERR_RplProfileNameUnavailable; + } else { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + Error = NERR_RplInternal; + } + goto cleanup; + } + + DiskDelete = TRUE; // just in case we fail before we are done + Error = ProfileDiskClone( TRUE, SourceProfileName, TargetProfileName); + if ( Error != NO_ERROR) { + goto cleanup; + } + if ( !RplFind( pSession, PROFILE_TABLE_TAG, TargetProfileName)) { + Error = NERR_RplInternal; + goto cleanup; + } + CallJ( JetPrepareUpdate( pSession->SesId, pSession->ProfileTableId, JET_prepReplace)); + Info.Flags = PROFILE_FLAGS_DISK_PRESENT_TRUE; + Error = ProfileSetField( pSession, PROFILE_Flags, &Info.Flags, sizeof(Info.Flags)); + if ( Error != NO_ERROR) { + goto cleanup; + } + JetError = JetUpdate( pSession->SesId, pSession->ProfileTableId, NULL, 0, NULL); + if ( JetError < 0) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + Error = NERR_RplInternal; + goto cleanup; + } + DiskDelete = FALSE; // success, make sure we do not delete disk data + +cleanup: + if ( DiskDelete == TRUE) { + // + // Delete new tree. We do not need to delete the new record + // since we are going to rollback the transaction. + // + ProfileDiskClone( FALSE, NULL, TargetProfileName); + } + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + // + // Restore source data, then release it. + // + Info.ProfileName = SaveProfileName; + Info.ProfileComment = SaveProfileComment; + ProfileGetInfoCleanup( 2, &Info); + return( Error); +} + + diff --git a/private/net/svcdlls/rpl/server/read.c b/private/net/svcdlls/rpl/server/read.c new file mode 100644 index 000000000..b47a9af0f --- /dev/null +++ b/private/net/svcdlls/rpl/server/read.c @@ -0,0 +1,409 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + _read.c + +Abstract: + + Module reads next send packet from a VIRTUAL boot block. + THIS IS VERY COMPLICATED ALGORITHM, YOU MUST UNDERSTAND THE ALGORITHM + AND KNOW THE SIDE EFFECTS IF YOU DO ANY CHANGES. + + Provides similar functionality to rmapread.c in LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "read.h" + + +VOID RplMakePatch( + IN PRPL_WORKER_DATA pWorkerData, + OUT PBYTE send_buffer, + IN DWORD read_len, + IN DWORD read_offset + ) +/*++ + +Routine Description: + Makes NLS patch to send buffer. + +Arguments: + send_buffer - send buffer to be sent to DLL + read_len - length of buffer + read_offset - offset of buffer in bblock image + +Return Value: + None. + +--*/ +{ + DWORD Length; + DWORD PatchOffset; + PBYTE Source; + PBYTE Target; + DWORD base_offset; + + PatchOffset = pWorkerData->PatchOffset + pWorkerData->fblock_base_offset; + + // if top 1 less that bottom 2 or bottom 1 greater that top 2 + // => blocks do not overlap and there is nothing to patch here + + if ( !(PatchOffset + DBCS_MESSAGE_BUFFER_SIZE < read_offset || + PatchOffset > read_offset + read_len)) { + + // blocks overlap, get copy address and length, + // read offset is MAX( bottom1, bottom2 ) + + if (read_offset < PatchOffset) { + Source = RG_DbcsMessageBuffer; + Target = send_buffer + (WORD)(PatchOffset - read_offset); + base_offset = PatchOffset; + } else { + Source = RG_DbcsMessageBuffer + (WORD)(read_offset - PatchOffset); + Target = send_buffer; + base_offset = read_offset; + } + + // end offset is MIN( top1, top2 ) + if (read_offset + read_len < PatchOffset + DBCS_MESSAGE_BUFFER_SIZE) { + Length = read_offset + read_len - base_offset; + } else { + Length = PatchOffset + DBCS_MESSAGE_BUFFER_SIZE - base_offset; + } + + // copy data from source to destination + memcpy( Target, Source, (WORD)Length ); + } + +} + + +BOOL RplReadData( + IN PRPL_WORKER_DATA pWorkerData, + IN DWORD read_offset, + OUT PDWORD pBytesRead + ) +/*++ + +Routine Description: + + Returns pointer to send buffer and its length. The data is read from + the offset (input param) of virtual boot block. The boot block consists + of small wksta specific data buffer, virtual file block and unused + memory between them (if any). Virtual file block is a file table. + The names are in memory, but the data is in hard disk (or in disk cache). + +Arguments: + + read_offset - offset of data that we need to read + pBuffer - address of location where pointer to send buffer is returned + pBytesRead - pointer to number of bytes read + +Return Value: + TRUE if success, else FALSE. + +--*/ +{ + DWORD bytes_read = 0; // the length of send buffer + LONG sint; // signed integer for length comp + DWORD temp; + DWORD read_len; + DWORD file_len; + PBYTE wksta_buf; + DWORD wksta_buf_len; + DWORD LengthDataBuffer; + PBYTE pDataBuffer; + PFLIST_TBL flist_tbl; + DWORD flist_tbl_len; + DWORD cur_flist_i; + DWORD cur_offset; + DWORD cur_file_base_offset; + DWORD fblock_base_offset; + BOOL is_end_of_bblock; + BOOL LAN_err; + +// RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++RplReadData")); + + // + // The following is set in RplWorkerThread2 + // + LengthDataBuffer = pWorkerData->send_buf_len; + + // + // The following are set in RplMakeWkstaBuf + // + wksta_buf = pWorkerData->wksta_buf; + wksta_buf_len = pWorkerData->wksta_buf_len; + fblock_base_offset = pWorkerData->fblock_base_offset; + + // + // The following are set in RplOpenData + // + pDataBuffer = pWorkerData->pDataBuffer; + + flist_tbl = pWorkerData->flist_tbl; + flist_tbl_len = pWorkerData->flist_tbl_len; + + cur_flist_i = pWorkerData->cur_flist_i; + cur_offset = pWorkerData->cur_offset; + cur_file_base_offset = pWorkerData->cur_file_base_offset; + is_end_of_bblock = pWorkerData->is_end_of_bblock; + + + if ( fblock_base_offset > read_offset) { + + // We have to copy at least some data from wksta buffer or/and from + // the empty space between "wksta_buf_len" (end of wksta buffer + // data) and "fblock_base_offset" (beginning of file list data). + // First copy the data from wksta buffer then from empty space. + + if ( wksta_buf_len > read_offset) { // wksta buffer data + + if ( wksta_buf_len >= read_offset + LengthDataBuffer) { + bytes_read = LengthDataBuffer; // all is here + } else { + // Some but not all of the leftover data is here. + bytes_read = wksta_buf_len - read_offset; + } + + memcpy( pDataBuffer, &wksta_buf[read_offset], bytes_read); + } + + if ( bytes_read < LengthDataBuffer) { // empty space data + + if ( read_offset + LengthDataBuffer <= fblock_base_offset) { + temp = LengthDataBuffer - bytes_read; // rest is here + } else { + // Some but not all of the leftover data is here. + temp = fblock_base_offset - wksta_buf_len; + } + + memset( &pDataBuffer[ bytes_read], 0, temp); + bytes_read += temp; + } + } + + // + // Check if the right file is opened and the seek is OK. There may + // have been a LAN I/O error in which case we must read the data from + // a new position. + // + if ( read_offset == cur_offset || cur_offset == -1L) { + LAN_err = FALSE; // everything OK + + } else { + LAN_err = TRUE; // error in LAN I/O, this is not a sequential read + // + // this flag is set if we were reading the last buffer, + // reset flag, otherwise the rest is not read with ReadFile() + // + is_end_of_bblock = FALSE; + } + + + if ( bytes_read < LengthDataBuffer && !is_end_of_bblock) { + // + // All the data has not been read yet. Read the rest from + // files mentioned in the file list table. + // + if ( LAN_err && pWorkerData->hFile != INVALID_HANDLE_VALUE) { + if ( !CloseHandle( pWorkerData->hFile)) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + } + pWorkerData->hFile = INVALID_HANDLE_VALUE; + } + + // Check if this read is from a wrong position or there was + // fatal error in the first file read => start from the beginning. + + if ( LAN_err && read_offset > fblock_base_offset) { + // + // error => reset bytes_read counter, reject the possible data + // resend an old packet, search the new file of read_offset + // + bytes_read = 0; + cur_file_base_offset = fblock_base_offset; + + for ( cur_flist_i = 0; cur_flist_i < flist_tbl_len; cur_flist_i++) { + if (read_offset < + cur_file_base_offset + flist_tbl[cur_flist_i].FileData.file_len) { + + break; // found, exit the search loop + } + cur_file_base_offset += flist_tbl[cur_flist_i].FileData.file_len; + } + + // + // If wksta has sent a wrong read offset, terminate read ahead. + // + if ( cur_flist_i >= flist_tbl_len) { + is_end_of_bblock = TRUE; + goto end_of_block_exit; + } + + // + // Open file for reading + // + pWorkerData->hFile = CreateFile( flist_tbl[cur_flist_i].path_name, + GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0L); + if ( pWorkerData->hFile == INVALID_HANDLE_VALUE) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = flist_tbl[cur_flist_i].path_name; + pWorkerData->EventId = NELOG_RplWkstaFileOpen; + return( FALSE); + } + + // + // seek the current position, we are probably not reading from + // the start of file + // + file_len = SetFilePointer( pWorkerData->hFile, + read_offset - cur_file_base_offset, NULL, FILE_BEGIN); + if ( file_len == INVALID_FILE_OFFSET) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = flist_tbl[cur_flist_i].path_name; + pWorkerData->EventId = NELOG_RplWkstaFileRead; + return( FALSE); + } + + } else { + // + // Open the primary file, if it's not opened yet + // + if ( pWorkerData->hFile == INVALID_HANDLE_VALUE) { + if (read_offset <= fblock_base_offset) { + // open the first file + cur_flist_i = 0; + cur_file_base_offset = fblock_base_offset; + } + // + // Open file for reading + // + pWorkerData->hFile = CreateFile( flist_tbl[cur_flist_i].path_name, + GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0L); + if ( pWorkerData->hFile == INVALID_HANDLE_VALUE) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = flist_tbl[cur_flist_i].path_name; + pWorkerData->EventId = NELOG_RplWkstaFileOpen; + return( FALSE); + } + } + } + + // + // read files until send buffer is full + // + while( bytes_read < LengthDataBuffer) { + if ( !ReadFile( pWorkerData->hFile, &pDataBuffer[bytes_read], + LengthDataBuffer - bytes_read, &read_len, NULL)) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = flist_tbl[cur_flist_i].path_name; + pWorkerData->EventId = NELOG_RplWkstaFileRead; + return( FALSE); + } + + bytes_read += read_len; + + if (bytes_read == LengthDataBuffer) { + break; // we read all the data for now, exit the loop + } + // + // We have not read all the data we asked for. Therefore, we + // must have reached end of file. Therefore, close the current + // file handle and prepare to read the next file. + // + if ( !CloseHandle( pWorkerData->hFile)) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + } + + pWorkerData->hFile = INVALID_HANDLE_VALUE; + cur_file_base_offset += flist_tbl[cur_flist_i].FileData.file_len; + cur_flist_i++; + + // reset the last bytes in the file + + temp = cur_file_base_offset - read_offset; + + if ( (sint = (LONG)(temp - bytes_read)) > 0) { + memset( pDataBuffer + bytes_read, 0, sint ); + } + bytes_read = temp; + + if ( cur_flist_i >= flist_tbl_len) { + is_end_of_bblock = TRUE; + break; // end of file list + } + + // + // Open file for reading + // + pWorkerData->hFile = CreateFile( flist_tbl[cur_flist_i].path_name, + GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0L); + if ( pWorkerData->hFile == INVALID_HANDLE_VALUE) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventStrings[ 1] = flist_tbl[cur_flist_i].path_name; + pWorkerData->EventId = NELOG_RplWkstaFileOpen; + return( FALSE); + } + } + } + + cur_offset = read_offset + LengthDataBuffer; + + // + // only for end of boot block + // + +end_of_block_exit: + + // + // update the changed values + // + + pWorkerData->cur_offset = cur_offset; + pWorkerData->cur_file_base_offset = cur_file_base_offset; + pWorkerData->cur_flist_i = cur_flist_i; + pWorkerData->is_end_of_bblock = is_end_of_bblock; + + // + // Make NLS (DBCS ?) patch to RPLBOOT.SYS. + // + + if ( pWorkerData->MakePatch == TRUE) { + RplMakePatch( pWorkerData, pDataBuffer, bytes_read, read_offset); + } + + // + // return the buffer address and the length + // + + *pBytesRead = bytes_read; +// RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--RplReadData")); + return( TRUE); + +} + + diff --git a/private/net/svcdlls/rpl/server/read.h b/private/net/svcdlls/rpl/server/read.h new file mode 100644 index 000000000..ee571320d --- /dev/null +++ b/private/net/svcdlls/rpl/server/read.h @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + read.h + +Abstract: + + Exports from read.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +BOOL RplReadData( + IN PRPL_WORKER_DATA pWorkerData, + IN DWORD read_offset, + OUT PDWORD bytes_read_ptr + ); diff --git a/private/net/svcdlls/rpl/server/report.c b/private/net/svcdlls/rpl/server/report.c new file mode 100644 index 000000000..7063e12ca --- /dev/null +++ b/private/net/svcdlls/rpl/server/report.c @@ -0,0 +1,199 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + report.c + +Abstract: + + Prints messages to the error log of Lan Manager. + + Provides similar functionality to rplermsg.c in LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "report.h" + +VOID RplAlertRaise( IN DWORD ErrorCode); + + +VOID RplEnd( IN DWORD ErrorCode) +/*++ + +Routine Description: + + This function is called under very unusual circumstances! + It provides a convenient way for service to log an event, send + an alert, then exits. + +Arguments: + ErrorCode - termination error code + +Return Value: + None. + +--*/ +{ + RplReportEvent( ErrorCode, NULL, 0, NULL ); + RplAlertRaise( (RG_ServiceStatus.dwCurrentState == SERVICE_INSTALL_PENDING) + ? NERR_RplBootStartFailed : NERR_RplBootServiceTerm); + (VOID)RplServiceAttemptStop(); // signal service to stop +} + + + +VOID RplAlertRaise( IN DWORD ErrorCode) +/*++ + +Routine Description: + + Sends an ADMIN alert. The input is a LanManager error message. + + This is a combination of the original Send_alert() routine && + RaiseAlert() routine from logonsrv\server\error.c + +Arguments: + ErrorCode - the alert to be raised, text in alertmsg.h + +Return Value: + None. + +Notes: + Failing to post an alert is considered unimportant. This is why this + function is VOID. + +--*/ +{ + char message[ ALERTSZ + sizeof(STD_ALERT) + sizeof(ADMIN_OTHER_INFO)]; + PSTD_ALERT alert = (PSTD_ALERT)message; + PADMIN_OTHER_INFO other = (PADMIN_OTHER_INFO)ALERT_OTHER_INFO( alert); + LARGE_INTEGER time; + HANDLE fileHandle; + DWORD inBytes; + DWORD outBytes; + + NtQuerySystemTime( &time); + RtlTimeToSecondsSince1970( &time, &alert->alrt_timestamp ); + + // Original code used alrt_servicename == SERVICE_SERVER + wcscpy( alert->alrt_servicename, SERVICE_RIPL); + wcscpy( alert->alrt_eventname, ALERT_ADMIN_EVENT ); + + other->alrtad_errcode = ErrorCode; + other->alrtad_numstrings = 0; + + + // NetAlertRaise() is gone, must use mailslots instead. So, first + // open the Alerter mailslot to write to it. + + fileHandle = CreateFile( + ALERTER_MAILSLOT, + GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + (LPSECURITY_ATTRIBUTES) NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if ( fileHandle == INVALID_HANDLE_VALUE) { + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( + "AlertRaise: Error opening alerter mailslot, error=%d", + GetLastError())); + return; + } + + inBytes = min( sizeof( message), + (DWORD)( (PCHAR)ALERT_VAR_DATA(other) - (PCHAR)message)); + + // Write alert notification to mailslot to be read by Alerter service + if ( !WriteFile( + fileHandle, + message, + inBytes, + &outBytes, + NULL) || inBytes != outBytes) { + + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( + "AlertRaise: Error writing to alerter mailslot %d", + GetLastError())); + + } else if ( ! CloseHandle( fileHandle)) { + + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( + "AlertRaise: Error closing alerter mailslot %d", + GetLastError() + )); + } + (VOID)CloseHandle( fileHandle); +} + + + +VOID RplReportEventEx( + IN DWORD MessageId, + IN LPWSTR * aStrings + ) +/*++ + +Routine Description: + + Writes an event in the event log. + A related function lives is RplReportEvent() in lib\report.c. + These two functions should be united. + +Arguments: + + MessageId - Message ID + aStrings - a NULL terminated array of strings + +Return Value: + + None. + +--*/ +{ + WORD cStrings; + HANDLE logHandle; + + logHandle = RegisterEventSource( NULL, RPL_EVENTLOG_NAME); + + // If the event log cannot be opened, just return. + + if ( logHandle == NULL) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + return; + } + + for ( cStrings = 0; aStrings[ cStrings] != NULL; cStrings++) { + NOTHING; + } + + if ( !ReportEvent( + logHandle, + EVENTLOG_ERROR_TYPE, + 0, // event category + MessageId, // event id + NULL, // user SID. We're local system - uninteresting + cStrings, // number of strings + 0, // raw data size + aStrings, // string array + NULL // raw data buffer + )) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + } + + DeregisterEventSource( logHandle); +} + diff --git a/private/net/svcdlls/rpl/server/report.h b/private/net/svcdlls/rpl/server/report.h new file mode 100644 index 000000000..be3b621e1 --- /dev/null +++ b/private/net/svcdlls/rpl/server/report.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + report.h + +Abstract: + + Exports from report.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +// +// VOID RplReportEvent( - declared in ..\inc\rpl.h +// + +VOID RplEnd( IN DWORD ErrorCode); +VOID RplReportEventEx( + IN DWORD MessageId, + IN LPWSTR * aStrings + ); + diff --git a/private/net/svcdlls/rpl/server/request.c b/private/net/svcdlls/rpl/server/request.c new file mode 100644 index 000000000..4a409dee2 --- /dev/null +++ b/private/net/svcdlls/rpl/server/request.c @@ -0,0 +1,697 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + request.c + +Abstract: + + Request thread code. + + Provides similar functionality to rplreq.c in LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "worker.h" +#include "database.h" +#include "report.h" +#include "request.h" + +typedef struct _RPL_SFR_PARAMS { // send file request thread parameters + POPEN_INFO pOpenInfo; // open info data of current DLL + PPRCB HeadRcbList; // list of RCBs used by worker threads + PCRITICAL_SECTION ProtectRcbList; +} SFR_PARAMS, *PRPL_SFR_PARAMS; + + +extern VOID RplInsertRcb( + IN OUT PPRCB HeadList, + IN OUT PRCB pRcb + ); + + + +VOID SfrThread( PRPL_SFR_PARAMS pSfrParams) +/*++ + +Routine Description: + + Procedure receives Send File Requests, searches the valid RCB + from list and starts the worker thread of RCB by clearing a + semaphore. + + This thread tries to run at highest settable priority because + claims must always be ready to receive acknowledges (if ASCLAN + receive is not active, then SF Requests may be lost and there + is 4 seconds timeout in the workstation). + +Arguments: + pSfrParams ptr to SFR_PARAMS + +Return Value: + None. + +--*/ +{ + DWORD status; + + if ( !SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) { + status = GetLastError(); + RplDump( ++RG_Assert, ("status=%d", status)); + RplEnd( NELOG_RplSystem); + return; + } + + // + // The call to SendFileRequest never returns. Not only is this thread + // capt captive, but the callee needlessly creates one more thread. + // Better interface would allow to post a receive for our two SAP-s, + // then from a single place read both FIND frame data (FIND_SAP) + // and SFR data (SFR_SAP). This could be all done from a single + // thread, resembling current RequestThread(). + // + + if ( RplDlcSfr( // was RPL1_Get_SF_Request() + pSfrParams->pOpenInfo, + pSfrParams->HeadRcbList, + pSfrParams->ProtectRcbList + )) { + return; // success + } + if ( RG_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) { + return; // somebody else initiated service shutdown + } + RplDump( ++RG_Assert, ("CurrentState=0x%x", RG_ServiceStatus.dwCurrentState)); + RplEnd( NELOG_RplSystem); +} + + + +PRCB RplPopRcb( PPRCB HeadList) +{ + PRCB pRcb = *HeadList; + DebugCheckList( HeadList, NULL, 0); + if ( pRcb != NULL) { + *HeadList = pRcb->next_rcb; + } + RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,( + "PopRcb: pRcb=0x%x, list=0x%x", pRcb, HeadList)); + DebugCheckList( HeadList, pRcb, RPL_MUST_NOT_FIND); + return( pRcb); +} + + +PRCB GetRcbFromFreeList( + IN OUT PPRCB pFreeList, + IN DWORD lan_rcb_size + ) +/*++ + +Routine Description: + + Finds the first RCB from the list of free RCBs. If list is empty, + creates a new RCB. Before returning RCB it (re)initializes all the + fields in the RCB. + +Arguments: + + pFreeList, - pointer to list of free RCB-s + lan_rcb_size - size of lan specific rcb + +Return Value: + + Pointer to RCB, or NULL if we cannot get an RCB. + +--*/ +{ + PRCB pRcb; + + EnterCriticalSection( &RG_ProtectRcbList); + + pRcb = RplPopRcb( pFreeList); + if ( pRcb != NULL) { + goto exit_GetRcbFromFreeList; // success + } + + pRcb = RplMemAlloc( RG_MemoryHandle, sizeof(RCB)); + if ( pRcb == NULL) { + goto exit_GetRcbFromFreeList; + } + + pRcb->lan_rcb_ptr = RplMemAlloc( RG_MemoryHandle, lan_rcb_size); + if ( pRcb->lan_rcb_ptr == NULL) { + RplMemFree( RG_MemoryHandle, pRcb); + pRcb = NULL; + goto exit_GetRcbFromFreeList; // failure + } + + // SF_wakeup was using automatic reset and RPL worker used not to + // reset SF_wakup before each FDR send. This did not work properly + // due to multiple SFR-s for a single frame. Multiple SFR-s would + // cause SF_wakeup to be in a signalled state immediately after + // worker sent an FDR, thus worker would wakeup immediately and find + // a wrong value for sfr_seq_number. + // To fix this RPL worker must make sure SF_wakeup is blocked + // before each FDR send. Since worker must now reset SF_wakeup + // anyway, SF_wakeup is now using manual reset. + // + pRcb->SF_wakeup = CreateEvent( + NULL, // no security attributes + TRUE, // use manual reset + TRUE, // initial value is signalled + NULL // event does not have a name + ); + if ( pRcb->SF_wakeup == NULL) { + RplDump( ++RG_Assert,("CreateEvent => error=%d", GetLastError())); + RplMemFree( RG_MemoryHandle, pRcb->lan_rcb_ptr); + RplMemFree( RG_MemoryHandle, pRcb); + pRcb = NULL; + goto exit_GetRcbFromFreeList; // failure + } + +exit_GetRcbFromFreeList: + + pRcb->AdapterName[ NODE_ADDRESS_LENGTH] = 0; + *pRcb->volume_id = 0; + pRcb->sfr_seq_number = 0; + pRcb->fdr_seq_number = 0; + pRcb->ReceivedSfr = FALSE; + + *(PBYTE)&pRcb->flags = 0; // reset the error flags + pRcb->next_rcb = NULL; + *(PBYTE)&pRcb->flags = 0; + + pRcb->Pending = TRUE; + pRcb->SFR = FALSE; + + LeaveCriticalSection( &RG_ProtectRcbList); + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST,( + "GetRcbFromFreeList: pRcb=0x%x", pRcb)); + return( pRcb); +} + + +PRPL_WORKER_PARAMS GetWorkerParams( + IN PRPL_REQUEST_PARAMS pRequestParams, + OUT PBOOL pShutdown + ) +/*++ + Loops until number of worker threads falls below the maximum value + allowed, or until it gets signalled to die. + If it is signalled to die, waits for all worker children and returns. + If it is not signalled to die, waits only for children that are + already exiting, and returns pointer to one of available RPL_WORKER_PARAMS + structures. +--*/ +{ + HANDLE eventArray[ 2]; + PRPL_WORKER_PARAMS pWorkerParams; + PRPL_WORKER_PARAMS pFoundWorkerParams; + DWORD status; + DWORD WorkerCount; + + eventArray[ 0] = RG_EventWorkerCount; + eventArray[ 1] = RG_TerminateNowEvent; + + *pShutdown = FALSE; + + for ( ; ;) { + EnterCriticalSection( &RG_ProtectWorkerCount); + WorkerCount = RG_WorkerCount; + if ( WorkerCount < RG_MaxWorkerCount) { + LeaveCriticalSection( &RG_ProtectWorkerCount); + break; + } + // + // We reset event from within critical section to make sure + // event is never reset for wrong reasons. + // + if ( !ResetEvent( RG_EventWorkerCount)) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + } + LeaveCriticalSection( &RG_ProtectWorkerCount); + status = WaitForMultipleObjects( + 2, // count + eventArray, // handles + FALSE, // wait for at least one + INFINITE // wait for ever + ); + if ( status == 1) { + *pShutdown = TRUE; // terminate now event + break; // to wait for children below + } + RPL_ASSERT( status == 0); // WorkerCount changed + continue; + } + + // + // If we are shutting down, wait on all valid thread handles. + // Else, wait only on thread handles for children that are exiting. + // + for ( pFoundWorkerParams = NULL, + pWorkerParams = pRequestParams->pWorkerParams; + pWorkerParams != NULL; + pWorkerParams = pWorkerParams->pWorkerParams) { + if ( pWorkerParams->Exiting == TRUE || + (*pShutdown == TRUE && pWorkerParams->ThreadHandle != NULL)) { + status = WaitForSingleObject( pWorkerParams->ThreadHandle, INFINITE); + if ( status != 0) { + RplDump( ++RG_Assert, ( "pWorkerParams=0x%x, status=0x%x", + pWorkerParams, status==WAIT_FAILED ? GetLastError() : status)); + } + if ( !CloseHandle( pWorkerParams->ThreadHandle)) { + RplDump( ++RG_Assert, ( "pWorkerParams=0x%x, error=%d", + pWorkerParams, GetLastError())); + } + pWorkerParams->ThreadHandle = NULL; // OK to reuse + pWorkerParams->Exiting = FALSE; + } + if ( pWorkerParams->ThreadHandle == NULL) { + pFoundWorkerParams = pWorkerParams; // reuse this structure + } + } + if ( *pShutdown == TRUE) { + return( NULL); + } + if ( pFoundWorkerParams == NULL) { + // + // Allocate a brand new RPL_WORKER_PARAMS structure. + // + pFoundWorkerParams = RplMemAlloc( RG_MemoryHandle, sizeof(RPL_WORKER_PARAMS)); + if ( pFoundWorkerParams == NULL) { + RplDump( ++RG_Assert, ( "")); + return( NULL); + } + pFoundWorkerParams->pWorkerParams = pRequestParams->pWorkerParams; + pRequestParams->pWorkerParams = pFoundWorkerParams; + pFoundWorkerParams->ThreadHandle = NULL; + pFoundWorkerParams->ThreadId = 0; + pFoundWorkerParams->pRequestParams = pRequestParams; + pFoundWorkerParams->pRcb = NULL; + pFoundWorkerParams->Exiting = FALSE; + } + return( pFoundWorkerParams); +} + + + +VOID RequestThread( PRPL_REQUEST_PARAMS pRequestParams) +/*++ + +Routine Description: + + Module is the RPL request thread. It must be re-entrant, because each + DLL has own instance of this module. Module loads rpl DLLs and gets + their entry point addresses. It initializes DLLs and dynamic memory + and starts RpldFind() loop. + +Arguments: + + pRequestParams - string containing names of RPL1 & RPL2 DLLs + +Return Value: + + None. + +Notes: + + This routine must have a single exit point because it is essential + to decrement the number of request threads and wake up the main + thread on our way out. + +--*/ +{ + PRPL_SFR_PARAMS pSfrParams; + DWORD ThreadId; + DWORD status; + POPEN_INFO pOpenInfo; // generic rpl DLL info + PRCB pRcb; // current Resource Control Block + PRPL_WORKER_PARAMS pWorkerParams; + BOOL Shutdown; + HANDLE ThreadHandle; + // + // TRUE if we inserted RCB in pending state on a worker queue. + // Used only when "pRcb" is not NULL i.e. while it still makes + // sense keeping pointer to that RCB. + // + BOOL RcbOnWorkerList; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++RequestThread(0x%x)", pRequestParams)); + + ThreadHandle = NULL; + pOpenInfo = pRequestParams->pOpenInfo; + + // + // Build parameter block for SfrThread + // + pSfrParams = RplMemAlloc( RG_MemoryHandle, sizeof( SFR_PARAMS)); + if( pSfrParams == NULL) { + status = GetLastError(); + RplDump( ++RG_Assert, ("status=%d", status)); + RplEnd( ERROR_NOT_ENOUGH_MEMORY); + goto exit_RequestThread; + } + pSfrParams->HeadRcbList = &pRequestParams->BusyRcbList; + pSfrParams->ProtectRcbList = &RG_ProtectRcbList; + pSfrParams->pOpenInfo = pOpenInfo; + + // + // Create Get_SF_Request thread, it receives Send File Requests + // from workstations, searches rcb from list and clears its semaphore, + // that releases the worker thread. + // + ThreadHandle = CreateThread( NULL, 0, + (LPTHREAD_START_ROUTINE)SfrThread, pSfrParams, 0, &ThreadId); + if ( ThreadHandle == NULL) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + RplEnd( ERROR_NOT_ENOUGH_MEMORY); + goto exit_RequestThread; + } + + // + // Read RPL request packets forever. Never create more than the + // maximum allowed number of worker threads. + // + for ( pRcb = NULL, pWorkerParams = NULL; NOTHING; NOTHING) { + // + // If pRcb is NULL we need to get an RCB from the free list. + // If pRcb is not NULL then we can still use it but we must + // dequeue it from worker queue if we placed it there. + // + if ( pRcb == NULL) { + for ( ; ;) { + pRcb = GetRcbFromFreeList( + &pRequestParams->FreeRcbList, + pOpenInfo->lan_rcb_size + ); + if ( pRcb != NULL) { + break; + } + Sleep( 1000L); // wait for things to recover + } + } else if ( RcbOnWorkerList == TRUE) { + EnterCriticalSection( &RG_ProtectRcbList); + RplRemoveRcb( &pRequestParams->BusyRcbList, pRcb); + LeaveCriticalSection( &RG_ProtectRcbList); + } + RcbOnWorkerList = FALSE; + + // + // Get the next RPL request. In the current design here we can + // block for ever if there are no FIND frames arriving. The only + // way then to let this thread out is for the main thread to call + // RPL_Term(). This would then cause RplDlcFind() to + // return with error, and we would exit main loop. + // A better interface would provide asynchronous calls, just the + // way DLC does. Then, ideally we would wait here for multiple + // events such as: + // - FIND frame arrival event + // - TerminateNowEvent + // + + if ( !RplDlcFind( pOpenInfo, pRcb)) { + if ( RG_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) { + goto exit_RequestThread; + } + RplDump( ++RG_Assert, ("CurrentState=0x%x", RG_ServiceStatus.dwCurrentState)); + continue; + } + + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST,( + "Request(0x%x): RplDlcFind => pRcb=0x%x, AdapterName=%ws", + pRequestParams, pRcb, pRcb->AdapterName)); + + // + // Send buffers must be paragraph aligned because of Jump address + // patching to the rplboot.sys code (dword fits always to one + // boot block) + // + pRcb->max_frame &= 0xFFF0; + + // + // "max_frame" is sent to us by the client as the max value of data + // that the client can handle. We can go smaller than that but never + // larger. + // + if (pRcb->max_frame > MAX_FRAME_SIZE) { + pRcb->max_frame = MAX_FRAME_SIZE; + } + + // + // Service this client if it is not already serviced by some of our + // children, and we have enough threads and we can find a matching + // wksta record. + // + + EnterCriticalSection( &RG_ProtectRcbList); + + if ( RplFindRcb( &pRequestParams->BusyRcbList, pRcb->NodeAddress) != NULL) { + // + // Client is already serviced by some of our children. + // + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST,( + "Request(0x%x): pRcb=0x%x, AdapterName=%ws client is already serviced", + pRequestParams, pRcb, pRcb->AdapterName)); + LeaveCriticalSection( &RG_ProtectRcbList); + continue; + } + + RcbOnWorkerList = TRUE; // to get it back in case of errors + pRcb->Pending = TRUE; // so SFR thread does not get confused + RplInsertRcb( &pRequestParams->BusyRcbList, pRcb); + LeaveCriticalSection( &RG_ProtectRcbList); + + if ( !RplRequestHaveWksta( pRcb->AdapterName)) { + continue; // no wksta record for this AdapterName + } + + if ( pWorkerParams == NULL) { + pWorkerParams = GetWorkerParams( pRequestParams, &Shutdown); + if ( Shutdown == TRUE) { + goto exit_RequestThread; + } else if ( pWorkerParams == NULL) { + continue; + } + } + + pWorkerParams->pRcb = pRcb; + pWorkerParams->ThreadHandle = CreateThread( NULL, 0, + (LPTHREAD_START_ROUTINE)RplWorkerThread, pWorkerParams, 0, + &pWorkerParams->ThreadId); + if ( pWorkerParams->ThreadHandle == NULL) { + RplDump( ++RG_Assert,( "Error=%d", GetLastError())); + RplReportEvent( ERROR_NOT_ENOUGH_MEMORY, NULL, 0, NULL); // keep going + continue; + } + pRcb = NULL; // need to get a new RCB + pWorkerParams = NULL; // need to get a new WORKER_PARAMS + } + +exit_RequestThread: + + if ( RcbOnWorkerList == TRUE) { + EnterCriticalSection( &RG_ProtectRcbList); + RplRemoveRcb( &pRequestParams->BusyRcbList, pRcb); + RplInsertRcb( &pRequestParams->FreeRcbList, pRcb); + LeaveCriticalSection( &RG_ProtectRcbList); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_REQUEST,( + "RequestThread(0x%x): on its way to exit", pRequestParams)); + + // + // Wait for SFR thread to exit then close its thread handle. + // + status = WaitForSingleObject( ThreadHandle, INFINITE); + if ( status != 0) { + RplDump( ++RG_Assert, ( "Params=0x%x Handle=0x%x Id=0x%x status=0x%x", + pSfrParams, ThreadHandle, ThreadId, status)); + } + if ( !CloseHandle( ThreadHandle)) { + RplDump( ++RG_Assert, ( "Params=0x%x Handle=0x%x Id=0x%x error=%d", + pSfrParams, ThreadHandle, ThreadId, GetLastError())); + } + pRequestParams->Exiting = TRUE; + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--RequestThread(0x%x)", pRequestParams)); +} + + +BOOL AddToTermList( IN POPEN_INFO pOpenInfo) +/*++ + +Routine Description: + +Arguments: + pOpenInfo - info ptr for dll + +Return Value: + TRUE if success, FALSE otherwise. + +--*/ +{ + PTERM_LIST pTermList; + + pTermList = RplMemAlloc( RG_MemoryHandle, sizeof(TERM_LIST)); + if ( pTermList == NULL) { + RG_Error = GetLastError(); + return( FALSE); + } + pTermList->pOpenInfo = pOpenInfo; + + EnterCriticalSection( &RG_ProtectTerminationList); + pTermList->next = RG_TerminationListBase; + RG_TerminationListBase = pTermList; + + LeaveCriticalSection( &RG_ProtectTerminationList); + return( TRUE); +} + + +BOOL RplStartAdapters( VOID) +/*++ + +Routine Description: + Attempt to start all adapters. + +Return Value: + TRUE if at least one of the adapters have been started. + FALSE otherwise + +--*/ +{ + POPEN_INFO pOpenInfo; // generic rpl DLL info + PRPL_REQUEST_PARAMS pRequestParams; + DWORD startedAdapters; + DWORD AdapterNumber; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++RplStartAdapters")); + + pOpenInfo = NULL; // must be reinitialized every time + pRequestParams = NULL; // must be reinitialized every time + + for ( AdapterNumber = 0, startedAdapters = 0; + AdapterNumber < MAX_ADAPTERS; AdapterNumber++) { + + if ( pOpenInfo == NULL) { + pOpenInfo = RplMemAlloc( RG_MemoryHandle, sizeof(OPEN_INFO)); + if ( pOpenInfo == NULL) { + RG_Error = GetLastError(); + RPL_ASSERT( FALSE); + continue; + } + memset( pOpenInfo, 0, sizeof( *pOpenInfo)); + } + if ( pOpenInfo->adapt_info_ptr == NULL) { + pOpenInfo->adapt_info_size = MAX_ADAPTER_INFO_SIZE; + pOpenInfo->adapt_info_ptr = RplMemAlloc( RG_MemoryHandle, MAX_ADAPTER_INFO_SIZE); + if ( pOpenInfo->adapt_info_ptr == NULL) { + RG_Error = GetLastError(); + RPL_ASSERT( FALSE); + continue; + } + memset( pOpenInfo->adapt_info_ptr, 0, MAX_ADAPTER_INFO_SIZE); + } + +#ifndef RPL_NO_SERVICE + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RplDump( ++RG_Assert, ( "Error = ", GetLastError())); + NOTHING; // just ignore this error + } +#endif + + // + // We try to start all adapters. + // + if ( !RplDlcInit( (POPEN_INFO)pOpenInfo, AdapterNumber)) { + continue; // try all adapters + } + + // + // Save termination addresses of dll-s for usage by RplTerminateDlls(). + // + if ( !AddToTermList( pOpenInfo)) { + break; + } + + // + // Allocate & initialize request thread parameters. + // + if ( pRequestParams == NULL) { + pRequestParams = RplMemAlloc( RG_MemoryHandle, sizeof(RPL_REQUEST_PARAMS)); + if ( pRequestParams == NULL) { + RG_Error = GetLastError(); + break; + } + memset( pRequestParams, 0, sizeof( *pRequestParams)); + pRequestParams->pOpenInfo = pOpenInfo; + pRequestParams->pRequestParams = RG_pRequestParams; + RG_pRequestParams = pRequestParams; + + } + pRequestParams->ThreadHandle = CreateThread( NULL, 0, + (LPTHREAD_START_ROUTINE)RequestThread, pRequestParams, 0, + &pRequestParams->ThreadId); + if ( pRequestParams->ThreadHandle == NULL) { + RG_Error = GetLastError(); + RPL_ASSERT( FALSE); + continue; + } + startedAdapters++; + pOpenInfo = NULL; // must be reinitialized every time + pRequestParams = NULL; // need to get new REQUEST_PARAMS + } + + if ( pOpenInfo) { + if ( pOpenInfo->adapt_info_ptr) { + RplMemFree( RG_MemoryHandle, pOpenInfo->adapt_info_ptr); + } + RplMemFree( RG_MemoryHandle, pOpenInfo); + } + + if ( startedAdapters == 0) { + RG_Error = RG_Error == NO_ERROR ? NERR_RplNoAdaptersStarted : RG_Error; + return( FALSE); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--RplStartAdapters")); + return( TRUE); +} + + +VOID RplCloseAdapters( VOID) +/*++ + +Routine Description: + + Terminates all the DLL-s in RPL termination list. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PTERM_LIST pTerm; + + for ( pTerm = RG_TerminationListBase; pTerm != NULL; pTerm = pTerm->next) { + RplDlcTerm( pTerm->pOpenInfo); + } +} + diff --git a/private/net/svcdlls/rpl/server/request.h b/private/net/svcdlls/rpl/server/request.h new file mode 100644 index 000000000..68e847db8 --- /dev/null +++ b/private/net/svcdlls/rpl/server/request.h @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + request.h + +Abstract: + + Exports from request.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +BOOL RplStartAdapters( VOID); +VOID RplCloseAdapters( VOID); diff --git a/private/net/svcdlls/rpl/server/resume.c b/private/net/svcdlls/rpl/server/resume.c new file mode 100644 index 000000000..e2175a179 --- /dev/null +++ b/private/net/svcdlls/rpl/server/resume.c @@ -0,0 +1,308 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + resume.c + +Abstract: + + Module for dealing with resume keys used in enumerations. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "db.h" +#include "config.h" +#include "database.h" +#define RPLRESUME_ALLOCATE +#include "resume.h" +#undef RPLRESUME_ALLOCATE + +#ifdef RPL_DEBUG + +VOID ResumeList( + IN PRPL_SESSION pSession, + IN PCHAR String + ) +{ + WCHAR ResumeValue[ 20]; + DWORD NameSize; + JET_ERR ForJetError; + DWORD ResumeHandle; + DWORD ServerHandle; + + Call( JetSetCurrentIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ResumeHandle)); + + // + // We could skip JetMove, but if we do so, we need to modify error + // testing for the first JetRetrieveColumn() call (it would return + // JET_errNoCurrentRecord for the empty table). + // + + for ( ForJetError = JetMove( pSession->SesId, pSession->ResumeTableId, JET_MoveFirst, 0); + ForJetError == JET_errSuccess; + ForJetError = JetMove( pSession->SesId, pSession->ResumeTableId, JET_MoveNext, 0)) { + Call( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId, + ResumeTable[ RESUME_ResumeHandle].ColumnId, + &ResumeHandle, sizeof( ResumeHandle), &NameSize, 0, NULL)); + Call( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId, + ResumeTable[ RESUME_ResumeValue].ColumnId, + ResumeValue, sizeof( ResumeValue), &NameSize, 0, NULL)); + Call( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId, + ResumeTable[ RESUME_ServerHandle].ColumnId, + &ServerHandle, sizeof( ServerHandle), &NameSize, 0, NULL)); + RplDump( RG_DebugLevel & RPL_DEBUG_RESUME, ( + "%s ResumeH=0x%x,Value=%ws,ServerH=0x%x", + String, ResumeHandle, ResumeValue, ServerHandle)); + } +} +#endif // RPL_DEBUG + + +DWORD ResumeCreateTable( OUT PRPL_SESSION pSession) +/*++ + Table gets created, then closed. The reason we do not keep the table + open is that creator of a table holds exclusive access to that table + until he/she closes the table. This would prevent other threads from + using the table. +--*/ +{ + JET_COLUMNDEF ColumnDef; + JET_ERR JetError; + DWORD index; + DWORD Offset; + CHAR IndexKey[ 255]; + + JetError = JetCreateTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME, + RESUME_TABLE_PAGE_COUNT, RESUME_TABLE_DENSITY, &pSession->ResumeTableId); + if ( JetError == JET_errTableDuplicate) { + // + // This would happend only if last time we did not shutdown properly + // so ResumeTable never got deleted. + // + CallM( JetDeleteTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME)); + JetError = JetCreateTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME, + RESUME_TABLE_PAGE_COUNT, RESUME_TABLE_DENSITY, &pSession->ResumeTableId); + } + if ( JetError != JET_errSuccess) { + return( MapJetError( JetError)); + } + + // + // Create columns. First initalize fields that do not change between + // addition of columns. + // + ColumnDef.cbStruct = sizeof(ColumnDef); + ColumnDef.columnid = 0; + ColumnDef.wCountry = 1; + ColumnDef.langid = 0x0409; // USA english + ColumnDef.cp = 1200; // UNICODE codepage + ColumnDef.wCollate = 0; + ColumnDef.cbMax = 0; + + for ( index = 0; index < RESUME_TABLE_LENGTH; index++) { + + ColumnDef.coltyp = ResumeTable[ index].ColumnType; + // + // All columns are variable length, but resume handle is autoincrement + // as well. + // + ColumnDef.grbit = (index==RESUME_ResumeHandle) ? + JET_bitColumnAutoincrement : 0; + + CallM( JetAddColumn( pSession->SesId, pSession->ResumeTableId, + ResumeTable[ index].ColumnName, &ColumnDef, + NULL, 0, &ResumeTable[ index].ColumnId)); + } + + // + // We need resume handle as an index, so that at Enum() time we quickly + // find resume value for a given resume handle. Beging primary index, + // this index is also unique. + // + Offset = AddKey( IndexKey, '+', ResumeTable[ RESUME_ResumeHandle].ColumnName); + IndexKey[ Offset++] = '\0'; + CallM( JetCreateIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ResumeHandle, + JET_bitIndexPrimary, IndexKey, Offset, 50)); + + // + // We need server handle as an index, so that at Close() time we quickly + // enumerate all resume keys for a given server handle, then delete them. + // This index is NOT unique since we can have a number of resume handles + // per client. + // + Offset = AddKey( IndexKey, '+', ResumeTable[ RESUME_ServerHandle].ColumnName); + IndexKey[ Offset++] = '\0'; + CallM( JetCreateIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ServerHandle, + 0, IndexKey, Offset, 50)); + +#ifdef RPL_DEBUG + if ( RG_DebugLevel == (DWORD)(-1)) { + ResumeList( pSession, "ResumeCreateTable"); + } +#endif // RPL_DEBUG + + CallM( JetCloseTable( pSession->SesId, pSession->ResumeTableId)); + return( ERROR_SUCCESS); +} + + + +DWORD ResumeDeleteTable( + IN PRPL_SESSION pSession + ) +{ + if ( pSession->ResumeTableId != 0) { + CallM( JetCloseTable( pSession->SesId, pSession->ResumeTableId)); + CallM( JetDeleteTable( pSession->SesId, pSession->DbId, RESUME_TABLE_NAME)); + } + return( NO_ERROR); +} + + +BOOL ResumeKeyGet( + IN PRPL_SESSION pSession, + IN DWORD ResumeHandle, + OUT PVOID ResumeValue, + IN OUT PDWORD pResumeSize + ) +{ + DWORD DataSize; +#ifdef RPL_DEBUG_NEVER + if ( RG_DebugLevel == (DWORD)(-1)) { + ResumeList( pSession, "++ResumeKeyGet"); + } +#endif // RPL_DEBUG_NEVER + CallB( JetSetCurrentIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ResumeHandle)); + CallB( JetMakeKey( pSession->SesId, pSession->ResumeTableId, &ResumeHandle, + sizeof( ResumeHandle), JET_bitNewKey)); + CallB( JetSeek( pSession->SesId, pSession->ResumeTableId, JET_bitSeekEQ)); + CallB( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId, + ResumeTable[ RESUME_ResumeValue].ColumnId, ResumeValue, + *pResumeSize, &DataSize, 0, NULL)); + if ( DataSize > *pResumeSize) { + RplDump( ++RG_Assert, ( "DataSize=%d", DataSize)); + return( FALSE); + } + *pResumeSize = DataSize; + return( TRUE); +} + + +BOOL ResumeKeySet( + IN PRPL_SESSION pSession, + IN DWORD ServerHandle, + IN PVOID ResumeValue, + IN DWORD ResumeSize, + OUT PDWORD pResumeHandle + ) +{ + DWORD DataSize; + + *pResumeHandle = 0; // just in case we fail below + +#ifdef RPL_DEBUG + if ( RG_DebugLevel == (DWORD)(-1)) { + ResumeList( pSession, "++ResumeKeySet"); + } +#endif // RPL_DEBUG + + CallB( JetSetCurrentIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ResumeHandle)); +#if 0 + // + // We do NOT call JetMove() here, because in the case of an empty table + // it returns error JET_errNoCurrentRecord. Also, if JetMove() is used + // here, then ordering of elements in the table is such that ResumePrune() + // function deletes only the OLDEST record for a given server handle. + // + CallB( JetMove( pSession->SesId, pSession->ResumeTableId, JET_MoveLast, 0)); +#endif + CallB( JetPrepareUpdate( pSession->SesId, pSession->ResumeTableId, JET_prepInsert)); + CallB( JetRetrieveColumn( pSession->SesId, pSession->ResumeTableId, + ResumeTable[ RESUME_ResumeHandle].ColumnId, pResumeHandle, + sizeof( *pResumeHandle), &DataSize, JET_bitRetrieveCopy, NULL)); + if ( DataSize != sizeof( *pResumeHandle) || *pResumeHandle == 0) { + RplDump( ++RG_Assert, ( "DataSize=%d", DataSize)); + return( FALSE); + } + CallB( JetSetColumn( pSession->SesId, pSession->ResumeTableId, + ResumeTable[ RESUME_ResumeValue].ColumnId, ResumeValue, + ResumeSize, 0, NULL)); + CallB( JetSetColumn( pSession->SesId, pSession->ResumeTableId, + ResumeTable[ RESUME_ServerHandle].ColumnId, &ServerHandle, + sizeof( ServerHandle), 0, NULL)); + CallB( JetUpdate( pSession->SesId, pSession->ResumeTableId, NULL, 0, NULL)); +#ifdef RPL_DEBUG + if ( RG_DebugLevel & RPL_DEBUG_RESUME) { + WCHAR ValueBuffer[ 32]; + DWORD Length; + PWCHAR Value; + Length = wcslen( (PWCHAR)ResumeValue); + if ( (Length + 1) * sizeof(WCHAR) < ResumeSize) { + wcscpy( ValueBuffer, (PWCHAR)ResumeValue); + wcscat( ValueBuffer, L"!"); + wcscat( ValueBuffer, (PWCHAR)ResumeValue + Length + 1); + Value = ValueBuffer; + } else { + Value = (PWCHAR)ResumeValue; + } + RplDump( RG_DebugLevel & RPL_DEBUG_RESUME, ( + "ResumeKeySet: Handle=0x%x, Value=%.20ws", *pResumeHandle, Value)); + } +#endif // RPL_DEBUG + return( TRUE); +} + + +VOID ResumePrune( + IN PRPL_SESSION pSession, + IN DWORD ServerHandle + ) +/*++ + This function returns no errors, since failure to delete old resume handles + is not considered fatal (and there is very little we can do about this). +--*/ +{ + JET_ERR JetError; + +#ifdef RPL_DEBUG + if ( RG_DebugLevel == (DWORD)(-1)) { + ResumeList( pSession, "++ResumePrune"); + } +#endif // RPL_DEBUG + CallR( JetSetCurrentIndex( pSession->SesId, pSession->ResumeTableId, RESUME_INDEX_ServerHandle)); + CallR( JetMakeKey( pSession->SesId, pSession->ResumeTableId, &ServerHandle, + sizeof( ServerHandle), JET_bitNewKey)); +#ifdef NOT_YET + JetError = JetSeek( pSession->SesId, pSession->ResumeTableId, JET_bitSeekEQ); +#else + JetError = JetSeek( pSession->SesId, pSession->ResumeTableId, JET_bitSeekEQ | JET_bitSetIndexRange); +#endif + if ( JetError == JET_errSuccess) { +#ifdef NOT_YET + CallR( JetMakeKey( pSession->SesId, pSession->ResumeTableId, &ServerHandle, + sizeof( ServerHandle), JET_bitNewKey)); + CallR( JetSetIndexRange( pSession->SesId, pSession->ResumeTableId, + JET_bitRangeInclusive | JET_bitRangeUpperLimit)); +#endif + do { + Call( JetDelete( pSession->SesId, pSession->ResumeTableId)); + JetError = JetMove( pSession->SesId, pSession->ResumeTableId, JET_MoveNext, 0); + } while ( JetError == JET_errSuccess); + } +#ifdef RPL_DEBUG + if ( RG_DebugLevel == (DWORD)(-1)) { + ResumeList( pSession, "--ResumePrune"); + } +#endif // RPL_DEBUG +} + diff --git a/private/net/svcdlls/rpl/server/resume.h b/private/net/svcdlls/rpl/server/resume.h new file mode 100644 index 000000000..12c791d4a --- /dev/null +++ b/private/net/svcdlls/rpl/server/resume.h @@ -0,0 +1,61 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + resume.h + +Abstract: + + Describes layout of JET database table used for RESUME structures. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#ifdef RPLRESUME_ALLOCATE +#define EXTERN_RESUME +#define INIT_RESUME( _x) = _x +#else +#define EXTERN_RESUME extern +#define INIT_RESUME( _x) +#endif + +// +// Indices of entries in ResumeTable[] - resume key array. +// +#define RESUME_ResumeHandle 0 +#define RESUME_ResumeType 1 +#define RESUME_ResumeValue 2 +#define RESUME_ServerHandle 3 +#define RESUME_TABLE_LENGTH 4 + +RPL_COLUMN_INFO ResumeTable[] +#ifdef RPLRESUME_ALLOCATE + = { + { "ResumeHandle", JET_coltypLong, 0}, // for enumeration + { "ResumeType", JET_coltypLong, 0}, // type of operation + { "ResumeValue", JET_coltypBinary, 0}, // where to restart + { "ServerHandle", JET_coltypLong, 0} +} +#endif // RPLRESUME_ALLOCATE +; + +#define RESUME_INDEX_ResumeHandle "foo" // + ResumeHandle +#define RESUME_INDEX_ServerHandle "goo" // + ServerHandle + +#define RESUME_TABLE_NAME "Resume" +#define RESUME_TABLE_PAGE_COUNT 5 // initial number of 4K pages +#define RESUME_TABLE_DENSITY 100 // initial density + +EXTERN_RESUME JET_TABLEID ResumeTableId; + diff --git a/private/net/svcdlls/rpl/server/rpldata.h b/private/net/svcdlls/rpl/server/rpldata.h new file mode 100644 index 000000000..26447bf68 --- /dev/null +++ b/private/net/svcdlls/rpl/server/rpldata.h @@ -0,0 +1,161 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + rpldata.h + +Abstract: + + Remote initial Program Load service global variables (external & + definitions). + + Provides similar functionality to rplglob.c & rmapext.h in LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +// +// rplmain.c will #include this file with RPLDATA_ALLOCATE defined. +// That will cause each of these variables to be allocated. +// +#ifdef RPLDATA_ALLOCATE +#define EXTERN +#define INIT( _x) = _x +#else +#define EXTERN extern +#define INIT( _x) +#endif + +#ifdef RPL_DEBUG +EXTERN DWORD RG_Debug; +EXTERN DWORD RG_BootCount; +#endif // RPL_DEBUG + + +EXTERN DWORD RG_Error; +EXTERN DWORD RG_Null INIT( 0); // used in bbcfile for empty entries in string tables + +// +// Synchronization Object for RPL server code +// + +EXTERN CRITICAL_SECTION RG_ProtectRcbList; +EXTERN CRITICAL_SECTION RG_ProtectServerHandle; +EXTERN CRITICAL_SECTION RG_ProtectCurrentStatus; // service status + + +EXTERN DWORD RG_ServerHandle; // service handle returned to client +EXTERN DWORD RG_AdapterPolicy; // whether to log AdapterName-s of unknown clients +EXTERN DWORD RG_BackupInterval; // how often to do database backup (in hours) +EXTERN RPL_SESSION RG_RequestSession; // jet handles for request threads +EXTERN RPL_SESSION RG_WorkerSession; // jet handles for worker threads +EXTERN RPL_SESSION RG_ApiSession; // jet handles for api threads +EXTERN BOOL RG_DetachDatabase; // do we need to detach jet database +EXTERN PCHAR RG_Mdb; // points to rplsvc.mdb +EXTERN PCHAR RG_BackupPath; // points to database backup path +EXTERN JET_INSTANCE RG_Instance; +EXTERN BOOL RG_InstanceAllocated; +EXTERN CRITICAL_SECTION RG_ProtectRequestSession; +EXTERN CRITICAL_SECTION RG_ProtectWorkerSession; +EXTERN CRITICAL_SECTION RG_ProtectDatabase; // used for ApiSession also + + +EXTERN HANDLE RG_TerminateNowEvent; + +// +// Other globals of the actual ripl server code: +// + +EXTERN SERVICE_STATUS RG_ServiceStatus; +EXTERN SERVICE_STATUS_HANDLE RG_ServiceStatusHandle; +EXTERN SC_HANDLE RG_ServiceHandle; +EXTERN DWORD RG_Tasks; +EXTERN CRITICAL_SECTION RG_ProtectServiceStatus; + +EXTERN HANDLE RG_MemoryHandle; // for memory "owned" by main thread +EXTERN HANDLE RG_MessageHandle; + +EXTERN PRPL_REQUEST_PARAMS RG_pRequestParams; +EXTERN CRITICAL_SECTION RG_ProtectRequestList; + + +EXTERN DWORD RG_MaxWorkerCount; // upper limit on number of worker threads +EXTERN DWORD RG_WorkerCount; // number of worker threads +EXTERN HANDLE RG_EventWorkerCount; // event for changes in the above +EXTERN CRITICAL_SECTION RG_ProtectWorkerCount; + +EXTERN CRITICAL_SECTION RG_ProtectTerminationList; +EXTERN PTERM_LIST RG_TerminationListBase; // base of termination list + +// +// The following globals are defined together with their default values. +// These values may be overriden by user in lanman.ini & command line. +// + +EXTERN WCHAR RG_Directory[ MAX_PATH]; // path to rpl service disk data +EXTERN DWORD RG_DirectoryLength; // length of the above path + +EXTERN BOOL RG_ReadChecksum; // status set while files chksmmed +EXTERN PBYTE RG_CodePageBuffer; // "pCodePage" +EXTERN DWORD RG_CodePageSize; // "cbCodePage" + +// +// This value contains the current adapter policy and also the startup flags +// + +EXTERN DWORD RG_AdapterPolicy; + +// +// If we ever separate DLC-RPL server from FILE-RPL server, then +// RG_ComputerName should be a pointer to FILE-RPL server name. +// +EXTERN WCHAR RG_ComputerName[ MAX_COMPUTERNAME_LENGTH + 1]; + +EXTERN PWCHAR RG_UncRplfiles; // UNC name sent to rpl client +EXTERN PWCHAR RG_DiskRplfiles; // local path used in disk operations + +EXTERN PWCHAR RG_DiskBinfiles; // local path to binfiles root + + +// +// The following group of globals should be constant and they are +// initialized only once, at load exe time (not every time at +// start service time). +// + +// +// NLS patches of RPLBOOT.SYS and DLCLOADR.COM +// + +EXTERN DWORD RG_MessageTable[] +#ifdef RPLDATA_ALLOCATE + = { + NERR_BadDosRetCode, + NERR_ProgNeedsExtraMem, + NERR_BadDosFunction, + NERR_RemoteBootFailed, + NERR_BadFileCheckSum, + NERR_NoRplBootSystem +} +#endif // RPLDATA_ALLOCATE +; + +#define MESSAGE_TABLE_LENGTH 6 // number of entries in the array above +#define DBCS_MESSAGE_BUFFER_SIZE (MESSAGE_TABLE_LENGTH * DBCS_SINGLE_MESSAGE_BUFFER_SIZE) + +EXTERN PBYTE RG_DbcsMessageBuffer INIT( NULL); + +#undef EXTERN + + diff --git a/private/net/svcdlls/rpl/server/rplmain.c b/private/net/svcdlls/rpl/server/rplmain.c new file mode 100644 index 000000000..2d8c568e3 --- /dev/null +++ b/private/net/svcdlls/rpl/server/rplmain.c @@ -0,0 +1,982 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + rplmain.c + +Abstract: + + Contains RPL_main(), RPL service entry point. Initializes and shuts down + RPL service. + + Provides similar functionality to rplservr.c in LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#define RPLDATA_ALLOCATE +#include "local.h" +#undef RPLDATA_ALLOCATE +#include "request.h" +#include "database.h" +#include "debug.h" +#include "apisec.h" +#include <rplnames.h> // RPL_INTERFACE_NAME +#include "rplsvc_s.h" // rplsvc_ServerIfHandle +#include "setup.h" // SetupAction() + +#define WCSLEN( _x_) ((DWORD) ( sizeof(_x_)/sizeof(WCHAR) - 1)) +#define NET_MSG_FILE L"netmsg.dll" +#define RPLFILES_STRING L"RPLFILES" +#define BINFILES_STRING L"\\BINFILES\\" +#define RPL_DEFAULT_DIRECTORY L"%SystemRoot%\\rpl\\" +#define RPL_SERVICE_NAME L"RemoteBoot" + +#define RPL_SECURITY_OBJECT_CREATED 0x1 +#define RPL_RPC_SERVER_STARTED 0x2 + + +DWORD RplMessageGet( + IN DWORD MessageId, + OUT LPWSTR buffer, + IN DWORD Size + ) +/*++ + +Routine Description: + + Fills in the unicode message corresponding to a given message id, + provided that a message can be found and that it fits in a supplied + buffer. + +Arguments: + + MessageId - message id + buffer - pointer to caller supplied buffer + Size - size (always in bytes) of supplied buffer + +Return Value: + + Count of characters, not counting the terminating null character, + returned in the buffer. Zero return value indicates failure. + +--*/ +{ + DWORD length; + LPVOID lpSource; + DWORD dwFlags; + + if ( MessageId < NERR_BASE) { + // + // Get message from system. + // + lpSource = NULL; // redundant step according to FormatMessage() spec + dwFlags = FORMAT_MESSAGE_FROM_SYSTEM; + + } else { + // + // Get message from netmsg.dll. + // + lpSource = (LPVOID)RG_MessageHandle; + dwFlags = FORMAT_MESSAGE_FROM_HMODULE; + } + +//#define RPL_ELNK +#ifdef RPL_ELNK + wcscpy( buffer, L"NET2500: "); + buffer[ 6] = L'0' + MessageId - NERR_BadDosRetCode; + buffer += 9; + Size -= 9 * sizeof(WCHAR); +#endif + + length = FormatMessage( + dwFlags, // dwFlags + lpSource, // lpSource + MessageId, // MessageId + 0, // dwLanguageId + buffer, // lpBuffer + Size, // nSize + NULL // lpArguments + ); + + if ( length == 0) { + RG_Error = GetLastError(); + RplReportEvent( NELOG_RplMessages, NULL, 0, NULL); + RPL_RETURN( 0); + } +#ifdef RPL_ELNK + length += 9; +#endif + return( length); +} + + +BOOL RplInitMessages( VOID) +/*++ + +Routine Description: + Creates an array of NLS (DBCS ??) messages for RPLBOOT.SYS. + +Arguments: + None. + +Return Value: + TRUE if success, FALSE otherwise. + +--*/ +{ + WCHAR UnicodeString[ MAX_PATH]; + DWORD UnicodeStringLength; + CHAR DbcsString[ MAX_PATH]; + PBYTE pByte; + DWORD Index; + DWORD DbcsStringSize; // not including terminal null byte + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOWINIT,( "++InitMessages")); + + RG_DbcsMessageBuffer = RplMemAlloc( RG_MemoryHandle, DBCS_MESSAGE_BUFFER_SIZE); + if ( RG_DbcsMessageBuffer == NULL) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + + // + // read NLS messages from message file to patch table + // + for ( Index = 0, pByte = RG_DbcsMessageBuffer; + Index < MESSAGE_TABLE_LENGTH; + Index++, pByte += DBCS_SINGLE_MESSAGE_BUFFER_SIZE) { + + UnicodeStringLength = RplMessageGet( RG_MessageTable[ Index], + UnicodeString, sizeof( UnicodeString)); + if ( UnicodeStringLength == 0) { + return( FALSE); + } + // + // Null terminate the string - redundant ? + // + UnicodeString[ UnicodeStringLength] = 0; + + DbcsStringSize = WideCharToMultiByte( + CP_OEMCP, + 0, + UnicodeString, + UnicodeStringLength, + DbcsString, + sizeof( DbcsString), + NULL, // no default character + NULL // no default character flag + ); + if ( DbcsStringSize == 0) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } +// #define TEST_MESSAGE_TOO_LONG +#ifdef TEST_MESSAGE_TOO_LONG + if ( DbcsStringSize > 48) { + DbcsStringSize = 48; + } +#else + // + // If message is too long truncate it - leaving one char for the + // end of string mark of MS-DOS ('$'). + // + if ( DbcsStringSize >= DBCS_SINGLE_MESSAGE_BUFFER_SIZE) { + DbcsStringSize = (DWORD)(DBCS_SINGLE_MESSAGE_BUFFER_SIZE-1); + } +#endif + memcpy( pByte, DbcsString, DbcsStringSize); + // + // The messages returned by DosGetMsg are not nul terminated => + // reset the whole message buffer with end of string marks of MS-DOS. + // + memset( pByte + DbcsStringSize, '$', DBCS_SINGLE_MESSAGE_BUFFER_SIZE - DbcsStringSize); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOWINIT,( "--InitMessages")); + return( TRUE); +} + + + +BOOL RplMakeSingleShare( + IN LPWSTR NetworkName, + IN LPWSTR Path, + IN LPWSTR Comment + ) +/*++ + +Routine Description: + + Sets up a file share. It also checks that the existing share is + valid (points to the right directory). + +Arguments: + + NetworkName - network name of the shared resource + Path - local path of the shared resource + Comment - comment about the shared resource + +Return Value: + + TRUE if successful, else FALSE. + +--*/ +{ + SHARE_INFO_2 ShareInfo2; + PSHARE_INFO_2 pShareInfo2 = NULL; + BOOL useNetApiBufferFree = TRUE; + DWORD Error; + + // + // Check if we have already the share. + // + Error = NetShareGetInfo( NULL, NetworkName, 2, (LPBYTE *)&pShareInfo2); + + if ( Error == NO_ERROR) { + // + // If the path points to the right place, assume share is O.K. + // and return from here. Else, delete this invalid share. + // + if ( !wcscmp( pShareInfo2->shi2_path, Path )) { + Error = NO_ERROR; + goto cleanup; + + } else if ( (Error = NetShareDel( NULL, NetworkName, 0)) + != NO_ERROR) { + goto cleanup; + } + + } else if ( Error != NERR_NetNameNotFound) { + // Unexpected return code from NetShareGetInfo. Bail out. + goto cleanup; + } + + // + // If we arrive here we either did not have the share or we have + // just deleted the invalid share. Now set up the correct share. + // + + ShareInfo2.shi2_netname = NetworkName; + ShareInfo2.shi2_path = Path; + ShareInfo2.shi2_remark = Comment; + + ShareInfo2.shi2_type = STYPE_DISKTREE; + ShareInfo2.shi2_permissions = 0x3F; // no permission bit set + ShareInfo2.shi2_max_uses = SHI_USES_UNLIMITED; + ShareInfo2.shi2_current_uses = 0; + ShareInfo2.shi2_passwd = NULL; + + Error = NetShareAdd( NULL, 2, (LPBYTE)&ShareInfo2, NULL); + +cleanup: + + if ( pShareInfo2) { + NetApiBufferFree( (LPVOID) pShareInfo2); + } + + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert,( "Error = %d", Error)); + return( FALSE); + } + return( TRUE); +} + + + +BOOL RplConfigured( VOID) +/*++ + +Routine Description: + + Verifies that FILE server has been configured to serve RPL clients + by checking for the existence of the group RPLUSER, a group + that gets created by RPLINST, the last phase of RPL configuration. + +Arguments: + None. + +Return Value: + +--*/ +{ + LPBYTE pbyte = NULL; + DWORD Error; + + Error = NetGroupGetInfo( NULL, RPLUSER_GROUP, 0, &pbyte); + + if ( pbyte != NULL) { + NetApiBufferFree( pbyte); + } + + if (Error == NERR_GroupNotFound) { +#ifdef NOT_YET + Error = NERR_RplNotRplServer; // error mapping +#else // NOT_YET + KdPrint(( "[RplSvc] %ws group not found\n", RPLUSER_GROUP)); + Error = NO_ERROR; // BUGBUG trundle along for now +#endif // NOT_YET + } + + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert,( "Error = %d", Error)); + RG_Error = NERR_RplNotRplServer; + return( FALSE); + } + return( TRUE); +} + + +BOOL RplInit( OUT PDWORD pStartup) +/*++ + pStartup - Startup actions flag, read from registry. +--*/ +{ + DWORD Error; + DWORD Size; + SC_HANDLE ControlManagerHandle; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++RplInit")); + + Error = RplMemInit( &RG_MemoryHandle); + if ( Error != NO_ERROR) { + RG_Error = Error; + return( FALSE); + } + RplDump( RG_DebugLevel & RPL_DEBUG_MEMORY,( + "MakeReinit: RG_MemoryHandle=0x%x", RG_MemoryHandle)); + + RG_DirectoryLength = sizeof(RG_Directory)/sizeof(WCHAR); + if ( RplRegRead( pStartup, &RG_BackupInterval, &RG_MaxWorkerCount, + RG_Directory, &RG_DirectoryLength) != NO_ERROR) { + RG_Error = NERR_RplBadRegistry; + return( FALSE); + } + + if ( !RplDbInit()) { + RG_Error = NERR_RplBadDatabase; + return( FALSE); + } + + ControlManagerHandle = OpenSCManager( NULL, L"ServicesActive", 0); + if ( ControlManagerHandle == NULL) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + + RG_ServiceHandle = OpenService( ControlManagerHandle, + RPL_SERVICE_NAME, + SERVICE_STOP // desired access + ); + if ( RG_ServiceHandle == NULL) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + + RG_TerminateNowEvent = CreateEvent( + NULL, // No security attributes + TRUE, // Must be manually reset + FALSE, // Initially not signaled + NULL); // No name + if ( RG_TerminateNowEvent == NULL ) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + +#ifndef RPL_NO_SERVICE + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } +#endif + + // + // We use manual reset. With automatic reset, when two request threads + // are both waiting for this event, if several worker threads exit at + // once, only one request thread may be awaken. Other request thread + // may stay asleep for a long time, until next worker thread exits. + // + RG_EventWorkerCount = CreateEvent( + NULL, // no security attributes + TRUE, // use manual reset + FALSE, // initial value is not-signalled + NULL); // no name + if ( RG_EventWorkerCount == NULL) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + + if ( !RplConfigured()) { + return( FALSE); + } + + // + // Note that upon successful return: Size == wcslen( RG_ComputerName) + // + Size = sizeof( RG_ComputerName); + if ( !GetComputerName( RG_ComputerName, &Size)) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + RPL_ASSERT( Size == wcslen( RG_ComputerName)); + + // + // Initialize RG_UncRplfiles which is used in fit file replacements + // and RG_DiskRplfiles which is used for api disk operations. + // + Size *= sizeof( WCHAR); + Size += sizeof(DOUBLE_BACK_SLASH_STRING) + sizeof(RPLFILES_STRING); + RG_UncRplfiles = RplMemAlloc( RG_MemoryHandle, Size); + if ( RG_UncRplfiles == NULL) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + wcscpy( RG_UncRplfiles, DOUBLE_BACK_SLASH_STRING); + wcscat( RG_UncRplfiles, RG_ComputerName); + wcscat( RG_UncRplfiles, L"\\"); + wcscat( RG_UncRplfiles, RPLFILES_STRING); + + Size = RG_DirectoryLength * sizeof(WCHAR) + sizeof(RPLFILES_STRING); + RG_DiskRplfiles = RplMemAlloc( RG_MemoryHandle, Size); + if ( RG_DiskRplfiles == NULL) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + wcscpy( RG_DiskRplfiles, RG_Directory); + wcscat( RG_DiskRplfiles, RPLFILES_STRING); + + Size += WCSLEN( BINFILES_STRING) * sizeof(WCHAR); + RG_DiskBinfiles = RplMemAlloc( RG_MemoryHandle, Size); + if ( RG_DiskBinfiles == NULL) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } + wcscpy( RG_DiskBinfiles, RG_DiskRplfiles); + wcscat( RG_DiskBinfiles, BINFILES_STRING); + +#ifndef RPL_NO_SERVICE + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } +#endif + + // + // Load file containing network messages. + // + RG_MessageHandle = LoadLibrary( NET_MSG_FILE); + if ( RG_MessageHandle == NULL) { + RG_Error = GetLastError(); + RplReportEvent( NELOG_Init_OpenCreate_Err, NET_MSG_FILE, + sizeof( RG_Error), (PBYTE)&RG_Error); + RPL_RETURN( FALSE); + } + + // + // Share the default rplfiles share, should have been done earlier ? + // + if ( !RplMakeSingleShare( RPLFILES_STRING, RG_DiskRplfiles, RPL_REMARK)){ + RG_Error = NERR_RplRplfilesShare; + return( FALSE); + } + +#ifndef RPL_NO_SERVICE + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RG_Error = GetLastError(); + RPL_RETURN( FALSE); + } +#endif + + // + // RplInitMessages() must be called before RplStartAdapters() because + // it initializes RG_DbcsMessageBuffer() which must be present as soon + // as adapters are started. Otherwise, a very quick boot request by + // RPL client would trap the service in RplMakePatch(). + // + if ( !RplInitMessages()) { + return( FALSE); + } + + if ( !RplStartAdapters()) { + return( FALSE); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--RplInit")); + return( TRUE); +} + + +VOID RplCleanup( VOID) +/*++ + +Routine Description: + + Cleanup all global resources. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + DWORD ErrorCode = NO_ERROR; + + RplDbTerm(); + // + // Free RPL critical sections. + // + DeleteCriticalSection( &RG_ProtectRcbList); + DeleteCriticalSection( &RG_ProtectTerminationList); + DeleteCriticalSection( &RG_ProtectRequestList); + DeleteCriticalSection( &RG_ProtectWorkerCount); + DeleteCriticalSection( &RG_ProtectServiceStatus); + DeleteCriticalSection( &RG_ProtectServerHandle); + DeleteCriticalSection( &RG_ProtectRequestSession); + DeleteCriticalSection( &RG_ProtectWorkerSession); + DeleteCriticalSection( &RG_ProtectDatabase); +} + + + +VOID RplControlHandler( IN DWORD OpCode) +/*++ + +Routine Description: + + Process and respond to a control signal from the service controller. + +Arguments: + + OpCode - Supplies a value which specifies the action for the RPL + service to perform. + +Return Value: + + None. + +--*/ +{ + KdPrint(( "[RplSvc]++ ControlHandler\n")); + + switch (OpCode) { + + case SERVICE_CONTROL_PAUSE: +#ifdef RPL_DEBUG + DbgUserBreakPoint(); // for debugging +#endif + EnterCriticalSection( &RG_ProtectServiceStatus); + RG_ServiceStatus.dwCurrentState = SERVICE_PAUSED; + LeaveCriticalSection( &RG_ProtectServiceStatus); + break; + + case SERVICE_CONTROL_CONTINUE: + EnterCriticalSection( &RG_ProtectServiceStatus); + RG_ServiceStatus.dwCurrentState = SERVICE_RUNNING; + LeaveCriticalSection( &RG_ProtectServiceStatus); + break; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + + if (RG_ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) { + + KdPrint(( "[RplSvc]ControlHandler: stopping remote boot service...\n")); + + RG_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + RG_ServiceStatus.dwCheckPoint = 1; + RG_ServiceStatus.dwWaitHint = RPL_WAIT_HINT_TIME; + + // + // Send the status response. + // +#ifndef RPL_NO_SERVICE + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RplDump( ++RG_Assert, ( "Error = ", RG_Error)); + NOTHING; // ignore this error + } +#endif + + if (! SetEvent( RG_TerminateNowEvent)) { + + KdPrint(( "[RplSvc]ControlHandler: error setting" + " TerminateNowEvent, error=%d\n", + GetLastError())); + RPL_ASSERT( FALSE); + } + + return; + } + break; + + case SERVICE_CONTROL_INTERROGATE: + break; + + default: + KdPrint(( + "[RplSvc] ControlHandler: unknown remote boot service control," + " OpCode=0x%x\n", + OpCode)); + break; + } + + // + // Send the status response. + // +#ifndef RPL_NO_SERVICE + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RplDump( ++RG_Assert, ( "Error = ", GetLastError())); + NOTHING; // ignore this error + } +#endif +} + + + +VOID RplInitGlobals( VOID) +{ + // + // Initializes all global variables that are "variable". + // + + RG_WorkerCount = 0; + RG_TerminationListBase = NULL; + RG_MessageHandle = NULL; +#ifdef RPL_DEBUG + RG_Debug = (DWORD)-1; + RG_BootCount = 0; +#endif // RPL_DEBUG + + // + // Values of globals below may be overriden by user in lanman.ini & command line. + // + + RG_Directory[ 0] = 0; + RG_DirectoryLength = 0; + RG_ReadChecksum = FALSE; + RG_CodePageBuffer = NULL; + RG_CodePageSize = 0; + + RG_TerminateNowEvent = NULL; + + RG_ComputerName[ 0] = 0; + RG_UncRplfiles = NULL; + RG_DiskRplfiles = NULL; + + RG_ServerHandle = 0; + + RG_pRequestParams = NULL; + + InitializeCriticalSection( &RG_ProtectRcbList); + InitializeCriticalSection( &RG_ProtectTerminationList); + InitializeCriticalSection( &RG_ProtectRequestList); + InitializeCriticalSection( &RG_ProtectWorkerCount); + InitializeCriticalSection( &RG_ProtectServiceStatus); + InitializeCriticalSection( &RG_ProtectServerHandle); + InitializeCriticalSection( &RG_ProtectRequestSession); + InitializeCriticalSection( &RG_ProtectWorkerSession); + InitializeCriticalSection( &RG_ProtectDatabase); +} + + +VOID ShutdownRequestParams( VOID) +{ + PRPL_REQUEST_PARAMS pRequestParams; + DWORD status; + + for ( pRequestParams = RG_pRequestParams; + pRequestParams != NULL; + pRequestParams = pRequestParams->pRequestParams) { + if ( pRequestParams->ThreadHandle != NULL) { + status = WaitForSingleObject( pRequestParams->ThreadHandle, INFINITE); + if ( status != 0) { + RplDump( ++RG_Assert, ( "pRequestParams=0x%x, status=0x%x", + pRequestParams, status==WAIT_FAILED ? GetLastError() : status)); + } + if ( !CloseHandle( pRequestParams->ThreadHandle)) { + RplDump( ++RG_Assert, ( "pRequestParams=0x%x, error=%d", + pRequestParams, GetLastError())); + } + pRequestParams->ThreadHandle = NULL; + } + } +} + + +VOID RPL_main( + IN DWORD argc, + IN LPWSTR argv[] + ) +/*++ + +Routine Description: + + Main procedure of the program. This is the main RPL worker thread. + Purpose: + + - start the initialization thread + - register signal handler + +Arguments: + + argc - parameter count + argv - array of pointers to parameters + +Return Value: + + None. + +--*/ +{ + DWORD Error; + DWORD InitState; + DWORD StartupFlags; + + UNREFERENCED_PARAMETER( argc); + UNREFERENCED_PARAMETER( argv); + + InitState = 0; + + RG_Error = NO_ERROR; + RG_ServiceStatus.dwServiceType = SERVICE_WIN32; + RG_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + RG_ServiceStatus.dwControlsAccepted = 0; + RG_ServiceStatus.dwCheckPoint = 1; + RG_ServiceStatus.dwWaitHint = RPL_WAIT_HINT_TIME; + + // This should be the FIRST thing we do. + +#ifdef RPL_DEBUG + RplDebugInitialize(); +#endif // RPL_DEBUG + + + SET_SERVICE_EXITCODE( + RG_Error, + RG_ServiceStatus.dwWin32ExitCode, + RG_ServiceStatus.dwServiceSpecificExitCode + ); + + RplInitGlobals(); // make sure we do not trap during cleanup + +#ifndef RPL_NO_SERVICE + RG_ServiceStatusHandle = RegisterServiceCtrlHandler( + SERVICE_RIPL, + RplControlHandler + ); + if( RG_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)NULL) { + RG_Error = GetLastError(); + RPL_ASSERT( FALSE); + goto main_exit; + } + + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RG_Error = GetLastError(); + RPL_ASSERT( FALSE); + goto main_exit; + } +#endif + + if ( !RplInit( &StartupFlags)) { + goto main_exit; + } + + // + // Create remote boot service security object + // + Error = RplCreateSecurityObject(); + if ( Error != NO_ERROR) { + RG_Error = Error; + goto main_exit; + } + InitState |= RPL_SECURITY_OBJECT_CREATED; + + // + // Initialize the schedule service to receive RPC requests. + // Note that interface name is defined in rplsvc.idl file. + // + Error = NetpStartRpcServer( RPL_INTERFACE_NAME, rplsvc_ServerIfHandle); + if ( Error != NO_ERROR) { + RG_Error = Error; + RPL_ASSERT( FALSE); + goto main_exit; + } + InitState |= RPL_RPC_SERVER_STARTED; + + // + // We are done with starting the Remoteboot service. Tell Service + // Controller our new status. + // + + RG_ServiceStatus.dwCurrentState = SERVICE_RUNNING; + RG_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE; + RG_ServiceStatus.dwCheckPoint = 0; + RG_ServiceStatus.dwWaitHint = 0; + +#ifndef RPL_NO_SERVICE + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RG_Error = GetLastError(); + RPL_ASSERT( FALSE); + goto main_exit; + } +#endif + + // + // The server is running. If the registry specified any + // special startup actions, perform them now. Note that + // it will not be possible to stop the service before these + // actions are complete. Also, note that SetupAction() does + // all necessary event logging & properly updates its argument + // even in case of failures. + // + + if ( StartupFlags & RPL_SPECIAL_ACTIONS) { + DWORD NewStartupFlags = StartupFlags; + (VOID)SetupAction( &NewStartupFlags, FALSE); // partial backup if any + if ( NewStartupFlags != StartupFlags) { + (VOID)RplRegSetPolicy( NewStartupFlags); + } + } + + // + // We started successfully. Wait for somebody to tell us it + // is time to die. + // + + RplDump( RG_DebugLevel & RPL_DEBUG_SERVICE,( + "Successful startup. Wait on TerminateNowEvent.")); + +#define ONE_HOUR (60 * 60 * 1000L) // in milliseconds + for ( ; ; ) { + DWORD Status; + Status = WaitForSingleObject( RG_TerminateNowEvent, + RG_BackupInterval == 0 ? INFINITE : RG_BackupInterval * ONE_HOUR); + if ( Status != WAIT_TIMEOUT) { + RPL_ASSERT( Status == 0); +#ifdef NOT_YET + // + // Backup is disabled here because in the field users will most + // likely use CTRL-ALT-DEL to shutdown the system & RPL service. + // In that case we do no enter this code path and to keep all + // remoteboot shutdown sequences similar backup is disabled here + // as well. By not doing backup here we also avoid problems due + // to full backup taking too long or incremental backup being + // buggy (jet bugs). + // + // + // In case of regular shutdown we do incremental backup so that + // user does not get an impression we are "stuck". Also, the + // backup is done now & not later in RplDbTerm() just in case + // we get in a state where we hang for ever in + // ShutdownWorkerParams(). + // + RplBackupDatabase( Status == 0 ? FALSE : TRUE); +#endif + break; + } + // + // Do full backup if not on shutdown path. + // + RplBackupDatabase( TRUE); + } + +main_exit: + + // + // If we come here, then it is time to die. Wait until all + // our children (request threads) have been terminated. + // And of course, request threads will in turn wail until all + // of their children (worker threads) get terminated. + // + // Because of a cumbersome inherited Rpld* interface, request + // threads may wait for ever on Rpld* events. The only way to get + // them out is to close the adapters. + // + RplCloseAdapters(); // cumbersome Rpld* interface + + ShutdownRequestParams(); + + // + // Close RPC server. Jet resources must be available at this + // point because rundown routines need them. + // + if ( InitState & RPL_RPC_SERVER_STARTED) { + Error = NetpStopRpcServer( rplsvc_ServerIfHandle); + if ( Error != NO_ERROR) { + RG_Error = Error; + RPL_ASSERT( FALSE); + } + } + + if ( InitState & RPL_SECURITY_OBJECT_CREATED) { + RplDeleteSecurityObject(); + } + + + RplCleanup(); // nobody alive but us now, clean up and die + +#ifdef RPL_DEBUG + RplDebugDelete(); +#endif // RPL_DEBUG + + // + // Set the service state to uninstalled, and tell the service controller. + // + + RG_ServiceStatus.dwCurrentState = SERVICE_STOPPED; + RG_ServiceStatus.dwControlsAccepted = 0; + + SET_SERVICE_EXITCODE( + RG_Error, + RG_ServiceStatus.dwWin32ExitCode, + RG_ServiceStatus.dwServiceSpecificExitCode + ); + + RG_ServiceStatus.dwCheckPoint = 0; + RG_ServiceStatus.dwWaitHint = 0; + +#ifndef RPL_NO_SERVICE + if ( !SetServiceStatus( RG_ServiceStatusHandle, &RG_ServiceStatus)) { + RplDump( ++RG_Assert, ( "Error = ", GetLastError())); + NOTHING; // ignore this error + } +#endif +} + + +BOOL RplServiceAttemptStop( VOID) +{ + SERVICE_STATUS ServiceStatus; + if ( ControlService( RG_ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus)) { + return( TRUE); // all done + } + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + if ( ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) { + // + // We arrive here if control handler already received + // SERVICE_CONTROL_STOP request from somewhere else. + // + return( TRUE); + } + return( FALSE); +} + + + + diff --git a/private/net/svcdlls/rpl/server/rplrest.c b/private/net/svcdlls/rpl/server/rplrest.c new file mode 100644 index 000000000..f570bb866 --- /dev/null +++ b/private/net/svcdlls/rpl/server/rplrest.c @@ -0,0 +1,36 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rplrest.c + +Abstract: + + This file contains program to test RPL JetRestore() call. + +Author: + + Vladimiv Z. Vulovic (vladimv) 17-June-1994 + +Environment: + + User Mode - Win32 + +Revision History: + +--*/ + +#include "local.h" + +#define BACKUP_PATH "d:\\nt689f\\rpl\\backup" + + +DWORD _CRTAPI1 main( int argc, char **argv) +{ + JET_ERR JetError; + JetError = JetRestore( BACKUP_PATH, 0, NULL, 0); + printf( "JetError=%d\n", JetError); + return(0); +} diff --git a/private/net/svcdlls/rpl/server/rplsvc.c b/private/net/svcdlls/rpl/server/rplsvc.c new file mode 100644 index 000000000..34a377a11 --- /dev/null +++ b/private/net/svcdlls/rpl/server/rplsvc.c @@ -0,0 +1,122 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + rplsvc.c + +Abstract: + + This is the main routine for the Remote Program Load Service. + +Author: + + Vladimir Z. Vulovic (vladimv) 10 - Februrary - 1993 + +Environment: + + User Mode - Win32 + +Revision History: + + 10-Feb-1993 vladimv + created + +--*/ + +#include "local.h" +#include <rpcutil.h> // NetpInitRpcServer() +#include <secobj.h> // NetpCreateWellKnownSids() + +// +// Dispatch table for all services. Passed to NetServiceStartCtrlDispatcher. +// +// Add new service entries here. +// + +SERVICE_TABLE_ENTRY RPLServiceDispatchTable[] = { + { SERVICE_RIPL, RPL_main }, + { NULL, NULL } +}; + + + +VOID _CRTAPI1 +main ( + VOID + ) + +/*++ + +Routine Description: + + This is a main routine for the LANMan Remote Program Load Services. + + It basically sets up the ControlDispatcher and, on return, exits from + this main thread. The call to NetServiceStartCtrlDispatcher does + not return until all services have terminated, and this process can + go away. + + It will be up to the ControlDispatcher thread to start/stop/pause/continue + any services. If a service is to be started, it will create a thread + and then call the main routine of that service. + + +Arguments: + + Anything passed in from the "command line". Currently, NOTHING. + +Return Value: + + NONE + +Note: + + +--*/ +{ + NTSTATUS ntstatus; + + // + // Create well-known SIDs + // + if (! NT_SUCCESS (ntstatus = NetpCreateWellKnownSids(NULL))) { + KdPrint(( + "[RplSvc] main: Failed to create well-known SIDs, ntstatus=0x%x\n", + ntstatus + )); + return; + } + + + // + // Initialize the RpcServer Locks. + // + + NetpInitRpcServer(); + + // + // Call ServiceStartCtrlDispatcher to set up the control interface. + // The API won't return until all services have been terminated. At that + // point, we just exit. + // + +#ifndef RPL_NO_SERVICE + if ( !StartServiceCtrlDispatcher ( RPLServiceDispatchTable)) { + DWORD error = GetLastError(); + // + // RPL service will eventually go in the same exe with all + // other services. Thus, no need here to log anything. + // + KdPrint(( + "[RplSvc] main: StartServiceCtrlDispatcher() fails with error=%d\n", + error + )); + } +#else + RPL_main( 1, (LPWSTR *)NULL); +#endif + + ExitProcess(0); +} diff --git a/private/net/svcdlls/rpl/server/rplsvc.rc b/private/net/svcdlls/rpl/server/rplsvc.rc new file mode 100644 index 000000000..1fffb1423 --- /dev/null +++ b/private/net/svcdlls/rpl/server/rplsvc.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "RemoteBoot Service DLL" +#define VER_INTERNALNAME_STR "RPLSVC.DLL" +#define VER_ORIGINALFILENAME_STR "RPLSVC.DLL" + +#include "common.ver" + diff --git a/private/net/svcdlls/rpl/server/security.c b/private/net/svcdlls/rpl/server/security.c new file mode 100644 index 000000000..2827437d9 --- /dev/null +++ b/private/net/svcdlls/rpl/server/security.c @@ -0,0 +1,1005 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + security.c + +Abstract: + + Security addons to the tree-manipulation module + for the RPL service. + +Author: + + Jon Newman (jonn) 16 - February - 1994 + +Revision History: + + Jon Newman (jonn) 16 - February - 1994 + Added RplGrant*Perms primitives + + Vladimir Z. Vulovic (vladimv) 06 - May - 1994 + Security fix: added new api + major reorg. + +--*/ + + +#include "local.h" +#include "rpldb.h" // Call(), CallM() +#include "db.h" +#include "dblib.h" // RplFilterFirst() +#include "tree.h" +#include "treei.h" +#include "wksta.h" // WKSTA_WkstaName +#include "profile.h" // PROFILE_ProfileName +#include <ntseapi.h> +#include <ntrtl.h> // RtlAllocateAndInitializeSid +#include <ntlsa.h> +#include <ntsam.h> +#include <nturtl.h> // see IsNTFS +#include <lmserver.h> // NetServerGetInfo + + +typedef enum _RPL_SD_BLOCK_TYPE { + + RPL_SD_BLOCK_TYPE_ADMINONLY = 0,// Only RPLADMIN gets access + + RPL_SD_BLOCK_TYPE_ALLUSERS, // RPLADMIN gets full access, RPLUSER + // gets RX access + + RPL_SD_BLOCK_TYPE_ONEUSER // RPLADMIN gets full access, one + // wksta account gets RWXCDA access +} RPL_SD_BLOCK_TYPE; + +/* + * This is the block of information which is retained between the recursive + * calls in a single RplDoTree run. It remembers the SECURITY_DESCRIPTOR + * which was assigned to the last file/directory, so if the next + * file/directory wants the same permissions (as is usually the case) + * we do not have to fetch everything all over again. It also contains + * some information about what kind of SECURITY_DESCRIPTOR is currently + * stored, plus items needed to get a different SECURITY_DESCRIPTOR. + */ +typedef struct _RPL_SD_BLOCK { + BOOL SkipThisTree; // must be the first element + PSECURITY_DESCRIPTOR psd; + PACL paclDacl; + BOOL MonitorSecurityType; + RPL_SD_BLOCK_TYPE SecurityType; + // + // CODEWORK do we need to keep these sids around + // + PSID psidSystem; + PSID psidAdministrators; + POLICY_ACCOUNT_DOMAIN_INFO * pinfoRPLUSERAccountDomain; + SAM_HANDLE hsamRPLUSERAccountDomain; + POLICY_ACCOUNT_DOMAIN_INFO * pinfoWkstaAccountDomain; + SAM_HANDLE hsamWkstaAccountDomain; +} RPL_SD_BLOCK, *PRPL_SD_BLOCK; + +// +// The DACL we assign to files has 2 or 3 ACEs. +// +#define RPL_INDEX_SYSTEM_ACE 0 +#define RPL_INDEX_ADMINS_ACE 1 +#define RPL_INDEX_CHANGEABLE_ACE 2 + + + +DWORD IsNTFS( + IN PWCHAR Resource, + OUT BOOL * pfIsNTFS + ) +/*++ + + NAME: IsNTFS + + SYNOPSIS: This function checks the given file resource and attempts to + determine if it is on an NTFS partition. + + ENTRY: Resource - Pointer to file/directory name in the form + "X:\aaa\bbb\ccc + pfIsNTFS - Pointer to BOOL that will receive the results + + RETURNS: NO_ERROR if successful, error code otherwise + + NOTES: + + HISTORY: + JonN 23-Feb-1994 Copied from acledit\ntfsacl.cxx + +--*/ +{ + DWORD Error = NO_ERROR ; + HANDLE hDrive = NULL ; + WCHAR awchDosDriveName[4]; + WCHAR awchNtDriveName[40]; + UNICODE_STRING unistrNtDriveName; + BYTE buffFsInfo[ sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 200 ] ; + PFILE_FS_ATTRIBUTE_INFORMATION FsInfo = + (PFILE_FS_ATTRIBUTE_INFORMATION)buffFsInfo ; + OBJECT_ATTRIBUTES oa ; + IO_STATUS_BLOCK StatusBlock ; + + RPL_ASSERT( Resource != NULL + && wcslen(Resource) >= 3 + && pfIsNTFS != NULL ) ; + + *pfIsNTFS = FALSE ; + + // + // Determine the NT drive name + // + + awchDosDriveName[0] = Resource[0]; + awchDosDriveName[1] = Resource[1]; + awchDosDriveName[2] = Resource[2]; + awchDosDriveName[3] = L'\0'; + RPL_ASSERT( awchDosDriveName[1] == L':' + && awchDosDriveName[2] == L'\\' ); + + unistrNtDriveName.Buffer = awchNtDriveName; + unistrNtDriveName.Length = sizeof(awchNtDriveName); + unistrNtDriveName.MaximumLength = sizeof(awchNtDriveName); + + if (!RtlDosPathNameToNtPathName_U( awchDosDriveName, + &unistrNtDriveName, + NULL, + NULL)){ + RPL_ASSERT( FALSE ) ; + Error = ERROR_NOT_ENOUGH_MEMORY ; + goto cleanup; + } + RPL_ASSERT( unistrNtDriveName.Length < unistrNtDriveName.MaximumLength ); + unistrNtDriveName.Buffer[unistrNtDriveName.Length/sizeof(WCHAR)] = L'\0'; + + // + // Open the NT volume and query volume information + // + + InitializeObjectAttributes( &oa, + &unistrNtDriveName, + OBJ_CASE_INSENSITIVE, + 0, + 0 ); + Error = NtOpenFile( &hDrive, + SYNCHRONIZE | FILE_READ_DATA, + &oa, + &StatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_ALERT); + if (Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + Error = NtQueryVolumeInformationFile( + hDrive, + &StatusBlock, + (PVOID) FsInfo, + sizeof(buffFsInfo), + FileFsAttributeInformation ); + if (Error != NO_ERROR) { + if (Error == ERROR_ACCESS_DENIED) { + RplDump( ++RG_Assert, ( "(access denied) assuming the file system is NTFS")); + Error = NO_ERROR ; + *pfIsNTFS = TRUE ; + } else { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + } + goto cleanup; + } + + if ( FsInfo->FileSystemAttributes & FILE_PERSISTENT_ACLS){ + *pfIsNTFS = TRUE ; + } + +cleanup: + + /* Close the volume if we ever opened it + */ + if ( hDrive != NULL){ + NtClose( hDrive ); + } + + return( Error) ; +} + + + +DWORD AddInheritableAce( + IN OUT ACL * pacl, + IN ACCESS_MASK mask, + IN SID * psid + ) +/*++ + Add an ACCESS_ALLOWED_ACE to the ACL, with all inheritance flags set +--*/ +{ + DWORD Error = NO_ERROR; + ACCESS_ALLOWED_ACE * pace = NULL; + + if ( !AddAccessAllowedAce( pacl, ACL_REVISION, mask, psid )) { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // new ACE should be the last ACE + // + if ( !GetAce( pacl, (pacl->AceCount) - 1, &pace )) { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + RPL_ASSERT( EqualSid( psid, &(pace->SidStart)) ); + + (pace->Header.AceFlags) |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE); + +cleanup: + + return( Error); +} + + +VOID DeInitSdBlock( IN RPL_SD_BLOCK * psdblock) +{ + if (psdblock->psd != NULL) { + RplMemFree( RG_MemoryHandle, psdblock->psd ); + } + if (psdblock->psidSystem != NULL) { + RtlFreeSid( psdblock->psidSystem ); + } + if (psdblock->psidAdministrators != NULL) { + RtlFreeSid( psdblock->psidAdministrators ); + } + if ( psdblock->pinfoRPLUSERAccountDomain != NULL) { + LsaFreeMemory( psdblock->pinfoRPLUSERAccountDomain); + } + if (psdblock->hsamRPLUSERAccountDomain != NULL) { + SamCloseHandle( psdblock->hsamRPLUSERAccountDomain); + } + if ( psdblock->pinfoWkstaAccountDomain != NULL + && psdblock->pinfoWkstaAccountDomain != + psdblock->pinfoRPLUSERAccountDomain) { + LsaFreeMemory( psdblock->pinfoWkstaAccountDomain); + } + if ( psdblock->hsamWkstaAccountDomain != NULL + && psdblock->hsamWkstaAccountDomain != + psdblock->hsamRPLUSERAccountDomain) { + SamCloseHandle( psdblock->hsamWkstaAccountDomain); + } +} + + +DWORD GetDomains( + OUT SAM_HANDLE * phsamWkstaAccountDomain, + OUT POLICY_ACCOUNT_DOMAIN_INFO ** ppinfoWkstaAccountDomain, + OUT SAM_HANDLE * phsamRPLUSERAccountDomain, + OUT POLICY_ACCOUNT_DOMAIN_INFO ** ppinfoRPLUSERAccountDomain, + IN ACCESS_MASK DesiredAccess + ) +/*-- + Get a SAM_HANDLE to the account domain, and other information about + the account domain. This routine uses SAM and LSA directly. +--*/ +{ + DWORD Error = NO_ERROR; + SAM_HANDLE hsamAccountServer = NULL; + SAM_HANDLE hsamLocalServer = NULL; + LSA_HANDLE hlsaLocal = NULL; + LSA_HANDLE hlsaPDC = NULL; + OBJECT_ATTRIBUTES oa; + SECURITY_QUALITY_OF_SERVICE sqos; + + BOOL fIsPrimaryDC = FALSE; + BOOL fIsBackupDC = FALSE; + BOOL fIsNotDC = FALSE; + + SERVER_INFO_101 * psi101 = NULL; + POLICY_PRIMARY_DOMAIN_INFO * pinfoPrimaryDomain = NULL; + WCHAR awchPrimaryDomain[ DNLEN+1 ]; + WCHAR * pwchPDC = NULL; + UNICODE_STRING unistrPDC; + + RPL_ASSERT( phsamWkstaAccountDomain != NULL ); + RPL_ASSERT( ppinfoWkstaAccountDomain != NULL ); + RPL_ASSERT( phsamRPLUSERAccountDomain != NULL ); + RPL_ASSERT( ppinfoRPLUSERAccountDomain != NULL ); + + // + // Set up object attributes (borrowed from uintlsa.cxx) + // + + sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); + sqos.ImpersonationLevel = SecurityImpersonation; + sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + sqos.EffectiveOnly = FALSE; + + InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL ); + oa.SecurityQualityOfService = &sqos; + + // + // Determine whether this is a PDC, BDC or other server. + // + + Error = NetServerGetInfo( NULL, 101, (LPBYTE *)&psi101 ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + RPL_ASSERT( psi101 != NULL ); + fIsPrimaryDC = !!(psi101->sv101_type & SV_TYPE_DOMAIN_CTRL); + fIsBackupDC = !!(psi101->sv101_type & SV_TYPE_DOMAIN_BAKCTRL); + fIsNotDC = !(psi101->sv101_type & (SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL)); + + // + // Get a local LSA handle + // + + Error = LsaOpenPolicy( NULL, + &oa, + GENERIC_EXECUTE, + &hlsaLocal ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // + // If this is not a DC, get the name of the primary domain and + // determine whether this is a ServerNt/WinNt machine on a workgroup. + // + + if (!fIsPrimaryDC) { + Error = LsaQueryInformationPolicy( hlsaLocal, + PolicyPrimaryDomainInformation, + &pinfoPrimaryDomain ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + if (pinfoPrimaryDomain->Sid == NULL) { + // + // This is a ServerNt/WinNt machine on a workgroup. Pretend + // this is a Primary DC from now on. + // + fIsPrimaryDC = TRUE; + fIsBackupDC = fIsNotDC = FALSE; + } + } + + // + // If this is not a PDC, get the name of a primary domain PDC + // and reload the LSA handle + // + + if (!fIsPrimaryDC) { + RPL_ASSERT( DNLEN*sizeof(WCHAR) >= pinfoPrimaryDomain->Name.Length ); + memcpy( awchPrimaryDomain, + pinfoPrimaryDomain->Name.Buffer, + pinfoPrimaryDomain->Name.Length ); // this is in bytes + awchPrimaryDomain[ pinfoPrimaryDomain->Name.Length / sizeof(WCHAR) ] + = L'\0'; + + Error = NetGetDCName( NULL, + awchPrimaryDomain, + (LPBYTE *)&pwchPDC ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + unistrPDC.Buffer = pwchPDC; + unistrPDC.Length = wcslen( pwchPDC ) * sizeof(WCHAR); + unistrPDC.MaximumLength = unistrPDC.Length + sizeof(WCHAR); + + Error = LsaOpenPolicy( &unistrPDC, + &oa, + GENERIC_EXECUTE, + &hlsaPDC ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + } + + // + // Load information on the RPLUSERAccount domain + // + + Error = LsaQueryInformationPolicy( (fIsBackupDC) ? hlsaPDC : hlsaLocal, + PolicyAccountDomainInformation, + ppinfoRPLUSERAccountDomain ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // Load a SAM handle on the RPLUSERAccount domain + // + + Error = SamConnect( (fIsBackupDC) ? &unistrPDC : NULL, + &hsamLocalServer, + SAM_SERVER_LOOKUP_DOMAIN, + NULL ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + Error = SamOpenDomain( hsamLocalServer, + DesiredAccess, + (*ppinfoRPLUSERAccountDomain)->DomainSid, + phsamRPLUSERAccountDomain ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // If this is not a DC, load information and a SAM handle on + // the RPLUSERAccount domain + // + + if (!fIsNotDC) { + *phsamWkstaAccountDomain = *phsamRPLUSERAccountDomain; + *ppinfoWkstaAccountDomain = *ppinfoRPLUSERAccountDomain; + } else { + Error = LsaQueryInformationPolicy( hlsaPDC, + PolicyAccountDomainInformation, + ppinfoWkstaAccountDomain ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // Get server handle + // + + Error = SamConnect( &unistrPDC, + &hsamAccountServer, + SAM_SERVER_LOOKUP_DOMAIN, + NULL ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + Error = SamOpenDomain( hsamAccountServer, + DesiredAccess, + (*ppinfoWkstaAccountDomain)->DomainSid, + phsamWkstaAccountDomain ); + if ( Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + } + + +cleanup: + + if ( hsamLocalServer != NULL) { + SamCloseHandle( hsamLocalServer); + } + + if ( hsamAccountServer != NULL) { + SamCloseHandle( hsamAccountServer); + } + + if ( hlsaLocal != NULL) { + LsaClose( hlsaLocal); + } + + if ( hlsaPDC != NULL) { + LsaClose( hlsaPDC); + } + + if ( pinfoPrimaryDomain != NULL) { + LsaFreeMemory( pinfoPrimaryDomain); + pinfoPrimaryDomain = NULL; + } + + if ( pwchPDC != NULL ) { + NetApiBufferFree( (LPBYTE)pwchPDC ); + pwchPDC = NULL; + } + + if ( psi101 != NULL ) { + NetApiBufferFree( (LPBYTE)psi101 ); + psi101 = NULL; + } + + if ( Error != NO_ERROR + && (*ppinfoWkstaAccountDomain) != NULL + && (*ppinfoWkstaAccountDomain) != (*ppinfoRPLUSERAccountDomain) ) { + LsaFreeMemory( (*ppinfoWkstaAccountDomain)); + *ppinfoWkstaAccountDomain = NULL; + } + + if ( Error != NO_ERROR + && (*phsamWkstaAccountDomain) != NULL + && (*phsamWkstaAccountDomain) != (*phsamRPLUSERAccountDomain) ) { + SamCloseHandle( *phsamWkstaAccountDomain); + *phsamWkstaAccountDomain = NULL; + } + + if ( Error != NO_ERROR && (*ppinfoRPLUSERAccountDomain) != NULL) { + LsaFreeMemory( (*ppinfoRPLUSERAccountDomain)); + *ppinfoRPLUSERAccountDomain = NULL; + } + + if ( Error != NO_ERROR && (*phsamRPLUSERAccountDomain) != NULL) { + SamCloseHandle( *phsamRPLUSERAccountDomain); + *phsamRPLUSERAccountDomain = NULL; + } + + return( Error); +} + + +DWORD MyBuildSid( + OUT PSID * ppsidAccountSid, + IN POLICY_ACCOUNT_DOMAIN_INFO * pinfoAccountDomain, + IN DWORD ulRid + ) +{ + DWORD Error = 0; + DWORD cbNewSid = 0; + PUCHAR pcSubAuthorityCount = NULL; + PDWORD pdwLastSubAuthority = NULL; + + RPL_ASSERT( ppsidAccountSid != NULL && pinfoAccountDomain != NULL && ulRid != 0 ); + + cbNewSid = GetLengthSid( pinfoAccountDomain->DomainSid) + sizeof(DWORD); + *ppsidAccountSid = RplMemAlloc( RG_MemoryHandle, cbNewSid ); + if ( *ppsidAccountSid == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + if ( !CopySid( cbNewSid, *ppsidAccountSid, pinfoAccountDomain->DomainSid)) { + Error = GetLastError(); + goto cleanup; + } + + pcSubAuthorityCount = GetSidSubAuthorityCount( *ppsidAccountSid ); + RPL_ASSERT( pcSubAuthorityCount != NULL ); + (*pcSubAuthorityCount)++; + pdwLastSubAuthority = GetSidSubAuthority( + *ppsidAccountSid, (DWORD)((*pcSubAuthorityCount)-1) ); + RPL_ASSERT( pdwLastSubAuthority != NULL ); + *pdwLastSubAuthority = ulRid; + +cleanup: + + if ( Error != NO_ERROR) { + if ( *ppsidAccountSid != NULL) { + RplMemFree( RG_MemoryHandle, *ppsidAccountSid); + } + } + + return( Error); +} + + +SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY; + +DWORD InitSdBlock( OUT RPL_SD_BLOCK * psdblock) +/*++ + Initialize SdBlock. +--*/ +{ + DWORD Error; + DWORD cbNewDacl; + + memset( psdblock, 0, sizeof(*psdblock)); + + // + // Get System SID + // + Error = RtlAllocateAndInitializeSid( &IDAuthorityNT, 1, + SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, + &(psdblock->psidSystem)); + if (Error != NO_ERROR) { + return( Error); + } + + // + // Get Administrators SID + // + Error = RtlAllocateAndInitializeSid( + &IDAuthorityNT, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &(psdblock->psidAdministrators) + ); + if (Error != NO_ERROR) { + return( Error); + } + + // + // Get information about local and (if not PDC) remote domain + // + Error = GetDomains( &(psdblock->hsamWkstaAccountDomain), + &(psdblock->pinfoWkstaAccountDomain), + &(psdblock->hsamRPLUSERAccountDomain), + &(psdblock->pinfoRPLUSERAccountDomain), + GENERIC_EXECUTE ); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + return( Error); + } + + // + // Start assembling DACL + // + cbNewDacl = sizeof(ACL) + (3*sizeof(ACCESS_ALLOWED_ACE)) + + (3*GetSidLengthRequired(SID_MAX_SUB_AUTHORITIES)) + - sizeof(DWORD); + psdblock->paclDacl = RplMemAlloc( RG_MemoryHandle, cbNewDacl); + if ( psdblock->paclDacl == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + return( Error); + } + if ( !InitializeAcl( psdblock->paclDacl, cbNewDacl, ACL_REVISION)) { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + return( Error); + } + + // + // Add System ACE + // + Error = AddInheritableAce( psdblock->paclDacl, GENERIC_ALL, psdblock->psidSystem); + if (Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + return( Error); + } + + // + // Add Administrators ACE + // + Error = AddInheritableAce( psdblock->paclDacl, GENERIC_ALL, psdblock->psidAdministrators); + if (Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + return( Error); + } + + // + // Build security descriptor + // + psdblock->psd = RplMemAlloc( RG_MemoryHandle, sizeof(SECURITY_DESCRIPTOR) ); + if ( psdblock->psd == NULL) { + Error = ERROR_NOT_ENOUGH_MEMORY; + return( Error); + } + if ( !InitializeSecurityDescriptor( psdblock->psd, + SECURITY_DESCRIPTOR_REVISION )) { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + return( Error); + } + + if ( !SetSecurityDescriptorDacl( psdblock->psd, TRUE, psdblock->paclDacl, FALSE)) { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + return( Error); + } + + // + // Set SecurityType in RPL_SD_BLOCK + // + psdblock->MonitorSecurityType = TRUE; + psdblock->SecurityType = RPL_SD_BLOCK_TYPE_ADMINONLY; + return( NO_ERROR); +} + + +DWORD UpdateSdBlock( + IN OUT RPL_SD_BLOCK * psdblock, + IN RPL_SD_BLOCK_TYPE SecurityType, + IN DWORD GrantToRid, + IN BOOL MonitorSecurityType + ) +/*-- + Updates the changeable ace in the security descriptor + to reflect GrantToRid. + + MonitorSecurityType - do we need to monitor (keep evaluating) security type + while working on this subtree +--*/ +{ + DWORD Error = NO_ERROR; + PSID pGrantToSid = NULL; + + // + // Delete the changeable ACE if present + // + if ( psdblock->SecurityType == RPL_SD_BLOCK_TYPE_ONEUSER + || psdblock->SecurityType == RPL_SD_BLOCK_TYPE_ALLUSERS) { + if ( !DeleteAce( psdblock->paclDacl, RPL_INDEX_CHANGEABLE_ACE)) { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + psdblock->SecurityType = RPL_SD_BLOCK_TYPE_ADMINONLY; + } + + // + // Rewrite the changeable ACE if needed + // + if ( GrantToRid != 0) { + Error = MyBuildSid( &pGrantToSid, + (SecurityType == RPL_SD_BLOCK_TYPE_ALLUSERS) + ? psdblock->pinfoRPLUSERAccountDomain + : psdblock->pinfoWkstaAccountDomain, + GrantToRid); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + switch( SecurityType) { + case RPL_SD_BLOCK_TYPE_ALLUSERS: + Error = AddInheritableAce( psdblock->paclDacl, + GENERIC_READ | GENERIC_EXECUTE, + pGrantToSid); + break; + case RPL_SD_BLOCK_TYPE_ONEUSER: + Error = AddInheritableAce( psdblock->paclDacl, + GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE, + pGrantToSid); + break; + default: + RPL_ASSERT( FALSE); + Error = NERR_RplInternal; + break; + } + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + psdblock->SecurityType = SecurityType; + } + +cleanup: + if ( Error == NO_ERROR) { + psdblock->MonitorSecurityType = MonitorSecurityType; + } + if ( pGrantToSid != NULL) { + RplMemFree( RG_MemoryHandle, pGrantToSid); + } + return( Error); +} + + + +RPL_SD_BLOCK_TYPE SecurityType( IN PWCHAR File) +/*++ + Based on a position of File in %RplRoot% tree, determines what + SECURITY_DESCRIPTOR type is appropriate for this file. +--*/ +{ +#define WCSLEN( _x_) ( (DWORD) (sizeof(_x_)/sizeof(WCHAR) - 1) ) +#define SEC_RPLFILES L"RPLFILES\\" +#define SEC_BINFILES L"BINFILES" +#define SEC_PROFILES L"PROFILES" +#define SEC_MACHINES L"MACHINES\\" +#define SEC_TMPFILES L"TMPFILES\\" + + RPL_ASSERT( _wcsnicmp( File, RG_Directory, RG_DirectoryLength) == 0); + + File += RG_DirectoryLength; + + // + // If file is not in rplfiles, then it should be accessible to + // admins only. + // + if ( _wcsnicmp( File, SEC_RPLFILES, WCSLEN( SEC_RPLFILES)) != 0) { + return( RPL_SD_BLOCK_TYPE_ADMINONLY); + } + File += WCSLEN( SEC_RPLFILES); + + // + // If file is in rplfiles\binfiles or rplfiles\profiles, then it + // should be accessible to admins & RPLUSER group. + // + + if ( _wcsnicmp( File, SEC_BINFILES, WCSLEN( SEC_BINFILES)) == 0 || + _wcsnicmp( File, SEC_PROFILES, WCSLEN( SEC_PROFILES)) == 0) { + return( RPL_SD_BLOCK_TYPE_ALLUSERS); + } + + // + // If file is in rplfiles\machines\* or rplfiles\tmpfiles\*, + // then it should be accessible to admins & a particular workstation + // account. + // + if ( _wcsnicmp( File, SEC_MACHINES, WCSLEN( SEC_MACHINES)) == 0 || + _wcsnicmp( File, SEC_TMPFILES, WCSLEN( SEC_TMPFILES)) == 0) { + return( RPL_SD_BLOCK_TYPE_ONEUSER); + } + + // + // Return the default value. Files in rplfiles\configs will take + // this code path. + // + return( RPL_SD_BLOCK_TYPE_ADMINONLY); +} + + +DWORD SetRplPerms( + IN PWCHAR File, + IN OUT PBOOL pAuxiliaryBlock + ) +/*-- + This is the callback routine called by RplDoTree to set permissions + on a specific file/directory. + + File Path to file or directory. + pAuxiliaryBlock Pointer to RPL_SD_BLOCK the first element + of which must be boolean SkipThisTree + +--*/ +{ + PRPL_SD_BLOCK psdblock = (PRPL_SD_BLOCK)pAuxiliaryBlock; + + psdblock->SkipThisTree = FALSE; // by default we do not skip + + if ( psdblock->MonitorSecurityType) { + // + // We skip subtrees that require different security information. + // + if ( SecurityType( File) != psdblock->SecurityType) { + psdblock->SkipThisTree = TRUE; + return( NO_ERROR); + } + } + + // + // Set the actual file security. Note that this call will succeed + // even if the volume is not NTFS, thus we must check for + // partition type elsewhere. + // + if ( !SetFileSecurity( File, DACL_SECURITY_INFORMATION, psdblock->psd)) { + DWORD Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + return( Error); + } + + return( NO_ERROR); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplSetSecurity( + IN RPL_RPC_HANDLE ServerHandle, + IN LPWSTR WkstaName, + IN DWORD WkstaRid, + IN DWORD RplUserRid + ) +/*++ + There are 3 types of permissions: ADMINONLY, RPLUSER & ONEUSER. + For each type we first construct the appropriate security + description then use it. +--*/ +{ + DWORD Error; + WCHAR Directory[ MAX_PATH]; + BOOL IsNtfs; + RPL_SD_BLOCK sdblock; + + // + // Make working copy of RG_Directory, then verify it is NTFS. + // If it is not NTFS then there is nothing for us to do here. + // + + wcscpy( Directory, RG_Directory); + Error = IsNTFS( Directory, &IsNtfs); + if (Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + return( Error); + } else if (!IsNtfs) { + return( NO_ERROR); + } + + // + // Initialize to ADMINONLY permissions only. + // + Error = InitSdBlock( &sdblock); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // If RplUserRid is given, set both ADMINONLY & RPLUSER permissions + // (different permissions on different trees). + // + if ( RplUserRid != 0) { + // + // Set ADMINONLY permissions. + // + Error = RplDoTree( Directory, NULL, RPL_TREE_AUXILIARY, + SetRplPerms, (PVOID)&sdblock); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + // + // Initialize to RPLUSER permissions, then set them. + // + Error = UpdateSdBlock( &sdblock, RPL_SD_BLOCK_TYPE_ALLUSERS, RplUserRid, FALSE); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + wcscpy( Directory, RG_Directory); + wcscat( Directory, L"RPLFILES\\BINFILES"); + Error = RplDoTree( Directory, NULL, RPL_TREE_AUXILIARY, + SetRplPerms, (PVOID)&sdblock); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + wcscpy( Directory, RG_Directory); + wcscat( Directory, L"RPLFILES\\PROFILES"); + Error = RplDoTree( Directory, NULL, RPL_TREE_AUXILIARY, + SetRplPerms, (PVOID)&sdblock); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + } + + // + // If WkstaRid is given, initilize then set ONEUSER permissions. + // + if ( WkstaRid != 0) { + if ( !ValidName( WkstaName, RPL_MAX_WKSTA_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + Error = UpdateSdBlock( &sdblock, RPL_SD_BLOCK_TYPE_ONEUSER, WkstaRid, FALSE); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + wcscpy( Directory, RG_Directory); + wcscat( Directory, L"RPLFILES\\MACHINES\\"); + wcscat( Directory, WkstaName); + Error = RplDoTree( Directory, NULL, RPL_TREE_AUXILIARY, + SetRplPerms, (PVOID)&sdblock); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + wcscpy( Directory, RG_Directory); + wcscat( Directory, L"RPLFILES\\TMPFILES\\"); + wcscat( Directory, WkstaName); + Error = RplDoTree( Directory, NULL, RPL_TREE_AUXILIARY, + SetRplPerms, (PVOID)&sdblock); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + } + +cleanup: + DeInitSdBlock( &sdblock); + if (Error != NO_ERROR) { + // + // CODEWORK Need a more appropriate event log ?! + // + RplReportEvent( NELOG_RplCheckSecurity, NULL, sizeof(DWORD), &Error); + } + return( Error); +} + + diff --git a/private/net/svcdlls/rpl/server/service.c b/private/net/svcdlls/rpl/server/service.c new file mode 100644 index 000000000..d18e0778b --- /dev/null +++ b/private/net/svcdlls/rpl/server/service.c @@ -0,0 +1,207 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + service.c + +Abstract: + + This module contains RPL service apis: Open, Close, GetInfo & SetInfo. + +Author: + + Vladimir Z. Vulovic (vladimv) 05 - November - 1993 + +Revision History: + + 05-Nov-1993 vladimv + Created + +--*/ + +#include "local.h" +#include "apisec.h" +#include <secobj.h> // NetpAccessCheckAndAuditAlarm() +#include "db.h" // ResumePrune() +#include "rplsvc_s.h" // RPL_RPC_HANDLE_rundown() +#include "setup.h" + + +NET_API_STATUS NET_API_FUNCTION +NetrRplOpen( + IN PWCHAR ServerName, + OUT LPRPL_RPC_HANDLE pServerHandle + ) +/*++ + +Routine Description: + +Arguments: + + pServerHandle - ptr to RPL_HANDLE + +Return Value: + + NO_ERROR if success. + +--*/ +{ + // + // ServerName got us to the server side and is uninteresting + // once we get here. + // + UNREFERENCED_PARAMETER( ServerName); + +#ifndef RPL_NO_SERVICE + // + // Perform access validation on the caller. All other + // operations are handle based, thus we can rely on RPC + // to prohibit unathorized callers. + // + if ( NetpAccessCheckAndAudit( + SERVICE_RIPL, // Subsystem name + SECURITY_OBJECT, // Object type name + RG_SecurityDescriptor, // Security descriptor + RPL_RECORD_ALL_ACCESS, // Desired access + &RG_SecurityMapping // Generic mapping + ) != NO_ERROR) { + return ERROR_ACCESS_DENIED; + } +#endif + + EnterCriticalSection( &RG_ProtectServerHandle); + *(PDWORD)pServerHandle = ++RG_ServerHandle; + LeaveCriticalSection( &RG_ProtectServerHandle); + return( NO_ERROR); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplClose( + IN OUT LPRPL_RPC_HANDLE pServerHandle + ) +/*++ + +Routine Description: + +Arguments: + + pServerHandle - ptr to RPL_HANDLE + +Return Value: + + NO_ERROR if success. + +--*/ +{ + PRPL_SESSION pSession = &RG_ApiSession; + + EnterCriticalSection( &RG_ProtectDatabase); + ResumePrune( pSession, *(PDWORD)pServerHandle); + LeaveCriticalSection( &RG_ProtectDatabase); + + *(PDWORD)pServerHandle = 0; // let rpc know that we are done + return( ERROR_SUCCESS); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplGetInfo( + IN RPL_RPC_HANDLE ServerHandle, + IN DWORD Level, + OUT LPRPL_INFO_STRUCT InfoStruct + ) +{ + LPBYTE Buffer; + + switch( Level) { + case 0: + Buffer = MIDL_user_allocate( sizeof( RPL_INFO_0)); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + memset( Buffer, 0, sizeof( RPL_INFO_0)); + InfoStruct->RplInfo0 = (LPRPL_INFO_0)Buffer; + InfoStruct->RplInfo0->Flags = 0; + break; + case 1: + Buffer = MIDL_user_allocate( sizeof( RPL_INFO_1)); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + memset( Buffer, 0, sizeof( RPL_INFO_1)); + InfoStruct->RplInfo1 = (LPRPL_INFO_1)Buffer; + InfoStruct->RplInfo1->AdapterPolicy = 0; // fix i_lmrpl.h + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + return( NO_ERROR); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplSetInfo( + IN RPL_RPC_HANDLE ServerHandle, + IN DWORD Level, + IN LPRPL_INFO_STRUCT InfoStruct, + IN OUT LPDWORD ErrorParameter + ) +{ + DWORD Flags; + DWORD Error; + + switch( Level) { + case 0: + Flags = InfoStruct->RplInfo0->Flags; + break; + case 1: + Flags = InfoStruct->RplInfo1->AdapterPolicy; // fix i_lmrpl.h + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( Flags & ~RPL_SPECIAL_ACTIONS) { + return( ERROR_INVALID_PARAMETER); + } +#ifdef RPL_NO_SERVICE + if ( Flags == 0) { + RplControlHandler( SERVICE_CONTROL_STOP); + } +#endif + Error = SetupAction( &Flags, TRUE); // full backup if any + return( Error); +} + + +VOID +RPL_RPC_HANDLE_rundown( + IN RPL_RPC_HANDLE ServerHandle + ) + +/*++ + +Routine Description: + + This function is called by RPC when a connection is broken that had + an outstanding context handle. The value of the context handle is + passed in here so that we have an opportunity to clean up. + +Arguments: + + ServerHandle - This is the handle value of the context handle that is broken. + +Return Value: + + none. + +--*/ +{ + NetrRplClose( &ServerHandle); // close the handle +} + diff --git a/private/net/svcdlls/rpl/server/setup.c b/private/net/svcdlls/rpl/server/setup.c new file mode 100644 index 000000000..36ee21738 --- /dev/null +++ b/private/net/svcdlls/rpl/server/setup.c @@ -0,0 +1,716 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + setup.c + +Abstract: + + Setup primitives + +Author: + + Jon Newman (jonn) 01-April-1994 + +Revision History: + + Jon Newman (jonn) 01 - April - 1994 + Added RplPolicy primitives + +--*/ + + +#include "local.h" +#include "rpldb.h" // Call(), CallM() +#include "db.h" // ConfigGetField() +#include "dblib.h" // RplFilterFirst() +#include "wksta.h" // WKSTA_WkstaName +#include "profile.h" // PROFILE_ProfileName +#include "setup.h" +#include "config.h" +#include "lmwksta.h" // NetWkstaGetInfo + +#define RPLDISK_SYS L"BBLOCK\\RPLDISK.SYS" +#define RPLDISK_OLD L"BBLOCK\\RPLDISK.OLD" +#define RPLDISK_NEW L"RPLDISK.NEW" + + + +BOOL FileExists( const WCHAR * FileToFind, DWORD * ErrorPtr) +/*++ + +Routine Description: + + This function checks whether the file exists. + +Arguments: + + +Return Value: + TRUE iff file exists + +--*/ +{ + BOOL BoolFileFound = FALSE; + DWORD TempError; + + if ( ErrorPtr == NULL ) + ErrorPtr = &TempError; + + *ErrorPtr = NO_ERROR; + + if (0xFFFFFFFF == GetFileAttributes( FileToFind )) { + *ErrorPtr = GetLastError(); + switch (*ErrorPtr) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + break; + case NO_ERROR: + default: + RplDump( ++RG_Assert, ( "*ErrorPtr=%d", *ErrorPtr)); + break; + } + } else { + BoolFileFound = TRUE; + } + + return( BoolFileFound); +} + + +DWORD RplReplaceRPLDISK( VOID) +/*++ + +Routine Description: + + This function checks whether the file RPLDISK.SYS has + been replaced with the newer version, and if not, + replaces it. + +Arguments: + +Return Value: + +--*/ +{ + DWORD Error = NO_ERROR; + WCHAR RpldiskBuffer[ MAX_PATH ]; + WCHAR SourceBuffer[ MAX_PATH ]; + WCHAR BackupBuffer[ MAX_PATH ]; + + RPL_ASSERT( RG_DirectoryLength == wcslen(RG_Directory) + && RG_DirectoryLength != 0 + && (RG_DirectoryLength + wcslen(RPLDISK_OLD)) < MAX_PATH ); + + wcscpy( RpldiskBuffer, RG_Directory ); + wcscat( RpldiskBuffer, RPLDISK_SYS ); + + wcscpy( SourceBuffer, RG_Directory ); + wcscat( SourceBuffer, RPLDISK_NEW ); + + // + // Make sure source file exists + // + + if (!FileExists(SourceBuffer, &Error)) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + wcscpy( BackupBuffer, RG_Directory ); + wcscat( BackupBuffer, RPLDISK_OLD ); + + // + // Copy existing RPLDISK.SYS to RPLDISK.OLD, on a best-effort basis + // + (void) CopyFile( RpldiskBuffer, BackupBuffer, FALSE ); + + // + // Copy the new RPLDISK.SYS + // + if (!CopyFile( SourceBuffer, RpldiskBuffer, FALSE )) { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + +cleanup: + + if (Error != NO_ERROR) { + RplReportEvent( NELOG_RplReplaceRPLDISK, NULL, sizeof(DWORD), &Error ); + } + + return( Error); +} + +#define LANMANINI_BINFILES L"RPLFILES\\BINFILES\\LANMAN.DOS\\LANMAN.INI" +#define LANMANINI_CONFIGSDOS L"RPLFILES\\CONFIGS\\DOS\\LANMAN.DOS\\LANMAN.INI" +#define LANMANINI_PROFILES L"RPLFILES\\PROFILES\\%ws\\LANMAN.DOS\\LANMAN.INI" +#define LANMANINI_WKSTAS L"RPLFILES\\MACHINES\\%ws\\%ws\\PRO\\LANMAN.DOS\\LANMAN.INI" +#define LANMANINI_SECTION L"WORKSTATION" +#define LANMANINI_KEY L"DOMAIN" + + +DWORD RplProcessLanmanInis( VOID ) +/*++ + +Routine Description: + + This function changes the "domain =" line in every LANMAN.INI + +Arguments: + +Return Value: + error code + +--*/ +{ + DWORD Error; + WCHAR achFile[ MAX_PATH ]; + WKSTA_INFO_100 * pw100 = NULL; + WCHAR * pwszDomainName = NULL; + PRPL_SESSION pSession = &RG_ApiSession; + BOOL InCritSec = FALSE; + BOOL InEnumeration = FALSE; + INT SpaceLeft; + BOOL TableEnd = TRUE; + WCHAR * EnumProfileName = NULL; + WCHAR * EnumWkstaName = NULL; + DWORD EnumWkstaFlags = 0; + + RPL_ASSERT( wcslen(RG_Directory) == RG_DirectoryLength + && RG_DirectoryLength+wcslen(LANMANINI_CONFIGSDOS) < MAX_PATH + && RG_DirectoryLength+wcslen(LANMANINI_BINFILES ) < MAX_PATH ); + + // + // get domain name + // + // CODEWORK OK for workgroup? Non-issue since we should be on NTAS + // + Error = NetWkstaGetInfo( NULL, 100, (LPBYTE *)&pw100); + if (Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + RPL_ASSERT( pw100 != NULL ); + pwszDomainName = pw100->wki100_langroup; + RPL_ASSERT( pwszDomainName != NULL && *pwszDomainName != L'\0' ); + + // + // update rplfiles\configs\dos\lanman.dos\lanman.ini + // + wcscpy( achFile, RG_Directory ); + wcscat( achFile, LANMANINI_CONFIGSDOS ); + + if ( !WritePrivateProfileString( LANMANINI_SECTION, + LANMANINI_KEY, + pwszDomainName, + achFile )) + { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // update rplfiles\binfiles\lanman.dos\lanman.ini + // + wcscpy( achFile + RG_DirectoryLength, LANMANINI_BINFILES ); + + if ( !WritePrivateProfileString( LANMANINI_SECTION, + LANMANINI_KEY, + pwszDomainName, + achFile )) + { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // update rplfiles\profiles\<profilename>\lanman.dos\lanman.ini + // + // Code lifted from NetrRplConfigEnum + // + EnterCriticalSection( &RG_ProtectDatabase); + InCritSec = TRUE; + Call( JetBeginTransaction( pSession->SesId)); + InEnumeration = TRUE; + + if ( !RplFilterFirst( pSession, PROFILE_TABLE_TAG, NULL, NULL, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + + for ( ; ; ) { + + if ( TableEnd == TRUE) { + break; + } + + if (EnumProfileName != NULL) { + MIDL_user_free( EnumProfileName ); + EnumProfileName = NULL; + } + + // get profile name + SpaceLeft = MAX_PATH; // CODEWORK * sizeof(WCHAR)? + Error = ProfileGetField( pSession, + PROFILE_ProfileName, + &EnumProfileName, + &SpaceLeft); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // build file name and modify file + if ( ( RG_DirectoryLength + + wcslen(LANMANINI_PROFILES) + + wcslen(EnumProfileName) + - 3) >= MAX_PATH ) + { + RplDump( ++RG_Assert, ( "wkstaname too long \"%ws\"", EnumWkstaName)); + } + else + { + swprintf( achFile + RG_DirectoryLength, + LANMANINI_PROFILES, + EnumProfileName ); + if ( !WritePrivateProfileString( LANMANINI_SECTION, + LANMANINI_KEY, + pwszDomainName, + achFile )) + { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + } + + if ( !RplFilterNext( pSession, pSession->ProfileTableId, NULL, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + } + + Call( JetCommitTransaction( pSession->SesId, 0)); // CODEWORK rollback on error? + InEnumeration = FALSE; + + // + // update rplfiles\machines\<wkstaname>\<profilename>\lanman.dos\lanman.ini + // + Call( JetBeginTransaction( pSession->SesId)); + InEnumeration = TRUE; + if ( !RplFilterFirst( pSession, WKSTA_TABLE_TAG, NULL, NULL, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + for ( ; ; ) { + + if ( TableEnd == TRUE) { + break; + } + + // check whether this wksta has a personal profile + SpaceLeft = sizeof(DWORD); + Error = WkstaGetField( pSession, + WKSTA_Flags, + (LPVOID *)&EnumWkstaFlags, + &SpaceLeft); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // only write for personal profile + if ( EnumWkstaFlags & WKSTA_FLAGS_SHARING_FALSE ) { + + if (EnumWkstaName != NULL) { + MIDL_user_free( EnumWkstaName ); + EnumProfileName = NULL; + } + + // get workstation name + SpaceLeft = MAX_PATH; // CODEWORK * sizeof(WCHAR)? + Error = WkstaGetField( pSession, + WKSTA_WkstaName, + &EnumWkstaName, + &SpaceLeft); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + if (EnumProfileName != NULL) { + MIDL_user_free( EnumProfileName ); + EnumProfileName = NULL; + } + + // get workstation-in-profile name + SpaceLeft = MAX_PATH; // CODEWORK * sizeof(WCHAR)? + Error = WkstaGetField( pSession, + WKSTA_ProfileName, + &EnumProfileName, + &SpaceLeft); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // build file name and modify file + if ( ( RG_DirectoryLength + + wcslen(LANMANINI_WKSTAS) + + wcslen(EnumWkstaName) + + wcslen(EnumProfileName) + - 6) >= MAX_PATH ) + { + RplDump( ++RG_Assert, + ( "Wksta+profile too long \"%ws\", \"%ws\"", + EnumWkstaName, + EnumProfileName)); + } + else + { + swprintf( achFile + RG_DirectoryLength, + LANMANINI_WKSTAS, + EnumWkstaName, + EnumProfileName ); + if ( !WritePrivateProfileString( LANMANINI_SECTION, + LANMANINI_KEY, + pwszDomainName, + achFile )) + { + Error = GetLastError(); + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + } + + + } + + + if ( !RplFilterNext( pSession, pSession->WkstaTableId, NULL, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + } + +cleanup: + + if ( InEnumeration) { + Call( JetCommitTransaction( pSession->SesId, 0)); // CODEWORK rollback on error? + } + + if ( InCritSec) { + LeaveCriticalSection( &RG_ProtectDatabase); + } + if (EnumProfileName != NULL) { + MIDL_user_free( EnumProfileName ); + EnumWkstaName = NULL; + } + + if (EnumWkstaName != NULL) { + MIDL_user_free( EnumWkstaName ); + EnumWkstaName = NULL; + } + + if ( pw100 != NULL) { + NetApiBufferFree( pw100); + } + + // + // BUGBUG Need better event id/text? + // + if (Error != NO_ERROR) { + RplReportEvent( NELOG_RplCheckSecurity, NULL, sizeof(DWORD), &Error ); + } + + return( Error); +} + +#define RPL_COM L"\\COMMAND.COM" +#define WCSLEN( _x_) ((DWORD) ( sizeof(_x_)/sizeof(WCHAR) - 1)) + +BOOL RplConfigEnabled( IN PWCHAR DirName2) +{ + WCHAR SearchBuffer[ MAX_PATH ]; + DWORD SearchBufferLength; + + wcscpy( SearchBuffer, RG_DiskBinfiles); + SearchBufferLength = wcslen( SearchBuffer); + + if ( SearchBufferLength + wcslen(DirName2) + WCSLEN( RPL_COM) + > WCSLEN( SearchBuffer)) { + RplDump( ++RG_Assert, ( "DirName2=%ws", DirName2)); + return( FALSE); + } + wcscpy( SearchBuffer + SearchBufferLength, DirName2); + wcscat( SearchBuffer + SearchBufferLength, RPL_COM); + /* + * The file COMMAND.COM should be in directory given by SearchBuffer + */ + return( FileExists( SearchBuffer, NULL)); +} + + +DWORD RplCheckConfigs( VOID) +/*++ + +Routine Description: + + This function checks whether the file COMMAND.COM exists + in the proper place for each configuration, and + enables/disables the configuration accordingly. + +Arguments: + +Return Value: + +--*/ +{ + DWORD Error = NO_ERROR; + INT SpaceLeft; + BOOL TableEnd; + WCHAR * DirName2 = NULL; + DWORD Flags; + WCHAR SearchBuffer[ MAX_PATH ]; + BOOL BoolConfigEnabled = FALSE; + BOOL BoolFileFound = FALSE; + DWORD SearchBufferLength; + PRPL_SESSION pSession = &RG_ApiSession; + + wcscpy( SearchBuffer, RG_DiskBinfiles); + SearchBufferLength = wcslen( SearchBuffer); + + // + // Code lifted from NetrRplConfigEnum + // + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFilterFirst( pSession, CONFIG_TABLE_TAG, NULL, NULL, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + for ( ; ; ) { + + if (DirName2 != NULL) { + MIDL_user_free( DirName2 ); + DirName2 = NULL; + } + + Error = ConfigGetField( pSession, + CONFIG_DirName2, + &DirName2, + &SpaceLeft); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + Error = ConfigGetField( pSession, + CONFIG_Flags, + (LPVOID *)&Flags, + &SpaceLeft); + if ( Error != NO_ERROR) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + goto cleanup; + } + + // + // Check whether this configuration should be enabled + // + RPL_ASSERT( (!!(Flags & CONFIG_FLAGS_ENABLED_TRUE)) + != (!!(Flags & CONFIG_FLAGS_ENABLED_FALSE)) ); + BoolConfigEnabled = !!(Flags & CONFIG_FLAGS_ENABLED_TRUE); + + if ( SearchBufferLength + wcslen(DirName2) + WCSLEN( RPL_COM) + > WCSLEN( SearchBuffer)) { + RplDump( ++RG_Assert, ( "DirName2=%ws", DirName2)); + continue; + } + wcscpy( SearchBuffer + SearchBufferLength, DirName2); + wcscat( SearchBuffer + SearchBufferLength, RPL_COM); + /* + * The file COMMAND.COM should be in directory given by SearchBuffer + */ + BoolFileFound = FileExists( SearchBuffer, NULL ); + + if (Error == NERR_Success && BoolConfigEnabled != BoolFileFound) { + Flags ^= CONFIG_FLAGS_MASK_ENABLED; // XOR + + // lifted from NetrRplConfigAdd and NetrWkstaSetinfo + CallJ( JetPrepareUpdate( pSession->SesId, + pSession->ConfigTableId, + JET_prepReplace)); + + // lifted from ConfigSetInfo + CallM( JetSetColumn( pSession->SesId, pSession->ConfigTableId, + ConfigTable[ CONFIG_Flags].ColumnId, + &Flags, sizeof( Flags), 0, NULL)); + + // lifted from NetrRplConfigAdd + CallJ( JetUpdate( pSession->SesId, + pSession->ConfigTableId, + NULL, 0, NULL)); + } + + if ( !RplFilterNext( pSession, pSession->ConfigTableId, NULL, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + } + +cleanup: + Call( JetCommitTransaction( pSession->SesId, 0)); // CODEWORK rollback on error? + LeaveCriticalSection( &RG_ProtectDatabase); + + if (DirName2 != NULL) { + MIDL_user_free( DirName2 ); + DirName2 = NULL; + } + + if (Error != NO_ERROR) { + RplReportEvent( NELOG_RplCheckConfigs, NULL, sizeof(DWORD), &Error ); + } + + return( Error); +} + + +DWORD RplBackupDatabase( IN BOOL FullBackup) +/*++ + +Routine Description: + + This function backs up the JET database. FullBackup copies the + database file and all log files. Incremental backup copies only + the log files that are modified since the last backup. + +Arguments: + + FullBackup - set to TRUE if full backup is required. + +Return Value: + + Windows Error. + +--*/ +{ + JET_ERR JetError; + + FullBackup = TRUE; // to avoid JET bugs in JetRestore() + + JetError = JetBackup( RG_BackupPath, +#ifdef __JET500 + JET_bitBackupAtomic | + (FullBackup ? 0 + : JET_bitBackupIncremental), + NULL +#else + (FullBackup ? JET_bitOverwriteExisting + : JET_bitBackupIncremental) +#endif + ); + + if( JetError == JET_errFileNotFound && FullBackup == FALSE) { + + // + // Full backup was not performed anytime, so do it now. + // + + JetError = JetBackup( RG_BackupPath, +#ifdef __JET500 + JET_bitBackupAtomic, + NULL +#else + JET_bitOverwriteExisting +#endif + ); + } + + if ( JetError < 0) { + RplReportEvent( NELOG_RplBackupDatabase, NULL, sizeof(DWORD), &JetError); + return( NERR_RplBackupDatabase); + } + return( NO_ERROR); +} + + +DWORD SetupAction( + IN OUT PDWORD pAction, + IN BOOL FullBackup + ) +/*++ + +Routine Description: + + Performs the setup action for all RPL_SPECIAL_ACTIONS specified + in *pAction. + +Arguments: + pAction: points to RPL_SPECIAL_ACTIONS DWORD. On return, the + RPL_SPECIAL_ACTIONS flags are reset for all actions which + were successfully performed. + +Return Value: + error word + +--*/ +{ + DWORD Error; + + if ((*pAction) & RPL_REPLACE_RPLDISK) { +#ifdef NOT_YET + Error = RplReplaceRPLDISK(); + if (Error != NO_ERROR) { + return( Error); + } +#endif + *pAction &= ~RPL_REPLACE_RPLDISK; + } + + if ((*pAction) & RPL_CHECK_SECURITY) { + Error = RplProcessLanmanInis(); + if (Error != NO_ERROR) { + return( Error); + } + *pAction &= ~RPL_CHECK_SECURITY; + } + + if ((*pAction) & RPL_CHECK_CONFIGS) { + Error = RplCheckConfigs(); + if (Error != NO_ERROR) { + return( Error); + } + *pAction &= ~RPL_CHECK_CONFIGS; + } + + if ((*pAction) & RPL_CREATE_PROFILES) { + // + // CODEWORK RPL_CREATE_PROFILES not implemented + // + *pAction &= ~RPL_CREATE_PROFILES; + } + + if ((*pAction) & RPL_BACKUP_DATABASE) { + Error = RplBackupDatabase( FullBackup); + if (Error != NO_ERROR) { + return( Error); + } + *pAction &= ~RPL_BACKUP_DATABASE; + } + + return( NO_ERROR); +} + diff --git a/private/net/svcdlls/rpl/server/setup.h b/private/net/svcdlls/rpl/server/setup.h new file mode 100644 index 000000000..67993c662 --- /dev/null +++ b/private/net/svcdlls/rpl/server/setup.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + setup.h + +Abstract: + + Exports from setup.c + +Author: + + Jon Newman (jonn) 01-April-1994 + +Revision History: + + Jon Newman (jonn) 01 - April - 1994 + Added setup primitives + +--*/ + +#ifndef _RPL_SETUP_H_ +#define _RPL_SETUP_H_ + +DWORD SetupAction( + IN OUT PDWORD pAction, + IN BOOL FullBackup + ); +DWORD RplBackupDatabase( IN BOOL FullBackup); +BOOL RplConfigEnabled( IN PWCHAR DirName2); + +#endif // _RPL_SETUP_H_ diff --git a/private/net/svcdlls/rpl/server/sources b/private/net/svcdlls/rpl/server/sources new file mode 100644 index 000000000..537309ea0 --- /dev/null +++ b/private/net/svcdlls/rpl/server/sources @@ -0,0 +1,83 @@ +# +# Source file used for building RplSvc.exe in this directory. +# + +MAJORCOMP=net +MINORCOMP=rplsvc + +TARGETPATH=obj +TARGETNAME=rplsvc +TARGETTYPE=PROGRAM + +TARGETLIBS= \ + ..\dll\obj\*\rplnet.lib \ + ..\lib\obj\*\rpllib.lib \ + $(BASEDIR)\Public\Sdk\Lib\*\dlcapi.lib \ + $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \ + $(BASEDIR)\public\sdk\lib\*\rpcutil.lib \ + $(BASEDIR)\public\sdk\lib\*\rpcndr.lib \ + $(BASEDIR)\public\sdk\lib\*\samlib.lib \ + $(BASEDIR)\Public\Sdk\Lib\*\wsock32.lib \ + $(BASEDIR)\public\sdk\lib\*\jet500.lib \ + $(BASEDIR)\public\sdk\lib\*\ntdll.lib + + +!IFNDEF DISABLE_NET_UNICODE +UNICODE=1 +NET_C_DEFINES=-DUNICODE +!ENDIF + +INCLUDES=.;..\inc;..\..\..\inc;..\..\..\api;..\..\..\..\inc; + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + apisec.c \ + dblib.c \ + tree.c \ + vendor.c \ + security.c \ + adapter.c \ + disk.c \ + service.c \ + resume.c \ + boot.c \ + config.c \ + profile.c \ + setup.c \ + wksta.c \ + fitfile.c \ + open.c \ + bbcfile.c \ + read.c \ + database.c \ + request.c \ + worker.c \ + rplsvc.c \ + rplsvc.rc \ + rplmain.c \ + debug.c \ + report.c \ + library.c \ + memory.c \ + rplsvc_s.c + +USE_CRTDLL=1 +# +#Add -DRPL_NO_SERVICE if you do not want RPL to run as a service +# +#C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 -DRPL_NO_SERVICE +# + +C_DEFINES= -DINCL_32= -DNT -DRPC_NO_WINDOWS_H -DWIN32 + +UMTYPE=console +UMTEST= rplrest +UMLIBS= \ + $(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \ + $(BASEDIR)\public\sdk\lib\*\jet500.lib \ + $(BASEDIR)\public\sdk\lib\*\netlib.lib \ + $(BASEDIR)\public\sdk\lib\*\netapi32.lib + + + diff --git a/private/net/svcdlls/rpl/server/tree.c b/private/net/svcdlls/rpl/server/tree.c new file mode 100644 index 000000000..40ede9642 --- /dev/null +++ b/private/net/svcdlls/rpl/server/tree.c @@ -0,0 +1,353 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tree.c + +Abstract: + + RplTreeCopy, RplTreeDelete, RplMakeDir file-management helper routines + for the RPL service. + +Author: + + Jon Newman (jonn) 23 - November - 1993 + +Revision History: + + Vladimir Z. Vulovic (vladimv) 02 - December - 1993 + Integrated with the rest of RPL service code. + Jon Newman (jonn) 15 - February - 1994 + Added RplGrant*Perms primitives + Jon Newman (jonn) 08 - March - 1994 + RplDoTree now creates log entries on failure + +--*/ + +#include "local.h" +#include "tree.h" +#include "treei.h" + +#define FILE_SEPARATOR L"\\" +#define HERE_DIRECTORY L"." +#define PARENT_DIRECTORY L".." +#define ALLFILES_SUFFIX L"*" + +#define LEN_FILE_SEPARATOR 1 +#define LEN_ALLFILES_SUFFIX 1 + + +VOID LoadError( + PWCHAR FilePath, + DWORD ActionError, + DWORD ActionFlags + ) +/*++ + BUGBUG if buffer inadequate, copy first part or last part? +--*/ +{ + DWORD Length0 = 0; + DWORD msgid = 0; + + // + // Dump error log entry, where the message depends on Flags + // + if (ActionFlags == 0) { + msgid = 0; + } else if (ActionFlags & RPL_TREE_COPY) { + msgid = NELOG_RplFileCopy; + } else if (ActionFlags & RPL_TREE_DELETE) { + msgid = NELOG_RplFileDelete; + } else if (ActionFlags & RPL_TREE_AUXILIARY) { + msgid = NELOG_RplFilePerms; + } else { + RPL_ASSERT( FALSE ); + } + + if (msgid != 0) { + RplReportEvent( msgid, FilePath, sizeof(DWORD), &ActionError ); + } +} + + +DWORD RplDoTree( + PWCHAR Source, + PWCHAR Target, + DWORD Flags, + RPL_TREE_CALLBACK AuxiliaryCallback, + PBOOL pAuxiliaryBlock + ) +/*++ + Target should only be examined if RPL_TREE_COPY case. +--*/ +{ + // CODEWORK too much stack space usage (1.5K / recursive invocation) + DWORD Error = NO_ERROR; + WCHAR CurrentSource[ MAX_PATH]; + WCHAR CurrentTarget[ MAX_PATH]; + HANDLE Handle = INVALID_HANDLE_VALUE; + WIN32_FIND_DATA FindData; + DWORD SourceLength = 0; + DWORD TargetLength = 0; + DWORD FileLength = 0; + BOOL Auxiliary = ((Flags & RPL_TREE_AUXILIARY) != 0); + BOOL Delete = ((Flags & RPL_TREE_DELETE) != 0); + BOOL Copy = ((Flags & RPL_TREE_COPY) != 0); + + // + // Delete is incompatible with Auxiliary and Copy + // + RPL_ASSERT( !Delete || (!Auxiliary && !Copy ) ); + + // + // Callback and callback data block required for Auxiliary + // + RPL_ASSERT( !Auxiliary + || (AuxiliaryCallback != NULL && pAuxiliaryBlock != NULL) ); + + if ( Source == NULL || *Source == L'\0') { + RPL_RETURN( ERROR_INVALID_PARAMETER); + } + SourceLength = wcslen( Source); + if ( SourceLength + LEN_ALLFILES_SUFFIX >= MAX_PATH) { + Error = ERROR_FILENAME_EXCED_RANGE; + RplDump( ++RG_Assert, ( "Error=%d", Error)); + LoadError( Source, Error, Flags); + return( Error); + } + // + // Initialize buffer for source names. + // + memcpy( CurrentSource, Source, SourceLength * sizeof(WCHAR)); + memcpy( CurrentSource + SourceLength, FILE_SEPARATOR, LEN_FILE_SEPARATOR * sizeof(WCHAR)); + memcpy( CurrentSource + SourceLength + LEN_FILE_SEPARATOR, ALLFILES_SUFFIX, (LEN_ALLFILES_SUFFIX+1) * sizeof(WCHAR)); + + // + // Copy directory operations are done at the beginning. + // + // BUGBUG broken if source is not a directory + // + if ( Copy) { + TargetLength = wcslen( Target); + RPL_ASSERT( TargetLength < MAX_PATH); + // + // Initialize buffer for target names. + // + memcpy( CurrentTarget, Target, (TargetLength+1) * sizeof(WCHAR)); + if ( !CreateDirectoryEx( Source, Target, NULL)) { + Error = GetLastError(); + if ( Error != ERROR_ALREADY_EXISTS) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + LoadError( Source, Error, RPL_TREE_COPY); + return( Error); + } + } + } + + // + // Stop recursing this tree if we are setting permission only and if + // SetRplPerms tells us to quit this branch. Here we depend on the fact that + // RPL_SD_BLOCK - structure not visible here, contains BOOL StopRecursion + // as its first element. + // + if ( Auxiliary) { + Error = (AuxiliaryCallback)( ((Copy)?Target:Source), pAuxiliaryBlock); + if (Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + LoadError( Source, Error, RPL_TREE_AUXILIARY); + return( Error); + } + if ( !Delete && !Copy && *pAuxiliaryBlock == TRUE) { + return( NO_ERROR); + } + } + + // + // Enumerate and copy/change/delete directory contents. + // + for ( Handle = INVALID_HANDLE_VALUE; NOTHING; Error = NO_ERROR) { + + if ( Handle == INVALID_HANDLE_VALUE) { + Handle = FindFirstFile( CurrentSource, &FindData); + if (Handle == INVALID_HANDLE_VALUE) { + Error = GetLastError(); + // + // ERROR_PATH_NOT_FOUND occurs for non-existing Source tree + // + if (Error == ERROR_NO_MORE_FILES || Error == ERROR_PATH_NOT_FOUND) { + Error = NO_ERROR; + } else { + RplDump( ++RG_Assert, ( "Error=%d, CurrentSource=%ws", Error, CurrentSource)); + LoadError( CurrentSource, Error, Flags); + } + break; + } + // + // Trim ALLFILES_SUFFIX off CurrentSource for future use + // + CurrentSource[ SourceLength + LEN_FILE_SEPARATOR] = L'\0'; + } else { + if ( !FindNextFile( Handle, &FindData)) { + Error = GetLastError(); + if ( Error == ERROR_NO_MORE_FILES) { + Error = NO_ERROR; + break; + } else { + RplDump( ++RG_Assert, ( "Error=%d, CurrentSource=%ws", Error, CurrentSource)); + LoadError( CurrentSource, Error, Flags); + } + } + } + + if ( 0 == wcscmp( FindData.cFileName, HERE_DIRECTORY) || + 0 == wcscmp( FindData.cFileName, PARENT_DIRECTORY)) { + continue; // get next entry + } + FileLength = wcslen( FindData.cFileName); + + // + // Update source name. + // + if ( SourceLength + LEN_FILE_SEPARATOR + FileLength >= MAX_PATH) { + Error = ERROR_FILENAME_EXCED_RANGE; + RplDump(++RG_Assert,("Error=%d, SourceLength=%d, FileName=%ws", + Error, SourceLength, FindData.cFileName)); + LoadError( Source, Error, Flags); + break; + } + memcpy( CurrentSource+SourceLength+LEN_FILE_SEPARATOR, + FindData.cFileName, (FileLength+1) * sizeof(WCHAR)); + + // + // Update target name (this is needed both for the file case & + // the directory case below). + // + if ( Copy) { + if ( TargetLength + LEN_FILE_SEPARATOR + FileLength >= MAX_PATH) { + Error = ERROR_FILENAME_EXCED_RANGE; + RplDump(++RG_Assert,("Error=%d, TargetLength=%d, FileName=%ws", + Error, TargetLength, FindData.cFileName)); + LoadError( Target, Error, RPL_TREE_COPY); + break; + } + memcpy( CurrentTarget+TargetLength, + FILE_SEPARATOR, sizeof(FILE_SEPARATOR)); + memcpy( CurrentTarget+TargetLength+LEN_FILE_SEPARATOR, + FindData.cFileName, (FileLength+1) * sizeof(WCHAR)); + } + + if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if ( Copy) { + if ( !CopyFile( CurrentSource, CurrentTarget, FALSE)) { + Error = GetLastError(); + RplDump(++RG_Assert,("Error=%d CurrentSource=%ws CurrentTarget=%ws", + Error, CurrentSource, CurrentTarget)); + LoadError( CurrentSource, Error, RPL_TREE_COPY); + break; + } + } else if ( Delete){ + // + // If file has readonly attribute, we need to reset this + // attribute, otherwise DeleteFile() with fail with error + // access denied. + // + if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)) { + (VOID)SetFileAttributes( CurrentSource, FILE_ATTRIBUTE_NORMAL); + } + if ( !DeleteFile( CurrentSource)) { + Error = GetLastError(); + RplDump(++RG_Assert,("Error=%d CurrentSource=%ws", Error, CurrentSource)); + LoadError( CurrentSource, Error, RPL_TREE_DELETE); + break; + } + } + + // + // Set permissions after file is created (in Copy && Auxiliary case) + // + if ( Auxiliary) { + Error = (AuxiliaryCallback)( ( (Copy) ? CurrentTarget + : CurrentSource ), + pAuxiliaryBlock ); + if (Error != NERR_Success) { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + LoadError( Source, Error, RPL_TREE_AUXILIARY); + break; + } + } + + } else { + Error = RplDoTree( CurrentSource, + CurrentTarget, + Flags, + AuxiliaryCallback, + pAuxiliaryBlock); + } + } + + if (Handle != INVALID_HANDLE_VALUE) { + FindClose( Handle ); + } + + // + // Delete is the only directory operation that is done at the end. + // + if ( Delete && Error == NO_ERROR) { + // + // If directory has readonly attribute, we need to reset this + // attribute, otherwise RemoveDirectory() with fail with error + // access denied. + // + (VOID)SetFileAttributes( Source, FILE_ATTRIBUTE_DIRECTORY); + if ( !RemoveDirectory( Source)) { + Error = GetLastError(); + if (Error == ERROR_FILE_NOT_FOUND || Error == ERROR_PATH_NOT_FOUND) { + Error = NO_ERROR; + } else { + RplDump( ++RG_Assert, ( "Error=%d", Error)); + LoadError( Source, Error, RPL_TREE_DELETE); + } + } + } + return( Error); +} + + +DWORD RplTreeCopy( IN PWCHAR Source, IN PWCHAR Target) +{ + DWORD Error; + + Error = RplDoTree( Source, Target, RPL_TREE_COPY, + NULL, NULL); + if ( Error != NO_ERROR) { + return( Error); + } + return( NO_ERROR); +} + + +DWORD RplTreeDelete( IN PWCHAR Source) +{ + DWORD Error; + + Error = RplDoTree( Source, L"", RPL_TREE_DELETE, + NULL, NULL); + if ( Error != NO_ERROR) { + return( Error); + } + return( NO_ERROR); +} + + +DWORD RplMakeDir( IN PWCHAR Source) +{ + DWORD Error = NO_ERROR; + if ( !CreateDirectory( Source, NULL)) { + Error = GetLastError(); + RplDump( ++RG_Assert, ("Error=%d", Error)); + } + return( Error); +} + diff --git a/private/net/svcdlls/rpl/server/tree.h b/private/net/svcdlls/rpl/server/tree.h new file mode 100644 index 000000000..d68d34917 --- /dev/null +++ b/private/net/svcdlls/rpl/server/tree.h @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tree.h + +Abstract: + + Exports from tree.c + +Author: + + Jon Newman (jonn) 23 - November - 1993 + +Revision History: + + Vladimir Z. Vulovic (vladimv) 02 - December - 1993 + Integrated with the rest of RPL service code. + +--*/ + +DWORD RplTreeCopy( IN PWCHAR Source, IN PWCHAR Target); +DWORD RplTreeDelete( IN PWCHAR Target); +DWORD RplMakeDir( IN PWCHAR Target); + + diff --git a/private/net/svcdlls/rpl/server/treei.h b/private/net/svcdlls/rpl/server/treei.h new file mode 100644 index 000000000..019dee4d1 --- /dev/null +++ b/private/net/svcdlls/rpl/server/treei.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + tree.h + +Abstract: + + Internal definitions from tree.c + +Author: + + Jon Newman (jonn) 16 - February - 1994 + +Revision History: + + Jon Newman (jonn) 16 - February - 1994 + Added RplGrant*Perms primitives + +--*/ + +typedef DWORD (RPL_TREE_CALLBACK)( PWCHAR Path, PBOOL pAuxiliaryBlock); + +#define RPL_TREE_AUXILIARY 0x2000 // perform callback action +#define RPL_TREE_COPY 0x4000 +#define RPL_TREE_DELETE 0x8000 + +// +// Forward declarations +// + +DWORD RplDoTree( + PWCHAR Source, + PWCHAR Target, + DWORD Flags, + RPL_TREE_CALLBACK AuxiliaryCallback, + PBOOL pAuxiliaryBlock + ); + +VOID LoadError( + PWCHAR FilePath, + DWORD ActionError, + DWORD ActionFlags + ); + diff --git a/private/net/svcdlls/rpl/server/vendor.c b/private/net/svcdlls/rpl/server/vendor.c new file mode 100644 index 000000000..708a1b26c --- /dev/null +++ b/private/net/svcdlls/rpl/server/vendor.c @@ -0,0 +1,528 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + config.c + +Abstract: + + This module contains RPL config apis: ConfigEnum. + +Author: + + Vladimir Z. Vulovic (vladimv) 05 - November - 1993 + +Revision History: + + 05-Nov-1993 vladimv + Created + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "db.h" +#include "dblib.h" +#define RPLVENDOR_ALLOCATE +#include "vendor.h" +#undef RPLVENDOR_ALLOCATE + + +DWORD VendorSetInfo( + IN PRPL_SESSION pSession, + IN DWORD Level, + IN LPVOID Buffer, + OUT LPDWORD pErrorParameter + ) +{ + LPRPL_VENDOR_INFO_1 Info = Buffer; + switch( Level) { + case 1: + // + // Must initialize Flags - or will trap in GetField. + // + { + *pErrorParameter = VENDOR_Flags; + CallM( JetSetColumn( pSession->SesId, pSession->VendorTableId, + VendorTable[ VENDOR_Flags].ColumnId, + &Info->Flags, sizeof( Info->Flags), 0, NULL)); + } + NOTHING; // fall through + case 0: + if ( Info->VendorComment != NULL) { + *pErrorParameter = VENDOR_VendorComment; + CallM( JetSetColumn( pSession->SesId, pSession->VendorTableId, + VendorTable[ VENDOR_VendorComment].ColumnId, + Info->VendorComment, + ( wcslen( Info->VendorComment) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->VendorName != NULL) { + *pErrorParameter = VENDOR_VendorName; + CallM( JetSetColumn( pSession->SesId, pSession->VendorTableId, + VendorTable[ VENDOR_VendorName].ColumnId, + Info->VendorName, + ( wcslen( Info->VendorName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + break; + } + return( NO_ERROR); +} + + +DWORD VendorGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + IN OUT LPINT pSpaceLeft + ) +{ + BYTE LocalBuffer[ 300]; + PBYTE Buffer; + DWORD DataSize; + DWORD BufferSize; + JET_ERR JetError; + + switch( FieldIndex) { + case VENDOR_Flags: + Buffer = (PBYTE)pData; + BufferSize = sizeof( DWORD); + break; + default: + Buffer = LocalBuffer; + BufferSize = sizeof( LocalBuffer); + break; + } + JetError = JetRetrieveColumn( pSession->SesId, pSession->VendorTableId, + VendorTable[ FieldIndex].ColumnId, Buffer, + BufferSize, &DataSize, 0, NULL); + if ( JetError < 0) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + return( NERR_RplVendorInfoCorrupted); + } + if ( Buffer != LocalBuffer) { + if ( BufferSize == DataSize) { + return( NO_ERROR); + } else { + RplDump( ++RG_Assert, ("Bad DataSize=0x%x", DataSize)); + return( NERR_RplVendorInfoCorrupted); + } + } + // + // We have done with fixed data. From here on we deal with unicode + // strings only. + // + if ( DataSize > sizeof( LocalBuffer)) { + RplDump( ++RG_Assert, ( "Too big DataSize=0x%x", DataSize)); + return( NERR_RplVendorInfoCorrupted); + } + if ( DataSize == 0) { + if ( JetError != JET_wrnColumnNull) { + RplDump( ++RG_Assert, ( "JetError=%d", JetError)); + return( NERR_RplVendorInfoCorrupted); + } else { + *pData = NULL; // so RPC rpcrt4!_tree_size_ndr() does not bomb here + return( NO_ERROR); + } + } + if ( DataSize & 1 != 0 || wcslen((PWCHAR)LocalBuffer) + 1 != DataSize/2) { + RplDump( ++RG_Assert, ("LocalBuffer=0x%x, DataSize=0x%x", LocalBuffer, DataSize)); + return( NERR_RplVendorInfoCorrupted); + } + *pData = MIDL_user_allocate( DataSize); + if ( *pData == NULL) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + return( ERROR_NOT_ENOUGH_MEMORY); + } + memcpy( *pData, LocalBuffer, DataSize); + *pSpaceLeft -= DataSize; + return( NO_ERROR); +} + + +DWORD VendorGetInfo( + IN PRPL_SESSION pSession, + IN LPWSTR VendorName, + IN DWORD Level, + OUT LPVOID Buffer, + IN OUT PINT pSpaceLeft + ) +{ + DWORD Error; + LPRPL_VENDOR_INFO_1 Info = Buffer; + + switch( Level) { + case 1: + Error = VendorGetField( pSession, VENDOR_Flags, (LPVOID *)&Info->Flags, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 0: + Error = VendorGetField( pSession, VENDOR_VendorComment, &Info->VendorComment, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + if ( VendorName == NULL) { + Error = VendorGetField( pSession, VENDOR_VendorName, &Info->VendorName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + } else { + DWORD DataSize = (wcslen( VendorName) + 1) * sizeof(WCHAR); + Info->VendorName = MIDL_user_allocate( DataSize); + if ( Info->VendorName == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_VENDOR, ( "VendorName=0x%x", Info->VendorName)); + memcpy( Info->VendorName, VendorName, DataSize); + *pSpaceLeft -= DataSize; + } + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + return( NO_ERROR); +} + + + +VOID VendorGetInfoCleanup( + IN DWORD Level, + IN OUT LPVOID Buffer + ) +{ + LPRPL_VENDOR_INFO_1 Info = Buffer; + + switch( Level) { + case 1: + NOTHING; // fall through + case 0: + if ( Info->VendorComment != NULL) { + MIDL_user_free( Info->VendorComment); + } + if ( Info->VendorName != NULL) { + MIDL_user_free( Info->VendorName); + } + break; + } +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplVendorAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD Level, + OUT LPRPL_VENDOR_INFO_STRUCT VendorInfoStruct, + OUT LPDWORD pErrorParameter OPTIONAL + ) +{ + LPRPL_VENDOR_INFO_1 Info; + LPVOID Buffer; + DWORD Error; + DWORD ErrorParameter; + PRPL_SESSION pSession = &RG_ApiSession; + + ErrorParameter = INVALID_ERROR_PARAMETER; + Buffer = Info = VendorInfoStruct->VendorInfo1; + + switch( Level) { + case 1: + if ( Info->Flags != 0) { + ErrorParameter = VENDOR_Flags; + break; + } + if ( RPL_STRING_TOO_LONG( Info->VendorComment)) { + ErrorParameter = VENDOR_VendorComment; + break; + } + if ( !ValidHexName( Info->VendorName, RPL_VENDOR_NAME_LENGTH, TRUE)) { + ErrorParameter = VENDOR_VendorName; + break; + } + _wcsupr( Info->VendorName); + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + return( ERROR_INVALID_PARAMETER); + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + // + // Verify that VendorName is available in the database. + // + if ( RplFind( pSession, VENDOR_TABLE_TAG, Info->VendorName)) { + Error = NERR_RplVendorNameUnavailable; + goto cleanup; + } + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->VendorTableId, JET_prepInsert)); + + Error = VendorSetInfo( pSession, Level, Buffer, &ErrorParameter); + if ( Error == ERROR_SUCCESS) { + ErrorParameter = 0; + CallJ( JetUpdate( pSession->SesId, pSession->VendorTableId, NULL, 0, NULL)); + } + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( Error != ERROR_SUCCESS) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + } + return( Error); +} + + + +NET_API_STATUS NET_API_FUNCTION +NetrRplVendorDel( + IN RPL_HANDLE ServerHandle, + IN LPWSTR VendorName + ) +/*++ + If VendorName is provided then delete matching record, else delete all + adapter records. +--*/ +{ + DWORD Error; + PRPL_SESSION pSession = &RG_ApiSession; + + if ( !ValidHexName( VendorName, RPL_VENDOR_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + _wcsupr( VendorName); + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFind( pSession, VENDOR_TABLE_TAG, VendorName)) { + Error = NERR_RplVendorNotFound; + goto cleanup; + } + CallJ( JetDelete( pSession->SesId, pSession->VendorTableId)); + Error = NO_ERROR; + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplVendorEnum( + IN RPL_RPC_HANDLE ServerHandle, + IN OUT LPRPL_VENDOR_ENUM VendorEnum, + IN DWORD PrefMaxLength, + OUT LPDWORD TotalEntries, + IN OUT LPDWORD pResumeHandle OPTIONAL + ) +/*++ + +Routine Description: + +Arguments: + + pServerHandle - ptr to RPL_HANDLE + + InfoStruct - Pointer to a structure that contains the information that + RPC needs about the returned data. This structure contains the + following information: + Level - The desired information level - indicates how to + interpret the structure of the returned buffer. + EntriesRead - Indicates how many elements are returned in the + array of structures that are returned. + BufferPointer - Location for the pointer to the array of + structures that are being returned. + + PrefMaxLen - Indicates a maximum size limit that the caller will allow + for (the return buffer. + + TotalEntries - Pointer to a value that upon return indicates the total + number of entries in the "active" database. + + pResumeHandle - Inidcates where to restart the enumeration. This is an + optional parameter and can be NULL. + +Return Value: + NO_ERROR if success. + +--*/ +{ + LPBYTE Buffer; + DWORD TypicalSize; + DWORD CoreSize; + DWORD Error; + INT SpaceLeft; + DWORD ArrayLength; + DWORD EntriesRead; + BOOL InfoError; + BOOL TableEnd; + PRPL_SESSION pSession = &RG_ApiSession; + + switch( VendorEnum->Level) { + case 1: + TypicalSize = CoreSize = sizeof( RPL_VENDOR_INFO_1); + NOTHING; // fall through + case 0: + if ( VendorEnum->Level == 0) { + TypicalSize = CoreSize = sizeof( RPL_VENDOR_INFO_0); + } + TypicalSize += 20 * sizeof( WCHAR); // typical size of VendorComment + TypicalSize += 8 * sizeof( WCHAR); // typical size of VendorName + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( PrefMaxLength == -1) { + // + // If the caller has not specified a size, calculate a size + // that will hold the entire enumeration. + // + SpaceLeft = DEFAULT_BUFFER_SIZE; + } else { + SpaceLeft = PrefMaxLength; + } + + // + // Buffer space is shared by the array and by strings pointed at + // by the elements in this array. We need to decide up front how much + // space is allocated for array and how much for the strings. + // + ArrayLength = SpaceLeft / TypicalSize; + if ( ArrayLength == 0) { + ArrayLength = 1; // try to return at least one element + } + + // + // Note that MIDL_user_allocate() returns memory which is NOT initialized + // to zero. Since we do NOT use allocate all nodes, this means that all + // fields, especially pointers, in array elements must be properly set. + // + Buffer = MIDL_user_allocate( ArrayLength * CoreSize); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_VENDOR, ( + "VendorEnum: Buffer=0x%x, ArrayLength=0x%x", Buffer, ArrayLength)); + + VendorEnum->VendorInfo.Level0->Buffer = (LPRPL_VENDOR_INFO_0)Buffer; + + EntriesRead = 0; + InfoError = FALSE; + Error = NO_ERROR; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFilterFirst( pSession, VENDOR_TABLE_TAG, NULL, pResumeHandle, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + for ( ; ; ) { + memset( Buffer, 0, CoreSize); // for cleanup to work properly + Error = VendorGetInfo( pSession, NULL, VendorEnum->Level, Buffer, &SpaceLeft); + if ( Error != NO_ERROR) { + InfoError = TRUE; // clean things up without holding crit sec + break; + } + EntriesRead++; + Buffer += CoreSize; + SpaceLeft -= CoreSize; + if ( !RplFilterNext( pSession, pSession->VendorTableId, NULL, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + if ( SpaceLeft <= 0) { + Error = ERROR_MORE_DATA; + break; + } + if ( EntriesRead >= ArrayLength) { + // + // We have space available but allocated array is not big enough. + // This should NOT happen often as our intent (see above) is to + // overestimate array length. When it happens we can still try + // to reallocate array to a larger size here. This is not done + // for now (too cumbersome) & we just stop the enumeration. + // + Error = ERROR_MORE_DATA; + break; + } + } +cleanup: + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + if ( InfoError == TRUE) { + VendorGetInfoCleanup( VendorEnum->Level, Buffer); + } + if ( Error == NO_ERROR) { + *TotalEntries = EntriesRead; + } else if ( Error == ERROR_MORE_DATA) { + *TotalEntries = EntriesRead * 2; // we cheat here + } else { + // + // Cleanup in case of "bad" errors. + // + while ( EntriesRead > 0) { + EntriesRead--; + Buffer -= CoreSize; + VendorGetInfoCleanup( VendorEnum->Level, Buffer); + } + MIDL_user_free( Buffer); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_VENDOR, ("VendorEnum: EntriesRead = 0x%x", EntriesRead)); + + VendorEnum->VendorInfo.Level0->EntriesRead = EntriesRead; + if ( EntriesRead == 0) { + VendorEnum->VendorInfo.Level0->Buffer = NULL; + } + + if ( ARGUMENT_PRESENT( pResumeHandle)) { + if ( Error == ERROR_MORE_DATA && EntriesRead > 0) { + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + RplFilterSave( pSession, (DWORD)ServerHandle, NULL, + ((LPRPL_VENDOR_INFO_0)(Buffer-CoreSize))->VendorName, + pResumeHandle); + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + LeaveCriticalSection( &RG_ProtectDatabase); + } else { + *pResumeHandle = 0; // resume from beginning + } + } + return( Error); +} diff --git a/private/net/svcdlls/rpl/server/wcst.c b/private/net/svcdlls/rpl/server/wcst.c new file mode 100644 index 000000000..2b9aa40be --- /dev/null +++ b/private/net/svcdlls/rpl/server/wcst.c @@ -0,0 +1,54 @@ +/*++ + +Module Name: + + wcst.c - to verify a fix for "D0H" strings. + +Abstract: + + +--*/ + + + +#include "local.h" + +DWORD StringToDword( IN PWCHAR String) +/*++ + We would like to use generic base (0) but it does not work for + strings like "D0H". That is the reason why we first check if + the last character is 'H' or 'h'. +--*/ +{ + DWORD Length; + + Length = wcslen( String); + if ( Length == 0) { + return( 0); + } + if ( String[ Length-1] == L'H' || String[ Length-1] == L'h') { + return( wcstoul( String, NULL, 16)); + } else { + return( wcstoul( String, NULL, 0)); + } +} + +void report ( IN PWCHAR String, IN DWORD Base) +{ + PWCHAR End; + DWORD Number; + Number = wcstoul( String, &End, Base); + printf( "String = %ws, End = %ws, Base = %d, Number = 0x%x\n", String, End, Base, Number); + printf( "StringToDword(%ws)= 0x%x\n", String, StringToDword( String)); +} + +VOID _CRTAPI1 main ( VOID) +{ + report( L"D0H", 0); // End = D0H, Number = 0x0 + report( L"D0H", 16); // End = H, Number = 0xd0 + report( L"D0", 0); // End = D0, Number = 0x0 + report( L"D0", 16); // End = , Number = 0xd0 + report( L"0xD0", 0); // End = , Number = 0xd0 + report( L"0xD0", 16); // End = , Number = 0xd0 +} + diff --git a/private/net/svcdlls/rpl/server/wksta.c b/private/net/svcdlls/rpl/server/wksta.c new file mode 100644 index 000000000..ef65e9174 --- /dev/null +++ b/private/net/svcdlls/rpl/server/wksta.c @@ -0,0 +1,1471 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + wksta.c + +Abstract: + + Wksta APIs. + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Revision History: + +--*/ + +#include "local.h" +#include "rpldb.h" +#include "database.h" // RplDbFindWksta() +#include "db.h" +#include "dblib.h" +#include "profile.h" +#define RPLWKSTA_ALLOCATE +#include "wksta.h" +#undef RPLWKSTA_ALLOCATE + + +DWORD WkstaSessionDel( IN PWCHAR WkstaName) +{ + DWORD Error; + WCHAR UncWkstaName[ MAX_PATH + sizeof(DOUBLE_BACK_SLASH_STRING)]; + + memcpy( UncWkstaName, DOUBLE_BACK_SLASH_STRING, sizeof(DOUBLE_BACK_SLASH_STRING)); + wcscat( UncWkstaName, WkstaName); + + Error = NetSessionDel( NULL, UncWkstaName, NULL); + if ( Error == NO_ERROR || Error == NERR_ClientNameNotFound) { + return( NO_ERROR); + } + RplDump( ++RG_Assert, ("Error=%d", Error)); + return( Error); +} + + +DWORD WkstaGetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + OUT LPVOID * pData, + IN OUT LPINT pSpaceLeft + ) +/*++ + Currently this routine always allocates buffer for variable length data. + It would be nice to relax this assumption - so that buffer gets allocated + if and only if *pData is NULL. We would then have to redefine meaning of + pSpaceLeft: rename it into pDataSize which on entry points to the size of + data buffer & on return to the size of data returned. The caller would + then have the responsibility of subtracting the amount of space left. + + Also, various GetField routines should be unified. + + BUGBUG This is too much of a change for this late moment. +--*/ +{ + BYTE LocalBuffer[ 300]; + PBYTE Buffer; + DWORD DataSize; + DWORD BufferSize; + JET_ERR JetError; + + switch( FieldIndex) { + case WKSTA_TcpIpAddress: + case WKSTA_TcpIpSubnet: + case WKSTA_TcpIpGateway: + case WKSTA_Flags: + Buffer = (PBYTE)pData; + BufferSize = sizeof( DWORD); + break; + default: +#ifdef NOT_YET + if ( *pData == NULL) { +#endif + Buffer = LocalBuffer; + BufferSize = sizeof( LocalBuffer); +#ifdef NOT_YET + } else { + Buffer = *pData; + BufferSize = *pSpaceLeft; + } +#endif + break; + } + JetError = JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ FieldIndex].ColumnId, Buffer, + BufferSize, &DataSize, 0, NULL); + if ( JetError < 0) { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + return( NERR_RplWkstaInfoCorrupted); + } + if ( Buffer != LocalBuffer) { + if ( BufferSize == DataSize) { + return( NO_ERROR); + } else if ( DataSize == 0) { + // + // This happens if we never defined this value. Set (-1) + // as an invalid tcp/ip address. + // + *(PDWORD)pData = (DWORD)-1; + return( NO_ERROR); + } else { + RplDump( ++RG_Assert, ("Bad DataSize=0x%x", DataSize)); + return( NERR_RplWkstaInfoCorrupted); + } + } + // + // We have done with fixed data. From here on we deal with unicode + // strings only. + // + if ( DataSize > sizeof( LocalBuffer)) { + RplDump( ++RG_Assert, ( "Too big DataSize=0x%x", DataSize)); + return( NERR_RplWkstaInfoCorrupted); + } + if ( DataSize == 0) { + if ( JetError != JET_wrnColumnNull) { + RplDump( ++RG_Assert, ( "JetError=%d", JetError)); + return( NERR_RplWkstaInfoCorrupted); + } else { + *pData = NULL; // so RPC rpcrt4!_tree_size_ndr() does not bomb here + return( NO_ERROR); + } + } + if ( DataSize & 1 != 0 || wcslen((PWCHAR)LocalBuffer) + 1 != DataSize/2) { + RplDump( ++RG_Assert, ("LocalBuffer=0x%x, DataSize=0x%x", LocalBuffer, DataSize)); + return( NERR_RplWkstaInfoCorrupted); + } + *pData = MIDL_user_allocate( DataSize); + if ( *pData == NULL) { + RplDump( ++RG_Assert, ( "Error=%d", GetLastError())); + return( ERROR_NOT_ENOUGH_MEMORY); + } + memcpy( *pData, LocalBuffer, DataSize); + *pSpaceLeft -= DataSize; + return( NO_ERROR); +} + + +DWORD WkstaGetInfo( + IN PRPL_SESSION pSession, + IN LPWSTR WkstaName, + IN DWORD Level, + OUT LPVOID Buffer, + IN OUT LPINT pSpaceLeft + ) +{ + DWORD Error; + LPRPL_WKSTA_INFO_2 Info = Buffer; + + switch( Level) { + case 2: + Error = WkstaGetField( pSession, WKSTA_TcpIpGateway, (LPVOID *)&Info->TcpIpGateway, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = WkstaGetField( pSession, WKSTA_TcpIpSubnet, (LPVOID *)&Info->TcpIpSubnet, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = WkstaGetField( pSession, WKSTA_TcpIpAddress, (LPVOID *)&Info->TcpIpAddress, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = WkstaGetField( pSession, WKSTA_AdapterName, &Info->AdapterName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = WkstaGetField( pSession, WKSTA_FitFile, &Info->FitFile, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = WkstaGetField( pSession, WKSTA_BootName, &Info->BootName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 1: + Error = WkstaGetField( pSession, WKSTA_ProfileName, &Info->ProfileName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + Error = WkstaGetField( pSession, WKSTA_Flags, (LPVOID *)&Info->Flags, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + NOTHING; // fall through + case 0: + Error = WkstaGetField( pSession, WKSTA_WkstaComment, &Info->WkstaComment, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + if ( WkstaName == NULL) { + Error = WkstaGetField( pSession, WKSTA_WkstaName, &Info->WkstaName, pSpaceLeft); + if ( Error != NO_ERROR) { + return( Error); + } + } else { + DWORD DataSize = (wcslen( WkstaName) + 1) * sizeof(WCHAR); + Info->WkstaName = MIDL_user_allocate( DataSize); + if ( Info->WkstaName == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_WKSTA, ( "WkstaName=0x%x", Info->WkstaName)); + memcpy( Info->WkstaName, WkstaName, DataSize); + *pSpaceLeft -= DataSize; + } + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + return( NO_ERROR); +} + + + +VOID WkstaGetInfoCleanup( + IN DWORD Level, + IN OUT LPVOID Buffer + ) +{ + LPRPL_WKSTA_INFO_2 Info = Buffer; + switch( Level) { + case 2: + if ( Info->AdapterName != NULL) { + MIDL_user_free( Info->AdapterName); + } + if ( Info->FitFile != NULL) { + MIDL_user_free( Info->FitFile); + } + if ( Info->BootName != NULL) { + MIDL_user_free( Info->BootName); + } + NOTHING; // fall through + case 1: + if ( Info->ProfileName != NULL) { + MIDL_user_free( Info->ProfileName); + } + NOTHING; // fall through + case 0: + if ( Info->WkstaComment != NULL) { + MIDL_user_free( Info->WkstaComment); + } + if ( Info->WkstaName != NULL) { + MIDL_user_free( Info->WkstaName); + } + break; + } +} + + + +BOOL WkstaScan( + IN PRPL_SESSION pSession, + IN LPWSTR ProfileName, + IN DWORD ProfileNameSize, + IN OUT PBOOL pTableEnd + ) +{ + JET_ERR JetError; + + JetError = JetSeek( pSession->SesId, pSession->WkstaTableId, JET_bitSeekGT); + if ( JetError != JET_errSuccess) { + RplDump( RG_DebugLevel & RPL_DEBUG_WKSTA, ("WkstaScan: JetSeek => %d", JetError)); + *pTableEnd = TRUE; + return( TRUE); + } + // + // Verify that current wksta has the desired profile & at the + // same time set index range to be used with JetMove( Next). + // + CallB( JetMakeKey( pSession->SesId, pSession->WkstaTableId, ProfileName, + ProfileNameSize, JET_bitNewKey)); + JetError = JetSetIndexRange( pSession->SesId, pSession->WkstaTableId, + JET_bitRangeInclusive | JET_bitRangeUpperLimit); + if ( JetError != JET_errSuccess) { + *pTableEnd = TRUE; + } + return( TRUE); +} + + + +BOOL WkstaResumeFirst( + IN PRPL_SESSION pSession, + IN LPWSTR ProfileName, + IN LPDWORD pResumeHandle, + OUT PBOOL pTableEnd + ) +/*++ + Set currency to the first wksta for this profile, following + the wksta described by the resume handle. +--*/ +{ + BYTE ResumeValue[ RPL_MAX_PROFILE_NAME_SIZE + RPL_MAX_WKSTA_NAME_SIZE]; + DWORD ResumeSize; + JET_ERR JetError; + DWORD ProfileNameSize; + DWORD WkstaNameSize; + WCHAR WkstaName[ RPL_MAX_WKSTA_NAME_LENGTH + 1 + JETBUG_STRING_LENGTH]; + + *pTableEnd = FALSE; + + if ( ProfileName == NULL) { + CallB( JetSetCurrentIndex( pSession->SesId, pSession->WkstaTableId, WKSTA_INDEX_WkstaName)); + } else { + ProfileNameSize = (wcslen( ProfileName) + 1) * sizeof(WCHAR); + CallB( JetSetCurrentIndex( pSession->SesId, pSession->WkstaTableId, WKSTA_INDEX_ProfileNameWkstaName)); + } + // + // The call to move to the beginning of the table is not redundant. + // E.g. JET_errNoCurrentRecord will be returned in case of empty table. + // + JetError = JetMove( pSession->SesId, pSession->WkstaTableId, JET_MoveFirst, 0); + if ( JetError < 0) { + if ( JetError == JET_errRecordNotFound + || JetError == JET_errNoCurrentRecord) { + *pTableEnd = TRUE; + return( TRUE); + } else { + RplDump( ++RG_Assert, ("JetError=%d", JetError)); + return( FALSE); + } + } + if ( (ARGUMENT_PRESENT( pResumeHandle)) && *pResumeHandle != 0) { + ResumeSize = sizeof( ResumeValue); + if ( !ResumeKeyGet( pSession, *pResumeHandle, ResumeValue, &ResumeSize)) { + return( FALSE); + } + if ( ProfileName == NULL) { + CallB( JetMakeKey( pSession->SesId, pSession->WkstaTableId, ResumeValue, ResumeSize, JET_bitNewKey)); + CallB( JetSeek( pSession->SesId, pSession->WkstaTableId, JET_bitSeekGT)); + return( TRUE); + } + if ( ProfileNameSize != (wcslen( (PWCHAR)ResumeValue) + 1) * sizeof( WCHAR) + || memcmp( ProfileName, ResumeValue, ProfileNameSize)) { + RplDump( ++RG_Assert, ("ResumeValue=0x%x")); + return( FALSE); + } + WkstaNameSize = (wcslen( (PWCHAR)(ResumeValue + ProfileNameSize)) + 1) * sizeof(WCHAR); + memcpy( WkstaName, ResumeValue + ProfileNameSize, WkstaNameSize); + } else { + if ( ProfileName == NULL) { + return( TRUE); + } + WkstaNameSize = 0; + } + CallB( JetMakeKey( pSession->SesId, pSession->WkstaTableId, ProfileName, ProfileNameSize, JET_bitNewKey)); + if ( WkstaNameSize != 0) { +#ifdef RPL_JETBUG + memcpy( (PBYTE)WkstaName + WkstaNameSize, JETBUG_STRING, JETBUG_STRING_SIZE); + WkstaNameSize += JETBUG_STRING_LENGTH * sizeof(WCHAR); +#endif + CallB( JetMakeKey( pSession->SesId, pSession->WkstaTableId, WkstaName, WkstaNameSize, 0)); + } + return( WkstaScan( pSession, ProfileName, ProfileNameSize, pTableEnd)); +} + + +VOID WkstaResumeSave( + IN PRPL_SESSION pSession, + IN DWORD ServerHandle, + IN PWCHAR ProfileName, + IN PWCHAR WkstaName, + IN PDWORD pResumeHandle + ) +{ + BYTE ResumeBuffer[ 30 * sizeof(WCHAR)]; + DWORD ResumeSize; + DWORD WkstaSize; + if ( ProfileName != NULL) { + ResumeSize = (wcslen( ProfileName) + 1) * sizeof(WCHAR); + memcpy( ResumeBuffer, ProfileName, ResumeSize); + } else { + ResumeSize = 0; + } + WkstaSize = ( wcslen( WkstaName) + 1) * sizeof(WCHAR); + memcpy( ResumeBuffer + ResumeSize, WkstaName, WkstaSize); + ResumeSize += WkstaSize; + (VOID)ResumeKeySet( pSession, (DWORD)ServerHandle, ResumeBuffer, ResumeSize, pResumeHandle); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaEnum( + IN RPL_HANDLE ServerHandle, + IN LPWSTR ProfileName, + IN OUT LPRPL_WKSTA_ENUM WkstaEnum, + IN DWORD PrefMaxLength, + OUT LPDWORD TotalEntries, + OUT LPDWORD pResumeHandle OPTIONAL + ) +/*++ + For more extensive comments see related code in NetrConfigEnum. +--*/ +{ + LPBYTE Buffer; + DWORD TypicalSize; + DWORD CoreSize; + DWORD Error; + INT SpaceLeft; + DWORD ArrayLength; + DWORD EntriesRead; + JET_ERR JetError; + BOOL InfoError; + BOOL TableEnd; + PRPL_SESSION pSession = &RG_ApiSession; + + if ( ProfileName != NULL) { + _wcsupr( ProfileName); + } + + switch( WkstaEnum->Level) { + case 2: + TypicalSize = CoreSize = sizeof( RPL_WKSTA_INFO_2); + TypicalSize += 14 * sizeof( WCHAR); // typical size of AdapterName + TypicalSize += 20 * sizeof( WCHAR); // typical size of FitFile + TypicalSize += 8 * sizeof( WCHAR); // typical size of BootName + NOTHING; // fall through + case 1: + if ( WkstaEnum->Level == 1) { + TypicalSize = CoreSize = sizeof( RPL_WKSTA_INFO_1); + } + TypicalSize += 8 * sizeof( WCHAR); // typical size of ProfileName + NOTHING; // fall through + case 0: + if ( WkstaEnum->Level == 0) { + TypicalSize = CoreSize = sizeof( RPL_WKSTA_INFO_0); + } + TypicalSize += 8 * sizeof( WCHAR); // typical size of WkstaName + TypicalSize += 20 * sizeof( WCHAR); // typical size of WkstaComment + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( PrefMaxLength == -1) { + SpaceLeft = DEFAULT_BUFFER_SIZE; + } else { + SpaceLeft = PrefMaxLength; + } + + ArrayLength = SpaceLeft / TypicalSize; + if ( ArrayLength == 0) { + ArrayLength = 1; // try to return at least one element + } + + Buffer = MIDL_user_allocate( ArrayLength * CoreSize); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + RplDump( RG_DebugLevel & RPL_DEBUG_WKSTA, ( + "WkstaEnum: Buffer=0x%x, ArrayLength=0x%x", Buffer, ArrayLength)); + + WkstaEnum->WkstaInfo.Level0->Buffer = (LPRPL_WKSTA_INFO_0)Buffer; + + EntriesRead = 0; + InfoError = FALSE; + Error = NO_ERROR; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !WkstaResumeFirst( pSession, ProfileName, pResumeHandle, &TableEnd)) { + Error = NERR_RplCannotEnum; + goto cleanup; + } + if ( TableEnd == TRUE) { + goto cleanup; + } + for ( ; ; ) { + memset( Buffer, 0, CoreSize); // for cleanup to work properly + Error = WkstaGetInfo( pSession, NULL, WkstaEnum->Level, Buffer, &SpaceLeft); + if ( Error != NO_ERROR) { + InfoError = TRUE; // clean things up without holding crit sec + break; + } + EntriesRead++; + Buffer += CoreSize; + SpaceLeft -= CoreSize; + JetError = JetMove( pSession->SesId, pSession->WkstaTableId, JET_MoveNext, 0); + if ( JetError != JET_errSuccess) { + break; // assume end of table + } + if ( SpaceLeft <= 0) { + Error = ERROR_MORE_DATA; + break; + } + if ( EntriesRead >= ArrayLength) { + Error = ERROR_MORE_DATA; + break; + } + } +cleanup: + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + if ( InfoError == TRUE) { + WkstaGetInfoCleanup( WkstaEnum->Level, Buffer); + } + if ( Error == NO_ERROR) { + *TotalEntries = EntriesRead; + } else if ( Error == ERROR_MORE_DATA) { + *TotalEntries = EntriesRead * 2; // we cheat here + } else { + // + // Cleanup in case of "bad" errors. + // + while ( EntriesRead > 0) { + EntriesRead--; + Buffer -= CoreSize; + WkstaGetInfoCleanup( WkstaEnum->Level, Buffer); + } + MIDL_user_free( Buffer); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_WKSTA, ("WkstaEnum: EntriesRead = 0x%x", EntriesRead)); + + WkstaEnum->WkstaInfo.Level0->EntriesRead = EntriesRead; + if ( EntriesRead == 0) { + WkstaEnum->WkstaInfo.Level0->Buffer = NULL; + } + + if ( ARGUMENT_PRESENT( pResumeHandle)) { + if ( Error == ERROR_MORE_DATA && EntriesRead > 0) { + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + WkstaResumeSave( pSession, (DWORD)ServerHandle, ProfileName, + ((LPRPL_WKSTA_INFO_0)(Buffer-CoreSize))->WkstaName, + pResumeHandle + ); + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + LeaveCriticalSection( &RG_ProtectDatabase); + } else { + *pResumeHandle = 0; // resume from beginning + } + } + + return( Error); +} + + +BOOL WkstaFindFirst( + IN PRPL_SESSION pSession, + IN PWCHAR ProfileName + ) +/*++ + Returns TRUE if it can find a record (the first record) using input + profile name. Returns FALSE otherwise. + + We cannot use SetIndexRange technique here because ProfileName is only + the first part of an index & we would never find a match. +--*/ +{ + DWORD ProfileNameSize; + JET_ERR JetError; + BYTE Data[ 300]; + DWORD DataSize; + + CallB( JetSetCurrentIndex( pSession->SesId, pSession->WkstaTableId, WKSTA_INDEX_ProfileNameWkstaName)); + ProfileNameSize = ( wcslen( ProfileName) + 1) * sizeof(WCHAR); + CallB( JetMakeKey( pSession->SesId, pSession->WkstaTableId, ProfileName, ProfileNameSize, JET_bitNewKey)); + JetError = JetSeek( pSession->SesId, pSession->WkstaTableId, JET_bitSeekGE); + if ( JetError < 0) { + return( FALSE); + } + CallB( JetRetrieveColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_ProfileName].ColumnId, Data, + sizeof( Data), &DataSize, 0, NULL)); + if ( ProfileNameSize != DataSize) { + return( FALSE); + } + if ( memcmp( ProfileName, Data, DataSize) != 0) { + return( FALSE); + } + return( TRUE); // we found wksta record using this profile +} + + + +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaGetInfo( + IN RPL_HANDLE ServerHandle, + IN LPWSTR WkstaName, + IN DWORD Level, + OUT LPRPL_WKSTA_INFO_STRUCT WkstaInfoStruct + ) +{ + DWORD Error; + LPBYTE Buffer; + DWORD DataSize; + PRPL_SESSION pSession = &RG_ApiSession; + + _wcsupr( WkstaName); + + switch( Level) { + case 0: + Buffer = MIDL_user_allocate( sizeof( RPL_WKSTA_INFO_0)); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + memset( Buffer, 0, sizeof( RPL_WKSTA_INFO_0)); + WkstaInfoStruct->WkstaInfo0 = (LPRPL_WKSTA_INFO_0)Buffer; + break; + case 1: + Buffer = MIDL_user_allocate( sizeof( RPL_WKSTA_INFO_1)); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + memset( Buffer, 0, sizeof( RPL_WKSTA_INFO_1)); + WkstaInfoStruct->WkstaInfo1 = (LPRPL_WKSTA_INFO_1)Buffer; + break; + case 2: + Buffer = MIDL_user_allocate( sizeof( RPL_WKSTA_INFO_2)); + if ( Buffer == NULL) { + return( ERROR_NOT_ENOUGH_MEMORY); + } + memset( Buffer, 0, sizeof( RPL_WKSTA_INFO_2)); + WkstaInfoStruct->WkstaInfo2 = (LPRPL_WKSTA_INFO_2)Buffer; + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFind( pSession, WKSTA_TABLE_TAG, WkstaName)) { + Error = NERR_RplWkstaNotFound; + } else { + Error = WkstaGetInfo( pSession, WkstaName, Level, Buffer, &DataSize); + } + + Call( JetCommitTransaction( pSession->SesId, 0)); + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( Error != NO_ERROR) { + WkstaGetInfoCleanup( Level, Buffer); + switch( Level) { + case 0: + MIDL_user_free( Buffer); + WkstaInfoStruct->WkstaInfo0 = NULL; + break; + case 1: + MIDL_user_free( Buffer); + WkstaInfoStruct->WkstaInfo1 = NULL; + break; + case 2: + MIDL_user_free( Buffer); + WkstaInfoStruct->WkstaInfo2 = NULL; + break; + } + } + return( Error); +} + + +DWORD WkstaSetField( + IN PRPL_SESSION pSession, + IN DWORD FieldIndex, + IN LPVOID Data, + IN DWORD DataSize + ) +{ + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ FieldIndex].ColumnId, Data, DataSize, 0, NULL)); + return( NO_ERROR); +} + + +DWORD WkstaSetInfo( + IN PRPL_SESSION pSession, + IN DWORD Level, + IN LPVOID Buffer, + OUT LPDWORD pErrorParameter + ) +/*++ + -1 used to be a special "do not change value" for TcpIp columns. + This was discontinued. The reason is, the only way for an admin + to disable TCP/IP on the client, is to set TcpIp columns to -1 which + then causes rpl service not to send TCP/IP addresss to rpl client. + + BUGBUG Whole TCP/IP approach has to be revisited, taking DHCP into account. +--*/ +{ + LPRPL_WKSTA_INFO_2 Info = Buffer; + switch( Level) { + case 2: +// if ( Info->TcpIpGateway != -1) { + { + *pErrorParameter = WKSTA_TcpIpGateway; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpGateway].ColumnId, + &Info->TcpIpGateway, sizeof( Info->TcpIpGateway), 0, NULL)); + } +// if ( Info->TcpIpSubnet != -1) { + { + *pErrorParameter = WKSTA_TcpIpSubnet; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpSubnet].ColumnId, + &Info->TcpIpSubnet, sizeof( Info->TcpIpSubnet), 0, NULL)); + } +// if ( Info->TcpIpAddress != -1) { + { + *pErrorParameter = WKSTA_TcpIpAddress; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_TcpIpAddress].ColumnId, + &Info->TcpIpAddress, sizeof( Info->TcpIpAddress), 0, NULL)); + } + if ( Info->AdapterName != NULL) { + *pErrorParameter = WKSTA_AdapterName; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_AdapterName].ColumnId, + Info->AdapterName, + ( wcslen( Info->AdapterName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->FitFile != NULL) { + *pErrorParameter = WKSTA_FitFile; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_FitFile].ColumnId, + Info->FitFile, + ( wcslen( Info->FitFile) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->BootName != NULL) { + *pErrorParameter = WKSTA_BootName; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_BootName].ColumnId, + Info->BootName, + ( wcslen( Info->BootName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + NOTHING; // fall through + case 1: + if ( Info->ProfileName != NULL) { + *pErrorParameter = WKSTA_ProfileName; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_ProfileName].ColumnId, + Info->ProfileName, + ( wcslen( Info->ProfileName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->Flags != 0) { + *pErrorParameter = WKSTA_Flags; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_Flags].ColumnId, + &Info->Flags, sizeof( Info->Flags), 0, NULL)); + } + NOTHING; // fall through + case 0: + if ( Info->WkstaComment != NULL) { + *pErrorParameter = WKSTA_WkstaComment; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_WkstaComment].ColumnId, + Info->WkstaComment, + ( wcslen( Info->WkstaComment) + 1) * sizeof(WCHAR), + 0, NULL)); + } + if ( Info->WkstaName != NULL) { + *pErrorParameter = WKSTA_WkstaName; + CallM( JetSetColumn( pSession->SesId, pSession->WkstaTableId, + WkstaTable[ WKSTA_WkstaName].ColumnId, + Info->WkstaName, + ( wcslen( Info->WkstaName) + 1) * sizeof(WCHAR), + 0, NULL)); + } + break; + } + return( NO_ERROR); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaSetInfo( + IN RPL_HANDLE ServerHandle, + IN LPWSTR WkstaName, + IN DWORD Level, + IN LPRPL_WKSTA_INFO_STRUCT WkstaInfoStruct, + OUT LPDWORD pErrorParameter OPTIONAL + ) +/*++ + Note that changes at info level 1 (ProfileName) imply that we need to + make changes to info level 2 (BootName & FitFile) parameters. + + Here we pay for the redundancy in wksta records. +--*/ +{ + DWORD Error; + DWORD ErrorParameter; + LPVOID Buffer; + LPRPL_WKSTA_INFO_2 Info; + DWORD Flags; + DWORD Sharing; + DWORD LogonInput; + DWORD Dhcp; + DWORD DeleteUserAccount; + PWCHAR ProfileName; + DWORD TargetSharing; + DWORD TargetLogonInput; + DWORD TargetDhcp; + DWORD TargetDeleteUserAccount; + PWCHAR TargetProfileName; + PWCHAR TargetWkstaName; + INT SpaceLeft; + BOOL TreeModified; + PWCHAR FitFile; + PWCHAR BootName; + PRPL_SESSION pSession = &RG_ApiSession; + + ErrorParameter = INVALID_ERROR_PARAMETER; + FitFile = NULL; + BootName = NULL; + TreeModified = FALSE; + Sharing = 0; + TargetSharing = 0; + ProfileName = NULL; + TargetProfileName = NULL; + _wcsupr( WkstaName); + TargetWkstaName = NULL; + + Info = Buffer = WkstaInfoStruct->WkstaInfo2; + switch( Level) { + case 2: + if ( !ValidName( Info->FitFile, RPL_MAX_STRING_LENGTH, FALSE)) { + ErrorParameter = WKSTA_FitFile; + break; + } + if ( !ValidHexName( Info->AdapterName, RPL_ADAPTER_NAME_LENGTH, FALSE)) { + ErrorParameter = WKSTA_AdapterName; + break; + } + if ( Info->AdapterName != NULL) { + _wcsupr( Info->AdapterName); + } + NOTHING; // fall through + case 1: + if ( !ValidName( Info->ProfileName, RPL_MAX_PROFILE_NAME_LENGTH, FALSE)) { + ErrorParameter = WKSTA_ProfileName; + break; + } + if ( Info->ProfileName != NULL) { + _wcsupr( Info->ProfileName); + } + TargetProfileName = Info->ProfileName; + if ( Info->Flags & ~WKSTA_FLAGS_MASK) { + ErrorParameter = WKSTA_Flags; + break; + } + TargetSharing = Info->Flags & WKSTA_FLAGS_MASK_SHARING; + switch ( TargetSharing) { + case 0: + case WKSTA_FLAGS_SHARING_TRUE: + case WKSTA_FLAGS_SHARING_FALSE: + break; + default: + ErrorParameter = WKSTA_Flags; + break; + } + TargetLogonInput = Info->Flags & WKSTA_FLAGS_MASK_LOGON_INPUT; + switch ( TargetLogonInput) { + case 0: + case WKSTA_FLAGS_LOGON_INPUT_REQUIRED: + case WKSTA_FLAGS_LOGON_INPUT_OPTIONAL: + case WKSTA_FLAGS_LOGON_INPUT_IMPOSSIBLE: + break; + default: + ErrorParameter = WKSTA_Flags; + break; + } + TargetDhcp = Info->Flags & WKSTA_FLAGS_MASK_DHCP; + switch( TargetDhcp) { + case 0: + case WKSTA_FLAGS_DHCP_TRUE: + case WKSTA_FLAGS_DHCP_FALSE: + break; + default: + ErrorParameter = WKSTA_Flags; + break; + } + TargetDeleteUserAccount = Info->Flags & WKSTA_FLAGS_MASK_DELETE; + switch( TargetDeleteUserAccount) { + case 0: + case WKSTA_FLAGS_DELETE_TRUE: + case WKSTA_FLAGS_DELETE_FALSE: + break; + default: + ErrorParameter = WKSTA_Flags; + break; + } + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + break; + } + NOTHING; // fall through + case 0: + if ( RPL_STRING_TOO_LONG( Info->WkstaComment)) { + ErrorParameter = WKSTA_WkstaComment; + break; + } + if ( !ValidName( Info->WkstaName, RPL_MAX_WKSTA_NAME_LENGTH, FALSE)) { + ErrorParameter = WKSTA_WkstaName; + break; + } + if ( Info->WkstaName != NULL) { + _wcsupr( Info->WkstaName); + // + // Take new wksta name into consideration only if it is different + // than old wksta name (we ignore NOOP requests). + // + if ( wcscmp( Info->WkstaName, WkstaName) != 0) { + TargetWkstaName = Info->WkstaName; + } + } + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + return( ERROR_INVALID_PARAMETER); + } + ErrorParameter = 0; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( TargetWkstaName != NULL) { + // + // Verify that TargetWkstaName is available in the database. + // Once we pass this check, disk routines below will nuke any + // old stuff in existing TargetWkstaName trees. + // + if ( RplFind( pSession, WKSTA_TABLE_TAG, TargetWkstaName)) { + Error = NERR_RplWkstaNameUnavailable; + goto cleanup; + } + } + + if ( !RplFind( pSession, WKSTA_TABLE_TAG, WkstaName)) { + Error = NERR_RplWkstaNotFound; + goto cleanup; + } + Error = WkstaGetField( pSession, WKSTA_Flags, (LPVOID *)&Flags, &SpaceLeft); + if ( Error != NO_ERROR) { + goto cleanup; + } + Dhcp = Flags & WKSTA_FLAGS_MASK_DHCP; + DeleteUserAccount = Flags & WKSTA_FLAGS_MASK_DELETE; + LogonInput = Flags & WKSTA_FLAGS_MASK_LOGON_INPUT; + Sharing = Flags & WKSTA_FLAGS_MASK_SHARING; + + if ( TargetSharing != 0 || TargetProfileName != NULL + || TargetWkstaName != NULL) { + Error = WkstaSessionDel( WkstaName); + if ( Error != NO_ERROR) { + goto cleanup; + } + if ( TargetSharing == Sharing) { + TargetSharing = 0; // ignore NOOP requests + } + Error = WkstaGetField( pSession, WKSTA_ProfileName, &ProfileName, &SpaceLeft); + if ( Error != NO_ERROR) { + goto cleanup; + } + if ( TargetProfileName != NULL && wcscmp( TargetProfileName, ProfileName) == 0) { + TargetProfileName = NULL; // ignore NOOP requests + } + } + + if ( TargetSharing != 0 || TargetProfileName != NULL) { + if ( !RplFind( pSession, PROFILE_TABLE_TAG, + TargetProfileName != NULL ? TargetProfileName : ProfileName)) { + Error = NERR_RplProfileNotFound; + goto cleanup; + } + if ( TargetProfileName != NULL) { + Error = ProfileGetField( pSession, PROFILE_BootName, &BootName, &SpaceLeft); + if ( Error != NO_ERROR) { + goto cleanup; + } + if ( !BootFind( pSession, BootName, + AdapterNameToVendorId( Info->AdapterName))) { + Error = NERR_RplIncompatibleProfile; + goto cleanup; + } + } + Error = ProfileGetField( pSession, (TargetSharing != 0 ? TargetSharing : Sharing) + == WKSTA_FLAGS_SHARING_TRUE ? PROFILE_FitShared : PROFILE_FitPersonal, + &FitFile, &SpaceLeft); + if ( Error != NO_ERROR) { + goto cleanup; + } + } + + if ( TargetSharing != 0 || TargetProfileName != NULL + || TargetWkstaName != NULL) { + // + // Create new tree, or add new branches to the current tree. + // + TreeModified = TRUE; // to undo tree changes in case of errors below + Error = WkstaDiskSet( ADD_NEW_BRANCHES, WkstaName, ProfileName, Sharing, + TargetWkstaName, TargetProfileName, TargetSharing); + if ( Error != NO_ERROR) { + goto cleanup; + } + } + + // + // Tree is ready and we can call jet to modify database wksta record. + // + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->WkstaTableId, JET_prepReplace)); + if ( TargetSharing == 0) { + // + // TargetSharing may have been reset to 0 due to being equal + // to Sharing. If so, then the line below is a no-op. + // + Info->Flags |= Sharing; + } + if ( TargetLogonInput == 0) { + Info->Flags |= LogonInput; + } + if ( TargetDhcp == 0) { + Info->Flags |= Dhcp; + } + if ( TargetDeleteUserAccount == 0) { + Info->Flags |= DeleteUserAccount; + } + Error = WkstaSetInfo( pSession, Level, Buffer, &ErrorParameter); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + if ( BootName != NULL) { + Error = WkstaSetField( pSession, WKSTA_BootName, BootName, + (wcslen(BootName)+1)*sizeof(WCHAR)); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + } + if ( FitFile != NULL) { + Error = WkstaSetField( pSession, WKSTA_FitFile, FitFile, + (wcslen(FitFile)+1)*sizeof(WCHAR)); + if ( Error != ERROR_SUCCESS) { + goto cleanup; + } + } + CallJ( JetUpdate( pSession->SesId, pSession->WkstaTableId, NULL, 0, NULL)); + + // + // Remove old tree, or old branches in the current tree. + // + WkstaDiskSet( DEL_OLD_BRANCHES, WkstaName, ProfileName, Sharing, + TargetWkstaName, TargetProfileName, TargetSharing); + +cleanup: + if ( Error != NO_ERROR && TreeModified == TRUE) { + // + // Remove new tree, or new branches in the current tree. + // + WkstaDiskSet( DEL_NEW_BRANCHES, WkstaName, ProfileName, Sharing, + TargetWkstaName, TargetProfileName, TargetSharing); + } + + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( FitFile != NULL) { + MIDL_user_free( FitFile); + } + if ( BootName != NULL) { + MIDL_user_free( BootName); + } + if ( ProfileName != NULL) { + MIDL_user_free( ProfileName); + } + if ( Error != ERROR_SUCCESS) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + } + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaAdd( + IN RPL_HANDLE ServerHandle, + IN DWORD Level, + IN LPRPL_WKSTA_INFO_STRUCT WkstaInfoStruct, + OUT LPDWORD pErrorParameter OPTIONAL + ) +{ + LPRPL_WKSTA_INFO_2 Info; + LPVOID Buffer; + DWORD Error; + DWORD ErrorParameter; + DWORD DataSize; + DWORD Sharing; + BOOL FreeBootName = FALSE; + BOOL FreeFitFile = FALSE; + PRPL_SESSION pSession = &RG_ApiSession; + + ErrorParameter = INVALID_ERROR_PARAMETER; + + Buffer = Info = WkstaInfoStruct->WkstaInfo2; + switch( Level) { + case 2: + if ( !ValidHexName( Info->AdapterName, RPL_ADAPTER_NAME_LENGTH, TRUE)) { + ErrorParameter = WKSTA_AdapterName; + break; + } + _wcsupr( Info->AdapterName); + if ( !ValidName( Info->ProfileName, RPL_MAX_PROFILE_NAME_LENGTH, TRUE)) { + ErrorParameter = WKSTA_ProfileName; + break; + } + _wcsupr( Info->ProfileName); + if ( Info->Flags & ~WKSTA_FLAGS_MASK) { + ErrorParameter = WKSTA_Flags; + break; + } + Sharing = Info->Flags & WKSTA_FLAGS_MASK_SHARING; + switch ( Sharing) { + case WKSTA_FLAGS_SHARING_TRUE: + case WKSTA_FLAGS_SHARING_FALSE: + break; + default: + ErrorParameter = WKSTA_Flags; + break; + } + switch( Info->Flags & WKSTA_FLAGS_MASK_LOGON_INPUT) { + case WKSTA_FLAGS_LOGON_INPUT_REQUIRED: + case WKSTA_FLAGS_LOGON_INPUT_OPTIONAL: + case WKSTA_FLAGS_LOGON_INPUT_IMPOSSIBLE: + break; + default: + ErrorParameter = WKSTA_Flags; + break; + } + switch( Info->Flags & WKSTA_FLAGS_MASK_DHCP) { + case WKSTA_FLAGS_DHCP_TRUE: + case WKSTA_FLAGS_DHCP_FALSE: + break; + default: + ErrorParameter = WKSTA_Flags; + break; + } + switch( Info->Flags & WKSTA_FLAGS_MASK_DELETE) { + case WKSTA_FLAGS_DELETE_TRUE: + case WKSTA_FLAGS_DELETE_FALSE: + break; + default: + ErrorParameter = WKSTA_Flags; + break; + } + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + break; + } + if ( RPL_STRING_TOO_LONG( Info->WkstaComment)) { + ErrorParameter = WKSTA_WkstaComment; + break; + } + if ( !ValidName( Info->WkstaName, RPL_MAX_WKSTA_NAME_LENGTH, TRUE)) { + ErrorParameter = WKSTA_WkstaName; + break; + } + _wcsupr( Info->WkstaName); + break; + default: + return( ERROR_INVALID_LEVEL); + break; + } + + if ( ErrorParameter != INVALID_ERROR_PARAMETER) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + return( ERROR_INVALID_PARAMETER); + } + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + // + // Verify that WkstaName is available in the database. + // + if ( RplFind( pSession, WKSTA_TABLE_TAG, Info->WkstaName)) { + Error = NERR_RplWkstaNameUnavailable; + goto cleanup; + } + // + // Verify that AdapterName is available in the database. + // + if ( RplDbFindWksta( pSession, Info->AdapterName)) { + Error = NERR_RplAdapterNameUnavailable; + goto cleanup; + } + if ( !RplFind( pSession, PROFILE_TABLE_TAG, Info->ProfileName)) { + Error = NERR_RplProfileNotFound; + goto cleanup; + } + // + // Verify that there is a boot block record for (AdapterName, ProfileName) + // pair. This in turn "validates" AdapterName. + // + if ( Info->BootName == NULL) { + Error = ProfileGetField( pSession, PROFILE_BootName, &Info->BootName, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + FreeBootName = TRUE; + } + if ( !BootFind( pSession, Info->BootName, AdapterNameToVendorId( Info->AdapterName))) { + Error = NERR_RplIncompatibleProfile; + goto cleanup; + } + + if ( Info->FitFile == NULL) { + Error = ProfileGetField( pSession, Sharing == WKSTA_FLAGS_SHARING_TRUE + ? PROFILE_FitShared : PROFILE_FitPersonal, &Info->FitFile, + &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + FreeFitFile = TRUE; + } + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->WkstaTableId, JET_prepInsert)); + + Error = WkstaSetInfo( pSession, Level, Buffer, &ErrorParameter); + if ( Error == ERROR_SUCCESS) { + ErrorParameter = 0; + CallJ( JetUpdate( pSession->SesId, pSession->WkstaTableId, NULL, 0, NULL)); + } + + Error = WkstaDiskAdd( TRUE, Info->WkstaName, Info->ProfileName, Sharing); + if ( Error != NO_ERROR) { + // + // WkstaDiskAdd deletion code does not care about ProfileName or Sharing + // We do not need to delete the new record since we are going to rollback + // the transaction. + // + WkstaDiskAdd( FALSE, Info->WkstaName, NULL, FALSE); + } + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + if ( FreeBootName == TRUE) { + MIDL_user_free( Info->BootName); + Info->BootName = NULL; + } + if ( FreeFitFile == TRUE) { + MIDL_user_free( Info->FitFile); + Info->FitFile = NULL; + } + if ( Error != ERROR_SUCCESS) { + if ( ARGUMENT_PRESENT( pErrorParameter)) { + *pErrorParameter = ErrorParameter; + } + } + return( Error); +} + + + +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaDel( + IN RPL_HANDLE ServerHandle, + IN LPWSTR WkstaName + ) +{ + DWORD Error; + PRPL_SESSION pSession = &RG_ApiSession; + + _wcsupr( WkstaName); + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + if ( !RplFind( pSession, WKSTA_TABLE_TAG, WkstaName)) { + Error = NERR_RplWkstaNotFound; + goto cleanup; + } + Error = WkstaSessionDel( WkstaName); + if ( Error != NO_ERROR) { + goto cleanup; + } + CallJ( JetDelete( pSession->SesId, pSession->WkstaTableId)); + // + // WkstaDiskAdd deletion code does not care about ProfileName or Sharing + // + WkstaDiskAdd( FALSE, WkstaName, NULL, FALSE); + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + return( Error); +} + + +NET_API_STATUS NET_API_FUNCTION +NetrRplWkstaClone( + IN RPL_HANDLE ServerHandle, + IN LPWSTR SourceWkstaName, + IN LPWSTR TargetWkstaName, + IN LPWSTR TargetWkstaComment, + IN LPWSTR TargetAdapterName, + IN DWORD TargetTcpIpAddress + ) +{ + RPL_WKSTA_INFO_2 Info; + DWORD Error; + DWORD ErrorParameter; + DWORD DataSize; + PWCHAR SaveWkstaName; + PWCHAR SaveWkstaComment; + PWCHAR SaveAdapterName; + PWCHAR BootName; + BOOL FreeBootName = FALSE; + INT SpaceLeft; + PRPL_SESSION pSession = &RG_ApiSession; + + if ( !ValidName( SourceWkstaName, RPL_MAX_WKSTA_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + _wcsupr( SourceWkstaName); + if ( !ValidName( TargetWkstaName, RPL_MAX_WKSTA_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + _wcsupr( TargetWkstaName); + if ( !ValidHexName( TargetAdapterName, RPL_ADAPTER_NAME_LENGTH, TRUE)) { + return( ERROR_INVALID_PARAMETER); + } + _wcsupr( TargetAdapterName); + if ( RPL_STRING_TOO_LONG( TargetWkstaComment)) { + return( ERROR_INVALID_PARAMETER); + } + + // + // Zero all the pointers so we can safely call WkstaGetInfoClenaup(). + // in all the cases. + // + memset( &Info, 0, sizeof( Info)); + SaveWkstaName = NULL; + SaveWkstaComment = NULL; + SaveAdapterName = NULL; + + EnterCriticalSection( &RG_ProtectDatabase); + Call( JetBeginTransaction( pSession->SesId)); + + // + // Verify that TargetWkstaName is available in the database. + // + if ( RplFind( pSession, WKSTA_TABLE_TAG, TargetWkstaName)) { + Error = NERR_RplWkstaNameUnavailable; + goto cleanup; + } + // + // Verify that TargetAdapterName is available in the database. + // + if ( RplDbFindWksta( pSession, TargetAdapterName)) { + Error = NERR_RplAdapterNameUnavailable; + goto cleanup; + } + // + // Verify that SourceWkstaName exists. + // + if ( !RplFind( pSession, WKSTA_TABLE_TAG, SourceWkstaName)) { + Error = NERR_RplWkstaNotFound; + goto cleanup; + } + Error = WkstaGetInfo( pSession, SourceWkstaName, 2, &Info, &DataSize); + if ( Error != NO_ERROR) { + goto cleanup; + } + // + // Verify that Source profile is compatible with Target workstation. + // + if ( !RplFind( pSession, PROFILE_TABLE_TAG, Info.ProfileName)) { + Error = NERR_RplProfileNotFound; + goto cleanup; + } + Error = ProfileGetField( pSession, PROFILE_BootName, &BootName, &SpaceLeft); + if ( Error != NO_ERROR) { + goto cleanup; + } + FreeBootName = TRUE; + if ( !BootFind( pSession, BootName, + AdapterNameToVendorId( TargetAdapterName))) { + Error = NERR_RplIncompatibleProfile; + goto cleanup; + } + // + // Save source data, then overload target data. + // + SaveWkstaName = Info.WkstaName; + SaveWkstaComment = Info.WkstaComment; + SaveAdapterName = Info.AdapterName; + Info.WkstaName = TargetWkstaName; + Info.WkstaComment = TargetWkstaComment; + Info.AdapterName = TargetAdapterName; + Info.TcpIpAddress = TargetTcpIpAddress; + + CallJ( JetPrepareUpdate( pSession->SesId, pSession->WkstaTableId, JET_prepInsert)); + + Error = WkstaSetInfo( pSession, 2, &Info, &ErrorParameter); + if ( Error == ERROR_SUCCESS) { + CallJ( JetUpdate( pSession->SesId, pSession->WkstaTableId, NULL, 0, NULL)); + } + + Error = WkstaDiskClone( TRUE, SourceWkstaName, TargetWkstaName); + if ( Error != NO_ERROR) { + // + // Delete new tree. We do not need to delete the new record + // since we are going to rollback the transaction. + // + WkstaDiskClone( FALSE, SourceWkstaName, TargetWkstaName); + } + +cleanup: + if ( Error == NO_ERROR) { + Call( JetCommitTransaction( pSession->SesId, JET_bitCommitFlush)); + } else { + Call( JetRollback( pSession->SesId, JET_bitRollbackAll)); + } + LeaveCriticalSection( &RG_ProtectDatabase); + + // + // Restore source data, then release it. + // + Info.WkstaName = SaveWkstaName; + Info.WkstaComment = SaveWkstaComment; + Info.AdapterName = SaveAdapterName; + WkstaGetInfoCleanup( 2, &Info); + if ( FreeBootName == TRUE) { + MIDL_user_free( BootName); + } + return( Error); +} + + diff --git a/private/net/svcdlls/rpl/server/worker.c b/private/net/svcdlls/rpl/server/worker.c new file mode 100644 index 000000000..8b2b74a55 --- /dev/null +++ b/private/net/svcdlls/rpl/server/worker.c @@ -0,0 +1,572 @@ +/*++ + +Copyright (c) 1987-1993 Microsoft Corporation + +Module Name: + + worker.c + +Abstract: + + Module is the code of RPL worker thread. Worker thread initializes + the connection to a workstation, sends a boot block (defined in + in a boot block definition file) to it and dies. + + Provides similar functionality to rplwork.c in LANMAN 2.1 code. + +Author: + + Vladimir Z. Vulovic 27 - July - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +#include "local.h" +#include "report.h" +#include "read.h" +#include "open.h" +#ifdef RPL_DEBUG +#include "request.h" // need DebugCheckDList() +#endif +#include "worker.h" + +DWORD usCurWinSize = 0; // the current window size + + +BOOL Worker( IN OUT PRPL_WORKER_DATA pWorkerData) +/*++ + +Routine Description: + xxx + +Arguments: + pWorkerData - ptr to WORKER_DATA structure + +Return Value: + FALSE if fatal error occurs (configuration errors are fatal), in this + case we also set termination event + TRUE if success or some of expected network errors occur + +--*/ +{ + POPEN_INFO pOpenInfo; + PRCB pRcb; + DWORD status; + DWORD max_buf_len; + DWORD offset; + DWORD bytes_read; + DWORD wait_ack_timeout; // the timeout of the ack wait + DWORD retries; + DWORD patch_offset; + + pOpenInfo = pWorkerData->pOpenInfo; + pRcb = pWorkerData->pRcb; + offset = 0; + retries = 0; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( + "++Worker(0x%x): pRcb=0x%x", pWorkerData, pRcb)); + + *(PBYTE)&pRcb->flags = 0; // reset the error flags + + // + // Send FOUND frame, telling the client that FIND has been received + // and we are ready to receive SEND.FILE.REQUEST + // + + RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,( + "Worker(0x%x): claim client pRcb=0x%x", pWorkerData, pRcb)); + + if ( !RplDlcFound( pOpenInfo, pRcb)) { + // + // Timeout in sending FOUND frames is not fatal. Terminate this + // thread but leave RPL server live and well. + // + RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,( + "Worker(0x%x): Found() fails pRcb=0x%x AdapterName=%ws", + pWorkerData, pRcb, pRcb->AdapterName)); + return( TRUE); // so we do not post any events + } + + RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,( + "Worker(0x%x): RpldFound() => pRcb=0x%x AdapterName=%ws", + pWorkerData, pRcb, pRcb->AdapterName)); + + // + // Wait until client sends Send File Request or we time out. + // + status = WaitForSingleObject( pRcb->SF_wakeup, GET_SF_REQUEST_TIMEOUT); + if ( status == WAIT_TIMEOUT) { + // + // Non-critical error, client probably chose another server. + // + RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,( + "--Worker(0x%x): timeout while waiting for SFR, pRcb=0x%x", + pWorkerData, pRcb)); + return( TRUE); + } else if ( status != ERROR_SUCCESS) { + RplDump( ++RG_Assert,( "pRcb=0x%x status=%d", pRcb, status)); + return( FALSE); // there is nothing we can do here + } + if ( pRcb->sfr_seq_number != 0) { + // + // Ignore idiot clients. + // + RplDump( ++RG_Assert,( "pRcb=0x%x sfr_seq_number=%d", pRcb, pRcb->sfr_seq_number)); + return( FALSE); + } + if ( !RplOpenData( pWorkerData)) { // Get this client's data + return( FALSE); + } + + // + // Set up the offset for patching of the boot block header to + // address to the rplboot header (CPU independent boot). + // + + patch_offset = + (DWORD)&(((PRPLBOOT_HEADER)(pWorkerData->jump_address))->phBootBlockHeader) + + OFFSET_RPLBOOT_HDR - pWorkerData->base_address; + + // Round max frame down to the next paragraph (otherwise algorithms of + // the normal read would be too complicated). Then copy this value to + // stack, it's faster. + + max_buf_len = pRcb->max_frame &= 0xfff0; + RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,( + "Worker(0x%x): pRcb=0x%x max_buf_len=%d", + pWorkerData, pRcb, max_buf_len)); + + // + // Initialize client specific send buffers. + // + pWorkerData->pDataBuffer = RplMemAlloc( pWorkerData->MemoryHandle, max_buf_len); + if ( pWorkerData->pDataBuffer == NULL) { + return( FALSE); + } + + pWorkerData->send_buf_len = max_buf_len; + + *(PUCHAR)&pRcb->send_flags = 0; // reset all bits in send_flags + pRcb->send_flags.locate_enable = TRUE; // for first frame + + // + // Read boot block and sent it wksta until all data has been sent. + // Only if we succeed we get beyond the bottom of this loop. + // + for ( ; ;) { + LONG tmp_long; + + offset = pRcb->fdr_seq_number * max_buf_len; + + if( !RplReadData( pWorkerData, offset, &bytes_read)) { + return( FALSE); + } + // + // RplReadData() uses PDWORD argument but we never expect to read more + // than MAXWORD of data. + // + RPL_ASSERT( HIWORD( bytes_read) == 0); + + // Patch the boot block base address to the rplboot.sys header + // (in this way we need no code patching and rplservr can + // support any CPU architecture (in principle)) + + if ( (DWORD)(tmp_long = patch_offset - offset) < bytes_read + && tmp_long >= 0) { + *((PDWORD)(pWorkerData->pDataBuffer + (WORD)tmp_long)) = pWorkerData->base_address; + } + + // + // First frame goes to a specified address, all other frames + // are stacked after the last frame received. + // + pRcb->send_flags.locate_enable = (pRcb->fdr_seq_number == 0); + + // + // Check if this is the last frame. Note that last frame with + // bytes_read equal to zero is a valid frame to send. + // + if ( bytes_read < max_buf_len) { + + // + // Request acknowledgments for the last packet to make sure + // that client really received all the packets. Note that + // some clients never acknowledge the last frame and for those + // clients this thread will time out after a long wait below. + // + pRcb->send_flags.ack_request = pWorkerData->FinalAck; + + // + // This is the last frame set set transfer control & end of + // data bits. + // + pRcb->send_flags.xfer_enable = TRUE; + pRcb->send_flags.end_of_file = TRUE; + + } else { + + // + // If WindowSize is nonzero use the adaptive algorithm to decide + // when to actually ask client for an acknowledgement. + // + if ( pWorkerData->WindowSize != 0 && pRcb->fdr_seq_number < + pRcb->sfr_seq_number + pWorkerData->WindowSize) { + pRcb->send_flags.ack_request = FALSE; + } else { + pRcb->send_flags.ack_request = TRUE; + } + // + // This is not the last frame so clear transfer control & end of + // data bits. These bits could be set otherwise if we've sent + // the last frame & now have to resend a "not the last frame". + // + pRcb->send_flags.xfer_enable = FALSE; + pRcb->send_flags.end_of_file = FALSE; + } + + // + // Check the error status that Send (SendFileRequest) thread may have + // set + // + if ( pRcb->flags.alerted || pRcb->flags.rcberr) { + RplDump( ++RG_Assert,( "pRcb=0x%x flags=0x%x", pRcb, pRcb->flags)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaNetwork; + return( FALSE); + } + + // + // We may call FDR twice, if we need an ack and fail to get it + // after a short timeout. + // + for ( wait_ack_timeout = WAIT_ACK_TIMEOUT; ; ) { + + if ( !RplDlcFdr( // was RPL1_Send_Rpl_Data() + pOpenInfo, + pRcb, + pWorkerData->pDataBuffer, // address of send buffer + (WORD)bytes_read, // length of data to send + pWorkerData->base_address, + pWorkerData->jump_address + )) { + if ( RG_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) { + return( TRUE); // somebody else initiated service shutdown + } + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaNetwork; + return( FALSE); + } + if ( !pRcb->send_flags.ack_request) { + // + // No need to wait for an acknowledgement. Update send + // sequence number & retry count. + // + retries = 0; + pRcb->fdr_seq_number++; + break; + } + + // + // Need to wait for an acknowledgement. Wait for a very short + // time, then retry & wait for a very long time. + // + // + status = WaitForSingleObject( pRcb->SF_wakeup, wait_ack_timeout); + if ( status == 0) { + // + // Received an acknowledgment. Update send sequence + // number & retry count. + // + if ( pRcb->fdr_seq_number + 1 == pRcb->sfr_seq_number) { + // + // Case of orderly progression. + // + retries = 0; + pRcb->fdr_seq_number++; + } else { + if ( ++retries > MAX_RETRIES) { + RplDump( ++RG_Assert,( "pRcb=0x%x", pRcb)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaNetwork; + return( FALSE); // out of sync for too long + } + RplDump( RG_DebugLevel & RPL_DEBUG_MISC,( + "Worker(0x%x): pRcb=0x%x, sfr=%d fdr=%d", + pWorkerData, pRcb, pRcb->sfr_seq_number, + pRcb->fdr_seq_number)); + pRcb->fdr_seq_number = pRcb->sfr_seq_number; + } + break; + } + + if ( status != WAIT_TIMEOUT) { + RplDump( ++RG_Assert,( "pRcb=0x%x, status=0x%x", pRcb, status)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaInternal; + return( FALSE); + } + + if ( wait_ack_timeout == LONG_WAIT_ACK_TIMEOUT) { + // + // Some RPL rom chips such as LANWORKS BootWare chip never + // acknowledge the last frame. This is why we log an event + // only if not the last frame. + // For now we do not assert here because some clients + // may fail to send an ack from time to time. + // + if ( bytes_read >= max_buf_len) { + RplDump( RG_DebugLevel & RPL_DEBUG_SFR,( + "--Worker(0x%x): pRcb=0x%x Name=%ws sfr=0x%x fdr=0x%x", + pWorkerData, pRcb, pWorkerData->WkstaName, + pRcb->sfr_seq_number, pRcb->fdr_seq_number)); + pWorkerData->EventStrings[ 0] = pWorkerData->WkstaName; + pWorkerData->EventId = NELOG_RplWkstaTimeout; + } + return( FALSE); + } + + // + // Resend the packet again & then wait with a larger timeout. + // + wait_ack_timeout = LONG_WAIT_ACK_TIMEOUT; + } + + if ( bytes_read < max_buf_len) { + break; // we have just sent the last frame + } + } + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( + "--Worker(0x%x): pRcb=0x%x", pWorkerData, pRcb)); + return( TRUE); +} + + + +VOID RplWorkerThread( IN OUT PRPL_WORKER_PARAMS pWorkerParams) +/*++ + +Routine Description: + Worker thread. It sends a boot block to a workstation. + + This thread depends on Request thread being around. + This is why at shutdown time each request thread must wait for + all of its worker threads to die before it dies itself. + +Arguments: + pWorkerParams - pointer to worker parameters structure + +Return Value: + None. + +--*/ +{ + PRPL_REQUEST_PARAMS pRequestParams; + HANDLE MemoryHandle; + PRPL_WORKER_DATA pWorkerData; + PRCB pRcb; + DWORD status; + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "++WorkerThread(0x%x)", pWorkerParams)); + + pRcb = pWorkerParams->pRcb; + pRequestParams = pWorkerParams->pRequestParams; + pWorkerData = NULL; + MemoryHandle = NULL; + + EnterCriticalSection( &RG_ProtectWorkerCount); + RG_WorkerCount++; +#ifdef RPL_DEBUG + RG_BootCount++; +#endif + LeaveCriticalSection( &RG_ProtectWorkerCount); + + // + // Let each worker have its own memory space. + // + status = RplMemInit( &MemoryHandle); + if ( status != ERROR_SUCCESS) { + RplReportEvent( NELOG_RplAdapterResource, pRcb->AdapterName, 0, NULL); + goto cleanup; + } + // + // Build up the data block for worker. + // + pWorkerData = RplMemAlloc( MemoryHandle, sizeof(RPL_WORKER_DATA)); + if( pWorkerData == NULL) { + RplReportEvent( NELOG_RplAdapterResource, pRcb->AdapterName, 0, NULL); + goto cleanup; + } + memset( pWorkerData, 0, sizeof(RPL_WORKER_DATA)); + + pWorkerData->pRcb = pRcb; + pWorkerData->pRequestParams = pRequestParams; + pWorkerData->pOpenInfo = pRequestParams->pOpenInfo; + pWorkerData->MemoryHandle = MemoryHandle; + + pRcb->Pending = FALSE; // allow SFR thread to work on this RCB + + // + // Transmit semaphore must be created before OK Claim !!!! + // + pRcb->txsemhdl = CreateEvent( + NULL, // no security attributes + FALSE, // use automatic reset + TRUE, // initial state is signaled + NULL // event has no name + ); + if ( pRcb->txsemhdl == NULL) { + RplDump( ++RG_Assert,( "CreateEvent() => status=%d", GetLastError())); + RplReportEvent( NELOG_RplAdapterResource, pRcb->AdapterName, 0, NULL); + goto cleanup; + } + + if ( !Worker( pWorkerData)) { + if ( pWorkerData->EventId != NO_ERROR) { + RplReportEventEx( pWorkerData->EventId, pWorkerData->EventStrings); + } + goto cleanup; + } + +cleanup: + + // + // It is OK to remove RCB from BusyRcbList only if SFR thread is not + // working on it. + // + for ( ; ;) { + EnterCriticalSection( &RG_ProtectRcbList); + if ( pRcb->SFR == FALSE) { + RplRemoveRcb( &pRequestParams->BusyRcbList, pRcb); + RplInsertRcb( &pRequestParams->FreeRcbList, pRcb); + LeaveCriticalSection( &RG_ProtectRcbList); + break; + } + LeaveCriticalSection( &RG_ProtectRcbList); + Sleep( 100); // wait 0.1 sec, give SFR thread a chance to finish up + } + + if ( pRcb->txsemhdl != NULL) { + if ( !CloseHandle( pRcb->txsemhdl)) { + RplDump( ++RG_Assert,( "pRcb=0x%x, status=%d", pRcb, GetLastError())); + // There is nothing meaningfull to log here. + } + pRcb->txsemhdl = NULL; + } + + if ( MemoryHandle != NULL) { + if ( pWorkerData != NULL) { + // + // Close open file handles and system semaphores which may be + // left open after an error. + // + if ( pWorkerData->hFile != INVALID_HANDLE_VALUE) { + (VOID)CloseHandle( pWorkerData->hFile); + } + RplMemFree( MemoryHandle, pWorkerData); + } + RplMemClose( MemoryHandle); + } + + EnterCriticalSection( &RG_ProtectWorkerCount); + RG_WorkerCount--; + LeaveCriticalSection( &RG_ProtectWorkerCount); + + // + // We have to set RG_EventWorkerCount too, otherwise request thread may + // wait for ever to be notified that RG_WorkerCount has been decreased + // below RG_MaxWorkerCount. Reseting this event after we exit critical + // section does not lead to deadlocks (and is also better for performance). + // + if ( !SetEvent( RG_EventWorkerCount)) { + RplDump( ++RG_Assert, ("Error=%d", GetLastError())); + } + + RplDump( RG_DebugLevel & RPL_DEBUG_FLOW,( "--WorkerThread(0x%x)", pWorkerData)); + + // + // Let request thread know that we will be out shortly. + // + pWorkerParams->Exiting = TRUE; +} + + + +VOID RplRemoveRcb( + IN OUT PPRCB HeadList, + IN OUT PRCB pRcb + ) +/*++ + +Routine Description: + Dequeus RCB. + +Arguments: + HeadList - head of a queue + pRcb - rcb to me dequeued + +Return Value: + None. + +--*/ +{ + PRCB pTempRcb; + + RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,( + "RemoveRcb: pRcb=0x%x, list=0x%x", pRcb, HeadList)); + + DebugCheckList( HeadList, pRcb, RPL_MUST_FIND); + + if (*HeadList == pRcb) { + + *HeadList = pRcb->next_rcb; + + } else { + + for ( pTempRcb = *HeadList; pTempRcb != NULL; pTempRcb = pTempRcb->next_rcb) { + + if ( pTempRcb->next_rcb == pRcb) { + pTempRcb->next_rcb = pRcb->next_rcb; + break; + } + } + } + DebugCheckList( HeadList, pRcb, RPL_MUST_NOT_FIND); +} + + + +VOID RplInsertRcb( + IN OUT PPRCB HeadList, + IN OUT PRCB pRcb + ) +/*++ + +Routine Description: + Queues RCB. + +Arguments: + HeadList - head of a queue + pRcb - rcb to me dequeued + +Return Value: + None. + +--*/ +{ + RplDump( RG_DebugLevel & RPL_DEBUG_WORKER,( + "InsertRcb: pRcb=0x%x, list=0x%x", pRcb, HeadList)); + + DebugCheckList( HeadList, pRcb, RPL_MUST_NOT_FIND); + pRcb->next_rcb = *HeadList; + *HeadList = pRcb; + DebugCheckList( HeadList, pRcb, RPL_MUST_FIND); +} + + + diff --git a/private/net/svcdlls/rpl/server/worker.h b/private/net/svcdlls/rpl/server/worker.h new file mode 100644 index 000000000..e6d4fe334 --- /dev/null +++ b/private/net/svcdlls/rpl/server/worker.h @@ -0,0 +1,35 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + worker.h + +Abstract: + + Exports from worker.c + +Author: + + Vladimir Z. Vulovic (vladimv) 19 - November - 1993 + +Environment: + + User mode + +Revision History : + +--*/ + +VOID RplRemoveRcb( + IN OUT PPRCB HeadList, + IN OUT PRCB pRcb + ); +VOID RplInsertRcb( + IN OUT PPRCB HeadList, + IN OUT PRCB pRcb + ); + +VOID RplWorkerThread( IN OUT PRPL_WORKER_PARAMS pWorkerParams); + |