fix: propagate errors and harden mount path handling
Addresses audit findings from 2026-04-19: - Q-H1: replace Println with Printf for %s-formatted error (line 42) - Q-H2/Q-M2/Q-M3: verify_mount_dir and mount_sshfs now return error; main exits on failure instead of continuing with invalid state - Q-M1: default Port to "22" when ssh_config has no entry - S-M1: create mount dir with 0700 instead of 0777 - S-M2: filepath.Clean + base-prefix check rejects HostName values that would escape ~/Servers/ - Q-L1: correct "~/.ssh_config" typo to "~/.ssh/config" Also: use os.Exit(2) for usage error (was 80), route user-facing errors to stderr.
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"github.com/moby/sys/mountinfo"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/kevinburke/ssh_config"
|
"github.com/kevinburke/ssh_config"
|
||||||
"flag"
|
"github.com/moby/sys/mountinfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
var eFlag = flag.Bool("e", false, "open mountpoint in your editor")
|
var eFlag = flag.Bool("e", false, "open mountpoint in your editor")
|
||||||
@@ -16,19 +19,28 @@ func main() {
|
|||||||
args := flag.Args()
|
args := flag.Args()
|
||||||
|
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
fmt.Println("No hostname specified.")
|
fmt.Fprintln(os.Stderr, "No hostname specified.")
|
||||||
os.Exit(80)
|
os.Exit(2)
|
||||||
} else {
|
}
|
||||||
|
|
||||||
hostname := ssh_config.Get(args[0], "HostName")
|
hostname := ssh_config.Get(args[0], "HostName")
|
||||||
user := ssh_config.Get(args[0], "User")
|
user := ssh_config.Get(args[0], "User")
|
||||||
port := ssh_config.Get(args[0], "Port")
|
port := ssh_config.Get(args[0], "Port")
|
||||||
ifile := ssh_config.Get(args[0], "IdentityFile")
|
ifile := ssh_config.Get(args[0], "IdentityFile")
|
||||||
|
|
||||||
if len(hostname) == 0 || len(user) == 0 || len(ifile) == 0 {
|
if len(hostname) == 0 || len(user) == 0 || len(ifile) == 0 {
|
||||||
fmt.Println("Hostname not found in ~/.ssh_config")
|
fmt.Fprintln(os.Stderr, "Hostname not found in ~/.ssh/config")
|
||||||
os.Exit(3)
|
os.Exit(3)
|
||||||
} else {
|
}
|
||||||
mount := verify_mount_dir(hostname)
|
if len(port) == 0 {
|
||||||
|
port = "22"
|
||||||
|
}
|
||||||
|
|
||||||
|
mount, err := verify_mount_dir(hostname)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "verify_mount_dir() failed:", err)
|
||||||
|
os.Exit(4)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("Hostname: ", hostname)
|
fmt.Println("Hostname: ", hostname)
|
||||||
fmt.Println("User: ", user)
|
fmt.Println("User: ", user)
|
||||||
@@ -39,42 +51,49 @@ func main() {
|
|||||||
|
|
||||||
chkmount, chkmount_err := mountinfo.Mounted(mount)
|
chkmount, chkmount_err := mountinfo.Mounted(mount)
|
||||||
if chkmount_err != nil {
|
if chkmount_err != nil {
|
||||||
fmt.Println("mountinfo.Mounted() failed with %s\n", chkmount_err)
|
fmt.Fprintf(os.Stderr, "mountinfo.Mounted() failed with %s\n", chkmount_err)
|
||||||
|
os.Exit(5)
|
||||||
|
}
|
||||||
|
if !chkmount {
|
||||||
|
if err := mount_sshfs(hostname, user, ifile, port, mount); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "mount_sshfs() failed:", err)
|
||||||
|
os.Exit(6)
|
||||||
}
|
}
|
||||||
if chkmount == false {
|
|
||||||
mount_sshfs(hostname, user, ifile, port, mount)
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("!!! Already mounted")
|
fmt.Println("!!! Already mounted")
|
||||||
}
|
}
|
||||||
run_editor(mount)
|
run_editor(mount)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func run_editor(mount string) {
|
func run_editor(mount string) {
|
||||||
if(*eFlag == true) {
|
if *eFlag {
|
||||||
cmd := exec.Command("subl", mount)
|
cmd := exec.Command("subl", mount)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("run_editor() failed with\n",err)
|
fmt.Fprintln(os.Stderr, "run_editor() failed with", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func verify_mount_dir(hostname string)(mount string) {
|
func verify_mount_dir(hostname string) (string, error) {
|
||||||
homedir, homedirerr := os.UserHomeDir()
|
homedir, err := os.UserHomeDir()
|
||||||
if homedirerr != nil {
|
if err != nil {
|
||||||
fmt.Println( homedirerr )
|
return "", fmt.Errorf("resolve home dir: %w", err)
|
||||||
}
|
}
|
||||||
mount = homedir+"/Servers/"+hostname
|
base := filepath.Join(homedir, "Servers")
|
||||||
os.MkdirAll(mount, os.ModePerm)
|
mount := filepath.Clean(filepath.Join(base, hostname))
|
||||||
|
if !strings.HasPrefix(mount, base+string(os.PathSeparator)) {
|
||||||
return
|
return "", fmt.Errorf("hostname %q escapes mount base %q", hostname, base)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(mount, 0700); err != nil {
|
||||||
|
return "", fmt.Errorf("create mount dir %q: %w", mount, err)
|
||||||
|
}
|
||||||
|
return mount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mount_sshfs(hostname string, user string, ifile string, port string, mount string) {
|
func mount_sshfs(hostname string, user string, ifile string, port string, mount string) error {
|
||||||
cmd := exec.Command("sshfs", "-p", port,
|
cmd := exec.Command("sshfs", "-p", port,
|
||||||
"-o", "IdentityFile="+ifile,
|
"-o", "IdentityFile="+ifile,
|
||||||
"-o", "idmap=user",
|
"-o", "idmap=user",
|
||||||
@@ -91,8 +110,5 @@ func mount_sshfs(hostname string, user string, ifile string, port string, mount
|
|||||||
user+"@"+hostname+":/", mount)
|
user+"@"+hostname+":/", mount)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
err := cmd.Run()
|
return cmd.Run()
|
||||||
if err != nil {
|
|
||||||
fmt.Println("mount_sshfs() failed with\n",err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user