Skip to content

Instantly share code, notes, and snippets.

@sauravg
Last active August 25, 2016 11:04
Show Gist options
  • Save sauravg/bf8a53b0da747dd194f0 to your computer and use it in GitHub Desktop.
Save sauravg/bf8a53b0da747dd194f0 to your computer and use it in GitHub Desktop.
Add more functionality to PasswordSafe CLI

Add more functionality to PasswordSafe CLI

This document proposes some new features to be added to command-line version of pwsafe (called pwsafe-cli, in src/ui/cli). It will probably not achieve feature parity with the GUI version, but will make pwsafe a lot more useful at the command-line.

  1. Existing Actions
  2. New Actions
  3. Multi-safe operations

All commands require the safe to be operated on as the very first argument to pwsafe-cli. This is the "current" safe: any operation that requires another safe provides the path to that safe as the value to the operation (e.g. --diff=some/other/safe.psafe3).

Any operation that can modify the safe takes a --dry-run argument which just skips the part that saves the safe file after making modifications.

1. Existing Actions

pwsafe-cli already implements import from & export to text & xml formats:

pwsafe-cli mysafe.psafe3 --imp|--exp[=filename] --text|--xml

2. New Actions

Create a new safe

pwsafe-cli newsafe.psafe3 --new 

newsafe.psafe3 must not exist.

Add a new entry to a safe

`pwsafe-cli newsafe-psafe3 --add='Group=Forums,Title=AVSForum,email=me@newmail.com,password=secret'`

Password is auto-generated if unspecified. Its an error if entry already exists.

Search for an entry

This is perhaps the most important command, because it lets you zero in on an entry and perform some operation on it. For search actions that modify the safe, pwsafe-cli would confirm before performing the action, once for each entry irrespective of the number of changes to that entry. --yes suppresses the confirmation, and just goes ahead with the changes.

`pwsafe-cli mysafe.psafe3 --search=search-text [--ignore-case] [--subset=Group^=Banks/[Ii]] [--fields=autotype,dca,...] [--yes] ACTION`

The --subset argument has the format <field><operator><value>. Other supported operators (mimicking the GUI) are

  1. == (exactly equal-to)
  2. !== (not equal-to)
  3. ^= (begins with)
  4. !^= (does not begin with)
  5. $= (ends with)
  6. !$= (does not end-with)
  7. ~= (contains)
  8. !~= (does not contain)

A trailing /i makes the string operation case-insensitive, while /I makes it case sensitive.

The fields argument is a comma-separated list of fields in which search-text would be searched for. By default, all fields would be searched. The known valid field types are

  1. Group
  2. Title
  3. Username
  4. Notes
  5. Password
  6. Created Time
  7. Password Modified Time
  8. Last Access Time
  9. Password Expiry Date
  10. Record Modified Time
  11. URL
  12. AutoType
  13. History
  14. Password Policy
  15. Password Expiry Interval
  16. Run Command
  17. DCA
  18. Shift-DCA
  19. e-mail
  20. Protected
  21. Symbols
  22. Password Policy Name
  23. Keyboard Shortcut

ACTION represents the action to be performed on the search results. Default action is print. Available search actions are

Print

Results are printed on stdout one entry per line in the following format:

Group1 >> Title1[User1] Group2 >> Title2[User2] Title3[User3] Group4 >> Title4 Title5

Printing just prints the Group, Title & User of matching entries on stdout, but Title is the only field that's guaranteed to be present for an entry. However, other fields can be printed by explicitly specifying the search action to be --print with the desired fields:

pwsafe-cli <safe> --search=gmail --print=e-mail,URL

Delete

pwsafe-cli ~/Sample123.psafe3 --search=gmail --delete

Update

pwsafe-cli <safe> --search=gmail --update=Field1=Value1,Field2=Value2...

Clear

pwsafe-cli <safe> --search=gmail --clear=field1,field2...

Generate new password

This will use the safe's and entry's password policy to generate the new password

`pwsafe-cli mysafe.psafe3 --search=Hotmail --fields=Title --new-password`

3. Multi-safe operations

Diff

`pwsafe-cli mysafe.psafe3 --diff=othersafe.psafe3 [--subset=Group^=Banks/[Ii]] [--fields=autotype,dca,...] [ --unified | --context | --sidebyside [--colwidth=<number>]]`

Show unified (default), context or side-by-side diff. Entries selected for comparison can be restricted by --subset, just like --search. Fields to be compared can be restricted with --fields.

Sync

`pwsafe-cli mysafe.psafe3 --sync=othersafe.psafe3  [--subset=Group^=Banks/[Ii]] [--fields=autotype,dca,...] [--yes]`

