summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2023-12-17 15:36:14 +0700
committerShulhan <ms@kilabit.info>2023-12-17 18:43:01 +0700
commitb0375d78d6f1f5572e54f9427a55af0a6aaa12bc (patch)
tree624d418d07a9f62c862bfb3cb3fe4fbfe7092ae2
parentcf8caf8844b51d71e39f5b454fc7c79a9bec3227 (diff)
downloadawwan-b0375d78d6f1f5572e54f9427a55af0a6aaa12bc.tar.xz
all: change the remote temporary directory to "~/.cache/awwan"
If the file to be copied contains sensitive data, putting them in "/tmp" considered a security risk, even though it will be moved to destination later. The issue is when the "#put" command failed, the plain file is left on "/tmp" directory. This changes add additional advantage where we did not need to remove the temporary directory on remote when execution completed, since the temporary directory should be accessible by user only. Implements: https://todo.sr.ht/~shulhan/awwan/8
-rw-r--r--awwan.go13
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--session.go23
-rw-r--r--ssh_client.go26
5 files changed, 32 insertions, 36 deletions
diff --git a/awwan.go b/awwan.go
index 4923779..4827f94 100644
--- a/awwan.go
+++ b/awwan.go
@@ -47,7 +47,6 @@ const (
defEnvFileName = `awwan.env` // The default awwan environment file name.
defSSHConfig = `config` // The default SSH config file name.
defSSHDir = `.ssh` // The default SSH config directory name.
- defTmpDir = `/tmp`
)
// defEncryptExt default file extension for encrypted file.
@@ -56,6 +55,12 @@ const defEncryptExt = `.vault`
// defFileEnvVault default awwan environment file name that is encrypted.
const defFileEnvVault = `.awwan.env.vault`
+// defTmpDirLocal default temporary directory in local.
+const defTmpDirLocal = `.cache/`
+
+// defTmpDirPlay default temporary directory in remote.
+const defTmpDirPlay = `~/.cache/awwan`
+
// Awwan is the service that run script in local or remote.
// Awwan contains cache of sessions and cache of environment files.
type Awwan struct {
@@ -328,12 +333,6 @@ func (aww *Awwan) Local(req *ExecRequest) (err error) {
}
req.mlog.Outf(`=== END: %s %s %s`, req.Mode, req.Script, req.LineRange)
out:
- if ses != nil {
- var errRemove = os.RemoveAll(ses.dirTmp)
- if errRemove != nil {
- req.mlog.Errf(`!!! %s: %s`, logp, errRemove)
- }
- }
if err != nil {
req.mlog.Errf(`!!! %s`, err)
err = fmt.Errorf(`%s: %w`, logp, err)
diff --git a/go.mod b/go.mod
index 81fcbea..57be190 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ go 1.20
require (
git.sr.ht/~shulhan/ciigo v0.11.0
github.com/evanw/esbuild v0.19.8
- github.com/shuLhan/share v0.51.1-0.20231213111840-f1aced043cd3
+ github.com/shuLhan/share v0.51.1-0.20231217081321-a9a2b0538189
)
require (
diff --git a/go.sum b/go.sum
index 4176e31..4697ca6 100644
--- a/go.sum
+++ b/go.sum
@@ -4,8 +4,8 @@ git.sr.ht/~shulhan/ciigo v0.11.0 h1:t8/PqVQVOsG025WLjNjJSI4S37jN5CkY+LyC+zd1snI=
git.sr.ht/~shulhan/ciigo v0.11.0/go.mod h1:pyt2kxKvipCAO+jrjHuEXOWJ2h0ss/hnO9j7Xot3JHc=
github.com/shuLhan/esbuild v0.19.9-0.20231209212032-2dc984ffc5f1 h1:U4DRlREmugTNkevukauQjjUsz82o3YRjtbxDILoN/Xs=
github.com/shuLhan/esbuild v0.19.9-0.20231209212032-2dc984ffc5f1/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
-github.com/shuLhan/share v0.51.1-0.20231213111840-f1aced043cd3 h1:TPu3qn0J7+oqN0zch1VpXvDEe93zM1AoyfD+5jougCw=
-github.com/shuLhan/share v0.51.1-0.20231213111840-f1aced043cd3/go.mod h1:Zn0zwUdSuu7L2BKaYkVOXwbwxd5Kn6Y2bhohD9Tf0Sc=
+github.com/shuLhan/share v0.51.1-0.20231217081321-a9a2b0538189 h1:PFEcAuAJGq9wA1IMQsK5pYTra4q8640KDwp0RCKqlOw=
+github.com/shuLhan/share v0.51.1-0.20231217081321-a9a2b0538189/go.mod h1:Zn0zwUdSuu7L2BKaYkVOXwbwxd5Kn6Y2bhohD9Tf0Sc=
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
diff --git a/session.go b/session.go
index 7a845c8..c156710 100644
--- a/session.go
+++ b/session.go
@@ -16,16 +16,12 @@ import (
"strings"
"text/template"
- "github.com/shuLhan/share/lib/ascii"
"github.com/shuLhan/share/lib/ini"
libos "github.com/shuLhan/share/lib/os"
libexec "github.com/shuLhan/share/lib/os/exec"
"github.com/shuLhan/share/lib/ssh/config"
)
-// defDirTmpPrefix default prefix for temporary directory.
-const defDirTmpPrefix = `awwan.`
-
// Session manage and cache SSH client and list of scripts.
// One session have one SSH client, but may contains more than one script.
type Session struct {
@@ -51,11 +47,7 @@ type Session struct {
// NewSession create and initialize the new session based on Awwan base
// directory and the session directory.
func NewSession(aww *Awwan, sessionDir string) (ses *Session, err error) {
- var (
- logp = `NewSession`
-
- randomString string
- )
+ var logp = `NewSession`
log.Printf(`--- NewSession %q`, relativePath(aww.BaseDir, sessionDir))
@@ -65,6 +57,7 @@ func NewSession(aww *Awwan, sessionDir string) (ses *Session, err error) {
BaseDir: aww.BaseDir,
ScriptDir: sessionDir,
hostname: filepath.Base(sessionDir),
+ dirTmp: defTmpDirLocal,
}
err = ses.generatePaths()
@@ -77,9 +70,6 @@ func NewSession(aww *Awwan, sessionDir string) (ses *Session, err error) {
return nil, fmt.Errorf(`%s: %w`, logp, err)
}
- randomString = string(ascii.Random([]byte(ascii.LettersNumber), 16))
- ses.dirTmp = filepath.Join(defTmpDir, defDirTmpPrefix+randomString)
-
return ses, nil
}
@@ -306,9 +296,10 @@ func (ses *Session) SudoCopy(req *ExecRequest, stmt *Statement) (err error) {
return nil
}
-// SudoGet copy file from remote that can be accessed by root on remote, to
-// local.
-// If the owner and mode is set, it will also changes using sudo.
+// SudoGet copy file from remote, that may not readable by remote user, to
+// local using sudo.
+// If the owner and/or mode is set, it will also applied using sudo on local
+// host, after the file has been retrieved.
func (ses *Session) SudoGet(req *ExecRequest, stmt *Statement) (err error) {
var (
logp = `SudoGet`
@@ -628,7 +619,7 @@ func (ses *Session) initSSHClient(req *ExecRequest, sshSection *config.Section)
lastIdentFile = sshSection.IdentityFile[len(sshSection.IdentityFile)-1]
}
- ses.sshc, err = newSSHClient(req, sshSection, ses.dirTmp)
+ ses.sshc, err = newSSHClient(req, sshSection)
if err != nil {
return fmt.Errorf(`%s: %w`, logp, err)
}
diff --git a/ssh_client.go b/ssh_client.go
index e47b47b..7b89491 100644
--- a/ssh_client.go
+++ b/ssh_client.go
@@ -4,12 +4,13 @@
package awwan
import (
+ "bytes"
"errors"
"fmt"
"io/fs"
"path/filepath"
+ "strings"
- "github.com/shuLhan/share/lib/ascii"
"github.com/shuLhan/share/lib/ssh"
"github.com/shuLhan/share/lib/ssh/config"
"github.com/shuLhan/share/lib/ssh/sftp"
@@ -29,13 +30,16 @@ type sshClient struct {
// dirTmp temporary directory for sudoGet or sudoPut operations.
dirTmp string
+
+ // dirHome define the remote user home directory.
+ dirHome string
}
// newSSHClient create new clients using the SSH config section.
//
// Once connection established, the client create new temporary directory on
// server at dirTmp for sudoGet or sudoPut operations.
-func newSSHClient(req *ExecRequest, section *config.Section, dirTmp string) (sshc *sshClient, err error) {
+func newSSHClient(req *ExecRequest, section *config.Section) (sshc *sshClient, err error) {
var logp = `newSSHClient`
req.mlog.Outf(`--- SSH connection: %s@%s:%s`,
@@ -45,7 +49,6 @@ func newSSHClient(req *ExecRequest, section *config.Section, dirTmp string) (ssh
sshc = &sshClient{
section: section,
- dirTmp: dirTmp,
}
sshc.conn, err = ssh.NewClientInteractive(section)
@@ -60,11 +63,16 @@ func newSSHClient(req *ExecRequest, section *config.Section, dirTmp string) (ssh
req.mlog.Errf(`%s: %s`, logp, err)
}
- if len(dirTmp) == 0 {
- var randomString = string(ascii.Random([]byte(ascii.LettersNumber), 16))
- sshc.dirTmp = filepath.Join(defTmpDir, defDirTmpPrefix+randomString)
+ // Get the remote user's home directory.
+ var stdout []byte
+ stdout, _, err = sshc.conn.Output(`pwd`)
+ if err != nil {
+ return nil, err
}
+ sshc.dirHome = string(bytes.TrimSpace(stdout))
+ sshc.dirTmp = strings.Replace(defTmpDirPlay, `~`, sshc.dirHome, 1)
+
err = sshc.mkdir(sshc.dirTmp, 0700)
if err != nil {
return nil, err
@@ -99,8 +107,6 @@ func (sshc *sshClient) chown(remoteFile, owner string) (err error) {
// close the connections and release all resources.
func (sshc *sshClient) close() (err error) {
- err = sshc.rmdirAll(sshc.dirTmp)
-
var errClose error
if sshc.sftpc != nil {
@@ -134,14 +140,14 @@ func (sshc *sshClient) get(remote, local string) (err error) {
// mkdir create directory on the remote server.
func (sshc *sshClient) mkdir(dir string, permission uint32) (err error) {
if sshc.sftpc == nil {
- var mkdirStmt = fmt.Sprintf(`mkdir %s`, dir)
+ var mkdirStmt = fmt.Sprintf(`mkdir -p %s`, dir)
err = sshc.conn.Execute(mkdirStmt)
} else {
var fa = sftp.FileAttrs{}
fa.SetPermissions(permission)
- err = sshc.sftpc.Mkdir(dir, &fa)
+ err = sshc.sftpc.MkdirAll(dir, &fa)
}
return err
}