bool StrArc::ReadFileStreamsToArchive(PUNICODE_STRING File, HANDLE hFile) { LPVOID lpCtx = NULL; for (;;) { YieldSingleProcessor(); if (bCancel) { if (bVerbose) fputs(", break.\r\n", stderr); return false; } if (bVerbose) fputs(", stream: ", stderr); DWORD dwBytesRead; if (!BackupRead(hFile, Buffer, dwBufferSize, &dwBytesRead, FALSE, bProcessSecurity, &lpCtx)) { WErrMsgA errmsg; oem_printf(stderr, "strarc: Cannot read '%2!.*ws!': %1%%n", errmsg, File->Length >> 1, File->Buffer); return false; } if (dwBytesRead == 0) { BackupRead(NULL, NULL, 0, NULL, TRUE, FALSE, &lpCtx); ++FileCounter; if (bVerbose) fputs("EOF\r\n", stderr); return true; } if (bVerbose) fprintf(stderr, "%u bytes", dwBytesRead); WriteArchive(Buffer, dwBytesRead); }
int ListDataStreams(char *szFilename) { int iRetCode = EXIT_SUCCESS; HANDLE *hFile = NULL; LPVOID lpContext = NULL; byte pbyBuffer[4096]; WIN32_STREAM_ID *psStreamInfo = (WIN32_STREAM_ID *)pbyBuffer; int uiHeaderLength = 20; DWORD dwRead, dwDummy; WHANDLEOK(hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)); while (1) { WNONZERO(BackupRead(hFile, pbyBuffer, uiHeaderLength, &dwRead, FALSE, TRUE, &lpContext)); if (dwRead == 0) break; if (psStreamInfo->dwStreamNameSize > 0) { WNONZERO(BackupRead(hFile, pbyBuffer + uiHeaderLength, psStreamInfo->dwStreamNameSize, &dwRead, FALSE, TRUE, &lpContext)); if (dwRead != psStreamInfo->dwStreamNameSize) break; } DumpStreamInfo(szFilename, psStreamInfo); if (psStreamInfo->Size.QuadPart > 0) { BackupSeek(hFile, psStreamInfo->Size.LowPart, psStreamInfo->Size.HighPart, &dwDummy, &dwDummy, &lpContext); } } cleanup: // release context BackupRead(hFile, pbyBuffer, 0, &dwRead, TRUE, FALSE, &lpContext); CloseHandle(hFile); return iRetCode; }
unsigned long read_stream(unsigned char *dest, unsigned long bytes, struct nt_sid *sid) { unsigned long br, rc; if(sid->is_write) return(0); br=(sid->rem.HighPart==0&&sid->rem.LowPart<bytes)?sid->rem.LowPart:bytes; if(br==0) return(0); if(!BackupRead(sid->hf, dest, br, &rc, FALSE, TRUE, &sid->lpcontext)) return(0); sid->rem=LargeIntegerSubtract(sid->rem, ConvertUlongToLargeInteger(rc)); return(rc); }
static void finalize_backup(struct nt_sid *sid) { DWORD dummy; if(sid->lpcontext!=NULL) { if(sid->is_write) BackupWrite(sid->hf, NULL, 0, &dummy, TRUE, FALSE, &sid->lpcontext); #if SFX_LEVEL>=ARJ else BackupRead(sid->hf, NULL, 0, &dummy, TRUE, FALSE, &sid->lpcontext); #endif sid->lpcontext=NULL; } }
int next_stream(WIN32_STREAM_ID *dest, struct nt_sid *sid) { DWORD lo, hi, b; if(sid->is_write) return(-1); if(sid->rem.LowPart!=0||sid->rem.HighPart!=0) { if(!BackupSeek(sid->hf, sid->rem.LowPart, sid->rem.HighPart, &lo, &hi, &sid->lpcontext)) return(-1); if(lo!=sid->rem.LowPart||hi!=sid->rem.HighPart) return(-1); sid->rem.LowPart=sid->rem.HighPart=0; } if(!BackupRead(sid->hf, (unsigned char *)dest, W32_SID_HEADER_SIZE, &b, FALSE, TRUE, &sid->lpcontext)) return(-1); if(b!=W32_SID_HEADER_SIZE) return(-1); sid->rem=dest->Size; return(0); }
/* Check if file has NTFS ADS */ int os_check_ads(const char *full_path) { HANDLE file_h; WIN32_STREAM_ID sid; void *context = NULL; char stream_name[MAX_PATH + 1]; char final_name[MAX_PATH + 1]; DWORD dwRead, shs, dw1, dw2; /* Open file */ file_h = CreateFile(full_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL); if (file_h == INVALID_HANDLE_VALUE) { return 0; } /* Zero memory */ ZeroMemory(&sid, sizeof(WIN32_STREAM_ID)); /* Get stream header size -- should be 20 bytes */ shs = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid + sid.dwStreamNameSize; while (1) { if (BackupRead(file_h, (LPBYTE) &sid, shs, &dwRead, FALSE, FALSE, &context) == 0) { break; } if (dwRead == 0) { break; } stream_name[0] = '\0'; stream_name[MAX_PATH] = '\0'; if (BackupRead(file_h, (LPBYTE)stream_name, sid.dwStreamNameSize, &dwRead, FALSE, FALSE, &context)) { if (dwRead != 0) { DWORD i = 0; int max_path_size = 0; char *tmp_pt; char op_msg[OS_SIZE_1024 + 1]; snprintf(final_name, MAX_PATH, "%s", full_path); max_path_size = strlen(final_name); /* Copy from wide char to char */ while ((i < dwRead) && (max_path_size < MAX_PATH)) { if (stream_name[i] != 0) { final_name[max_path_size] = stream_name[i]; max_path_size++; final_name[max_path_size] = '\0'; } i++; } tmp_pt = strrchr(final_name, ':'); if (tmp_pt) { *tmp_pt = '\0'; } snprintf(op_msg, OS_SIZE_1024, "NTFS Alternate data stream " "found: '%s'. Possible hidden" " content.", final_name); notify_rk(ALERT_ROOTKIT_FOUND, op_msg); } } /* Get next */ if (!BackupSeek(file_h, sid.Size.LowPart, sid.Size.HighPart, &dw1, &dw2, &context)) { break; } } CloseHandle(file_h); return (0); }
int backup1(struct fout *ff, const char *f) { WIN32_STREAM_ID sid; LPVOID lpContext; HANDLE h; DWORD rv; int r, n; lpContext = NULL; set_backup_privs(1); h = CreateFileA(f, FILE_READ_DATA | STANDARD_RIGHTS_READ | ACCESS_SYSTEM_SECURITY, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (h == INVALID_HANDLE_VALUE) { r = GetLastError(); if (r == ERROR_FILE_NOT_FOUND) { set_backup_privs(0); fout_abort(ff); return 1; } set_backup_privs(0); /* try to read it raw */ if (!backup1_ntfs(ff, f)) { return 0; } /* hooray! it read in- get the security info */ if (s_flag) return backupsec2(f); return 1; } if (!backupsec(h, f)) { r = GetLastError(); CloseHandle(h); set_backup_privs(0); SetLastError(r); return 0; } NEXT_STREAM: rv = 0; if (!BackupRead(h,(void*)&sid,20, &rv,FALSE,FALSE,&lpContext)) { goto FAIL; } if (rv < 2) { /* SUCCESS */ (void)BackupRead(h,buffer,sizeof(buffer),&rv,TRUE,FALSE,&lpContext); CloseHandle(h); set_backup_privs(0); SetLastError(ERROR_SUCCESS); return 1; } if (rv != 20) { goto FAIL; } if (sid.dwStreamId != 1 || sid.dwStreamAttributes != 0 || sid.dwStreamNameSize > 0) { /* skip */ BackupSeek(h, sid.dwStreamNameSize, 0, (void*)buffer, (void*)(buffer+8), &lpContext); BackupSeek(h, sid.Size.LowPart, sid.Size.HighPart, (void*)buffer, (void*)(buffer+8), &lpContext); goto NEXT_STREAM; } while (sid.Size.QuadPart > 0) { rv = 0; if (sid.Size.QuadPart < sizeof(buffer)) { n = sid.Size.QuadPart; } else { n = sizeof(buffer); } if (!BackupRead(h,buffer,n,&rv,FALSE,FALSE,&lpContext)) { goto FAIL; } r=rv; if (!r) break; if (!fout(ff, buffer, r)) { goto FAIL; } } goto NEXT_STREAM; FAIL: r = GetLastError(); (void)BackupRead(h,buffer,sizeof(buffer),&rv,TRUE,FALSE,&lpContext); CloseHandle(h); set_backup_privs(0); SetLastError(r); return 0; }
NET_API_STATUS ReplCopyFile( IN LPCTSTR SourcePath, IN LPCTSTR DestPath, IN BOOL bFailIfExists ) /*++ Routine Description: ReplCopyFile copies everthing contained in a file. ("Everything" includes data, alternate data, extended attributes, attributes, timestamps, and security info.) Arguments: SourcePath - Points to source file path, which might be a UNC name. DestPath - Points to destination file path name. bFailIfExists - a boolean which is TRUE iff this routine should fail if the destination already exists. Return Value: NET_API_STATUS Threads: Used by client and syncer threads. --*/ { NET_API_STATUS ApiStatus; BOOL DestExists; HANDLE DestHandle = INVALID_HANDLE_VALUE; PSECURITY_ATTRIBUTES DestSecurityAttr = NULL; DWORD SourceAttributes = (DWORD) (-1); #ifdef USE_BACKUP_APIS DWORD ActualBufferSizeRead = 0; DWORD ActualBufferSizeWritten; LPVOID BackupBuffer = NULL; LPVOID DestContext = NULL; LPVOID SourceContext = NULL; HANDLE SourceHandle = INVALID_HANDLE_VALUE; #endif // // Check for caller errors. // NetpAssert( SourcePath != NULL ); NetpAssert( (*SourcePath) != TCHAR_EOS ); NetpAssert( STRLEN(SourcePath) <= PATHLEN ); NetpAssert( DestPath != NULL ); NetpAssert( (*DestPath) != TCHAR_EOS ); NetpAssert( STRLEN(DestPath) <= PATHLEN ); DestExists = ReplFileOrDirExists( DestPath ); if (bFailIfExists && DestExists) { // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ERROR_ALREADY_EXISTS); } // // What kind of source (file/directory) is it? // SourceAttributes = GetFileAttributes( (LPTSTR) SourcePath ); if ( SourceAttributes == (DWORD) -1 ) { // // File doesn't exist, bad syntax, or something along those lines. // ApiStatus = (NET_API_STATUS) GetLastError(); NetpAssert( ApiStatus != NO_ERROR ); // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ApiStatus); } else if ((SourceAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { // // Source is a directory tree. We don't handle this! // NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: source is directory! path: '" FORMAT_LPTSTR "', src attr " FORMAT_HEX_DWORD ".\n", SourcePath, SourceAttributes )); ApiStatus = NERR_InternalError; // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ApiStatus); } else { // // Simple case: source exists and is just a single file. // Start off by setting desired destination security attributes. // ApiStatus = ReplMakeSecurityAttributes( SourcePath, &DestSecurityAttr ); // alloc and set ptr if (ApiStatus==ERROR_NOT_SUPPORTED) { // Just downlevel master, so set default security and continue. DestSecurityAttr = NULL; } else if (ApiStatus != NO_ERROR) { // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ApiStatus); } else { NetpAssert( ApiStatus == NO_ERROR ); NetpAssert( DestSecurityAttr != NULL ); } #ifdef USE_BACKUP_APIS // // Open source file. // SourceHandle = CreateFile( SourcePath, GENERIC_READ, // desired access FILE_SHARE_READ, // share mode NULL, // no security attributes OPEN_EXISTING, // open if exists; fail if not. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN, // flags (HANDLE) NULL // no template ); if (SourceHandle == INVALID_HANDLE_VALUE) { ApiStatus = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: open of source '" FORMAT_LPTSTR "' gave status " FORMAT_API_STATUS ".\n", SourcePath, ApiStatus )); NetpAssert( ApiStatus != NO_ERROR ); if (DestSecurityAttr != NULL) { NetpMemoryFree( DestSecurityAttr ); } // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ApiStatus); } #endif // // Delete the destination file. Why? Because... // We're going to set the security on destination file using // the CreateFile API. This will ignore setting the security if the // file already exists. So, we need to delete it to force this to // happen. // if (DestExists) { ApiStatus = ReplDeleteFile( DestPath ); if (ApiStatus != NO_ERROR) { goto Cleanup; } } NetpAssert( !ReplFileOrDirExists( DestPath ) ); // // Open dest file. Since we already deleted any existing one, we know // this will create the file from scratch. This is important, because // we're depending on CreateFile's use of DestSecurityAttr to set // security on the file. // DestHandle = CreateFile( DestPath, GENERIC_WRITE // desired... | WRITE_DAC // ... | WRITE_OWNER, // access FILE_SHARE_WRITE, // share mode: none DestSecurityAttr, // desired security attributes CREATE_NEW, // disposition create new (fail exist) #ifdef USE_BACKUP_APIS FILE_FLAG_BACKUP_SEMANTICS, // flags #else 0, // flags #endif (HANDLE) NULL // no template ); if (DestHandle == INVALID_HANDLE_VALUE) { ApiStatus = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: open of dest '" FORMAT_LPTSTR "' gave status " FORMAT_API_STATUS ".\n", DestPath, ApiStatus )); NetpAssert( ApiStatus != NO_ERROR ); goto Cleanup; } #ifndef USE_BACKUP_APIS // // Close the dest file and copy the data. // (In this case, we're using CopyFile API, which is not handle-based.) // NetpAssert( DestHandle != INVALID_HANDLE_VALUE ); (VOID) CloseHandle( DestHandle ); DestHandle = INVALID_HANDLE_VALUE; if ( !CopyFile( (LPTSTR) SourcePath, (LPTSTR) DestPath, FALSE /* don't fail if exists */ ) ) { ApiStatus = (NET_API_STATUS) GetLastError(); NetpAssert( ApiStatus != NO_ERROR ); goto Cleanup; } NetpAssert( ReplFileOrDirExists( DestPath ) ); // Timestamps and attributes will be copied below. // BUGBUG no way to copy EAs, alt data. ApiStatus = NO_ERROR; #else // defined(USE_BACKUP_APIS) BackupBuffer = NetpMemoryAllocate( REPL_BACKUP_BUFFER_SIZE ); if (BackupBuffer == NULL) { ApiStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } IF_DEBUG( SYNC ) { NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: copying" )); } for (;;) { // until end of file... IF_DEBUG( SYNC ) { NetpKdPrint(( "<" )); } if ( !BackupRead( SourceHandle, BackupBuffer, REPL_BACKUP_BUFFER_SIZE, & ActualBufferSizeRead, FALSE, // don't abort yet REPL_PROCESS_SECURITY, & SourceContext ) ) { // Process read error. ApiStatus = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: BackupRead" " gave status " FORMAT_API_STATUS ".\n", ApiStatus )); NetpAssert( ApiStatus != NO_ERROR ); goto Cleanup; } // No error on read, how about EOF? if (ActualBufferSizeRead == 0) { // normal end of file. ApiStatus = NO_ERROR; IF_DEBUG( SYNC ) { NetpKdPrint(( "DONE(OK)\n" )); } break; } IF_DEBUG( SYNC ) { NetpKdPrint(( ">" )); } if ( !BackupWrite( DestHandle, BackupBuffer, ActualBufferSizeRead, & ActualBufferSizeWritten, FALSE, // don't abort yet REPL_PROCESS_SECURITY, & DestContext ) ) { ApiStatus = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: BackupWrite" " gave status " FORMAT_API_STATUS ".\n", ApiStatus )); NetpAssert( ApiStatus != NO_ERROR ); goto Cleanup; } } // until end of file ApiStatus = NO_ERROR; #endif } // else (just single file)
/****************************************************************************** * CKMPrivate_Utils::secureDeleteStreams() * * Parameters: inFilename - [in] name of file with streams to delete * inDeletePasses - [in] number of "cleaning" passes to make * * Returns: Nothing * Throws: Nothing * * Description: Securely delete all streams belonging to the supplied * file by overwriting them with 111s and 000s. * * Note: Does not exist under Unix, which has no alternate stream support *****************************************************************************/ bool FileVEILOperationsImpl::secureDeleteStreams(const tscrypto::tsCryptoString& inFilename, int inDeletePasses) { TSDECLARE_FUNCTIONExt(true); #ifdef WIN32 // if we aren't on an NT platform, bail out now (no streams to delete) //OSVERSIONINFO osvi; //ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); //osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); //if (! GetVersionEx ( (OSVERSIONINFO *) &osvi)) //{ // return TSRETURN(("OK"),true); //} //else if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) //{ // return TSRETURN(("OK"),true); //} int index; HANDLE hFile; BOOL bContinue; void * ctx = NULL; WIN32_STREAM_ID sid; DWORD dwRead, lo, hi; // open the file whose streams we want to delete if (INVALID_HANDLE_VALUE == (hFile = CreateFileA(inFilename.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0))) { LogError("Unable to open the specified file. " + inFilename); return TSRETURN_ERROR(("Invalid filename"), true); } // we have to build a list of named files to delete, and then close the // original file. The streams can't be written when the main file is open int streamCnt = 0; tscrypto::tsCryptoStringList streamList = CreateTsAsciiList(); CryptoUtf16 streamName; tscrypto::tsCryptoString tmpStr; // read the first 20 bytes of the stream (all but the last field) while ((bContinue = BackupRead(hFile, (LPBYTE)&sid, sizeof(sid) - sizeof(WCHAR *), &dwRead, FALSE, FALSE, &ctx)) != FALSE) { // if we are done or there was no data read, break out if (!bContinue || !dwRead) break; // if this stream is named Alternate Data, delete it if (sid.dwStreamId == BACKUP_ALTERNATE_DATA && sid.dwStreamNameSize > 0) { // get the name of the stream (Wide-Char format) streamName.clear(); streamName.resize(sid.dwStreamNameSize / sizeof(ts_wchar)); BackupRead(hFile, (byte *)streamName.data(), sid.dwStreamNameSize, &dwRead, FALSE, FALSE, &ctx); if (wcslen(streamName.c_str()) >= 6 && wcscmp(&streamName[wcslen(streamName.c_str()) - 6], L":$DATA") == 0) { streamName.resize(streamName.size() - 6); } tmpStr = inFilename + streamName.toUtf8(); streamList->push_back(tmpStr); } // seek to the end of this stream so we can check the next one BackupSeek(hFile, sid.Size.LowPart, sid.Size.HighPart, &lo, &hi, &ctx); } // free memory allocated by BackupRead and close the file BackupRead(hFile, (LPBYTE)&sid, 0, &dwRead, TRUE, FALSE, &ctx); CloseHandle(hFile); m_taskCount += streamCnt; // now go through the list we built and secureDelete each stream for (index = 0; index < streamCnt; index++) { // ignore exceptions and move on to the next one LOG(DebugInfo1, "CKMPrivate_Utils::secureDeleteStreams() securedelete stream " << streamList->at(index)); if (!secureDeleteFile(streamList->at(index), inDeletePasses)) return TSRETURN(("Returns ~~"), false); m_currentTask++; } #endif /* WIN32 */ return TSRETURN(("OK"), true); }
/* Print out streams of a file */ int os_get_streams(char *full_path) { HANDLE file_h; WIN32_STREAM_ID sid; void *context = NULL; char stream_name[MAX_PATH +1]; char final_name[MAX_PATH +1]; DWORD dwRead, shs, dw1, dw2; /* Opening file */ file_h = CreateFile(full_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL); if (file_h == INVALID_HANDLE_VALUE) { return 0; } /* Zeroing memory */ ZeroMemory(&sid, sizeof(WIN32_STREAM_ID)); /* Getting stream header size -- should be 20 bytes */ shs = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid+ sid.dwStreamNameSize; while(1) { if(BackupRead(file_h, (LPBYTE) &sid, shs, &dwRead, FALSE, FALSE, &context) == 0) { break; } if(dwRead == 0) { break; } stream_name[0] = '\0'; stream_name[MAX_PATH] = '\0'; if(BackupRead(file_h, (LPBYTE)stream_name, sid.dwStreamNameSize, &dwRead, FALSE, FALSE, &context)) { if(dwRead != 0) { char *tmp_pt; snprintf(final_name, MAX_PATH, "%s%S", full_path, (WCHAR *)stream_name); tmp_pt = strrchr(final_name, ':'); if(tmp_pt) { *tmp_pt = '\0'; } printf("Found NTFS ADS: '%s' \n", final_name); ads_found = 1; } } /* Getting next */ if(!BackupSeek(file_h, sid.Size.LowPart, sid.Size.HighPart, &dw1, &dw2, &context)) { break; } } CloseHandle(file_h); return(0); }