Update entries of mysafe.psafe3 with matching entries from othersafe.psafe3, wherever they differ. Entries in othersafe.psafe3 that don't exist in mysafe.psafe3 are ignored. Fields selected for sync'ing and the fields sync'ed in matching entries can be restricted just like --search.

--yes suppresses the "yes, no, no-to-all, yes-to-all, quit, abort" prompt before making each change.

Merge

`pwsafe-cli mysafe.psafe3 --merge=othersafe.psafe3  [--subset=Group^=Banks/[Ii]] --yes`

Merges all fields of matching entries. The entries selected for merging can be restricted, but NOT the fields.

--yes suppresses the "yes, no, no-to-all, yes-to-all, quit, abort" prompt before making each change.

Everything below this line is To-Be-Implemented

3. Other mechanisms for safe password input

For all operations that require a passphrase, pwsafe-cli would read it by turning terminal echo off. It won't support entering the passphrase on the command-line due to security concerns: it would probably get logged in shell history, be visible in ps output and could be visible in a scrollable terminal window. However, for performing multiple operations on a safe, it might sometimes be convenient to automate the passphrase input for pwsafe-cli, in a secure mannerl.

From an environment variable

export PASSWORSAFE_PASSWORD=mysecret

pwsafe-cli mysafe.psafe3 --combination-env=PASSWORDSAFE_PASSWORD --select='Title:ebay' --view

This idea is from ipmitool, which works somewhat like that.

There are possibly security issues with this feature, so it is under review. The arguments in favor are:

  1. The user has to set the environment variable with the passphrase himself. It doesn't get set automatically.

  2. The user controls the name of the environment variable. So it could be different for each user, e.g. MY_TEMP_FOO, every single time they set the variable.

  3. Any attempt to exploit this feature requires the machine to be exploited already. In which case, the malicious code would use a keylogger or screenshot generator. Basically, on a compromised machine, the game is over anyway. Any "external" code would run in a browser, which won't allow access to environment variables.

  4. It could be compiled in conditionally, with exclusion being the default.

And lastly, this is a very useful feature which allows users to not have to type long & hard to remember (& type) passphrases for every invocation of pwsafe-cli. The only other secure alternative is to type it each time which is very inconvenient for long & hard passphrases, which would push users choose weak & short passphrases for their safes (but the passphrase entry would be secure). The keyring option, IMO, is less secure than this. Using file descriptor is only good for scripting.

From a keyring (if possible, like on OSX)

The keyring manager should prompt the user to allow/disallow specific apps from accessing the password.

`pwsafe-cli mysafe.psafe3 --combination-keyring --search=AVSForum --print=Notes`

From a file descriptor

An application having access to a safe's combination might want to launch pwsafe-cli and pass the combination to it securely. Passing safe combination as command line parameter has the security issue that the combination could be visible in the output of ps command. Instead, the parent application could create an fd and fork pwsafe such that pwsafe inherits it. The combination then be securely written to & read from the fd by the parent application and pwsafe-cli respectively.

`pwsafe-cli mysafe.psafe3 --combination-fd=5 --search=SomeTitle --autotype`

1. Copy to clipboard (only if X is running)

`pwsafe-cli mysafe.psafe3 --search=Github --fields=Title --to-clipboard=password`

I'm not sure if copy/paste makes sense outside of a GUI enviroment like X. Therefore, this feature would probably depend on conditional compilation, and be available only if the required system headers are found at compilation time. Alternatively, it could work like expect for non-gui purposes, although I don't know right now how expect works. If not compiled in, it could probably use xsel if available at runtime.

2. Autotype

`pwsafe-cli mysafe.psafe3 --search='Gmail' --fields=Title --autotype`

This feature is subject to further review & investigation. But for now, it seems that on Linux, since it requires compiling & linking with X windows headers, it would compiled conditionally. Though pwsafe-cli is intended for a non-GUI server-like environment, the feature itself would be useful in an xterm-like app in a GUI environment like Gnome. Alternatively, it could use an external tool like xdotool to do the autotyping, if not compiled with this feature natively.

3. Run Command

Run an external command as configured in the entry

`pwsafe-cli mysafe.psafe3 --search=HomeNAS --fields=Title --run-command`

Run Command feature has not been implemented in the Linux/wxWidgets port yet.

@ronys
Copy link

ronys commented Mar 10, 2016

  1. Another alternative to environment variables would be an agent along the lines of ssh-agent.
  2. Environment variables are just too easy to snoop, e.g., /proc/pid/environ
  3. --help would also be useful, and quicker to set up than a man page.
  4. Advanced exercise: support predicates for selection, e.g., title='foo' and group!='bar'...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment