I have some Juniper SSG firewalls which I need to manage, and I'd like to be able to send commands to them from some monitoring scripts. I configured SSH access using public keys, and I'm able to automatically login to the firewalls.
When I run SSH interactively, everything works fine:
$ssh <firewall IP>
FIREWALL-> <command>
<command output>
FIREWALL-> exit
Connection to <firewall IP> closed.
$
But when I try to run the command from the command line, it doesn't work:
$ssh <firewall IP> <command>
$
This, of course, works fine when sending a command to a remote Linux box:
$ssh <linux box IP> <command>
<command output>
$
Why is this happening? What is the difference between running SSH interactively and specifying the command to run on the SSH command line?
Update:
It also works fine with a Cisco router. Only these Juniper firewalls seem to behave this way.
From the debug output from SSH, it looks like the connection gets established correctly, but the Juniper box replies with an EOF when sending the command, while instead the Linux box replies with the actual command output:
Linux:
debug1: Authentication succeeded (publickey).
debug1: channel 0: new [client-session]
debug2: channel 0: send open
debug1: Entering interactive session.
debug2: callback start
debug2: client_session2_setup: id 0
debug1: Sending command: uptime
debug2: channel 0: request exec confirm 0
debug2: callback done
debug2: channel 0: open confirm rwindow 0 rmax 32768
debug2: channel 0: rcvd adjust 131072
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
16:44:44 up 25 days, 1:06, 3 users, load average: 0.08, 0.02, 0.01
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
debug2: channel 0: obuf empty
debug2: channel 0: close_write
debug2: channel 0: output drain -> closed
debug2: channel 0: rcvd close
debug2: channel 0: close_read
debug2: channel 0: input open -> closed
debug2: channel 0: almost dead
debug2: channel 0: gc: notify user
debug2: channel 0: gc: user detached
debug2: channel 0: send close
debug2: channel 0: is dead
debug2: channel 0: garbage collecting
debug1: channel 0: free: client-session, nchannels 1
debug1: Transferred: stdin 0, stdout 0, stderr 0 bytes in 0.1 seconds
debug1: Bytes per second: stdin 0.0, stdout 0.0, stderr 0.0
debug1: Exit status 0
Juniper:
debug1: Authentication succeeded (publickey).
debug1: channel 0: new [client-session]
debug2: channel 0: send open
debug1: Entering interactive session.
debug2: callback start
debug2: client_session2_setup: id 0
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8
debug2: channel 0: request env confirm 0
debug1: Sending command: get system
debug2: channel 0: request exec confirm 0
debug2: callback done
debug2: channel 0: open confirm rwindow 2048 rmax 1024
debug2: channel 0: rcvd eof
debug2: channel 0: output open -> drain
debug2: channel 0: obuf empty
debug2: channel 0: close_write
debug2: channel 0: output drain -> closed
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug2: channel 0: rcvd close
debug2: channel 0: close_read
debug2: channel 0: input open -> closed
debug2: channel 0: almost dead
debug2: channel 0: gc: notify user
debug2: channel 0: gc: user detached
debug2: channel 0: send close
debug2: channel 0: is dead
debug2: channel 0: garbage collecting
debug1: channel 0: free: client-session, nchannels 1
debug1: Transferred: stdin 0, stdout 0, stderr 0 bytes in 0.2 seconds
debug1: Bytes per second: stdin 0.0, stdout 0.0, stderr 0.0
debug1: Exit status 1
SSH doesn't allocate a pseudo-TTY when you specify a command to run. Try adding "-t" option to override this.
Passing the command on the command line is not the same thing as typing commands in the shell. In the first case the shell needs to parse the arguments, and in the latter it needs to read lines from the standard input.
If it is a dumb (or limited, if you prefer to call it) interactive shell it may very well not have been coded to support both (I have seen this behavior in practice). However, since the shell obviously supports typed commands, you would probably have better luck if you just send all commands to its standard input. Like this:
Like somebody commented, try adding -t, or even -tt to force it. A similar issue was supposedly fixed with this workaround.
I'm having a related issue to this one in fact, except for me it's working from the CLI, but not working through cron.
this works on an SRX240:
This can be further improved by making it use a bash heredoc so you could just paste complete statements in to it, but this example should sufficiently guide you for now.