test: netboot.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# netboot.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1997  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     netboot.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the code to initialize network boot.
    00012
    00013 Author:
    00014
    00015     Chuck Lenzmeier (chuckl) December 27, 1996
    00016
    00017 Environment:
    00018
    00019     Kernel mode, system initialization code
    00020
    00021 Revision History:
    00022
    00023     Colin Watson (colinw) November 1997 Add CSC support
    00024
    00025 --*/
    00026
    00027 #include "iop.h"
    00028 #pragma hdrstop
    00029
    00030 #include <ntddip.h>
    00031 #include <nbtioctl.h>
    00032 #include <ntddnfs.h>
    00033 #include <ntddbrow.h>
    00034 #include <ntddtcp.h>
    00035 #include <setupblk.h>
    00036 #include <remboot.h>
    00037 #include <oscpkt.h>
    00038 #include <windef.h>
    00039 #include <tdiinfo.h>
    00040 #if defined(REMOTE_BOOT)
    00041 #include <ntddndis.h>
    00042 #include <ipsec.h>
    00043 #endif // defined(REMOTE_BOOT)
    00044
    00045 #ifndef NT
    00046 #define NT
    00047 #include <ipinfo.h>
    00048 #undef NT
    00049 #else
    00050 #include <ipinfo.h>
    00051 #endif
    00052
    00053 extern BOOLEAN ExpInTextModeSetup;
    00054
    00055 //
    00056 // TCP/IP definitions
    00057 //
    00058
    00059 #define DEFAULT_DEST                    0
    00060 #define DEFAULT_DEST_MASK               0
    00061 #define DEFAULT_METRIC                  1
    00062
    00063 NTSTATUS
    00064 IopWriteIpAddressToRegistry(
    00065         HANDLE handle,
    00066         PWCHAR regkey,
    00067         PUCHAR value
    00068         );
    00069
    00070 NTSTATUS
    00071 IopTCPQueryInformationEx(
    00072     IN HANDLE                 TCPHandle,
    00073     IN TDIObjectID FAR       *ID,
    00074     OUT void FAR             *Buffer,
    00075     IN OUT DWORD FAR         *BufferSize,
    00076     IN OUT BYTE FAR          *Context
    00077     );
    00078
    00079 NTSTATUS
    00080 IopTCPSetInformationEx(
    00081     IN HANDLE             TCPHandle,
    00082     IN TDIObjectID FAR   *ID,
    00083     IN void FAR          *Buffer,
    00084     IN DWORD FAR          BufferSize
    00085     );
    00086
    00087 NTSTATUS
    00088 IopSetDefaultGateway(
    00089     IN ULONG GatewayAddress
    00090     );
    00091
    00092 NTSTATUS
    00093 IopCacheNetbiosNameForIpAddress(
    00094     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    00095     );
    00096
    00097 VOID
    00098 IopAssignNetworkDriveLetter (
    00099     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    00100     );
    00101
    00102 #if defined(REMOTE_BOOT)
    00103
    00104 #if DBG
    00105 BOOLEAN DebugReset = FALSE;
    00106 #endif
    00107
    00108 //
    00109 // The following variable is used by IoStartCscForTextmodeSetup.
    00110 //
    00111
    00112 BOOLEAN TextmodeSetupHasStartedCsc = FALSE;
    00113
    00114 //
    00115 // CSC definitions
    00116 //
    00117
    00118 typedef struct _FILETIME {
    00119     ULONG dwLowDateTime;
    00120     ULONG dwHighDateTime;
    00121 } FILETIME, *LPFILETIME;
    00122
    00123 typedef struct _WIN32_FIND_DATAA {
    00124     ULONG dwFileAttributes;
    00125     FILETIME ftCreationTime;
    00126     FILETIME ftLastAccessTime;
    00127     FILETIME ftLastWriteTime;
    00128     ULONG nFileSizeHigh;
    00129     ULONG nFileSizeLow;
    00130     ULONG dwReserved0;
    00131     ULONG dwReserved1;
    00132     CHAR   cFileName[ MAX_PATH ];
    00133     CHAR   cAlternateFileName[ 14 ];
    00134 } WIN32_FIND_DATAA;
    00135
    00136 typedef struct _WIN32_FIND_DATAW {
    00137     DWORD dwFileAttributes;
    00138     FILETIME ftCreationTime;
    00139     FILETIME ftLastAccessTime;
    00140     FILETIME ftLastWriteTime;
    00141     DWORD nFileSizeHigh;
    00142     DWORD nFileSizeLow;
    00143     DWORD dwReserved0;
    00144     DWORD dwReserved1;
    00145     WCHAR  cFileName[ MAX_PATH ];
    00146     WCHAR  cAlternateFileName[ 14 ];
    00147 } WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;
    00148
    00149
    00150 LIST_ENTRY DirectoryList;
    00151
    00152 HANDLE RdrHandle = NULL;
    00153 PKPROCESS RdrHandleProcess = NULL;
    00154
    00155 typedef enum _START_CSC {
    00156     INIT_CSC,
    00157     FLUSH_CSC
    00158 } START_CSC;
    00159
    00160 START_CSC StartCsc;
    00161
    00162 typedef enum _CSC_CONTROL {
    00163     READ_CSC,
    00164     SET_FLUSH_CSC,
    00165     SET_FLUSHED_CSC
    00166 } CSC_CONTROL;
    00167
    00168 #include <shdcom.h>
    00169
    00170 //
    00171 // Structure for holding discovered directories until we can process them.
    00172 //
    00173
    00174 typedef struct _DIRENT {
    00175     LIST_ENTRY Next;
    00176     UNICODE_STRING Directory;
    00177     PWCHAR LastToken;
    00178     HSHADOW CSCHandle;
    00179     WCHAR Name[1];
    00180 } DIRENT, *PDIRENT;
    00181
    00182 NTSTATUS
    00183 IopInitCsc(
    00184     IN PUCHAR CscPath
    00185     );
    00186
    00187 NTSTATUS
    00188 IopResetCsc(
    00189     IN PUCHAR CscPath
    00190     );
    00191
    00192 PWSTR
    00193 IopBreakPath(
    00194     IN PWSTR* Path
    00195     );
    00196
    00197 NTSTATUS
    00198 IopMarkRoot(
    00199     IN PUNICODE_STRING FileName,
    00200     OUT PHSHADOW RootHandle
    00201     );
    00202
    00203 VOID
    00204 IopSetFlushCSC(
    00205     IN CSC_CONTROL Command
    00206     );
    00207
    00208 NTSTATUS
    00209 IopWalkDirectoryHelper (
    00210     IN PUNICODE_STRING Directory,
    00211     IN HSHADOW CSCHandle,
    00212     IN PUCHAR Buffer,
    00213     IN ULONG BufferSize
    00214     );
    00215
    00216 NTSTATUS
    00217 IopWalkDirectoryTree (
    00218     IN PUNICODE_STRING Directory,
    00219     IN HSHADOW CSCHandle
    00220     );
    00221
    00222 NTSTATUS
    00223 IopGetShadowExW(
    00224     HSHADOW hDir,
    00225     LPWIN32_FIND_DATAW lpFind32,
    00226     LPSHADOWINFO lpSI
    00227     );
    00228
    00229 NTSTATUS
    00230 IopAddHintFromInode(
    00231     HSHADOW hDir,
    00232     HSHADOW hShadow,
    00233     ULONG *lpulHintPri,
    00234     ULONG *lpulHintFlags,
    00235     ULONG HintFlagsToSet
    00236     );
    00237
    00238 NTSTATUS
    00239 IopSetShadowInfoW(
    00240     HSHADOW hDir,
    00241     HSHADOW hShadow,
    00242     ULONG uStatus,
    00243     ULONG uOp
    00244     );
    00245
    00246 NTSTATUS
    00247 IopCreateShadowW(
    00248     HSHADOW hDir,
    00249     LPWIN32_FIND_DATAW lpFind32,
    00250     ULONG uStatus,
    00251     PHSHADOW lphShadow
    00252     );
    00253
    00254 NTSTATUS
    00255 IopCopyServerAcl(
    00256     HANDLE ParentHandle,
    00257     PWCHAR FileName,
    00258     HSHADOW ShadowHandle,
    00259     BOOLEAN IsDirectory,
    00260     PUCHAR Buffer,
    00261     ULONG BufferSize
    00262     );
    00263
    00264 NTSTATUS
    00265 IopGetShadowPathW(
    00266     HSHADOW hShadow,
    00267     PWCHAR lpLocalPath,
    00268     LPCOPYPARAMSW lpCP
    00269     );
    00270
    00271 VOID
    00272 IopEnableRemoteBootSecurity (
    00273     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    00274     );
    00275
    00276 VOID
    00277 IopGetHarddiskInfo(
    00278     OUT PWSTR NetHDCSCPartition
    00279     );
    00280
    00281 #endif // defined(REMOTE_BOOT)
    00282
    00283 //
    00284 // The following allows the I/O system's initialization routines to be
    00285 // paged out of memory.
    00286 //
    00287
    00288 #ifdef ALLOC_PRAGMA
    00289 #pragma alloc_text(INIT,IopAddRemoteBootValuesToRegistry)
    00290 #pragma alloc_text(INIT,IopStartNetworkForRemoteBoot)
    00291 #pragma alloc_text(INIT,IopStartTcpIpForRemoteBoot)
    00292 #pragma alloc_text(INIT,IopIsRemoteBootCard)
    00293 #pragma alloc_text(INIT,IopSetupRemoteBootCard)
    00294 #if defined(REMOTE_BOOT)
    00295 #pragma alloc_text(INIT,IopAssignNetworkDriveLetter)
    00296 #pragma alloc_text(INIT,IopInitCsc)
    00297 #pragma alloc_text(INIT,IopResetCsc)
    00298 #pragma alloc_text(INIT,IopBreakPath)
    00299 #pragma alloc_text(INIT,IopMarkRoot)
    00300 #pragma alloc_text(INIT,IopSetFlushCSC)
    00301 #pragma alloc_text(INIT,IopWalkDirectoryHelper)
    00302 #pragma alloc_text(INIT,IopWalkDirectoryTree)
    00303 #pragma alloc_text(INIT,IopGetShadowExW)
    00304 #pragma alloc_text(INIT,IopAddHintFromInode)
    00305 #pragma alloc_text(INIT,IopCreateShadowW)
    00306 #pragma alloc_text(INIT,IopCopyServerAcl)
    00307 #pragma alloc_text(INIT,IopGetShadowPathW)
    00308 #pragma alloc_text(INIT,IopGetHarddiskInfo)
    00309 #endif // defined(REMOTE_BOOT)
    00310 #endif
    00311
    00312
    00313 NTSTATUS
    00314 IopAddRemoteBootValuesToRegistry (
    00315     PLOADER_PARAMETER_BLOCK LoaderBlock
    00316     )
    00317 {
    00318     NTSTATUS status = STATUS_SUCCESS;
    00319     HANDLE handle;
    00320     HANDLE serviceHandle;
    00321     OBJECT_ATTRIBUTES objectAttributes;
    00322     UNICODE_STRING string;
    00323     CHAR addressA[16];
    00324     WCHAR addressW[16];
    00325     STRING addressStringA;
    00326     UNICODE_STRING addressStringW;
    00327     PUCHAR addressPointer;
    00328     PUCHAR p;
    00329     PUCHAR q;
    00330     UCHAR ntName[128];
    00331     WCHAR imagePath[128];
    00332     STRING ansiString;
    00333     UNICODE_STRING unicodeString;
    00334     UNICODE_STRING dnsNameString;
    00335     UNICODE_STRING netbiosNameString;
    00336     ULONG tmpValue;
    00337
    00338     if (LoaderBlock->SetupLoaderBlock->ComputerName[0] != 0) {
    00339
    00340         //
    00341         // Convert the name to a Netbios name.
    00342         //
    00343
    00344         _wcsupr( LoaderBlock->SetupLoaderBlock->ComputerName );
    00345
    00346         RtlInitUnicodeString( &dnsNameString, LoaderBlock->SetupLoaderBlock->ComputerName );
    00347
    00348         status = RtlDnsHostNameToComputerName(
    00349                      &netbiosNameString,
    00350                      &dnsNameString,
    00351                      TRUE);            // allocate netbiosNameString
    00352
    00353         if ( !NT_SUCCESS(status) ) {
    00354             KdPrint(( "IopAddRemoteBootValuesToRegistry: Failed RtlDnsHostNameToComputerName: %x\n", status ));
    00355             goto cleanup;
    00356         }
    00357
    00358         //
    00359         // Add a value for the computername.
    00360         //
    00361
    00362         RtlInitUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName" );
    00363
    00364         InitializeObjectAttributes(
    00365             &objectAttributes,
    00366             &string,
    00367             OBJ_CASE_INSENSITIVE,
    00368             NULL,
    00369             NULL
    00370             );
    00371
    00372         status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
    00373         if ( !NT_SUCCESS(status) ) {
    00374             KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open ComputerName key: %x\n", status ));
    00375             RtlFreeUnicodeString( &netbiosNameString );
    00376             goto cleanup;
    00377         }
    00378
    00379         RtlInitUnicodeString( &string, L"ComputerName" );
    00380
    00381         status = NtSetValueKey(
    00382                     handle,
    00383                     &string,
    00384                     0,
    00385                     REG_SZ,
    00386                     netbiosNameString.Buffer,
    00387                     netbiosNameString.Length + sizeof(WCHAR)
    00388                     );
    00389         NtClose( handle );
    00390         RtlFreeUnicodeString( &netbiosNameString );
    00391
    00392         if ( !NT_SUCCESS(status) ) {
    00393             KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set ComputerName value: %x\n", status ));
    00394             goto cleanup;
    00395         }
    00396
    00397         //
    00398         // Add a value for the host name.
    00399         //
    00400
    00401         RtlInitUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters" );
    00402
    00403         InitializeObjectAttributes(
    00404             &objectAttributes,
    00405             &string,
    00406             OBJ_CASE_INSENSITIVE,
    00407             NULL,
    00408             NULL
    00409             );
    00410
    00411         status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
    00412         if ( !NT_SUCCESS(status) ) {
    00413             KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open Tcpip\\Parameters key: %x\n", status ));
    00414             goto cleanup;
    00415         }
    00416
    00417         _wcslwr( LoaderBlock->SetupLoaderBlock->ComputerName );
    00418
    00419         RtlInitUnicodeString( &string, L"Hostname" );
    00420
    00421         status = NtSetValueKey(
    00422                     handle,
    00423                     &string,
    00424                     0,
    00425                     REG_SZ,
    00426                     LoaderBlock->SetupLoaderBlock->ComputerName,
    00427                     (wcslen(LoaderBlock->SetupLoaderBlock->ComputerName) + 1) * sizeof(WCHAR)
    00428                     );
    00429         NtClose( handle );
    00430         if ( !NT_SUCCESS(status) ) {
    00431             KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set Hostname value: %x\n", status ));
    00432             goto cleanup;
    00433         }
    00434     }
    00435
    00436     //
    00437     //  If the UNC path to the system files is supplied then store it in the registry.
    00438     //
    00439
    00440     ASSERT( _stricmp(LoaderBlock->ArcBootDeviceName,"net(0)") == 0 );
    00441
    00442     RtlInitUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control" );
    00443
    00444     InitializeObjectAttributes(
    00445         &objectAttributes,
    00446         &string,
    00447         OBJ_CASE_INSENSITIVE,
    00448         NULL,
    00449         NULL
    00450         );
    00451
    00452     status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
    00453     if ( !NT_SUCCESS(status) ) {
    00454         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open Control key: %x\n", status ));
    00455         goto skiproot;
    00456     }
    00457
    00458     p = strrchr( LoaderBlock->NtBootPathName, '\\' );   // find last separator
    00459     if ( (p != NULL) && (*(p+1) == 0) ) {
    00460
    00461         //
    00462         // NtBootPathName ends with a backslash, so we need to back up
    00463         // to the previous backslash.
    00464         //
    00465
    00466         q = p;
    00467         *q = 0;
    00468         p = strrchr( LoaderBlock->NtBootPathName, '\\' );   // find last separator
    00469         *q = '\\';
    00470     }
    00471     if ( p == NULL ) {
    00472         KdPrint(( "IopAddRemoteBootValuesToRegistry: malformed NtBootPathName: %s\n", LoaderBlock->NtBootPathName ));
    00473         NtClose( handle );
    00474         goto skiproot;
    00475     }
    00476     *p = 0;                                 // terminate \server\share\images\machine
    00477
    00478 #if defined(REMOTE_BOOT)
    00479     //
    00480     // Store the server path in the shared user data area. Note that we need
    00481     // to add an extra \ at the beginning of this path to make it a UNC name.
    00482     //
    00483
    00484     SharedUserData->RemoteBootServerPath[0] = L'\\';
    00485     RtlInitAnsiString( &ansiString, LoaderBlock->NtBootPathName );
    00486     unicodeString.MaximumLength = sizeof(SharedUserData->RemoteBootServerPath) - (2 * sizeof(WCHAR));
    00487     unicodeString.Buffer = &SharedUserData->RemoteBootServerPath[1];
    00488     RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, FALSE );
    00489     SharedUserData->RemoteBootServerPath[1 + (unicodeString.Length/sizeof(WCHAR))] = 0;
    00490 #endif // defined(REMOTE_BOOT)
    00491
    00492     strcpy( ntName, "\\Device\\LanmanRedirector");
    00493     strcat( ntName, LoaderBlock->NtBootPathName );  // append \server\share\images\machine
    00494     *p = '\\';
    00495
    00496     RtlInitAnsiString( &ansiString, ntName );
    00497     RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE );
    00498
    00499     RtlInitUnicodeString( &string, L"RemoteBootRoot" );
    00500
    00501     status = NtSetValueKey(
    00502                 handle,
    00503                 &string,
    00504                 0,
    00505                 REG_SZ,
    00506                 unicodeString.Buffer,
    00507                 unicodeString.Length + sizeof(WCHAR)
    00508                 );
    00509
    00510     RtlFreeUnicodeString( &unicodeString );
    00511     if ( !NT_SUCCESS(status) ) {
    00512         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set RemoteBootRoot value: %x\n", status ));
    00513     }
    00514
    00515     if ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IS_TEXTMODE) != 0) {
    00516
    00517         strcpy( ntName, "\\Device\\LanmanRedirector");
    00518         strcat( ntName, LoaderBlock->SetupLoaderBlock->MachineDirectoryPath );
    00519         RtlInitAnsiString( &ansiString, ntName );
    00520         RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE );
    00521
    00522         RtlInitUnicodeString( &string, L"RemoteBootMachineDirectory" );
    00523
    00524         status = NtSetValueKey(
    00525                     handle,
    00526                     &string,
    00527                     0,
    00528                     REG_SZ,
    00529                     unicodeString.Buffer,
    00530                     unicodeString.Length + sizeof(WCHAR)
    00531                     );
    00532
    00533         RtlFreeUnicodeString( &unicodeString );
    00534         if ( !NT_SUCCESS(status) ) {
    00535             KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set RemoteBootMachineDirectory value: %x\n", status ));
    00536         }
    00537     }
    00538
    00539     NtClose( handle );
    00540
    00541 skiproot:
    00542
    00543 #if defined(REMOTE_BOOT)
    00544     StartCsc = INIT_CSC;
    00545     IopSetFlushCSC(READ_CSC);
    00546
    00547     if ( (StartCsc != FLUSH_CSC) &&
    00548          ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_REPIN) != 0) ) {
    00549         StartCsc = FLUSH_CSC;
    00550         IopSetFlushCSC(SET_FLUSH_CSC);
    00551     }
    00552
    00553 #if 0
    00554     RtlInitUnicodeString( &string, L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CSCSettings" );
    00555
    00556     InitializeObjectAttributes(
    00557         &objectAttributes,
    00558         &string,
    00559         OBJ_CASE_INSENSITIVE,
    00560         NULL,
    00561         NULL
    00562         );
    00563
    00564     status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
    00565
    00566     if ( NT_SUCCESS(status) ) {
    00567
    00568         PKEY_VALUE_PARTIAL_INFORMATION keyValue;
    00569         UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(DWORD)];
    00570         ULONG length;
    00571         DWORD disabled;
    00572
    00573 #define ONE_BOOT 2
    00574
    00575         RtlInitUnicodeString( &string, L"DisableAgent" );
    00576
    00577         if ( (LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_DISABLE_CSC) == 0 ) {
    00578
    00579             //
    00580             // Disable CSC for this boot.
    00581             //
    00582
    00583             disabled = ONE_BOOT;
    00584             status = NtSetValueKey(
    00585                         handle,
    00586                         &string,
    00587                         0,
    00588                         REG_DWORD,
    00589                         &disabled,
    00590                         sizeof(DWORD));
    00591
    00592         } else {
    00593
    00594             keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
    00595             status = NtQueryValueKey(
    00596                          handle,
    00597                          &string,
    00598                          KeyValuePartialInformation,
    00599                          keyValue,
    00600                          sizeof(buffer),
    00601                          &length);
    00602             if (NT_SUCCESS(status)) {
    00603                 disabled = *((DWORD *)(&keyValue->Data[0]));
    00604
    00605                 if (disabled == ONE_BOOT) {
    00606                     //  Only disabled for last boot so re-enable now.
    00607                     status = NtDeleteValueKey( handle, &string);
    00608                     //  BUGBUG should we repin?
    00609                 }
    00610             }
    00611         }
    00612
    00613         NtClose( handle );
    00614         if ( !NT_SUCCESS(status) ) {
    00615             KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to set CSCSettings: %x\n", status ));
    00616             goto cleanup;
    00617         }
    00618     }
    00619 #endif
    00620 #endif // defined(REMOTE_BOOT)
    00621
    00622     //
    00623     // Add registry values for the IP address and subnet mask received
    00624     // from DHCP. These are stored under the Tcpip service key and are
    00625     // read by both Tcpip and Netbt. The adapter name used is the known
    00626     // GUID for the NetbootCard.
    00627     //
    00628
    00629     RtlInitUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{54C7D140-09EF-11D1-B25A-F5FE627ED95E}" );
    00630
    00631     InitializeObjectAttributes(
    00632         &objectAttributes,
    00633         &string,
    00634         OBJ_CASE_INSENSITIVE,
    00635         NULL,
    00636         NULL
    00637         );
    00638
    00639     status = NtOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
    00640     if ( !NT_SUCCESS(status) ) {
    00641         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open Tcpip\\Parameters\\Interfaces\\{54C7D140-09EF-11D1-B25A-F5FE627ED95E} key: %x\n", status ));
    00642         goto cleanup;
    00643     }
    00644
    00645     status = IopWriteIpAddressToRegistry(handle,
    00646                                          L"DhcpIPAddress",
    00647                                          (PUCHAR)&(LoaderBlock->SetupLoaderBlock->IpAddress)
    00648                                         );
    00649
    00650     if ( !NT_SUCCESS(status)) {
    00651         NtClose(handle);
    00652         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write DhcpIPAddress: %x\n", status ));
    00653         goto cleanup;
    00654     }
    00655
    00656     status = IopWriteIpAddressToRegistry(handle,
    00657                                          L"DhcpSubnetMask",
    00658                                          (PUCHAR)&(LoaderBlock->SetupLoaderBlock->SubnetMask)
    00659                                         );
    00660
    00661     if ( !NT_SUCCESS(status)) {
    00662         NtClose(handle);
    00663         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write DhcpSubnetMask: %x\n", status ));
    00664         goto cleanup;
    00665     }
    00666
    00667     status = IopWriteIpAddressToRegistry(handle,
    00668                                          L"DhcpDefaultGateway",
    00669                                          (PUCHAR)&(LoaderBlock->SetupLoaderBlock->DefaultRouter)
    00670                                         );
    00671
    00672     NtClose(handle);
    00673
    00674     if ( !NT_SUCCESS(status)) {
    00675         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write DhcpDefaultGateway: %x\n", status ));
    00676         goto cleanup;
    00677     }
    00678
    00679     //
    00680     // Create the service key for the netboot card. We need to have
    00681     // the Type value there or the card won't be initialized.
    00682     //
    00683
    00684     status = IopOpenRegistryKey(&handle,
    00685                                 NULL,
    00686                                 &CmRegistryMachineSystemCurrentControlSetServices,
    00687                                 KEY_ALL_ACCESS,
    00688                                 FALSE
    00689                                 );
    00690
    00691     if (!NT_SUCCESS(status)) {
    00692         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open CurrentControlSet\\Services: %x\n", status ));
    00693         goto cleanup;
    00694     }
    00695
    00696     RtlInitUnicodeString(&string, LoaderBlock->SetupLoaderBlock->NetbootCardServiceName);
    00697
    00698     InitializeObjectAttributes(&objectAttributes,
    00699                                &string,
    00700                                OBJ_CASE_INSENSITIVE,
    00701                                handle,
    00702                                (PSECURITY_DESCRIPTOR)NULL
    00703                                );
    00704
    00705     status = ZwCreateKey(&serviceHandle,
    00706                          KEY_ALL_ACCESS,
    00707                          &objectAttributes,
    00708                          0,
    00709                          (PUNICODE_STRING)NULL,
    00710                          0,
    00711                          &tmpValue     // disposition
    00712                          );
    00713
    00714     ZwClose(handle);
    00715
    00716     if (!NT_SUCCESS(status)) {
    00717         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to open/create netboot card service key: %x\n", status ));
    00718         goto cleanup;
    00719     }
    00720
    00721     //
    00722     // Store the image path.
    00723     //
    00724
    00725     PiWstrToUnicodeString(&string, L"ImagePath");
    00726     wcscpy(imagePath, L"system32\\drivers\\");
    00727     wcscat(imagePath, LoaderBlock->SetupLoaderBlock->NetbootCardDriverName);
    00728
    00729     status = ZwSetValueKey(serviceHandle,
    00730                            &string,
    00731                            TITLE_INDEX_VALUE,
    00732                            REG_SZ,
    00733                            imagePath,
    00734                            (wcslen(imagePath) + 1) * sizeof(WCHAR)
    00735                            );
    00736
    00737     if (!NT_SUCCESS(status)) {
    00738         NtClose(serviceHandle);
    00739         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write ImagePath: %x\n", status ));
    00740         goto cleanup;
    00741     }
    00742
    00743     //
    00744     // Store the type.
    00745     //
    00746
    00747     PiWstrToUnicodeString(&string, L"Type");
    00748     tmpValue = 1;
    00749
    00750     ZwSetValueKey(serviceHandle,
    00751                   &string,
    00752                   TITLE_INDEX_VALUE,
    00753                   REG_DWORD,
    00754                   &tmpValue,
    00755                   sizeof(tmpValue)
    00756                   );
    00757
    00758     NtClose(serviceHandle);
    00759
    00760     if (!NT_SUCCESS(status)) {
    00761         KdPrint(( "IopAddRemoteBootValuesToRegistry: Unable to write Type: %x\n", status ));
    00762     }
    00763
    00764 cleanup:
    00765
    00766     return status;
    00767 }
    00768
    00769 NTSTATUS
    00770 IopStartNetworkForRemoteBoot (
    00771     PLOADER_PARAMETER_BLOCK LoaderBlock
    00772     )
    00773 {
    00774     NTSTATUS status;
    00775     HANDLE dgHandle;
    00776     HANDLE keyHandle;
    00777     OBJECT_ATTRIBUTES objectAttributes;
    00778     IO_STATUS_BLOCK ioStatusBlock;
    00779     UNICODE_STRING string;
    00780     UNICODE_STRING computerName;
    00781     UNICODE_STRING domainName;
    00782     PUCHAR buffer;
    00783     ULONG bufferLength;
    00784     PLMR_REQUEST_PACKET rrp;
    00785     PLMDR_REQUEST_PACKET drrp;
    00786     WKSTA_INFO_502 wkstaConfig;
    00787     WKSTA_TRANSPORT_INFO_0 wkstaTransportInfo;
    00788     LARGE_INTEGER interval;
    00789     ULONG length;
    00790     PKEY_VALUE_PARTIAL_INFORMATION keyValue;
    00791     BOOLEAN startDatagramReceiver;
    00792     ULONG enumerateAttempts;
    00793 #if defined(REMOTE_BOOT)
    00794     PWSTR NetHDCSCPartition;
    00795     BOOLEAN leaveRdrHandleOpen;
    00796     BOOLEAN pinNetDriver;
    00797 #else
    00798     HANDLE RdrHandle;
    00799 #endif // defined(REMOTE_BOOT)
    00800
    00801     //
    00802     // Initialize for cleanup.
    00803     //
    00804
    00805     buffer = NULL;
    00806     computerName.Buffer = NULL;
    00807     domainName.Buffer = NULL;
    00808     dgHandle = NULL;
    00809     RdrHandle = NULL;
    00810 #if defined(REMOTE_BOOT)
    00811     NetHDCSCPartition = NULL;
    00812     leaveRdrHandleOpen = FALSE;
    00813     pinNetDriver = FALSE;
    00814 #endif // defined(REMOTE_BOOT)
    00815
    00816     //
    00817     // Allocate a temporary buffer. It has to be big enough for all the
    00818     // various FSCTLs we send down.
    00819     //
    00820
    00821     bufferLength = max(sizeof(LMR_REQUEST_PACKET) + (MAX_PATH + 1) * sizeof(WCHAR) +
    00822                                                  (DNLEN + 1) * sizeof(WCHAR),
    00823                        max(sizeof(LMDR_REQUEST_PACKET),
    00824                            FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + MAX_PATH));
    00825     bufferLength = max(bufferLength, sizeof(LMMR_RI_INITIALIZE_SECRET));
    00826
    00827 #if defined(REMOTE_BOOT)
    00828     NetHDCSCPartition = ExAllocatePoolWithTag(
    00829                             NonPagedPool,
    00830                             (80 * sizeof(WCHAR)) + bufferLength,
    00831                             'bRoI'
    00832                             );
    00833     if (NetHDCSCPartition == NULL) {
    00834         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to allocate buffer\n"));
    00835         status = STATUS_INSUFFICIENT_RESOURCES;
    00836         goto cleanup;
    00837     }
    00838     buffer = (PUCHAR)(NetHDCSCPartition + 80);
    00839 #else
    00840     buffer = ExAllocatePoolWithTag( NonPagedPool, bufferLength, 'bRoI' );
    00841     if (buffer == NULL) {
    00842         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to allocate buffer\n"));
    00843         status = STATUS_INSUFFICIENT_RESOURCES;
    00844         goto cleanup;
    00845     }
    00846 #endif // defined(REMOTE_BOOT)
    00847
    00848     rrp = (PLMR_REQUEST_PACKET)buffer;
    00849     drrp = (PLMDR_REQUEST_PACKET)buffer;
    00850
    00851     //
    00852     // Open the redirector and the datagram receiver.
    00853     //
    00854
    00855     RtlInitUnicodeString( &string, L"\\Device\\LanmanRedirector" );
    00856
    00857     InitializeObjectAttributes(
    00858         &objectAttributes,
    00859         &string,
    00860         OBJ_CASE_INSENSITIVE,
    00861         NULL,
    00862         NULL
    00863         );
    00864
    00865     status = NtCreateFile(
    00866                 &RdrHandle,
    00867                 GENERIC_READ | GENERIC_WRITE,
    00868                 &objectAttributes,
    00869                 &ioStatusBlock,
    00870                 NULL,
    00871                 0,
    00872                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    00873                 FILE_OPEN,
    00874                 FILE_SYNCHRONOUS_IO_NONALERT,
    00875                 NULL,
    00876                 0
    00877                 );
    00878     if ( !NT_SUCCESS(status) ) {
    00879         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open redirector: %x\n", status ));
    00880         goto cleanup;
    00881     }
    00882
    00883 #if defined(REMOTE_BOOT)
    00884     RdrHandleProcess = &IoGetCurrentProcess()->Pcb;
    00885 #endif // defined(REMOTE_BOOT)
    00886
    00887     RtlInitUnicodeString( &string, DD_BROWSER_DEVICE_NAME_U );
    00888
    00889     InitializeObjectAttributes(
    00890         &objectAttributes,
    00891         &string,
    00892         OBJ_CASE_INSENSITIVE,
    00893         NULL,
    00894         NULL
    00895         );
    00896
    00897     status = NtCreateFile(
    00898                 &dgHandle,
    00899                 GENERIC_READ | GENERIC_WRITE,
    00900                 &objectAttributes,
    00901                 &ioStatusBlock,
    00902                 NULL,
    00903                 0,
    00904                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    00905                 FILE_OPEN,
    00906                 FILE_SYNCHRONOUS_IO_NONALERT,
    00907                 NULL,
    00908                 0
    00909                 );
    00910     if ( !NT_SUCCESS(status) ) {
    00911         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open datagram receiver: %x\n", status ));
    00912         goto cleanup;
    00913     }
    00914
    00915     //
    00916     // If the setup loader block has a disk secret in it provided by the
    00917     // loader, pass this down to the redirector (do this before sending
    00918     // the LMR_START, since that uses this information).
    00919     //
    00920
    00921 #if defined(REMOTE_BOOT)
    00922     if (LoaderBlock->SetupLoaderBlock->NetBootSecret)
    00923 #endif // defined(REMOTE_BOOT)
    00924     {
    00925         PLMMR_RI_INITIALIZE_SECRET RbInit = (PLMMR_RI_INITIALIZE_SECRET)buffer;
    00926
    00927         ASSERT(LoaderBlock->SetupLoaderBlock->NetBootSecret != NULL);
    00928         RtlCopyMemory(
    00929             &RbInit->Secret,
    00930             LoaderBlock->SetupLoaderBlock->NetBootSecret,
    00931             sizeof(RI_SECRET));
    00932 #if defined(REMOTE_BOOT)
    00933         RbInit->UsePassword2 = LoaderBlock->SetupLoaderBlock->NetBootUsePassword2;
    00934 #endif // defined(REMOTE_BOOT)
    00935
    00936         status = NtFsControlFile(
    00937                     RdrHandle,
    00938                     NULL,
    00939                     NULL,
    00940                     NULL,
    00941                     &ioStatusBlock,
    00942                     FSCTL_LMMR_RI_INITIALIZE_SECRET,
    00943                     buffer,
    00944                     sizeof(LMMR_RI_INITIALIZE_SECRET),
    00945                     NULL,
    00946                     0
    00947                     );
    00948
    00949         if ( NT_SUCCESS(status) ) {
    00950             status = ioStatusBlock.Status;
    00951         }
    00952         if ( !NT_SUCCESS(status) ) {
    00953             KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(RB initialize) redirector: %x\n", status ));
    00954             goto cleanup;
    00955         }
    00956     }
    00957
    00958     //
    00959     // Read the computer name and domain name from the registry so we
    00960     // can give them to the datagram receiver. During textmode setup
    00961     // the domain name will not be there, so we won't start the datagram
    00962     // receiver, which is fine.
    00963     //
    00964     // BUGBUG: Figure out the correct location to read the domain name
    00965     // from -- this one is a special hack in winnt.sif just for this.
    00966     //
    00967
    00968     RtlInitUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName" );
    00969
    00970     InitializeObjectAttributes(
    00971         &objectAttributes,
    00972         &string,
    00973         OBJ_CASE_INSENSITIVE,
    00974         NULL,
    00975         NULL
    00976         );
    00977
    00978     status = NtOpenKey( &keyHandle, KEY_ALL_ACCESS, &objectAttributes );
    00979     if ( !NT_SUCCESS(status) ) {
    00980         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open ComputerName key: %x\n", status ));
    00981         goto cleanup;
    00982     }
    00983
    00984     RtlInitUnicodeString( &string, L"ComputerName" );
    00985
    00986     keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
    00987     RtlZeroMemory(buffer, bufferLength);
    00988
    00989     status = NtQueryValueKey(
    00990                  keyHandle,
    00991                  &string,
    00992                  KeyValuePartialInformation,
    00993                  keyValue,
    00994                  bufferLength,
    00995                  &length);
    00996
    00997     NtClose( keyHandle );
    00998     if ( !NT_SUCCESS(status) ) {
    00999         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to query ComputerName value: %x\n", status ));
    01000         goto cleanup;
    01001     }
    01002
    01003     if ( !RtlCreateUnicodeString(&computerName, (PWSTR)keyValue->Data) ) {
    01004         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to create ComputerName string\n" ));
    01005         status = STATUS_INSUFFICIENT_RESOURCES;
    01006         goto cleanup;
    01007     }
    01008
    01009     domainName.Length = 0;
    01010
    01011     RtlInitUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\DomainName" );
    01012
    01013     InitializeObjectAttributes(
    01014         &objectAttributes,
    01015         &string,
    01016         OBJ_CASE_INSENSITIVE,
    01017         NULL,
    01018         NULL
    01019         );
    01020
    01021     status = NtOpenKey( &keyHandle, KEY_ALL_ACCESS, &objectAttributes );
    01022     if ( !NT_SUCCESS(status) ) {
    01023         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open DomainName key: %x\n", status ));
    01024         startDatagramReceiver = FALSE;
    01025     } else {
    01026
    01027         RtlInitUnicodeString( &string, L"DomainName" );
    01028
    01029         keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
    01030         RtlZeroMemory(buffer, bufferLength);
    01031
    01032         status = NtQueryValueKey(
    01033                      keyHandle,
    01034                      &string,
    01035                      KeyValuePartialInformation,
    01036                      keyValue,
    01037                      bufferLength,
    01038                      &length);
    01039
    01040         NtClose( keyHandle );
    01041         if ( !NT_SUCCESS(status) ) {
    01042             KdPrint(( "IopStartNetworkForRemoteBoot: Unable to query Domain value: %x\n", status ));
    01043             startDatagramReceiver = FALSE;
    01044         } else {
    01045             if ( !RtlCreateUnicodeString(&domainName, (PWSTR)keyValue->Data) ) {
    01046                 KdPrint(( "IopStartNetworkForRemoteBoot: Unable to create DomainName string\n" ));
    01047                 status = STATUS_INSUFFICIENT_RESOURCES;
    01048                 goto cleanup;
    01049             }
    01050             startDatagramReceiver = TRUE;
    01051         }
    01052     }
    01053
    01054     //
    01055     // Tell the redir to start.
    01056     //
    01057
    01058     rrp->Type = ConfigInformation;
    01059     rrp->Version = REQUEST_PACKET_VERSION;
    01060
    01061     rrp->Parameters.Start.RedirectorNameLength = computerName.Length;
    01062     RtlCopyMemory(rrp->Parameters.Start.RedirectorName,
    01063                   computerName.Buffer,
    01064                   computerName.Length);
    01065
    01066     rrp->Parameters.Start.DomainNameLength = domainName.Length;
    01067     RtlCopyMemory(((PUCHAR)rrp->Parameters.Start.RedirectorName) + computerName.Length,
    01068                   domainName.Buffer,
    01069                   domainName.Length);
    01070
    01071     RtlFreeUnicodeString(&computerName);
    01072     RtlFreeUnicodeString(&domainName);
    01073
    01074     wkstaConfig.wki502_char_wait = 3600;
    01075     wkstaConfig.wki502_maximum_collection_count = 16;
    01076     wkstaConfig.wki502_collection_time = 250;
    01077     wkstaConfig.wki502_keep_conn = 600;
    01078     wkstaConfig.wki502_max_cmds = 5;
    01079     wkstaConfig.wki502_sess_timeout = 45;
    01080     wkstaConfig.wki502_siz_char_buf = 512;
    01081     wkstaConfig.wki502_max_threads = 17;
    01082     wkstaConfig.wki502_lock_quota = 6144;
    01083     wkstaConfig.wki502_lock_increment = 10;
    01084     wkstaConfig.wki502_lock_maximum = 500;
    01085     wkstaConfig.wki502_pipe_increment = 10;
    01086     wkstaConfig.wki502_pipe_maximum = 500;
    01087     wkstaConfig.wki502_cache_file_timeout = 40;
    01088     wkstaConfig.wki502_dormant_file_limit = 45;
    01089     wkstaConfig.wki502_read_ahead_throughput = MAXULONG;
    01090     wkstaConfig.wki502_num_mailslot_buffers = 3;
    01091     wkstaConfig.wki502_num_srv_announce_buffers = 20;
    01092     wkstaConfig.wki502_max_illegal_datagram_events = 5;
    01093     wkstaConfig.wki502_illegal_datagram_event_reset_frequency = 60;
    01094     wkstaConfig.wki502_log_election_packets = FALSE;
    01095     wkstaConfig.wki502_use_opportunistic_locking = TRUE;
    01096     wkstaConfig.wki502_use_unlock_behind = TRUE;
    01097     wkstaConfig.wki502_use_close_behind = TRUE;
    01098     wkstaConfig.wki502_buf_named_pipes = TRUE;
    01099     wkstaConfig.wki502_use_lock_read_unlock = TRUE;
    01100     wkstaConfig.wki502_utilize_nt_caching = TRUE;
    01101     wkstaConfig.wki502_use_raw_read = TRUE;
    01102     wkstaConfig.wki502_use_raw_write = TRUE;
    01103     wkstaConfig.wki502_use_write_raw_data = TRUE;
    01104     wkstaConfig.wki502_use_encryption = TRUE;
    01105     wkstaConfig.wki502_buf_files_deny_write = TRUE;
    01106     wkstaConfig.wki502_buf_read_only_files = TRUE;
    01107     wkstaConfig.wki502_force_core_create_mode = TRUE;
    01108     wkstaConfig.wki502_use_512_byte_max_transfer = FALSE;
    01109
    01110     status = NtFsControlFile(
    01111                 RdrHandle,
    01112                 NULL,
    01113                 NULL,
    01114                 NULL,
    01115                 &ioStatusBlock,
    01116                 FSCTL_LMR_START | 0x80000000,
    01117                 rrp,
    01118                 sizeof(LMR_REQUEST_PACKET) +
    01119                     rrp->Parameters.Start.RedirectorNameLength +
    01120                     rrp->Parameters.Start.DomainNameLength,
    01121                 &wkstaConfig,
    01122                 sizeof(wkstaConfig)
    01123                 );
    01124
    01125     if ( NT_SUCCESS(status) ) {
    01126         status = ioStatusBlock.Status;
    01127     }
    01128     if ( !NT_SUCCESS(status) ) {
    01129         KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(start) redirector: %x\n", status ));
    01130         goto cleanup;
    01131     }
    01132
    01133     if (startDatagramReceiver) {
    01134
    01135         //
    01136         // Tell the datagram receiver to start.
    01137         //
    01138
    01139         drrp->Version = LMDR_REQUEST_PACKET_VERSION;
    01140
    01141         drrp->Parameters.Start.NumberOfMailslotBuffers = 16;
    01142         drrp->Parameters.Start.NumberOfServerAnnounceBuffers = 20;
    01143         drrp->Parameters.Start.IllegalDatagramThreshold = 5;
    01144         drrp->Parameters.Start.EventLogResetFrequency = 60;
    01145         drrp->Parameters.Start.LogElectionPackets = FALSE;
    01146
    01147         drrp->Parameters.Start.IsLanManNt = FALSE;
    01148
    01149         status = NtDeviceIoControlFile(
    01150                     dgHandle,
    01151                     NULL,
    01152                     NULL,
    01153                     NULL,
    01154                     &ioStatusBlock,
    01155                     IOCTL_LMDR_START,
    01156                     drrp,
    01157                     sizeof(LMDR_REQUEST_PACKET),
    01158                     NULL,
    01159                     0
    01160                     );
    01161
    01162         if ( NT_SUCCESS(status) ) {
    01163             status = ioStatusBlock.Status;
    01164         }
    01165
    01166         NtClose( dgHandle );
    01167         dgHandle = NULL;
    01168
    01169         if ( !NT_SUCCESS(status) ) {
    01170             KdPrint(( "IopStartNetworkForRemoteBoot: Unable to IOCTL(start) datagram receiver: %x\n", status ));
    01171             goto cleanup;
    01172         }
    01173
    01174     } else {
    01175
    01176         NtClose( dgHandle );
    01177         dgHandle = NULL;
    01178
    01179         //
    01180         // Tell the redir to bind to the transports.
    01181         //
    01182         // Note: In the current redirector implementation, this call just
    01183         // tells the redirector to register for TDI PnP notifications.
    01184         // Starting the datagram receiver also does this, so we only issue
    01185         // this FSCTL if we're not starting the datagram receiver.
    01186         //
    01187
    01188         status = NtFsControlFile(
    01189                     RdrHandle,
    01190                     NULL,
    01191                     NULL,
    01192                     NULL,
    01193                     &ioStatusBlock,
    01194                     FSCTL_LMR_BIND_TO_TRANSPORT | 0x80000000,
    01195                     NULL,
    01196                     0,
    01197                     NULL,
    01198                     0
    01199                     );
    01200
    01201         if ( NT_SUCCESS(status) ) {
    01202             status = ioStatusBlock.Status;
    01203         }
    01204
    01205         if ( !NT_SUCCESS(status) ) {
    01206             KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(bind) redirector: %x\n", status ));
    01207             goto cleanup;
    01208         }
    01209     }
    01210
    01211 #if defined(REMOTE_BOOT)
    01212     if (((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IS_TEXTMODE) == 0) &&
    01213         ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_FORMAT_NEEDED) == 0)) {
    01214
    01215         //
    01216         // Get the path to the boot partition on the disk for CSC and redirection
    01217         // Note: On failure, this defaults to \Device\Harddisk0\Partition1
    01218         //
    01219
    01220         IopGetHarddiskInfo(NetHDCSCPartition);
    01221
    01222         //
    01223         // Tell the redirector to initialize remote boot redirection (back
    01224         // to the local disk). Note that we only do this if we're NOT doing
    01225         // textmode setup. During textmode, we let Setup do this so that it
    01226         // can do so AFTER it has reformatted the local disk.
    01227         //
    01228
    01229         status = NtFsControlFile(
    01230                     RdrHandle,
    01231                     NULL,
    01232                     NULL,
    01233                     NULL,
    01234                     &ioStatusBlock,
    01235                     FSCTL_LMR_START_RBR,
    01236                     NetHDCSCPartition,
    01237                     wcslen(NetHDCSCPartition) * sizeof(WCHAR),
    01238                     NULL,
    01239                     0
    01240                     );
    01241
    01242         if (NT_SUCCESS(status) ) {
    01243             status = ioStatusBlock.Status;
    01244         }
    01245
    01246         if ( !NT_SUCCESS(status) ) {
    01247             KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(RBR) redirector: %x\n", status ));
    01248         }
    01249     }
    01250
    01251     if ( (LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_DISCONNECTED) == 0 )
    01252 #endif // defined(REMOTE_BOOT)
    01253     {
    01254
    01255         //
    01256         // Loop until the redirector is bound to the transport. It may take a
    01257         // while because TDI defers notification of binding to a worker thread.
    01258         // We start with a half a second wait and double it each time, trying
    01259         // five times total.
    01260         //
    01261
    01262         interval.QuadPart = -500 * 1000 * 10;    // 1/2 second, relative
    01263         enumerateAttempts = 0;
    01264
    01265         while (TRUE) {
    01266
    01267             KeDelayExecutionThread(KernelMode, FALSE, &interval);
    01268
    01269             RtlZeroMemory(rrp, sizeof(LMR_REQUEST_PACKET));
    01270
    01271             rrp->Type = EnumerateTransports;
    01272             rrp->Version = REQUEST_PACKET_VERSION;
    01273
    01274             status = NtFsControlFile(
    01275                         RdrHandle,
    01276                         NULL,
    01277                         NULL,
    01278                         NULL,
    01279                         &ioStatusBlock,
    01280                         FSCTL_LMR_ENUMERATE_TRANSPORTS,
    01281                         rrp,
    01282                         sizeof(LMR_REQUEST_PACKET),
    01283                         &wkstaTransportInfo,
    01284                         sizeof(wkstaTransportInfo)
    01285                         );
    01286
    01287             if ( NT_SUCCESS(status) ) {
    01288                 status = ioStatusBlock.Status;
    01289             }
    01290             if ( !NT_SUCCESS(status) ) {
    01291                 //KdPrint(( "IopStartNetworkForRemoteBoot: Unable to FSCTL(enumerate) redirector: %x\n", status ));
    01292             } else if (rrp->Parameters.Get.TotalBytesNeeded == 0) {
    01293                 //KdPrint(( "IopStartNetworkForRemoteBoot: FSCTL(enumerate) returned 0 entries\n" ));
    01294             } else {
    01295                 break;
    01296             }
    01297
    01298             ++enumerateAttempts;
    01299
    01300             if (enumerateAttempts == 5) {
    01301                 KdPrint(( "IopStartNetworkForRemoteBoot: Redirector didn't start\n" ));
    01302                 status = STATUS_REDIRECTOR_NOT_STARTED;
    01303                 goto cleanup;
    01304             }
    01305
    01306             interval.QuadPart *= 2;
    01307
    01308         }
    01309     }
    01310
    01311     //
    01312     // Prime the transport.
    01313     //
    01314
    01315 #if defined(REMOTE_BOOT)
    01316     IopEnableRemoteBootSecurity(LoaderBlock);
    01317 #endif // defined(REMOTE_BOOT)
    01318     IopSetDefaultGateway(LoaderBlock->SetupLoaderBlock->DefaultRouter);
    01319     IopCacheNetbiosNameForIpAddress(LoaderBlock);
    01320
    01321 #if defined(REMOTE_BOOT)
    01322     //
    01323     // CSC needs to be initialized after binding to the transport because ResetCSC
    01324     // (if needed) will try to enumerate the files and directories on the server.
    01325     //
    01326
    01327     if (((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IS_TEXTMODE) == 0) &&
    01328         ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_FORMAT_NEEDED) == 0)
    01329 #if 0
    01330         && ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_DISABLE_CSC) != 0)
    01331 #endif
    01332         ) {
    01333
    01334         wcstombs(buffer, NetHDCSCPartition, wcslen(NetHDCSCPartition) + 1);
    01335         strcat(buffer, REMOTE_BOOT_IMIRROR_PATH_A REMOTE_BOOT_CSC_SUBDIR_A);
    01336
    01337         status = IopInitCsc( buffer );
    01338
    01339         //
    01340         //  If we are connected and either we are part way through a reset of
    01341         //  the csc or the init failed then reset the csc.
    01342         //
    01343
    01344         if ( NT_SUCCESS(status) ) {
    01345
    01346             if (StartCsc == FLUSH_CSC ) {
    01347
    01348                 if ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_DISCONNECTED) == 0) {
    01349
    01350                     //
    01351                     // CSC may have lost the pin information.
    01352                     //
    01353
    01354                     status = IopResetCsc( buffer );
    01355
    01356                     if ( !NT_SUCCESS(status) ) {
    01357                         KdPrint(("IopStartNetworkForRemoteBoot: reset of Csc failed %x\n", status));
    01358                     }
    01359                 } else {
    01360                     IoCscInitializationFailed = TRUE;
    01361                 }
    01362             } else if ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_PIN_NET_DRIVER) &&
    01363                        (LoaderBlock->SetupLoaderBlock->NetbootCardDriverName[0] != L'\0')) {
    01364
    01365                 //
    01366                 // if we are connected and we're not repinning all files and
    01367                 // we have a new net card driver to pin, then pin it below
    01368                 // after we've created called IopAssignNetworkDriveLetter
    01369                 //
    01370
    01371                 pinNetDriver = TRUE;
    01372             }
    01373         }
    01374
    01375         if ( !NT_SUCCESS(status) ) {
    01376             KdPrint(("IopStartNetworkForRemoteBoot: initialization of Csc failed %x\n", status));
    01377             IoCscInitializationFailed = TRUE;
    01378             SharedUserData->SystemFlags |= SYSTEM_FLAG_DISKLESS_CLIENT;
    01379         }
    01380
    01381     } else {
    01382         IoCscInitializationFailed = TRUE;
    01383         SharedUserData->SystemFlags |= SYSTEM_FLAG_DISKLESS_CLIENT;
    01384     }
    01385 #endif // defined(REMOTE_BOOT)
    01386
    01387     IopAssignNetworkDriveLetter(LoaderBlock);
    01388
    01389 #if defined(REMOTE_BOOT)
    01390     if (pinNetDriver) {
    01391
    01392         //
    01393         //  Pin the new net card driver simply by opening it.  if it
    01394         //  fails, it's not fatal, as we'll eventually pin it since
    01395         //  the directory it's in is marked as system/inherit.
    01396         //
    01397
    01398         HANDLE driverHandle = NULL;
    01399         PWCHAR fullDriverName;
    01400
    01401         fullDriverName = (PWCHAR) ExAllocatePoolWithTag(
    01402                             NonPagedPool,
    01403                             sizeof( L"\\SystemRoot\\System32\\Drivers\\" ) +
    01404                             sizeof( LoaderBlock->SetupLoaderBlock->NetbootCardDriverName ),
    01405                             'bRoI'
    01406                             );
    01407
    01408         if (fullDriverName != NULL) {
    01409
    01410             wcscpy(fullDriverName, L"\\SystemRoot\\System32\\Drivers\\");
    01411             wcscat(fullDriverName, LoaderBlock->SetupLoaderBlock->NetbootCardDriverName);
    01412
    01413             RtlInitUnicodeString( &string, fullDriverName );
    01414
    01415             InitializeObjectAttributes(
    01416                 &objectAttributes,
    01417                 &string,
    01418                 OBJ_CASE_INSENSITIVE,
    01419                 NULL,
    01420                 NULL
    01421                 );
    01422
    01423             status = NtCreateFile(
    01424                         &driverHandle,
    01425                         GENERIC_READ,
    01426                         &objectAttributes,
    01427                         &ioStatusBlock,
    01428                         NULL,
    01429                         FILE_ATTRIBUTE_NORMAL,
    01430                         FILE_SHARE_READ,
    01431                         FILE_OPEN,
    01432                         FILE_SYNCHRONOUS_IO_NONALERT,
    01433                         NULL,
    01434                         0
    01435                         );
    01436             if ( !NT_SUCCESS(status) ) {
    01437
    01438                 //
    01439                 //  this is not a fatal error, the redir should pin it eventually
    01440                 //
    01441
    01442                 KdPrint(( "IopStartNetworkForRemoteBoot: Unable to open new net driver: 0x%x\n", status ));
    01443             }
    01444             if (driverHandle != NULL) {
    01445                 NtClose( driverHandle );
    01446             }
    01447
    01448             ExFreePool( fullDriverName );
    01449
    01450         } else {
    01451
    01452             //
    01453             //  this is not a fatal error, the redir should pin it eventually
    01454             //
    01455
    01456             KdPrint(( "IopStartNetworkForRemoteBoot: Unable to allocate buffer to pin netcard driver\n" ));
    01457         }
    01458     }
    01459
    01460     leaveRdrHandleOpen = TRUE;
    01461 #endif // defined(REMOTE_BOOT)
    01462
    01463 cleanup:
    01464
    01465     RtlFreeUnicodeString( &computerName );
    01466     RtlFreeUnicodeString( &domainName );
    01467 #if defined(REMOTE_BOOT)
    01468     if ( NetHDCSCPartition != NULL ) {
    01469         ExFreePool( NetHDCSCPartition );
    01470     }
    01471 #else
    01472     if ( buffer != NULL ) {
    01473         ExFreePool( buffer );
    01474     }
    01475 #endif // defined(REMOTE_BOOT)
    01476
    01477     if ( dgHandle != NULL ) {
    01478         NtClose( dgHandle );
    01479     }
    01480
    01481 #if defined(REMOTE_BOOT)
    01482     //
    01483     // If requested, exit with RdrHandle still set so that we can close CSC quickly.
    01484     //
    01485
    01486     if ( !leaveRdrHandleOpen && (RdrHandle != NULL) ) {
    01487         NtClose( RdrHandle );
    01488         RdrHandle = NULL;
    01489     }
    01490 #endif // defined(REMOTE_BOOT)
    01491
    01492     return status;
    01493 }
    01494
    01495
    01496 #if defined(REMOTE_BOOT)
    01497 VOID
    01498 IopShutdownCsc(
    01499     )
    01500 {
    01501     NTSTATUS status;
    01502     IO_STATUS_BLOCK ioStatusBlock;
    01503     SHADOWINFO shadowInfo;
    01504
    01505     if ( RdrHandle != NULL ) {
    01506
    01507         KeAttachProcess( RdrHandleProcess );
    01508
    01509         RtlZeroMemory( &shadowInfo, sizeof(shadowInfo) );
    01510         shadowInfo.uStatus = 0x0001; // SHADOW_SWITCH_SHADOWING
    01511         shadowInfo.uOp = 1; // SHADOW_SWITCH_OFF
    01512
    01513         status = NtDeviceIoControlFile(
    01514                     RdrHandle,
    01515                     NULL,
    01516                     NULL,
    01517                     NULL,
    01518                     &ioStatusBlock,
    01519                     IOCTL_SWITCHES,
    01520                     &shadowInfo,
    01521                     0,
    01522                     NULL,
    01523                     0
    01524                     );
    01525 #if DBG
    01526         if ( NT_SUCCESS(status) ) {
    01527             status = ioStatusBlock.Status;
    01528         }
    01529
    01530         if ( !NT_SUCCESS(status) ) {
    01531             KdPrint(( "IopShutdownCsc: %x\n", status ));
    01532         }
    01533 #endif
    01534         NtClose( RdrHandle );
    01535         RdrHandle = NULL;
    01536
    01537         KeDetachProcess();
    01538     }
    01539
    01540     return;
    01541 }
    01542 #endif // defined(REMOTE_BOOT)
    01543
    01544
    01545 VOID
    01546 IopAssignNetworkDriveLetter (
    01547     PLOADER_PARAMETER_BLOCK LoaderBlock
    01548     )
    01549 {
    01550     PUCHAR p;
    01551     PUCHAR q;
    01552     UCHAR ntName[128];
    01553     STRING ansiString;
    01554     UNICODE_STRING unicodeString;
    01555     UNICODE_STRING unicodeString2;
    01556     NTSTATUS status;
    01557
    01558     //
    01559     // Create the symbolic link of X: to the redirector. We do this
    01560     // after the redirector has loaded, but before AssignDriveLetters
    01561     // is called the first time in textmode setup (once that has
    01562     // happened, the drive letters will stick).
    01563     //
    01564     // Note that we use X: for the textmode setup phase of a remote
    01565     // installation. But for a true remote boot, we use C:.
    01566     //
    01567
    01568     if ((LoaderBlock->SetupLoaderBlock->Flags & (SETUPBLK_FLAGS_REMOTE_INSTALL |
    01569                                                  SETUPBLK_FLAGS_SYSPREP_INSTALL)) != 0) {
    01570         RtlInitUnicodeString( &unicodeString2, L"\\DosDevices\\X:");
    01571     } else {
    01572         RtlInitUnicodeString( &unicodeString2, L"\\DosDevices\\C:");
    01573     }
    01574
    01575     //
    01576     // If this is a remote boot setup boot, NtBootPathName is of the
    01577     // form <server><share>\setup<install-directory><platform>.
    01578     // We want the root of the X: drive to be the root of the install
    01579     // directory.
    01580     //
    01581     // If this is a normal remote boot, NtBootPathName is of the form
    01582     // <server><share>\images<machine>\winnt. We want the root of
    01583     // the X: drive to be the root of the machine directory.
    01584     //
    01585     // Thus in either case, we need to remove the last element of the
    01586     // path.
    01587     //
    01588
    01589     p = strrchr( LoaderBlock->NtBootPathName, '\\' );   // find last separator
    01590     if ( (p != NULL) && (*(p+1) == 0) ) {
    01591
    01592         //
    01593         // NtBootPathName ends with a backslash, so we need to back up
    01594         // to the previous backslash.
    01595         //
    01596
    01597         q = p;
    01598         *q = 0;
    01599         p = strrchr( LoaderBlock->NtBootPathName, '\\' );   // find last separator
    01600         *q = '\\';
    01601     }
    01602     if ( p == NULL ) {
    01603         KdPrint(( "IopAssignNetworkDriveLetter: malformed NtBootPathName: %s\n", LoaderBlock->NtBootPathName ));
    01604         KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED );
    01605     }
    01606     *p = 0;                                 // terminate \server\share\images\machine
    01607
    01608     strcpy( ntName, "\\Device\\LanmanRedirector");
    01609     strcat( ntName, LoaderBlock->NtBootPathName );  // append \server\share\images\machine
    01610
    01611     RtlInitAnsiString( &ansiString, ntName );
    01612     RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, TRUE );
    01613
    01614     status = IoCreateSymbolicLink(&unicodeString2, &unicodeString);
    01615     if (!NT_SUCCESS(status)) {
    01616         KdPrint(( "IopAssignNetworkDriveLetter: unable to create DOS link for redirected boot drive: %x\n", status ));
    01617         KeBugCheck( ASSIGN_DRIVE_LETTERS_FAILED );
    01618     }
    01619     // DbgPrint("IopAssignNetworkDriveLetter: assigned %wZ to %wZ\n", &unicodeString2, &unicodeString);
    01620
    01621     RtlFreeUnicodeString( &unicodeString );
    01622
    01623     *p = '\\';                              // restore string
    01624
    01625     return;
    01626 }
    01627
    01628
    01629 #if defined(REMOTE_BOOT)
    01630 VOID
    01631 IopEnableRemoteBootSecurity (
    01632     PLOADER_PARAMETER_BLOCK LoaderBlock
    01633     )
    01634 {
    01635     UNICODE_STRING IpsecString;
    01636     NTSTATUS status;
    01637     HANDLE handle;
    01638     OBJECT_ATTRIBUTES objectAttributes;
    01639     IO_STATUS_BLOCK ioStatusBlock;
    01640     UCHAR policyBuffer[sizeof(IPSEC_SET_POLICY) + sizeof(IPSEC_POLICY_INFO)];
    01641     PIPSEC_SET_POLICY setPolicy = (PIPSEC_SET_POLICY)policyBuffer;
    01642     IPSEC_FILTER outboundFilter;
    01643     IPSEC_FILTER inboundFilter;
    01644     IPSEC_SET_SPI setSpi;
    01645     UCHAR saBuffer[sizeof(IPSEC_ADD_UPDATE_SA) + (6 * sizeof(ULONG))];
    01646     PIPSEC_ADD_UPDATE_SA addUpdateSa;
    01647
    01648
    01649     if ((LoaderBlock->SetupLoaderBlock->Flags & SETUPBLK_FLAGS_IPSEC_ENABLED) == 0) {
    01650         return;
    01651     }
    01652
    01653     RtlInitUnicodeString( &IpsecString, DD_IPSEC_DEVICE_NAME );
    01654
    01655     InitializeObjectAttributes(
    01656         &objectAttributes,
    01657         &IpsecString,
    01658         OBJ_CASE_INSENSITIVE,
    01659         NULL,
    01660         NULL
    01661         );
    01662
    01663     status = NtCreateFile(
    01664                 &handle,
    01665                 GENERIC_READ | GENERIC_WRITE,
    01666                 &objectAttributes,
    01667                 &ioStatusBlock,
    01668                 NULL,
    01669                 0,
    01670                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    01671                 FILE_OPEN,
    01672                 FILE_SYNCHRONOUS_IO_NONALERT,
    01673                 NULL,
    01674                 0
    01675                 );
    01676     if ( !NT_SUCCESS(status) ) {
    01677         KdPrint(( "IopEnableRemoteBootSecurity: Unable to open IPSEC: %x\n", status ));
    01678         return;
    01679     }
    01680
    01681     //
    01682     // Set the policy. We need two filters, one for outbound and
    01683     // one for inbound.
    01684     //
    01685
    01686     RtlZeroMemory(&outboundFilter, sizeof(IPSEC_FILTER));
    01687     RtlZeroMemory(&inboundFilter, sizeof(IPSEC_FILTER));
    01688
    01689     outboundFilter.SrcAddr = LoaderBlock->SetupLoaderBlock->IpAddress;
    01690     outboundFilter.SrcMask = 0xffffffff;
    01691     outboundFilter.DestAddr = LoaderBlock->SetupLoaderBlock->ServerIpAddress;
    01692     outboundFilter.DestMask = 0xffffffff;
    01693     // outboundFilter.DestPort = 0x8B;  // netbios session port
    01694     outboundFilter.Protocol = 0x6;   // TCP
    01695
    01696     inboundFilter.SrcAddr = LoaderBlock->SetupLoaderBlock->ServerIpAddress;
    01697     inboundFilter.SrcMask = 0xffffffff;
    01698     // inboundFilter.SrcPort = 0x8B;  // netbios session port
    01699     inboundFilter.DestAddr = LoaderBlock->SetupLoaderBlock->IpAddress;
    01700     inboundFilter.DestMask = 0xffffffff;
    01701     inboundFilter.Protocol = 0x6;   // TCP
    01702
    01703     RtlZeroMemory(setPolicy, sizeof(policyBuffer));
    01704
    01705     setPolicy->NumEntries = 2;
    01706     setPolicy->pInfo[0].Index = 1;
    01707     setPolicy->pInfo[0].AssociatedFilter = outboundFilter;
    01708     setPolicy->pInfo[1].Index = 2;
    01709     setPolicy->pInfo[1].AssociatedFilter = inboundFilter;
    01710
    01711     status = NtDeviceIoControlFile(
    01712                 handle,
    01713                 NULL,
    01714                 NULL,
    01715                 NULL,
    01716                 &ioStatusBlock,
    01717                 IOCTL_IPSEC_SET_POLICY,
    01718                 setPolicy,
    01719                 sizeof(policyBuffer),
    01720                 NULL,
    01721                 0
    01722                 );
    01723
    01724     if ( !NT_SUCCESS(status) ) {
    01725         KdPrint(( "IopEnableRemoteBootSecurity: Unable to IOCTL_IPSEC_SET_POLICY: %x\n", status ));
    01726         return;
    01727     }
    01728
    01729     //
    01730     // Now set the SPI we made up in the loader.
    01731     //
    01732
    01733     setSpi.Context = 0;
    01734     setSpi.InstantiatedFilter = inboundFilter;
    01735     setSpi.SPI = LoaderBlock->SetupLoaderBlock->IpsecInboundSpi;
    01736
    01737     status = NtDeviceIoControlFile(
    01738                 handle,
    01739                 NULL,
    01740                 NULL,
    01741                 NULL,
    01742                 &ioStatusBlock,
    01743                 IOCTL_IPSEC_SET_SPI,
    01744                 &setSpi,
    01745                 sizeof(IPSEC_SET_SPI),
    01746                 &setSpi,
    01747                 sizeof(IPSEC_SET_SPI)
    01748                 );
    01749
    01750     if ( !NT_SUCCESS(status) ) {
    01751         KdPrint(( "IopEnableRemoteBootSecurity: Unable to IOCTL_IPSEC_SET_SPI: %x\n", status ));
    01752         return;
    01753     }
    01754
    01755     //
    01756     // Set up the security association for the outbound
    01757     // connection.
    01758     //
    01759
    01760     addUpdateSa = (PIPSEC_ADD_UPDATE_SA)saBuffer;
    01761     memset(addUpdateSa, 0, sizeof(saBuffer));
    01762
    01763     addUpdateSa->SAInfo.Context = setSpi.Context;
    01764     addUpdateSa->SAInfo.NumSAs = 1;
    01765     addUpdateSa->SAInfo.InstantiatedFilter = outboundFilter;
    01766     addUpdateSa->SAInfo.SecAssoc[0].Operation = Encrypt;
    01767     addUpdateSa->SAInfo.SecAssoc[0].SPI = LoaderBlock->SetupLoaderBlock->IpsecOutboundSpi;
    01768     addUpdateSa->SAInfo.SecAssoc[0].IntegrityAlgo.algoIdentifier = IPSEC_AH_MD5;
    01769     addUpdateSa->SAInfo.SecAssoc[0].IntegrityAlgo.algoKeylen = 4 * sizeof(ULONG);
    01770     addUpdateSa->SAInfo.SecAssoc[0].ConfAlgo.algoIdentifier = IPSEC_ESP_DES;
    01771     addUpdateSa->SAInfo.SecAssoc[0].ConfAlgo.algoKeylen = 2 * sizeof(ULONG);
    01772
    01773     addUpdateSa->SAInfo.KeyLen = 6 * sizeof(ULONG);
    01774     memcpy(addUpdateSa->SAInfo.KeyMat, &LoaderBlock->SetupLoaderBlock->IpsecSessionKey, sizeof(ULONG));
    01775     memcpy(addUpdateSa->SAInfo.KeyMat+sizeof(ULONG), &LoaderBlock->SetupLoaderBlock->IpsecSessionKey, sizeof(ULONG));
    01776     memcpy(addUpdateSa->SAInfo.KeyMat+(2*sizeof(ULONG)), &LoaderBlock->SetupLoaderBlock->IpsecSessionKey, sizeof(ULONG));
    01777     memcpy(addUpdateSa->SAInfo.KeyMat+(3*sizeof(ULONG)), &LoaderBlock->SetupLoaderBlock->IpsecSessionKey, sizeof(ULONG));
    01778     memcpy(addUpdateSa->SAInfo.KeyMat+(4*sizeof(ULONG)), &LoaderBlock->SetupLoaderBlock->IpsecSessionKey, sizeof(ULONG));
    01779     memcpy(addUpdateSa->SAInfo.KeyMat+(5*sizeof(ULONG)), &LoaderBlock->SetupLoaderBlock->IpsecSessionKey, sizeof(ULONG));
    01780
    01781     status = NtDeviceIoControlFile(
    01782                 handle,
    01783                 NULL,
    01784                 NULL,
    01785                 NULL,
    01786                 &ioStatusBlock,
    01787                 IOCTL_IPSEC_ADD_SA,
    01788                 addUpdateSa,
    01789                 FIELD_OFFSET(IPSEC_ADD_UPDATE_SA, SAInfo.KeyMat[0]) + addUpdateSa->SAInfo.KeyLen,
    01790                 NULL,
    01791                 0
    01792                 );
    01793
    01794     if ( !NT_SUCCESS(status) ) {
    01795         KdPrint(( "IopEnableRemoteBootSecurity: Unable to IOCTL_IPSEC_ADD_SA: %x\n", status ));
    01796         return;
    01797     }
    01798
    01799     //
    01800     // Set up the security association for the inbound connection.
    01801     // If our Operation is "None", IPSEC does this for us.
    01802     //
    01803
    01804     if (addUpdateSa->SAInfo.SecAssoc[0].Operation != None) {
    01805
    01806         addUpdateSa->SAInfo.SecAssoc[0].SPI = LoaderBlock->SetupLoaderBlock->IpsecInboundSpi;
    01807         addUpdateSa->SAInfo.InstantiatedFilter = inboundFilter;
    01808
    01809         status = NtDeviceIoControlFile(
    01810                     handle,
    01811                     NULL,
    01812                     NULL,
    01813                     NULL,
    01814                     &ioStatusBlock,
    01815                     IOCTL_IPSEC_UPDATE_SA,
    01816                     addUpdateSa,
    01817                     FIELD_OFFSET(IPSEC_ADD_UPDATE_SA, SAInfo.KeyMat[0]) + addUpdateSa->SAInfo.KeyLen,
    01818                     NULL,
    01819                     0
    01820                     );
    01821
    01822         if ( !NT_SUCCESS(status) ) {
    01823             KdPrint(( "IopEnableRemoteBootSecurity: Unable to IOCTL_IPSEC_UPDATE_SA: %x\n", status ));
    01824             return;
    01825         }
    01826     }
    01827
    01828     NtClose( handle );
    01829
    01830 }
    01831 #endif // defined(REMOTE_BOOT)
    01832
    01833 NTSTATUS
    01834 IopStartTcpIpForRemoteBoot (
    01835     PLOADER_PARAMETER_BLOCK LoaderBlock
    01836     )
    01837 {
    01838     UNICODE_STRING IpString;
    01839     NTSTATUS status = STATUS_SUCCESS;
    01840     HANDLE handle;
    01841     OBJECT_ATTRIBUTES objectAttributes;
    01842     IO_STATUS_BLOCK ioStatusBlock;
    01843     IP_SET_ADDRESS_REQUEST IpRequest;
    01844
    01845     RtlInitUnicodeString( &IpString, DD_IP_DEVICE_NAME );
    01846
    01847     InitializeObjectAttributes(
    01848         &objectAttributes,
    01849         &IpString,
    01850         OBJ_CASE_INSENSITIVE,
    01851         NULL,
    01852         NULL
    01853         );
    01854
    01855     IpRequest.Context = (USHORT)2;
    01856     IpRequest.Address = LoaderBlock->SetupLoaderBlock->IpAddress;
    01857     IpRequest.SubnetMask = LoaderBlock->SetupLoaderBlock->SubnetMask;
    01858
    01859     status = NtCreateFile(
    01860                 &handle,
    01861                 GENERIC_READ | GENERIC_WRITE,
    01862                 &objectAttributes,
    01863                 &ioStatusBlock,
    01864                 NULL,
    01865                 0,
    01866                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    01867                 FILE_OPEN,
    01868                 FILE_SYNCHRONOUS_IO_NONALERT,
    01869                 NULL,
    01870                 0
    01871                 );
    01872     if ( !NT_SUCCESS(status) ) {
    01873         KdPrint(( "IopStartTcpIpForRemoteBoot: Unable to open IP: %x\n", status ));
    01874         goto cleanup;
    01875     }
    01876
    01877     status = NtDeviceIoControlFile(
    01878                 handle,
    01879                 NULL,
    01880                 NULL,
    01881                 NULL,
    01882                 &ioStatusBlock,
    01883                 IOCTL_IP_SET_ADDRESS_DUP,
    01884                 &IpRequest,
    01885                 sizeof(IP_SET_ADDRESS_REQUEST),
    01886                 NULL,
    01887                 0
    01888                 );
    01889
    01890     NtClose( handle );
    01891
    01892     if ( !NT_SUCCESS(status) ) {
    01893         KdPrint(( "IopStartTcpIpForRemoteBoot: Unable to IOCTL IP: %x\n", status ));
    01894         goto cleanup;
    01895     }
    01896
    01897 cleanup:
    01898
    01899     return status;
    01900 }
    01901
    01902 BOOLEAN
    01903 IopIsRemoteBootCard(
    01904     IN PDEVICE_NODE DeviceNode,
    01905     IN PLOADER_PARAMETER_BLOCK LoaderBlock,
    01906     IN PWCHAR HwIds
    01907     )
    01908
    01909 /*++
    01910
    01911 Routine Description:
    01912
    01913     This function determines if the card described by the hwIds is the
    01914     remote boot network card. It checks against the hardware ID for the
    01915     card that is stored in the setup loader block.
    01916
    01917     THIS ASSUMES THAT IOREMOTEBOOTCLIENT IS TRUE AND THAT LOADERBLOCK
    01918     IS VALID.
    01919
    01920 Arguments:
    01921
    01922     DeviceNode - Device node for the card in question.
    01923
    01924     LoaderBlock - Supplies a pointer to the loader parameter block that was
    01925         created by the OS Loader.
    01926
    01927     HwIds - The hardware IDs for the device in question.
    01928
    01929 Return Value:
    01930
    01931     TRUE or FALSE.
    01932
    01933 --*/
    01934
    01935 {
    01936     PSETUP_LOADER_BLOCK setupLoaderBlock;
    01937     PWCHAR curHwId;
    01938
    01939     //
    01940     // setupLoaderBlock will always be non-NULL if we are
    01941     // remote booting, even if we are not in setup.
    01942     //
    01943
    01944     setupLoaderBlock = LoaderBlock->SetupLoaderBlock;
    01945
    01946     //
    01947     // Scan through the HwIds for a match.
    01948     //
    01949
    01950     curHwId = HwIds;
    01951
    01952     while (*curHwId != L'\0') {
    01953         if (wcscmp(curHwId, setupLoaderBlock->NetbootCardHardwareId) == 0) {
    01954
    01955             ULONG BusNumber, SlotNumber;
    01956
    01957             BusNumber = (ULONG)((((PNET_CARD_INFO)setupLoaderBlock->NetbootCardInfo)->pci.BusDevFunc) >> 8);
    01958             SlotNumber = (ULONG)(((((PNET_CARD_INFO)setupLoaderBlock->NetbootCardInfo)->pci.BusDevFunc) & 0xf8) >> 3);
    01959
    01960             KdPrint(("IopIsRemoteBootCard: FOUND %ws\n", setupLoaderBlock->NetbootCardHardwareId));
    01961             if ((DeviceNode->ResourceRequirements->BusNumber != BusNumber) ||
    01962                 (DeviceNode->ResourceRequirements->SlotNumber != SlotNumber)) {
    01963                 KdPrint(("IopIsRemoteBootCard: ignoring non-matching card:\n"));
    01964                 KdPrint(("  devnode bus %d, busdevfunc bus %d\n",
    01965                     DeviceNode->ResourceRequirements->BusNumber,
    01966                     BusNumber));
    01967                 KdPrint(("  devnode slot %d, busdevfunc slot %d\n",
    01968                     DeviceNode->ResourceRequirements->SlotNumber,
    01969                     SlotNumber));
    01970                 return FALSE;
    01971             } else {
    01972                 return TRUE;
    01973             }
    01974         }
    01975         curHwId += (wcslen(curHwId) + 1);
    01976     }
    01977
    01978     return FALSE;
    01979 }
    01980
    01981 NTSTATUS
    01982 IopSetupRemoteBootCard(
    01983     IN PLOADER_PARAMETER_BLOCK LoaderBlock,
    01984     IN HANDLE UniqueIdHandle,
    01985     IN PUNICODE_STRING UnicodeDeviceInstance
    01986     )
    01987
    01988 /*++
    01989
    01990 Routine Description:
    01991
    01992     This function modifies the registry to set up the netboot card.
    01993     We must do this here since the card is needed to boot, we can't
    01994     wait for the class installer to run.
    01995
    01996     THIS ASSUMES THAT IOREMOTEBOOTCLIENT IS TRUE.
    01997
    01998 Arguments:
    01999
    02000     LoaderBlock - Supplies a pointer to the loader parameter block that was
    02001         created by the OS Loader.
    02002
    02003     UniqueIdHandle - A handle to the device's unique node under the
    02004         Enum key.
    02005
    02006     UnicodeDeviceInstance - The device instance assigned to the device.
    02007
    02008 Return Value:
    02009
    02010     Status of the operation.
    02011
    02012 --*/
    02013
    02014 {
    02015     PSETUP_LOADER_BLOCK setupLoaderBlock;
    02016     UNICODE_STRING unicodeName, pnpInstanceId, keyName;
    02017     HANDLE tmpHandle;
    02018     HANDLE parametersHandle = NULL;
    02019     HANDLE currentControlSetHandle = NULL;
    02020     HANDLE remoteBootHandle = NULL;
    02021     HANDLE instanceHandle = NULL;
    02022     PWCHAR componentIdBuffer, curComponentIdLoc;
    02023     PCHAR registryList;
    02024     ULONG componentIdLength;
    02025     WCHAR tempNameBuffer[32];
    02026     WCHAR tempValueBuffer[128];
    02027     NTSTATUS status;
    02028     ULONG tmpValue, length;
    02029     PKEY_VALUE_PARTIAL_INFORMATION keyValue;
    02030     PKEY_VALUE_BASIC_INFORMATION keyValueBasic;
    02031     UCHAR dataBuffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + 128];
    02032     ULONG enumerateIndex;
    02033     OBJECT_ATTRIBUTES objectAttributes;
    02034     ULONG disposition;
    02035
    02036     //
    02037     // If we already think we have initialized a remote boot card, then
    02038     // exit (should not really happen once we identify cards using the
    02039     // bus/slot.
    02040     //
    02041
    02042     if (IopRemoteBootCardInitialized) {
    02043         return STATUS_SUCCESS;
    02044     }
    02045
    02046     //
    02047     // setupLoaderBlock will always be non-NULL if we are
    02048     // remote booting, even if we are not in setup.
    02049     //
    02050
    02051     setupLoaderBlock = LoaderBlock->SetupLoaderBlock;
    02052
    02053     //
    02054     // Open the current control set.
    02055     //
    02056
    02057     status = IopOpenRegistryKey(&currentControlSetHandle,
    02058                                 NULL,
    02059                                 &CmRegistryMachineSystemCurrentControlSet,
    02060                                 KEY_ALL_ACCESS,
    02061                                 FALSE
    02062                                 );
    02063
    02064     if (!NT_SUCCESS(status)) {
    02065         goto cleanup;
    02066     }
    02067
    02068     //
    02069     // Open the Control\RemoteBoot key, which may not exist.
    02070     //
    02071
    02072     PiWstrToUnicodeString(&unicodeName, L"Control\\RemoteBoot");
    02073
    02074     InitializeObjectAttributes(&objectAttributes,
    02075                                &unicodeName,
    02076                                OBJ_CASE_INSENSITIVE,
    02077                                currentControlSetHandle,
    02078                                (PSECURITY_DESCRIPTOR)NULL
    02079                                );
    02080
    02081     status = ZwCreateKey(&remoteBootHandle,
    02082                          KEY_ALL_ACCESS,
    02083                          &objectAttributes,
    02084                          0,
    02085                          (PUNICODE_STRING)NULL,
    02086                          0,
    02087                          &disposition
    02088                          );
    02089
    02090     if (!NT_SUCCESS(status)) {
    02091         goto cleanup;
    02092     }
    02093
    02094     //
    02095     // Open the key where the netui code stores information about the cards.
    02096     // During textmode setup this will fail because the Control\Network
    02097     // key is not there. After that it should work, although we may need
    02098     // to create the last node in the path.
    02099     //
    02100
    02101     PiWstrToUnicodeString(&unicodeName, L"Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\{54C7D140-09EF-11D1-B25A-F5FE627ED95E}");
    02102
    02103     InitializeObjectAttributes(&objectAttributes,
    02104                                &unicodeName,
    02105                                OBJ_CASE_INSENSITIVE,
    02106                                currentControlSetHandle,
    02107                                (PSECURITY_DESCRIPTOR)NULL
    02108                                );
    02109
    02110     status = ZwCreateKey(&instanceHandle,
    02111                          KEY_ALL_ACCESS,
    02112                          &objectAttributes,
    02113                          0,
    02114                          (PUNICODE_STRING)NULL,
    02115                          0,
    02116                          &disposition
    02117                          );
    02118
    02119     if (NT_SUCCESS(status)) {
    02120
    02121         //
    02122         // If the PnpInstanceID of the first netboot card matches the one
    02123         // for this device node, and the NET_CARD_INFO that the loader
    02124         // found is the same as the one we saved, then this is the same
    02125         // card with the same instance ID as before, so we don't need to
    02126         // do anything.
    02127         //
    02128
    02129         PiWstrToUnicodeString(&unicodeName, L"PnPInstanceID");
    02130         keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)dataBuffer;
    02131         RtlZeroMemory(dataBuffer, sizeof(dataBuffer));
    02132
    02133         status = ZwQueryValueKey(
    02134                      instanceHandle,
    02135                      &unicodeName,
    02136                      KeyValuePartialInformation,
    02137                      keyValue,
    02138                      sizeof(dataBuffer),
    02139                      &length);
    02140
    02141         //
    02142         // Check that it matches. We can init the string because we zeroed
    02143         // the dataBuffer before reading the key, so even if the
    02144         // registry value had no NULL at the end that is OK.
    02145         //
    02146
    02147         if ((NT_SUCCESS(status)) &&
    02148             (keyValue->Type == REG_SZ)) {
    02149
    02150             RtlInitUnicodeString(&pnpInstanceId, (PWSTR)(keyValue->Data));
    02151
    02152             if (RtlEqualUnicodeString(UnicodeDeviceInstance, &pnpInstanceId, TRUE)) {
    02153
    02154                 //
    02155                 // Instance ID matched, see if the NET_CARD_INFO matches.
    02156                 //
    02157
    02158                 PiWstrToUnicodeString(&unicodeName, L"NetCardInfo");
    02159                 RtlZeroMemory(dataBuffer, sizeof(dataBuffer));
    02160
    02161                 status = ZwQueryValueKey(
    02162                              remoteBootHandle,
    02163                              &unicodeName,
    02164                              KeyValuePartialInformation,
    02165                              keyValue,
    02166                              sizeof(dataBuffer),
    02167                              &length);
    02168
    02169                 if ((NT_SUCCESS(status)) &&
    02170                     (keyValue->Type == REG_BINARY) &&
    02171                     (keyValue->DataLength == sizeof(NET_CARD_INFO)) &&
    02172                     (memcmp(keyValue->Data, setupLoaderBlock->NetbootCardInfo, sizeof(NET_CARD_INFO)) == 0)) {
    02173
    02174                     //
    02175                     // Everything matched, so no need to do any setup.
    02176                     //
    02177
    02178                     status = STATUS_SUCCESS;
    02179                     goto cleanup;
    02180
    02181                 }
    02182             }
    02183         }
    02184     }
    02185
    02186
    02187     //
    02188     // We come through here if the saved registry data was missing or
    02189     // not correct. Write all the relevant values to the registry.
    02190     //
    02191
    02192
    02193     //
    02194     // Service name is in the loader block.
    02195     //
    02196
    02197     PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_SERVICE);
    02198     ZwSetValueKey(UniqueIdHandle,
    02199                   &unicodeName,
    02200                   TITLE_INDEX_VALUE,
    02201                   REG_SZ,
    02202                   setupLoaderBlock->NetbootCardServiceName,
    02203                   (wcslen(setupLoaderBlock->NetbootCardServiceName) + 1) * sizeof(WCHAR)
    02204                   );
    02205
    02206     //
    02207     // ClassGUID is the known net card GUID.
    02208     //
    02209
    02210     PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_CLASSGUID);
    02211     ZwSetValueKey(UniqueIdHandle,
    02212                   &unicodeName,
    02213                   TITLE_INDEX_VALUE,
    02214                   REG_SZ,
    02215                   L"{4D36E972-E325-11CE-BFC1-08002BE10318}",
    02216                   sizeof(L"{4D36E972-E325-11CE-BFC1-08002BE10318}")
    02217                   );
    02218
    02219     //
    02220     // Driver is the first net card.
    02221     //
    02222
    02223     PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_DRIVER);
    02224     ZwSetValueKey(UniqueIdHandle,
    02225                   &unicodeName,
    02226                   TITLE_INDEX_VALUE,
    02227                   REG_SZ,
    02228                   L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\0000",
    02229                   sizeof(L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\0000")
    02230                   );
    02231
    02232 #ifdef REMOTE_BOOT
    02233     //
    02234     // Identify this as the netboot card so the network class
    02235     // installer knows to assign the reserved GUID.
    02236     //
    02237
    02238     PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_CONFIG_FLAGS);
    02239
    02240     keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)dataBuffer;
    02241     RtlZeroMemory(dataBuffer, sizeof(dataBuffer));
    02242
    02243     status = ZwQueryValueKey(UniqueIdHandle,
    02244                              &unicodeName,
    02245                              KeyValuePartialInformation,
    02246                              keyValue,
    02247                              sizeof(dataBuffer),
    02248                              &length);
    02249
    02250     if ((NT_SUCCESS(status)) &&
    02251         (keyValue->Type == REG_DWORD)) {
    02252         //
    02253         // The ConfigFlags value exists in the registry
    02254         //
    02255         tmpValue = (*(PULONG)keyValue->Data) | CONFIGFLAG_NETBOOT_CARD;
    02256     } else {
    02257         tmpValue = CONFIGFLAG_NETBOOT_CARD;
    02258     }
    02259
    02260     ZwSetValueKey(UniqueIdHandle,
    02261                   &unicodeName,
    02262                   TITLE_INDEX_VALUE,
    02263                   REG_DWORD,
    02264                   &tmpValue,
    02265                   sizeof(tmpValue)
    02266                   );
    02267 #endif
    02268
    02269
    02270     //
    02271     // Open a handle for card parameters. We write RemoteBootCard plus
    02272     // whatever the BINL server told us to write.
    02273     //
    02274
    02275     status = IopOpenRegistryKey(&tmpHandle,
    02276                                 NULL,
    02277                                 &CmRegistryMachineSystemCurrentControlSetControlClass,
    02278                                 KEY_ALL_ACCESS,
    02279                                 FALSE
    02280                                 );
    02281
    02282     if (!NT_SUCCESS(status)) {
    02283         goto cleanup;
    02284     }
    02285
    02286     PiWstrToUnicodeString(&unicodeName, L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\0000");
    02287
    02288     status = IopOpenRegistryKey(&parametersHandle,
    02289                                 tmpHandle,
    02290                                 &unicodeName,
    02291                                 KEY_ALL_ACCESS,
    02292                                 FALSE
    02293                                 );
    02294
    02295     ZwClose(tmpHandle);
    02296
    02297     if (!NT_SUCCESS(status)) {
    02298         goto cleanup;
    02299     }
    02300
    02301     //
    02302     // We know that this is a different NIC, so remove all the old parameters.
    02303     //
    02304
    02305     keyValueBasic = (PKEY_VALUE_BASIC_INFORMATION)dataBuffer;
    02306     enumerateIndex = 0;
    02307
    02308     while (TRUE) {
    02309
    02310         RtlZeroMemory(dataBuffer, sizeof(dataBuffer));
    02311
    02312         status = ZwEnumerateValueKey(
    02313                     parametersHandle,
    02314                     enumerateIndex,
    02315                     KeyValueBasicInformation,
    02316                     keyValueBasic,
    02317                     sizeof(dataBuffer),
    02318                     &length
    02319                     );
    02320         if (status == STATUS_NO_MORE_ENTRIES) {
    02321             status = STATUS_SUCCESS;
    02322             break;
    02323         }
    02324
    02325         if (!NT_SUCCESS(status)) {
    02326             goto cleanup;
    02327         }
    02328
    02329         //
    02330         // We don't delete "NetCfgInstanceID", it won't change and
    02331         // its presence signifies to the net class installer that
    02332         // this is a replacement not a clean install.
    02333         //
    02334
    02335         if (_wcsicmp(keyValueBasic->Name, L"NetCfgInstanceID") != 0) {
    02336
    02337             RtlInitUnicodeString(&keyName, keyValueBasic->Name);
    02338             status = ZwDeleteValueKey(
    02339                         parametersHandle,
    02340                         &keyName
    02341                         );
    02342
    02343             if (!NT_SUCCESS(status)) {
    02344                 goto cleanup;
    02345             }
    02346
    02347         } else {
    02348
    02349             enumerateIndex = 1;   // leave NetCfgInstanceID at index 0
    02350         }
    02351
    02352     }
    02353
    02354     //
    02355     // Write a parameter called RemoteBootCard set to TRUE, this
    02356     // is primarily so NDIS can recognize this as such.
    02357     //
    02358
    02359     PiWstrToUnicodeString(&unicodeName, L"RemoteBootCard");
    02360     tmpValue = 1;
    02361     ZwSetValueKey(parametersHandle,
    02362                   &unicodeName,
    02363                   TITLE_INDEX_VALUE,
    02364                   REG_DWORD,
    02365                   &tmpValue,
    02366                   sizeof(tmpValue)
    02367                   );
    02368
    02369
    02370     //
    02371     // Store any other parameters sent from the server.
    02372     //
    02373
    02374     registryList = setupLoaderBlock->NetbootCardRegistry;
    02375
    02376     if (registryList != NULL) {
    02377
    02378         STRING aString;
    02379         UNICODE_STRING uString, uString2;
    02380
    02381         //
    02382         // The registry list is a series of name\0type\0value\0, with
    02383         // a final \0 at the end. It is in ANSI, not UNICODE.
    02384         //
    02385         // All values are stored under parametersHandle. Type is 1 for
    02386         // DWORD and 2 for SZ.
    02387         //
    02388
    02389         uString.Buffer = tempNameBuffer;
    02390         uString.MaximumLength = sizeof(tempNameBuffer);
    02391
    02392         while (*registryList != '\0') {
    02393
    02394             //
    02395             // First the name.
    02396             //
    02397
    02398             RtlInitString(&aString, registryList);
    02399             RtlAnsiStringToUnicodeString(&uString, &aString, FALSE);
    02400
    02401             //
    02402             // Now the type.
    02403             //
    02404
    02405             registryList += (strlen(registryList) + 1);
    02406
    02407             if (*registryList == '1') {
    02408
    02409                 //
    02410                 // A DWORD, parse it.
    02411                 //
    02412
    02413                 registryList += 2;   // skip "1\0"
    02414                 tmpValue = 0;
    02415
    02416                 while (*registryList != '\0') {
    02417                     tmpValue = (tmpValue * 10) + (*registryList - '0');
    02418                     ++registryList;
    02419                 }
    02420
    02421                 ZwSetValueKey(parametersHandle,
    02422                               &uString,
    02423                               TITLE_INDEX_VALUE,
    02424                               REG_DWORD,
    02425                               &tmpValue,
    02426                               sizeof(tmpValue)
    02427                               );
    02428
    02429                 registryList += (strlen(registryList) + 1);
    02430
    02431             } else if (*registryList == '2') {
    02432
    02433                 //
    02434                 // An SZ, convert to Unicode.
    02435                 //
    02436
    02437                 registryList += 2;   // skip "2\0"
    02438
    02439                 uString2.Buffer = tempValueBuffer;
    02440                 uString2.MaximumLength = sizeof(tempValueBuffer);
    02441                 RtlInitAnsiString(&aString, registryList);
    02442                 RtlAnsiStringToUnicodeString(&uString2, &aString, FALSE);
    02443
    02444                 ZwSetValueKey(parametersHandle,
    02445                               &uString,
    02446                               TITLE_INDEX_VALUE,
    02447                               REG_SZ,
    02448                               uString2.Buffer,
    02449                               uString2.Length + sizeof(WCHAR)
    02450                               );
    02451
    02452                 registryList += (strlen(registryList) + 1);
    02453
    02454             } else {
    02455
    02456                 //
    02457                 // Not "1" or "2", so stop processing registryList.
    02458                 //
    02459
    02460                 break;
    02461
    02462             }
    02463
    02464         }
    02465
    02466     }
    02467
    02468     //
    02469     // Save the NET_CARD_INFO so we can check it next time.
    02470     //
    02471
    02472     PiWstrToUnicodeString(&unicodeName, L"NetCardInfo");
    02473
    02474     ZwSetValueKey(remoteBootHandle,
    02475                   &unicodeName,
    02476                   TITLE_INDEX_VALUE,
    02477                   REG_BINARY,
    02478                   setupLoaderBlock->NetbootCardInfo,
    02479                   sizeof(NET_CARD_INFO)
    02480                   );
    02481
    02482
    02483     //
    02484     // Save the hardware ID, driver name, and service name,
    02485     // so the loader can read  those if the server is down
    02486     // on subsequent boots.
    02487     //
    02488
    02489     PiWstrToUnicodeString(&unicodeName, L"HardwareId");
    02490
    02491     ZwSetValueKey(remoteBootHandle,
    02492                   &unicodeName,
    02493                   TITLE_INDEX_VALUE,
    02494                   REG_SZ,
    02495                   setupLoaderBlock->NetbootCardHardwareId,
    02496                   (wcslen(setupLoaderBlock->NetbootCardHardwareId) + 1) * sizeof(WCHAR)
    02497                   );
    02498
    02499     PiWstrToUnicodeString(&unicodeName, L"DriverName");
    02500
    02501     ZwSetValueKey(remoteBootHandle,
    02502                   &unicodeName,
    02503                   TITLE_INDEX_VALUE,
    02504                   REG_SZ,
    02505                   setupLoaderBlock->NetbootCardDriverName,
    02506                   (wcslen(setupLoaderBlock->NetbootCardDriverName) + 1) * sizeof(WCHAR)
    02507                   );
    02508
    02509     PiWstrToUnicodeString(&unicodeName, L"ServiceName");
    02510
    02511     ZwSetValueKey(remoteBootHandle,
    02512                   &unicodeName,
    02513                   TITLE_INDEX_VALUE,
    02514                   REG_SZ,
    02515                   setupLoaderBlock->NetbootCardServiceName,
    02516                   (wcslen(setupLoaderBlock->NetbootCardServiceName) + 1) * sizeof(WCHAR)
    02517                   );
    02518
    02519     //
    02520     // Save the device instance, in case we need to ID the card later.
    02521     //
    02522
    02523     PiWstrToUnicodeString(&unicodeName, L"DeviceInstance");
    02524
    02525     ZwSetValueKey(remoteBootHandle,
    02526                   &unicodeName,
    02527                   TITLE_INDEX_VALUE,
    02528                   REG_SZ,
    02529                   UnicodeDeviceInstance->Buffer,
    02530                   UnicodeDeviceInstance->Length + sizeof(WCHAR)
    02531                   );
    02532
    02533     //
    02534     // Make sure we only pick one card to setup this way!
    02535     //
    02536
    02537     IopRemoteBootCardInitialized = TRUE;
    02538
    02539
    02540 cleanup:
    02541     if (instanceHandle != NULL) {
    02542         ZwClose(instanceHandle);
    02543     }
    02544     if (remoteBootHandle != NULL) {
    02545         ZwClose(remoteBootHandle);
    02546     }
    02547     if (parametersHandle != NULL) {
    02548         ZwClose(parametersHandle);
    02549     }
    02550     if (currentControlSetHandle != NULL) {
    02551         ZwClose(currentControlSetHandle);
    02552     }
    02553
    02554     return status;
    02555
    02556 }
    02557
    02558 #if defined(REMOTE_BOOT)
    02559 NTSTATUS
    02560 IopInitCsc(
    02561     IN PUCHAR CscPath
    02562     )
    02563 /*++
    02564
    02565 Routine Description:
    02566
    02567     This function informs the Rdr2 Client Side Cache where to put the CSC database.
    02568     If the database is not there or is corrupt then an error is returned.
    02569
    02570 Arguments:
    02571
    02572     CscPath - supplies the Nt path with no trailing backslash to the csc directory.
    02573
    02574 Return Value:
    02575
    02576     Status of the operation. STATUS_MEDIA_CHECK if database may have lost pin information.
    02577
    02578 --*/
    02579
    02580 {
    02581     NTSTATUS status;
    02582     IO_STATUS_BLOCK ioStatusBlock;
    02583     SHADOWINFO shadowInfo;
    02584     WIN32_FIND_DATAA * find32;
    02585
    02586     find32 = ExAllocatePoolWithTag(NonPagedPool, sizeof(WIN32_FIND_DATAA), 'bRoI');
    02587     if (find32 == NULL) {
    02588         return STATUS_INSUFFICIENT_RESOURCES;
    02589     }
    02590
    02591     RtlZeroMemory( find32, sizeof(WIN32_FIND_DATAA) );
    02592     find32->nFileSizeHigh = 0;
    02593     find32->nFileSizeLow = 0xccab348;
    02594     find32->dwReserved1 = 0x8000;
    02595     ASSERT(strlen(CscPath) < MAX_PATH);
    02596     strcpy( find32->cFileName, CscPath );
    02597
    02598     RtlZeroMemory( &shadowInfo, sizeof(shadowInfo) );
    02599     shadowInfo.uStatus = 0x0001; // SHADOW_SWITCH_SHADOWING
    02600     shadowInfo.uOp = 2; // SHADOW_SWITCH_ON
    02601     shadowInfo.lpFind32 = (WIN32_FIND_DATAW *)find32;
    02602
    02603     status = ZwDeviceIoControlFile(
    02604                 RdrHandle,
    02605                 NULL,
    02606                 NULL,
    02607                 NULL,
    02608                 &ioStatusBlock,
    02609                 IOCTL_SWITCHES,
    02610                 &shadowInfo,
    02611                 0,
    02612                 NULL,
    02613                 0
    02614                 );
    02615
    02616     if ( NT_SUCCESS(status) ) {
    02617         status = ioStatusBlock.Status;
    02618     }
    02619
    02620     if ( NT_SUCCESS(status) && shadowInfo.uOp ) {
    02621
    02622         //
    02623         // Database was recreated.
    02624         //
    02625
    02626         StartCsc = FLUSH_CSC;
    02627         IopSetFlushCSC(SET_FLUSH_CSC);
    02628     }
    02629
    02630     ExFreePool(find32);
    02631
    02632     return status;
    02633 }
    02634
    02635 NTSTATUS
    02636 IopResetCsc(
    02637     IN PUCHAR CscPath
    02638     )
    02639 /*++
    02640
    02641 Routine Description:
    02642
    02643     This function walks the servers directories creating CSC database entries for each
    02644     file and directory on the server. The entries are marked as SPARSE so that the local
    02645     copies of all files are discarded.
    02646
    02647     There is a potential problem when a file is in the CSC database and is deleted on the
    02648     server by an admin local to the server. Should this happen, go to the workstation with
    02649     the CSC and delete the file or directory.
    02650
    02651 Arguments:
    02652
    02653     CscPath - supplies the Nt path with no trailing backslash to the csc directory.
    02654
    02655 Return Value:
    02656
    02657     Status of the operation.
    02658
    02659 --*/
    02660
    02661 {
    02662     NTSTATUS status;
    02663     UNICODE_STRING root;
    02664     HSHADOW rootHandle;
    02665
    02666     PUCHAR nameBuffer;
    02667     ULONG nameBufferLength;
    02668     ULONG length;
    02669     HANDLE handle;
    02670     UNICODE_STRING string;
    02671     OBJECT_ATTRIBUTES objectAttributes;
    02672     PKEY_VALUE_PARTIAL_INFORMATION keyValue;
    02673
    02674     KdPrint(( "IopResetCsc Start\n" ));
    02675
    02676 #if 0
    02677    //  We don't think we want to re-initialize the database since this will
    02678     //  delete the information for user pinned files. If this functionality
    02679     //  is required then CSC probably needs to implement it for all CSC machines.
    02680
    02681     IO_STATUS_BLOCK ioStatusBlock;
    02682     SHADOWINFO shadowInfo;
    02683     WIN32_FIND_DATAA   sFind32;
    02684
    02685     memset(&shadowInfo, 0, sizeof(SHADOWINFO));
    02686     memset(&sFind32, 0, sizeof(sFind32));
    02687     sFind32.nFileSizeHigh = 0;
    02688     sFind32.nFileSizeLow = 0xccab348;
    02689     sFind32.dwReserved1 = 0x8000;
    02690
    02691     ASSERT(strlen(CscPath) < MAX_PATH);
    02692     strcpy(sFind32.cFileName, CscPath);
    02693
    02694     shadowInfo.uOp = 9; // SHADOW_REINIT_DATABASE;
    02695     shadowInfo.lpFind32 = (WIN32_FIND_DATAW *)&sFind32;
    02696
    02697     status = ZwDeviceIoControlFile(
    02698                 RdrHandle,
    02699                 NULL,
    02700                 NULL,
    02701                 NULL,
    02702                 &ioStatusBlock,
    02703                 IOCTL_DO_SHADOW_MAINTENANCE,
    02704                 &shadowInfo,
    02705                 0,
    02706                 NULL,
    02707                 0
    02708                 );
    02709
    02710     if ( NT_SUCCESS(status) ) {
    02711         status = ioStatusBlock.Status;
    02712     }
    02713
    02714     if ( !NT_SUCCESS(status) ) {
    02715         return status;
    02716     }
    02717
    02718 #endif
    02719
    02720     RtlInitUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control" );
    02721     InitializeObjectAttributes(
    02722         &objectAttributes,
    02723         &string,
    02724         OBJ_CASE_INSENSITIVE,
    02725         NULL,
    02726         NULL
    02727         );
    02728
    02729     status = ZwOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
    02730     if ( !NT_SUCCESS(status) ) {
    02731         KdPrint(( "IopResetCsc: Unable to open Control key: %x\n", status ));
    02732         return status;
    02733     }
    02734
    02735     if ( !ExpInTextModeSetup ) {
    02736         RtlInitUnicodeString( &string, L"RemoteBootRoot" );
    02737     } else {
    02738         RtlInitUnicodeString( &string, L"RemoteBootMachineDirectory" );
    02739     }
    02740
    02741     nameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + (128 * sizeof(WCHAR));
    02742     nameBuffer = ExAllocatePoolWithTag(NonPagedPool, nameBufferLength, 'bRoI');
    02743     if (nameBuffer == NULL) {
    02744         KdPrint(( "IopResetCsc: Unable to allocate nameBuffer\n"));
    02745         return STATUS_INSUFFICIENT_RESOURCES;
    02746     }
    02747
    02748     keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)nameBuffer;
    02749     RtlZeroMemory(nameBuffer, nameBufferLength);
    02750
    02751     status = ZwQueryValueKey(
    02752                  handle,
    02753                  &string,
    02754                  KeyValuePartialInformation,
    02755                  keyValue,
    02756                  nameBufferLength,
    02757                  &length);
    02758
    02759     ZwClose(handle);
    02760
    02761     if ( !NT_SUCCESS(status) ) {
    02762         KdPrint(( "IopResetCsc: Unable to read RemoteBootRoot value: %x\n", status ));
    02763         KdPrint(( "IopResetCsc: returning: %x\n", status ));
    02764         ExFreePool(nameBuffer);
    02765         return status;
    02766     }
    02767     RtlInitUnicodeString(&root, (PWSTR)keyValue->Data);
    02768     status = IopMarkRoot( &root, &rootHandle );
    02769     if (NT_SUCCESS(status)) {
    02770         status = IopWalkDirectoryTree( &root, rootHandle );
    02771     }
    02772
    02773     KdPrint(( "IopResetCsc: returning: %x\n", status ));
    02774
    02775     ExFreePool(nameBuffer);
    02776     return status;
    02777 }
    02778
    02779 PWSTR
    02780 IopBreakPath(
    02781     IN PWSTR* Path
    02782     )
    02783
    02784 /*++
    02785
    02786 Routine Description:
    02787
    02788     Break Path by skipping any leading backslashes, skip over filename and then
    02789     null out the nextbackslash or null.
    02790
    02791     NOTE the Path must not end in a backslash.
    02792
    02793
    02794 Arguments:
    02795
    02796     Path - Supplies the start of the next token. On return supplies the terminator
    02797     of the current token or NULL if we return the last element in the Path.
    02798
    02799 Return Value:
    02800
    02801     Start of the current token skipping any leading backslashes.
    02802
    02803 --*/
    02804 {
    02805     PWSTR start = *Path;
    02806
    02807     //  skip leading backslashes
    02808     while (*start == L'\\') {
    02809         start++;
    02810     }
    02811
    02812     //  Scan along token to find the terminator.
    02813
    02814     *Path = start;
    02815     while ((**Path != L'\\') && (**Path) ) {
    02816         (*Path)++;
    02817     }
    02818
    02819     if (**Path) {
    02820         //  Found backslash, NULL terminate token
    02821         **Path = L'\0';
    02822     } else {
    02823         *Path = NULL;    //  Flag end of token string.
    02824     }
    02825
    02826     return start;
    02827 }
    02828
    02829 NTSTATUS
    02830 IopMarkRoot(
    02831     IN PUNICODE_STRING Root,
    02832     OUT PHSHADOW RootHandle
    02833     )
    02834
    02835 /*++
    02836
    02837 Routine Description:
    02838
    02839     Tells CSC to pin all files created beneath the Root.
    02840
    02841     RootHandle - Supplies where to put the CSC handle corresponding to Root.
    02842
    02843 Arguments:
    02844
    02845     Root - Supplies the NT fully qualified name to the root. e.g.:
    02846             L"\Device\LanmanRedirector\colinw3\remoteboot\images\cwcompaq"
    02847
    02848 Return Value:
    02849
    02850     NTSTATUS - status of the operation.
    02851
    02852 --*/
    02853
    02854 {
    02855
    02856     NTSTATUS Status;
    02857     PWSTR  current, next;
    02858     HSHADOW hDir=0;
    02859     HSHADOW hShadow;
    02860     BOOLEAN first = TRUE;
    02861     BOOLEAN done;
    02862
    02863     PWIN32_FIND_DATAW sFind32;
    02864     SHADOWINFO sSI;
    02865
    02866     sFind32 = ExAllocatePoolWithTag(NonPagedPool, sizeof(WIN32_FIND_DATAW), 'bRoI');
    02867     if (sFind32 == NULL) {
    02868         return STATUS_INSUFFICIENT_RESOURCES;
    02869     }
    02870
    02871     //  Walk the CSC datastructures down to the Root directory
    02872
    02873
    02874     if (Root->Length >= (MAX_PATH * sizeof(WCHAR))) {
    02875         //  Simplifies some checking filling in FIND32 structures later.
    02876         KdPrint(("IopMarkRoot: %ws is invalid\n", Root->Buffer));
    02877         Status = STATUS_INVALID_PARAMETER;
    02878         goto cleanup;
    02879     }
    02880
    02881     //
    02882     //  Process the server component of the name. This is automatically in the
    02883     //  database, magically created by CSC.
    02884     //
    02885
    02886     next = Root->Buffer + (sizeof(L"\\Device\\LanmanRedirector")/sizeof(WCHAR));;
    02887     current = IopBreakPath(&next);
    02888
    02889     RtlZeroMemory(sFind32, sizeof(WIN32_FIND_DATAW));
    02890     sFind32->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
    02891     //  Build \\Server\Share
    02892     wcscpy(sFind32->cFileName, L"\\\\");
    02893     wcscat(sFind32->cFileName, current);
    02894
    02895     //  Restore separator that IopBreakPath removed
    02896     if (next) {
    02897         *next = L'\\';
    02898     } else {
    02899         Status = STATUS_INVALID_PARAMETER;
    02900         goto cleanup;
    02901     }
    02902     current = IopBreakPath(&next);
    02903
    02904     wcscat(sFind32->cFileName, L"\\");
    02905     wcscat(sFind32->cFileName, current);
    02906
    02907     Status = IopGetShadowExW(hDir, sFind32, &sSI);
    02908     if (!NT_SUCCESS(Status)) {
    02909         KdPrint(("IopMarkRoot: IopGetShadowExW (%ws) failed %lx\n", sFind32->cFileName, Status));
    02910         goto cleanup;
    02911     }
    02912
    02913     if (!sSI.hShadow) {
    02914         //
    02915         //  Directory is not already known to CSC. Make it so.
    02916         //
    02917         Status = IopCreateShadowW( hDir, sFind32, SHADOW_SPARSE, &hShadow );
    02918
    02919         if (!NT_SUCCESS(Status)) {
    02920             KdPrint(("IopMarkRoot: IopCreateShadowW (%ws) failed %lx\n", sFind32->cFileName, Status));
    02921             goto cleanup;
    02922         }
    02923     } else {
    02924         hShadow = sSI.hShadow;
    02925     }
    02926
    02927     //  Pinning the share means that the files are available without a LAN connection.
    02928     Status = IopAddHintFromInode(
    02929                 hDir,
    02930                 hShadow,
    02931                 &sSI.ulHintPri,
    02932                 &sSI.ulHintFlags,
    02933                 FLAG_CSC_HINT_PIN_SYSTEM);
    02934
    02935 #if DBG
    02936     if (Status != STATUS_PENDING) {
    02937         if (DebugReset) KdPrint(( "IopAddHintFromInode: modified hint flags for %ws\n", next ));
    02938     }
    02939 #endif
    02940
    02941     //  Restore separator that IopBreakPath removed
    02942     if (next) {
    02943         *next = L'\\';
    02944     } else {
    02945         Status = STATUS_INVALID_PARAMETER;
    02946         goto cleanup;
    02947     }
    02948
    02949     do {
    02950         current = IopBreakPath(&next);
    02951
    02952         RtlZeroMemory(sFind32, sizeof(WIN32_FIND_DATAW));
    02953         sFind32->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
    02954         wcscpy(sFind32->cFileName, current);
    02955
    02956         hDir = hShadow;
    02957
    02958         Status = IopGetShadowExW(hDir, sFind32, &sSI);
    02959         if (!NT_SUCCESS(Status)) {
    02960             KdPrint(("IopMarkRoot: IopGetShadowExW (%ws) failed %lx\n", sFind32->cFileName, Status));
    02961             goto cleanup;
    02962         }
    02963
    02964
    02965         if (!sSI.hShadow) {
    02966             //
    02967             //  Directory is not already known to CSC. Make it so.
    02968             //
    02969             Status = IopCreateShadowW( hDir, sFind32, SHADOW_SPARSE, &hShadow );
    02970
    02971             if (!NT_SUCCESS(Status)) {
    02972                 KdPrint(("IopMarkRoot: IopCreateShadowW (%ws) failed %lx\n", sFind32->cFileName, Status));
    02973                 goto cleanup;
    02974             }
    02975
    02976         } else {
    02977             hShadow = sSI.hShadow;
    02978         }
    02979
    02980         if (next) {
    02981
    02982             //  Pinning the share means that the files are available without a LAN connection.
    02983             Status = IopAddHintFromInode(
    02984                         hDir,
    02985                         hShadow,
    02986                         &sSI.ulHintPri,
    02987                         &sSI.ulHintFlags,
    02988                         FLAG_CSC_HINT_PIN_SYSTEM);
    02989
    02990 #if DBG
    02991             if (Status != STATUS_PENDING) {
    02992                 if (DebugReset) KdPrint(( "IopAddHintFromInode: modified hint flags for %ws\n", next ));
    02993             }
    02994 #endif
    02995
    02996             //  Restore separator that IopBreakPath removed
    02997             *next = L'\\';
    02998
    02999         } else {
    03000
    03001             //
    03002             //  WE HAVE FOUND THE ROOT. MARK IT
    03003             //
    03004             Status = IopAddHintFromInode(
    03005                         hDir,
    03006                         hShadow,
    03007                         &sSI.ulHintPri,
    03008                         &sSI.ulHintFlags,
    03009                         (FLAG_CSC_HINT_PIN_SYSTEM | FLAG_CSC_HINT_PIN_INHERIT_SYSTEM));
    03010
    03011 #if DBG
    03012             if (Status != STATUS_PENDING) {
    03013                 if (DebugReset) KdPrint(( "IopAddHintFromInode: modified hint flags for %ws\n", next ));
    03014             }
    03015 #endif
    03016
    03017             *RootHandle = hShadow;
    03018
    03019             break;
    03020         }
    03021
    03022     } while ( TRUE );
    03023
    03024 cleanup:
    03025
    03026     ExFreePool(sFind32);
    03027
    03028     return Status;
    03029 }
    03030
    03031 VOID
    03032 IopSetFlushCSC(
    03033     IN CSC_CONTROL Command
    03034     )
    03035 /*++
    03036
    03037 Routine Description:
    03038
    03039     Accesses the registry key that controls when to walk the server directory,
    03040     discard all local copies of files and repin.
    03041
    03042 Arguments:
    03043
    03044     Command - Supplies the intentions of the caller.
    03045
    03046 Return Value:
    03047
    03048     TRUE if repin is required.
    03049
    03050 --*/
    03051
    03052 {
    03053
    03054     NTSTATUS status;
    03055     HANDLE handle;
    03056     OBJECT_ATTRIBUTES objectAttributes;
    03057     UNICODE_STRING string;
    03058     DWORD dword = Command;
    03059
    03060     PKEY_VALUE_PARTIAL_INFORMATION keyValue;
    03061     UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(DWORD)];
    03062     ULONG length;
    03063
    03064     RtlInitUnicodeString( &string, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control" );
    03065
    03066     InitializeObjectAttributes(
    03067         &objectAttributes,
    03068         &string,
    03069         OBJ_CASE_INSENSITIVE,
    03070         NULL,
    03071         NULL
    03072         );
    03073
    03074     status = ZwOpenKey( &handle, KEY_ALL_ACCESS, &objectAttributes );
    03075     if ( !NT_SUCCESS(status) ) {
    03076         return;
    03077     }
    03078
    03079     RtlInitUnicodeString( &string, L"ControlCSC" );
    03080
    03081     if (Command == READ_CSC) {
    03082
    03083         keyValue = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
    03084         status = ZwQueryValueKey(
    03085                      handle,
    03086                      &string,
    03087                      KeyValuePartialInformation,
    03088                      keyValue,
    03089                      sizeof(buffer),
    03090                      &length);
    03091
    03092         dword = *((DWORD *)(&keyValue->Data[0]));
    03093
    03094         if (NT_SUCCESS(status) && (dword == SET_FLUSH_CSC)) {
    03095             StartCsc = FLUSH_CSC;
    03096         }
    03097
    03098     } else {
    03099         status = ZwSetValueKey(
    03100                     handle,
    03101                     &string,
    03102                     0,
    03103                     REG_DWORD,
    03104                     &dword,
    03105                     sizeof(DWORD)
    03106                     );
    03107         if ( !NT_SUCCESS(status) ) {
    03108             KdPrint(( "IopSetFlushCSC: Unable to set ControlCSC value: %x\n", status ));
    03109         }
    03110     }
    03111
    03112     ZwClose( handle );
    03113
    03114     return;
    03115 }
    03116
    03117 NTSTATUS
    03118 IopWalkDirectoryHelper(
    03119     IN PUNICODE_STRING Directory,
    03120     IN HSHADOW CSCHandle,
    03121     IN PUCHAR Buffer,
    03122     IN ULONG BufferSize
    03123     )
    03124
    03125 /*++
    03126
    03127 Routine Description:
    03128
    03129     This is a helper function for IopWalkDirectoryTree. Each file found is
    03130     pinned. Each directory is added to the list for later processing.
    03131
    03132 Arguments:
    03133
    03134     Directory - Supplies the NT Path to the directory to walk.
    03135
    03136     CSCHandle - Supplies the handle passed to CSC that describes
    03137                 the Directory when pinning individual files.
    03138
    03139     Buffer    - A scratch buffer to use.
    03140
    03141     BufferSize - The length of Buffer.
    03142
    03143 Return Value:
    03144
    03145     NTSTATUS - status of the operation.
    03146
    03147 --*/
    03148
    03149 {
    03150
    03151     NTSTATUS Status;
    03152
    03153     HANDLE FileHandle;
    03154     OBJECT_ATTRIBUTES ObjectAttributes;
    03155     IO_STATUS_BLOCK IoStatus;
    03156     PUCHAR CopyAclBuffer;
    03157
    03158     NTSTATUS NtStatus;
    03159
    03160     PFILE_BOTH_DIR_INFORMATION FileInfo;
    03161     ULONG i;
    03162     PWIN32_FIND_DATAW sFind32;
    03163
    03164     PWCHAR SkipNames[] = {L".",
    03165                             L"..",
    03166                             L"pagefile.sys",
    03167                             L"csc",
    03168                             L"RECYCLER",
    03169                             L"TEMP",
    03170                             L"TMP",
    03171                             L""};
    03172     BOOLEAN skip;
    03173
    03174
    03175     sFind32 = ExAllocatePoolWithTag(NonPagedPool, sizeof(WIN32_FIND_DATAW), 'bRoI');
    03176     if (sFind32 == NULL) {
    03177         return STATUS_INSUFFICIENT_RESOURCES;
    03178     }
    03179
    03180     CopyAclBuffer = ExAllocatePoolWithTag(NonPagedPool, 512, 'bRoI');
    03181     if (CopyAclBuffer == NULL) {
    03182         ExFreePool(sFind32);
    03183         return STATUS_INSUFFICIENT_RESOURCES;
    03184     }
    03185
    03186     //
    03187     //  Open the file for list directory access
    03188     //
    03189
    03190     InitializeObjectAttributes(
    03191         &ObjectAttributes,
    03192         Directory,
    03193         OBJ_CASE_INSENSITIVE,
    03194         NULL,
    03195         NULL
    03196         );
    03197
    03198     if (!NT_SUCCESS(Status = ZwOpenFile( &FileHandle,
    03199                                FILE_LIST_DIRECTORY | SYNCHRONIZE,
    03200                                &ObjectAttributes,
    03201                                &IoStatus,
    03202                                FILE_SHARE_READ,
    03203                                FILE_DIRECTORY_FILE ))) {
    03204         goto cleanup;
    03205     }
    03206
    03207     //
    03208     //  Do the directory loop
    03209     //
    03210
    03211     for (NtStatus = ZwQueryDirectoryFile( FileHandle,
    03212                                           (HANDLE)NULL,
    03213                                           (PIO_APC_ROUTINE)NULL,
    03214                                           (PVOID)NULL,
    03215                                           &IoStatus,
    03216                                           Buffer,
    03217                                           BufferSize,
    03218                                           FileBothDirectoryInformation,
    03219                                           FALSE,
    03220                                           (PUNICODE_STRING)NULL,
    03221                                           TRUE);
    03222          NT_SUCCESS(NtStatus);
    03223          NtStatus = ZwQueryDirectoryFile( FileHandle,
    03224                                           (HANDLE)NULL,
    03225                                           (PIO_APC_ROUTINE)NULL,
    03226                                           (PVOID)NULL,
    03227                                           &IoStatus,
    03228                                           Buffer,
    03229                                           BufferSize,
    03230                                           FileBothDirectoryInformation,
    03231                                           FALSE,
    03232                                           (PUNICODE_STRING)NULL,
    03233                                           FALSE) ) {
    03234
    03235         if (!NT_SUCCESS(Status = ZwWaitForSingleObject(FileHandle, TRUE, NULL))) {
    03236             goto cleanup;
    03237         }
    03238
    03239         //
    03240         //  Check the Irp for success
    03241         //
    03242
    03243         if (!NT_SUCCESS(IoStatus.Status)) {
    03244             break;
    03245         }
    03246
    03247         //
    03248         //  For every record in the buffer type out the directory information
    03249         //
    03250
    03251         //
    03252         //  Point to the first record in the buffer, we are guaranteed to have
    03253         //  one otherwise IoStatus would have been No More Files
    03254         //
    03255
    03256         FileInfo = (PFILE_BOTH_DIR_INFORMATION)&Buffer[0];
    03257
    03258         while (TRUE) {
    03259
    03260             {
    03261                 WCHAR Saved;
    03262                 DWORD Index;
    03263
    03264                 Saved = FileInfo->FileName[FileInfo->FileNameLength/2];
    03265                 FileInfo->FileName[FileInfo->FileNameLength/2] = 0;
    03266
    03267                 Index = 0;
    03268                 skip = FALSE;
    03269                 while (SkipNames[Index][0] != L'\0') {
    03270                     if (_wcsicmp( FileInfo->FileName,SkipNames[Index])) {
    03271                         Index++;
    03272                     } else {
    03273                         skip = TRUE;
    03274                         break;
    03275                     }
    03276                 }
    03277
    03278                 if (!skip) {
    03279                     UNICODE_STRING Entry;
    03280                     SHADOWINFO sSI;
    03281                     PDIRENT pDE;
    03282
    03283                     RtlInitUnicodeString(&Entry,NULL);
    03284
    03285                     if (FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
    03286                         //
    03287                         //  Allocate an entry in the directory list. We will process
    03288                         //  the directory at a later time.
    03289                         //
    03290                         UNICODE_STRING DirName;
    03291                         USHORT NewNameLength;
    03292
    03293                         RtlInitUnicodeString(&DirName, FileInfo->FileName);
    03294
    03295                         NewNameLength =
    03296                             (Directory->Length + DirName.Length + 1) * sizeof(WCHAR);
    03297
    03298                         pDE = ExAllocatePoolWithTag(PagedPool, sizeof(DIRENT) + NewNameLength, 'bRoI');
    03299
    03300                         if (pDE == NULL) {
    03301                             KdPrint(("Couldn't allocate space for directory\n"));
    03302                             KdPrint(("\\%ws\\%ws\n", Directory->Buffer, FileInfo->FileName));
    03303                             Status = STATUS_INSUFFICIENT_RESOURCES;
    03304                             goto cleanup;
    03305                         }
    03306
    03307                         InsertHeadList( &DirectoryList , &pDE->Next );
    03308                         pDE->Directory.Length=0;
    03309                         pDE->Directory.MaximumLength=NewNameLength;
    03310                         pDE->Directory.Buffer = &pDE->Name[0];
    03311                         RtlCopyUnicodeString(&pDE->Directory, Directory);
    03312                         RtlAppendUnicodeToString(&pDE->Directory, L"\\");
    03313                         pDE->LastToken = pDE->Directory.Buffer + (pDE->Directory.Length/sizeof(WCHAR));
    03314                         RtlAppendUnicodeStringToString(&pDE->Directory, &DirName);
    03315                     }
    03316
    03317                     RtlZeroMemory(sFind32, sizeof(WIN32_FIND_DATAW));
    03318                     wcscpy(sFind32->cFileName, FileInfo->FileName);
    03319
    03320                     Status = IopGetShadowExW(CSCHandle, sFind32, &sSI);
    03321                     if (!NT_SUCCESS(Status)) {
    03322                         KdPrint(( "IopGetShadowExW: returned: %x for %wZ\\%ws\n", Status, Directory, FileInfo->FileName ));
    03323                         goto cleanup;
    03324                     }
    03325
    03326                     if (!sSI.hShadow) {
    03327                         //  Need to create CSC database entry.
    03328                         sFind32->dwFileAttributes = FileInfo->FileAttributes;
    03329                         sFind32->ftCreationTime = *(LPFILETIME)&FileInfo->CreationTime;
    03330                         sFind32->ftLastAccessTime = *(LPFILETIME)&FileInfo->LastAccessTime;
    03331                         sFind32->ftLastWriteTime = *(LPFILETIME)&FileInfo->LastWriteTime;
    03332                         sFind32->nFileSizeLow = FileInfo->EndOfFile.LowPart;
    03333                         sFind32->nFileSizeHigh = FileInfo->EndOfFile.HighPart;
    03334                         memcpy(
    03335                             sFind32->cAlternateFileName,
    03336                             FileInfo->ShortName,
    03337                             FileInfo->ShortNameLength );
    03338                         Status = IopCreateShadowW( CSCHandle, sFind32, SHADOW_SPARSE, &sSI.hShadow);
    03339
    03340                         if (!NT_SUCCESS(Status)) {
    03341                             KdPrint(( "IopCreateShadowW: returned: %x for %wZ\\%ws\n", Status, Directory, FileInfo->FileName ));
    03342                             goto cleanup;
    03343                         }
    03344                         // Copy the ACL from the server.
    03345                         Status = IopCopyServerAcl(
    03346                                      FileHandle,         // parent directory
    03347                                      FileInfo->FileName, // this directory
    03348                                      sSI.hShadow,        // shadow handle
    03349                                      TRUE,               // it is a directory
    03350                                      CopyAclBuffer,      // scratch buffer
    03351                                      512);               // buffer size
    03352 #if 0
    03353                         //
    03354                         // We may get ACCESS_DENIED errors from dirs that
    03355                         // have been created on the server by hand, so don't
    03356                         // treat this as fatal.
    03357                         //
    03358                         if (!NT_SUCCESS(Status)) {
    03359                             goto cleanup;
    03360                         }
    03361 #endif
    03362                     }
    03363                     ASSERT(CSCHandle == sSI.hDir);
    03364
    03365                     Status = IopAddHintFromInode(
    03366                                 sSI.hDir,
    03367                                 sSI.hShadow,
    03368                                 &sSI.ulHintPri,
    03369                                 &sSI.ulHintFlags,
    03370                                 (FLAG_CSC_HINT_PIN_SYSTEM | FLAG_CSC_HINT_PIN_INHERIT_SYSTEM));
    03371
    03372 #if DBG
    03373                     if (Status != STATUS_PENDING) {
    03374                         if (DebugReset) KdPrint(( "IopAddHintFromInode: modified hint flags for %wZ\\%ws\n", Directory, FileInfo->FileName ));
    03375                     }
    03376 #endif
    03377                     if (!NT_SUCCESS(Status)) {
    03378                         KdPrint(( "IopAddHintFromInode: returned: %x for %wZ\\%ws\n", Status, Directory, FileInfo->FileName ));
    03379                         goto cleanup;
    03380                     }
    03381
    03382                     if (FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
    03383                         pDE->CSCHandle = sSI.hShadow;
    03384                     } else {
    03385                         if ((sSI.uStatus & SHADOW_SPARSE) == 0) {
    03386                             Status = IopSetShadowInfoW(
    03387                                         sSI.hDir,
    03388                                         sSI.hShadow,
    03389                                         SHADOW_SPARSE,
    03390                                         SHADOW_FLAGS_ASSIGN | SHADOW_FLAGS_TRUNCATE_DATA);
    03391 #if DBG
    03392                             if (DebugReset) KdPrint(( "IopSetShadowInfoW: truncated %wZ\\%ws\n", Directory, FileInfo->FileName ));
    03393 #endif
    03394                             if (!NT_SUCCESS(Status)) {
    03395                                 KdPrint(( "IopSetShadowInfoW: returned: %x for %wZ\\%ws\n", Status, Directory, FileInfo->FileName ));
    03396                                 goto cleanup;
    03397                             }
    03398                         }
    03399                     }
    03400                 }
    03401
    03402                 FileInfo->FileName[FileInfo->FileNameLength/2] = Saved;
    03403             }
    03404
    03405
    03406             //
    03407             //  Check if there is another record, if there isn't then we
    03408             //  simply get out of this loop
    03409             //
    03410
    03411             if (FileInfo->NextEntryOffset == 0) {
    03412                 break;
    03413             }
    03414
    03415             //
    03416             //  There is another record so advance FileInfo to the next
    03417             //  record
    03418             //
    03419
    03420
    03421             FileInfo = (PFILE_BOTH_DIR_INFORMATION)(((PUCHAR)FileInfo) + FileInfo->NextEntryOffset);
    03422
    03423         }
    03424     }
    03425
    03426     ZwClose( FileHandle );
    03427
    03428     Status = STATUS_SUCCESS;
    03429
    03430 cleanup:
    03431
    03432     ExFreePool(sFind32);
    03433     ExFreePool(CopyAclBuffer);
    03434
    03435     return Status;
    03436
    03437 } // IopWalkDirectoryHelper
    03438
    03439 NTSTATUS
    03440 IopWalkDirectoryTree(
    03441     IN PUNICODE_STRING Directory,
    03442     IN HSHADOW CSCHandle
    03443     )
    03444
    03445 /*++
    03446
    03447 Routine Description:
    03448
    03449 Arguments:
    03450
    03451     Directory - Supplies the NT Path to the directory to walk.
    03452
    03453     CSCHandle - Supplies the handle passed to CSC that describes
    03454                 the Directory when pinning individual files.
    03455
    03456 Return Value:
    03457
    03458     NTSTATUS - status of the operation.
    03459
    03460 --*/
    03461
    03462 {
    03463
    03464     PDIRENT Next;
    03465     NTSTATUS status;
    03466
    03467     #define BUFFERSIZE 1024
    03468     PUCHAR Buffer;
    03469
    03470
    03471     // Make 2 bytes larger so that when we null terminate filename we can't run off the end.
    03472     Buffer = ExAllocatePoolWithTag(NonPagedPool, BUFFERSIZE+2, 'bRoI');
    03473
    03474     if (Buffer == NULL) {
    03475         return STATUS_INSUFFICIENT_RESOURCES;
    03476     }
    03477
    03478     InitializeListHead(&DirectoryList);
    03479
    03480     status = IopWalkDirectoryHelper(Directory, CSCHandle, Buffer, BUFFERSIZE); // Process first level
    03481
    03482     if (!NT_SUCCESS(status)) {
    03483         while (!IsListEmpty(&DirectoryList)) {
    03484             Next = (PDIRENT)RemoveHeadList(&DirectoryList);
    03485             ExFreePool(Next);
    03486         }
    03487         ExFreePool(Buffer);
    03488         return status;
    03489     }
    03490
    03491     //
    03492     //  Each directory that WalkDirectory finds gets added to the list.
    03493     //  process the list until we have no more directories.
    03494     //
    03495
    03496     while (!IsListEmpty(&DirectoryList)) {
    03497
    03498         Next = (PDIRENT)RemoveHeadList(&DirectoryList);
    03499
    03500         status = IopWalkDirectoryHelper(&Next->Directory, Next->CSCHandle, Buffer, BUFFERSIZE);
    03501
    03502         ExFreePool(Next);
    03503
    03504         if (!NT_SUCCESS(status)) {
    03505             while (!IsListEmpty(&DirectoryList)) {
    03506                 Next = (PDIRENT)RemoveHeadList(&DirectoryList);
    03507                 ExFreePool(Next);
    03508             }
    03509             //  We will try to repin next reboot
    03510             ExFreePool(Buffer);
    03511             return status;
    03512         }
    03513     }
    03514
    03515     IopSetFlushCSC(SET_FLUSHED_CSC);
    03516     ExFreePool(Buffer);
    03517     return status;
    03518
    03519 } // IopWalkDirectoryTree
    03520
    03521 /*****************************************************************************
    03522  *      Given an hDir and filename, get SHADOWINFO if it exists
    03523  */
    03524 NTSTATUS
    03525 IopGetShadowExW(
    03526     HSHADOW hDir,
    03527     LPWIN32_FIND_DATAW lpFind32,
    03528     LPSHADOWINFO lpSI
    03529     )
    03530 {
    03531     IO_STATUS_BLOCK Iosb;
    03532     NTSTATUS status;
    03533
    03534     RtlZeroMemory((PUCHAR)lpSI, sizeof(SHADOWINFO));
    03535     lpSI->hDir = hDir;
    03536     lpSI->lpFind32 = lpFind32;
    03537
    03538     status = ZwDeviceIoControlFile(
    03539                 RdrHandle,
    03540                 NULL,
    03541                 NULL,               // APC routine
    03542                 NULL,               // APC Context
    03543                 &Iosb,
    03544                 IOCTL_GETSHADOW,    // IoControlCode
    03545                 (LPVOID)(lpSI),     // Buffer for data to the FS
    03546                 0,
    03547                 NULL,               // OutputBuffer for data from the FS
    03548                 0                   // OutputBuffer Length
    03549                 );
    03550
    03551     ASSERT( status != STATUS_PENDING );
    03552     if ( NT_SUCCESS(status) ) {
    03553         status = Iosb.Status;
    03554     }
    03555
    03556     return status;
    03557 }
    03558
    03559 /*****************************************************************************
    03560  *      Call down to the VxD to add a hint on the inode.
    03561  *  This ioctl does the right thing for user and system hints
    03562  *  If successful, there is an additional pincount on the inode entry
    03563  *  and the flags that are passed in are ORed with the original entry
    03564  */
    03565 NTSTATUS
    03566 IopAddHintFromInode(
    03567     HSHADOW  hDir,
    03568     HSHADOW  hShadow,
    03569     ULONG    *lpulHintPri,
    03570     ULONG    *lpulHintFlags,
    03571     ULONG    HintFlagsToSet
    03572     )
    03573 {
    03574
    03575     IO_STATUS_BLOCK Iosb;
    03576     NTSTATUS status;
    03577     SHADOWINFO      sSI;
    03578
    03579     HintFlagsToSet |= FLAG_CSC_HINT_CONSERVE_BANDWIDTH;
    03580
    03581     if ((*lpulHintFlags & HintFlagsToSet) != HintFlagsToSet) {
    03582
    03583         RtlZeroMemory(&sSI, sizeof(SHADOWINFO));
    03584         sSI.hDir = hDir;
    03585         sSI.hShadow = hShadow;
    03586         sSI.ulHintFlags = *lpulHintFlags | HintFlagsToSet;
    03587         sSI.uOp = SHADOW_ADDHINT_FROM_INODE;
    03588
    03589         status = ZwDeviceIoControlFile(
    03590                     RdrHandle,
    03591                     NULL,
    03592                     NULL,               // APC routine
    03593                     NULL,               // APC Context
    03594                     &Iosb,
    03595                     IOCTL_DO_SHADOW_MAINTENANCE,    // IoControlCode
    03596                     (LPVOID)(&sSI),     // Buffer for data to the FS
    03597                     0,
    03598                     NULL,               // OutputBuffer for data from the FS
    03599                     0                   // OutputBuffer Length
    03600                     );
    03601
    03602         ASSERT( status != STATUS_PENDING );
    03603         if ( NT_SUCCESS(status) ) {
    03604             status = Iosb.Status;
    03605         }
    03606
    03607         if (NT_SUCCESS(status)) {
    03608             *lpulHintFlags = sSI.ulHintFlags;
    03609             *lpulHintPri = sSI.ulHintPri;
    03610         }
    03611     } else {
    03612         status = STATUS_PENDING;
    03613     }
    03614
    03615     return status;
    03616 }
    03617
    03618 /*****************************************************************************
    03619  *  given an hDir and hShadow, set uStatus about the file.
    03620  *  Operation depends on uOp given.
    03621  */
    03622 NTSTATUS
    03623 IopSetShadowInfoW(
    03624     HSHADOW hDir,
    03625     HSHADOW hShadow,
    03626     ULONG uStatus,
    03627     ULONG uOp
    03628     )
    03629 {
    03630
    03631     IO_STATUS_BLOCK Iosb;
    03632     NTSTATUS status;
    03633     SHADOWINFO      sSI;
    03634
    03635     RtlZeroMemory(&sSI, sizeof(SHADOWINFO));
    03636     sSI.hDir = hDir;
    03637     sSI.hShadow = hShadow;
    03638     sSI.uStatus = uStatus;
    03639     sSI.uOp = uOp;
    03640
    03641     status = ZwDeviceIoControlFile(
    03642                 RdrHandle,
    03643                 NULL,
    03644                 NULL,               // APC routine
    03645                 NULL,               // APC Context
    03646                 &Iosb,
    03647                 IOCTL_SHADOW_SET_SHADOW_INFO,    // IoControlCode
    03648                 (LPVOID)(&sSI),     // Buffer for data to the FS
    03649                 0,
    03650                 NULL,               // OutputBuffer for data from the FS
    03651                 0                   // OutputBuffer Length
    03652                 );
    03653
    03654     ASSERT( status != STATUS_PENDING );
    03655     if ( NT_SUCCESS(status) ) {
    03656         status = Iosb.Status;
    03657     }
    03658
    03659     return status;
    03660 }
    03661
    03662 /*****************************************************************************
    03663  *      Call down to the VxD to add a file to the shadow.
    03664  *      lphShadow is filled in with the new HSHADOW.
    03665  *      Set uStatus as necessary (ie: SPARSE or whatever...)
    03666  */
    03667 NTSTATUS
    03668 IopCreateShadowW(
    03669     HSHADOW hDir,
    03670     LPWIN32_FIND_DATAW lpFind32,
    03671     ULONG uStatus,
    03672     PHSHADOW lphShadow
    03673     )
    03674 {
    03675     IO_STATUS_BLOCK Iosb;
    03676     NTSTATUS status;
    03677     SHADOWINFO sSI;
    03678
    03679     RtlZeroMemory(&sSI, sizeof(SHADOWINFO));
    03680     sSI.hDir = hDir;
    03681     sSI.uStatus = uStatus;
    03682     sSI.lpFind32 = lpFind32;
    03683
    03684
    03685     status = ZwDeviceIoControlFile(
    03686                 RdrHandle,
    03687                 NULL,
    03688                 NULL,               // APC routine
    03689                 NULL,               // APC Context
    03690                 &Iosb,
    03691                 IOCTL_SHADOW_CREATE,    // IoControlCode
    03692                 (LPVOID)(&sSI),     // Buffer for data to the FS
    03693                 0,
    03694                 NULL,               // OutputBuffer for data from the FS
    03695                 0                   // OutputBuffer Length
    03696                 );
    03697
    03698     ASSERT( status != STATUS_PENDING );
    03699     if ( NT_SUCCESS(status) ) {
    03700         status = Iosb.Status;
    03701     }
    03702
    03703     if (NT_SUCCESS(status)) {
    03704         *lphShadow = sSI.hShadow;
    03705     }
    03706
    03707     return status;
    03708 }
    03709
    03710 NTSTATUS
    03711 IopCopyServerAcl(
    03712     HANDLE ParentHandle,
    03713     PWCHAR FileName,
    03714     HSHADOW ShadowHandle,
    03715     BOOLEAN IsDirectory,
    03716     PUCHAR Buffer,
    03717     ULONG BufferSize
    03718     )
    03719
    03720 /*++
    03721
    03722 Routine Description:
    03723
    03724     This routines takes a file/directory on the server and a shadow
    03725     file handle and copies the security descriptor from the server
    03726     to the shadow file.
    03727
    03728 Arguments:
    03729
    03730     ParentHandle - The open handle to the parent of the file on the server.
    03731
    03732     FileName - The name of the file/directory on the server.
    03733
    03734     ShadowHandle - A CSC handle to the shadow file.
    03735
    03736     IsDirectory - Does FileName refer to a directory.
    03737
    03738     Buffer - A temporary buffer used to query security descriptors.
    03739
    03740     BufferSize - The number of bytes of Buffer.
    03741
    03742 Return Value:
    03743
    03744     NTSTATUS - status of the operation.
    03745
    03746 --*/
    03747
    03748 {
    03749     PWCHAR ShadowFileName = NULL;
    03750     UNICODE_STRING ShadowFileString;
    03751     UNICODE_STRING FileNameString;
    03752     OBJECT_ATTRIBUTES ObjectAttributes;
    03753     IO_STATUS_BLOCK IoStatusBlock;
    03754     COPYPARAMSW CopyParams;
    03755     HANDLE ShadowFileHandle;
    03756     HANDLE ServerFileHandle;
    03757     ULONG LengthNeeded;
    03758     PSECURITY_DESCRIPTOR SecurityDescriptor;
    03759     BOOLEAN AllocatedSecurityDescriptor = FALSE;
    03760     PACL Dacl;
    03761     BOOLEAN DaclPresent, DaclDefaulted;
    03762     NTSTATUS Status;
    03763
    03764     //
    03765     // Open the server file with "read contol" permission.
    03766     //
    03767
    03768     RtlInitUnicodeString(&FileNameString, FileName);
    03769
    03770     InitializeObjectAttributes(
    03771         &ObjectAttributes,
    03772         &FileNameString,
    03773         OBJ_CASE_INSENSITIVE,
    03774         ParentHandle,
    03775         NULL);
    03776
    03777     Status = ZwOpenFile(
    03778                  &ServerFileHandle,
    03779                  READ_CONTROL,
    03780                  &ObjectAttributes,
    03781                  &IoStatusBlock,
    03782                  FILE_SHARE_READ | FILE_SHARE_WRITE,
    03783                  0);
    03784
    03785     if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatusBlock.Status)) {
    03786         KdPrint(("IopCopyServerAcl: ZwOpenFile on %wZ failed %lx %lx\n", &FileNameString, Status, IoStatusBlock.Status));
    03787         if (NT_SUCCESS(Status)) {
    03788             Status = IoStatusBlock.Status;
    03789         }
    03790         goto cleanup;
    03791     }
    03792
    03793     //
    03794     // Now read the DACL from the server file.
    03795     //
    03796
    03797     Status = ZwQuerySecurityObject(
    03798                  ServerFileHandle,
    03799                  DACL_SECURITY_INFORMATION,
    03800                  Buffer,
    03801                  BufferSize,
    03802                  &LengthNeeded);
    03803
    03804     if (!NT_SUCCESS(Status)) {
    03805         if (Status == STATUS_BUFFER_TOO_SMALL) {
    03806
    03807             //
    03808             // Allocate a buffer and query again.
    03809             //
    03810
    03811             SecurityDescriptor = ExAllocatePoolWithTag(PagedPool, LengthNeeded, 'bRoI');
    03812             if (SecurityDescriptor == NULL) {
    03813                 Status = STATUS_INSUFFICIENT_RESOURCES;
    03814             } else {
    03815                 AllocatedSecurityDescriptor = TRUE;
    03816
    03817                 Status = ZwQuerySecurityObject(
    03818                              ServerFileHandle,
    03819                              DACL_SECURITY_INFORMATION,
    03820                              SecurityDescriptor,
    03821                              LengthNeeded,
    03822                              &LengthNeeded);
    03823
    03824             }
    03825         }
    03826         if (!NT_SUCCESS(Status)) {
    03827             KdPrint(("IopCopyServerAcl: Could not ZwQuerySecurityObject on %wZ %lx\n", &FileNameString, Status));
    03828             ZwClose(ServerFileHandle);
    03829             goto cleanup;
    03830         }
    03831
    03832     } else {
    03833
    03834         SecurityDescriptor = (PSECURITY_DESCRIPTOR)Buffer;
    03835     }
    03836
    03837     ZwClose(ServerFileHandle);   // don't need this any more.
    03838
    03839
    03840     //
    03841     // If there is no DACL, return.
    03842     //
    03843
    03844     Status = RtlGetDaclSecurityDescriptor(
    03845                  SecurityDescriptor,
    03846                  &DaclPresent,
    03847                  &Dacl,
    03848                  &DaclDefaulted);
    03849
    03850     if (!NT_SUCCESS(Status) || !DaclPresent || (Dacl == NULL)) {
    03851         // DbgPrint("IopCopyServerAcl: No DACL for %wZ\n", &FileNameString);
    03852         goto cleanup;
    03853     }
    03854
    03855     //
    03856     // Get the shadow file name.
    03857     //
    03858
    03859     ShadowFileName = ExAllocatePoolWithTag(NonPagedPool, sizeof(WCHAR) * MAX_PATH, 'bRoI');
    03860     if (ShadowFileName == NULL) {
    03861         KdPrint(("IopCopyServerAcl: Could not allocate ShadowFileName\n"));
    03862         goto cleanup;
    03863     }
    03864
    03865     Status = IopGetShadowPathW(
    03866                  ShadowHandle,
    03867                  ShadowFileName,
    03868                  &CopyParams);
    03869
    03870     if (!NT_SUCCESS(Status)) {
    03871         KdPrint(("IopCopyServerAcl: IopGetShadowPathW failed on %wZ %lx\n", &FileNameString, Status));
    03872         goto cleanup;
    03873     }
    03874
    03875     //
    03876     // Open the file with "write DACL" permission.
    03877     //
    03878
    03879     RtlInitUnicodeString(&ShadowFileString, ShadowFileName);
    03880
    03881     InitializeObjectAttributes(
    03882         &ObjectAttributes,
    03883         &ShadowFileString,
    03884         OBJ_CASE_INSENSITIVE,
    03885         NULL,
    03886         NULL);
    03887
    03888     Status = ZwOpenFile(
    03889                  &ShadowFileHandle,
    03890                  WRITE_DAC,
    03891                  &ObjectAttributes,
    03892                  &IoStatusBlock,
    03893                  FILE_SHARE_READ | FILE_SHARE_WRITE,
    03894                  0);
    03895
    03896     if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatusBlock.Status)) {
    03897         KdPrint(("IopCopyServerAcl: ZwOpenFile on %wZ (%wZ) failed %lx %lx\n", &FileNameString, &ShadowFileString, Status, IoStatusBlock.Status));
    03898         if (NT_SUCCESS(Status)) {
    03899             Status = IoStatusBlock.Status;
    03900         }
    03901         goto cleanup;
    03902     }
    03903
    03904     //
    03905     // Write the security descriptor to the shadow file.
    03906     //
    03907
    03908     Status = ZwSetSecurityObject(
    03909                  ShadowFileHandle,
    03910                  DACL_SECURITY_INFORMATION,
    03911                  SecurityDescriptor);
    03912
    03913     ZwClose(ShadowFileHandle);
    03914
    03915     if (!NT_SUCCESS(Status)) {
    03916         KdPrint(("IopCopyServerAcl: Could not ZwSetSecurityObject on %wZ %lx\n", &FileNameString, Status));
    03917     }
    03918
    03919 cleanup:
    03920
    03921     if (AllocatedSecurityDescriptor) {
    03922         ExFreePool(SecurityDescriptor);
    03923     }
    03924     if (ShadowFileName != NULL) {
    03925         ExFreePool(ShadowFileName);
    03926     }
    03927
    03928     return Status;
    03929
    03930 }
    03931
    03932
    03933 /*****************************************************************************
    03934  *      Given an hShadow, get the shadow path if it exists
    03935  */
    03936 NTSTATUS
    03937 IopGetShadowPathW(
    03938     HSHADOW hShadow,
    03939     PWCHAR lpLocalPath,
    03940     LPCOPYPARAMSW lpCP
    03941     )
    03942 {
    03943     IO_STATUS_BLOCK Iosb;
    03944     NTSTATUS status;
    03945
    03946     RtlZeroMemory((PUCHAR)lpCP, sizeof(COPYPARAMSW));
    03947     lpCP->hShadow = hShadow;
    03948     lpCP->lpLocalPath = lpLocalPath;
    03949     lpCP->uOp = 1;     // return full \Device\... name
    03950
    03951     status = ZwDeviceIoControlFile(
    03952                 RdrHandle,
    03953                 NULL,
    03954                 NULL,               // APC routine
    03955                 NULL,               // APC Context
    03956                 &Iosb,
    03957                 IOCTL_SHADOW_GET_UNC_PATH, // IoControlCode
    03958                 (LPVOID)(lpCP),     // Buffer for data to the FS
    03959                 0,
    03960                 NULL,               // OutputBuffer for data from the FS
    03961                 0                   // OutputBuffer Length
    03962                 );
    03963
    03964     ASSERT( status != STATUS_PENDING );
    03965     if ( NT_SUCCESS(status) ) {
    03966         status = Iosb.Status;
    03967     }
    03968
    03969     return status;
    03970 }
    03971 #endif // defined(REMOTE_BOOT)
    03972
    03973 NTSTATUS
    03974 IopWriteIpAddressToRegistry(
    03975         HANDLE handle,
    03976         PWCHAR regkey,
    03977         PUCHAR value
    03978         )
    03979 {
    03980     NTSTATUS status;
    03981     UNICODE_STRING string;
    03982     CHAR addressA[16];
    03983     WCHAR addressW[16];
    03984     STRING addressStringA;
    03985     UNICODE_STRING addressStringW;
    03986
    03987     RtlInitUnicodeString( &string, regkey );
    03988
    03989     sprintf(addressA, "%d.%d.%d.%d",
    03990              value[0],
    03991              value[1],
    03992              value[2],
    03993              value[3]);
    03994
    03995     RtlInitAnsiString(&addressStringA, addressA);
    03996     addressStringW.Buffer = addressW;
    03997     addressStringW.MaximumLength = sizeof(addressW);
    03998
    03999     RtlAnsiStringToUnicodeString(&addressStringW, &addressStringA, FALSE);
    04000
    04001     status = NtSetValueKey(
    04002                 handle,
    04003                 &string,
    04004                 0,
    04005                 REG_MULTI_SZ,
    04006                 addressW,
    04007                 addressStringW.Length + sizeof(WCHAR)
    04008                 );
    04009     if ( !NT_SUCCESS(status) ) {
    04010         KdPrint(( "IopWriteIpAddressToRegistry: Unable to set %ws value: %x\n", regkey, status ));
    04011     }
    04012     return status;
    04013 }
    04014
    04015
    04016 NTSTATUS
    04017 IopSetDefaultGateway(
    04018     IN ULONG GatewayAddress
    04019     )
    04020 /*++
    04021
    04022 Routine Description:
    04023
    04024     This function adds a default gateway entry from the router table.
    04025
    04026 Arguments:
    04027
    04028     GatewayAddress - Address of the default gateway.
    04029
    04030 Return Value:
    04031
    04032     Error Code.
    04033
    04034 --*/
    04035 {
    04036     NTSTATUS Status;
    04037
    04038     HANDLE Handle = NULL;
    04039     BYTE Context[CONTEXT_SIZE];
    04040     TDIObjectID ID;
    04041     DWORD Size;
    04042     IPSNMPInfo IPStats;
    04043     IPAddrEntry *AddrTable = NULL;
    04044     DWORD NumReturned;
    04045     DWORD Type;
    04046     DWORD i;
    04047     DWORD MatchIndex;
    04048     IPRouteEntry RouteEntry;
    04049     OBJECT_ATTRIBUTES objectAttributes;
    04050     UNICODE_STRING NameString;
    04051     IO_STATUS_BLOCK ioStatusBlock;
    04052
    04053     if (GatewayAddress == 0) {
    04054         return STATUS_SUCCESS;
    04055     }
    04056
    04057     RtlInitUnicodeString( &NameString, DD_TCP_DEVICE_NAME );
    04058
    04059     InitializeObjectAttributes(
    04060         &objectAttributes,
    04061         &NameString,
    04062         OBJ_CASE_INSENSITIVE,
    04063         NULL,
    04064         NULL
    04065         );
    04066
    04067     Status = NtCreateFile(
    04068                 &Handle,
    04069                 GENERIC_READ | GENERIC_WRITE,
    04070                 &objectAttributes,
    04071                 &ioStatusBlock,
    04072                 NULL,
    04073                 0,
    04074                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    04075                 FILE_OPEN,
    04076                 FILE_SYNCHRONOUS_IO_NONALERT,
    04077                 NULL,
    04078                 0
    04079                 );
    04080     if ( !NT_SUCCESS(Status) ) {
    04081         KdPrint(( "IopSetDefaultGateway: Unable to open TCPIP: %x\n", Status ));
    04082         return Status;
    04083     }
    04084
    04085     //
    04086     // Get the NetAddr info, to find an interface index for the gateway.
    04087     //
    04088
    04089     ID.toi_entity.tei_entity   = CL_NL_ENTITY;
    04090     ID.toi_entity.tei_instance = 0;
    04091     ID.toi_class               = INFO_CLASS_PROTOCOL;
    04092     ID.toi_type                = INFO_TYPE_PROVIDER;
    04093     ID.toi_id                  = IP_MIB_STATS_ID;
    04094
    04095     Size = sizeof(IPStats);
    04096     memset(&IPStats, 0x0, Size);
    04097     memset(Context, 0x0, CONTEXT_SIZE);
    04098
    04099     Status = IopTCPQueryInformationEx(
    04100                 Handle,
    04101                 &ID,
    04102                 &IPStats,
    04103                 &Size,
    04104                 Context);
    04105
    04106     if (!NT_SUCCESS(Status)) {
    04107         KdPrint(( "IopSetDefaultGateway: Unable to query TCPIP(1): %x\n", Status ));
    04108         goto Cleanup;
    04109     }
    04110
    04111     Size = IPStats.ipsi_numaddr * sizeof(IPAddrEntry);
    04112     AddrTable = ExAllocatePoolWithTag(PagedPool, Size, 'bRoI');
    04113
    04114     if (AddrTable == NULL) {
    04115         Status = STATUS_NO_MEMORY;
    04116         goto Cleanup;
    04117     }
    04118
    04119     ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
    04120     memset(Context, 0x0, CONTEXT_SIZE);
    04121
    04122     Status = IopTCPQueryInformationEx(
    04123                 Handle,
    04124                 &ID,
    04125                 AddrTable,
    04126                 &Size,
    04127                 Context);
    04128
    04129     if (!NT_SUCCESS(Status)) {
    04130         KdPrint(( "IopSetDefaultGateway: Unable to query TCPIP(2): %x\n", Status ));
    04131         goto Cleanup;
    04132     }
    04133
    04134     NumReturned = Size/sizeof(IPAddrEntry);
    04135
    04136     //
    04137     // We've got the address table. Loop through it. If we find an exact
    04138     // match for the gateway, then we're adding or deleting a direct route
    04139     // and we're done. Otherwise try to find a match on the subnet mask,
    04140     // and remember the first one we find.
    04141     //
    04142
    04143     Type = IRE_TYPE_INDIRECT;
    04144     for (i = 0, MatchIndex = 0xffff; i < NumReturned; i++) {
    04145
    04146         if( AddrTable[i].iae_addr == GatewayAddress ) {
    04147
    04148             //
    04149             // Found an exact match.
    04150             //
    04151
    04152             MatchIndex = i;
    04153             Type = IRE_TYPE_DIRECT;
    04154             break;
    04155         }
    04156
    04157         //
    04158         // The next hop is on the same subnet as this address. If
    04159         // we haven't already found a match, remember this one.
    04160         //
    04161
    04162         if ( (MatchIndex == 0xffff) &&
    04163              (AddrTable[i].iae_addr != 0) &&
    04164              (AddrTable[i].iae_mask != 0) &&
    04165              ((AddrTable[i].iae_addr & AddrTable[i].iae_mask) ==
    04166                 (GatewayAddress  & AddrTable[i].iae_mask)) ) {
    04167
    04168             MatchIndex = i;
    04169         }
    04170     }
    04171
    04172     //
    04173     // We've looked at all of the entries. See if we found a match.
    04174     //
    04175
    04176     if (MatchIndex == 0xffff) {
    04177         //
    04178         // Didn't find a match.
    04179         //
    04180
    04181         Status = STATUS_UNSUCCESSFUL;
    04182         KdPrint(( "IopSetDefaultGateway: Unable to find match for gateway\n" ));
    04183         goto Cleanup;
    04184     }
    04185
    04186     //
    04187     // We've found a match. Fill in the route entry, and call the
    04188     // Set API.
    04189     //
    04190
    04191     RouteEntry.ire_dest = DEFAULT_DEST;
    04192     RouteEntry.ire_index = AddrTable[MatchIndex].iae_index;
    04193     RouteEntry.ire_metric1 = DEFAULT_METRIC;
    04194     RouteEntry.ire_metric2 = (DWORD)(-1);
    04195     RouteEntry.ire_metric3 = (DWORD)(-1);
    04196     RouteEntry.ire_metric4 = (DWORD)(-1);
    04197     RouteEntry.ire_nexthop = GatewayAddress;
    04198     RouteEntry.ire_type = Type;
    04199     RouteEntry.ire_proto = IRE_PROTO_LOCAL;
    04200     RouteEntry.ire_age = 0;
    04201     RouteEntry.ire_mask = DEFAULT_DEST_MASK;
    04202     RouteEntry.ire_metric5 = (DWORD)(-1);
    04203     RouteEntry.ire_context = NULL;
    04204
    04205     Size = sizeof(RouteEntry);
    04206
    04207     ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
    04208
    04209     Status = IopTCPSetInformationEx(
    04210                 Handle,
    04211                 &ID,
    04212                 &RouteEntry,
    04213                 Size );
    04214
    04215     if (!NT_SUCCESS(Status)) {
    04216         KdPrint(( "IopSetDefaultGateway: Unable to set default gateway: %x\n", Status ));
    04217     }
    04218
    04219     NtClose(Handle);
    04220
    04221     Handle = NULL;
    04222
    04223 Cleanup:
    04224
    04225     if (Handle != NULL) {
    04226         NtClose(Handle);
    04227     }
    04228
    04229     if( AddrTable != NULL ) {
    04230         ExFreePool( AddrTable );
    04231     }
    04232
    04233     return Status;
    04234 }
    04235
    04236
    04237 __inline long
    04238 htonl(long x)
    04239 {
    04240         return((((x) >> 24) & 0x000000FFL) |
    04241            (((x) >>  8) & 0x0000FF00L) |
    04242            (((x) <<  8) & 0x00FF0000L) |
    04243            (((x) << 24) & 0xFF000000L));
    04244 }
    04245
    04246 NTSTATUS
    04247 IopCacheNetbiosNameForIpAddress(
    04248     IN PLOADER_PARAMETER_BLOCK LoaderBlock
    04249     )
    04250 /*++
    04251
    04252 Routine Description:
    04253
    04254     This function takes an IP address, and submits it to NetBt for name resolution.
    04255
    04256 Arguments:
    04257
    04258     IpAddress - Address to resolve
    04259
    04260 Return Value:
    04261
    04262     Error Code.
    04263
    04264 --*/
    04265 {
    04266     NTSTATUS Status;
    04267     HANDLE Handle = NULL;
    04268     BYTE Context[CONTEXT_SIZE];
    04269     DWORD Size;
    04270     OBJECT_ATTRIBUTES objectAttributes;
    04271     UNICODE_STRING NameString;
    04272     IO_STATUS_BLOCK ioStatusBlock;
    04273     tREMOTE_CACHE cacheInfo;
    04274     PCHAR serverName;
    04275     PCHAR endOfServerName;
    04276
    04277     //
    04278     // Open NetBT.
    04279     //
    04280
    04281     RtlInitUnicodeString(
    04282         &NameString,
    04283         L"\\Device\\NetBT_Tcpip_{54C7D140-09EF-11D1-B25A-F5FE627ED95E}"
    04284         );
    04285
    04286     InitializeObjectAttributes(
    04287         &objectAttributes,
    04288         &NameString,
    04289         OBJ_CASE_INSENSITIVE,
    04290         NULL,
    04291         NULL
    04292         );
    04293
    04294     Status = NtCreateFile(
    04295                 &Handle,
    04296                 GENERIC_READ | GENERIC_WRITE,
    04297                 &objectAttributes,
    04298                 &ioStatusBlock,
    04299                 NULL,
    04300                 0,
    04301                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    04302                 FILE_OPEN,
    04303                 FILE_SYNCHRONOUS_IO_NONALERT,
    04304                 NULL,
    04305                 0
    04306                 );
    04307     if ( !NT_SUCCESS(Status) ) {
    04308         KdPrint(( "IopCacheNetbiosNameForIpAddress: Unable to open NETBT: %x\n", Status ));
    04309         return Status;
    04310     }
    04311
    04312     //
    04313     // Get the server's name.
    04314     //
    04315     // If this is a remote boot setup boot, NtBootPathName is of the
    04316     // form <server><share>\setup<install-directory><platform>.
    04317     // If this is a normal remote boot, NtBootPathName is of the form
    04318     // <server><share>\images<machine>\winnt.
    04319     //
    04320     // Thus in either case, we need to isolate the first element of the
    04321     // path.
    04322     //
    04323
    04324     serverName = LoaderBlock->NtBootPathName;
    04325     if ( *serverName == '\\' ) {
    04326         serverName++;
    04327     }
    04328     endOfServerName = strchr( serverName, '\\' );
    04329     if ( endOfServerName == NULL ) {
    04330         endOfServerName = strchr( serverName, '\0' );
    04331     }
    04332
    04333     //
    04334     // Fill in the tREMOTE_CACHE structure.
    04335     //
    04336
    04337     memset(&cacheInfo, 0x0, sizeof(cacheInfo));
    04338
    04339     memset(cacheInfo.name, ' ', NETBIOS_NAMESIZE);
    04340     memcpy(cacheInfo.name, serverName, (ULONG)(endOfServerName - serverName));
    04341     cacheInfo.IpAddress = htonl(LoaderBlock->SetupLoaderBlock->ServerIpAddress);
    04342     cacheInfo.Ttl = MAXULONG;
    04343
    04344     //
    04345     // Submit the IOCTL.
    04346     //
    04347
    04348     Status = NtDeviceIoControlFile(
    04349                Handle,
    04350                NULL,
    04351                NULL,
    04352                NULL,
    04353                &ioStatusBlock,
    04354                IOCTL_NETBT_ADD_TO_REMOTE_TABLE,
    04355                &cacheInfo,
    04356                sizeof(cacheInfo),
    04357                Context,
    04358                sizeof(Context)
    04359                );
    04360
    04361     ASSERT( Status != STATUS_PENDING );
    04362     if ( NT_SUCCESS(Status) ) {
    04363         Status = ioStatusBlock.Status;
    04364     }
    04365
    04366     if ( !NT_SUCCESS(Status) ) {
    04367         KdPrint(( "IopCacheNetbiosNameForIpAddress: Adapter status failed: %x\n", Status ));
    04368     }
    04369
    04370     NtClose(Handle);
    04371
    04372     return Status;
    04373 }
    04374
    04375
    04376 NTSTATUS
    04377 IopTCPQueryInformationEx(
    04378     IN HANDLE                 TCPHandle,
    04379     IN TDIObjectID FAR       *ID,
    04380     OUT void FAR             *Buffer,
    04381     IN OUT DWORD FAR         *BufferSize,
    04382     IN OUT BYTE FAR          *Context
    04383     )
    04384 /*++
    04385
    04386 Routine Description:
    04387
    04388     This routine provides the interface to the TDI QueryInformationEx
    04389     facility of the TCP/IP stack on NT. Someday, this facility will be
    04390     part of TDI.
    04391
    04392 Arguments:
    04393
    04394     TCPHandle     - Open handle to the TCP driver
    04395     ID            - The TDI Object ID to query
    04396     Buffer        - Data buffer to contain the query results
    04397     BufferSize    - Pointer to the size of the results buffer. Filled in
    04398                     with the amount of results data on return.
    04399     Context       - Context value for the query. Should be zeroed for a
    04400                     new query. It will be filled with context
    04401                     information for linked enumeration queries.
    04402
    04403 Return Value:
    04404
    04405     An NTSTATUS value.
    04406
    04407 --*/
    04408
    04409 {
    04410     TCP_REQUEST_QUERY_INFORMATION_EX   queryBuffer;
    04411     DWORD                              queryBufferSize;
    04412     NTSTATUS                           status;
    04413     IO_STATUS_BLOCK                    ioStatusBlock;
    04414
    04415
    04416     if (TCPHandle == NULL) {
    04417         return(STATUS_INVALID_PARAMETER);
    04418     }
    04419
    04420     queryBufferSize = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
    04421     memcpy(&(queryBuffer.ID), ID, sizeof(TDIObjectID));
    04422     memcpy(&(queryBuffer.Context), Context, CONTEXT_SIZE);
    04423
    04424     status = NtDeviceIoControlFile(
    04425                  TCPHandle,                       // Driver handle
    04426                  NULL,                            // Event
    04427                  NULL,                            // APC Routine
    04428                  NULL,                            // APC context
    04429                  &ioStatusBlock,                  // Status block
    04430                  IOCTL_TCP_QUERY_INFORMATION_EX,  // Control code
    04431                  &queryBuffer,                    // Input buffer
    04432                  queryBufferSize,                 // Input buffer size
    04433                  Buffer,                          // Output buffer
    04434                  *BufferSize                      // Output buffer size
    04435                  );
    04436
    04437     ASSERT( status != STATUS_PENDING );
    04438     if ( NT_SUCCESS(status) ) {
    04439         status = ioStatusBlock.Status;
    04440     }
    04441
    04442     if (status == STATUS_SUCCESS) {
    04443         //
    04444         // Copy the return context to the caller's context buffer
    04445         //
    04446         memcpy(Context, &(queryBuffer.Context), CONTEXT_SIZE);
    04447         *BufferSize = (ULONG)ioStatusBlock.Information;
    04448         status = ioStatusBlock.Status;
    04449     } else {
    04450         *BufferSize = 0;
    04451     }
    04452
    04453     return(status);
    04454 }
    04455
    04456
    04457 NTSTATUS
    04458 IopTCPSetInformationEx(
    04459     IN HANDLE             TCPHandle,
    04460     IN TDIObjectID FAR   *ID,
    04461     IN void FAR          *Buffer,
    04462     IN DWORD FAR          BufferSize
    04463     )
    04464 /*++
    04465
    04466 Routine Description:
    04467
    04468     This routine provides the interface to the TDI SetInformationEx
    04469     facility of the TCP/IP stack on NT. Someday, this facility will be
    04470     part of TDI.
    04471
    04472 Arguments:
    04473
    04474     TCPHandle     - Open handle to the TCP driver
    04475     ID            - The TDI Object ID to set
    04476     Buffer        - Data buffer containing the information to be set
    04477     BufferSize    - The size of the set data buffer.
    04478
    04479 Return Value:
    04480
    04481     An NTSTATUS value.
    04482
    04483 --*/
    04484
    04485 {
    04486     PTCP_REQUEST_SET_INFORMATION_EX    setBuffer;
    04487     NTSTATUS                           status;
    04488     IO_STATUS_BLOCK                    ioStatusBlock;
    04489     DWORD                              setBufferSize;
    04490
    04491
    04492     if (TCPHandle == NULL) {
    04493         return(STATUS_INVALID_PARAMETER);
    04494     }
    04495
    04496     setBufferSize = FIELD_OFFSET(TCP_REQUEST_SET_INFORMATION_EX, Buffer) + BufferSize;
    04497
    04498     setBuffer = ExAllocatePoolWithTag(PagedPool, setBufferSize, 'bRoI');
    04499
    04500     if (setBuffer == NULL) {
    04501         return(STATUS_INSUFFICIENT_RESOURCES);
    04502     }
    04503
    04504     setBuffer->BufferSize = BufferSize;
    04505
    04506     memcpy(&(setBuffer->ID), ID, sizeof(TDIObjectID));
    04507
    04508     memcpy(&(setBuffer->Buffer[0]), Buffer, BufferSize);
    04509
    04510     status = NtDeviceIoControlFile(
    04511                  TCPHandle,                       // Driver handle
    04512                  NULL,                            // Event
    04513                  NULL,                            // APC Routine
    04514                  NULL,                            // APC context
    04515                  &ioStatusBlock,                  // Status block
    04516                  IOCTL_TCP_SET_INFORMATION_EX,    // Control code
    04517                  setBuffer,                       // Input buffer
    04518                  setBufferSize,                   // Input buffer size
    04519                  NULL,                            // Output buffer
    04520                  0                                // Output buffer size
    04521                  );
    04522
    04523     ASSERT( status != STATUS_PENDING );
    04524     if ( NT_SUCCESS(status) ) {
    04525         status = ioStatusBlock.Status;
    04526     }
    04527
    04528     ExFreePool(setBuffer);
    04529
    04530     return(status);
    04531 }
    04532
    04533 #if defined(REMOTE_BOOT)
    04534 VOID
    04535 IopGetHarddiskInfo(
    04536     OUT PWSTR NetHDCSCPartition
    04537     )
    04538 /*++
    04539
    04540 Routine Description:
    04541
    04542     This routine searches the each partition on each hard disk for
    04543     one which has the active bit set, returning the first one encountered.
    04544
    04545 Arguments:
    04546
    04547     LoaderBlock - The loader parameter block.
    04548
    04549     NetHDCSCPartition - Either an arcname or string of type \Device\HarddiskX\PartitionY.
    04550         Defaults to \Device\Harddisk0\Partition1
    04551
    04552 Return Value:
    04553
    04554     None
    04555
    04556 --*/
    04557
    04558 {
    04559     PARTITION_INFORMATION PartitionInfo;
    04560     FILE_FS_SIZE_INFORMATION SizeInfo;
    04561     PWSTR NameBuffer;
    04562     PWSTR DiskNameBuffer;
    04563     PWSTR NetHDBootPartition;
    04564     ULONG DiskNumber;
    04565     ULONG PartitionNumber;
    04566     ULONG DestPartitionNumber;
    04567     HANDLE Handle;
    04568     NTSTATUS Status;
    04569     IO_STATUS_BLOCK IoStatus;
    04570     OBJECT_ATTRIBUTES ObjectAttributes;
    04571     UNICODE_STRING UnicodeString;
    04572     LARGE_INTEGER LargestFreeSpace;
    04573     LARGE_INTEGER FreeSpace;
    04574
    04575     wcscpy(NetHDCSCPartition, L"\\Device\\Harddisk0\\Partition1");
    04576
    04577     NameBuffer = ExAllocatePoolWithTag(NonPagedPool, 80 * 3 * sizeof(WCHAR), 'bRoI');
    04578     if ( NameBuffer == NULL ) {
    04579         KdPrint(( "IopGetHarddiskInfo: unable to allocate buffer\n" ));
    04580         return;
    04581     }
    04582
    04583     DiskNameBuffer = NameBuffer + 80;
    04584     NetHDBootPartition = DiskNameBuffer + 80;
    04585
    04586     wcscpy(DiskNameBuffer, L"\\Device\\Harddisk0");
    04587     wcscpy(NetHDBootPartition, DiskNameBuffer);
    04588     wcscpy(NetHDBootPartition, L"\\Partition1");
    04589     wcscpy(NetHDCSCPartition, NetHDBootPartition);
    04590
    04591     //
    04592     // We find the first bootable harddisk-slash-partition and call that the boot partition.
    04593     //
    04594
    04595     DiskNumber = 0;
    04596     while (TRUE) {
    04597
    04598         //
    04599         // First check if there is any disk there at all by opening partition 0
    04600         //
    04601         PartitionNumber = 0;
    04602
    04603         swprintf(NameBuffer, L"\\Device\\Harddisk%d\\Partition%d", DiskNumber, PartitionNumber);
    04604
    04605         RtlInitUnicodeString(&UnicodeString, NameBuffer);
    04606
    04607         InitializeObjectAttributes(
    04608             &ObjectAttributes,
    04609             &UnicodeString,
    04610             OBJ_CASE_INSENSITIVE,
    04611             NULL,
    04612             NULL
    04613             );
    04614
    04615         Status = ZwCreateFile( &Handle,
    04616                                (ACCESS_MASK)FILE_GENERIC_READ,
    04617                                &ObjectAttributes,
    04618                                &IoStatus,
    04619                                NULL,
    04620                                FILE_ATTRIBUTE_NORMAL,
    04621                                FILE_SHARE_READ,
    04622                                FILE_OPEN,
    04623                                FILE_SYNCHRONOUS_IO_NONALERT,
    04624                                NULL,
    04625                                0
    04626                              );
    04627
    04628         if (!NT_SUCCESS(Status)) {
    04629             ExFreePool(NameBuffer);
    04630             return;
    04631         }
    04632
    04633         ZwClose(Handle);
    04634
    04635         //
    04636         // Now, for each partition, check if it is marked 'active'
    04637         //
    04638         while (TRUE) {
    04639
    04640             PartitionNumber++;
    04641
    04642             swprintf(NameBuffer, L"\\Device\\Harddisk%d\\Partition%d", DiskNumber, PartitionNumber);
    04643
    04644             RtlInitUnicodeString(&UnicodeString, NameBuffer);
    04645
    04646             InitializeObjectAttributes(
    04647                 &ObjectAttributes,
    04648                 &UnicodeString,
    04649                 OBJ_CASE_INSENSITIVE,
    04650                 NULL,
    04651                 NULL
    04652                 );
    04653
    04654
    04655             Status = ZwCreateFile( &Handle,
    04656                                    (ACCESS_MASK)FILE_GENERIC_READ,
    04657                                    &ObjectAttributes,
    04658                                    &IoStatus,
    04659                                    NULL,
    04660                                    FILE_ATTRIBUTE_NORMAL,
    04661                                    FILE_SHARE_READ,
    04662                                    FILE_OPEN,
    04663                                    FILE_SYNCHRONOUS_IO_NONALERT,
    04664                                    NULL,
    04665                                    0
    04666                                  );
    04667
    04668             if (!NT_SUCCESS(Status)) {
    04669                 break;
    04670             }
    04671
    04672             Status = ZwDeviceIoControlFile(Handle,
    04673                                            NULL,
    04674                                            NULL,
    04675                                            NULL,
    04676                                            &IoStatus,
    04677                                            IOCTL_DISK_GET_PARTITION_INFO,
    04678                                            NULL,
    04679                                            0,
    04680                                            &PartitionInfo,
    04681                                            sizeof(PARTITION_INFORMATION)
    04682                                           );
    04683
    04684             ZwClose(Handle);
    04685
    04686             if (!NT_SUCCESS(Status)) {
    04687                 break;
    04688             }
    04689
    04690             if (PartitionInfo.BootIndicator) {
    04691                 wcscpy(NetHDBootPartition, NameBuffer);
    04692                 swprintf(DiskNameBuffer, L"\\Device\\Harddisk%d", DiskNumber);
    04693                 goto FoundDisk;
    04694             }
    04695
    04696         }
    04697
    04698         DiskNumber++;
    04699     }
    04700
    04701     ASSERT(0); // We only exit the loop with a return (no boot disk found), or jump to the label
    04702
    04703 FoundDisk:
    04704
    04705     //
    04706     // Check each partition for the CSC directory, and find largest free space partition in
    04707     // case no CSC directory exists.
    04708     //
    04709
    04710     wcscpy(NetHDCSCPartition, NetHDBootPartition);
    04711
    04712     PartitionNumber = 0;
    04713     DestPartitionNumber = 0;
    04714     LargestFreeSpace = RtlConvertUlongToLargeInteger(0);
    04715
    04716     while (TRUE) {
    04717
    04718         PartitionNumber++;
    04719
    04720         //
    04721         // Check for CSC directory first
    04722         //
    04723         swprintf(NameBuffer,
    04724                  L"%ws\\Partition%d%ws",
    04725                  DiskNameBuffer,
    04726                  PartitionNumber,
    04727                  REMOTE_BOOT_IMIRROR_PATH_W REMOTE_BOOT_CSC_SUBDIR_W);
    04728
    04729         RtlInitUnicodeString(&UnicodeString, NameBuffer);
    04730
    04731         InitializeObjectAttributes(
    04732             &ObjectAttributes,
    04733             &UnicodeString,
    04734             OBJ_CASE_INSENSITIVE,
    04735             NULL,
    04736             NULL
    04737             );
    04738
    04739
    04740         Status = ZwOpenFile( &Handle,
    04741                              FILE_GENERIC_READ,
    04742                              &ObjectAttributes,
    04743                              &IoStatus,
    04744                              FILE_SHARE_READ,
    04745                              FILE_DIRECTORY_FILE
    04746                            );
    04747
    04748         if (NT_SUCCESS(Status)) {
    04749             ZwClose(Handle);
    04750             DestPartitionNumber = PartitionNumber;
    04751             break;
    04752         }
    04753
    04754         if (Status == STATUS_UNRECOGNIZED_VOLUME) {
    04755             //
    04756             // Skip this one
    04757             //
    04758             continue;
    04759         }
    04760
    04761         //
    04762         // Now get this partition's free space, if it is an NTFS partition.
    04763         //
    04764         swprintf(NameBuffer, L"%ws\\Partition%d", DiskNameBuffer, PartitionNumber);
    04765
    04766         RtlInitUnicodeString(&UnicodeString, NameBuffer);
    04767
    04768         InitializeObjectAttributes(
    04769             &ObjectAttributes,
    04770             &UnicodeString,
    04771             OBJ_CASE_INSENSITIVE,
    04772             NULL,
    04773             NULL
    04774             );
    04775
    04776         Status = ZwCreateFile( &Handle,
    04777                                FILE_GENERIC_READ,
    04778                                &ObjectAttributes,
    04779                                &IoStatus,
    04780                                NULL,
    04781                                FILE_ATTRIBUTE_NORMAL,
    04782                                FILE_SHARE_READ,
    04783                                FILE_OPEN,
    04784                                FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_FREE_SPACE_QUERY,
    04785                                NULL,
    04786                                0
    04787                              );
    04788
    04789         if (!NT_SUCCESS(Status)) {
    04790             break;
    04791         }
    04792
    04793         Status = ZwDeviceIoControlFile(Handle,
    04794                                        NULL,
    04795                                        NULL,
    04796                                        NULL,
    04797                                        &IoStatus,
    04798                                        IOCTL_DISK_GET_PARTITION_INFO,
    04799                                        NULL,
    04800                                        0,
    04801                                        &PartitionInfo,
    04802                                        sizeof(PARTITION_INFORMATION)
    04803                                       );
    04804
    04805         if (!NT_SUCCESS(Status) || (PartitionInfo.PartitionType != PARTITION_IFS)) {
    04806             ZwClose(Handle);
    04807             continue;
    04808         }
    04809
    04810
    04811         Status = ZwQueryVolumeInformationFile(
    04812                     Handle,
    04813                     &IoStatus,
    04814                     &SizeInfo,
    04815                     sizeof(SizeInfo),
    04816                     FileFsSizeInformation
    04817                     );
    04818
    04819         ZwClose(Handle);
    04820
    04821         if(NT_SUCCESS(Status)) {
    04822
    04823             //
    04824             // Calculate the amount of free space on the drive.
    04825             //
    04826             FreeSpace = RtlExtendedIntegerMultiply(
    04827                             SizeInfo.AvailableAllocationUnits,
    04828                             SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector
    04829                             );
    04830
    04831             if (RtlLargeIntegerGreaterThan(FreeSpace, LargestFreeSpace)) {
    04832                 LargestFreeSpace = FreeSpace;
    04833                 DestPartitionNumber = PartitionNumber;
    04834             }
    04835
    04836         }
    04837
    04838     }
    04839
    04840     if (DestPartitionNumber != 0) {
    04841         swprintf(NetHDCSCPartition, L"%ws\\Partition%d", DiskNameBuffer, DestPartitionNumber);
    04842     }
    04843
    04844     ExFreePool(NameBuffer);
    04845
    04846     return;
    04847 }
    04848
    04849 VOID
    04850 IoStartCscForTextmodeSetup (
    04851     IN BOOLEAN Upgrade
    04852     )
    04853 {
    04854     NTSTATUS status;
    04855     PWSTR NetHDCSCPartition;
    04856     PUCHAR buffer;
    04857     IO_STATUS_BLOCK ioStatusBlock;
    04858
    04859     if (RdrHandle == NULL) {
    04860         ASSERT(FALSE);
    04861         return;
    04862     }
    04863     if (!ExpInTextModeSetup) {
    04864         ASSERT(FALSE);
    04865         return;
    04866     }
    04867     if (TextmodeSetupHasStartedCsc) {
    04868         ASSERT(FALSE);
    04869         return;
    04870     }
    04871
    04872     NetHDCSCPartition = ExAllocatePoolWithTag(
    04873                             NonPagedPool,
    04874                             (80 + MAX_PATH) * sizeof(WCHAR),
    04875                             'bRoI'
    04876                             );
    04877     if (NetHDCSCPartition == NULL) {
    04878         KdPrint(( "IoStartCscForTextmodeSetup: Unable to allocate buffer\n"));
    04879         return;
    04880     }
    04881     buffer = (PUCHAR)(NetHDCSCPartition + 80);
    04882
    04883     //
    04884     // Get the path to the boot partition on the disk for CSC and redirection
    04885     // Note: On failure, this defaults to \Device\Harddisk0\Partition1
    04886     //
    04887
    04888     IopGetHarddiskInfo(NetHDCSCPartition);
    04889
    04890     //
    04891     // Tell the redirector to initialize remote boot redirection (back
    04892     // to the local disk).
    04893     //
    04894
    04895     KeAttachProcess( RdrHandleProcess );
    04896
    04897     status = ZwFsControlFile(
    04898                 RdrHandle,
    04899                 NULL,
    04900                 NULL,
    04901                 NULL,
    04902                 &ioStatusBlock,
    04903                 FSCTL_LMR_START_RBR,
    04904                 NetHDCSCPartition,
    04905                 wcslen(NetHDCSCPartition) * sizeof(WCHAR),
    04906                 NULL,
    04907                 0
    04908                 );
    04909
    04910     if (NT_SUCCESS(status) ) {
    04911         status = ioStatusBlock.Status;
    04912     }
    04913
    04914     if ( !NT_SUCCESS(status) ) {
    04915         KdPrint(( "IoStartCscForTextmodeSetup: Unable to FSCTL(RBR) redirector: %x\n", status ));
    04916     }
    04917
    04918     wcstombs(buffer, NetHDCSCPartition, wcslen(NetHDCSCPartition) + 1);
    04919     strcat(buffer, REMOTE_BOOT_IMIRROR_PATH_A REMOTE_BOOT_CSC_SUBDIR_A);
    04920
    04921     StartCsc = INIT_CSC;
    04922     status = IopInitCsc( buffer );
    04923
    04924     //
    04925     // If this is not an upgrade, or if initialization of CSC failed,
    04926     // reset the cache.
    04927     //
    04928
    04929     if ( NT_SUCCESS(status) && (!Upgrade || (StartCsc == FLUSH_CSC)) ) {
    04930
    04931         status = IopResetCsc( buffer );
    04932
    04933         if ( !NT_SUCCESS(status) ) {
    04934             KdPrint(("IoStartCscForTextmodeSetup: reset of Csc failed %x\n", status));
    04935         }
    04936     }
    04937
    04938     if ( !NT_SUCCESS(status) ) {
    04939         KdPrint(("IoStartCscForTextmodeSetup: initialization of Csc failed %x\n", status));
    04940         IoCscInitializationFailed = TRUE;
    04941         SharedUserData->SystemFlags |= SYSTEM_FLAG_DISKLESS_CLIENT;
    04942     } else {
    04943         IoCscInitializationFailed = FALSE;
    04944         SharedUserData->SystemFlags &= ~SYSTEM_FLAG_DISKLESS_CLIENT;
    04945     }
    04946
    04947     KeDetachProcess();
    04948
    04949     ExFreePool( NetHDCSCPartition );
    04950
    04951     return;
    04952
    04953 } // IoStartCscForTextModeSetup
    04954 #endif // defined(REMOTE_BOOT)
    04955