Refactor VM volume mounting
- Replace bind-mounts on /lmn/media/$USER with separate mounting for Home and Share SMB shares in the VM. - Update vm-run to start virtiofsd with /lmn/media/$USER (/home/$USER on localhome machines). - Use vm-vminfo to generate a JSON file containing user information, including Username, Groups, printer list krb5-ticket and some more - Configure vminfo.service (systemd-timer) to periodically call vm-vminfo. - Ensure krb5-ticket (TGT) is injected into the Windows VM. - Mount SMB-Home and SMB-Share shares as part of the new structure.
This commit is contained in:
parent
efd48de6c7
commit
b688a8df59
12 changed files with 560 additions and 24 deletions
BIN
misc/vm/Netzlaufwerke neu verbinden.lnk
Executable file
BIN
misc/vm/Netzlaufwerke neu verbinden.lnk
Executable file
Binary file not shown.
155
misc/vm/injector.ps1
Normal file
155
misc/vm/injector.ps1
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
param(
|
||||
[string]$ticketb64
|
||||
)
|
||||
# BASE64
|
||||
$ticket = New-Object System.Byte
|
||||
#reading from b64
|
||||
$ticket = [System.Convert]::FromBase64String($ticketb64)
|
||||
if ($ticket -eq $null){
|
||||
write-host "[-] Be Sure entering the correct mode"
|
||||
write-host "[-] Cannot receive ticket from file or b64"
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
# ------------------- FUNCTIONS -----------------------#
|
||||
$ptt = @"
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct LUID
|
||||
{
|
||||
public UInt32 LowPart;
|
||||
public Int32 HighPart;
|
||||
}
|
||||
public enum KERB_PROTOCOL_MESSAGE_TYPE
|
||||
{
|
||||
KerbDebugRequestMessage,
|
||||
KerbQueryTicketCacheMessage,
|
||||
KerbChangeMachinePasswordMessage,
|
||||
KerbVerifyPacMessage,
|
||||
KerbRetrieveTicketMessage,
|
||||
KerbUpdateAddressesMessage,
|
||||
KerbPurgeTicketCacheMessage,
|
||||
KerbChangePasswordMessage,
|
||||
KerbRetrieveEncodedTicketMessage,
|
||||
KerbDecryptDataMessage,
|
||||
KerbAddBindingCacheEntryMessage,
|
||||
KerbSetPasswordMessage,
|
||||
KerbSetPasswordExMessage,
|
||||
KerbVerifyCredentialMessage,
|
||||
KerbQueryTicketCacheExMessage,
|
||||
KerbPurgeTicketCacheExMessage,
|
||||
KerbRefreshSmartcardCredentialsMessage,
|
||||
KerbAddExtraCredentialsMessage,
|
||||
KerbQuerySupplementalCredentialsMessage,
|
||||
KerbTransferCredentialsMessage,
|
||||
KerbQueryTicketCacheEx2Message,
|
||||
KerbSubmitTicketMessage,
|
||||
KerbAddExtraCredentialsExMessage
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct KERB_CRYPTO_KEY32
|
||||
{
|
||||
public int KeyType;
|
||||
public int Length;
|
||||
public int Offset;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct KERB_SUBMIT_TKT_REQUEST
|
||||
{
|
||||
public KERB_PROTOCOL_MESSAGE_TYPE MessageType;
|
||||
public LUID LogonId;
|
||||
public int Flags;
|
||||
public KERB_CRYPTO_KEY32 Key;
|
||||
public int KerbCredSize;
|
||||
public int KerbCredOffset;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct LSA_STRING_IN
|
||||
{
|
||||
public ushort Length;
|
||||
public ushort MaximumLength;
|
||||
public IntPtr buffer;
|
||||
}
|
||||
[DllImport("secur32.dll", SetLastError=false)]
|
||||
public static extern int LsaLookupAuthenticationPackage([In] IntPtr LsaHandle,[In] ref LSA_STRING_IN PackageName,[Out] out UInt32 AuthenticationPackage);
|
||||
[DllImport("Secur32.dll", SetLastError = true)]
|
||||
public static extern int LsaCallAuthenticationPackage(IntPtr LsaHandle,uint AuthenticationPackage,IntPtr ProtocolSubmitBuffer,int SubmitBufferLength,out IntPtr ProtocolReturnBuffer,out ulong ReturnBufferLength,out int ProtocolStatus);
|
||||
[DllImport("secur32.dll", SetLastError=false)]
|
||||
public static extern int LsaConnectUntrusted([Out] out IntPtr LsaHandle);
|
||||
[DllImport("secur32.dll", SetLastError=false)]
|
||||
public static extern int LsaDeregisterLogonProcess([In] IntPtr LsaHandle);
|
||||
[DllImport("advapi32.dll", SetLastError=true)]
|
||||
public static extern uint LsaNtStatusToWinError(uint status);
|
||||
"@
|
||||
|
||||
|
||||
Function ConnectToLsa()
|
||||
{
|
||||
$lsahandle = New-Object System.IntPtr
|
||||
[int]$retcode = [KRB.PTT]::LsaConnectUntrusted([ref]$lsahandle)
|
||||
if ($retcode -ne 0){
|
||||
write-host "[-] LsaConnectUntrusted Error (NTSTATUS): ", $retcode -ForegroundColor Red
|
||||
exit;
|
||||
}
|
||||
return $lsahandle
|
||||
}
|
||||
|
||||
#-------------------------------- ENTRY POINT ----------------------------#
|
||||
|
||||
$assemblies = [System.Reflection.Assembly]::LoadWithPartialName("System.Security.Principal")
|
||||
Add-Type -MemberDefinition $ptt -Namespace "KRB" -Name "PTT" -ReferencedAssemblies $assemblies.location -UsingNamespace System.Security.Principal
|
||||
# CONNECTING TO LSA
|
||||
$LsaHandle = ConnectToLsa
|
||||
write-host "[?] LSA HANDLE: ", $LsaHandle
|
||||
# EXTRACTING KERBEROS AP
|
||||
$retcode = New-Object System.Int32
|
||||
$authPackage = New-Object System.Int32
|
||||
$name = "kerberos"
|
||||
$importnantlsastring = New-Object KRB.PTT+LSA_STRING_IN
|
||||
$importnantlsastring.Length = [uint16]$name.Length
|
||||
$importnantlsastring.MaximumLength = [uint16]($name.Length + 1)
|
||||
$importnantlsastring.buffer = [System.Runtime.InteropServices.Marshal]::StringToHGlobalAnsi($name)
|
||||
$retcode = [KRB.PTT]::LsaLookupAuthenticationPackage($lsaHandle,[ref]$importnantlsastring,[ref]$authPackage)
|
||||
if ($retcode -ne 0){
|
||||
write-host "[-] Error LsaLookupAuthPckg (NTSTATUS): ", $retcode -ForegroundColor Red
|
||||
exit;
|
||||
}
|
||||
write-host "[?] Kerberos Package: ", $authPackage
|
||||
# GETTING CURRENT LUID (INJECT PURPOSES)
|
||||
$output = klist
|
||||
$CurrLuid = $output.split("`n")[1].split(":")[1]
|
||||
$sysIntCurrLuid = [convert]::ToInt32($CurrLuid,16)
|
||||
$luidFinally = New-Object KRB.PTT+LUID
|
||||
$luidFinally.LowPart = $sysIntCurrLuid
|
||||
|
||||
# TICKET INJECTING
|
||||
$protocolReturnBuffer = New-Object System.IntPtr
|
||||
$ReturnBufferLength = New-Object System.Int32
|
||||
$ProtocolStatus = New-Object System.Int32
|
||||
$KrbRequestInfo = New-Object KRB.PTT+KERB_SUBMIT_TKT_REQUEST
|
||||
$KrbRequestInfoType = $KrbRequestInfo.getType()
|
||||
$KrbRequestInfo.MessageType = [KRB.PTT+KERB_PROTOCOL_MESSAGE_TYPE]::KerbSubmitTicketMessage
|
||||
$KrbRequestInfo.KerbCredSize = $ticket.Length
|
||||
$KrbRequestInfo.KerbCredOffset = [System.Runtime.InteropServices.Marshal]::SizeOf([type]$KrbRequestInfoType)
|
||||
$KrbRequestInfo.LogonId = $luidFinally
|
||||
$inputBufferSize = [System.Runtime.InteropServices.Marshal]::SizeOf([type]$KrbRequestInfoType) + $ticket.Length
|
||||
$inputBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($inputBufferSize)
|
||||
[System.Runtime.InteropServices.Marshal]::StructureToPtr($KrbRequestInfo,$inputBuffer,$false)
|
||||
[System.IntPtr]$PtrToCred = $inputBuffer.ToInt64() + $KrbRequestInfo.KerbCredOffset
|
||||
[System.Runtime.InteropServices.Marshal]::Copy($ticket,0,$PtrToCred,$ticket.Length)
|
||||
$ntstatus = [KRB.PTT]::LsaCallAuthenticationPackage($lsaHandle,$authPackage,$inputBuffer,$inputBufferSize,[ref]$protocolReturnBuffer,[ref]$ReturnBufferLength,[ref]$ProtocolStatus)
|
||||
if(($ProtocolStatus -ne 0) -or ($ntstatus -ne 0))
|
||||
{
|
||||
Write-Host "[!] Error in LsaCallAuthenticationPackage" -ForegroundColor Red
|
||||
write-host " NTSTATUS: ", $ntstatus, " Protocol Status: ", $ProtocolStatus
|
||||
if ($ProtocolStatus -eq -1073741517){
|
||||
" Ticket may be out of date"
|
||||
}
|
||||
exit;
|
||||
}
|
||||
if($inputBuffer -ne [System.IntPtr]::Zero)
|
||||
{
|
||||
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($inputBuffer)
|
||||
[System.Object]$ticket = $null
|
||||
}
|
||||
klist
|
||||
73
misc/vm/vm-prepare-sys.ps1
Normal file
73
misc/vm/vm-prepare-sys.ps1
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Installiere alle Mounts aus target.csv
|
||||
# Geprüft wird, ob das Laufwerk bereits vorhanden
|
||||
# 11.05.2025 da
|
||||
|
||||
function Mount-Drive {
|
||||
param (
|
||||
[string]$DriveLetter,
|
||||
[string]$TargetPath
|
||||
)
|
||||
|
||||
try {
|
||||
& "C:\Program Files (x86)\WinFsp\bin\launchctl-x64.exe" start virtiofs viofs$DriveLetter $TargetPath \\.\${DriveLetter}:
|
||||
Write-Verbose "Laufwerk hinzugefügt: $DriveLetter"
|
||||
} catch {
|
||||
Write-Error "Fehler beim Hinzufügen des Laufwerks ${DriveLetter}: $_"
|
||||
}
|
||||
}
|
||||
|
||||
function Import-VMInfo {
|
||||
param (
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
if (Test-Path $Path) {
|
||||
return Get-Content -Path $Path -Raw | ConvertFrom-Json
|
||||
} else {
|
||||
Write-Error "Fehler beim Einlesen der VMInfo Datei ($Path nicht gefunden)."
|
||||
Write-Error "Tipp: Beim Neustart der VM wird diese Datei neu angelegt."
|
||||
Pause
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
# Laufwerk Y: mit weiteren Mountpoint-Infos mounten
|
||||
& "C:\Program Files\Virtio-Win\VioFS\virtiofs.exe" -m Y:
|
||||
#Mount-Drive -DriveLetter "Y" -TargetPath "VM-Data"
|
||||
|
||||
# VMInfo aus JSON File einlesen
|
||||
$VMInfoPath = "Y:\.vminfo.json"
|
||||
# Schleife, die auf das Laufwerk wartet
|
||||
while (-not (Test-Path $VMInfoPath)) {
|
||||
Write-Host "Warte auf $VMInfoPath..."
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
$VMInfo = Import-VMInfo -Path $VMInfoPath
|
||||
|
||||
# Weitere Laufwerke einbinden
|
||||
#foreach ($virtiofs in $VMInfo.VirtioFS) {
|
||||
# $targetDrive = $virtiofs.Drive
|
||||
# if (-not (Get-PSDrive -Name $targetDrive -ErrorAction SilentlyContinue)) {
|
||||
# Mount-Drive -DriveLetter $targetDrive -TargetPath $virtiofs.Target
|
||||
# } else {
|
||||
# Write-Error "Laufwerk bereits vorhanden: $targetDrive"
|
||||
# }
|
||||
#}
|
||||
|
||||
# Drucker installieren
|
||||
foreach ($drucker in $VMInfo.Printers) {
|
||||
# Überprüfen, ob der Drucker bereits vorhanden ist
|
||||
$druckerName = $drucker.Name
|
||||
$druckerVorhanden = Get-Printer | Where-Object { $_.Name -eq $druckerName }
|
||||
|
||||
# Umwandlung in HTTP-URL
|
||||
$httpUrl = $drucker.IppURL -replace "ipp://", "http://" -replace "122.1", "122.1:631"
|
||||
|
||||
if (-not $druckerVorhanden) {
|
||||
# Drucker hinzufügen, wenn er nicht vorhanden ist
|
||||
Add-Printer -PortName $httpUrl -Name $druckerName -DriverName "Microsoft IPP Class Driver"
|
||||
Write-Host "Drucker hinzugefuegt: $druckerName"
|
||||
} else {
|
||||
Write-Host "Drucker bereits vorhanden: $druckerName"
|
||||
}
|
||||
}
|
||||
BIN
misc/vm/vm-prepare-sys.xml
Executable file
BIN
misc/vm/vm-prepare-sys.xml
Executable file
Binary file not shown.
102
misc/vm/vm-prepare-user.ps1
Normal file
102
misc/vm/vm-prepare-user.ps1
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
# Installiere alle Mounts aus target.csv
|
||||
# Geprüft wird, ob das Laufwerk bereits vorhanden
|
||||
# 11.05.2025 da
|
||||
|
||||
function Import-VMInfo {
|
||||
param (
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
if (Test-Path $Path) {
|
||||
return Get-Content -Path $Path -Raw | ConvertFrom-Json
|
||||
} else {
|
||||
Write-Error "Fehler beim Einlesen der VMInfo Datei ($Path nicht gefunden)."
|
||||
Write-Error "Tipp: Beim Neustart der VM wird diese Datei neu angelegt."
|
||||
Pause
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
function Add-PathToQuickAccess([string[]]$path){
|
||||
$path | %{
|
||||
write-host "Adding path '$($_)' to Quick acccess list." -F Green
|
||||
try{
|
||||
$link = (New-Object -Com Shell.Application).NameSpace($_).Self
|
||||
if(!$link){throw "Item path not valid to be pinned."}
|
||||
$link.Verbs()| ?{$_.Name.replace('&','') -match 'An Schnellzugriff anheften|Pin to Quick access'} | %{$_.DoIt()}
|
||||
}catch{
|
||||
write-error "Error adding path. $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$VMInfoPath = "Y:\.vminfo.json"
|
||||
|
||||
# Schleife, die auf das Laufwerk wartet
|
||||
while (-not (Test-Path $VMInfoPath)) {
|
||||
Write-Host "Warte auf $VMInfoPath..."
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
|
||||
# VMInfo aus JSON File einlesen
|
||||
$VMInfo = Import-VMInfo -Path $VMInfoPath
|
||||
|
||||
& $PSScriptRoot\injector.ps1 $VMInfo.krb5.cred
|
||||
$klistOutput = klist
|
||||
|
||||
$serverping = Test-Connection -ComputerName "server.pn.steinbeis.schule" -Count 2 -Quiet
|
||||
if ($serverping) {
|
||||
if ($klistOutput -like "*Client*") {
|
||||
foreach ($Mount in $VMInfo.Mounts) {
|
||||
net use /persistent:no "$($Mount.Drive):" "$($Mount.RemotePath)"
|
||||
#New-SMBMapping -Localpath "$($Mount.Drive):" -Remotepath $Mount.RemotePath
|
||||
Write-Host("net use $($Mount.Drive): $($Mount.RemotePath)")
|
||||
}
|
||||
} else {
|
||||
#if (-not ($klistOutput -like "*Client*") -or (-not (Test-Path "H:"))) {
|
||||
$Credential = Get-Credential -Message "Die automatische Einbindung der Netzlaufwerke ist fehlgeschlagen.`nBitte geben Sie Ihre Anmeldeinformationen für das Netzlaufwerk ein" $VMInfo.User
|
||||
# Laufwerke einbinden
|
||||
foreach ($Mount in $VMInfo.Mounts) {
|
||||
net use /persistent:no "$($Mount.Drive):" "$($Mount.RemotePath)" /user:"$($Credential.UserName)" "$($Credential.GetNetworkCredential().Password)"
|
||||
Write-Host("net use /persistent:no `"$($Mount.Drive):`" `"$($Mount.RemotePath)`"")
|
||||
#New-SMBMapping -Localpath "$($Mount.Drive):" -Remotepath "$($Mount.RemotePath)" -UserName "$($Credential.UserName)" -Password "$($Credential.GetNetworkCredential().Password)"
|
||||
#Write-Host("New-SMBMapping -Localpath $($Mount.Drive): -Remotepath $Mount.RemotePath")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
$message = "Der Server kann derzeit nicht erreicht werden.`nDaher können die Netzlaufwerke derzeit nicht verbunden werden.`nVersuchen Sie es zu einem späteren Zeitpunkt erneut mit dem Skript: Netzlaufwerke-verbinden"
|
||||
$title = "Server nicht erreichbar"
|
||||
[System.Windows.Forms.MessageBox]::Show($message, $title, [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Warning)
|
||||
}
|
||||
|
||||
# Ändere den Namen der Netzlaufwerke
|
||||
$shell = New-Object -ComObject Shell.Application
|
||||
foreach ($Mount in $VMInfo.Mounts) {
|
||||
$folder = $shell.Namespace("$($Mount.Drive):")
|
||||
if ($folder) {
|
||||
$folder.Self.Name = $Mount.Name
|
||||
Write-Host "Das Netzlaufwerk $($Mount.Drive): wurde in '$($Mount.Name)' umbenannt."
|
||||
} else {
|
||||
Write-Host "Fehler beim Zugriff auf das Netzlaufwerk."
|
||||
}
|
||||
}
|
||||
|
||||
# Pfade zur Schnellzugriff hinzufügen
|
||||
Add-PathToQuickAccess $VMInfo.QuickAccess
|
||||
|
||||
# Pfade für Standardorte ändern
|
||||
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
|
||||
foreach ($USF in $VMInfo.UserShellFolders) {
|
||||
Write-Host "Set-ItemProperty -Path $regPath -Name $($USF.Name) -Value $($USF.Path)"
|
||||
Set-ItemProperty -Path $regPath -Name "$($USF.Name)" -Value "$($USF.Path)"
|
||||
}
|
||||
|
||||
# Explorer Neustart erzwingen (evtl. nicht notwendig)
|
||||
Stop-Process -Name explorer -Force
|
||||
# Start-Process explorer
|
||||
|
||||
# Bei Lehrern Papercut-Client starten
|
||||
if (($VMInfo.Groups -contains "teachers") -and -not (Get-Process -Name pc-client -ErrorAction SilentlyContinue)) {
|
||||
& "C:\custom\papercut\pc-client.exe" -m --user $VMInfo.User
|
||||
}
|
||||
BIN
misc/vm/vm-prepare-user.xml
Executable file
BIN
misc/vm/vm-prepare-user.xml
Executable file
Binary file not shown.
30
misc/vm/vm-update-user.ps1
Normal file
30
misc/vm/vm-update-user.ps1
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Injects krb5-credential from .vminfo.json if available
|
||||
# 02.07.2025 da
|
||||
|
||||
function Import-VMInfo {
|
||||
param (
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
if (Test-Path $Path) {
|
||||
return Get-Content -Path $Path -Raw | ConvertFrom-Json
|
||||
} else {
|
||||
Write-Error "Fehler beim Einlesen der VMInfo Datei ($Path nicht gefunden)."
|
||||
Write-Error "Tipp: Beim Neustart der VM wird diese Datei neu angelegt."
|
||||
Pause
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
$VMInfoPath = "Y:\.vminfo.json"
|
||||
|
||||
# Schleife, die auf das Laufwerk wartet
|
||||
if (-not (Test-Path $VMInfoPath)) {
|
||||
Write-Host "$VMInfoPath nicht gefunden. Skript beenden."
|
||||
exit
|
||||
}
|
||||
|
||||
# VMInfo aus JSON File einlesen
|
||||
$VMInfo = Import-VMInfo -Path $VMInfoPath
|
||||
|
||||
& $PSScriptRoot\injector.ps1 $VMInfo.krb5.cred
|
||||
BIN
misc/vm/vm-update-user.xml
Executable file
BIN
misc/vm/vm-update-user.xml
Executable file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue