Compare commits

..

No commits in common. "main" and "fvs" have entirely different histories.
main ... fvs

54 changed files with 818 additions and 1764 deletions

View file

@ -1,12 +1,6 @@
# Installation on existing client # Installation on existing client
A straightforward way to test the lmn-client is to manually run the playbook on a freshly installed client. An easy method to test the lmn-client is to run the playbook manual on a fresh installed client.
This can be done in the following ways:
On the client using ansible-pull
On the client by checking out the lmn-client repository and running the playbook locally
On a target device by checking out the lmn-client repository locally and executing the playbook against the target device
## Direct call via ansible-pull ## Direct call via ansible-pull
@ -15,10 +9,10 @@ With two simple commands you can install the lmn-client with default configurati
Steps: Steps:
* Install debian on client (via USB or PXE) * Install debian on client (via USB or PXE)
* Install additional packages: ansible * Install additional packages: ansible
`sudo apt install ansible` `sudo apt install ansible`
* Run Playbook * Run Playbook
`sudo ansible-pull --verbose -i inventory-sample.yml -l localhost --url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git -C main lmn-client.yml` `ansible-pull -i inventory.yml -l localhost, --url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git -C main lmn-client.yml`
## Checkout git and run ansible locally ## Checkout git and run ansible locally
@ -30,12 +24,10 @@ Steps:
* Install debian on client (via USB or PXE) * Install debian on client (via USB or PXE)
* Install additional packages: ansible, git * Install additional packages: ansible, git
`sudo apt install ansible git` `sudo apt install ansible git`
* Checkout Repository * Checkout Repository
`git clone https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git` `git clone https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git`
* Change into repository directory
`cd lmn-client`
* Create inventory * Create inventory
`cp inventory-sample.yml inventory-myschool.yml` `cp inventory.yml inventory-myschool.yml`
* Edit inventory-myschool.yml * Edit inventory-myschool.yml
e.g.: `nano inventory-myschool.yml` e.g.: `nano inventory-myschool.yml`
* Run Playbook * Run Playbook

View file

@ -2,28 +2,15 @@
* **Using DigitalSouveraeneSchule repository and LinuxMuster.Net tftp** * **Using DigitalSouveraeneSchule repository and LinuxMuster.Net tftp**
Simplest solution. Playbook and default inventory from DigitalSouveraeneSchule codeberg repository. Simplest solution. Playbook and default inventory from DigitalSouveraeneSchule codeberg repository.
Linux kernel and initial Ramdisk from debian repository. Linux kernel and initial Ramdisk from debian repository.
Client must have access to the internet (noproxy group).
* **Using your own repository and LinuxMuster.Net tftp** * **Using your own repository and LinuxMuster.Net tftp**
Here you can use your own inventory and make many custom settings. Here you can use your own inventory and make many custom settings.
Linux kernel and initial Ramdisk from debian repository. Linux kernel and initial Ramdisk from debian repository.
Client must have access to the internet (noproxy group).
* **Using your own repository and livebox tftp** * **Using your own repository and livebox tftp**
Additional kernel and Ramdisk from your own infrastrukture. Additional kernel and Ramdisk from your own infrastrukture.
Client does not need direct internet access.
## Using codeberg repository and LinuxMuster.Net tftp ## Using codeberg repository and LinuxMuster.Net tftp
### Requirements / firewall settings
The computer on which the linuxclient is to be installed must have access to the Internet (add host to noproxy group)
The following resources are downloaded from the internet:
* The repository is provided by codeberg.org
* the Linux kernel, the initial ramdisk and the installation files are loaded from debian.org.
* mscorefonts from Microsoft
### Modification LinuxMuster.Net server ### Modification LinuxMuster.Net server
Create grub config for device group `lmnclient` on your schools server: Create grub config for device group `lmnclient` on your schools server:
@ -38,12 +25,9 @@ set default=1
menuentry 'Installer Debian bookworm (amd64) + preseed + ansible inventory' { menuentry 'Installer Debian bookworm (amd64) + preseed + ansible inventory' {
echo -n "Enter domain join password: " echo -n "Enter domain join password: "
read adpw read adpw
set vaultpw="dummy"
# echo -n "Enter vault password"
# read vaultpw
linux (http,ftp.debian.org)/debian/dists/stable/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux auto=true priority=high \ linux (http,ftp.debian.org)/debian/dists/stable/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux auto=true priority=high \
url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client/raw/branch/main/misc/preseed.cfg interface=auto \ url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client/raw/branch/fvs/misc/preseed.cfg interface=auto \
playbook=lmn-client.yml adpw="${adpw}" vaultpw="${vaultpw}" --- playbook=lmn-client.yml adpw="${adpw}" ---
initrd (http,ftp.debian.org)/debian/dists/stable/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz initrd (http,ftp.debian.org)/debian/dists/stable/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz
} }
``` ```
@ -63,52 +47,4 @@ classroom;mypc01;lmnclient;F2:81:6B:C9:E3:EF;10.0.5.51;;;;classroom-studentcompu
* confirm `hostname` and `domain` (you will be asked in network setup) * confirm `hostname` and `domain` (you will be asked in network setup)
* ... Get a cup of coffee ... wait until reboot ... login (Logging in may take a few minutes after installation) * ... Get a cup of coffee ... wait until reboot ... login (Logging in may take a few minutes after installation)
## Using your own livebox server
## Using your own repository and LinuxMuster.Net tftp
If you fork the lmn-client repository, you can customize the preseeding and inventory to your needs.
Use the instructions in the previous section and customize the repository in `/srv/linbo/boot/grub/lmnclient.cfg`.
It makes sense to encrypt your inventory via `ansible-vault`.
When using encrypted inventories you have to provide the vault password by commenting in the two lines in the `/srv/linbo/boot/grub/lmnclient.cfg`.
## Using your own repository and livebox tftp
The next improvement will be to use your own livebox with following functionalities:
* Providing linux kernel and initial ramdisk for installer
* Can be used as cache for debian packages (aptcacher)
* Can provide mscorefonts and libdvdcss (multimedia codecs)
* Can be used to boot live systems (netboot) via pxe
### Installing the livebox server
* Install debian VM and configure network
* Install additional packages: ansible
`sudo apt install ansible`
* Run livebox playbook
`ansible-pull -i localhost, --url=https://salsa.debian.org/andi/debian-lan-ansible.git -C master livebox.yml`
* Set DNS entry for your new livebox server
### Modification LinuxMuster.Net server
The file `/srv/linbo/boot/grub/lmnclient.cfg` might look like this:
```
# ### NOT managed by linuxmuster.net ###
# edit to your needs
set default=1
menuentry 'Installer Debian bookworm (amd64) + preseed + ansible inventory' {
echo -n "Enter domain join password: "
read adpw
set vaultpw="dummy"
# echo -n "Enter vault password"
# read vaultpw
linux (http,livebox.example.com)/d-i/n-pkg/images/12/amd64/text/debian-installer/amd64/linux auto=true priority=high \
url=https://codeberg.org/MySchool/lmn-client/raw/branch/main/misc/preseed-myschool.cfg interface=auto \
playbook=lmn-client.yml adpw="${adpw}" vaultpw="${vaultpw}" ---
initrd (http,livebox.example.com)/d-i/n-pkg/images/12/amd64/text/debian-installer/amd64/initrd.gz
}
```

View file

@ -2,9 +2,10 @@
all: all:
vars: vars:
domain: "{{ ansible_domain }}" domain: "{{ ansible_domain }}"
# Comment out on productive systems when ssh key is provided
security_defaultuser_login_disable: false security_defaultuser_login_disable: false
kde_desktop_pkg:
- akonadi-backend-sqlite
## Proxy configuration (see: doc/localproxy.md) ## Proxy configuration (see: doc/localproxy.md)
# localproxy: true # localproxy: true
@ -58,6 +59,7 @@ all:
# - vim # - vim
# - mc # - mc
# - tmux # - tmux
# - debconf-utils
## WLAN configuration (see: doc/vpn.md): ## WLAN configuration (see: doc/vpn.md):
## ##
@ -103,7 +105,6 @@ all:
hosts: hosts:
localhost: localhost:
ansible_connection: local
laptops: laptops:
children: children:

File diff suppressed because it is too large Load diff

View file

