Share accounts: per-site Samba passwords from the webapp

Tools > Share accounts sets the pxe-upload, blancco and clonezilla Samba
passwords. Saving one runs smbpasswd and writes it everywhere it is used:
startnet.cmd in boot.wim (pxe-upload), the served Blancco preferences and
the live config.img (blancco), the iPXE menu's Clonezilla entries
(clonezilla). Refused while a PC is imaging unless forced. Stored 0600 in
UPDATES_DIR/shares/accounts.json, never shown back.

- The stored values are the authority: the playbook only creates the
  Samba accounts, seeds the store from site-vars (pxe_upload_password,
  blancco_smb_password, clonezilla_smb_password) for accounts it does not
  hold, and runs "share_accounts apply" at the end of every run.
- Every startnet save re-pins SHAREPASS, so a restored snapshot cannot
  bring an old password back; new menu blocks use %SHAREUSER%/%SHAREPASS%.
- Shop floor unattend Order 4 reads the login from fetch-source.txt;
  Invoke-PostPpkg deletes that file once the PPKG is applied.
- Upload-Image.ps1 asks for the password unless -Pass is given.
- pxe_admin_password: the Linux pxe login. Required while the box still
  has the shipped "pxe"; set with chpasswd when it differs.
- Blancco site settings now also reach the live config.img (BIOS path).
This commit is contained in:
cproudlock
2026-10-17 12:29:06 -04:00
parent 5f7954ac88
commit fa79f76951
20 changed files with 1526 additions and 671 deletions

View File

@@ -202,8 +202,8 @@
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>4</Order>
<CommandLine>powershell.exe -ep Bypass -Command "net use Z: \\172.16.9.1\enrollment /user:pxe-upload pxe; robocopy Z:\shopfloor-setup C:\Enrollment Fetch-StagingPayload.ps1 Verify-And-Heal-Staging.ps1 /R:2 /W:2; robocopy Z:\scripts C:\Enrollment run-enrollment.ps1 wait-for-internet.ps1 migrate-to-wifi.ps1 /R:2 /W:2"</CommandLine>
<Description>Bootstrap self-heal: pull Fetch/Verify-Heal + enrollment scripts from the PXE share so Order 5/6 run after an early WinPE staging failure.</Description>
<CommandLine>powershell.exe -ep Bypass -Command "$u='pxe-upload'; $p='pxe'; $f='C:\Enrollment\fetch-source.txt'; if (Test-Path $f) { $l=@(Get-Content $f); if ($l.Count -ge 3) { $u=$l[1].Trim(); $p=$l[2].Trim() } }; net use Z: \\172.16.9.1\enrollment /user:$u $p; robocopy Z:\shopfloor-setup C:\Enrollment Fetch-StagingPayload.ps1 Verify-And-Heal-Staging.ps1 /R:2 /W:2; robocopy Z:\scripts C:\Enrollment run-enrollment.ps1 wait-for-internet.ps1 migrate-to-wifi.ps1 /R:2 /W:2"</CommandLine>
<Description>Bootstrap self-heal: pull Fetch/Verify-Heal + enrollment scripts from the PXE share so Order 5/6 run after an early WinPE staging failure. Share login from fetch-source.txt (startnet writes it).</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>5</Order>

View File

