2015-06-06 14:52:10 +00:00
|
|
|
import socket
|
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
import tempfile
|
|
|
|
import contextlib
|
|
|
|
import threading
|
|
|
|
|
2015-06-15 15:13:10 +00:00
|
|
|
from . import protocol
|
|
|
|
from . import formats
|
|
|
|
from . import util
|
2015-06-06 14:52:10 +00:00
|
|
|
|
2015-06-16 07:20:11 +00:00
|
|
|
import logging
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
2015-06-16 07:03:48 +00:00
|
|
|
|
2015-06-06 14:52:10 +00:00
|
|
|
@contextlib.contextmanager
|
|
|
|
def unix_domain_socket_server(sock_path):
|
|
|
|
log.debug('serving on SSH_AUTH_SOCK=%s', sock_path)
|
|
|
|
try:
|
|
|
|
os.remove(sock_path)
|
|
|
|
except OSError:
|
|
|
|
if os.path.exists(sock_path):
|
|
|
|
raise
|
|
|
|
|
|
|
|
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
|
|
server.bind(sock_path)
|
|
|
|
server.listen(1)
|
|
|
|
try:
|
|
|
|
yield server
|
|
|
|
finally:
|
|
|
|
os.remove(sock_path)
|
|
|
|
|
2015-06-16 07:03:48 +00:00
|
|
|
|
2015-06-16 07:34:02 +00:00
|
|
|
def handle_connection(conn, handler):
|
2015-06-15 15:13:10 +00:00
|
|
|
try:
|
|
|
|
log.debug('welcome agent')
|
|
|
|
while True:
|
|
|
|
msg = util.read_frame(conn)
|
2015-06-16 07:34:02 +00:00
|
|
|
reply = handler.handle(msg=msg)
|
2015-06-15 15:13:10 +00:00
|
|
|
util.send(conn, reply)
|
|
|
|
except EOFError:
|
|
|
|
log.debug('goodbye agent')
|
|
|
|
except:
|
|
|
|
log.exception('error')
|
|
|
|
raise
|
2015-06-06 14:52:10 +00:00
|
|
|
|
2015-06-16 07:03:48 +00:00
|
|
|
|
2015-06-17 15:01:47 +00:00
|
|
|
def server_thread(server, handler):
|
2015-06-15 06:16:47 +00:00
|
|
|
log.debug('server thread started')
|
2015-06-06 14:52:10 +00:00
|
|
|
while True:
|
|
|
|
log.debug('waiting for connection on %s', server.getsockname())
|
|
|
|
try:
|
|
|
|
conn, _ = server.accept()
|
|
|
|
except socket.error as e:
|
2015-07-20 15:28:09 +00:00
|
|
|
log.debug('server stopped: %s', e)
|
2015-06-06 14:52:10 +00:00
|
|
|
break
|
|
|
|
with contextlib.closing(conn):
|
2015-06-16 07:34:02 +00:00
|
|
|
handle_connection(conn, handler)
|
2015-06-15 06:16:47 +00:00
|
|
|
log.debug('server thread stopped')
|
2015-06-06 14:52:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
@contextlib.contextmanager
|
|
|
|
def spawn(func, **kwargs):
|
|
|
|
t = threading.Thread(target=func, kwargs=kwargs)
|
|
|
|
t.start()
|
|
|
|
yield
|
|
|
|
t.join()
|
|
|
|
|
|
|
|
|
2015-06-17 13:52:11 +00:00
|
|
|
@contextlib.contextmanager
|
2015-07-04 05:35:59 +00:00
|
|
|
def serve(public_keys, signer, sock_path=None):
|
2015-06-06 14:52:10 +00:00
|
|
|
if sock_path is None:
|
|
|
|
sock_path = tempfile.mktemp(prefix='ssh-agent-')
|
|
|
|
|
2015-07-20 15:28:00 +00:00
|
|
|
keys = [formats.import_public_key(k) for k in public_keys]
|
2015-06-06 14:52:10 +00:00
|
|
|
environ = {'SSH_AUTH_SOCK': sock_path, 'SSH_AGENT_PID': str(os.getpid())}
|
|
|
|
with unix_domain_socket_server(sock_path) as server:
|
2015-06-17 15:01:47 +00:00
|
|
|
handler = protocol.Handler(keys=keys, signer=signer)
|
|
|
|
with spawn(server_thread, server=server, handler=handler):
|
2015-06-15 06:15:24 +00:00
|
|
|
try:
|
2015-06-17 13:52:11 +00:00
|
|
|
yield environ
|
2015-06-15 06:15:24 +00:00
|
|
|
finally:
|
|
|
|
log.debug('closing server')
|
|
|
|
server.shutdown(socket.SHUT_RD)
|
2015-06-17 13:52:11 +00:00
|
|
|
|
|
|
|
|
2015-07-04 06:24:10 +00:00
|
|
|
def run_process(command, environ, use_shell=False):
|
2015-06-17 13:52:11 +00:00
|
|
|
log.debug('running %r with %r', command, environ)
|
|
|
|
env = dict(os.environ)
|
|
|
|
env.update(environ)
|
|
|
|
try:
|
2015-07-04 06:24:10 +00:00
|
|
|
p = subprocess.Popen(args=command, env=env, shell=use_shell)
|
2015-06-17 13:52:11 +00:00
|
|
|
except OSError as e:
|
|
|
|
raise OSError('cannot run %r: %s' % (command, e))
|
|
|
|
log.debug('subprocess %d is running', p.pid)
|
|
|
|
ret = p.wait()
|
|
|
|
log.debug('subprocess %d exited: %d', p.pid, ret)
|
2015-06-15 15:13:10 +00:00
|
|
|
return ret
|