@ -49,7 +49,6 @@
- lmn_network - lmn_network
- role: up2date_debian - role: up2date_debian
tags: upgrade tags: upgrade
- lmn_encrypt
- lmn_sssd - lmn_sssd
- lmn_mount - lmn_mount
- lmn_kde - lmn_kde
@ -64,7 +63,7 @@
- role: lmn_localhome - role: lmn_localhome
when: localhome when: localhome
- role: lmn_localuser - role: lmn_localuser
when: localuser|bool when: localuser
- role: lmn_exam - role: lmn_exam
when: exam_mode when: exam_mode
- role: lmn_wlan - role: lmn_wlan
@ -81,17 +80,15 @@
loop_var: rolename loop_var: rolename
when: custom_roles is defined when: custom_roles is defined
- name: Import role security - name: Final tasks
ansible.builtin.import_role: ansible.builtin.include_role:
name: lmn_security name: "{{ role }}"
loop_control:
- name: Import role finish loop_var: role
ansible.builtin.import_role: loop:
name: lmn_finish - lmn_security
- lmn_finish
- name: Import role tmpfixes - lmn_tmpfixes
ansible.builtin.import_role:
name: lmn_tmpfixes
- name: Apply roles that must run serial - name: Apply roles that must run serial

View file

@ -50,11 +50,13 @@ d-i apt-setup/contrib boolean true
d-i mirror/country string manual d-i mirror/country string manual
d-i mirror/http/hostname string deb.debian.org d-i mirror/http/hostname string deb.debian.org
d-i mirror/http/directory string /debian d-i mirror/http/directory string /debian
#d-i mirror/http/proxy string http://aptcache.pn.steinbeis.schule:3142/ #d-i mirror/http/proxy string http://10.167.0.253:3142/
d-i mirror/http/proxy string #d-i mirror/http/proxy string http://192.168.1.17:3142/
#d-i mirror/http/proxy string http://aptcache.steinbeisschule-reutlingen.de:3142/
d-i mirror/http/proxy string http://aptcache.pn.steinbeis.schule:3142/
# NTP server to use: # NTP server to use:
#d-i clock-setup/ntp-server string server.pn.steinbeis.schule d-i clock-setup/ntp-server string server.pn.steinbeis.schule
### Backports: ### Backports:
#apt-setup-udeb apt-setup/services-select multiselect security, updates, backports #apt-setup-udeb apt-setup/services-select multiselect security, updates, backports
@ -127,9 +129,10 @@ d-i preseed/late_command string \
in-target mount -v -t tmpfs tmpfs /dev/shm ; \ in-target mount -v -t tmpfs tmpfs /dev/shm ; \
echo "$vaultpw" > /target/dev/shm/vaultpw ; \ echo "$vaultpw" > /target/dev/shm/vaultpw ; \
in-target ansible-pull --verbose --purge --extra-vars="run_in_installer=true" \ in-target ansible-pull --verbose --purge --extra-vars="run_in_installer=true" \
--vault-password-file /dev/shm/vaultpw -l localhost \ -l localhost \
-i inventory-sample.yml --url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git -C main $playbook ; \ -i inventory-sample.yml --url=https://codeberg.org/DigitalSouveraeneSchule/lmn-client.git -C fvs $playbook ; \
fi fi
## --vault-password-file /dev/shm/vaultpw -l localhost \
# #
## When installing in combination with ansible-pull, ## When installing in combination with ansible-pull,
## export your ansible playbook like: ## export your ansible playbook like:

View file

@ -1,155 +0,0 @@
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

@ -1,73 +0,0 @@
# 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"
}
}

Binary file not shown.

View file

@ -1,102 +0,0 @@
# 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
}

Binary file not shown.

View file

@ -1,30 +0,0 @@
# 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

Binary file not shown.

View file

@ -16,16 +16,11 @@ fi
id="$(grep ID "$file" | sed -E "s|^.+ID>([[:digit:]]+)/([[:digit:]]+)</ID.+$|\1:\2|" \ id="$(grep ID "$file" | sed -E "s|^.+ID>([[:digit:]]+)/([[:digit:]]+)</ID.+$|\1:\2|" \
| sort -n -t: -k2 | tail -1 )" | sort -n -t: -k2 | tail -1 )"
for dir in teachers examusers staff parents; do if id | grep -q teachers; then
if [[ -d "/srv/samba/schools/default-school/${dir}/${USER}" ]]; then NETHOME=/srv/samba/schools/default-school/teachers/$USER
NETHOME="/srv/samba/schools/default-school/${dir}/${USER}" else
break
fi
done
if [[ -z "${NETHOME+x}" ]]; then
NETHOME=(/srv/samba/schools/default-school/students/*/"$USER") NETHOME=(/srv/samba/schools/default-school/students/*/"$USER")
fi fi
[[ -d $NETHOME ]] || exit 0 [[ -d $NETHOME ]] || exit 0
IDENTITY="${id%%:*}" IDENTITY="${id%%:*}"
@ -54,7 +49,7 @@ fi
patch=" patch="
--- a/$file --- a/$file
+++ b/$file +++ b/$file
@@ -98,9 +98,33 @@ @@ -98,9 +98,45 @@
<isSystemItem>true</isSystemItem> <isSystemItem>true</isSystemItem>
</metadata> </metadata>
</info> </info>
@ -71,6 +66,18 @@ $HOMEONSERVER
+ <isSystemItem>true</isSystemItem> + <isSystemItem>true</isSystemItem>
+ </metadata> + </metadata>
+ </info> + </info>
+ </bookmark>
+ <bookmark href=\"file:///lmn/media/$USER/nextcloud\">
+ <title>Nextcloud</title>
+ <info>
+ <metadata owner=\"http://freedesktop.org\">
+ <bookmark:icon name=\"folder-cloud\"/>
+ </metadata>
+ <metadata owner=\"http://www.kde.org\">
+ <ID>$IDENTITY/${NUM3}</ID>
+ <isSystemItem>true</isSystemItem>
+ </metadata>
+ </info>
+ </bookmark> + </bookmark>
<bookmark href=\"remote:/\"> <bookmark href=\"remote:/\">
<title>Network</title> <title>Network</title>

View file

@ -12,7 +12,7 @@ fi
#rsync -rlptD --chown=pgmadmin:root --chmod=F755,D755 rsync://server:/local-program/ /usr/local/lmn #rsync -rlptD --chown=pgmadmin:root --chmod=F755,D755 rsync://server:/local-program/ /usr/local/lmn
RSYNC_COMMAND=$(rsync -ai --delete --exclude=mimeinfo.cache \ RSYNC_COMMAND=$(rsync -ai --delete --exclude=mimeinfo.cache \
--chown=root:root --chmod=F644,D755 "rsync://fileserver:/desktopstarter" \ --chown=root:root --chmod=F644,D755 "rsync://server:/desktopstarter" \
/usr/local/share/applications/ | sed '/ \.\//d') /usr/local/share/applications/ | sed '/ \.\//d')
if [[ $? -eq 0 ]] && [[ -n "${RSYNC_COMMAND}" ]]; then if [[ $? -eq 0 ]] && [[ -n "${RSYNC_COMMAND}" ]]; then
echo "${RSYNC_COMMAND}" echo "${RSYNC_COMMAND}"

View file

