Sample code for 30+ languages & platforms
Visual FoxPro

SSH Commands that Prompt for Input, such as su

See more SSH Examples

Demonstrates running a shell command that prompts for additional input, using su as the example. The technique is: send the command, read until the expected prompt appears, then send the response exactly as though it were typed.

Note: This example deliberately requests a PTY. su reads its password from a controlling terminal and refuses to run without one, so a pseudo-terminal is genuinely required here.

Background: Programs that ask for a password almost always insist on reading it from a real terminal rather than a pipe — a deliberate safeguard against passwords being fed in by scripts. That is why this is one of the cases where a PTY is necessary despite the general advice to avoid one. The interaction is a strict send-then-read-to-prompt cycle, and retrieving the received text between steps is essential: a prompt left in the buffer would make the next receive return immediately with the wrong output. Where possible, a passwordless sudo rule avoids this dance altogether.

Chilkat Visual FoxPro Downloads

Visual FoxPro
LOCAL lnSuccess
LOCAL loSsh
LOCAL lcHostname
LOCAL lnPort
LOCAL lcPassword
LOCAL lnChannelNum
LOCAL lcTermType
LOCAL lnWidthInChars
LOCAL lnHeightInChars
LOCAL lnPixWidth
LOCAL lnPixHeight
LOCAL lnCaseSensitive
LOCAL lcCmdOutput
LOCAL lcSuPassword
LOCAL lcMyShellPrompt

lnSuccess = 0

*  This example requires the Chilkat API to have been previously unlocked.
*  See Global Unlock Sample for sample code.

*  Demonstrates running a shell command that prompts for additional input, using "su" as the
*  example.  The technique is: send the command, read until the expected prompt, then send the
*  response as though it were typed.
*  
*  Note: This example deliberately DOES request a PTY.  "su" reads its password from a
*  controlling terminal and refuses to run without one, so a pseudo-terminal is required here.

loSsh = CreateObject('Chilkat.Ssh')

lcHostname = "ssh.example.com"
lnPort = 22
lnSuccess = loSsh.Connect(lcHostname,lnPort)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

*  Normally you would not hard-code the password in source.  You should instead obtain it
*  from an interactive prompt, environment variable, or a secrets vault.
lcPassword = "mySshPassword"

lnSuccess = loSsh.AuthenticatePw("mySshLogin",lcPassword)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

lnChannelNum = loSsh.OpenSessionChannel()
IF (lnChannelNum < 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

*  Request a pseudo-terminal.  A "dumb" terminal avoids ANSI escape sequences in the output.
lcTermType = "dumb"
lnWidthInChars = 120
lnHeightInChars = 40
lnPixWidth = 0
lnPixHeight = 0
lnSuccess = loSsh.SendReqPty(lnChannelNum,lcTermType,lnWidthInChars,lnHeightInChars,lnPixWidth,lnPixHeight)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

lnSuccess = loSsh.SendReqShell(lnChannelNum)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

*  IMPORTANT: Set a read timeout before receiving until a match.  ReadTimeoutMs defaults to 0,
*  which means no limit -- without it, this call waits forever if the received data never
*  contains a match.
loSsh.ReadTimeoutMs = 15000

lnCaseSensitive = 1

*  Send the su command.  Linux/UNIX servers generally expect a bare LF, not a CRLF.
lnSuccess = loSsh.ChannelSendString(lnChannelNum,"su" + CHR(10),"utf-8")
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

*  Read until su prompts for the password.
lnSuccess = loSsh.ChannelReceiveUntilMatch(lnChannelNum,"Password:","utf-8",lnCaseSensitive)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

lcCmdOutput = loSsh.GetReceivedText(lnChannelNum,"utf-8")
IF (loSsh.LastMethodSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

? lcCmdOutput

*  Send the root password, exactly as if it were typed at the prompt.  Like the login password,
*  this should come from a secure source rather than being hard-coded.
lcSuPassword = "myRootPassword"
lnSuccess = loSsh.ChannelSendString(lnChannelNum,lcSuPassword,"utf-8")
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

lnSuccess = loSsh.ChannelSendString(lnChannelNum,CHR(10),"utf-8")
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

*  Read the response up to the root shell prompt.  This will differ on your system.
lcMyShellPrompt = "root@myserver:~#"
lnSuccess = loSsh.ChannelReceiveUntilMatch(lnChannelNum,lcMyShellPrompt,"utf-8",lnCaseSensitive)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

*  Retrieving the text also clears the receive buffer, which matters: if the prompt were left
*  buffered, the next receive would match it immediately.
lcCmdOutput = loSsh.GetReceivedText(lnChannelNum,"utf-8")
IF (loSsh.LastMethodSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

? lcCmdOutput

*  Now run a command as root.
lnSuccess = loSsh.ChannelSendString(lnChannelNum,"ls" + CHR(10),"utf-8")
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

lnSuccess = loSsh.ChannelReceiveUntilMatch(lnChannelNum,lcMyShellPrompt,"utf-8",lnCaseSensitive)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

lcCmdOutput = loSsh.GetReceivedText(lnChannelNum,"utf-8")
IF (loSsh.LastMethodSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

? lcCmdOutput

*  Additional commands follow the same pattern: send the command, read to the next prompt, then
*  fetch and clear the receive buffer.

lnSuccess = loSsh.ChannelSendEof(lnChannelNum)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

lnSuccess = loSsh.ChannelSendClose(lnChannelNum)
IF (lnSuccess = 0) THEN
    ? loSsh.LastErrorText
    RELEASE loSsh
    CANCEL
ENDIF

loSsh.Disconnect()

RELEASE loSsh