71 lines
1.8 KiB
Go
71 lines
1.8 KiB
Go
|
package ssh
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"io"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// This is the phrase that tells us sudo is looking for a password via stdin
|
||
|
const sudoPwPrompt = "sudo_password"
|
||
|
|
||
|
// sudoWriter is used to both combine stdout and stderr as well as
|
||
|
// look for a password request from sudo.
|
||
|
type sudoWriter struct {
|
||
|
b bytes.Buffer
|
||
|
pw string // The password to pass to sudo (if requested)
|
||
|
stdin io.Writer // The writer from the ssh session
|
||
|
m sync.Mutex
|
||
|
}
|
||
|
|
||
|
func (w *sudoWriter) Write(p []byte) (int, error) {
|
||
|
// If we get the sudo password prompt phrase send the password via stdin
|
||
|
// and don't write it to the buffer.
|
||
|
if string(p) == sudoPwPrompt {
|
||
|
w.stdin.Write([]byte(w.pw + "\n"))
|
||
|
w.pw = "" // We don't need the password anymore so reset the string
|
||
|
return len(p), nil
|
||
|
}
|
||
|
|
||
|
w.m.Lock()
|
||
|
defer w.m.Unlock()
|
||
|
|
||
|
return w.b.Write(p)
|
||
|
}
|
||
|
|
||
|
// ExecSu Execute cmd via sudo. Do not include the sudo command in
|
||
|
// the cmd string. For example: Client.ExecSudo("uptime", "password").
|
||
|
// If you are using passwordless sudo you can use the regular Exec()
|
||
|
// function.
|
||
|
func (c *Client) ExecSu(cmd, passwd string) ([]byte, error) {
|
||
|
session, err := c.SSHClient.NewSession()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer session.Close()
|
||
|
|
||
|
// -n run non interactively
|
||
|
// -p specify the prompt. We do this to know that sudo is asking for a passwd
|
||
|
// -S Writes the prompt to StdErr and reads the password from StdIn
|
||
|
cmd = "sudo -p " + sudoPwPrompt + " -S " + cmd
|
||
|
|
||
|
// Use the sudoRW struct to handle the interaction with sudo and capture the
|
||
|
// output of the command
|
||
|
w := &sudoWriter{
|
||
|
pw: passwd,
|
||
|
}
|
||
|
w.stdin, err = session.StdinPipe()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// Combine stdout, stderr to the same writer which also looks for the sudo
|
||
|
// password prompt
|
||
|
session.Stdout = w
|
||
|
session.Stderr = w
|
||
|
|
||
|
err = session.Run(cmd)
|
||
|
|
||
|
return w.b.Bytes(), err
|
||
|
}
|