/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: sif.c Abstract: This module contains the following routines for manipulating the sif file in which Plug and Play migration data will be stored: AsrCreatePnpStateFileW AsrCreatePnpStateFileA Author: Jim Cavalaris (jamesca) 07-Mar-2000 Environment: User-mode only. Revision History: 07-March-2000 jamesca Creation and initial implementation. --*/ // // includes // #include "precomp.h" #include "debug.h" #include "pnpsif.h" #include #include // // definitions // // Maximum length of a line in the sif file #define MAX_SIF_LINE 4096 // // private prototypes // BOOL CreateSifFileW( IN PCWSTR FilePath, IN BOOL CreateNew, OUT LPHANDLE SifHandle ); BOOL WriteSifSection( IN CONST HANDLE SifHandle, IN PCTSTR SectionName, IN PCTSTR SectionData, IN BOOL Ansi ); // // routines // BOOL AsrCreatePnpStateFileW( IN PCWSTR lpFilePath ) /*++ Routine Description: Creates the ASR PNP state file (asrpnp.sif) at the specified file-path during an ASR backup operation. This sif file is retrieved from the ASR floppy disk during the setupldr phase of a clean install, and in used during text mode setup. Arguments: lpFilePath - Specifies the path to the file where the state file is to be created. Return Value: TRUE if successful, FALSE otherwise. Upon failure, additional information can be retrieved by calling GetLastError(). --*/ { BOOL result = TRUE; BOOL bAnsiSif = TRUE; // always write ANSI sif files. LPTSTR buffer = NULL; HANDLE sifHandle = NULL; // // Create an empty sif file using the supplied path name. // result = CreateSifFileW(lpFilePath, TRUE, // create a new asrpnp.sif file &sifHandle); if (!result) { // // LastError already set by CreateSifFile. // DBGTRACE((DBGF_ERRORS, TEXT("AsrCreatePnpStateFile: CreateSifFileW failed for file %s, ") TEXT("error=0x%08lx\n"), lpFilePath, GetLastError())); return FALSE; } // // Do the device instance migration stuff... // if (MigrateDeviceInstanceData(&buffer)) { // // Write the device instance section to the sif file. // result = WriteSifSection(sifHandle, WINNT_DEVICEINSTANCES, buffer, bAnsiSif); // Write sif section as ANSI if (!result) { DBGTRACE((DBGF_ERRORS, TEXT("AsrCreatePnpStateFile: WriteSifSection failed for [%s], ") TEXT("error=0x%08lx\n"), WINNT_DEVICEINSTANCES, GetLastError())); } // // Free the allocated buffer. // LocalFree(buffer); buffer = NULL; } else { DBGTRACE((DBGF_ERRORS, TEXT("AsrCreatePnpStateFile: MigrateDeviceInstanceData failed, ") TEXT("error=0x%08lx\n"), GetLastError())); } // // Do the class key migration stuff... // if (MigrateClassKeys(&buffer)) { // // Write the class key section to the sif file. // result = WriteSifSection(sifHandle, WINNT_CLASSKEYS, buffer, bAnsiSif); // Write sif section as ANSI if (!result) { DBGTRACE((DBGF_ERRORS, TEXT("AsrCreatePnpStateFile: WriteSifSection failed for [%s], ") TEXT("error=0x%08lx\n"), WINNT_CLASSKEYS, GetLastError())); } // // Free the allocated buffer. // LocalFree(buffer); buffer = NULL; } else { DBGTRACE((DBGF_ERRORS, TEXT("AsrCreatePnpStateFile: MigrateClassKeys failed, ") TEXT("error=0x%08lx\n"), GetLastError())); } // // Do the hash value migration stuff... // if (MigrateHashValues(&buffer)) { // // Write the hash value section to the sif file. // result = WriteSifSection(sifHandle, WINNT_DEVICEHASHVALUES, buffer, bAnsiSif); // Write sif section as ANSI? if (!result) { DBGTRACE((DBGF_ERRORS, TEXT("AsrCreatePnpStateFile: WriteSifSection failed for [%s], ") TEXT("error=0x%08lx\n"), WINNT_DEVICEHASHVALUES, GetLastError())); } // // Free the allocated buffer. // LocalFree(buffer); buffer = NULL; } else { DBGTRACE((DBGF_ERRORS, TEXT("AsrCreatePnpStateFile: MigrateHashValues failed, ") TEXT("error=0x%08lx\n"), GetLastError())); } // // Close the sif file. // if (sifHandle) { CloseHandle(sifHandle); } // // Reset the last error as successful in case we encountered a non-fatal // error along the way. // SetLastError(ERROR_SUCCESS); return TRUE; } // AsrCreatePnpStateFile() BOOL AsrCreatePnpStateFileA( IN PCSTR lpFilePath ) /*++ Routine Description: None. Arguments: None. Return Value: None. --*/ { WCHAR wszFilePath[MAX_PATH + 1]; // // Validate arguments. // if (!ARGUMENT_PRESENT(lpFilePath) || strlen(lpFilePath) > MAX_PATH) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } // // Convert the file path to a wide string. // memset(wszFilePath, 0, MAX_PATH + 1); if (!(MultiByteToWideChar(CP_ACP, 0, lpFilePath, -1, wszFilePath, MAX_PATH + 1))) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } // // Return the result of calling the wide char version // return AsrCreatePnpStateFileW(wszFilePath); } // AsrCreatePnpStateFileA() BOOL CreateSifFileW( IN PCWSTR lpFilePath, IN BOOL bCreateNew, OUT LPHANDLE lpSifHandle ) /*++ Routine Description: None. Arguments: None. Return Value: None. --*/ { DWORD Err = NO_ERROR; SID_IDENTIFIER_AUTHORITY sidNtAuthority = SECURITY_NT_AUTHORITY; PSID psidAdministrators = NULL; PSID psidBackupOperators = NULL; PSID psidLocalSystem = NULL; PACL pDacl = NULL; ULONG ulAclSize; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; HANDLE sifhandle = NULL; // // Validate arguments. // if (!ARGUMENT_PRESENT(lpFilePath) || (wcslen(lpFilePath) > MAX_PATH) || !ARGUMENT_PRESENT(lpSifHandle)) { Err = ERROR_INVALID_PARAMETER; goto Clean0; } // // Initialize output paramaters. // *lpSifHandle = NULL; // // Construct the security attributes for the sif file. // Allow access for Administrators, BackupOperators, and LocalSystem. // if (!AllocateAndInitializeSid( &sidNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators)) { Err = GetLastError(); goto Clean0; } ASSERT(IsValidSid(psidAdministrators)); if (!AllocateAndInitializeSid( &sidNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS, 0, 0, 0, 0, 0, 0, &psidBackupOperators)) { Err = GetLastError(); goto Clean0; } ASSERT(IsValidSid(psidBackupOperators)); if (!AllocateAndInitializeSid( &sidNtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidLocalSystem)) { Err = GetLastError(); goto Clean0; } ASSERT(IsValidSid(psidLocalSystem)); // // Determine the size required for the DACL // ulAclSize = sizeof(ACL); ulAclSize += sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdministrators) - sizeof(DWORD); ulAclSize += sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidBackupOperators) - sizeof(DWORD); ulAclSize += sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidLocalSystem) - sizeof(DWORD); // // Allocate and initialize the DACL // pDacl =(PACL)LocalAlloc(0, ulAclSize); if (pDacl == NULL) { Err = ERROR_NOT_ENOUGH_MEMORY; goto Clean0; } if (!InitializeAcl(pDacl, ulAclSize, ACL_REVISION)) { Err = GetLastError(); goto Clean0; } // // Add an ACE to the DACL for Administrators FILE_ALL_ACCESS // if (!AddAccessAllowedAceEx( pDacl, ACL_REVISION, 0, FILE_ALL_ACCESS, psidAdministrators)) { Err = GetLastError(); goto Clean0; } // // Add an ACE to the DACL for BackupOperators FILE_ALL_ACCESS // if (!AddAccessAllowedAceEx( pDacl, ACL_REVISION, 0, FILE_ALL_ACCESS, psidBackupOperators)) { Err = GetLastError(); goto Clean0; } // // Add an ACE to the DACL for LocalSystem FILE_ALL_ACCESS // if (!AddAccessAllowedAceEx( pDacl, ACL_REVISION, 0, FILE_ALL_ACCESS, psidLocalSystem)) { Err = GetLastError(); goto Clean0; } ASSERT(IsValidAcl(pDacl)); // // Initialize the security descriptor // if (!InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION)) { Err = GetLastError(); goto Clean0; } // // Set the new DACL in the security descriptor // if (!SetSecurityDescriptorDacl( &sd, TRUE, pDacl, FALSE)) { Err = GetLastError(); goto Clean0; } ASSERT(IsValidSecurityDescriptor(&sd)); // // Add the security descriptor to the security attributes // ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = TRUE; // // Create the file. The handle will be closed by the caller, once they are // finished with it. // sifhandle = CreateFileW(lpFilePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, &sa, bCreateNew ? CREATE_ALWAYS : OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (sifhandle == INVALID_HANDLE_VALUE) { Err = GetLastError(); goto Clean0; } ASSERT(sifhandle != NULL); // // Return the sif handle to the caller only if successful. // *lpSifHandle = sifhandle; Clean0: if (pDacl != NULL) { LocalFree(pDacl); } if (psidLocalSystem != NULL) { FreeSid(psidLocalSystem); } if (psidBackupOperators != NULL) { FreeSid(psidBackupOperators); } if (psidAdministrators != NULL) { FreeSid(psidAdministrators); } SetLastError(Err); return(Err == NO_ERROR); } // CreateSifFileW() BOOL WriteSifSection( IN CONST HANDLE SifHandle, IN PCTSTR SectionName, IN PCTSTR SectionData, IN BOOL Ansi ) /*++ Routine Description: None. Arguments: None. Return Value: None. --*/ { BYTE buffer[(MAX_SIF_LINE+1)*sizeof(WCHAR)]; DWORD dwSize, dwTempSize; PCTSTR p; HRESULT hr; // // Validate the arguments // if (!ARGUMENT_PRESENT(SifHandle) || !ARGUMENT_PRESENT(SectionName) || !ARGUMENT_PRESENT(SectionData)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } // // Write the section name to the sif file. // if (Ansi) { // // Write ANSI strings to the sif file // #if UNICODE hr = StringCbPrintfExA((LPSTR)buffer, sizeof(buffer), NULL, NULL, STRSAFE_NULL_ON_FAILURE, (LPCSTR)"[%ls]\r\n", SectionName); #else // ANSI hr = StringCbPrintfExA((LPSTR)buffer, sizeof(buffer), NULL, NULL, STRSAFE_NULL_ON_FAILURE, (LPCSTR)"[%s]\r\n", SectionName); #endif // UNICODE/ANSI // // If unable to write the section name to the sif file, we can't write // the section at all. // if (FAILED(hr)) { SetLastError(ERROR_INVALID_DATA); return FALSE; } dwSize = (DWORD)strlen((PSTR)buffer); } else { // // Write Unicode strings to the sif file // #if UNICODE hr = StringCbPrintfExW((LPWSTR)buffer, sizeof(buffer), NULL, NULL, STRSAFE_NULL_ON_FAILURE, (LPCWSTR)L"[%ws]\r\n", SectionName); #else // ANSI hr = StringCbPrintfExW((LPWSTR)buffer, sizeof(buffer), NULL, NULL, STRSAFE_NULL_ON_FAILURE, (LPCWSTR)L"[%S]\r\n", SectionName); #endif // UNICODE/ANSI // // If unable to write the section name to the sif file, we can't write // the section at all. // if (FAILED(hr)) { SetLastError(ERROR_INVALID_DATA); return FALSE; } dwSize = (DWORD)wcslen((PWSTR)buffer) * sizeof(WCHAR); } if (!WriteFile(SifHandle, buffer, dwSize, &dwTempSize, NULL)) { // // LastError already set by WriteFile // return FALSE; } DBGTRACE((DBGF_INFO, TEXT("[%s]\n"), SectionName)); // // Write the multi-sz section data to the file. // for (p = SectionData; *p != TEXT('\0'); p += lstrlen(p) + 1) { if (Ansi) { // // Write ANSI strings to the sif file // #if UNICODE hr = StringCbPrintfExA((LPSTR)buffer, sizeof(buffer), NULL, NULL, STRSAFE_NULL_ON_FAILURE, (LPCSTR)"%ls\r\n", p); #else // ANSI hr = StringCbPrintfExA((LPSTR)buffer, sizeof(buffer), NULL, NULL, STRSAFE_NULL_ON_FAILURE, (LPCSTR)"%s\r\n", p); #endif // UNICODE/ANSI // // If unable to write this string to the sif file, skip to the next. // if (FAILED(hr)) { continue; } dwSize = (DWORD)strlen((PSTR)buffer); } else { // // Write Unicode strings to the sif file // #if UNICODE hr = StringCbPrintfExW((LPWSTR)buffer, sizeof(buffer), NULL, NULL, STRSAFE_NULL_ON_FAILURE, (LPCWSTR)L"%ws\r\n", p); #else // ANSI hr = StringCbPrintfExW((LPWSTR)buffer, sizeof(buffer), NULL, NULL, STRSAFE_NULL_ON_FAILURE, (LPCWSTR)L"%S\r\n", p); #endif // UNICODE/ANSI // // If unable to write this string to the sif file, skip to the next. // if (FAILED(hr)) { continue; } dwSize = (DWORD)wcslen((PWSTR)buffer) * sizeof(WCHAR); } if (!WriteFile(SifHandle, buffer, dwSize, &dwTempSize, NULL)) { // // LastError already set by WriteFile // return FALSE; } DBGTRACE((DBGF_INFO, TEXT("%s\n"), p)); } return TRUE; } // WriteSifSection()