Files
plainleaf/server/shell_backend.go
T

100 lines
2.3 KiB
Go

package server
import (
"bytes"
"log"
"os/exec"
"slices"
"strings"
)
// LocalShell implements shell execution on the local system
type LocalShell struct {
Cwd string
CmdWhiteList []string
AllowAllCmds bool
}
// NewLocalShell creates a new LocalShell instance
func NewLocalShell(cwd string, cmdWhiteList string) *LocalShell {
whiteListedCommands := strings.Split(cmdWhiteList, " ")
if cmdWhiteList == "" {
whiteListedCommands = []string{}
}
return &LocalShell{
Cwd: cwd,
CmdWhiteList: whiteListedCommands,
AllowAllCmds: len(whiteListedCommands) == 0,
}
}
// Handle executes a shell command and returns the result
func (ls *LocalShell) Handle(request ShellRequest) (ShellResponse, error) {
// Check if command is whitelisted
if !ls.AllowAllCmds && !slices.Contains(ls.CmdWhiteList, request.Cmd) {
log.Printf("Not running shell command because not in whitelist: %s\n", request.Cmd)
return ShellResponse{
Code: -1,
Stdout: "",
Stderr: "Not allowed, command not in whitelist",
}, nil
}
log.Printf("Running shell command: %s %s\n", request.Cmd, strings.Join(request.Args, " "))
// Create the command
cmd := exec.Command(request.Cmd, request.Args...)
cmd.Dir = ls.Cwd
// Set up stdin if provided
if request.Stdin != nil {
cmd.Stdin = strings.NewReader(*request.Stdin)
}
// Set up separate buffers for stdout and stderr
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
// Execute the command
err := cmd.Run()
var exitCode int
if err != nil {
// Try to get the exit code
if exitError, ok := err.(*exec.ExitError); ok {
exitCode = exitError.ExitCode()
} else {
// Command failed to start
return ShellResponse{
Code: -1,
Stdout: "",
Stderr: err.Error(),
}, nil
}
}
return ShellResponse{
Code: exitCode,
Stdout: stdout.String(),
Stderr: stderr.String(),
}, nil
}
// NotSupportedShell implements a shell backend that doesn't support execution
type NotSupportedShell struct{}
// NewNotSupportedShell creates a new NotSupportedShell instance
func NewNotSupportedShell() *NotSupportedShell {
return &NotSupportedShell{}
}
// Handle always returns a "not supported" error
func (nss *NotSupportedShell) Handle(request ShellRequest) (ShellResponse, error) {
return ShellResponse{
Code: 1,
Stdout: "",
Stderr: "Not supported",
}, nil
}