Przeglądaj źródła

ssh commands: fix parsing commands with space

For now we support "\" escaping style
Nicola Murino 5 lat temu
rodzic
commit
7bfe0ddf80
4 zmienionych plików z 32 dodań i 4 usunięć
  1. 1 1
      README.md
  2. 19 0
      sftpd/internal_test.go
  3. 1 0
      sftpd/scp.go
  4. 11 3
      sftpd/ssh_cmd.go

+ 1 - 1
README.md

@@ -301,7 +301,7 @@ sftpgo initprovider --help
 
 
 The `initprovider` command is enough for new installations. From now on, the database structure will be automatically checked and updated, if required, at startup.
 The `initprovider` command is enough for new installations. From now on, the database structure will be automatically checked and updated, if required, at startup.
 
 
-If you are upgrading from version 0.9.5 or before you have to manually execute the SQL scripts to create the required database structure.Theese script can be found inside the source tree [sql](./sql "sql") directory. The SQL scripts filename is, by convention, the date as `YYYYMMDD` and the suffix `.sql`. You need to apply all the SQL scripts for your database ordered by name, for example `20190828.sql` must be applied before `20191112.sql` and so on.
+If you are upgrading from version 0.9.5 or before you have to manually execute the SQL scripts to create the required database structure.These script can be found inside the source tree [sql](./sql "sql") directory. The SQL scripts filename is, by convention, the date as `YYYYMMDD` and the suffix `.sql`. You need to apply all the SQL scripts for your database ordered by name, for example `20190828.sql` must be applied before `20191112.sql` and so on.
 Example for SQLite: `find sql/sqlite/ -type f -iname '*.sql' -print | sort -n | xargs cat | sqlite3 sftpgo.db`.
 Example for SQLite: `find sql/sqlite/ -type f -iname '*.sql' -print | sort -n | xargs cat | sqlite3 sftpgo.db`.
 After applying these scripts your database structure is the same as the one obtained using `initprovider` for new installations, so from now on you don't have to manually upgrade your database anymore.
 After applying these scripts your database structure is the same as the one obtained using `initprovider` for new installations, so from now on you don't have to manually upgrade your database anymore.
 
 

+ 19 - 0
sftpd/internal_test.go

@@ -628,6 +628,25 @@ func TestSSHCommandPath(t *testing.T) {
 	if path != "/" {
 	if path != "/" {
 		t.Errorf("unexpected path: %v", path)
 		t.Errorf("unexpected path: %v", path)
 	}
 	}
+	sshCommand.args = []string{"-f", "/a space.txt"}
+	path = sshCommand.getDestPath()
+	if path != "/a space.txt" {
+		t.Errorf("unexpected path: %v", path)
+	}
+}
+
+func TestSSHParseCommandPayload(t *testing.T) {
+	cmd := "command -a  -f  some\\ spaces\\ \\ .txt"
+	name, args, _ := parseCommandPayload(cmd)
+	if name != "command" {
+		t.Errorf("unexpected command: %v", name)
+	}
+	if len(args) != 3 {
+		t.Errorf("unexpected number of arguments %v/3", len(args))
+	}
+	if !utils.IsStringInSlice("some spaces  .txt", args) {
+		t.Errorf("command parsing error, expected arguments not found: %v", args)
+	}
 }
 }
 
 
 func TestSSHCommandErrors(t *testing.T) {
 func TestSSHCommandErrors(t *testing.T) {

+ 1 - 0
sftpd/scp.go

@@ -56,6 +56,7 @@ func (c *scpCommand) handle() error {
 		}
 		}
 	} else {
 	} else {
 		err = fmt.Errorf("scp command not supported, args: %v", c.args)
 		err = fmt.Errorf("scp command not supported, args: %v", c.args)
+		c.connection.Log(logger.LevelDebug, logSenderSCP, "unsupported scp command, args: %v", c.args)
 	}
 	}
 	c.sendExitStatus(err)
 	c.sendExitStatus(err)
 	return err
 	return err

+ 11 - 3
sftpd/ssh_cmd.go

@@ -45,7 +45,7 @@ type systemCommand struct {
 func processSSHCommand(payload []byte, connection *Connection, channel ssh.Channel, enabledSSHCommands []string) bool {
 func processSSHCommand(payload []byte, connection *Connection, channel ssh.Channel, enabledSSHCommands []string) bool {
 	var msg sshSubsystemExecMsg
 	var msg sshSubsystemExecMsg
 	if err := ssh.Unmarshal(payload, &msg); err == nil {
 	if err := ssh.Unmarshal(payload, &msg); err == nil {
-		name, args, err := parseCommandPayload(msg.Command)
+		name, args, err := parseCommandPayload(strings.TrimSpace(msg.Command))
 		connection.Log(logger.LevelDebug, logSenderSSH, "new ssh command: %#v args: %v user: %v, error: %v",
 		connection.Log(logger.LevelDebug, logSenderSSH, "new ssh command: %#v args: %v user: %v, error: %v",
 			name, args, connection.User.Username, err)
 			name, args, connection.User.Username, err)
 		if err == nil && utils.IsStringInSlice(name, enabledSSHCommands) {
 		if err == nil && utils.IsStringInSlice(name, enabledSSHCommands) {
@@ -421,9 +421,17 @@ func computeHashForFile(hasher hash.Hash, path string) (string, error) {
 }
 }
 
 
 func parseCommandPayload(command string) (string, []string, error) {
 func parseCommandPayload(command string) (string, []string, error) {
-	parts := strings.Split(command, " ")
+	parts := strings.Split(strings.ReplaceAll(command, "\\ ", "\\"), " ")
 	if len(parts) < 2 {
 	if len(parts) < 2 {
 		return parts[0], []string{}, nil
 		return parts[0], []string{}, nil
 	}
 	}
-	return parts[0], parts[1:], nil
+	args := []string{}
+	for _, arg := range parts[1:] {
+		parsed := strings.TrimSpace(strings.ReplaceAll(arg, "\\", " "))
+		if len(parsed) == 0 {
+			continue
+		}
+		args = append(args, parsed)
+	}
+	return parts[0], args, nil
 }
 }