From b3729e4666eb40cdfbc8de8441f4628118805916 Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Tue, 19 Nov 2019 11:38:39 +0100 Subject: [PATCH] log ssh commands in "command logs" category --- README.md | 5 +++-- logger/logger.go | 5 +++-- sftpd/handler.go | 16 ++++++++-------- sftpd/sftpd.go | 43 ++++++++++++++++++++++--------------------- sftpd/ssh_cmd.go | 7 +++++-- 5 files changed, 41 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 65401413..fa8d00f9 100644 --- a/README.md +++ b/README.md @@ -462,7 +462,7 @@ The logs can be divided into the following categories: - `connection_id` string. Unique connection identifier - `protocol` string. `SFTP` or `SCP` - **"command logs"**, SFTP/SCP command logs: - - `sender` string. `Rename`, `Rmdir`, `Mkdir`, `Symlink`, `Remove`, `Chmod`, `Chown`, `Chtimes` + - `sender` string. `Rename`, `Rmdir`, `Mkdir`, `Symlink`, `Remove`, `Chmod`, `Chown`, `Chtimes`, `SSHCommand` - `level` string - `username`, string - `file_path` string @@ -472,8 +472,9 @@ The logs can be divided into the following categories: - `gid` integer. Valid for sender `Chown` otherwise -1 - `access_time` datetime as YYYY-MM-DDTHH:MM:SS. Valid for sender `Chtimes` otherwise empty - `modification_time` datetime as YYYY-MM-DDTHH:MM:SS. Valid for sender `Chtimes` otherwise empty + - `ssh_command`, string. Valid for sender `SSHCommand` otherwise empty - `connection_id` string. Unique connection identifier - - `protocol` string. `SFTP` or `SCP` + - `protocol` string. `SFTP`, `SCP` or `SSH` - **"http logs"**, REST API logs: - `sender` string. `httpd` - `level` string diff --git a/logger/logger.go b/logger/logger.go index add5858d..afc2b0af 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -149,8 +149,8 @@ func TransferLog(operation string, path string, elapsed int64, size int64, user Msg("") } -// CommandLog logs an SFTP/SCP command -func CommandLog(command, path, target, user, fileMode, connectionID, protocol string, uid, gid int, atime, mtime string) { +// CommandLog logs an SFTP/SCP/SSH command +func CommandLog(command, path, target, user, fileMode, connectionID, protocol string, uid, gid int, atime, mtime, sshCommand string) { logger.Info(). Timestamp(). Str("sender", command). @@ -162,6 +162,7 @@ func CommandLog(command, path, target, user, fileMode, connectionID, protocol st Int("gid", gid). Str("access_time", atime). Str("modification_time", atime). + Str("ssh_command", sshCommand). Str("connection_id", connectionID). Str("protocol", protocol). Msg("") diff --git a/sftpd/handler.go b/sftpd/handler.go index 884d14a8..36d82f3a 100644 --- a/sftpd/handler.go +++ b/sftpd/handler.go @@ -271,7 +271,7 @@ func (c Connection) handleSFTPSetstat(path string, request *sftp.Request) error c.Log(logger.LevelWarn, logSender, "failed to chmod path %#v, mode: %v, err: %v", path, fileMode.String(), err) return getSFTPErrorFromOSError(err) } - logger.CommandLog(chmodLogSender, path, "", c.User.Username, fileMode.String(), c.ID, c.protocol, -1, -1, "", "") + logger.CommandLog(chmodLogSender, path, "", c.User.Username, fileMode.String(), c.ID, c.protocol, -1, -1, "", "", "") return nil } else if attrFlags.UidGid { if !c.User.HasPerm(dataprovider.PermChown) { @@ -283,7 +283,7 @@ func (c Connection) handleSFTPSetstat(path string, request *sftp.Request) error c.Log(logger.LevelWarn, logSender, "failed to chown path %#v, uid: %v, gid: %v, err: %v", path, uid, gid, err) return getSFTPErrorFromOSError(err) } - logger.CommandLog(chownLogSender, path, "", c.User.Username, "", c.ID, c.protocol, uid, gid, "", "") + logger.CommandLog(chownLogSender, path, "", c.User.Username, "", c.ID, c.protocol, uid, gid, "", "", "") return nil } else if attrFlags.Acmodtime { if !c.User.HasPerm(dataprovider.PermChtimes) { @@ -300,7 +300,7 @@ func (c Connection) handleSFTPSetstat(path string, request *sftp.Request) error return getSFTPErrorFromOSError(err) } logger.CommandLog(chtimesLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, accessTimeString, - modificationTimeString) + modificationTimeString, "") return nil } return nil @@ -314,7 +314,7 @@ func (c Connection) handleSFTPRename(sourcePath string, targetPath string) error c.Log(logger.LevelWarn, logSender, "failed to rename file, source: %#v target: %#v: %v", sourcePath, targetPath, err) return getSFTPErrorFromOSError(err) } - logger.CommandLog(renameLogSender, sourcePath, targetPath, c.User.Username, "", c.ID, c.protocol, -1, -1, "", "") + logger.CommandLog(renameLogSender, sourcePath, targetPath, c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") go executeAction(operationRename, c.User.Username, sourcePath, targetPath) return nil } @@ -340,7 +340,7 @@ func (c Connection) handleSFTPRmdir(path string) error { return getSFTPErrorFromOSError(err) } - logger.CommandLog(rmdirLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "") + logger.CommandLog(rmdirLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") return sftp.ErrSSHFxOk } @@ -353,7 +353,7 @@ func (c Connection) handleSFTPSymlink(sourcePath string, targetPath string) erro return getSFTPErrorFromOSError(err) } - logger.CommandLog(symlinkLogSender, sourcePath, targetPath, c.User.Username, "", c.ID, c.protocol, -1, -1, "", "") + logger.CommandLog(symlinkLogSender, sourcePath, targetPath, c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") return nil } @@ -367,7 +367,7 @@ func (c Connection) handleSFTPMkdir(path string) error { } utils.SetPathPermissions(path, c.User.GetUID(), c.User.GetGID()) - logger.CommandLog(mkdirLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "") + logger.CommandLog(mkdirLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") return nil } @@ -393,7 +393,7 @@ func (c Connection) handleSFTPRemove(path string) error { return getSFTPErrorFromOSError(err) } - logger.CommandLog(removeLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "") + logger.CommandLog(removeLogSender, path, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "") if fi.Mode()&os.ModeSymlink != os.ModeSymlink { dataprovider.UpdateUserQuota(dataProvider, c.User, -1, -size, false) } diff --git a/sftpd/sftpd.go b/sftpd/sftpd.go index a1e599be..1a371677 100644 --- a/sftpd/sftpd.go +++ b/sftpd/sftpd.go @@ -20,27 +20,28 @@ import ( ) const ( - logSender = "sftpd" - logSenderSCP = "scp" - logSenderSSH = "ssh" - uploadLogSender = "Upload" - downloadLogSender = "Download" - renameLogSender = "Rename" - rmdirLogSender = "Rmdir" - mkdirLogSender = "Mkdir" - symlinkLogSender = "Symlink" - removeLogSender = "Remove" - chownLogSender = "Chown" - chmodLogSender = "Chmod" - chtimesLogSender = "Chtimes" - operationDownload = "download" - operationUpload = "upload" - operationDelete = "delete" - operationRename = "rename" - protocolSFTP = "SFTP" - protocolSCP = "SCP" - protocolSSH = "SSH" - handshakeTimeout = 2 * time.Minute + logSender = "sftpd" + logSenderSCP = "scp" + logSenderSSH = "ssh" + uploadLogSender = "Upload" + downloadLogSender = "Download" + renameLogSender = "Rename" + rmdirLogSender = "Rmdir" + mkdirLogSender = "Mkdir" + symlinkLogSender = "Symlink" + removeLogSender = "Remove" + chownLogSender = "Chown" + chmodLogSender = "Chmod" + chtimesLogSender = "Chtimes" + sshCommandLogSender = "SSHCommand" + operationDownload = "download" + operationUpload = "upload" + operationDelete = "delete" + operationRename = "rename" + protocolSFTP = "SFTP" + protocolSCP = "SCP" + protocolSSH = "SSH" + handshakeTimeout = 2 * time.Minute ) const ( diff --git a/sftpd/ssh_cmd.go b/sftpd/ssh_cmd.go index 6ab0df22..1e8add76 100644 --- a/sftpd/ssh_cmd.go +++ b/sftpd/ssh_cmd.go @@ -140,12 +140,15 @@ func (c *sshCommand) sendExitStatus(err error) { status := uint32(0) if err != nil { status = uint32(1) + c.connection.Log(logger.LevelWarn, logSenderSSH, "command failed: %#v args: %v user: %v err: %v", + c.command, c.args, c.connection.User.Username, err) + } else { + logger.CommandLog(sshCommandLogSender, c.getDestPath(), "", c.connection.User.Username, "", c.connection.ID, + protocolSSH, -1, -1, "", "", c.connection.command) } exitStatus := sshSubsystemExitStatus{ Status: status, } - c.connection.Log(logger.LevelDebug, logSenderSSH, "send exit status for command %#v with args: %v user: %v err: %v", - c.command, c.args, c.connection.User.Username, err) c.connection.channel.SendRequest("exit-status", false, ssh.Marshal(&exitStatus)) c.connection.channel.Close() }