Ver código fonte

Merge branch 'master' of https://github.com/pwman3/pwman3

oz123 12 anos atrás
pai
commit
0aa6a34527
8 arquivos alterados com 308 adições e 116 exclusões
  1. 24 3
      README.md
  2. 56 0
      documentation/general_notes.txt
  3. 3 4
      pwman/data/database.py
  4. 4 4
      pwman/data/factory.py
  5. 67 10
      pwman/ui/cli.py
  6. 0 1
      pwman/util/config.py
  7. 104 50
      pwman/util/crypto.py
  8. 50 44
      scripts/pwman3

+ 24 - 3
README.md

@@ -4,26 +4,47 @@ A nice command line password manager, which is smart enough to use different SQL
 Pwman3 can also copy passwords to the clipboard (on Mac and Linux) without exposing them, so you save
 some typing. 
 Besides managing and storing passwords, Pwman3 can also generate passwords using different algorithms. 
+## Nice Features in pwman3:
 
+ * copying of passwords to clipboard
+ * lauching specific uri's with default browser
+ * password generators
 
 ## Installing 
 
 Pwman3 requires the following debian packages:
 	
-when using python 2.4    
+when using python 2.4:    
+    
     python-pysqlite2
 	python-celementtree
     python-crypto
+
+
+
 when using python >= 2.5 
+    
     python-crypto
 
-
 for nicer functionality:
     xsel - to copy password to clipboard on Linux
 
+
+
+Pwman now uses argparse, which is only
+available in Python 2.7. Therefore, if you intend to use
+pwman3 with an older version of Python, please do so before
+installing:
+
+    $ cp scripts/pwman3 scripts/pwman3_bkup
+    $ cp scripts/pwman3_old scripts/pwman3
+
+Note that the old startup script of pwman3 might have limited
+functionality compared to the newer version. 
+
 To install:
 
-$ python setup.py install
+    $ python setup.py install
 
 ## ikegam's function 
 

+ 56 - 0
documentation/general_notes.txt

@@ -0,0 +1,56 @@
+# Work in progress
+
+
+enc = CryptoEngine.get() in ui/cli.py (L:940)
+
+is called before the db is even set !
+
+when priniting nodes, decrypt is first called by:
+this initializes CryptoEngine instance,
+and sets the following instance properties:
+    - _callback
+    - _instance 
+    - _keycrypted
+    - _timeout
+    - _cypher
+
+this initialization asks the user for the decryption key
+of the database. 
+
+the action that user does called the respective db function which
+returns an ENCRYPTED STRING!, 
+which is then given to decryption via nodes.py or tags.py which do the
+actual decryption on each decrypted string returned from the DB.
+
+for example print_node:
+
+initializing a _db instance, then we call _db.open()
+
+calling do_print(10) calls _db.getnodes([i]) at this point
+the database is still not decrypted ... e.g. _cypher is still empty
+
+when _db.getnodes([i]) is done node inside  print_node is containing 
+alot of encrypted string.
+
+now print_node will be called, at which point the different methods
+of node instance will decrypt their respective string:
+
+e.g. get_username(self) instide nodes.py:
+     
+     self._username -> OexYH7vT/WVpXO0ZBM93RF/l8+o8/QU8ykgDB4qY8+BxBaKylAOeJWEQ+edjpLTU\n
+     enc = CryptoEngine.get() 
+     enc.decrypt(self._username) -> nahum.oz@gmail.com
+
+
+to see this in work:
+insert 
+        import ipdb; ipdb.set_trace()
+to def getnodes(self, ids) in "pwman/data/drivers/sqlite.py.
+
+continue to pwman3/pwman/ui/cli.py(382) self.print_node(node[0])
+and then step into this function. 
+continue further into  def print_node(self, node) inside pwman3/pwman/ui/cli.py, 
+finally you should step into:
+
+    node.get_username()
+

+ 3 - 4
pwman/data/database.py

@@ -16,7 +16,6 @@
 #============================================================================
 # Copyright (C) 2012 Oz Nahum <nahumoz@gmail.com>
 #============================================================================
-#============================================================================
 # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
 #============================================================================
 
@@ -58,9 +57,9 @@ class Database:
         return self._filtertags
     
     def filter(self, tags):
-        for t in tags:
-            if not (t in self._filtertags):
-                self._filtertags.append(t)
+        for tag in tags:
+            if not (tag in self._filtertags):
+                self._filtertags.append(tag)
 
     def clearfilter(self):
         self._filtertags = []

