[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[minion-cvs] Add support for reading passphrases and SURBs from the ...
Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv32580/lib/mixminion
Modified Files:
ClientMain.py ClientUtils.py Main.py
Log Message:
Add support for reading passphrases and SURBs from the arbitrary fds.
Also clean up some error messages.
Based on a patch submitted by Brian Warner.
Index: ClientMain.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ClientMain.py,v
retrieving revision 1.149
retrieving revision 1.150
diff -u -d -r1.149 -r1.150
--- ClientMain.py 8 Jan 2004 22:35:24 -0000 1.149
+++ ClientMain.py 15 Jan 2004 21:03:25 -0000 1.150
@@ -12,7 +12,7 @@
import os
import sys
import time
-from types import ListType
+from types import IntType, StringType
import mixminion.BuildMessage
import mixminion.ClientUtils
@@ -194,7 +194,7 @@
# keys: A ClientKeyring object.
# queue: A ClientQueue object.
# surbLogFilename: The filename used by the SURB log.
- def __init__(self, conf):
+ def __init__(self, conf, password_fileno=None):
"""Create a new MixminionClient with a given configuration"""
self.config = conf
@@ -202,7 +202,10 @@
userdir = self.config['User']['UserDir']
createPrivateDir(userdir)
keyDir = os.path.join(userdir, "keys")
- self.pwdManager = mixminion.ClientUtils.CLIPasswordManager()
+ if password_fileno is None:
+ self.pwdManager = mixminion.ClientUtils.CLIPasswordManager()
+ else:
+ self.pwdManager = mixminion.ClientUtils.FDPasswordManager(password_fileno)
self.keys = ClientKeyring(keyDir, self.pwdManager)
self.surbLogFilename = os.path.join(userdir, "surbs", "log")
@@ -308,6 +311,8 @@
"""
#XXXX write unit tests
key = self.keys.getSURBKey(name=name, create=1)
+ if not key:
+ raise UIError("unable to get SURB key")
exitType, exitInfo, _ = address.getRouting()
block = mixminion.BuildMessage.buildReplyBlock(
@@ -701,7 +706,7 @@
-D | --download-directory : force/disable directory downloading.
PATH-RELATED
-t | --to : specify an exit address
- -R | --reply-block : specify a reply block
+ -R | --reply-block | --reply-block-fd : specify a reply block
-H | --hops : specify a path length
-P | --path : specify a literal path.
REPLY PATH ONLY
@@ -726,7 +731,7 @@
# nHops: number of hops, or None.
# address: exit address, or None.
# lifetime: SURB lifetime, or None.
- # replyBlockFiles: list of SURB filenames.
+ # replyBlockFiles: list of SURB filenames. DOCDOC
# configFile: Filename of configuration file, or None.
# forceQueue: true if "--queue" is set.
# forceNoQueue: true if "--no-queue" is set.
@@ -781,12 +786,13 @@
self.configFile = None
self.verbose = 0
self.download = None
+ self.password_fileno = None
self.path = None
self.nHops = None
self.exitAddress = None
self.lifetime = None
- self.replyBlockFiles = []
+ self.replyBlockSources = [] #DOCDOC int is fd, str is filename
self.forceQueue = None
self.forceNoQueue = None
@@ -824,7 +830,12 @@
raise UsageError(str(e))
elif o in ('-R', '--reply-block'):
assert wantForwardPath
- self.replyBlockFiles.append(v)
+ self.replyBlockSources.append(v)
+ elif o == '--reply-block-fd':
+ try:
+ self.replyBlockSources.append(int(v))
+ except ValueError:
+ raise UIError("%s expects an integer"%o)
elif o in ('-H', '--hops'):
assert wantForwardPath or wantReplyPath
if self.nHops is not None:
@@ -848,6 +859,12 @@
self.lifetime = int(v)
except ValueError:
raise UsageError("%s expects an integer"%o)
+ elif o in ('--passphrase-fd',):
+ #DOCDOC
+ try:
+ self.password_fileno = int(v)
+ except ValueError:
+ raise UsageError("%s expects an integer"%o)
elif o in ('--queue',):
self.forceQueue = 1
elif o in ('--no-queue',):
@@ -890,7 +907,7 @@
if self.wantClient:
assert self.wantConfig
LOG.debug("Configuring client")
- self.client = MixminionClient(self.config)
+ self.client = MixminionClient(self.config, self.password_fileno)
if self.wantClientDirectory:
assert self.wantConfig
@@ -925,18 +942,25 @@
self.exitAddress = mixminion.ClientDirectory.parseAddress(address)
except ParseError, e:
raise UIError("Error in SURBAddress: %s" % e)
- elif self.exitAddress is None and self.replyBlockFiles == []:
+ elif self.exitAddress is None and self.replyBlockSources == []:
raise UIError("No recipients specified; exiting. (Try using "
"-t <recipient-address>")
- elif self.exitAddress is not None and self.replyBlockFiles:
+ elif self.exitAddress is not None and self.replyBlockSources:
raise UIError("Cannot use both a recipient and a reply block")
- elif self.replyBlockFiles:
+ elif self.replyBlockSources:
useRB = 1
surbs = []
- for fn in self.replyBlockFiles:
- if fn == '-':
+ for fn in self.replyBlockSources:
+ if isinstance(fn, IntType):
+ f = os.fdopen(fn, 'rb')
+ try:
+ s = f.read()
+ finally:
+ f.close()
+ elif fn == '-':
s = sys.stdin.read()
else:
+ assert isinstance(fn, StringType)
s = readFile(fn, 1)
try:
if stringContains(s,
@@ -1010,6 +1034,7 @@
packet, then deliver multiple fragmented packets
to the recipient instead of having the server
reassemble the message.
+ --reply-block-fd=<N> DOCDOC
%(extra)s
EXAMPLES:
@@ -1076,10 +1101,10 @@
# Parse and validate our options.
options, args = getopt.getopt(args, "hvf:D:t:H:P:R:i:",
["help", "verbose", "config=", "download-directory=",
- "to=", "hops=", "path=", "reply-block=",
+ "to=", "hops=", "path=", "reply-block=", "reply-block-fd=",
"input=", "queue", "no-queue",
"subject=", "from=", "in-reply-to=", "references=",
- "deliver-fragments" ])
+ "deliver-fragments", ])
if not options:
sendUsageAndExit(cmd)
@@ -1124,7 +1149,7 @@
except MixError, e:
raise UIError("Invalid headers: %s"%e)
- if inFile in (None, '-') and '-' in parser.replyBlockFiles:
+ if inFile in (None, '-') and '-' in parser.replyBlockSources:
raise UIError(
"Can't read both message and reply block from stdin")
@@ -1475,6 +1500,8 @@
overcompressed.
-o <file>, --output=<file> Write the results to <file> rather than stdout.
-i <file>, --input=<file> Read the results from <file>.
+ --passphrase-fd=<N> Read passphrase from file descriptor N instead
+ of asking on the console.
EXAMPLES:
Decode message(s) stored in 'NewMail', writing the result to stdout.
@@ -1487,7 +1514,7 @@
"""[Entry point] Decode a message."""
options, args = getopt.getopt(args, "hvf:o:Fi:",
['help', 'verbose', 'config=',
- 'output=', 'force', 'input='])
+ 'output=', 'force', 'input=', 'passphrase-fd=',])
outputFile = '-'
inputFile = None
@@ -1564,6 +1591,8 @@
of ascii mode.
-n <N>, --count=<N> Generate <N> reply blocks. (Defaults to 1.)
--identity=<name> Specify a pseudonymous identity.
+ --passphrase-fd=<N> Read passphrase from file descriptor N instead
+ of asking on the console.
EXAMPLES:
Generate a reply block to deliver messages to the address given in
@@ -1591,7 +1620,7 @@
def generateSURB(cmd, args):
options, args = getopt.getopt(args, "hvf:D:t:H:P:o:bn:",
['help', 'verbose', 'config=', 'download-directory=',
- 'to=', 'hops=', 'path=', 'lifetime=',
+ 'to=', 'hops=', 'path=', 'lifetime=', 'passphrase-fd=',
'output=', 'binary', 'count=', 'identity='])
outputFile = '-'
Index: ClientUtils.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ClientUtils.py,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- ClientUtils.py 3 Jan 2004 07:35:23 -0000 1.16
+++ ClientUtils.py 15 Jan 2004 21:03:26 -0000 1.17
@@ -39,6 +39,9 @@
abstract class."""
## Fields
# passwords: map from password name to string value of the password.
+ # do_retry: static field: should we keep asking for a password until
+ # one is correct?
+ do_retry = 1
def __init__(self):
"""Create a new PasswordManager"""
self.passwords = {}
@@ -83,6 +86,8 @@
if confirmFn(pwd):
self.passwords[name] = pwd
return pwd
+ if not self.do_retry:
+ break
maxTries -= 1
pmt = "Incorrect password. "+prompt
@@ -95,13 +100,37 @@
class CLIPasswordManager(PasswordManager):
"""Impementation of PasswordManager that asks for passwords from the
command line."""
- def __init__(self):
+ def __init__(self, password_fileno=None):
PasswordManager.__init__(self)
def _getPassword(self, name, prompt):
return getPassword_term(prompt)
def _getNewPassword(self, name, prompt):
return getNewPassword_term(prompt)
+class FDPasswordManager(PasswordManager):
+ """Impementation of PasswordManager that asks for passwords from a
+ specified fileno."""
+ do_retry = 0
+ def __init__(self, password_fileno=None):
+ PasswordManager.__init__(self)
+ self.password_fileno = password_fileno
+ def _getPassword(self, name, prompt):
+ return getPassword_fd(self.password_fileno)
+ def _getNewPassword(self, name, prompt):
+ return getPassword_fd(self.password_fileno)
+
+def getPassword_fd(fileno):
+ """Read a password from a specified fileno."""
+ pw = ""
+ while 1:
+ chunk = os.read(fileno, 1024) # read from --password-fd filehandle
+ if not chunk:
+ break
+ pw += chunk
+ # Strip trailing endline from password, if any.
+ if pw.endswith("\n"): pw = pw[:-1]
+ return pw
+
def getPassword_term(prompt):
"""Read a password from the console, then return it. Use the string
'message' as a prompt."""
Index: Main.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Main.py,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -d -r1.66 -r1.67
--- Main.py 14 Dec 2003 01:43:38 -0000 1.66
+++ Main.py 15 Jan 2004 21:03:26 -0000 1.67
@@ -265,8 +265,8 @@
if args[1] not in ('unittests', 'benchmarks', 'version') and \
'--quiet' not in args and '-Q' not in args:
import mixminion
- print "Mixminion version %s" % mixminion.__version__
- print "This software is for testing purposes only."\
+ print >>sys.stderr, "Mixminion version %s" % mixminion.__version__
+ print >>sys.stderr, "This software is for testing purposes only."\
" Anonymity is not guaranteed."
# Read the 'common' module to get the UIError class. To simplify