Skip to content

Commit

Permalink
Merge cc3c311 into a9b7650
Browse files Browse the repository at this point in the history
  • Loading branch information
Jc2k committed Oct 5, 2015
2 parents a9b7650 + cc3c311 commit 7d28999
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 0 deletions.
3 changes: 3 additions & 0 deletions touchdown/ssh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
from .client import Client, private_key_from_string
from .connection import Connection, Instance

from . import terminal # noqa


__all__ = [
"Client",
"Connection",
Expand Down
126 changes: 126 additions & 0 deletions touchdown/ssh/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import struct
import os
import SocketServer
import shutil
import tempfile
import threading
import time

import paramiko
from paramiko.message import Message
from paramiko.common import asbytes
from paramiko.py3compat import byte_chr


SSH_AGENT_FAILURE = 5
SSH_AGENT_SUCCESS = 6
SSH2_AGENT_IDENTITIES_ANSWER = 12
SSH2_AGENT_SIGN_RESPONSE = 14


class ConnectionError(Exception):
pass


class AgentRequestHandler(SocketServer.BaseRequestHandler):

def _read(self, wanted):
result = ''
while len(result) < wanted:
buf = self.request.recv(wanted - len(result))
if not buf:
raise ConnectionError()
result += buf
return result

def read_message(self):
size = struct.unpack('>I', self._read(4))[0]
msg = Message(self._read(size))
return ord(msg.get_byte()), msg

def send_message(self, msg):
msg = asbytes(msg)
self.request.sendall(struct.pack('>I', len(msg)) + msg)

def handler_11(self, msg):
# SSH2_AGENTC_REQUEST_IDENTITIES = 11
m = Message()
m.add_byte(byte_chr(SSH2_AGENT_IDENTITIES_ANSWER))
m.add_int(len(self.server.identities))
for pkey, comment in self.server.identities.values():
m.add_string(pkey.asbytes())
m.add_string(comment)
return m

def handler_13(self, msg):
# SSH2_AGENTC_SIGN_REQUEST = 13
pkey, comment = self.server.identities.get(msg.get_binary(), (None, None))
data = msg.get_binary()
msg.get_int()
m = Message()
if not pkey:
m.add_byte(chr(SSH_AGENT_FAILURE))
return m
m.add_byte(chr(SSH2_AGENT_SIGN_RESPONSE))
m.add_string(pkey.sign_ssh_data(data).asbytes())
return m

def handle(self):
while True:
try:
mtype, msg = self.read_message()
except ConnectionError:
return

handler = getattr(self, "handler_{}".format(mtype))
if not handler:
print "{!r} not a supported message type".format(mtype)
continue

self.send_message(handler(msg))


class AgentServer(SocketServer.UnixStreamServer):

def __init__(self, socket_file):
SocketServer.UnixStreamServer.__init__(self, socket_file, AgentRequestHandler)
self.identities = {}

def add(self, pkey, comment):
self.identities[pkey.asbytes()] = (pkey, comment)

def serve_while_pid(self, pid):
t = threading.Thread(target=self.serve_forever)
t.daemon = True
t.start()

while os.waitpid(pid, 0)[0] != pid:
pass

self.shutdown()
self.server_close()


def main():
pid = os.getpid()
socket_dir = tempfile.mkdtemp(prefix='ssh-')
socket_file = os.path.join(socket_dir, 'agent.{}'.format(pid))

child_pid = os.fork()
if child_pid:
a = AgentServer(socket_file)
a.add(
paramiko.RSAKey.from_private_key_file('/home/john/test.pem'),
'test.pem',
)
a.serve_while_pid(child_pid)
shutil.rmtree(socket_dir)
return

while not os.path.exists(socket_file):
time.sleep(0.5)

os.execvpe("/usr/bin/ssh", ["ssh", "ubuntu@127.0.0.1"], {"SSH_AUTH_SOCK": socket_file})


main()
23 changes: 23 additions & 0 deletions touchdown/ssh/terminal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2015 Isotoma Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from touchdown.ssh import connection


class ConnectionPlan(connection.ConnectionPlan):

name = "ssh"

def start(self):
pass

0 comments on commit 7d28999

Please sign in to comment.