From a832f0543d0a7992663cc37e066e9e7dce3f74d9 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Tue, 9 Oct 2012 08:38:30 -0400 Subject: [PATCH] crypt: use AssuanClient.send_fds() to send file descriptors to gpgme-tool. This requires Python 3.3, so I've updated the docs accordingly. It brings us up to date with pyassuan commit: commit 9133ecb527756f4fc8f3461002eecfc4c4f45aaa Author: W. Trevor King Date: Mon Oct 8 14:47:35 2012 -0400 client: add AssuanClient.send_fds() and .receive_fds(). --- README | 11 +++-- bin/send-pgp-mime.py | 2 +- pgp_mime/crypt.py | 110 +++++++++++++++++-------------------------- pgp_mime/key.py | 4 +- setup.py | 1 - 5 files changed, 52 insertions(+), 76 deletions(-) diff --git a/README b/README index a122d47..034c3c0 100644 --- a/README +++ b/README @@ -24,7 +24,7 @@ Dependencies ------------ ``pgp-mime`` is a simple package with no external dependencies outside -the Python 3 standard library. There are a number of GnuPG_ wrappers +the Python 3.3 standard library. There are a number of GnuPG_ wrappers for python `out there`__, but none of them seem mature/stable enough to be worth installing. Instead, we use the `pyassuan`_ module to talk to `gpgme-tool`_ over pipes or sockets. If this isn't working @@ -33,10 +33,11 @@ the cryptography. __ wrappers_ -It would be awkward to backport ``pgp-mime`` to Python 2.7, because we -take advantage of the ``pass_fds`` argument to Popen_ to pass file -descriptors to the child `gpgme-tool` processes. Once we get to -Python 3.3, we'll use sendmsg_ and recvmsg_ instead. +It would be awkward to backport ``pgp-mime`` to earlier versions of +Python, because versions before Python 3.3 lack sendmsg_ and recvmsg_, +and Python 2.7 doesn't even have that pass_fds option for Popen. This +makes it much harder to pass file descriptors to the `gpgme-tool` +process. Installing by hand ------------------ diff --git a/bin/send-pgp-mime.py b/bin/send-pgp-mime.py index 012f55e..01f063a 100755 --- a/bin/send-pgp-mime.py +++ b/bin/send-pgp-mime.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3.3 # Copyright (C) 2012 W. Trevor King # # This file is part of pgp-mime. diff --git a/pgp_mime/crypt.py b/pgp_mime/crypt.py index b98b323..9c2a2d2 100644 --- a/pgp_mime/crypt.py +++ b/pgp_mime/crypt.py @@ -18,9 +18,6 @@ import codecs as _codecs import logging as _logging import os as _os import os.path as _os_path -from _socket import socket as _Socket -import socket as _socket -import subprocess as _subprocess from pyassuan import client as _client from pyassuan import common as _common @@ -29,41 +26,17 @@ from . import LOG as _LOG from . import signature as _signature -def connect(client, filename, **kwargs): - filename = _os_path.expanduser(filename) - if False: - socket = _socket.socket(_socket.AF_UNIX, _socket.SOCK_STREAM) - socket.connect(filename) - client.input = socket.makefile('rb') - client.output = socket.makefile('wb') - else: - p = _subprocess.Popen( - filename, stdin=_subprocess.PIPE, stdout=_subprocess.PIPE, - close_fds=True, **kwargs) - client.input = p.stdout - client.output = p.stdin - socket = p - client.connect() - return socket - def get_client(**kwargs): logger = _logging.getLogger('{}.{}'.format(_LOG.name, 'pyassuan')) client = _client.AssuanClient( name='pgp-mime', logger=logger, use_sublogger=False, close_on_disconnect=True) - socket = connect(client, '~/src/gpgme/build/src/gpgme-tool', **kwargs) - #socket = connect(client, '~/.assuan/S.gpgme-tool', **kwargs) - return (client, socket) + client.connect(socket_path='/tmp/gpgme-tool.sock') + return client -def disconnect(client, socket): +def disconnect(client): client.make_request(_common.Request('BYE')) client.disconnect() - if isinstance(socket, _Socket): - socket.shutdown(_socket.SHUT_RDWR) - socket.close() - else: - status = socket.wait() - assert status == 0, status def hello(client): responses,data = client.get_responses() # get initial 'OK' from server @@ -126,9 +99,7 @@ def sign_and_encrypt_bytes(data, signers=None, recipients=None, """ input_read,input_write = _os.pipe() output_read,output_write = _os.pipe() - client,socket = get_client(pass_fds=(input_read, output_write)) - _os.close(input_read) - _os.close(output_write) + client = get_client() try: hello(client) if signers: @@ -137,10 +108,14 @@ def sign_and_encrypt_bytes(data, signers=None, recipients=None, if recipients: for recipient in recipients: client.make_request(_common.Request('RECIPIENT', recipient)) - client.make_request( - _common.Request('INPUT', 'FD={}'.format(input_read))) - client.make_request( - _common.Request('OUTPUT', 'FD={}'.format(output_write))) + client.send_fds([input_read]) + client.make_request(_common.Request('INPUT', 'FD')) + _os.close(input_read) + input_read = -1 + client.send_fds([output_write]) + client.make_request(_common.Request('OUTPUT', 'FD')) + _os.close(output_write) + output_write = -1 parameters = [] if signers or allow_default_signer: if recipients: @@ -161,8 +136,8 @@ def sign_and_encrypt_bytes(data, signers=None, recipients=None, _common.Request(command, ' '.join(parameters))) d = _read(output_read) finally: - disconnect(client, socket) - for fd in [input_write, output_read]: + disconnect(client) + for fd in [input_read, input_write, output_read, output_write]: if fd >= 0: _os.close(fd) return d @@ -191,23 +166,25 @@ def decrypt_bytes(data): """ input_read,input_write = _os.pipe() output_read,output_write = _os.pipe() - client,socket = get_client(pass_fds=(input_read, output_write)) - _os.close(input_read) - _os.close(output_write) + client = get_client() try: hello(client) - client.make_request( - _common.Request('INPUT', 'FD={}'.format(input_read))) - client.make_request( - _common.Request('OUTPUT', 'FD={}'.format(output_write))) + client.send_fds([input_read]) + client.make_request(_common.Request('INPUT', 'FD')) + _os.close(input_read) + input_read = -1 + client.send_fds([output_write]) + client.make_request(_common.Request('OUTPUT', 'FD')) + _os.close(output_write) + output_write = -1 _write(input_write, data) _os.close(input_write) input_write = -1 client.make_request(_common.Request('DECRYPT')) d = _read(output_read) finally: - disconnect(client, socket) - for fd in [input_write, output_read]: + disconnect(client) + for fd in [input_read, input_write, output_read, output_write]: if fd >= 0: _os.close(fd) return d @@ -376,33 +353,31 @@ def verify_bytes(data, signature=None, always_trust=False): hash algorithm: SHA256 """ input_read,input_write = _os.pipe() - pass_fds = [input_read] if signature: message_read,message_write = _os.pipe() - output_read = -1 - pass_fds.append(message_read) + output_read = output_write = -1 else: - message_write = -1 + message_read = message_write = -1 output_read,output_write = _os.pipe() - pass_fds.append(output_write) - client,socket = get_client(pass_fds=pass_fds) - _os.close(input_read) - if signature: - _os.close(message_read) - else: - _os.close(output_write) + client = get_client() verified = None signatures = [] try: hello(client) - client.make_request( - _common.Request('INPUT', 'FD={}'.format(input_read))) + client.send_fds([input_read]) + client.make_request(_common.Request('INPUT', 'FD')) + _os.close(input_read) + input_read = -1 if signature: - client.make_request( - _common.Request('MESSAGE', 'FD={}'.format(message_read))) + client.send_fds([message_read]) + client.make_request(_common.Request('MESSAGE', 'FD')) + _os.close(message_read) + message_read = -1 else: - client.make_request( - _common.Request('OUTPUT', 'FD={}'.format(output_write))) + client.send_fds([output_write]) + client.make_request(_common.Request('OUTPUT', 'FD')) + _os.close(output_write) + output_write = -1 if signature: _write(input_write, signature) _os.close(input_write) @@ -428,8 +403,9 @@ def verify_bytes(data, signature=None, always_trust=False): elif signature.pka_trust != 'good': verified = False finally: - disconnect(client, socket) - for fd in [input_write, message_write, output_read]: + disconnect(client) + for fd in [input_read, input_write, message_read, message_write, + output_read, output_write]: if fd >= 0: _os.close(fd) return (plain, verified, signatures) diff --git a/pgp_mime/key.py b/pgp_mime/key.py index 3a5ab48..00ba127 100644 --- a/pgp_mime/key.py +++ b/pgp_mime/key.py @@ -144,7 +144,7 @@ def lookup_keys(patterns=None): [..., , ...] """ _LOG.debug('lookup key: {}'.format(patterns)) - client,socket = _crypt.get_client() + client = _crypt.get_client() parameters = [] if patterns: args = [' '.join(patterns)] @@ -154,7 +154,7 @@ def lookup_keys(patterns=None): _crypt.hello(client) rs,result = client.make_request(_common.Request('KEYLIST', *args)) finally: - _crypt.disconnect(client, socket) + _crypt.disconnect(client) tag_mapping = { } tree = _etree.fromstring(result.replace(b'\x00', b'')) diff --git a/setup.py b/setup.py index 97f63e4..9fa096a 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,6 @@ _setup( 'Operating System :: OS Independent', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Topic :: Communications :: Email', 'Topic :: Security :: Cryptography', -- 2.26.2