. "$BST_LIB" # BST-TIMEOUT: 900 # sshpass 1.10 (meta-networking recipes-connectivity) -- the helper that answers # a password prompt for a program that will only read one from a terminal. It # allocates a pty, forks the command onto it as the command's CONTROLLING # terminal, watches the master side for the prompt indicator, and types the # password in. Nothing else: no crypt, no network, no library. # # WHAT THIS SUITE IS BUILT AROUND. sshpass is one page of C over five platform # primitives, and on this arm they split cleanly into two halves that this file # scores separately, because they fail for different reasons and a merged # verdict would hide both: # # * THE PTY HALF -- posix_openpt/grantpt/unlockpt/ptsname, fork+execvp, # setsid, TIOCSCTTY, and the prompt match itself. All of it is already # evidenced on this image (45-expect.test drives a real pty through spawn; # mingetty takes /dev/tty1 with TIOCSCTTY), and it is what actually delivers # the password. Every delivery case below therefore asserts THE ARTIFACT -- # a file the forked child wrote with the password it received -- and not # sshpass's exit status. # * THE REAPING HALF -- sshpass's main loop is a pselect(2) with no timeout, # woken by SIGCHLD, followed by waitpid(2). Both of those are known-broken # here: signal delivery does not work on this arm (brintos/linux#21), and a # blocking wait on a child that is still running never returns even after # that child exits (brintos/linux#74). A parent that cannot be told its # child is gone cannot return the child's status, so every exit-status case # below is scored on its own and is bounded rather than trusted. # # The split is why a case can be green on delivery and red on status for the # same run: the password DID reach the program through the pty, and sshpass then # could not report what came of it. That is the honest reading and it is the one # a merged case would destroy. # # THE TICKET'S NAMED CRITERION -- an sshd on loopback with a known password # account, driven through `sshpass -p` -- IS BLOCKED ON THIS IMAGE, in the # server, by gaps that are already tracked and are nothing to do with this port. # Both halves of the image's ssh surface refuse to authenticate anybody: # # * openssh's sshd cannot serve ANY connection -- chroot(2) is unwired and its # privilege-separation preauth child fatal()s before authentication # (brintos/linux#58, and the permanent reds that own it in 88-openssh.test). # * dropbear answers, and its per-connection child then dies at seteuid() # because the credential setters are unwired (brintos/linux#19, measured in # 89-libssh.test with dropbear's own dbclient as the control). This image's # dropbear is additionally built DROPBEAR_SVR_PASSWORD_AUTH=0, because glibc # 2.43 moved crypt() to libxcrypt and dropbear's shadow-hash comparison is # the one feature that calls it (dropbear_%.bbappend). # # So the criterion is run against dropbear anyway and scored as a # present-and-blocked red naming the server's gap -- never a skip. What CAN be # reached against that live server is the step before authentication, and it is # the strongest real-peer evidence this image can produce for this port: a real # ssh client, under sshpass's pty, is asked to accept an unknown host key, and # sshpass must detect that prompt and exit 6 without typing the password at a # question that is not a password question. require sshpass sshpass/present D=${TMPDIR:-/tmp}/bst-sshpass.$$ rm -rf "$D"; mkdir -p "$D" PW=br1nt0s PORT=22122 # --- a bounded run ------------------------------------------------------------ # Every case that lets sshpass fork has to carry its own wall-clock bound, and # neither obvious way of doing it exists here: timeout(1) bounds nothing on this # arm (it signals, and `timeout 3 sleep 30` exits 0 after 30 s -- brintos/linux#21), # and `wait` on a running child never returns (brintos/linux#74). This is the # runner's own watchdog shape applied per case: run behind a completion # sentinel, poll /proc/uptime with builtins only, kill -9 on overrun -- an # explicit SIGKILL does reap a syscall-blocked process even where delivery to a # handler does not. # # Sets SP_RC and SP_OUT. SP_RC is the literal string TIMEOUT when the bound # tripped; every caller distinguishes that from a status, because "sshpass never # returned" and "sshpass returned the wrong number" are different findings. # # BRINTOS-WORKAROUND: brintos/linux#21 revisit -- this whole function exists # because `timeout N cmd` bounds nothing here: it signals, and signal delivery # does not work on this arm at all. When #21 closes, every `sp` call collapses # to a `timeout` and this watchdog goes away -- revisit rather than remove, # because the sentinel poll is serviceable regardless. # BRINTOS-WORKAROUND: brintos/linux#74 revisit -- the reason a bound is needed # at all rather than merely tidy: sshpass's own waitpid(2) on a running child # never returns here, so a case with no bound hangs for the suite's whole 900 s. # When #74 closes the `reap` cases should go green on their own, which is the # signal to retire the attribution in `reap` -- against a run, not against the # issue's closed state. # _spread -- the clock every bound below is measured against. Sets SP_NOW and # SP_SRC and returns non-zero when neither source answered. # # IT SETS VARIABLES RATHER THAN PRINTING ONE, and that is not a style choice: a # function whose answer is read through `$( )` is a FORK, and this is called # once per poll iteration. Process spawns are this runtime's scarce resource, # and a spawn on a loaded guest costs seconds rather than milliseconds -- so a # clock that forks makes the poll loop expensive exactly when the bound it # enforces matters most. A shell function call is free; a command substitution # is not. # # read < /proc/uptime a BUILTIN read, no fork. First for that reason alone. # date +%s a real wall clock that does not go through procfs, # read only when the builtin answered nothing -- # procfs reads do trap on this runtime (a do_task_stat # / seq_read trap sits in the boot log immediately # before this suite's cases), which is why the fallback # exists at all. # # The two sources are NOT comparable in value -- one counts from boot, the other # from the epoch -- so SP_SRC is returned with the reading and the caller # re-baselines rather than subtracting across a switch. Subtracting across one # would either never trip (uptime minus epoch) or trip at once (epoch minus # uptime), and the second is the error this watchdog must never make: reporting # a working case as a hang. _spread() { if { read -r SP_NOW _ < /proc/uptime; } 2>/dev/null; then SP_NOW=${SP_NOW%.*} case $SP_NOW in ''|*[!0-9]*) ;; *) SP_SRC=up; return 0 ;; esac fi SP_NOW=$(date +%s 2>/dev/null) case $SP_NOW in ''|*[!0-9]*) ;; *) SP_SRC=date; return 0 ;; esac SP_NOW=; SP_SRC=; return 1 } SP_STDIN=/dev/null sp() { # sp _spb=$1; shift rm -f "$D/.rc" "$D/.out" { "$@" < "$SP_STDIN"; echo $? > "$D/.rc"; } > "$D/.out" 2>&1 & _sppid=$! # The baseline is taken here if it can be, and RE-TAKEN in the loop if it # could not. A clock that did not answer at THIS instant must not disable the # wall-clock bound for the rest of the case, which is what the previous shape # did: `_sps0` was latched from one reading -- and that reading needed a fork, # so a guest that could not spawn at that moment left the case with the tick # ceiling as its only exit. That is the only shape in which a single case can # spend the suite's entire bound, and a case that does is what the second # batch-664 verify recorded (eight cases in 900 s, nothing on the console # between them). Whether it is what happened there was NOT established -- that # guest was also being killed on RSS rate -- so this is a shape removed # because it can produce that reading, not a diagnosis of it. if _spread; then _sps0=$SP_NOW; _spsrc=$SP_SRC; else _sps0=; _spsrc=; fi # The tick count is the LAST resort, behind both clocks, and it is # deliberately five times the bound in ITERATIONS rather than in seconds: # sleep(1) does not sleep on this image when the guest is idle (~0.29 s, # linux-in-the-browser#120), so counting iterations as seconds would fire the # bound at a fifth of it and report a working case as a hang -- the one error # this watchdog must not make. It is a ceiling, not a bound: it is what keeps # a case finite when no clock answers at all, and the lazy baseline above is # what keeps it from being the only thing enforcing the bound. _spt=0 _spcap=$((_spb * 5)) SP_RC=TIMEOUT # THE TICK CEILING IS CHECKED UNCONDITIONALLY. The first shape of this loop # consulted it only on the branch where the clock read FAILED, so a clock that # was readable but STOOD STILL left the loop with no exit at all -- measured, # not supposed: batch-664's first verify put this suite at elapsed=900s # bound=900s with 29 cases emitted and case 30 never returning. No clock # behaviour can do that now. while [ ! -e "$D/.rc" ]; do _spover=0 [ "$_spt" -ge "$_spcap" ] && _spover=1 if [ "$_spover" = 0 ] && _spread; then if [ -z "$_sps0" ] || [ "$SP_SRC" != "$_spsrc" ]; then # No baseline yet, or the source changed under us. Start the window # here rather than subtract two readings that do not mean the same # thing. Costs at most one extra window per switch, which the ceiling # still caps. _sps0=$SP_NOW; _spsrc=$SP_SRC elif [ $((SP_NOW - _sps0)) -ge "$_spb" ]; then _spover=1 fi fi [ "$_spover" = 1 ] && { kill -9 "$_sppid" 2>/dev/null; break; } # Poll coarsely. Each iteration spawns a process, and sleep does not # actually sleep here, so a 1-second poll under a per-case bound measured in # tens of seconds is a near-spin that spawns hundreds of times per hanging # case -- and process spawns are this runtime's scarce resource (the # runner's own watchdog carries the same warning, and brintos/hardwarejs#20 # is the platform side of it). Resolution is irrelevant against these bounds. sleep 3 _spt=$((_spt + 1)) done [ -e "$D/.rc" ] && SP_RC=$(cat "$D/.rc") SP_OUT=$(cat "$D/.out" 2>/dev/null) # A killed subshell leaves sshpass itself parked on the pty it owns; the next # case would then be measuring two sshpasses. Explicit SIGKILL is the one # signal that does reach a blocked process here. # ...and so do the helpers it forked, which would otherwise sit on the pty # they were handed. Matched on the run-unique temp directory in their argv, so # this can only ever reach this suite's own children. # SPARING THE LIVE SERVER, WHICH THE BLANKET pkill DID NOT. dropbear is # started with -r "$D/hostkey", so the run-unique temp directory is in ITS # argv too and `pkill -f bst-sshpass.$$` matched it: the first live case tore # down the very server the second live case is measured against, so the # criterion case scored a connection refusal while reporting the server's auth # gap. Sweep by pid and skip DBPID instead. Its per-connection children are # not spared and should not be -- they are what this sweep is for. if command -v pgrep >/dev/null 2>&1; then pkill -9 -x sshpass 2>/dev/null for _spk in $(pgrep -f "bst-sshpass.$$" 2>/dev/null); do [ "$_spk" = "${DBPID:-}" ] && continue kill -9 "$_spk" 2>/dev/null done elif command -v pkill >/dev/null 2>&1; then pkill -9 -x sshpass 2>/dev/null [ -n "${DBPID:-}" ] || pkill -9 -f "bst-sshpass.$$" 2>/dev/null fi rm -f "$D/.rc" "$D/.out" SP_STDIN=/dev/null return 0 } # reap -- the exit-status half of a delivery case. A bound that # tripped is attributed at the case rather than left as a bare red: this is the # one failure mode the platform's own gaps predict, and an unattributed red here # would read as sshpass returning garbage. reap() { if [ "$SP_RC" = "$2" ]; then bst_ok "$1" elif [ "$SP_RC" = TIMEOUT ]; then bst_notok "$1" "brintos/linux#21 + #74 (no signal delivery; blocking wait never wakes): sshpass never reaped its child -- killed at the bound. out:'$(_bst_1line "$SP_OUT")'" else bst_notok "$1" "rc=$SP_RC want=$2 out:'$(_bst_1line "$SP_OUT")'" fi } # got -- the delivery half: what the forked child actually read # off its controlling terminal. Independent of sshpass's exit status by # construction, which is the whole point. got() { if [ -f "$2" ]; then _g=$(head -1 "$2" 2>/dev/null) check_eq "$1" "$PW" "$_g" else bst_notok "$1" "the child wrote no artifact at $2 -- it never reached its read" fi } # --- the child helpers -------------------------------------------------------- # Written as files rather than -c strings: sshpass execvp()s its argument # vector, and a quoted-to-death `sh -c` in the middle of that is the kind of # thing that fails for its own reasons and gets read as a platform finding. # # askpw.sh: prompt on the CONTROLLING TERMINAL -- not on stdout. sshpass does # not dup the pty onto the child's stdio (that is why ssh's own prompt reaches # it), so a helper that printed to stdout would never be seen by the matcher and # would prove nothing. cat > "$D/askpw.sh" <<'EOF' # $1 prompt $2 artifact $3 how many times to prompt $4 exit status : > "$2" _n=${3:-1}; _i=0 while [ "$_i" -lt "$_n" ]; do printf '%s' "$1" > /dev/tty read _p < /dev/tty printf '%s\n' "$_p" >> "$2" _i=$((_i + 1)) done exit "${4:-0}" EOF # say.sh: put one line on the controlling terminal and leave. Used for the two # host-key answers, which sshpass must recognise as NOT password prompts. cat > "$D/say.sh" <<'EOF' printf '%s\n' "$1" > /dev/tty exit 0 EOF # ctty.sh: report the child's controlling terminal -- the pty allocation itself, # read back from the child's side rather than asserted from the parent's. # # NOT `tty` AND NOT readlink /proc/self/fd/0. Both name the path that was # OPENED, so a child that opened /dev/tty is told "/dev/tty" and the slave's # real identity never appears (measured on x86-64 while writing this file). The # device number in field 7 of /proc/self/stat is the kernel's own answer and is # what actually distinguishes a Unix98 slave from no controlling terminal at # all. cat > "$D/ctty.sh" <<'EOF' _out=$1 exec < /dev/tty set -- $(cat /proc/self/stat) printf 'ttynr=%s tty=%s\n' "$7" "$(tty)" > "$_out" exit 0 EOF # quiet.sh: never prompts. The child's status has to survive the reaping path # with no prompt match anywhere in it. cat > "$D/quiet.sh" <<'EOF' exit 42 EOF # fd.sh: -d takes an already-open descriptor, which only a wrapper can arrange. cat > "$D/fd.sh" <<'EOF' _f=$1; shift exec 3< "$_f" exec sshpass -d 3 "$@" EOF printf '%s\n' "$PW" > "$D/pwfile" # --- identity and inventory --------------------------------------------------- check sshpass/binary test -x /usr/bin/sshpass check_out sshpass/version "sshpass 1.10" sshpass -V # -V also prints the compiled-in prompt indicator, which is the one build-time # decision this port makes visible at runtime: the recipe takes upstream's # default rather than --enable-password-prompt, so every match below is against # "assword" and a future recipe that changed it would fail here first. check_out sshpass/prompt-indicator 'Using "assword" as the default password prompt indicator.' sshpass -V check_out sshpass/help "Usage: sshpass" sshpass -h # With no command at all sshpass prints its help and exits 0 rather than erroring. check_out sshpass/no-args "Usage: sshpass" sshpass check_eq sshpass/no-trap-stubs "" \ "$(strings /usr/bin/sshpass 2>/dev/null | grep signature_mismatch)" # --- argument handling: the exit codes that need no child --------------------- # These reach neither fork nor pty, so they are the part of sshpass's documented # status contract that is answerable on this image without qualification. check_rc sshpass/rc-invalid-option 1 sshpass -Z true check_rc sshpass/rc-conflicting 2 sshpass -p "$PW" -f "$D/pwfile" true # --- password delivery over the pty ------------------------------------------ # Each source gets both halves: did the password arrive (artifact), and did # sshpass report the child's status (bounded). sp 25 sshpass -p "$PW" sh "$D/askpw.sh" 'Password: ' "$D/got-p" 1 0 got sshpass/deliver-p "$D/got-p" reap sshpass/rc-p 0 sp 25 sshpass -f "$D/pwfile" sh "$D/askpw.sh" 'Password: ' "$D/got-f" 1 0 got sshpass/deliver-f "$D/got-f" reap sshpass/rc-f 0 sp 25 env SSHPASS="$PW" sshpass -e sh "$D/askpw.sh" 'Password: ' "$D/got-e" 1 0 got sshpass/deliver-e "$D/got-e" reap sshpass/rc-e 0 sp 25 sh "$D/fd.sh" "$D/pwfile" sh "$D/askpw.sh" 'Password: ' "$D/got-d" 1 0 got sshpass/deliver-d "$D/got-d" reap sshpass/rc-d 0 SP_STDIN=$D/pwfile sp 25 sshpass sh "$D/askpw.sh" 'Password: ' "$D/got-stdin" 1 0 got sshpass/deliver-stdin "$D/got-stdin" reap sshpass/rc-stdin 0 # -P replaces the indicator entirely, so a prompt with no "assword" in it is the # only honest test of it: under the default matcher this run would hang at the # prompt, and the password arriving proves the override took. sp 25 sshpass -P 'Secret token:' -p "$PW" sh "$D/askpw.sh" 'Secret token: ' "$D/got-P" 1 0 got sshpass/deliver-P "$D/got-P" reap sshpass/rc-P 0 # The child's controlling terminal is a Unix98 pty slave -- the allocation # sshpass exists to perform, named by the child itself. sp 25 sshpass -p "$PW" sh "$D/ctty.sh" "$D/ctty.txt" if [ -f "$D/ctty.txt" ]; then _t=$(head -1 "$D/ctty.txt") _n=${_t#ttynr=}; _n=${_n%% *} case "$_n" in ''|*[!0-9]*) _n=0 ;; esac if [ "$_n" -ne 0 ]; then bst_ok sshpass/child-ctty else bst_notok sshpass/child-ctty "the child has no controlling terminal: '$(_bst_1line "$_t")'"; fi # ...and it is a Unix98 slave, major 136, which is what posix_openpt(3) + # /dev/ptmx hands out. A legacy /dev/ttyp* pair (major 3) would still be a # terminal and would still pass the case above, so the two are separate. if [ $((_n / 256)) -eq 136 ]; then bst_ok sshpass/child-ctty-unix98 else bst_notok sshpass/child-ctty-unix98 "want device major 136 (/dev/pts), got major $((_n / 256)) from '$(_bst_1line "$_t")'"; fi else bst_notok sshpass/child-ctty "the child wrote no artifact -- it never opened /dev/tty" bst_notok sshpass/child-ctty-unix98 "the child wrote no artifact -- it never opened /dev/tty" fi # --- the status contract ------------------------------------------------------ # THE HEADLINE CASE OF THE TICKET. A prompt seen a SECOND time is how sshpass # knows the password was wrong, and 5 rather than a hang at the prompt is the # whole reason the tool exists. The artifact carries the other half: the first # prompt was answered with the password and the second was not answered at all. sp 25 sshpass -p "$PW" sh "$D/askpw.sh" 'Password: ' "$D/got-wrong" 2 0 reap sshpass/rc-wrong-password 5 if [ -f "$D/got-wrong" ]; then check_eq sshpass/wrong-password-first-answered "$PW" "$(head -1 "$D/got-wrong")" # The second read is asserted EMPTY rather than absent: sshpass answers the # first prompt and then closes the pty on the second, so the child's read # fails and it records an empty line. Either shape is correct -- what must not # happen is the password being typed a second time. check_eq sshpass/wrong-password-second-unanswered "" "$(sed -n 2p "$D/got-wrong")" else bst_notok sshpass/wrong-password-first-answered "the child wrote no artifact" bst_notok sshpass/wrong-password-second-unanswered "the child wrote no artifact" fi # A child that never prompts: its status is sshpass's status, which is the # contract every caller that wraps a non-interactive run depends on. sp 25 sshpass -p "$PW" sh "$D/quiet.sh" reap sshpass/rc-passthrough 42 # The two host-key answers are matched on the tty and are NOT password prompts: # 6 for an unknown host, 7 for one whose key differs from the IP's. Driven here # from a helper so the codes are asserted against a fixed string rather than # against whatever a particular ssh release words it as; the live-server case # below is the same code reached through a real client. sp 25 sshpass -p "$PW" sh "$D/say.sh" "The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established." reap sshpass/rc-hostkey-unknown 6 sp 25 sshpass -p "$PW" sh "$D/say.sh" "Warning: the ECDSA host key for 'x' differs from the key for the IP address '127.0.0.1'" reap sshpass/rc-hostkey-changed 7 # A command that is not there: the child's perror + exit 3 has to come back as # sshpass's 3, and the diagnostic has to name what failed. sp 25 sshpass -p "$PW" /bin/no-such-command-bst reap sshpass/rc-exec-failure 3 case "$SP_OUT" in *"Failed to run command"*) bst_ok sshpass/exec-failure-diagnostic ;; *) bst_notok sshpass/exec-failure-diagnostic "want:'Failed to run command' got:'$(_bst_1line "$SP_OUT")'" ;; esac # --- against a live ssh server on loopback: the ticket's named criterion ------- ssh_cases="sshpass/live-hostkey-unknown sshpass/live-password-auth" skip_live() { for _c in $ssh_cases; do bst_notok "$_c" "$1"; done } if ! command -v dropbear >/dev/null 2>&1 || ! command -v dropbearkey >/dev/null 2>&1; then skip_live "dropbear not installed on this image, so no ssh server answers here" elif ! command -v ssh >/dev/null 2>&1; then skip_live "no ssh client on this image" else # dropbear rather than openssh's sshd, and the choice is forced: sshd cannot # serve any connection here at all (chroot(2) unwired, brintos/linux#58), so # driving sshpass at it would measure that gap instead of this port. # Under sp, not bare. Every other command this suite lets fork carries a # bound; keygen was the one exception, and an unbounded step in the section # that overran is not one to leave to trust. sp 30 dropbearkey -t ed25519 -f "$D/hostkey" KEYFAIL= [ -s "$D/hostkey" ] || KEYFAIL="dropbearkey wrote no host key (rc=$SP_RC) -- $(_bst_1line "$SP_OUT")" dropbear -F -E -p 127.0.0.1:$PORT -r "$D/hostkey" > "$D/dropbear.log" 2>&1 & DBPID=$! # Readiness is the server's own greeting, polled -- not a sleep. sleep(1) does # not sleep on this image (~0.29 s, linux-in-the-browser#120) and ssh-keyscan # cannot run at all (getrlimit ENOSYS, brintos/linux#20), so the bounded tcl # reader 88-openssh.test already uses is what reads the banner. # Six attempts, not twelve, and a server that has already died is not polled # to the end of the loop: kill -0 bails, the way 89-libssh's readiness loop # already does here. NOT wrapped in sp, deliberately -- sp's own sweep is # keyed on the run-unique temp directory, which is in the probe's argv too, # and tcl's [after] is a real bound against a loopback peer that either # accepts at once or refuses at once. banner="" if command -v tclsh >/dev/null 2>&1 && [ -f "$BST_DATA/openssh-greeting.tcl" ]; then i=0 while [ $i -lt 6 ]; do banner=$(tclsh "$BST_DATA/openssh-greeting.tcl" $PORT 2000 2>&1) case "$banner" in *"banner=SSH-"*) break ;; *) banner="" ;; esac kill -0 "$DBPID" 2>/dev/null || break i=$((i + 1)); sleep 3 done fi srvlog() { _s=$(grep -m1 -e 'fatal' -e 'not implemented' -e 'euid' -e 'Error' "$D/dropbear.log" 2>/dev/null) [ -n "$_s" ] || _s=$(tail -3 "$D/dropbear.log" 2>/dev/null) _bst_1line "$_s" } if [ -n "$KEYFAIL" ]; then skip_live "$KEYFAIL" elif [ -z "$banner" ]; then skip_live "dropbear never greeted on $PORT -- $(srvlog)" else SSHOPTS="-o ConnectTimeout=10 -o LogLevel=ERROR -o NumberOfPasswordPrompts=3" # THE ONE REAL-PEER CASE THIS IMAGE CAN ANSWER. A real ssh client, run under # sshpass's pty against a real server, is asked to accept an unknown host # key. That question arrives BEFORE authentication -- so it is reached even # though nothing here can authenticate -- and sshpass must recognise it as # not-a-password and exit 6 rather than typing the password into it. rm -f "$D/kh" sp 60 sshpass -p "$PW" ssh $SSHOPTS -o StrictHostKeyChecking=ask \ -o UserKnownHostsFile="$D/kh" -p $PORT root@127.0.0.1 true reap sshpass/live-hostkey-unknown 6 # THE CRITERION ITSELF, run rather than assumed, and red for the server's # reasons: this dropbear is built without server password auth (glibc 2.43 # has no crypt(), dropbear_%.bbappend) and its per-connection child dies at # seteuid() before authentication anyway (brintos/linux#19, measured with # dropbear's own dbclient as the control in 89-libssh.test). openssh's sshd # is no alternative (brintos/linux#58). What a green here would look like is # unambiguous -- rc 0 and BST-SSHPASS-LIVE on stdout -- so this case flips # by itself on the day the server side works. sp 60 sshpass -p "$PW" ssh $SSHOPTS -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null -o PubkeyAuthentication=no \ -o PreferredAuthentications=password \ -p $PORT root@127.0.0.1 "echo BST-SSHPASS-LIVE" case "$SP_RC:$SP_OUT" in 0:*BST-SSHPASS-LIVE*) bst_ok sshpass/live-password-auth ;; *) bst_notok sshpass/live-password-auth "brintos/linux#19 (credential setters unwired; dropbear's child dies at seteuid before auth) + this image's dropbear is built DROPBEAR_SVR_PASSWORD_AUTH=0 for the missing crypt() -- rc=$SP_RC out:'$(_bst_1line "$SP_OUT")' -- dropbear: $(srvlog)" ;; esac fi kill -9 "$DBPID" 2>/dev/null fi rm -rf "$D"