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

Generated on Sat May 15 19:40:57 2004 for test by doxygen 1.3.7