@@ -199,6 +199,17 @@
# letters, digits . _ ~ - (it sits in a URI, a kernel command line and
# a mount option list), 8 to 64 of them.
clonezilla_smb_password: "clonezilla-backup"
# The two other Samba accounts. pxe-upload: WinPE and Shop Floor setup
# on every imaging PC, image and app uploads. blancco: Blancco's report
# share. Same rules as clonezilla_smb_password. Empty: the shipped
# default (pxe / blancco). All three only SEED the webapp's Tools >
# Share accounts on the first run that sees them; after that the webapp
# owns them and a re-run keeps what it holds.
pxe_upload_password: ""
blancco_smb_password: ""
# The server's Linux login (pxe: SSH and sudo). Required while the box
# still has the shipped password "pxe"; set on every run it differs.
pxe_admin_password: ""
# The site, as stamped on Blancco erasure reports and the monthly CMMC
# evidence packs (webapp BLANCCO_SITE). Empty: "Unnamed site", so a
# missing name shows instead of another site's. Letters, digits, spaces
@@ -377,6 +388,46 @@
site-specific value in playbook/site-vars.yml and re-run.
when: clonezilla_smb_password == "clonezilla-backup"
- name: "Shares: check the pxe-upload and blancco Samba passwords"
assert:
that:
- pxe_upload_password is string and blancco_smb_password is string
- pxe_upload_password | length == 0 or pxe_upload_password is match('^[A-Za-z0-9._~-]{8,64}$')
- blancco_smb_password | length == 0 or blancco_smb_password is match('^[A-Za-z0-9._~-]{8,64}$')
fail_msg: >-
pxe_upload_password and blancco_smb_password must be empty or 8-64
characters from A-Z a-z 0-9 . _ ~ - (they go into startnet.cmd and
the Blancco preferences). Fix them in playbook/site-vars.yml and re-run.
quiet: yes
- name: "Admin: is the Linux pxe login still the shipped password?"
shell: |
h=$(getent shadow pxe | cut -d: -f2)
case "$h" in
'$6$'*) salt=$(printf '%s' "$h" | cut -d'$' -f3)
if [ "$(printf 'pxe' | openssl passwd -6 -salt "$salt" -stdin)" = "$h" ]; then echo DEFAULT; else echo SITE; fi ;;
*) echo UNKNOWN ;;
esac
args:
executable: /bin/bash
register: pxe_admin_state
changed_when: false
- name: "Admin: check pxe_admin_password"
assert:
that:
- pxe_admin_password is string
- pxe_admin_password | length > 0 or pxe_admin_state.stdout != 'DEFAULT'
- pxe_admin_password | length == 0 or (pxe_admin_password | length >= 8 and pxe_admin_password | length <= 128)
- pxe_admin_password | length == 0 or pxe_admin_password is not search('[\x00-\x1f]')
- pxe_admin_password != 'pxe'
fail_msg: >-
Set pxe_admin_password in playbook/site-vars.yml (8-128 characters,
no line breaks): the Linux login pxe (SSH and sudo) still has the
shipped password "pxe", the same on every server. Fix the file and
re-run.
quiet: yes
# --- Re-run safety (nothing below changes the box until these pass) ---
- name: "Re-run safety: is imaging in progress? (SMB sessions, recent DHCP leases)"
args:
@@ -1473,28 +1524,49 @@
valid users = pxe-upload
comment = Dell BIOS update bundle (read-only, served to WinPE)
- name: "Create Samba users (pxe-upload and blancco)"
# The Samba passwords belong to the webapp (Tools > Share accounts):
# here the accounts are only created, with the site-vars value or the
# default; "Shares: apply the stored passwords" near the end sets them.
- name: "Create Samba users (pxe-upload, blancco, clonezilla)"
# clonezilla: system user, no home, no login shell; only [clonezilla]
# lists it in valid users.
shell: |
add() { # user password
pdbedit -L 2>/dev/null | grep -q "^$1:" && return 0
printf '%s\n%s\n' "$2" "$2" | smbpasswd -a -s "$1" >/dev/null && echo "created $1"
}
id pxe-upload >/dev/null 2>&1 || useradd -M -s /usr/sbin/nologin pxe-upload
echo -e 'pxe\npxe' | smbpasswd -a pxe-upload -s
id blancco >/dev/null 2>&1 || useradd -M -s /usr/sbin/nologin blancco
echo -e 'blancco\nblancco' | smbpasswd -a blancco -s
args:
executable: /bin/bash
changed_when: false
- name: "Create the clonezilla Samba user ([clonezilla] share only)"
# System user, no home, no login shell. Only [clonezilla] lists it in
# valid users. smbpasswd runs every time so a changed
# clonezilla_smb_password takes effect (the menu is updated with it).
shell: |
id clonezilla >/dev/null 2>&1 || useradd -r -M -d /nonexistent -s /usr/sbin/nologin clonezilla
printf '%s\n%s\n' "$CZ_PW" "$CZ_PW" | smbpasswd -a -s clonezilla >/dev/null
add pxe-upload "${UP_PW:-pxe}"
add blancco "${BL_PW:-blancco}"
add clonezilla "$CZ_PW"
environment:
UP_PW: "{{ pxe_upload_password }}"
BL_PW: "{{ blancco_smb_password }}"
CZ_PW: "{{ clonezilla_smb_password }}"
args:
executable: /bin/bash
changed_when: false
register: smb_users
changed_when: "'created' in smb_users.stdout"
no_log: true
- name: "Admin: set the Linux pxe password from pxe_admin_password"
shell: |
h=$(getent shadow pxe | cut -d: -f2)
salt=$(printf '%s' "$h" | cut -d'$' -f3)
if [ -n "$salt" ] && [ "$(printf '%s' "$PW" | openssl passwd -6 -salt "$salt" -stdin)" = "$h" ]; then
echo UNCHANGED
else
printf 'pxe:%s\n' "$PW" | chpasswd && echo CHANGED
fi
environment:
PW: "{{ pxe_admin_password }}"
args:
executable: /bin/bash
register: pxe_admin_set
changed_when: "'CHANGED' in pxe_admin_set.stdout"
when: pxe_admin_password | length > 0
no_log: true
- name: "Deploy nf_conntrack TCP timeout sysctl for PXE workload"
@@ -2001,12 +2073,6 @@
dest: "{{ web_root }}/blancco/blancco-progress.py"
mode: '0644'
- name: "Ensure Samba user for Blancco reports exists (idempotent)"
shell: |
id blancco >/dev/null 2>&1 || useradd -r -s /usr/sbin/nologin blancco
pdbedit -L 2>/dev/null | grep -q '^blancco:' || (echo -e "blancco\nblancco" | smbpasswd -a -s blancco)
changed_when: false
- name: "Check for WinPE deployment content on USB"
stat:
path: "{{ usb_root }}/images"
@@ -2422,6 +2488,28 @@
debug:
msg: "{{ blancco_render.stdout_lines | select('search', 'CHANGED|WARNING|seeded') | list }}"
# The Samba passwords: seeded from site-vars only for accounts the
# webapp does not hold yet (Tools > Share accounts owns them after
# that), then set in Samba, startnet.cmd in boot.wim (this run injected
# the USB copy), the iPXE menu's Clonezilla entries (rendered from
# site-vars above) and the Blancco preferences. Passwords via env.
- name: "Shares: apply the stored passwords"
command: python3 -m services.share_accounts apply --seed
args:
chdir: /opt/pxe-webapp
environment:
WEB_ROOT: "{{ web_root }}"
SHARE_SEED_PXE_UPLOAD: "{{ pxe_upload_password }}"
SHARE_SEED_BLANCCO: "{{ blancco_smb_password }}"
SHARE_SEED_CLONEZILLA: "{{ clonezilla_smb_password }}"
no_log: true
register: share_apply
changed_when: share_apply.stdout_lines | select('search', 'updated|seeded') | list | length > 0
- name: "Shares: apply result"
debug:
msg: "{{ share_apply.stdout_lines }}"
# Hard gate: blancco-init.sh in initramfs drops to shell if the served
# preferences.xml is malformed or missing the SMB target. Fail the
# playbook here too so the problem surfaces at deploy time, not at the

