@@ -92,18 +92,19 @@ func (c *etcdChecker) doCheck(hostport string) utils.State {
9292
9393// findDestination finds a reachable destination for the sshd server according
9494// to the etcd database if available or the routes and route_select algorithm.
95- // It returns a string with the service name and a string with host:port, a
95+ // It returns a string with the service name, a string with host:port, a string
96+ // containing ForceCommand value and a bool containing CommandMustMatch; a
9697// string with the service name and an empty string if no destination is found
9798// or an error if any.
98- func findDestination (cli * utils.Client , username string , routes map [string ]* utils.RouteConfig , sshdHostport string , checkInterval utils.Duration ) (string , string , error ) {
99+ func findDestination (cli * utils.Client , username string , routes map [string ]* utils.RouteConfig , sshdHostport string , checkInterval utils.Duration ) (string , string , string , bool , error ) {
99100 checker := & etcdChecker {
100101 checkInterval : checkInterval ,
101102 cli : cli ,
102103 }
103104
104105 service , err := findService (routes , sshdHostport )
105106 if err != nil {
106- return "" , "" , err
107+ return "" , "" , "" , false , err
107108 }
108109 key := fmt .Sprintf ("%s@%s" , username , service )
109110
@@ -117,7 +118,7 @@ func findDestination(cli *utils.Client, username string, routes map[string]*util
117118 if utils .IsDestinationInRoutes (dest , routes [service ].Dest ) {
118119 if checker .Check (dest ) {
119120 log .Debugf ("found destination in etcd: %s" , dest )
120- return service , dest , nil
121+ return service , dest , routes [ service ]. ForceCommand , routes [ service ]. CommandMustMatch , nil
121122 }
122123 log .Infof ("cannot connect %s to already existing connection(s) to %s: host %s" , key , dest , checker .LastState )
123124 } else {
@@ -128,10 +129,10 @@ func findDestination(cli *utils.Client, username string, routes map[string]*util
128129
129130 if len (routes [service ].Dest ) > 0 {
130131 selected , err := utils .SelectRoute (routes [service ].RouteSelect , routes [service ].Dest , checker , cli , key )
131- return service , selected , err
132+ return service , selected , routes [ service ]. ForceCommand , routes [ service ]. CommandMustMatch , err
132133 }
133134
134- return service , "" , fmt .Errorf ("no destination set for service %s" , service )
135+ return service , "" , "" , false , fmt .Errorf ("no destination set for service %s" , service )
135136}
136137
137138// findService finds the first service containing a suitable source in the conf,
@@ -309,6 +310,7 @@ func mainExitCode() int {
309310 log .Debugf ("config.log_stats_interval = %s" , config .LogStatsInterval .Duration ())
310311 log .Debugf ("config.etcd = %+v" , config .Etcd )
311312 log .Debugf ("config.bg_command = %s" , config .BgCommand )
313+ log .Debugf ("config.translate_commands = %v" , config .TranslateCommands )
312314 log .Debugf ("config.environment = %v" , config .Environment )
313315 log .Debugf ("config.routes = %v" , config .Routes )
314316 log .Debugf ("config.ssh.exe = %s" , config .SSH .Exe )
@@ -324,7 +326,7 @@ func mainExitCode() int {
324326 log .Errorf ("Cannot contact etcd cluster to update state: %v" , err )
325327 }
326328
327- service , hostport , err := findDestination (cli , username , config .Routes , sshInfos .Dst (), config .CheckInterval )
329+ service , hostport , forceCommand , commandMustMatch , err := findDestination (cli , username , config .Routes , sshInfos .Dst (), config .CheckInterval )
328330 switch {
329331 case err != nil :
330332 log .Fatalf ("Finding destination: %s" , err )
@@ -442,24 +444,39 @@ func mainExitCode() int {
442444 if port != utils .DefaultSSHPort {
443445 sshArgs = append (sshArgs , "-p" , port )
444446 }
445- if originalCmd != "" {
446- if strings .Contains (originalCmd , "sftp-server" ) {
447- // Ask for sftp subsystem on destination (arguments are
448- // the same used by sftp client command).
449- sshArgs = append (sshArgs , "-oForwardX11=no" ,
450- "-oForwardAgent=no" , "-oPermitLocalCommand=no" ,
451- "-oClearAllForwardings=yes" , "-oProtocol=2" ,
452- "-s" , "--" , host , "sftp" )
453- if config .Dump != "" {
454- // We don't want to dump sftp connections
455- config .Dump = "etcd"
447+ doCmd := ""
448+ if forceCommand != "" {
449+ log .Debugf ("forceCommand = %s" , forceCommand )
450+ doCmd = forceCommand
451+ } else if originalCmd != "" {
452+ doCmd = originalCmd
453+ }
454+ commandTranslated := false
455+ if doCmd != "" {
456+ if commandMustMatch && originalCmd != doCmd {
457+ log .Errorf ("error executing proxied ssh command: originalCmd \" %s\" does not match forceCommand \" %s\" " , originalCmd , forceCommand )
458+ return 1
459+ }
460+ for fromCmd , translateCmdConf := range config .TranslateCommands {
461+ if doCmd == fromCmd {
462+ log .Debugf ("translateCmdConf = %+v" , translateCmdConf )
463+ for _ , sshArg := range translateCmdConf .SSHArgs {
464+ sshArgs = append (sshArgs , sshArg )
465+ }
466+ sshArgs = append (sshArgs , "--" , host , translateCmdConf .Command )
467+ if config .Dump != "" && translateCmdConf .DisableDump {
468+ config .Dump = "etcd"
469+ }
470+ commandTranslated = true
471+ break
456472 }
457- } else {
473+ }
474+ if ! commandTranslated {
458475 if interactiveCommand {
459476 // Force TTY allocation because the user probably asked for it.
460477 sshArgs = append (sshArgs , "-t" )
461478 }
462- sshArgs = append (sshArgs , host , originalCmd )
479+ sshArgs = append (sshArgs , host , doCmd )
463480 }
464481 } else {
465482 sshArgs = append (sshArgs , host )
@@ -469,7 +486,7 @@ func mainExitCode() int {
469486
470487 var recorder * Recorder
471488 if config .Dump != "" {
472- recorder = NewRecorder (conninfo , config .Dump , originalCmd , config .EtcdStatsInterval .Duration (), config .LogStatsInterval .Duration (), config .DumpLimitSize , config .DumpLimitWindow .Duration ())
489+ recorder = NewRecorder (conninfo , config .Dump , doCmd , config .EtcdStatsInterval .Duration (), config .LogStatsInterval .Duration (), config .DumpLimitSize , config .DumpLimitWindow .Duration ())
473490
474491 wg .Add (1 )
475492 go func () {
0 commit comments