#!/usr/bin/env bash # Run a command on a Ubiquiti airOS radio over SSH (password auth). # # Usage: # AIROS_PASSWORDS='pw1,pw2' ./airos-ssh.sh "" # # Env: # AIROS_USER login user (default: ubnt) # AIROS_PASSWORDS comma-separated passwords, tried in order (required) # # Handles the legacy KEX/hostkey algos old airOS dropbear builds need and # never writes to known_hosts. Exits with the remote command's status, or # 255 if every password is rejected. set -u if [ $# -lt 2 ]; then echo "Usage: AIROS_PASSWORDS='pw1,pw2' $0 \"\"" >&2 exit 1 fi IP="$1"; shift CMD="$*" USER="${AIROS_USER:-ubnt}" IFS=',' read -ra PWS <<< "${AIROS_PASSWORDS:?set AIROS_PASSWORDS (comma-separated)}" for PW in "${PWS[@]}"; do OUT=$(AIP="$IP" AUSER="$USER" APASS="$PW" ACMD="$CMD" expect <<'EOF' set timeout 30 set ip $env(AIP) set user $env(AUSER) set pass $env(APASS) set cmd $env(ACMD) spawn ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ -o LogLevel=ERROR -o ConnectTimeout=8 -o NumberOfPasswordPrompts=1 \ -o PreferredAuthentications=password \ -o HostKeyAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group14-sha1 \ "$user@$ip" $cmd expect { -re {(?i)password:} { send -- "$pass\r"; exp_continue } eof } catch wait result exit [lindex $result 3] EOF ) RC=$? if [ $RC -eq 0 ] || ! grep -q "Permission denied" <<<"$OUT"; then # Drop the echoed password-prompt line, keep real output. printf '%s\n' "$OUT" | sed '/[Pp]assword:/d' exit $RC fi done echo "airos-ssh: all passwords failed for $USER@$IP" >&2 exit 255