View File

@@ -13,6 +13,8 @@
# same, but it runs as Users and the HKLM write can be denied.
# 3. Once Monitor-IntuneProgress has written C:\Enrollment\sync-complete.txt,
# remove the "Shopfloor Intune Sync" logon task.
# Also, once the PPKG is applied, delete C:\Enrollment\fetch-source.txt (the
# pxe-upload share login startnet leaves for the first-logon scripts).
# When all three are done the task unregisters itself.
#
# Never throws: every step logs and the script exits 0.
@@ -47,6 +49,19 @@ if (Test-Path -LiteralPath $doneMarker) {
}
}
# 1b. fetch-source.txt holds the pxe-upload share password (startnet writes
# it for the first-logon Fetch/Verify scripts). Once the PPKG has run the
# PC is off the imaging LAN and the file has no use left.
$fetchSource = 'C:\Enrollment\fetch-source.txt'
if ((Test-Path -LiteralPath $appliedMarker) -and (Test-Path -LiteralPath $fetchSource)) {
try {
Remove-Item -LiteralPath $fetchSource -Force -ErrorAction Stop
Write-Host "Removed $fetchSource (share login)."
} catch {
Write-Warning "Could not remove ${fetchSource}: $_"
}
}
# 2. AutoLogonCount after the ShopFloor handover
$handedOver = $false
$countGone = $true