mirror of
https://github.com/dockur/windows.git
synced 2026-08-24 15:48:59 +01:00
fix: Reject control characters in workgroup names (#2076)
This commit is contained in:
+148
-66
@@ -36,13 +36,18 @@ updateXML() {
|
|||||||
updateLocaleXML "$asset" "$language" || return 1
|
updateLocaleXML "$asset" "$language" || return 1
|
||||||
|
|
||||||
if [ -n "$domain" ]; then
|
if [ -n "$domain" ]; then
|
||||||
|
|
||||||
result=$(prepareDomainAccount "$domain") || return 1
|
result=$(prepareDomainAccount "$domain") || return 1
|
||||||
mapfile -t values <<< "$result"
|
mapfile -t values <<< "$result"
|
||||||
(( ${#values[@]} == 2 )) || return 1
|
(( ${#values[@]} == 2 )) || return 1
|
||||||
|
|
||||||
account="${values[0]}"
|
account="${values[0]}"
|
||||||
auth="${values[1]}"
|
auth="${values[1]}"
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
updateLocalAccount "$asset" || return 1
|
updateLocalAccount "$asset" || return 1
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
updateMembership "$asset" "$domain" "$workgroup" "$account" "$auth" || return 1
|
updateMembership "$asset" "$domain" "$workgroup" "$account" "$auth" || return 1
|
||||||
@@ -74,11 +79,16 @@ setXML() {
|
|||||||
# A custom answer file always takes precedence over bundled or generated
|
# A custom answer file always takes precedence over bundled or generated
|
||||||
# templates, in root, storage, then asset-directory order.
|
# templates, in root, storage, then asset-directory order.
|
||||||
for file in "${custom_files[@]}"; do
|
for file in "${custom_files[@]}"; do
|
||||||
|
|
||||||
if [ -f "$file" ] && [ -s "$file" ]; then
|
if [ -f "$file" ] && [ -s "$file" ]; then
|
||||||
|
|
||||||
CUSTOM_XML="Y"
|
CUSTOM_XML="Y"
|
||||||
XML="$file"
|
XML="$file"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
file="$1"
|
file="$1"
|
||||||
@@ -111,21 +121,25 @@ setXML() {
|
|||||||
hasAnswerFile() {
|
hasAnswerFile() {
|
||||||
|
|
||||||
local id="$1"
|
local id="$1"
|
||||||
|
|
||||||
local file="/run/assets/$id.xml"
|
local file="/run/assets/$id.xml"
|
||||||
|
|
||||||
[ -s "$file" ] && return 0
|
[ -s "$file" ] && return 0
|
||||||
|
|
||||||
if [[ "${id,,}" == *"-eval" ]]; then
|
if [[ "${id,,}" == *"-eval" ]]; then
|
||||||
|
|
||||||
file="/run/assets/${id%-eval}.xml"
|
file="/run/assets/${id%-eval}.xml"
|
||||||
[ -s "$file" ] && return 0
|
[ -s "$file" ] && return 0
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Editions without a dedicated template can use the generic template.
|
# Editions without a dedicated template can use the generic template.
|
||||||
case "${id,,}" in
|
case "${id,,}" in
|
||||||
|
|
||||||
"win7"* | "win8"* | "win10"* | "win11"* | "winvista"* | "win20"* )
|
"win7"* | "win8"* | "win10"* | "win11"* | "winvista"* | "win20"* )
|
||||||
|
|
||||||
file="/run/assets/${id%%-*}.xml"
|
file="/run/assets/${id%%-*}.xml"
|
||||||
[ -s "$file" ] && return 0
|
[ -s "$file" ] && return 0 ;;
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
@@ -137,8 +151,8 @@ addAnswerFile() {
|
|||||||
local language="$2"
|
local language="$2"
|
||||||
local stage="$3"
|
local stage="$3"
|
||||||
|
|
||||||
local answer="$stage/Autounattend.xml"
|
|
||||||
local script="" name
|
local script="" name
|
||||||
|
local answer="$stage/Autounattend.xml"
|
||||||
|
|
||||||
if enabled "$MANUAL"; then
|
if enabled "$MANUAL"; then
|
||||||
removeGeneratedXML "$asset" || return 1
|
removeGeneratedXML "$asset" || return 1
|
||||||
@@ -163,10 +177,12 @@ addAnswerFile() {
|
|||||||
# Custom answer files keep their user-defined settings, but still receive
|
# Custom answer files keep their user-defined settings, but still receive
|
||||||
# the media-specific disk and configuration-set adjustments below.
|
# the media-specific disk and configuration-set adjustments below.
|
||||||
if [ -z "${CUSTOM_XML:-}" ]; then
|
if [ -z "${CUSTOM_XML:-}" ]; then
|
||||||
|
|
||||||
if ! updateXML "$answer" "$language"; then
|
if ! updateXML "$answer" "$language"; then
|
||||||
error "Failed to update answer file: $answer"
|
error "Failed to update answer file: $answer"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! updateDiskID "$answer" "${DISK_TYPE:-}" "setup"; then
|
if ! updateDiskID "$answer" "${DISK_TYPE:-}" "setup"; then
|
||||||
@@ -182,7 +198,9 @@ addAnswerFile() {
|
|||||||
validateGeneratedXML "$answer" || return 1
|
validateGeneratedXML "$answer" || return 1
|
||||||
|
|
||||||
if [ -z "${CUSTOM_XML:-}" ]; then
|
if [ -z "${CUSTOM_XML:-}" ]; then
|
||||||
|
|
||||||
script=$(prepareSetupScript "$asset" "$stage") || exit 84
|
script=$(prepareSetupScript "$asset" "$stage") || exit 84
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
@@ -230,14 +248,17 @@ generateAnswerFile() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$type" != "evaluation" ] || [ "$remove_selector" = "Y" ]; then
|
if [ "$type" != "evaluation" ] || [ "$remove_selector" = "Y" ]; then
|
||||||
|
|
||||||
if ! xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -d "$install_from" "$tmp"; then
|
if ! xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -d "$install_from" "$tmp"; then
|
||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
error "Failed to generate $type answer file from $source!"
|
error "Failed to generate $type answer file from $source!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$index" ]; then
|
if [ -n "$index" ]; then
|
||||||
|
|
||||||
install_count=$(getXMLNodeCount "$tmp" "$install_from") || {
|
install_count=$(getXMLNodeCount "$tmp" "$install_from") || {
|
||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
return 1
|
return 1
|
||||||
@@ -250,6 +271,7 @@ generateAnswerFile() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$install_count" = "0" ]; then
|
if [ "$install_count" = "0" ]; then
|
||||||
|
|
||||||
# InstallFrom must be inserted before InstallTo to preserve the ordering
|
# InstallFrom must be inserted before InstallTo to preserve the ordering
|
||||||
# expected by the Windows Setup schema.
|
# expected by the Windows Setup schema.
|
||||||
install_to_count=$(getXMLNodeCount "$tmp" "$install_to") || {
|
install_to_count=$(getXMLNodeCount "$tmp" "$install_to") || {
|
||||||
@@ -278,6 +300,7 @@ generateAnswerFile() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! markGeneratedXML "$tmp"; then
|
if ! markGeneratedXML "$tmp"; then
|
||||||
@@ -311,16 +334,18 @@ generateEvalXML() {
|
|||||||
[[ "${id,,}" == *"-eval" ]] || return 1
|
[[ "${id,,}" == *"-eval" ]] || return 1
|
||||||
|
|
||||||
local normal="${id::-5}"
|
local normal="${id::-5}"
|
||||||
local source="/run/assets/$normal.xml"
|
|
||||||
local target="/run/assets/$id.xml"
|
|
||||||
local index="$detected_index"
|
|
||||||
local remove_selector="N"
|
local remove_selector="N"
|
||||||
|
local index="$detected_index"
|
||||||
|
local target="/run/assets/$id.xml"
|
||||||
|
local source="/run/assets/$normal.xml"
|
||||||
|
|
||||||
removeGeneratedXML "$source" || return 1
|
removeGeneratedXML "$source" || return 1
|
||||||
|
|
||||||
if [ ! -s "$source" ]; then
|
if [ ! -s "$source" ]; then
|
||||||
|
|
||||||
source="/run/assets/${normal%%-*}.xml"
|
source="/run/assets/${normal%%-*}.xml"
|
||||||
removeGeneratedXML "$source" || return 1
|
removeGeneratedXML "$source" || return 1
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -s "$source" ] || return 1
|
[ -s "$source" ] || return 1
|
||||||
@@ -348,12 +373,13 @@ generateFallbackXML() {
|
|||||||
local id="$1"
|
local id="$1"
|
||||||
local index="${2:-}"
|
local index="${2:-}"
|
||||||
|
|
||||||
local source="/run/assets/${id%%-*}.xml"
|
|
||||||
local target="/run/assets/$id.xml"
|
local target="/run/assets/$id.xml"
|
||||||
|
local source="/run/assets/${id%%-*}.xml"
|
||||||
|
|
||||||
[ "$source" != "$target" ] || return 1
|
[ "$source" != "$target" ] || return 1
|
||||||
|
|
||||||
removeGeneratedXML "$source" || return 1
|
removeGeneratedXML "$source" || return 1
|
||||||
|
|
||||||
[ -s "$source" ] || return 1
|
[ -s "$source" ] || return 1
|
||||||
|
|
||||||
generateAnswerFile "$id" "$source" "$target" "$index" "fallback" "Y" || return 1
|
generateAnswerFile "$id" "$source" "$target" "$index" "fallback" "Y" || return 1
|
||||||
@@ -369,6 +395,7 @@ updateUserXML() {
|
|||||||
local specialize="$XML_COMPONENT_SHELL_SPECIALIZE"
|
local specialize="$XML_COMPONENT_SHELL_SPECIALIZE"
|
||||||
local oobe="$XML_COMPONENT_SHELL_OOBE"
|
local oobe="$XML_COMPONENT_SHELL_OOBE"
|
||||||
local app="$APP for $ENGINE"
|
local app="$APP for $ENGINE"
|
||||||
|
|
||||||
local -a args=(
|
local -a args=(
|
||||||
-L
|
-L
|
||||||
-N "$XML_NS_UNATTEND_ARG"
|
-N "$XML_NS_UNATTEND_ARG"
|
||||||
@@ -423,7 +450,6 @@ updateLocaleXML() {
|
|||||||
updateAutologinXML() {
|
updateAutologinXML() {
|
||||||
|
|
||||||
local asset="$1"
|
local asset="$1"
|
||||||
|
|
||||||
local shell="$XML_COMPONENT_SHELL_OOBE"
|
local shell="$XML_COMPONENT_SHELL_OOBE"
|
||||||
|
|
||||||
disabled "${AUTOLOGIN:-}" || return 0
|
disabled "${AUTOLOGIN:-}" || return 0
|
||||||
@@ -437,8 +463,7 @@ updateProductKey() {
|
|||||||
|
|
||||||
local script="$1"
|
local script="$1"
|
||||||
|
|
||||||
local key="${KEY:-}"
|
local key="${KEY:-}" content
|
||||||
local content
|
|
||||||
|
|
||||||
if [ -z "$key" ]; then
|
if [ -z "$key" ]; then
|
||||||
removeSetupBlock "$script" "PRODUCT_KEY" || return 1
|
removeSetupBlock "$script" "PRODUCT_KEY" || return 1
|
||||||
@@ -540,6 +565,7 @@ configureDomainAccounts() {
|
|||||||
(( autologon_count <= 1 )) || return 1
|
(( autologon_count <= 1 )) || return 1
|
||||||
|
|
||||||
if [ "$accounts_count" = "0" ]; then
|
if [ "$accounts_count" = "0" ]; then
|
||||||
|
|
||||||
child_count=$(getXMLNodeCount "$asset" "$shell/*") || return 1
|
child_count=$(getXMLNodeCount "$asset" "$shell/*") || return 1
|
||||||
|
|
||||||
if [ "$child_count" = "0" ]; then
|
if [ "$child_count" = "0" ]; then
|
||||||
@@ -547,6 +573,7 @@ configureDomainAccounts() {
|
|||||||
else
|
else
|
||||||
xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -i "$shell/*[1]" -t elem -n 'UserAccounts' "$asset" || return 1
|
xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -i "$shell/*[1]" -t elem -n 'UserAccounts' "$asset" || return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local created_accounts="$accounts/*[local-name()='DomainAccounts']"
|
local created_accounts="$accounts/*[local-name()='DomainAccounts']"
|
||||||
@@ -612,10 +639,10 @@ configureDomainJoin() {
|
|||||||
local ou="$5"
|
local ou="$5"
|
||||||
local arch="$6"
|
local arch="$6"
|
||||||
|
|
||||||
|
local cred_domain="$domain"
|
||||||
local component="$XML_COMPONENT_UNATTENDED_JOIN"
|
local component="$XML_COMPONENT_UNATTENDED_JOIN"
|
||||||
local identification="$component/u:Identification"
|
local identification="$component/u:Identification"
|
||||||
local credentials="$identification/*[local-name()='Credentials']"
|
local credentials="$identification/*[local-name()='Credentials']"
|
||||||
local cred_domain="$domain"
|
|
||||||
|
|
||||||
local -a args=(
|
local -a args=(
|
||||||
-L
|
-L
|
||||||
@@ -665,6 +692,7 @@ configureDomainJoin() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
xmlstarlet ed "${values[@]}" "$asset" || return 1
|
xmlstarlet ed "${values[@]}" "$asset" || return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,12 +752,17 @@ findPrimaryLocalAccount() {
|
|||||||
IFS=';,' read -r -a groups <<< "$group"
|
IFS=';,' read -r -a groups <<< "$group"
|
||||||
|
|
||||||
for token in "${groups[@]}"; do
|
for token in "${groups[@]}"; do
|
||||||
|
|
||||||
token="${token#"${token%%[![:space:]]*}"}"
|
token="${token#"${token%%[![:space:]]*}"}"
|
||||||
token="${token%"${token##*[![:space:]]}"}"
|
token="${token%"${token##*[![:space:]]}"}"
|
||||||
|
|
||||||
[[ "${token,,}" == "administrators" ]] || continue
|
[[ "${token,,}" == "administrators" ]] || continue
|
||||||
|
|
||||||
admin_primary="$position"
|
admin_primary="$position"
|
||||||
((admin_matches += 1))
|
((admin_matches += 1))
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
done <<< "$records"
|
done <<< "$records"
|
||||||
@@ -757,8 +790,7 @@ findPrimaryLocalAccount() {
|
|||||||
|
|
||||||
[ -n "$selected_user" ] || return 1
|
[ -n "$selected_user" ] || return 1
|
||||||
|
|
||||||
printf '%s\n' \
|
printf '%s\n' "$selected" "$selected_user" "$found_admin" "$found_autologon"
|
||||||
"$selected" "$selected_user" "$found_admin" "$found_autologon"
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -961,13 +993,16 @@ updateDiskID() {
|
|||||||
# The setup overlay occupies disk 0, so common VirtIO installation disks move
|
# The setup overlay occupies disk 0, so common VirtIO installation disks move
|
||||||
# to disk 1 in setup-image mode. Rebuilt media keeps the original disk layout.
|
# to disk 1 in setup-image mode. Rebuilt media keeps the original disk layout.
|
||||||
case "$mode" in
|
case "$mode" in
|
||||||
|
|
||||||
"setup" )
|
"setup" )
|
||||||
|
|
||||||
case "$disk_type" in
|
case "$disk_type" in
|
||||||
"" | "scsi" | "virtio-scsi" | "blk" | "virtio-blk" ) target="1" ;;
|
"" | "scsi" | "virtio-scsi" | "blk" | "virtio-blk" ) target="1" ;;
|
||||||
esac
|
esac ;;
|
||||||
;;
|
|
||||||
"image" ) ;;
|
"image" ) ;;
|
||||||
* ) return 1 ;;
|
* ) return 1 ;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
count=$(getXMLNodeCount "$asset" "$disk_ids") || {
|
count=$(getXMLNodeCount "$asset" "$disk_ids") || {
|
||||||
@@ -983,12 +1018,14 @@ updateDiskID() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while IFS= read -r value; do
|
while IFS= read -r value; do
|
||||||
|
|
||||||
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
|
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
|
||||||
error "Invalid DiskID value in answer file: $asset"
|
error "Invalid DiskID value in answer file: $asset"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ids+=( "$value" )
|
ids+=( "$value" )
|
||||||
|
|
||||||
done <<< "$values"
|
done <<< "$values"
|
||||||
|
|
||||||
mapfile -t ids < <(printf '%s\n' "${ids[@]}" | sort -u)
|
mapfile -t ids < <(printf '%s\n' "${ids[@]}" | sort -u)
|
||||||
@@ -1000,15 +1037,16 @@ updateDiskID() {
|
|||||||
[ "$current" = "$target" ] && return 0
|
[ "$current" = "$target" ] && return 0
|
||||||
|
|
||||||
case "$current" in
|
case "$current" in
|
||||||
|
|
||||||
"0" | "1" ) ;;
|
"0" | "1" ) ;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
error "Unsupported DiskID $current in answer file: $asset"
|
error "Unsupported DiskID $current in answer file: $asset"
|
||||||
return 1
|
return 1 ;;
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if ! xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -u "${disk_ids}[normalize-space(.)='$current']" -v "$target" "$asset"; then
|
if ! xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -u "${disk_ids}[normalize-space(.)='$current']" -v "$target" "$asset"; then
|
||||||
|
|
||||||
error "Failed to update DiskID in answer file: $asset"
|
error "Failed to update DiskID in answer file: $asset"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -1020,7 +1058,6 @@ getXMLArchitecture() {
|
|||||||
|
|
||||||
local asset="$1"
|
local asset="$1"
|
||||||
|
|
||||||
local arch
|
|
||||||
# Prefer architecture declarations from Windows PE setup components and skip
|
# Prefer architecture declarations from Windows PE setup components and skip
|
||||||
# wow64 compatibility components, which do not describe the target image.
|
# wow64 compatibility components, which do not describe the target image.
|
||||||
local -a paths=(
|
local -a paths=(
|
||||||
@@ -1028,15 +1065,19 @@ getXMLArchitecture() {
|
|||||||
"$XML_SETTINGS_WINDOWS_PE/u:component[@name='Microsoft-Windows-International-Core-WinPE']/@processorArchitecture"
|
"$XML_SETTINGS_WINDOWS_PE/u:component[@name='Microsoft-Windows-International-Core-WinPE']/@processorArchitecture"
|
||||||
'/u:unattend/u:settings/u:component[translate(@processorArchitecture, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz") != "wow64"]/@processorArchitecture'
|
'/u:unattend/u:settings/u:component[translate(@processorArchitecture, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz") != "wow64"]/@processorArchitecture'
|
||||||
)
|
)
|
||||||
local path
|
|
||||||
|
local arch path
|
||||||
|
|
||||||
for path in "${paths[@]}"; do
|
for path in "${paths[@]}"; do
|
||||||
|
|
||||||
arch=$(xmlstarlet sel -N "$XML_NS_UNATTEND_ARG" -T -t -v "normalize-space(string(($path)[1]))" "$asset") || arch=""
|
arch=$(xmlstarlet sel -N "$XML_NS_UNATTEND_ARG" -T -t -v "normalize-space(string(($path)[1]))" "$asset") || arch=""
|
||||||
|
|
||||||
[ -n "$arch" ] || continue
|
[ -n "$arch" ] || continue
|
||||||
[[ "${arch,,}" != "wow64" ]] || continue
|
[[ "${arch,,}" != "wow64" ]] || continue
|
||||||
|
|
||||||
printf '%s' "$arch"
|
printf '%s' "$arch"
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
@@ -1177,6 +1218,7 @@ removeEmbeddedProductKeys() {
|
|||||||
"$asset") || return 1
|
"$asset") || return 1
|
||||||
|
|
||||||
while IFS="$separator" read -r position child_key direct_key; do
|
while IFS="$separator" read -r position child_key direct_key; do
|
||||||
|
|
||||||
[ -n "$position" ] || continue
|
[ -n "$position" ] || continue
|
||||||
|
|
||||||
if [[ ! "$child_key" =~ ^[A-Za-z0-9]{5}(-[A-Za-z0-9]{5}){4}$ ]] &&
|
if [[ ! "$child_key" =~ ^[A-Za-z0-9]{5}(-[A-Za-z0-9]{5}){4}$ ]] &&
|
||||||
@@ -1193,11 +1235,13 @@ removeEmbeddedProductKeys() {
|
|||||||
[ -z "$delete_xpath" ] || delete_xpath+=" | "
|
[ -z "$delete_xpath" ] || delete_xpath+=" | "
|
||||||
delete_xpath+="($product_keys)[$position]/text()[normalize-space()][1]"
|
delete_xpath+="($product_keys)[$position]/text()[normalize-space()][1]"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done <<< "$records"
|
done <<< "$records"
|
||||||
|
|
||||||
[ -n "$delete_xpath" ] || return 0
|
[ -n "$delete_xpath" ] || return 0
|
||||||
|
|
||||||
xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -d "$delete_xpath" "$asset" || return 1
|
xmlstarlet ed -L -N "$XML_NS_UNATTEND_ARG" -d "$delete_xpath" "$asset" || return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1235,7 +1279,9 @@ validateSetupScript() {
|
|||||||
[ -s "$file" ] || return 1
|
[ -s "$file" ] || return 1
|
||||||
|
|
||||||
for block in "${blocks[@]}"; do
|
for block in "${blocks[@]}"; do
|
||||||
|
|
||||||
validateSetupBlock "$file" "$block" || return 1
|
validateSetupBlock "$file" "$block" || return 1
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
@@ -1334,8 +1380,6 @@ validateWorkgroup() {
|
|||||||
|
|
||||||
local value="$1"
|
local value="$1"
|
||||||
|
|
||||||
local safe
|
|
||||||
|
|
||||||
[ -z "$value" ] && return 0
|
[ -z "$value" ] && return 0
|
||||||
|
|
||||||
if [ "${#value}" -gt 15 ]; then
|
if [ "${#value}" -gt 15 ]; then
|
||||||
@@ -1343,6 +1387,12 @@ validateWorkgroup() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "$value" =~ [[:cntrl:]] ]]; then
|
||||||
|
error "The WORKGROUP variable cannot contain control characters!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local safe
|
||||||
safe=$(printf '%s' "$value" | tr -d '"/\\[]:;|=,+*?<>') || return 1
|
safe=$(printf '%s' "$value" | tr -d '"/\\[]:;|=,+*?<>') || return 1
|
||||||
|
|
||||||
if [[ "$safe" != "$value" ]]; then
|
if [[ "$safe" != "$value" ]]; then
|
||||||
@@ -1371,6 +1421,7 @@ validateMembership() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
validateWorkgroup "$WORKGROUP" || return 1
|
validateWorkgroup "$WORKGROUP" || return 1
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1380,7 +1431,6 @@ validatePassword() {
|
|||||||
local desc="${2:-}"
|
local desc="${2:-}"
|
||||||
|
|
||||||
local suffix=""
|
local suffix=""
|
||||||
|
|
||||||
[ -n "$desc" ] && suffix=" for $desc"
|
[ -n "$desc" ] && suffix=" for $desc"
|
||||||
|
|
||||||
if [ "${#value}" -gt 127 ]; then
|
if [ "${#value}" -gt 127 ]; then
|
||||||
@@ -1404,15 +1454,17 @@ validateUsername() {
|
|||||||
local maximum length_suffix invalid_message
|
local maximum length_suffix invalid_message
|
||||||
|
|
||||||
case "$type" in
|
case "$type" in
|
||||||
|
|
||||||
"local" )
|
"local" )
|
||||||
|
|
||||||
[ -z "$value" ] && return 0
|
[ -z "$value" ] && return 0
|
||||||
|
|
||||||
maximum=20
|
maximum=20
|
||||||
length_suffix=""
|
length_suffix=""
|
||||||
invalid_message="The USERNAME variable contains characters that are not supported by Windows local accounts!"
|
invalid_message="The USERNAME variable contains characters that are not supported by Windows local accounts!" ;;
|
||||||
;;
|
|
||||||
|
|
||||||
"domain" )
|
"domain" )
|
||||||
|
|
||||||
if [ -z "$value" ]; then
|
if [ -z "$value" ]; then
|
||||||
error "The USERNAME variable does not contain a valid domain account name!"
|
error "The USERNAME variable does not contain a valid domain account name!"
|
||||||
return 1
|
return 1
|
||||||
@@ -1420,12 +1472,11 @@ validateUsername() {
|
|||||||
|
|
||||||
maximum=256
|
maximum=256
|
||||||
length_suffix=" for a domain account"
|
length_suffix=" for a domain account"
|
||||||
invalid_message="The domain account name contains characters that are not supported by Windows unattended setup!"
|
invalid_message="The domain account name contains characters that are not supported by Windows unattended setup!" ;;
|
||||||
;;
|
|
||||||
|
|
||||||
* )
|
* )
|
||||||
return 1
|
return 1 ;;
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ "${#value}" -gt "$maximum" ]; then
|
if [ "${#value}" -gt "$maximum" ]; then
|
||||||
@@ -1441,8 +1492,7 @@ validateUsername() {
|
|||||||
case "$value" in
|
case "$value" in
|
||||||
*'"'* | *'/'* | *\\* | *'['* | *']'* | *':'* | *';'* | *'|'* | *'='* | *','* | *'+'* | *'*'* | *'?'* | *'<'* | *'>'* | *'%'* | *'@'* )
|
*'"'* | *'/'* | *\\* | *'['* | *']'* | *':'* | *';'* | *'|'* | *'='* | *','* | *'+'* | *'*'* | *'?'* | *'<'* | *'>'* | *'%'* | *'@'* )
|
||||||
error "$invalid_message"
|
error "$invalid_message"
|
||||||
return 1
|
return 1 ;;
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ "$value" == *"." ]]; then
|
if [[ "$value" == *"." ]]; then
|
||||||
@@ -1456,22 +1506,51 @@ validateUsername() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
case "${value^^}" in
|
case "${value^^}" in
|
||||||
|
|
||||||
"NONE" )
|
"NONE" )
|
||||||
|
|
||||||
error "The USERNAME value \"NONE\" is reserved by Windows!"
|
error "The USERNAME value \"NONE\" is reserved by Windows!"
|
||||||
return 1
|
return 1 ;;
|
||||||
;;
|
|
||||||
|
|
||||||
"ADMINISTRATOR" | "GUEST" | "DEFAULTACCOUNT" | "WDAGUTILITYACCOUNT" | "WSIACCOUNT" )
|
"ADMINISTRATOR" | "GUEST" | "DEFAULTACCOUNT" | "WDAGUTILITYACCOUNT" | "WSIACCOUNT" )
|
||||||
|
|
||||||
[[ "$type" == "domain" ]] && return 0
|
[[ "$type" == "domain" ]] && return 0
|
||||||
|
|
||||||
error "The USERNAME value \"$value\" is reserved for a built-in Windows account!"
|
error "The USERNAME value \"$value\" is reserved for a built-in Windows account!"
|
||||||
return 1
|
return 1 ;;
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateDomainName() {
|
||||||
|
|
||||||
|
local value="$1"
|
||||||
|
local name="${2:-DOMAIN}"
|
||||||
|
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
error "The $name variable must contain a valid domain name!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$value" == *"://"* ]]; then
|
||||||
|
error "The $name variable must contain a domain name, not a URL!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${#value}" -gt 255 ] ||
|
||||||
|
[[ "$value" =~ [[:cntrl:]] ]] ||
|
||||||
|
[[ "$value" =~ [[:space:]] ]] ||
|
||||||
|
[[ ! "$value" =~ ^[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$ ]]; then
|
||||||
|
|
||||||
|
error "The $name variable does not contain a valid domain name!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
validateLegacyText() {
|
validateLegacyText() {
|
||||||
|
|
||||||
local name="$1"
|
local name="$1"
|
||||||
@@ -1479,7 +1558,6 @@ validateLegacyText() {
|
|||||||
local desc="${3:-}"
|
local desc="${3:-}"
|
||||||
|
|
||||||
local suffix=""
|
local suffix=""
|
||||||
|
|
||||||
[ -n "$desc" ] && suffix=" for $desc"
|
[ -n "$desc" ] && suffix=" for $desc"
|
||||||
|
|
||||||
if [[ "$value" =~ [[:cntrl:]] ]]; then
|
if [[ "$value" =~ [[:cntrl:]] ]]; then
|
||||||
@@ -1501,7 +1579,6 @@ validateLegacyUsername() {
|
|||||||
local desc="${2:-}"
|
local desc="${2:-}"
|
||||||
|
|
||||||
local suffix=""
|
local suffix=""
|
||||||
|
|
||||||
[ -n "$desc" ] && suffix=" for $desc"
|
[ -n "$desc" ] && suffix=" for $desc"
|
||||||
|
|
||||||
if [ -z "$value" ]; then
|
if [ -z "$value" ]; then
|
||||||
@@ -1537,38 +1614,31 @@ validateLegacyUsername() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
case "${value^^}" in
|
case "${value^^}" in
|
||||||
|
|
||||||
"NONE" )
|
"NONE" )
|
||||||
error "The USERNAME value \"NONE\" is reserved by Windows$suffix!"
|
error "The USERNAME value \"NONE\" is reserved by Windows$suffix!"
|
||||||
return 1 ;;
|
return 1 ;;
|
||||||
|
|
||||||
"ADMINISTRATOR" | "GUEST" | "DEFAULTACCOUNT" | "WDAGUTILITYACCOUNT" | "WSIACCOUNT" )
|
"ADMINISTRATOR" | "GUEST" | "DEFAULTACCOUNT" | "WDAGUTILITYACCOUNT" | "WSIACCOUNT" )
|
||||||
error "The USERNAME value \"$value\" is reserved for a built-in Windows account$suffix!"
|
error "The USERNAME value \"$value\" is reserved for a built-in Windows account$suffix!"
|
||||||
return 1 ;;
|
return 1 ;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
validateDomainName() {
|
validateLegacyEncoding() {
|
||||||
|
|
||||||
local value="$1"
|
local name="$1"
|
||||||
local name="${2:-DOMAIN}"
|
local value="$2"
|
||||||
|
local desc="${3:-}"
|
||||||
|
|
||||||
if [ -z "$value" ]; then
|
local suffix=""
|
||||||
error "The $name variable must contain a valid domain name!"
|
[ -n "$desc" ] && suffix=" for $desc"
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$value" == *"://"* ]]; then
|
if LC_ALL=C grep -q '[^ -~]' <<< "$value"; then
|
||||||
error "The $name variable must contain a domain name, not a URL!"
|
error "The $name variable may only contain printable ASCII characters$suffix!"
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${#value}" -gt 255 ] ||
|
|
||||||
[[ "$value" =~ [[:cntrl:]] ]] ||
|
|
||||||
[[ "$value" =~ [[:space:]] ]] ||
|
|
||||||
[[ ! "$value" =~ ^[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$ ]]; then
|
|
||||||
|
|
||||||
error "The $name variable does not contain a valid domain name!"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1602,7 +1672,9 @@ prepareDomainAccount() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
case "$auth" in
|
case "$auth" in
|
||||||
|
|
||||||
*@* )
|
*@* )
|
||||||
|
|
||||||
account="${auth%%@*}"
|
account="${auth%%@*}"
|
||||||
qualifier="${auth#*@}"
|
qualifier="${auth#*@}"
|
||||||
|
|
||||||
@@ -1619,12 +1691,11 @@ prepareDomainAccount() {
|
|||||||
if [[ "${qualifier,,}" != "${domain,,}" ]]; then
|
if [[ "${qualifier,,}" != "${domain,,}" ]]; then
|
||||||
error "The domain in the USERNAME variable must match the DOMAIN variable!"
|
error "The domain in the USERNAME variable must match the DOMAIN variable!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi ;;
|
||||||
;;
|
|
||||||
|
|
||||||
* )
|
* )
|
||||||
account="$auth"
|
account="$auth" ;;
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
validateUsername "$account" "domain" || return 1
|
validateUsername "$account" "domain" || return 1
|
||||||
@@ -1764,6 +1835,7 @@ getXMLNodeCount() {
|
|||||||
local xpath="$2"
|
local xpath="$2"
|
||||||
|
|
||||||
xmlstarlet sel -N "$XML_NS_UNATTEND_ARG" -T -t -v "count($xpath)" "$asset"
|
xmlstarlet sel -N "$XML_NS_UNATTEND_ARG" -T -t -v "count($xpath)" "$asset"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validateUniqueXMLNodes() {
|
validateUniqueXMLNodes() {
|
||||||
@@ -1784,7 +1856,6 @@ validateUniqueXMLNodes() {
|
|||||||
copyXMLAsset() {
|
copyXMLAsset() {
|
||||||
|
|
||||||
local asset="$1"
|
local asset="$1"
|
||||||
|
|
||||||
local copy
|
local copy
|
||||||
|
|
||||||
if ! copy=$(mktemp "${asset}.XXXXXX") ||
|
if ! copy=$(mktemp "${asset}.XXXXXX") ||
|
||||||
@@ -1816,7 +1887,6 @@ replaceXMLAsset() {
|
|||||||
markGeneratedXML() {
|
markGeneratedXML() {
|
||||||
|
|
||||||
local file="$1"
|
local file="$1"
|
||||||
|
|
||||||
local marker='<!-- generated-answer-file: do not reuse as a template -->'
|
local marker='<!-- generated-answer-file: do not reuse as a template -->'
|
||||||
|
|
||||||
[ -s "$file" ] || return 1
|
[ -s "$file" ] || return 1
|
||||||
@@ -1852,7 +1922,6 @@ prepareSetupScript() {
|
|||||||
|
|
||||||
local asset="$1"
|
local asset="$1"
|
||||||
local stage="$2"
|
local stage="$2"
|
||||||
|
|
||||||
local staged=""
|
local staged=""
|
||||||
|
|
||||||
staged=$(stageSetupScript "$asset" "$stage") || return 1
|
staged=$(stageSetupScript "$asset" "$stage") || return 1
|
||||||
@@ -1993,7 +2062,6 @@ installSetupScript() {
|
|||||||
|
|
||||||
local script="$1"
|
local script="$1"
|
||||||
local root="$2"
|
local root="$2"
|
||||||
|
|
||||||
local target
|
local target
|
||||||
|
|
||||||
[ -n "$script" ] || return 0
|
[ -n "$script" ] || return 0
|
||||||
@@ -2132,6 +2200,7 @@ escapeSIFValue() {
|
|||||||
escapeRegistryValue() {
|
escapeRegistryValue() {
|
||||||
|
|
||||||
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
|
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extractDrivers() {
|
extractDrivers() {
|
||||||
@@ -2665,6 +2734,7 @@ disableAutoReboot() {
|
|||||||
local target="$1"
|
local target="$1"
|
||||||
|
|
||||||
local file
|
local file
|
||||||
|
local pattern='^[[:space:]]*HKLM[[:space:]]*,[[:space:]]*"SYSTEM\\CurrentControlSet\\Control\\CrashControl"[[:space:]]*,[[:space:]]*"AutoReboot"[[:space:]]*,[[:space:]]*[^,]*,'
|
||||||
|
|
||||||
file=$(find \
|
file=$(find \
|
||||||
"$target" -maxdepth 1 -type f -iname HIVESYS.INF -print -quit
|
"$target" -maxdepth 1 -type f -iname HIVESYS.INF -print -quit
|
||||||
@@ -2677,10 +2747,10 @@ disableAutoReboot() {
|
|||||||
|
|
||||||
# Keep setup crashes visible instead of immediately rebooting into an
|
# Keep setup crashes visible instead of immediately rebooting into an
|
||||||
# opaque installation loop.
|
# opaque installation loop.
|
||||||
if grep -Fqi 'HKLM,"SYSTEM\CurrentControlSet\Control\CrashControl","AutoReboot"' "$file"; then
|
if grep -Eqi "${pattern}[[:space:]]*[^,;[:space:]]+" "$file"; then
|
||||||
|
|
||||||
sed -i -E \
|
sed -i -E \
|
||||||
's|^(HKLM,"SYSTEM\\CurrentControlSet\\Control\\CrashControl","AutoReboot",[^,]*,)[^[:space:]]*|\1 0|I' \
|
"s|(${pattern})[[:space:]]*[^,;[:space:]]+|\\1 0|I" \
|
||||||
"$file" || return 1
|
"$file" || return 1
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -2769,9 +2839,15 @@ legacyInstall() {
|
|||||||
validateResolution "HEIGHT" "$HEIGHT" 200 || return 1
|
validateResolution "HEIGHT" "$HEIGHT" 200 || return 1
|
||||||
validateMembership || return 1
|
validateMembership || return 1
|
||||||
validateComputerName "$HOST" || return 1
|
validateComputerName "$HOST" || return 1
|
||||||
|
|
||||||
validateLegacyText "APP" "$APP" "$desc" || return 1
|
validateLegacyText "APP" "$APP" "$desc" || return 1
|
||||||
validateLegacyText "ENGINE" "$ENGINE" "$desc" || return 1
|
validateLegacyText "ENGINE" "$ENGINE" "$desc" || return 1
|
||||||
|
|
||||||
|
if [[ "$driver" == "2k" ]]; then
|
||||||
|
validateLegacyEncoding "APP" "$APP" "$desc" || return 1
|
||||||
|
validateLegacyEncoding "ENGINE" "$ENGINE" "$desc" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
XHEX=$(printf '%08x\n' "$((10#$WIDTH))") || return 1
|
XHEX=$(printf '%08x\n' "$((10#$WIDTH))") || return 1
|
||||||
YHEX=$(printf '%08x\n' "$((10#$HEIGHT))") || return 1
|
YHEX=$(printf '%08x\n' "$((10#$HEIGHT))") || return 1
|
||||||
|
|
||||||
@@ -2785,6 +2861,12 @@ legacyInstall() {
|
|||||||
validateLegacyUsername "$username" "$desc" || return 1
|
validateLegacyUsername "$username" "$desc" || return 1
|
||||||
validatePassword "$password" "$desc" || return 1
|
validatePassword "$password" "$desc" || return 1
|
||||||
|
|
||||||
|
if [[ "$driver" == "2k" ]]; then
|
||||||
|
validateLegacyEncoding "USERNAME" "$username" "$desc" || return 1
|
||||||
|
validateLegacyEncoding "PASSWORD" "$password" "$desc" || return 1
|
||||||
|
validateLegacyEncoding "WORKGROUP" "$workgroup" "$desc" || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
# WINNT.SIF and .reg files use different escaping rules, so prepare their
|
# WINNT.SIF and .reg files use different escaping rules, so prepare their
|
||||||
# values independently before generating either file.
|
# values independently before generating either file.
|
||||||
sifHost=$(escapeSIFValue "${HOST:-*}") || return 1
|
sifHost=$(escapeSIFValue "${HOST:-*}") || return 1
|
||||||
|
|||||||
Reference in New Issue
Block a user