+ 4 - 4
pwman/data/factory.py

@@ -16,15 +16,15 @@
 #============================================================================
 # Copyright (C) 2012 Oz Nahum <nahumoz@gmail.com>
 #============================================================================
-#============================================================================
 # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
 #============================================================================
 
-"""Factory to create Database instances
-
+"""
+Factory to create Database instances
+A Generic interface for all DB engines.
 Usage:
 
-import pwlib.db.DatabaseFactory as DBFactory
+import pwman.data.factory as DBFactory
 
 db = DBFactory.create(params)
 db.open()

+ 67 - 10
pwman/ui/cli.py

@@ -512,10 +512,10 @@ class PwmanCli(cmd.Cmd):
         if self.hasxsel:
             ids= self.get_ids(args)
             if len(ids) > 1:
-                print "Can only 1 password at a time..."
+                print "Can copy only 1 password at a time..."
+                return None
             try:
                 node = self._db.getnodes(ids)
-                node[0].get_password()
                 text_to_clipboards(node[0].get_password())
                 print """copied password for %s@%s clipboard... erasing in 10 sec...""" %\
                 (node[0].get_username(), node[0].get_url()) 
@@ -528,13 +528,35 @@ class PwmanCli(cmd.Cmd):
 
     def do_cp(self,args):
         self.do_copy(args)
-        
+    
+    def do_open(self, args):
+        ids = self.get_ids(args)
+        if len(ids) > 1:
+            print "Can open only 1 link at a time ..."
+            return None
+        try:
+            node = self._db.getnodes(ids)
+            url = node[0].get_url()
+            open_url(url)
+        except Exception, e:
+            self.error(e)
+
+    def do_o(self, args):
+        self.do_open(args)
     ##
     ## Help functions
     ##
     def usage(self, string):
         print "Usage: %s" % (string)
-   
+    
+    def help_open(self):
+        self.usage("open <ID>")
+        print "Launch default browser with 'xdg-open url',\n\
+the url must contain http:// or https://."
+    
+    def help_o(self):
+        self.help_open()
+
     def help_copy(self):
         self.usage("copy <ID>")
         print "Copy password to X clipboard (xsel required)"
@@ -696,15 +718,35 @@ class PwmanCliMac(PwmanCli):
     def do_cp(self,args):
         self.do_copy(args)
         
+    def do_open(self, args):
+        ids = self.get_ids(args)
+        if len(ids) > 1:
+            print "Can open only 1 link at a time ..."
+            return None
+        try:
+            node = self._db.getnodes(ids)
+            url = node[0].get_url()
+            open_url(url,MacOS=True)
+        except Exception, e:
+            self.error(e)
+
+    def do_o(self, args):
+        self.do_open(args)
+    
     ##
     ## Help functions
     ##
-    def usage(self, string):
-        print "Usage: %s" % (string)
-   
+    def help_open(self):
+        self.usage("open <ID>")
+        print "Launch default browser with 'open url',\n\
+the url must contain http:// or https://."
+    
+    def help_o(self):
+        self.help_open()
+
     def help_copy(self):
         self.usage("copy <ID>")
-        print "Copy password to X clipboard (xsel required)"
+        print "Copy password to Cocoa clipboard using pbcopy)"
 
     def help_cp(self):
         self.help_copy()
@@ -771,7 +813,6 @@ def getpassword(question, width=_defaultwidth, echo=False):
         print question.ljust(width),
         return sys.stdin.readline().rstrip()
     else:
-        
         while 1:
             a1 = getpass.getpass(question.ljust(width))
             if len(a1) == 0:
@@ -807,6 +848,7 @@ def select(question, possible):
 
 def text_to_clipboards(text):
     """
+    copy text to clipboard
     credit:
     https://pythonadventures.wordpress.com/tag/xclip/
     """
@@ -818,11 +860,13 @@ def text_to_clipboards(text):
         xsel_proc = sp.Popen(['xsel', '-bi'], stdin=sp.PIPE)
         xsel_proc.communicate(text) 
     except OSError, e:
-        print e, "\nExecuting xsel failed, is it installed ?"
+        print e, "\nExecuting xsel failed, is it installed ?\n \
+please check your configuration file ... "
         
         
 def text_to_mcclipboards(text):
     """
+    copy text to mac os x clip board
     credit:
     https://pythonadventures.wordpress.com/tag/xclip/
     """
