title: Go SSH server accepting file transfers via SCP
body: <p>I would like to create a server process with Go which can receive or send files via scp, like:</p>
  
  <pre><code>scp -P 2200 -i ssh/tester_rsa  foo@localhost:/test output.txt
  </code></pre>
  
  <p>or</p>
  
  <pre><code>scp -P 2200 -i ssh/tester_rsa  input.txt foo@localhost:/test
  </code></pre>
  
  <p>With help of <a href="https://gist.github.com/nictuku/2338048" rel="nofollow noreferrer">this gist</a> I was already able to create an interactive ssh server which is able to accpet connections/commands via</p>
  
  <pre><code>ssh -i ssh/tester_rsa foo@localhost -p 2200 'somecommand'
  </code></pre>
  
  <p>and works nicely.</p>
  
  <p>I understood that the payload contains "scp -f /test" for the first shown scp request. I am stuck in how to return actual content from the server, I tried in replying with a string (as with a normal ssh reply) but I get no file back.</p>
  
  <p>Here my output of scp -vv</p>
  
  <pre><code>...
  debug2: callback done
  debug2: channel 0: open confirm rwindow 2097152 rmax 32768
  debug2: channel_input_status_confirm: type 99 id 0
  debug2: exec request accepted on channel 0
  debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
  debug2: channel 0: rcvd close
  debug2: channel 0: output open -&gt; drain
  debug2: channel 0: close_read
  ...
  </code></pre>
  
  <p>When I am trying with a propper server I get following lines</p>
  
  <pre><code>...
  debug2: exec request accepted on channel 0
  debug2: channel 0: rcvd ext data 43
  Sending file modes: C0644 98 output.txt
  debug2: channel 0: written 43 to efd 7
  Sink: C0644 98 output.txt
  output.txt           
  debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
  debug1: client_input_channel_req: channel 0 rtype eow@openssh.com     reply 0
  debug2: channel 0: rcvd eow
  debug2: channel 0: close_read
  ...
  </code></pre>
  
  <p>So I guess I am missing some protocol / flow parameters or commands in Go.</p>
  
  <p>Only the snippet of Go Code, as project is huge and is not easy to copy and paste here:</p>
  
  <pre><code>func (a *Shell) handleExec(connection ssh.Channel, payload []byte) {
  ...
  for _, c := range a.ExecCmds {
      if matchCmds(str, c.Cmd) {
          connection.Write([]byte("Here comes the file content")
      }
  }
  ...
  </code></pre>
  
  <p>I know that the code is not right for scp, but it works fine for normal ssh. I don't know how to handle the connection, and what exactly to return so that a correct file transfer is done.</p>
  
  <p>Googling for a while led me to <a href="https://stackoverflow.com/questions/33846959/golang-ssh-server-how-to-handle-file-transfer-with-scp">this question on stack overflow</a> which is nearly the same but got not completely answered, as I am exactly looking for the part</p>
  
  <pre><code> runYourCommand(msg.Command, ch)
  </code></pre>
  
  <p>which I guess contains the logic :)</p>
  
  <p>Update: I am looking not for external ressources any more, I got some more input from <a href="http://www.programcreek.com/java-api-examples/index.php?class=com.jcraft.jsch.ChannelExec&amp;method=getOutputStream" rel="nofollow noreferrer">this java snippet</a></p>
  
  <p>It looks like they are emulating the scp protocol and I would perfectly be fine to have someone helping me to translate it to Go:</p>
  
  <pre><code>  StringBuilder params = new StringBuilder("C0").append(perms);
    params.append(" ").append(data.length).append(" ");
    params.append(remoteFileName).append("\n");
  
    out.write(params.toString().getBytes());
    out.flush();
  
    if (!waitForInputStream(logger, in)) {
       cleanup(logger, out, channel);
       logger.log(Level.SEVERE, "Error before writing SCP bytes");
       return UNKNOWN_ERROR;           /* TODO: Improve */
    }
  
    out.write(data);
    out.write(new byte[]{0}, 0, 1);
    out.flush();
  </code></pre>
  
  <p>I tried this so far, but didn't help</p>
  
  <pre><code>o:="Some content of a faked file"
  connection.Write([]byte("C0644 "+string(len(o))+"test.txt\n"))
  connection.Write([]byte(o))
  connection.Write([]byte{0,0,1})
  </code></pre>
  
  <p>To clarify: I would not like to serve a real file, rather then Go simulating a file delivery over scp (using a string as the content of the file).</p>
  
  <p>Thanks in advance!</p>