update where shell starts and add override -home setting
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 41 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB |
@@ -33,6 +33,7 @@ Change with `-setlogin` before first use.
|
|||||||
| `-log off` | — | Disable file logging (console output always on) |
|
| `-log off` | — | Disable file logging (console output always on) |
|
||||||
| `-mfa <user> on` | — | Enable TOTP MFA for user — prints secret + QR code |
|
| `-mfa <user> on` | — | Enable TOTP MFA for user — prints secret + QR code |
|
||||||
| `-mfa <user> off` | — | Disable TOTP MFA for user |
|
| `-mfa <user> off` | — | Disable TOTP MFA for user |
|
||||||
|
| `-home <path>` | `~` | Starting directory for new shell sessions |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -101,26 +102,8 @@ Structured JSON-lines, one entry per login attempt:
|
|||||||
|
|
||||||
## Run as service
|
## Run as service
|
||||||
- `gotermix.service` is pretty limitted, you can change settings there to suit your needs
|
- `gotermix.service` is pretty limitted, you can change settings there to suit your needs
|
||||||
```bash
|
- there are 2 samples, `gotermix-limitted.service` has many settings what limits what this app and sessions in can do ( you may not even change user)
|
||||||
# 1. Create unprivileged system user (no shell, no home)
|
- `gotermix.service` is pretty much normal full shell without restriction, run as specific user.
|
||||||
useradd --system --no-create-home --shell /sbin/nologin gotermix
|
|
||||||
|
|
||||||
# 2. Deploy binary and set ownership
|
|
||||||
mkdir -p /opt/gotermix
|
|
||||||
cp gotermix /opt/gotermix/
|
|
||||||
chown -R gotermix:gotermix /opt/gotermix
|
|
||||||
chmod 750 /opt/gotermix
|
|
||||||
chmod 750 /opt/gotermix/gotermix
|
|
||||||
|
|
||||||
# 3. Install and enable service
|
|
||||||
cp gotermix.service /etc/systemd/system/
|
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl enable --now gotermix
|
|
||||||
|
|
||||||
# 4. Check it's up
|
|
||||||
systemctl status gotermix
|
|
||||||
journalctl -u gotermix -f
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ type Session struct {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
initialCwd string
|
initialCwd string
|
||||||
|
shellHome string // starting directory for new shell sessions
|
||||||
nopwMode bool
|
nopwMode bool
|
||||||
appCreds storedCreds
|
appCreds storedCreds
|
||||||
authSecret []byte
|
authSecret []byte
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ func handleUpload(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
destDir := strings.TrimSpace(r.FormValue("dest"))
|
destDir := strings.TrimSpace(r.FormValue("dest"))
|
||||||
if destDir == "" {
|
if destDir == "" {
|
||||||
destDir = initialCwd
|
destDir = shellHome
|
||||||
}
|
}
|
||||||
destPath := filepath.Join(filepath.Clean(destDir), filepath.Base(header.Filename))
|
destPath := filepath.Join(filepath.Clean(destDir), filepath.Base(header.Filename))
|
||||||
|
|
||||||
@@ -400,7 +400,7 @@ func handleDownload(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
full := filepath.Clean(path)
|
full := filepath.Clean(path)
|
||||||
if !filepath.IsAbs(full) {
|
if !filepath.IsAbs(full) {
|
||||||
full = filepath.Join(initialCwd, full)
|
full = filepath.Join(shellHome, full)
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(full); err != nil {
|
if _, err := os.Stat(full); err != nil {
|
||||||
http.Error(w, "file not found", http.StatusNotFound)
|
http.Error(w, "file not found", http.StatusNotFound)
|
||||||
|
|||||||
@@ -15,6 +15,24 @@ import (
|
|||||||
qrcode "github.com/skip2/go-qrcode"
|
qrcode "github.com/skip2/go-qrcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// expandHome resolves a leading ~ to the current user's home directory.
|
||||||
|
func expandHome(p string) (string, error) {
|
||||||
|
if p == "" {
|
||||||
|
return os.UserHomeDir()
|
||||||
|
}
|
||||||
|
if p == "~" {
|
||||||
|
return os.UserHomeDir()
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(p, "~/") {
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return filepath.Join(home, p[2:]), nil
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Run is the application entry point, called from main().
|
// Run is the application entry point, called from main().
|
||||||
func Run() {
|
func Run() {
|
||||||
addr := flag.String("addr", "127.0.0.1:5000", "listen address")
|
addr := flag.String("addr", "127.0.0.1:5000", "listen address")
|
||||||
@@ -25,10 +43,24 @@ func Run() {
|
|||||||
certreset := flag.Bool("certreset", false, "remove stored custom certificate, revert to self-signed")
|
certreset := flag.Bool("certreset", false, "remove stored custom certificate, revert to self-signed")
|
||||||
logFlag := flag.String("log", "", "auth log file path; 'off' disables file logging (default: gotermix.log next to binary)")
|
logFlag := flag.String("log", "", "auth log file path; 'off' disables file logging (default: gotermix.log next to binary)")
|
||||||
mfaFlag := flag.String("mfa", "", "manage MFA for a user: -mfa <username> on|off")
|
mfaFlag := flag.String("mfa", "", "manage MFA for a user: -mfa <username> on|off")
|
||||||
|
homeFlag := flag.String("home", "", "starting directory for new shell sessions (default: user home ~)")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
initialCwd, _ = os.Getwd()
|
initialCwd, _ = os.Getwd()
|
||||||
|
|
||||||
|
// Resolve shell starting directory.
|
||||||
|
home, err := expandHome(*homeFlag)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error resolving home directory: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
info, err := os.Stat(home)
|
||||||
|
if err != nil || !info.IsDir() {
|
||||||
|
fmt.Fprintf(os.Stderr, "error: -home %q is not a valid directory\n", home)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
shellHome = home
|
||||||
|
|
||||||
// Credentials file lives next to the executable.
|
// Credentials file lives next to the executable.
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func getOrCreate(id string) *Session {
|
|||||||
} else {
|
} else {
|
||||||
cmd = exec.Command("/bin/bash", "-i")
|
cmd = exec.Command("/bin/bash", "-i")
|
||||||
}
|
}
|
||||||
cmd.Dir = initialCwd
|
cmd.Dir = shellHome
|
||||||
|
|
||||||
// Build environment: inherit parent env but force TERM so that bash readline
|
// Build environment: inherit parent env but force TERM so that bash readline
|
||||||
// correctly decodes modifier+cursor sequences (Shift+Arrow etc.).
|
// correctly decodes modifier+cursor sequences (Shift+Arrow etc.).
|
||||||
|
|||||||
Reference in New Issue
Block a user