@@ -834,6 +878,19 @@ def text_to_mcclipboards(text):
         print e, "\nExecuting pbcoy failed..."
 
 
+def open_url(link, MacOS=False):
+    """
+    launch xdg-open or open in MacOSX with url
+    """
+    uopen="xdg-open"
+    if MacOS:
+        uopen="open"
+    try:
+       sp.Popen([uopen, link], stdin=sp.PIPE)
+    except OSError, e:
+        print "Executing open_url failed with:\n", e
+    
+
 class CliMenu(object):
     def __init__(self):
         self.items = []

+ 0 - 1
pwman/util/config.py

@@ -16,7 +16,6 @@
 #============================================================================
 # Copyright (C) 2012 Oz Nahum <nahumoz@gmail.com>
 #============================================================================
-#============================================================================
 # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
 #============================================================================
 

+ 104 - 50
pwman/util/crypto.py

@@ -1,31 +1,32 @@
 #============================================================================
 # This file is part of Pwman3.
-# 
+#
 # Pwman3 is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License, version 2
-# as published by the Free Software Foundation; 
-# 
+# as published by the Free Software Foundation;
+#
 # Pwman3 is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
-# 
+#
 # You should have received a copy of the GNU General Public License
 # along with Pwman3; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #============================================================================
 # Copyright (C) 2012 Oz Nahum <nahumoz@gmail.com>
 #============================================================================
-#============================================================================
 # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
 #============================================================================
 
-"""Encryption Module used by PwmanDatabase
+"""
+Encryption Module used by PwmanDatabase
 
 Supports AES, ARC2, Blowfish, CAST, DES, DES3, IDEA, RC5.
 
 Usage:
 import pwman.util.crypto.CryptoEngine as CryptoEngine
+from pwman.util.crypto import CryptoEngine
 
 class myCallback(CryptoEngine.Callback):
     def execute(self):
@@ -41,14 +42,22 @@ ciphertext = crypto.encrypt("plaintext")
 plaintext = cyypto.decrypt(ciphertext)
 
 """
-from Crypto.Cipher import *
+from Crypto.Cipher import Blowfish as cBlowfish
+from Crypto.Cipher import AES as cAES
+from Crypto.Cipher import ARC2 as cARC2
+from Crypto.Cipher import ARC4 as cARC2
+from Crypto.Cipher import CAST as cCAST
+from Crypto.Cipher import DES as cDES
+from Crypto.Cipher import DES3 as cDES3
+
 from Crypto.Util.randpool import RandomPool
+
 from pwman.util.callback import Callback
 import pwman.util.config as config
 import cPickle
 import time
 
-_instance = None
+_INSTANCE = None
 
 # Use this to tell if crypto is successful or not
 _TAG = "PWMANCRYPTO"
@@ -84,14 +93,15 @@ class CryptoPasswordMismatchException(CryptoException):
     """Entered passwords do not match."""
     def __str__(self):
         return "CryptoPasswordMismatchException: " + self.message
-    
+
 
 class CryptoEngine:
     """Cryptographic Engine"""
     _timeoutcount = 0
     _instance = None
     _callback = None
-    
+
+    @classmethod
     def get(cls):
         """
         get() -> CryptoEngine
@@ -105,7 +115,7 @@ class CryptoEngine:
             else:
                 CryptoEngine._instance = CryptoEngine()
         return CryptoEngine._instance
-    get = classmethod(get)
+    #get = classmethod(get)
 
     def __init__(self):
         """Initialise the Cryptographic Engine
@@ -121,27 +131,27 @@ class CryptoEngine:
         if len(algo) > 0:
             self._algo = algo
         else:
-            raise CryptoException("Parameters missing [%s]" % (e) )
+            raise CryptoException("Parameters missing, no algorithm given")
 
         callback = config.get_value("Encryption", "callback")
         if isinstance(callback, Callback):
             self._callback = callback
         else:
             self._callback = None
-        
+
         keycrypted = config.get_value("Encryption", "keycrypted")
         if len(keycrypted) > 0:
             self._keycrypted = keycrypted
         else:
             self._keycrypted = None
-            
+
         timeout = config.get_value("Encryption", "timeout")
         if timeout.isdigit():
             self._timeout = timeout
         else:
             self._timeout = -1
         self._cipher = None
-    
+
     def encrypt(self, obj):
         """
         encrypt(obj) -> ciphertext