@ -3,9 +3,9 @@
"Proxy": { "Proxy": {
"Mode": "autoDetect" "Mode": "autoDetect"
}, },
"OverrideFirstRunPage": "https://www.steinbeis.schule", "OverrideFirstRunPage": "https://www.steinbeisschule-reutlingen.de",
"Homepage": { "Homepage": {
"URL": "https://www.steinbeis.schule", "URL": "https://www.steinbeisschule-reutlingen.de",
"Locked": false, "Locked": false,
"StartPage": "previous-session" "StartPage": "previous-session"
}, },
@ -15,7 +15,7 @@
"toplevel_name": "FvS-Reutlingen" "toplevel_name": "FvS-Reutlingen"
}, },
{ {
"url": "https://www.steinbeis.schule", "url": "https://www.steinbeisschule-reutlingen.de",
"name": "FvS-Homepage" "name": "FvS-Homepage"
}, },
{ {
@ -27,7 +27,7 @@
"name": "FvS-eMail" "name": "FvS-eMail"
}, },
{ {
"url": "https://info.steinbeis.schule", "url": "https://dw.steinbeis.schule",
"name": "FvS-Hilfesystem" "name": "FvS-Hilfesystem"
}, },
{ {
@ -35,23 +35,15 @@
"name": "FvS-Moodle" "name": "FvS-Moodle"
}, },
{ {
"url": "https://cloud.steinbeis.schule", "url": "https://nc.steinbeis.schule",
"name": "FvS-Schulcloud" "name": "FvS-Nextcloud"
},
{
"url": "https://nct.steinbeis.schule",
"name": "FvS-Nextcloud-Teacher (Nur für Lehrer)"
},
{
"url": "https://git.steinbeis.schule",
"name": "FvS-Git Versionsverwaltung"
}, },
{ {
"url": "https://server.pn.steinbeis.schule", "url": "https://server.pn.steinbeis.schule",
"name": "Schulkonsole" "name": "Schulkonsole"
}, },
{ {
"url": "https://steinbeis.webuntis.com/WebUntis/?school=steinbeis#/basic/login", "url": "https://peleus.webuntis.com/WebUntis/?school=Ferd.von+Steinbeis#/basic/login",
"name": "FvS-Stundenplan" "name": "FvS-Stundenplan"
}, },
{ {

View file

@ -29,6 +29,7 @@
- elpa-magit - elpa-magit
- emacs - emacs
- filezilla - filezilla
- freeplane
- git - git
- git-cola - git-cola
- gitg - gitg
@ -45,7 +46,6 @@
- libasound2-dev - libasound2-dev
- libdbus-glib-1-2 ## needed for zotero - libdbus-glib-1-2 ## needed for zotero
- libnotify-bin ## needed for pwroff script - libnotify-bin ## needed for pwroff script
- libsqlite3-dev
- libwayland-dev - libwayland-dev
- libxcursor-dev - libxcursor-dev
- libxi-dev - libxi-dev
@ -62,7 +62,6 @@
- okular-extra-backends ## needed for CHM files - okular-extra-backends ## needed for CHM files
- pdf-presenter-console - pdf-presenter-console
- php-cli - php-cli
- php-sqlite3
- pipx - pipx
- planner - planner
- pulseview - pulseview
@ -83,7 +82,7 @@
- unison-gtk - unison-gtk
- w3m - w3m
- wireshark - wireshark
# - zulucrypt-gui ## no longer in trixie - zulucrypt-gui
autoremove: true autoremove: true
state: latest state: latest
environment: environment:
@ -163,16 +162,6 @@
dest: /usr/share/plasma/shells/org.kde.plasma.desktop/contents/updates/fvs-config.js dest: /usr/share/plasma/shells/org.kde.plasma.desktop/contents/updates/fvs-config.js
mode: '0644' mode: '0644'
- name: Configure default KDE applications
ansible.builtin.blockinfile:
path: /etc/xdg/mimeapps.list
create: true
mode: '0644'
block: |
[Default Applications]
x-scheme-handler/http=firefox-esr.desktop;
x-scheme-handler/https=firefox-esr.desktop;
x-scheme-handler/mailto=thunderbird.desktop;
- name: Configure some KDE aspects - name: Configure some KDE aspects
ansible.builtin.blockinfile: ansible.builtin.blockinfile:
@ -181,11 +170,11 @@
mode: '0644' mode: '0644'
block: | block: |
[KDE] [KDE]
#SingleClick=false SingleClick=false
[KDE Action Restrictions][$i] [KDE Action Restrictions][$i]
action/start_new_session=false action/start_new_session=false
action/switch_user=false #action/switch_user=false
#action/lock_screen=false #action/lock_screen=false
- name: Start with empty session by default - name: Start with empty session by default
@ -231,7 +220,7 @@
ansible.builtin.blockinfile: ansible.builtin.blockinfile:
path: /usr/share/sddm/themes/debian-breeze/Main.qml path: /usr/share/sddm/themes/debian-breeze/Main.qml
marker: // {mark} ANSIBLE MANAGED BLOCK marker: // {mark} ANSIBLE MANAGED BLOCK
insertbefore: '^}$' insertbefore: '\s+//Footer'
block: | block: |
Text { Text {
id: hostname id: hostname
@ -260,12 +249,5 @@
KERNEL=="mmcblk[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", GROUP="domain users" KERNEL=="mmcblk[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", GROUP="domain users"
KERNEL=="mmcblk[0-9]p[0-9]*", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", GROUP="domain users" KERNEL=="mmcblk[0-9]p[0-9]*", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", GROUP="domain users"
- name: Set KiCad 3Dmodel path
ansible.builtin.lineinfile:
path: /etc/environment.d/90lmn-kicad.conf
create: true
mode: '0644'
line: KICAD9_3DMODEL_DIR=/lmn/tools/KiCad/kicad-packages3D
- name: Include sync - name: Include sync
ansible.builtin.include_tasks: sync.yml ansible.builtin.include_tasks: sync.yml

View file

@ -1,3 +0,0 @@
---
encrypt_passphrase_initial: Muster!
encrypt_tpm2: false

View file

@ -1,5 +0,0 @@
- name: Run update-grub
ansible.builtin.command: update-grub
- name: Run update-dracut
ansible.builtin.command: dracut -f

View file

@ -1,46 +0,0 @@
---
- name: Find device with LUKS holder
vars:
partitions: "{{ item.value.partitions | dict2items | selectattr('value.holders', 'search', 'luks|crypt') }}"
ansible.builtin.set_fact:
encrypt_device: "/dev/disk/by-id/{{ partitions[0].value.links.ids[0] }}"
when:
- item.value.partitions is defined
- item.value.partitions | dict2items | length > 0
- item.value.partitions | dict2items | selectattr('value.holders', 'search', 'luks|crypt') | length > 0
loop: "{{ ansible_devices | dict2items }}"
- name: Get luks slots
ansible.builtin.command:
cmd: "systemd-cryptenroll {{ encrypt_device }}"
register: encrypt_slots_result
changed_when: false
when: encrypt_device is defined
- name: Change Password of Luks password slot
ansible.builtin.command:
cmd: >
systemd-run -P --wait
-p SetCredential=cryptenroll.passphrase:{{ encrypt_passphrase_initial }}
-p SetCredential=cryptenroll.new-passphrase:{{ encrypt_passphrase }}
systemd-cryptenroll --password {{ encrypt_device }} --wipe-slot=password
no_log: true
when:
- encrypt_device is defined
- encrypt_passphrase is defined
- encrypt_slots_result.stdout_lines | length == 2
- encrypt_slots_result.stdout_lines[1].startswith(' 0')
- name: TPM Device Check
ansible.builtin.stat:
path: /dev/tpm0
register: tpm_device
when: encrypt_device is defined
- name: Include TPM2 role
ansible.builtin.include_tasks:
file: tpm2.yml
when:
- encrypt_device is defined
- encrypt_tpm2
- tpm_device.stat.exists

View file

@ -1,42 +0,0 @@
---
- name: Install tpm2-tools and dracut
ansible.builtin.apt:
name:
- tpm2-tools
- dracut
- name: Enable tpm2-tss crypt module on dracut
ansible.builtin.copy:
dest: /etc/dracut.conf.d/crypt.conf
content: add_dracutmodules+=" tpm2-tss crypt "
mode: '0644'
notify: Run update-dracut
- name: Comment out root device in crypttab
ansible.builtin.lineinfile:
dest: /etc/crypttab
regexp: '^([^#].*)'
line: '#\1'
backrefs: true
- name: Insert luks support to GRUB_CMDLINE_LINUX
ansible.builtin.lineinfile:
dest: /etc/default/grub
regexp: '^(GRUB_CMDLINE_LINUX=).*'
line: '\1"rd.auto rd.luks=1"'
backrefs: true
notify: Run update-grub
- name: Insert TPM2 to Luks slot
ansible.builtin.command:
cmd: >
systemd-run -P --wait
-p SetCredential=cryptenroll.passphrase:{{ encrypt_passphrase | default(encrypt_passphrase_initial) }}
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 {{ encrypt_device }} --wipe-slot=tpm2
no_log: true
when: "'tpm2' not in encrypt_slots_result.stdout"
# - name: Update TPM2 Luks slot
# ansible.builtin.command:
# cmd: systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7+8 --unlock-tpm2-device=auto {{ encrypt_device }} --wipe-slot=tpm2
# when: not grub_config.changed

View file

@ -1,3 +1,2 @@
--- ---
exam_mode: true exam_mode: true
exam_teacherpc_last_digit: 80

View file

@ -5,16 +5,10 @@
if [[ "${PAM_USER}" =~ -exam$ ]]; then if [[ "${PAM_USER}" =~ -exam$ ]]; then
systemctl start firewalld.service systemctl start firewalld.service
if [[ -f /usr/local/sbin/no-way-out-nftable ]]; then
/usr/local/sbin/no-way-out-nftable || true
fi
if systemctl is-enabled --quiet libvirtd.service; then if systemctl is-enabled --quiet libvirtd.service; then
systemctl restart libvirtd.service systemctl restart libvirtd.service
fi fi
elif ! (users | grep -q -- "-exam"); then elif ! (users | grep -q -- "-exam"); then
if /usr/sbin/nft list tables | /usr/bin/grep -q filtermacvtap; then
/usr/sbin/nft delete table netdev filtermacvtap || true
fi
systemctl stop firewalld.service systemctl stop firewalld.service
if systemctl is-enabled --quiet libvirtd.service; then if systemctl is-enabled --quiet libvirtd.service; then
systemctl restart libvirtd.service systemctl restart libvirtd.service

View file

@ -50,37 +50,6 @@
- pam-exec.sh - pam-exec.sh
- rmexam - rmexam
- name: Append teacherPC to exam_destination_allowed_ipv4 addresses
ansible.builtin.set_fact:
exam_destination_allowed_ipv4: "{{ exam_destination_allowed_ipv4 + [ ansible_default_ipv4.address[:-1] ~ exam_teacherpc_last_digit ] }}"
when:
- exam_destination_allowed_ipv4 is defined
- exam_destination_allowed_ipv4 | length > 0
- name: Install no-way-out-policy
ansible.builtin.template:
src: no-way-out.xml.j2
dest: "/etc/firewalld/policies/no-way-out-{{ item }}.xml"
mode: '0644'
vars:
zones:
- HOST
- "{{ 'libvirt' if vm_support | default(false) else '' }}"
loop: "{{ zones | reject('match','^$') }}"
when:
- exam_destination_allowed_ipv4 is defined
- exam_destination_allowed_ipv4 | length > 0
- name: Install no-way-out nf-table for macvtap device
ansible.builtin.template:
src: no-way-out-nftable.j2
dest: "/usr/local/sbin/no-way-out-nftable"
mode: '0755'
when:
- exam_destination_allowed_ipv4 is defined
- exam_destination_allowed_ipv4 | length > 0
- vm_support is defined and vm_support
- name: Enable login script via pam_exec.so - name: Enable login script via pam_exec.so
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
dest: /etc/pam.d/common-session dest: /etc/pam.d/common-session

View file

@ -1,43 +0,0 @@
#!/usr/bin/bash
set -eu
interfaces=$(/usr/bin/ip link | /usr/bin/sed -En 's/.*(macvtap-.*)@.*/\1/p')
gateway=$(/usr/bin/ip route list default | /usr/bin/head -1 | /usr/bin/cut -f 3 -d " ")
filterchain=""
for interface in ${interfaces}; do
filterchain=$(cat <<- EOF
${filterchain}
chain filterin_${interface} {
type filter hook ingress device ${interface} priority filter; policy drop;
ip saddr \$allowed_ipv4 accept
ip saddr ${gateway} accept
ip saddr 255.255.255.255 accept
ether type arp accept
}
chain filterout_${interface} {
type filter hook egress device ${interface} priority filter; policy drop;
ip daddr \$allowed_ipv4 accept
ip daddr ${gateway} accept
ip daddr 255.255.255.255 accept
ether type arp accept
}
EOF
)
done
nft_table=$(cat <<- EOF
define allowed_ipv4 = { {{ exam_destination_allowed_ipv4 | join(",") }} }
table netdev filtermacvtap {
${filterchain}
}
EOF
)
echo "$nft_table" | /usr/sbin/nft -f -

View file

@ -1,10 +0,0 @@
<policy target="REJECT">
{% for address in exam_destination_allowed_ipv4 %}
<rule family="ipv4">
<destination address="{{ address }}"/>
<accept/>
</rule>
{% endfor %}
<ingress-zone name="{{ item }}"/>
<egress-zone name="ANY"/>
</policy>

View file

@ -1,4 +0,0 @@
---
- name: Reboot client
ansible.builtin.command:
cmd: "shutdown -r -t 60"

View file

@ -6,8 +6,6 @@
- "{{ extra_pkgs }}" - "{{ extra_pkgs }}"
- "{{ extra_pkgs1 }}" - "{{ extra_pkgs1 }}"
- "{{ extra_pkgs2 }}" - "{{ extra_pkgs2 }}"
tags:
- baseinstall
- name: Add backports for {{ ansible_distribution_release }} - name: Add backports for {{ ansible_distribution_release }}
ansible.builtin.apt_repository: ansible.builtin.apt_repository:
@ -16,7 +14,7 @@
main non-free-firmware main non-free-firmware
state: present state: present
update_cache: true update_cache: true
when: extra_pkgs_bpo | length > 0 or extra_pkgs_bpo1 | length > 0 or extra_pkgs_bpo2 | length > 0 # when: extra_pkgs_bpo|length
- name: Install extra packages from backports - name: Install extra packages from backports
ansible.builtin.apt: ansible.builtin.apt:
@ -27,19 +25,6 @@
- "{{ extra_pkgs_bpo }}" - "{{ extra_pkgs_bpo }}"
- "{{ extra_pkgs_bpo1 }}" - "{{ extra_pkgs_bpo1 }}"
- "{{ extra_pkgs_bpo2 }}" - "{{ extra_pkgs_bpo2 }}"
when: extra_pkgs_bpo | length > 0 or extra_pkgs_bpo1 | length > 0 or extra_pkgs_bpo2 | length > 0
- name: Check if former ansible-stamp exists
ansible.builtin.stat:
path: /var/local/ansible-stamps
register: stamp_exists
- name: Trigger Reboot if no former ansible-run is found
ansible.builtin.debug:
msg: "First Ansible-Run on Client - Reboot handler started"
changed_when: not stamp_exists.stat.exists
notify: "Reboot client"
- name: Timestamp successfull run and send up-to-date report - name: Timestamp successfull run and send up-to-date report
ansible.builtin.shell: ansible.builtin.shell:

View file

@ -6,7 +6,6 @@ kde_desktop_pkg:
- calligra - calligra
- codeblocks - codeblocks
- dia - dia
- filius
- flameshot - flameshot
- freecad - freecad
- fritzing - fritzing
@ -15,9 +14,8 @@ kde_desktop_pkg:
- inkscape - inkscape
- kde-full - kde-full
- keepassxc - keepassxc
- kicad
- kicad-doc-de
- librecad - librecad
- mu-editor
- openboard - openboard
- qtcreator - qtcreator
- spyder - spyder
@ -36,5 +34,3 @@ kde_desktop_pkg:
- xdg-desktop-portal-kde - xdg-desktop-portal-kde
- xdg-desktop-portal-wlr # share screen in browser - xdg-desktop-portal-wlr # share screen in browser
- xournalpp - xournalpp
kde_desktop_pkg_bpo: [ ]

View file

@ -8,14 +8,19 @@
repo: deb http://deb.debian.org/debian/ {{ ansible_distribution_release }}-backports main non-free-firmware repo: deb http://deb.debian.org/debian/ {{ ansible_distribution_release }}-backports main non-free-firmware
state: present state: present
update_cache: true update_cache: true
when: kde_desktop_pkg_bpo | length > 0
- name: Install extra packages from backports - name: Install extra packages from backports
ansible.builtin.apt: ansible.builtin.apt:
name: "{{ kde_desktop_pkg_bpo }}" name:
- filius
- kicad
- kicad-doc-de
- libreoffice
- libreoffice-l10n-de
- libreoffice-qt5
state: latest # noqa package-latest
autoremove: true autoremove: true
default_release: "{{ ansible_distribution_release }}-backports" default_release: "{{ ansible_distribution_release }}-backports"
when: kde_desktop_pkg_bpo | length > 0
- name: Create akonadi config dir - name: Create akonadi config dir

View file

@ -9,7 +9,7 @@
ansible.builtin.blockinfile: ansible.builtin.blockinfile:
path: /usr/share/sddm/themes/debian-breeze/Main.qml path: /usr/share/sddm/themes/debian-breeze/Main.qml
marker: // {mark} ANSIBLE MANAGED BLOCK localhome marker: // {mark} ANSIBLE MANAGED BLOCK localhome
insertbefore: '^}$' insertbefore: '\s+//Footer'
block: | block: |
Text { Text {
id: localhome id: localhome
@ -33,6 +33,7 @@
dest: /etc/profile.d/lmn-logout.sh dest: /etc/profile.d/lmn-logout.sh
mode: '0755' mode: '0755'
content: | content: |
[[ "${UID}" -gt 10000 ]] && ! findmnt "/lmn/media/${USER}/home" > /dev/null && exit 0
{% if localhome_logout_missing_serverhome %} {% if localhome_logout_missing_serverhome %}
[[ "${UID}" -gt 10000 ]] && ! findmnt /srv/samba/schools/default-school > /dev/null && exit 0 [[ "${UID}" -gt 10000 ]] && ! findmnt /srv/samba/schools/default-school > /dev/null && exit 0
{% endif %} {% endif %}

View file

@ -5,11 +5,11 @@
set -eu set -eu
cur="$(efibootmgr | grep -Ei 'BootOrder:' | \ cur="$(efibootmgr | grep -Ei 'BootOrder:' | \
sed -E 's/^BootOrder: ([[:xdigit:]]{4}),.+$/\1/')" sed -E 's/^BootOrder: ([[:xdigit:]]{4}),.+$/\1/')"
pxeip4="$(efibootmgr | grep -Ei "IP.{0,5}4" | \ pxeip4="$(efibootmgr | grep -Ei "IP.*4" | \
sed -E 's/^Boot([[:xdigit:]]{4}).+$/\1/' | paste -sd, -)" sed -E 's/^Boot([[:xdigit:]]{4}).+$/\1/')"
debian="$(efibootmgr | grep -Ei "debian" | \ debian="$(efibootmgr | grep -Ei "debian" | \
sed -E 's/^Boot([[:xdigit:]]{4}).+$/\1/' | paste -sd, -)" sed -E 's/^Boot([[:xdigit:]]{4}).+$/\1/')"
if [[ "$cur" != "$pxeip4" ]] && [[ -n "$pxeip4" ]] && [[ -n "$debian" ]] ; then if [[ "$cur" != "$pxeip4" ]] && [[ -n "$pxeip4" ]] && [[ -n "$debian" ]] ; then
efibootmgr -o $pxeip4,$debian efibootmgr -o $pxeip4,$debian

View file

@ -98,7 +98,7 @@
export superusers export superusers
password_pbkdf2 root {{ grub_pwd }} password_pbkdf2 root {{ grub_pwd }}
notify: Run update-grub notify: Run update-grub
when: grub_pwd | bool | default(false) when: grub_pwd|default(false)
- name: Allow booting grub menu entries - name: Allow booting grub menu entries
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
@ -167,8 +167,6 @@
src: reporter.j2 src: reporter.j2
dest: /usr/local/sbin/reporter dest: /usr/local/sbin/reporter
mode: '0755' mode: '0755'
tags:
- baseinstall
- name: Provide services and timers for reporter - name: Provide services and timers for reporter
ansible.builtin.copy: ansible.builtin.copy:
@ -179,16 +177,12 @@
- reporter.service - reporter.service
- reporter.timer - reporter.timer
when: misc_reporter when: misc_reporter
tags:
- baseinstall
- name: Enable reporter.timer - name: Enable reporter.timer
ansible.builtin.systemd: ansible.builtin.systemd:
name: reporter.timer name: reporter.timer
enabled: true enabled: true
when: misc_reporter when: misc_reporter
tags:
- baseinstall
# Prepare CloneScreen on Presenter PCs # Prepare CloneScreen on Presenter PCs

View file

@ -5,14 +5,14 @@
mode: '0644' mode: '0644'
content: > content: >
{{ apt_conf }} {{ apt_conf }}
when: apt_conf | bool | default(false) when: apt_conf|default(false)
- name: Set NTP server - name: Set NTP server
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
path: /etc/systemd/timesyncd.conf path: /etc/systemd/timesyncd.conf
insertafter: '^#NTP=' insertafter: '^#NTP='
line: NTP={{ ntp_serv }} line: NTP={{ ntp_serv }}
when: ntp_serv | bool | default(false) when: ntp_serv|default(false)
- name: Add proposed-updates repository - name: Add proposed-updates repository
ansible.builtin.apt_repository: ansible.builtin.apt_repository:

View file

@ -37,7 +37,7 @@
line: "SystemGroup root lpadmin {{ printer_admin_group }}" line: "SystemGroup root lpadmin {{ printer_admin_group }}"
regexp: '^SystemGroup' regexp: '^SystemGroup'
state: present state: present
when: printer_admin_group | length > 0 when: printer_admin_group | length
- name: Disable cups-browsed - name: Disable cups-browsed
ansible.builtin.systemd: ansible.builtin.systemd:

View file

@ -5,8 +5,6 @@
key: "{{ item }}" key: "{{ item }}"
loop: "{{ keys2deploy }}" loop: "{{ keys2deploy }}"
when: keys2deploy is defined when: keys2deploy is defined
tags:
- baseinstall
- name: Allow sudo without password for ansible - name: Allow sudo without password for ansible
ansible.builtin.lineinfile: ansible.builtin.lineinfile:
@ -16,16 +14,12 @@
owner: root owner: root
group: root group: root
mode: '0700' mode: '0700'
tags:
- baseinstall
- name: Disable ansible user login - name: Disable ansible user login
ansible.builtin.user: ansible.builtin.user:
name: ansible name: ansible
password_lock: true password_lock: true
when: security_defaultuser_login_disable when: security_defaultuser_login_disable
tags:
- baseinstall
- name: Limit SSH access to user ansible - name: Limit SSH access to user ansible
ansible.builtin.blockinfile: ansible.builtin.blockinfile:

View file

@ -1,2 +0,0 @@
---
sssd_domjoin_user: global-admin

View file

@ -13,23 +13,12 @@
mode: '0600' mode: '0600'
notify: Restart sssd notify: Restart sssd
- name: Check if the machine account password and the join are still valid ## Either one of the variables is defined:
ansible.builtin.shell:
cmd: adcli testjoin -D {{ domain | upper }}
register: adcli_test_result
failed_when: false
changed_when: false
# If domjoin not valid:
- name: Join the domain - name: Join the domain
ansible.builtin.shell: ansible.builtin.shell:
cmd: > cmd: >
echo "{{ ad_passwd }}" | adcli join --stdin-password -U {{ ad_user }} {{ domain | upper }} echo "{{ ansible_cmdline.adpw | default('') + adpw.user_input | default('') }}" |
no_log: true adcli join --stdin-password -U global-admin {{ domain | upper }}
vars: when: >
ad_user: "{{ 'global-admin' if (adpw.user_input | default(ansible_cmdline.adpw) | default('') | length > 0) else sssd_domjoin_user }}" ansible_cmdline.adpw | default('') | length > 0 or
ad_passwd: "{{ adpw.user_input | default('') if adpw.user_input | default ('') | length > 0 else ansible_cmdline.adpw | default(sssd_domjoin_passwd) | default('') }}" adpw.user_input | default('') | length > 0
when:
- adpw.user_input | default('') | length > 0 or
ansible_cmdline.adpw | default(sssd_domjoin_passwd) | default('') | length > 0
- adcli_test_result.rc != 0

View file

@ -17,7 +17,6 @@ ad_gpo_access_control = disabled
ad_gpo_ignore_unreadable = True ad_gpo_ignore_unreadable = True
ad_maximum_machine_account_password_age = 0 ad_maximum_machine_account_password_age = 0
ignore_group_members = True ignore_group_members = True
krb5_renew_interval = 1h
{% if localhome is defined and localhome %} {% if localhome is defined and localhome %}
override_homedir = /home/%u override_homedir = /home/%u
{% endif %} {% endif %}

View file

@ -8,11 +8,3 @@
- bookworm.yml - bookworm.yml
- cleanup.yml - cleanup.yml
when: ansible_distribution_release == "bookworm" when: ansible_distribution_release == "bookworm"
- name: Set chromium gl-flags fixing AMD graphic issues
ansible.builtin.copy:
dest: /etc/chromium.d/fvs
content: |
export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --use-gl=desktop"
when: ansible_board_vendor == "LENOVO" and
(ansible_board_name == "312D" or ansible_board_name == "312A")

View file

@ -3,11 +3,6 @@
%role-student ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-sync %role-student ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-sync
%examusers ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-sync %examusers ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-sync
# vm-delete: Delete VM-Images
%role-teacher ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-delete
%role-student ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-delete
%examusers ALL=(lmnsynci) NOPASSWD: /usr/local/bin/vm-delete
# vm-aria2: Start/Stop aria2 as systemd-service for VM-Images # vm-aria2: Start/Stop aria2 as systemd-service for VM-Images
lmnsynci ALL=(root) NOPASSWD: /usr/local/bin/vm-aria2 lmnsynci ALL=(root) NOPASSWD: /usr/local/bin/vm-aria2

View file

@ -1,45 +0,0 @@
#!/bin/bash
set -eu
directory="/lmn/vm"
if [ ! -d "$directory" ]; then
echo "No VM directory found."
exit 1
fi
qcow2_files=("$directory"/*.qcow2)
if [ "${#qcow2_files[@]}" -eq 0 ]; then
echo "Keine QCOW2-Dateien gefunden."
exit 0
fi
echo "Gefundene QCOW2-Dateien:"
echo "-------------------------------------------------------------"
printf "%-50s %10s\n" "Datei" "Größe (MB)"
echo "-------------------------------------------------------------"
for file in "${qcow2_files[@]}"; do
size=$(du -m "$file" | cut -f1) # Größe in MB
printf "%-50s %10d\n" "$file" "$size"
done
echo "-------------------------------------------------------------"
for file in "${qcow2_files[@]}"; do
read -rp "Möchtest du die Datei $file löschen? (j/n) " confirmation
if [[ "$confirmation" == "j" || "$confirmation" == "J" ]]; then
link_count=$(stat -c %h "$file")
rm "$file"
echo "$file wurde gelöscht."
if [ "$link_count" -gt 1 ]; then
echo "Achtung: $file hat noch $((link_count - 1)) weitere Hardlinks."
echo "Diese liegen evtl. unter:"
echo "- /var/tmp/${UID}/vm/ (temporäre VMs, werden automatisch beim Neustart gelöscht)"
echo "- /var/vm/${UID}/ (persistente VMs)"
fi
echo
fi
done

View file

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

View file

@ -7,10 +7,10 @@ set -eu
## Imporant for all virsh libvirt calls: ## Imporant for all virsh libvirt calls:
export XDG_CONFIG_HOME="/var/tmp/vm/${UID}" export XDG_CONFIG_HOME="/var/tmp/vm/${UID}"
menu=(standard-edu "CLI Standard Debian GNU/Linux NFS" menu=(standard "CLI Standard Debian GNU/Linux NFS"
standard-edu-ram "CLI Standard Debian GNU/Linux RAM" standard-ram "CLI Standard Debian GNU/Linux RAM"
kde-edu "KDE Plasma Desktop Debian GNU/Linux NFS" kde-desktop "KDE Plasma Desktop Debian GNU/Linux NFS"
gnome-edu "Gnome Desktop Debian GNU/Linux NFS") gnome-desktop "Gnome Desktop Debian GNU/Linux NFS")
img=$(dialog --clear --backtitle "Virtual Machine Chooser" \ img=$(dialog --clear --backtitle "Virtual Machine Chooser" \
--title "Choose the Virtual Machine to Start" \ --title "Choose the Virtual Machine to Start" \
--menu "Start VM:" 12 70 6 "${menu[@]}" 2>&1 >/dev/tty) --menu "Start VM:" 12 70 6 "${menu[@]}" 2>&1 >/dev/tty)
@ -22,8 +22,6 @@ mac="$(ip link | grep -A1 -m1 "macvtap-" | \
sed -nE "s%\s+link/ether ([[:xdigit:]:]{17}) .+%\1%p")" sed -nE "s%\s+link/ether ([[:xdigit:]:]{17}) .+%\1%p")"
tapdev="$(ip link | grep -A1 -m1 "macvtap-" | sed -nE "s%^[1-9]:\s(\S+)@.*%\1%p")" tapdev="$(ip link | grep -A1 -m1 "macvtap-" | sed -nE "s%^[1-9]:\s(\S+)@.*%\1%p")"
livebox=$(host livebox | sed -E "s/.+ ([0-9.]+)$/\1/")
if [[ $# -eq 0 ]] ; then if [[ $# -eq 0 ]] ; then
mem=$(sed -En "s/^MemAvailable:\s+([0-9]+)\s+kB/\1/p" /proc/meminfo) mem=$(sed -En "s/^MemAvailable:\s+([0-9]+)\s+kB/\1/p" /proc/meminfo)
cpu=$(sed -En "0,/^cpu cores/s/^cpu cores\s+:\s+([0-9]+)/\1/p" /proc/cpuinfo) cpu=$(sed -En "0,/^cpu cores/s/^cpu cores\s+:\s+([0-9]+)/\1/p" /proc/cpuinfo)
@ -33,8 +31,8 @@ else
arg=("$@") arg=("$@")
fi fi
kernel="http://${livebox}/d-i/n-live/${img%-ram}/live/vmlinuz" kernel="http://livebox/d-i/n-live/${img%-ram}/live/vmlinuz"
initrd="http://${livebox}/d-i/n-live/${img%-ram}/live/initrd.img" initrd="http://livebox/d-i/n-live/${img%-ram}/live/initrd.img"
kargs=(boot=live components splash locales=de_DE.UTF-8 keyboard-layouts=de kargs=(boot=live components splash locales=de_DE.UTF-8 keyboard-layouts=de
swap=true live-config.timezone=Europe/Berlin) swap=true live-config.timezone=Europe/Berlin)
@ -44,10 +42,10 @@ case "$img" in
kargs+=(console=ttyS0) kargs+=(console=ttyS0)
;;& ;;&
*-ram) *-ram)
kargs+=("root=live:nfs4:${livebox}:/images/${img%-ram}/live/filesystem.squashfs rd.live.ram=1") kargs+=("fetch=http://10.190.1.2/d-i/n-live/${img%-ram}/live/filesystem.squashfs")
;; ;;
*) *)
kargs+=("root=live:nfs4:${livebox}:/images/${img%-ram}/live/filesystem.squashfs") kargs+=(netboot=nfs "nfsroot=10.190.1.2:/srv/nfs/debian-live/${img%-ram}")
;; ;;
esac esac

View file

@ -90,21 +90,17 @@ create_clone() {
local VM_NAME="$1" local VM_NAME="$1"
if ! [[ -f "${VM_SYSDIR}/${VM_NAME}.qcow2" || -f "${VM_DIR}/${VM_NAME}.qcow2" ]]; then if ! [[ -f "${VM_SYSDIR}/${VM_NAME}.qcow2" || -f "${VM_DIR}/${VM_NAME}.qcow2" ]]; then
echo "qcow2 File does not exists." >&2 echo "qcow2 File does not exists." >&2
exit 1 exit 1
fi fi
# Create User-VM-Dir and link system VM-Images # Create User-VM-Dir and link system VM-Images
[[ -d "${VM_DIR}" ]] || mkdir -p "${VM_DIR}" [[ -d "${VM_DIR}" ]] || mkdir -p "${VM_DIR}"
IMAGE="${VM_NAME}.qcow2" if [[ "${PERSISTENT}" -eq 1 ]]; then
while [[ -n ${IMAGE} ]]; do sudo /usr/local/bin/vm-link-images -p
if [[ "${PERSISTENT}" -eq 1 ]]; then else
sudo /usr/local/bin/vm-link-images -p "${IMAGE}" sudo /usr/local/bin/vm-link-images
else fi
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 # Create backing file
cd "${VM_DIR}" cd "${VM_DIR}"
@ -134,30 +130,18 @@ create_printerlist() {
} }
create_mountlist() { create_mountlist() {
NETHOMEPART="${NETHOME#/srv/samba/schools}" if id | grep -q teachers; then
cat << EOF > "${VMINFO_DIR}/.mounts.csv" NETHOME=/srv/samba/schools/default-school/teachers/$USER
Drive;Remotepath else
H;\\\\server.pn.steinbeis.schule${NETHOMEPART//\//\\} NETHOME=(/srv/samba/schools/default-school/students/*/"$USER")
T;\\\\server.pn.steinbeis.schule\\default-school\\share
EOF
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 fi
NETHOME="${NETHOME#/srv/samba/schools}"
LIBVIRTOPTS="${LIBVIRTOPTS} --filesystem driver.type=virtiofs,accessmode=passthrough,target.dir=${target_name},xpath1.set=./source/@socket=${socket}" cat << EOF > "/lmn/media/${USER}/.mounts.csv"
Drive;Remotepath
H;\\\\10.190.1.1${NETHOME//\//\\}
T;\\\\10.190.1.1\default-school\share
EOF
echo "${USER}" > "/lmn/media/${USER}/.user"
} }
start_virtiofsd() { start_virtiofsd() {
@ -167,17 +151,9 @@ start_virtiofsd() {
[[ "$GUEST_GID" == 0 ]] && GUEST_GID=1010 [[ "$GUEST_GID" == 0 ]] && GUEST_GID=1010
fi fi
# END temporary fix # END temporary fix
socket="/run/user/$(id -u $USER)/virtiofs-${VM_NAME}.sock"
# start_virtiofs_service "VM-Data" "/lmn/media/${USER}" "Y" systemd-run --user /usr/local/bin/virtiofsd --uid-map=:${GUEST_UID}:${UID}:1: --gid-map=:${GUEST_GID}:$(id -g):1: \
# start_virtiofs_service "default-school" "/srv/samba/schools/default-school" "Y" --socket-path "$socket" --shared-dir "/lmn/media/${USER}" --syslog
# Home@PC / VM-Data
# if the environment variable VMLEGACY is set, /lmn/media/USER is forced
if [[ "${HOME}" != "${NETHOME}" && ! -v VMLEGACY ]]; then
start_virtiofs_service "Home_Linux" "${HOME}" "Y"
else
start_virtiofs_service "VM-Data" "/lmn/media/${USER}" "Y"
fi
} }
ask_really_persistent() { ask_really_persistent() {
@ -240,7 +216,7 @@ while true; do
shift shift
;; ;;
-o | --options ) -o | --options )
LIBVIRTOPTS="${LIBVIRTOPTS} $2" LIBVIRTOPTS=$2
shift 2 shift 2
;; ;;
--no-viewer ) --no-viewer )
@ -291,7 +267,6 @@ while true; do
type="ethernet,mac=${mac},target.dev=${interface},xpath1.set=./target/@managed=no,model.type=virtio" type="ethernet,mac=${mac},target.dev=${interface},xpath1.set=./target/@managed=no,model.type=virtio"
LIBVIRTOPTS="${LIBVIRTOPTS} --network type=$type" LIBVIRTOPTS="${LIBVIRTOPTS} --network type=$type"
done done
LIBVIRTOPTS="${LIBVIRTOPTS} --check mac_in_use=off"
shift shift
;; ;;
--os ) --os )
@ -340,38 +315,18 @@ if ! virsh --connect="${QEMU}" list | grep "${VM_NAME}-clone"; then
check_images check_images
fi fi
if [[ "${NEWCLONE}" = 1 ]] || [[ ! -f "${VM_DIR}/${VM_NAME}-clone.qcow2" ]]; then if [[ "${NEWCLONE}" = 1 ]] || [[ ! -f "${VM_DIR}/${VM_NAME}-clone.qcow2" ]]; then
create_clone "${VM_NAME}" create_clone "${VM_NAME}"
fi fi
# delete the old vm # delete the old vm
virsh --connect=qemu:///session undefine --nvram "${VM_NAME}-clone" || echo "${VM_NAME}-clone did not exist" virsh --connect=qemu:///session undefine --nvram "${VM_NAME}-clone" || echo "${VM_NAME}-clone did not exist"
#trap exit_script SIGHUP SIGINT SIGTERM #trap exit_script SIGHUP SIGINT SIGTERM
for dir in teachers examusers staff parents; do
if [[ -d "/srv/samba/schools/default-school/${dir}/${USER}" ]]; then
NETHOME="/srv/samba/schools/default-school/${dir}/${USER}"
break
fi
done
if [[ -z "${NETHOME+x}" ]]; then
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_printerlist
create_mountlist create_mountlist
# start virtiofsd-service # start virtiofsd-service
[[ "${QEMU}" = 'qemu:///session' ]] && start_virtiofsd [[ "${QEMU}" = 'qemu:///session' ]] && start_virtiofsd
# Create VMInfo Json file
#( umask 027; ./vm-create-vminfo > "${VMINFO_DIR}/.vminfo.json" )
# Start vminfo.timer
systemctl --user restart vminfo.timer
uuid=$(openssl rand -hex 16) uuid=$(openssl rand -hex 16)
uuid="${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}" uuid="${uuid:0:8}-${uuid:8:4}-${uuid:12:4}-${uuid:16:4}-${uuid:20:12}"
@ -393,6 +348,7 @@ if ! virsh --connect="${QEMU}" list | grep "${VM_NAME}-clone"; then
--memorybacking source.type=memfd,access.mode=shared \ --memorybacking source.type=memfd,access.mode=shared \
--disk "${VM_DIR}/${VM_NAME}-clone.qcow2",driver.discard=unmap,target.bus=scsi,cache=writeback \ --disk "${VM_DIR}/${VM_NAME}-clone.qcow2",driver.discard=unmap,target.bus=scsi,cache=writeback \
--network=bridge=virbr0,model.type=virtio \ --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 \ --controller type=scsi,model=virtio-scsi \
--check path_in_use=off \ --check path_in_use=off \
--connect="${QEMU}" \ --connect="${QEMU}" \

View file

@ -1,117 +0,0 @@
#!/usr/bin/python3
import argparse
import struct
import subprocess
import json
import sys
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:
sys.stderr.write(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:
sys.stderr.write(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:
sys.stderr.write("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'))
for dir in ['teachers','examusers','staff','parents']:
potential_path = f"/srv/samba/schools/default-school/{dir}/{vminfo['User']}"
if path.isdir(potential_path):
nethome = potential_path
break
if not nethome:
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.splitlines()[0]
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

@ -18,9 +18,7 @@
- mktorrent - mktorrent
- libvirt-daemon-system - libvirt-daemon-system
- virt-manager - virt-manager
- virt-viewer
- dialog # for vm-netboot menu - dialog # for vm-netboot menu
- python3-impacket
# - name: allow all users to use VMs # - name: allow all users to use VMs
# lineinfile: # lineinfile:
@ -29,6 +27,32 @@
# insertafter: '#auth_unix_rw = "polkit"' # insertafter: '#auth_unix_rw = "polkit"'
# notify: reload libvirtd # notify: reload libvirtd
- name: Configure pam_mount for VM bind mounts
ansible.builtin.blockinfile:
dest: /etc/security/pam_mount.conf.xml
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK (bind mounts for VMs) -->"
block: |
<!-- bind mounts for the VMs, setting gid here does not work -->
<volume
path="~"
mountpoint="/lmn/media/%(USER)/home"
options="bind"
><not><or><user>root</user><user>ansible</user><user>Debian-gdm</user><user>sddm</user>{% if localuser %}<user>{{ localuser }}</user>{% endif %}</or></not>
</volume>
<volume
path="/srv/samba/schools/default-school/share"
mountpoint="/lmn/media/%(USER)/share"
options="bind"
><not><or><user>root</user><user>ansible</user><user>Debian-gdm</user><user>sddm</user>{% if localuser %}<user>{{ localuser }}</user>{% endif %}</or></not>
</volume>
<volume
path="/srv/samba/schools/default-school"
mountpoint="/lmn/media/%(USER)/school"
options="bind"
><not><or><user>root</user><user>ansible</user><user>Debian-gdm</user><user>sddm</user>{% if localuser %}<user>{{ localuser }}</user>{% endif %}</or></not>
</volume>
insertafter: "<!-- END ANSIBLE MANAGED BLOCK .* -->"
- name: Use umount script for proper cleanup - name: Use umount script for proper cleanup
ansible.builtin.blockinfile: ansible.builtin.blockinfile:
dest: /etc/security/pam_mount.conf.xml dest: /etc/security/pam_mount.conf.xml
@ -118,7 +142,6 @@
group: root group: root
mode: '0755' mode: '0755'
loop: loop:
- vm-delete
- vm-create - vm-create
- vm-rebase - vm-rebase
- vm-run - vm-run
@ -126,7 +149,6 @@
- vm-sync - vm-sync
- vm-link-images - vm-link-images
- vm-virtiofsd - vm-virtiofsd
- vm-vminfo
- virtiofsd - virtiofsd
- vm-aria2 - vm-aria2
- uploadseed - uploadseed
@ -214,26 +236,3 @@
src: vm-netboot src: vm-netboot
dest: /usr/local/bin/ dest: /usr/local/bin/
mode: '0755' 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 %}/home{% else %}/lmn/media{% endif %}/${USER}/.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'

View file

@ -13,32 +13,30 @@ if [[ "$CONNECTION_ID" = "VPN-Schule" ]]; then
# Exit if server is already mounted # Exit if server is already mounted
findmnt /srv/samba/schools/default-school > /dev/null && exit 0 findmnt /srv/samba/schools/default-school > /dev/null && exit 0
counter=1 if ! klist -s -c "${KRB5CCNAME}"; then
while ! klist -s -c "${KRB5CCNAME}"; do #echo "try to renew KRB5-Ticket" >&2
(( counter > 30 )) && exit 0 #sudo -u "${USERNAME}" kinit -R -c "${KRB5CCNAME}"
echo "KRB5-Ticket is expired. Sleep 1 seconds and hope it will be renewed after." >&2 echo "KRB5-Ticket is expired. Sleep 3 seconds and hope it will be renewed after." >&2
# if (( counter == 10 )); then sleep 3
# echo "try to renew KRB5-Ticket" >&2 fi
# sudo -u "${USERNAME}" kinit -R -c "${KRB5CCNAME}"
# fi
sleep 1
((counter++))
done
echo "prepare mountpoints" >&2 echo "prepare mountpoints" >&2
umask 0002 umask 0002
mkdir -p /srv/samba/schools/default-school mkdir -p /srv/samba/schools/default-school
chmod 777 /srv/samba/schools/default-school chmod 777 /srv/samba/schools/default-school
mkdir -p "/lmn/media/${USERNAME}/share"
mount -t cifs //server/default-school/ /srv/samba/schools/default-school \ mount -t cifs //server/default-school/ /srv/samba/schools/default-school \
-o "sec=krb5i,cruid=${USERID},user=${USERNAME},uid=${USERID},gid=${GROUPID},file_mode=0700,dir_mode=0700,mfsymlinks,nobrl,actimeo=600,cache=loose,echo_interval=10" -o "sec=krb5i,cruid=${USERID},user=${USERNAME},uid=${USERID},gid=${GROUPID},file_mode=0700,dir_mode=0700,mfsymlinks,nobrl,actimeo=600,cache=loose,echo_interval=10"
echo "after mount" >&2 echo "after mount" >&2
mount --bind /srv/samba/schools/default-school/share "/lmn/media/${USERNAME}/share"
SUDO_USER=$USERNAME /usr/local/bin/install-printers.sh SUDO_USER=$USERNAME /usr/local/bin/install-printers.sh
elif [[ "$NM_DISPATCHER_ACTION" = "pre-down" ]]; then elif [[ "$NM_DISPATCHER_ACTION" = "pre-down" ]]; then
# FIXME: Only umount server when Wireguard-Connection was the only connection to server. # FIXME: Only umount server when Wireguard-Connection was the only connection to server.
# Dirty fix (works only in fvs-IP-Range) # Dirty fix (works only in fvs-IP-Range)
if ! (ip r s | grep "10.190." | grep -v wg0); then if ! (ip r s | grep "10.190." | grep -v wg0); then
echo "Try to umount server" echo "Try to umount server shares"
umount "/lmn/media/${USERNAME}/share"
umount /srv/samba/schools/default-school umount /srv/samba/schools/default-school
fi fi
fi fi

View file

@ -3,6 +3,7 @@ set -eu
exit_script() { exit_script() {
echo "unmounting media - terminated by trap!" >> "/tmp/${SUDO_UID}-exit-mount.log" echo "unmounting media - terminated by trap!" >> "/tmp/${SUDO_UID}-exit-mount.log"
findmnt "/lmn/media/${SUDO_USER}/share" && umount "/lmn/media/${SUDO_USER}/share"
findmnt "/srv/samba/schools/default-school" && umount "/srv/samba/schools/default-school" findmnt "/srv/samba/schools/default-school" && umount "/srv/samba/schools/default-school"
trap - SIGHUP SIGINT SIGTERM # clear the trap trap - SIGHUP SIGINT SIGTERM # clear the trap
kill -- -$$ # Sends SIGTERM to child/sub processes kill -- -$$ # Sends SIGTERM to child/sub processes
@ -13,9 +14,11 @@ findmnt /srv/samba/schools/default-school > /dev/null && exit 0
umask 0002 umask 0002
mkdir -p /srv/samba/schools/default-school mkdir -p /srv/samba/schools/default-school
chmod 777 /srv/samba/schools/default-school chmod 777 /srv/samba/schools/default-school
mkdir -p "/lmn/media/${SUDO_USER}/share"
mount -t cifs //server/default-school/ /srv/samba/schools/default-school \ mount -t cifs //server/default-school/ /srv/samba/schools/default-school \
-o "sec=krb5i,cruid=${SUDO_UID},user=${SUDO_USER},uid=${SUDO_UID},gid=${SUDO_GID},file_mode=0700,dir_mode=0700,mfsymlinks,nobrl,actimeo=600,cache=loose,echo_interval=10" -o "sec=krb5i,cruid=${SUDO_UID},user=${SUDO_USER},uid=${SUDO_UID},gid=${SUDO_GID},file_mode=0700,dir_mode=0700,mfsymlinks,nobrl,actimeo=600,cache=loose,echo_interval=10"
mount --bind /srv/samba/schools/default-school/share "/lmn/media/${SUDO_USER}/share"
echo "Einbindung erfolgreich!" echo "Einbindung erfolgreich!"
echo "Dieses Fenster bitte nicht schließen!" echo "Dieses Fenster bitte nicht schließen!"

View file

@ -5,7 +5,7 @@
- wireguard - wireguard
- name: Check if wg_server is reachable - name: Check if wg_server is reachable
ansible.builtin.command: echo "reachable" ansible.builtin.command: echo "Test if wg_server is reachable"
delegate_to: wireguard_server delegate_to: wireguard_server
register: result register: result
changed_when: false changed_when: false
@ -17,12 +17,10 @@
* server not reachable * server not reachable
* no matching ssh-key * no matching ssh-key
changed_when: true changed_when: true
when: result.stdout is not defined or result.stdout!="reachable" when: result.unreachable is defined and result.unreachable
- name: Configure WG Server - name: Configure WG Server
when: when: result.unreachable is not defined or not result.unreachable
- result.stdout is defined and result.stdout=="reachable"
- not run_in_installer|default(false)|bool
block: block:
- name: Set facts wg_clientname - name: Set facts wg_clientname
ansible.builtin.set_fact: ansible.builtin.set_fact:

View file

@ -27,7 +27,7 @@
when: cert_client_active.stat.exists when: cert_client_active.stat.exists
- name: Check if radius-server is reachable - name: Check if radius-server is reachable
ansible.builtin.command: echo "reachable" ansible.builtin.command: echo "Test if radius-server is reachable"
delegate_to: radius_server delegate_to: radius_server
register: radius_reachable register: radius_reachable
changed_when: false changed_when: false
@ -40,13 +40,12 @@
- "* server not reachable" - "* server not reachable"
- "* no matching ssh-key" - "* no matching ssh-key"
changed_when: true changed_when: true
when: radius_reachable.stdout is not defined or radius_reachable.stdout!='reachable' when: radius_reachable.unreachable is defined and radius_reachable.unreachable
- name: Issue radius certificate - name: Issue radius certificate
ansible.builtin.include_tasks: eap-tls_issue-certificate.yaml ansible.builtin.include_tasks: eap-tls_issue-certificate.yaml
when: when:
- radius_reachable.stdout is defined and radius_reachable.stdout=="reachable" - radius_reachable.unreachable is not defined or not radius_reachable.unreachable
- not run_in_installer|default(false)|bool
- | - |
( not cert_client_active.stat.exists ) or ( not cert_client_active.stat.exists ) or
(cert_serial.stdout | replace('serial=','') | int(base=16) ) in ( radius_crl.revoked_certificates | map(attribute='serial_number') | list ) or (cert_serial.stdout | replace('serial=','') | int(base=16) ) in ( radius_crl.revoked_certificates | map(attribute='serial_number') | list ) or

View file

@ -105,7 +105,6 @@
ansible.builtin.systemd: ansible.builtin.systemd:
name: iwd.service name: iwd.service
enabled: false enabled: false
failed_when: false
- name: Remove deprecated NetworkManager config - name: Remove deprecated NetworkManager config
ansible.builtin.blockinfile: ansible.builtin.blockinfile:

View file

@ -3,6 +3,7 @@
- name: Install packages related to wifi - name: Install packages related to wifi
ansible.builtin.apt: ansible.builtin.apt:
name: name:
- systemd-resolved
- firmware-realtek # for our wifi sticks - firmware-realtek # for our wifi sticks
- name: Provide service to enable WiFi on boot - name: Provide service to enable WiFi on boot