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
|
|
}
|