@@ -150,31 +160,48 @@ class CryptoEngine:
         cipher = self._getcipher()
         plaintext = self._preparedata(obj, cipher.block_size)
         ciphertext = cipher.encrypt(plaintext)
+
         return str(ciphertext).encode('base64')
-        
+
     def decrypt(self, ciphertext):
         """
         decrypt(ciphertext) -> obj
         Decrypt ciphertext and returns the obj that was encrypted.
         If key is bad, a CryptoBadKeyException is raised
         Can also raise a CryptoException and CryptoUnsupportedException"""
+        print ciphertext
         cipher = self._getcipher()
         ciphertext = str(ciphertext).decode('base64')
         plaintext = cipher.decrypt(ciphertext)
+        print plaintext
+        #import pdb
+        #pdb.set_trace()
         return self._retrievedata(plaintext)
 
     def set_cryptedkey(self, key):
+        """
+        hold _keycrypted
+        """
         self._keycrypted = key
 
     def get_cryptedkey(self):
+        """
+        return _keycrypted
+        """
         return self._keycrypted
 
     def set_callback(self, callback):
+        """
+        set the callback function
+        """
         self._callback = callback
 
     def get_callback(self):
+        """
+        return call back function
+        """
         return self._callback
-    
+
     def changepassword(self):
         """
         Creates a new key. The key itself is actually stored in
@@ -183,106 +210,127 @@ class CryptoEngine:
         password for the database.
         If oldKeyCrypted is none, then a new password is generated."""
         if (self._callback == None):
-            raise CryptoNoCallbackException("No call back class has been specified")
+            raise CryptoNoCallbackException("No call back class has been \
+specified")
         if (self._keycrypted == None):
             # Generate a new key, 32 bits in length, if that's
             # too long for the Cipher, _getCipherReal will sort it out
             random = RandomPool()
             key = str(random.get_bytes(32)).encode('base64')
         else:
-            password = self._callback.getsecret("Please enter your current password")
+            password = self._callback.getsecret("Please enter your current \
+password")
             cipher = self._getcipher_real(password, self._algo)
             plainkey = cipher.decrypt(str(self._keycrypted).decode('base64'))
             key = self._retrievedata(plainkey)
-        newpassword1 = self._callback.getsecret("Please enter your new password");
-        newpassword2 = self._callback.getsecret("Please enter your new password again");
+        newpassword1 = self._callback.getsecret("Please enter your new \
+password")
+        newpassword2 = self._callback.getsecret("Please enter your new \
+password again")
         if (newpassword1 != newpassword2):
             raise CryptoPasswordMismatchException("Passwords do not match")
         newcipher = self._getcipher_real(newpassword1, self._algo)
-        self._keycrypted = str(newcipher.encrypt(self._preparedata(key, newcipher.block_size))).encode('base64')
-        
+        self._keycrypted = str(newcipher.encrypt(self._preparedata(key,
+                           newcipher.block_size))).encode('base64')
+
         # we also want to create the cipher if there isn't one already
         # so this CryptoEngine can be used from now on
         if (self._cipher == None):
-            self._cipher = self._getcipher_real(str(key).decode('base64'), self._algo)
-            CryptoEngine._timeoutcount = time.time()        
-            
+            self._cipher = self._getcipher_real(str(key).decode('base64'),
+                                                self._algo)
+            CryptoEngine._timeoutcount = time.time()
+
         return self._keycrypted
 
     def alive(self):
+        """
+        check if we have cipher
+        """
         if (self._cipher != None):
             return True
         else:
             return False
 
     def forget(self):
+        """
+        discard cipher
+        """
         self._cipher = None
-        
+
     def _getcipher(self):
+        """
+        get cypher from user, to decrypt DB
+        """
         if (self._cipher != None
             and (self._timeout == -1
-                 or (time.time() - CryptoEngine._timeoutcount) < self._timeout)):
+            or (time.time() - CryptoEngine._timeoutcount) < self._timeout)):
             return self._cipher
         if (self._callback == None):
             raise CryptoNoCallbackException("No Callback exception")
         if (self._keycrypted == None):
             raise CryptoNoKeyException("Encryption key has not been generated")
 
-        maxTries = 5
+        max_tries = 5
         tries = 0
 
         key = None
 
