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:
Raphael Dannecker 2025-07-02 13:54:19 +02:00
parent 3ff8d48827
commit 6e03863016
12 changed files with 560 additions and 24 deletions

Binary file not shown.

155
misc/vm/injector.ps1 Normal file
View 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

View 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

Binary file not shown.

102
misc/vm/vm-prepare-user.ps1 Normal file
View 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

Binary file not shown.

View 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

Binary file not shown.

View file

@ -19,8 +19,9 @@ done
shift "$((OPTIND -1))"
# link system-VM-Images to User VM Directory
for i in *.qcow2; do
[[ -f "${VM_DIR}/${i}" ]] || ln "${i}" "${VM_DIR}/${i}"
for filename in "$@"; do
filename="$(basename ${filename})"
[[ -f "${VM_DIR}/${filename}" ]] || ln "${filename}" "${VM_DIR}/${filename}"
done
# allow lmnsynci to remove old vm images

View file

@ -96,11 +96,15 @@ create_clone() {
# Create User-VM-Dir and link system VM-Images
[[ -d "${VM_DIR}" ]] || mkdir -p "${VM_DIR}"
IMAGE="${VM_NAME}.qcow2"
while [[ -n ${IMAGE} ]]; do
if [[ "${PERSISTENT}" -eq 1 ]]; then
sudo /usr/local/bin/vm-link-images -p
sudo /usr/local/bin/vm-link-images -p "${IMAGE}"
else
sudo /usr/local/bin/vm-link-images
sudo /usr/local/bin/vm-link-images "${IMAGE}"
fi
IMAGE="$(qemu-img info -U "${VM_DIR}/${IMAGE}" | grep "^backing file:" | cut -d ' ' -f 3)"
done
# Create backing file
cd "${VM_DIR}"
@ -130,18 +134,30 @@ create_printerlist() {
}
create_mountlist() {
if id | grep -q teachers; then
NETHOME=/srv/samba/schools/default-school/teachers/$USER
else
NETHOME=(/srv/samba/schools/default-school/students/*/"$USER")
fi
NETHOME="${NETHOME#/srv/samba/schools}"
cat << EOF > "/lmn/media/${USER}/.mounts.csv"
NETHOMEPART="${NETHOME#/srv/samba/schools}"
cat << EOF > "${VMINFO_DIR}/.mounts.csv"
Drive;Remotepath
H;\\\\10.190.1.1${NETHOME//\//\\}
T;\\\\10.190.1.1\default-school\share
H;\\\\server.pn.steinbeis.schule${NETHOMEPART//\//\\}
T;\\\\server.pn.steinbeis.schule\\default-school\\share
EOF
echo "${USER}" > "/lmn/media/${USER}/.user"
echo "${USER}" > "/${VMINFO_DIR}/.user"
}
start_virtiofs_service() {
local target_name=$1
local shared_dir=$2
local drive_letter=$3
local socket="/run/user/${UID}/virtiofs-${VM_NAME}-${target_name,,}.sock"
systemd-run --user /usr/local/bin/virtiofsd --uid-map=":${GUEST_UID}:${UID}:1:" --gid-map=":${GUEST_GID}:$(id -g):1:" \
--socket-path "${socket}" --shared-dir "${shared_dir}" --syslog
if [[ $? -ne 0 ]]; then
echo "Error starting virtiofsd for ${target_name}." >&2
return 1
fi
LIBVIRTOPTS="${LIBVIRTOPTS} --filesystem driver.type=virtiofs,accessmode=passthrough,target.dir=${target_name},xpath1.set=./source/@socket=${socket}"
}
start_virtiofsd() {
@ -151,9 +167,16 @@ start_virtiofsd() {
[[ "$GUEST_GID" == 0 ]] && GUEST_GID=1010
fi
# END temporary fix
socket="/run/user/$(id -u $USER)/virtiofs-${VM_NAME}.sock"
systemd-run --user /usr/local/bin/virtiofsd --uid-map=:${GUEST_UID}:${UID}:1: --gid-map=:${GUEST_GID}:$(id -g):1: \
--socket-path "$socket" --shared-dir "/lmn/media/${USER}" --syslog
# start_virtiofs_service "VM-Data" "/lmn/media/${USER}" "Y"
# start_virtiofs_service "default-school" "/srv/samba/schools/default-school" "Y"
# Home@PC / VM-Data
if [[ "${HOME}" != "${NETHOME}" ]]; then
start_virtiofs_service "Home_Linux" "${HOME}" "Y"
else
start_virtiofs_service "VM-Data" "/lmn/media/${USER}" "Y"
fi
}
ask_really_persistent() {
@ -322,12 +345,27 @@ if ! virsh --connect="${QEMU}" list | grep "${VM_NAME}-clone"; then
virsh --connect=qemu:///session undefine --nvram "${VM_NAME}-clone" || echo "${VM_NAME}-clone did not exist"
#trap exit_script SIGHUP SIGINT SIGTERM
if id | grep -q teachers; then
NETHOME=/srv/samba/schools/default-school/teachers/$USER
else
NETHOME=(/srv/samba/schools/default-school/students/*/"$USER")
fi
if [[ "${HOME}" != "${NETHOME}" ]]; then
VMINFO_DIR="${HOME}"
else
VMINFO_DIR="/lmn/media/${USER}"
fi
create_printerlist
create_mountlist
# start virtiofsd-service
[[ "${QEMU}" = 'qemu:///session' ]] && start_virtiofsd
# Create VMInfo Json file
#( umask 027; ./vm-create-vminfo > "${VMINFO_DIR}/.vminfo.json" )
# Start vminfo.timer
systemctl --user start vminfo.timer
uuid=$(openssl rand -hex 16)
uuid="${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}"
@ -349,7 +387,6 @@ if ! virsh --connect="${QEMU}" list | grep "${VM_NAME}-clone"; then
--memorybacking source.type=memfd,access.mode=shared \
--disk "${VM_DIR}/${VM_NAME}-clone.qcow2",driver.discard=unmap,target.bus=scsi,cache=writeback \
--network=bridge=virbr0,model.type=virtio \
--filesystem driver.type=virtiofs,accessmode=passthrough,target.dir=virtiofs,xpath1.set=./source/@socket="/run/user/${UID}/virtiofs-${VM_NAME}.sock" \
--controller type=scsi,model=virtio-scsi \
--check path_in_use=off \
--connect="${QEMU}" \

113
roles/lmn_vm/files/vm-vminfo Executable file
View file

@ -0,0 +1,113 @@
#!/usr/bin/python3
import argparse
import struct
import subprocess
import json
from os import environ,path
from impacket.krb5.ccache import CCache
from base64 import b64encode
home = ""
nethome = ""
vminfo = {}
def get_printers():
printers = []
try:
result = subprocess.run(['lpstat', '-v'], capture_output=True, text=True, check=True)
for line in result.stdout.splitlines():
# Extrahiere den Druckernamen
printer_name = line.split()[2].rstrip(':')
ipp_url = f"ipp://192.168.122.1/printers/{printer_name}"
printer = { 'Name': printer_name, 'IppURL': ipp_url }
printers.append(printer)
return printers
except subprocess.CalledProcessError as e:
print(f"Fehler beim Abrufen der Drucker: {e}")
return []
def get_groups(username):
try:
result = subprocess.run(['id', '-Gnz', username], capture_output=True, text=True, check=True)
groups = result.stdout.strip().split('\0')
return groups
except subprocess.CalledProcessError as e:
print(f"Fehler beim Abrufen der Gruppen: {e}")
return []
def get_krb5 ():
krb5 = {}
ccachefilename = environ.get('KRB5CCNAME').replace('FILE:', '')
if ccachefilename:
try:
ccache = CCache.loadFile(ccachefilename)
cred = ccache.toKRBCRED()
cred_enc = b64encode(cred)
krb5['cred'] = cred_enc.decode('utf-8')
krb5['starttime'] = ccache.credentials[0]['time']['starttime']
krb5['endtime'] = ccache.credentials[0]['time']['endtime']
krb5['renew_till'] = ccache.credentials[0]['time']['renew_till']
except:
print("Fehler beim Ticket laden")
return krb5
def get_mounts():
mounts = []
mounts.append({ 'Drive': 'H', 'RemotePath': '\\\\server.pn.steinbeis.schule' + nethome.replace('/srv/samba/schools','').replace('/','\\'), 'Name': 'Home_Server' })
mounts.append({ 'Drive': 'T', 'RemotePath': '\\\\server.pn.steinbeis.schule\default-school\share', 'Name': 'Tausch' })
return mounts
def get_user_folders():
HOME="H:"
if environ.get('HOME') != nethome:
HOME="Y:"
folders = []
folders.append( {'Name': 'Personal', 'Path': f"{HOME}\Dokumente"} )
folders.append( {'Name': 'My Pictures', 'Path': f"{HOME}\Bilder"} )
folders.append( {'Name': 'My Music', 'Path': f"{HOME}\Musik"} )
folders.append( {'Name': 'My Video', 'Path': f"{HOME}\Videos"} )
return folders
def get_quickaccess():
quickaccess = []
quickaccess.append( 'H:\\transfer' )
return quickaccess
def parse_args():
parser = argparse.ArgumentParser()
#parser.add_argument('input_file', help="File in kirbi (KRB-CRED) or ccache format")
#parser.add_argument('output_file', help="Output file")
return parser.parse_args()
def main():
global home, nethome
args = parse_args()
home = environ.get('HOME')
vminfo['User'] = environ.get('USER')
vminfo['Groups'] = get_groups(environ.get('USER'))
if 'teachers' in vminfo['Groups']:
nethome = f"/srv/samba/schools/default-school/teachers/{vminfo['User']}"
else:
result = subprocess.run(['find', '/srv/samba/schools/default-school/students/', '-name', vminfo['User'], '-maxdepth', '2', '-type', 'd'], capture_output=True, text=True, check=False)
nethome = result.stdout
vminfo['Printers'] = get_printers()
vminfo['krb5'] = get_krb5()
vminfo['Mounts'] = get_mounts()
vminfo['UserShellFolders'] = get_user_folders()
vminfo['QuickAccess'] = get_quickaccess()
vminfo_json = json.dumps(vminfo, ensure_ascii=False, indent=4)
print(vminfo_json)
if __name__ == '__main__':
main()

View file

@ -20,6 +20,7 @@
- virt-manager
- virt-viewer
- dialog # for vm-netboot menu
- python3-impacket
# - name: allow all users to use VMs
# lineinfile:
@ -124,6 +125,7 @@
- vm-sync
- vm-link-images
- vm-virtiofsd
- vm-vminfo
- virtiofsd
- vm-aria2
- uploadseed
@ -211,3 +213,26 @@
src: vm-netboot
dest: /usr/local/bin/
mode: '0755'
- name: Provide vminfo service
ansible.builtin.copy:
content: |
[Unit]
Description=Create .vminfo.json for VMs
[Service]
Type=simple
ExecStart=/usr/bin/bash -c 'umask 027; /usr/local/bin/vm-vminfo > "{% if localhome %}~{% else %}/lmn/media/${USER}{% endif %}/.vminfo.json"'
dest: /etc/systemd/user/vminfo.service
mode: '0644'
- name: Provide vminfo timer
ansible.builtin.copy:
content: |
[Unit]
Description=Timer for vm-info
[Timer]
OnActiveSec=0s
OnUnitActiveSec=1h
Persistent=true
dest: /etc/systemd/user/vminfo.timer
mode: '0644'