-        while tries < maxTries:
+        while tries < max_tries:
             try:
-                password = self._callback.getsecret("Please enter your password")
+                password = self._callback.getsecret("Please enter your\
+password")
                 tmpcipher = self._getcipher_real(password, self._algo)
-                plainkey = tmpcipher.decrypt(str(self._keycrypted).decode('base64'))
+                plainkey = tmpcipher.decrypt(str(self._keycrypted).decode(
+                    'base64'))
                 key = self._retrievedata(plainkey)
                 break
-            except CryptoBadKeyException, e:
+            except CryptoBadKeyException:
                 print "Wrong password."
                 tries += 1
 
         if not key:
-            raise Exception("Wrong password entered %s times; giving up" % maxTries)
-        
-        self._cipher = self._getcipher_real(str(key).decode('base64'), self._algo)
+            raise Exception("Wrong password entered %s times; giving up" \
+                    % max_tries)
+
+        self._cipher = self._getcipher_real(str(key).decode('base64'),
+                self._algo)
 
         CryptoEngine._timeoutcount = time.time()
         return self._cipher
-        
+
 
     def _getcipher_real(self, key, algo):
+        """
+        do the real job of decrypting using functions
+        form PyCrypto
+        """
         if (algo == "AES"):
             key = self._padkey(key, [16, 24, 32])
-            cipher = AES.new(key, AES.MODE_ECB)
+            cipher = cAES.new(key, cAES.MODE_ECB)
         elif (algo == 'ARC2'):
-            cipher = ARC2.new(key, ARC2.MODE_ECB)
+            cipher = cARC2.new(key, cARC2.MODE_ECB)
         elif (algo == 'ARC4'):
             raise CryptoUnsupportedException("ARC4 is currently unsupported")
         elif (algo == 'Blowfish'):
-            cipher = Blowfish.new(key, Blowfish.MODE_ECB)
+            cipher = cBlowfish.new(key, cBlowfish.MODE_ECB)
         elif (algo == 'CAST'):
-            cipher = CAST.new(key, CAST.MODE_ECB)
+            cipher = cCAST.new(key, cCAST.MODE_ECB)
         elif (algo == 'DES'):
             self._padkey(key, [8])
-            cipher = DES.new(key, DES.MODE_ECB)
+            cipher = cDES.new(key, cDES.MODE_ECB)
         elif (algo == 'DES3'):
             key = self._padkey(key, [16, 24])
-            cipher = DES3.new(key, DES3.MODE_ECB)
-        elif (algo == 'IDEA'):
-            key = self._padkey(key, [16])
-            cipher = IDEA.new(key, IDEA.MODE_ECB)
-        elif (algo == 'RC5'):
-            cipher = RC5.new(key, RC5.MODE_ECB)
+            cipher =  cDES3.new(key, cDES3.MODE_ECB)
         elif (algo == 'XOR'):
             raise CryptoUnsupportedException("XOR is currently unsupported")
         else:
-            raise CryptoException("Invalid algorithm specified")        
+            raise CryptoException("Invalid algorithm specified")
         return cipher
 
     def _padkey(self, key, acceptable_lengths):
+        """
+        pad key with extra string
+        """
         maxlen = max(acceptable_lengths)
         keylen = len(key)
         if (keylen > maxlen):
@@ -297,6 +345,9 @@ class CryptoEngine:
         return key.ljust(newkeylen)
 
     def _preparedata(self, obj, blocksize):
+        """
+        prepare data before encrypting
+        """
         plaintext = cPickle.dumps(obj)
         plaintext = _TAG + plaintext
         numblocks = (len(plaintext)/blocksize) + 1
@@ -304,6 +355,9 @@ class CryptoEngine:
         return plaintext.ljust(newdatasize)
 
     def _retrievedata(self, plaintext):
+        """
+        retrieve encrypted data
+        """
         if (plaintext.startswith(_TAG)):
             plaintext = plaintext[len(_TAG):]
         else:
@@ -316,7 +370,7 @@ class DummyCryptoEngine(CryptoEngine):
     Only for testing and debugging the DB drivers really."""
     def __init__(self):
         pass
-    
+
     def encrypt(self, obj):
         """Return the object pickled."""
         return cPickle.dumps(obj)

+ 50 - 44
scripts/pwman3

@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/python
 #============================================================================
 # This file is part of Pwman3.
 #
@@ -15,37 +15,54 @@
 # along with Pwman3; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #============================================================================
+#============================================================================
+# Copyright (C) 2012 Oz Nahum <nahumoz@gmail.com>
+#============================================================================
 # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
 #============================================================================
+import os
+import os.path
+import subprocess as sp
+
+_saveconfig = True
+
+import argparse
+
+
+parser = argparse.ArgumentParser(description='pwman3 - a command line password'\
++'manager.')
+parser.add_argument('-c','--config', dest='cfile', 
+                    default=os.path.expanduser("~/.pwman/config"),
+                    help='cofiguretion file to read')
+parser.add_argument('-d', '--database', dest='dbase',
+                    default=os.path.expanduser("~/.pwman/pwman.db"))
+
+parser.add_argument('-e', '--encryption', dest="algo", default="Blowfish",
+                help="Possible options are: AES, ARC2, ARC4, "\
+                +"Blowfish(default) CAST, DES, DES3, IDEA, RC5")
+
+parser.add_argument('-t','--test',  help="Run pwman from current directory \
+without installation", action="store_true")
+args = parser.parse_args()
+
+if args.test:
+    import sys
+    sys.path.insert(0,os.getcwd())
+
 from pwman.util.crypto import CryptoEngine
 import getopt
 import sys
 if 'darwin' in sys.platform:
-    from pwman.ui.cli import PwmanCliMac
+    from pwman.ui.cli import PwmanCliMac as PwmanCli
+    OSX=True
 else:
     from pwman.ui.cli import PwmanCli
 
 import pwman.util.config as config
 import pwman.data.factory
-import os
-import os.path
-import subprocess as sp
-_saveconfig = True
-
 
-def print_help():
-    print """Syntax: %s [options]
+config_file=args.cfile
 
- -c, --config FILE      Read configuration from FILE
- -d, --database FILE    Use FILE as database
- -e, --encryption ALGO  Use ALGO to encrypt data
-                        Possible options are:
-                         AES, ARC2, ARC4, Blowfish(default),
-                         CAST, DES, DES3, IDEA, RC5
- -h, --help             Display this help and exit
-
-Please report bugs at https://github.com/pwman3/pwman3
-""" % (sys.argv[0])
 
 
 def which(cmd):
@@ -75,42 +92,31 @@ try:
                       }
     config.set_defaults(default_config)
 
-    opts, args = getopt.getopt(sys.argv[1:], 'c:d:e:h',
-                               ["config=", "database=",
-                               "encryption=", "help"])
-
-    for o in opts:
-        if o[0] == '-c' or o[0] == "--config":
-            config_file = os.path.expanduser(o[1])
-
-        if o[0] == '-h' or o[0] == "--help":
-            print_help()
-            sys.exit(0)
-    # if no config exists yet, look for xsel
     if os.path.exists(config_file):
         config.load(config_file)
         xselpath = config.get_value("Global", "xselpath")
-    else:
+    elif not OSX :
         xselpath = which("xsel")
         config.set_value("Global", "xsel", xselpath)
-
-    for o in opts:
-        if o[0] == '-d' or o[0] == "--database":
-            config.set_value("Database", "filename",
-                             os.path.expanduser(o[1]))
-            _saveconfig = False
-        if o[0] == '-e' or o[0] == "--encryption":
-            config.set_value("Encryption", "algorithm", o[1])
+    elif OSX:
+        pbcopypath = which("pbcopy")
+        config.set_value("Global", "xsel", pbcopypath)
+        
+    if args.dbase !=  config.get_value('Database', "filename"):
+        config.set_value("Database", "filename", args.dbase)
+        _saveconfig = False
+    if args.algo != "Blowfish":
+            config.set_value("Encryption", "algorithm", args.algo)
             _saveconfig = False
 
     # set umask before creating/opening any files
     umask = int(config.get_value("Global", "umask"))
     os.umask(umask)
-
+    
     enc = CryptoEngine.get()
 
-    type = config.get_value("Database", "type")
-    db = pwman.data.factory.create(type)
+    dbtype = config.get_value("Database", "type")
+    db = pwman.data.factory.create(dbtype)
     cli = PwmanCli(db, xselpath)
 except SystemExit, e:
     sys.exit(e)
@@ -122,7 +128,7 @@ try:
     try:
         cli.cmdloop()
     except KeyboardInterrupt, e:
-        print
+        print e
 finally:
     try:
         if _saveconfig: