2 # -*- coding: ascii -*-
3 ###########################################################################
4 # clivepass, the login password utility for clive
5 # Copyright (C) 2008 Toni Gundogdu.
7 # This file is part of clive-utils.
9 # clivepass is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # clivepass is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with clivepass. If not, see <http://www.gnu.org/licenses/>.
21 ###########################################################################
25 # TODO: Implement --show (usernames only)
26 # TODO: Document --show
31 binmode(STDOUT
, ":utf8");
38 use Digest
::MD5
qw(md5_hex);
40 use Getopt
::Long
qw(:config bundling);
47 my $VERSION = "2.0beta3";
48 my $CONFIGDIR = $ENV{CLIVEPASS_CONFIGDIR
}
49 || File
::Spec
->catfile($ENV{HOME
}, ".config/clivepass");
50 my $PASSWDFILE = File
::Spec
->catfile($CONFIGDIR, "passwd");
54 'create|c', 'add|a=s', 'get|g=s', 'edit|e=s', 'delete|d=s',
55 'manual|m', 'help|h', 'version|v' => \
&print_version
,
58 pod2usage
(-exitstatus
=> 0, -verbose
=> 1) if $opts{help
};
59 pod2usage
(-exitstatus
=> 0, -verbose
=> 2) if $opts{manual
};
64 mkpath
( [$CONFIGDIR], 1, 0700 );
66 if ( $opts{add
} ) { add_login
(); }
67 elsif ( $opts{create
} ) { create_passwd
(); }
68 elsif ( $opts{edit
} ) { edit_login
(); }
69 elsif ( $opts{delete} ) { delete_login
(); }
70 elsif ( $opts{get
} ) { get_login
(); }
72 pod2usage
(-exitstatus
=> 0, -verbose
=> 1);
77 if ( -e
$PASSWDFILE ) {
78 print "WARN: $PASSWDFILE exists already.\n"
79 . "WARN: You are about to overwrite the existing file.\n"
80 . "WARN: Hit ctrl-c now if that's not your intention.\n";
82 print "Creating $PASSWDFILE.\n";
85 $phrase = getpass
("Enter passphrase: ") while ( ! $phrase );
86 $again = getpass
("Enter passphrase again: ") while ( ! $again );
88 print STDERR
"error: passphrases did not match\n" and exit
89 unless $phrase eq $again;
91 my $passwd = Config
::Tiny
->new;
92 $passwd->{_
}->{phrase
} = unix_md5_crypt
($phrase, salt
(8));
93 $passwd->write($PASSWDFILE);
95 return ( passwd
=> $passwd, phrase
=> $phrase );
99 my ($phrase_hash) = @_;
101 print STDERR
"error: $PASSWDFILE: phrase hash not found\n" and exit
105 $phrase = getpass
("Enter passphrase: ") while ( ! $phrase );
107 if ( unix_md5_crypt
($phrase, $phrase_hash) ne $phrase_hash ) {
108 print STDERR
"error: invalid passphrase\n";
115 my ($dupl_user) = @_;
117 print STDERR
"error: $PASSWDFILE does not exist, use --create\n"
118 and exit if ( ! -e
$PASSWDFILE );
120 my $passwd = Config
::Tiny
->read($PASSWDFILE);
123 my ($id, $pwd) = lookup_login
($passwd, $dupl_user);
124 print STDERR
qq/error: login with the "$dupl_user" /
125 . "username exists already\n" and exit if $pwd;
128 my $phrase = verify_phrase
($passwd->{_
}->{phrase
});
129 my $key = md5_hex
($phrase);
131 return ($key, $passwd);
140 chomp(my $passwd = <STDIN
>);
150 my ($key, $passwd, $user) = @_;
153 $pwd = getpass
("Enter password for $user: ") while ( ! $pwd );
154 $again = getpass
("Re-enter the password: ") while ( ! $again );
156 print STDERR
"error: passwords did not match\n" and exit
157 unless $pwd eq $again;
159 my $c = Crypt
::Twofish2
->new($key, Crypt
::Twofish2
::MODE_CBC
);
161 $passwd->{login
}->{$user} =
162 encode_base64
( $c->encrypt( pack('a16',$pwd) ) );
164 $passwd->write($PASSWDFILE);
168 my ($key, $passwd) = get_key
($opts{add
});
169 new_login
($key, $passwd, $opts{add
});
173 my ($key, $passwd) = get_key
();
174 my ($id, $pwd) = lookup_login
($passwd, $opts{edit
});
176 print STDERR
qq/error: no such login with the "$opts{edit}" /
177 . "username exists\n" and exit unless $pwd;
179 print "WARN: Changing password for the login "
180 . qq/with the username "$id".\n/;
182 new_login
($key, $passwd, $id);
186 my ($key, $passwd) = get_key
();
187 my ($id, $pwd) = lookup_login
($passwd, $opts{get
});
189 print STDERR
qq/error: no such login with the "$opts{get}" /
190 . "username exists\n" and exit unless $pwd;
192 my $c = Crypt
::Twofish2
->new($key, Crypt
::Twofish2
::MODE_CBC
);
193 print "login: " .$opts{get
}."=". $c->decrypt(decode_base64
($pwd)) ."\n";
197 my ($key, $passwd) = get_key
();
198 my ($id, $pwd) = lookup_login
($passwd, $opts{delete});
200 print STDERR
qq/error: no such login with the "$opts{delete}" /
201 . "username exists\n" and exit unless $pwd;
203 print "WARN: About to delete the login with the username "
204 . qq/"$id".\n/ ."> Confirm delete (y/N): ";
206 chomp(my $confirm = <STDIN
>);
207 exit unless $confirm eq "y";
209 delete $passwd->{login
}->{$id};
210 $passwd->write($PASSWDFILE);
214 my ($passwd, $user) = @_;
216 foreach ( $passwd->{login
} ) {
217 while ( my ($id, $pwd) = each(%{$_}) ) {
218 if ( $id eq $user ) {
226 my $perl_v = sprintf "%vd", $^V
;
228 "clivepass version $VERSION. Copyright (C) 2008 Toni Gundogdu.
232 * Crypt::PasswdMD5/$Crypt::PasswdMD5::VERSION\t* Crypt::Twofish2/$Crypt::Twofish2::VERSION
233 * Crypt::Salt/$Crypt::Salt::VERSION\t\t* Config::Tiny/$Config::Tiny::VERSION
236 * Getopt::Long/$Getopt::Long::VERSION\t\t* Encode/$Encode::VERSION
237 * File::Spec/$File::Spec::VERSION\t\t* File::Find/$File::Find::VERSION
238 * Pod::Usage/$Pod::Usage::VERSION\t\t* Digest::MD5/$Digest::MD5::VERSION
239 * MIME::Base64/$MIME::Base64::VERSION
241 This program comes with ABSOLUTELY NO WARRANTY. You may redistribute copies of
242 clivepass under the terms of the GNU General Public License as published by the
243 Free Software Foundation, either version 3 of the License, or (at your option)
244 any later version. You should have received a copy of the General Public License
245 along with this program. If not, see http://www.gnu.org/licenses/.
253 clivepass - the login password utility for clive
257 clivepass [option]...
261 clivepass is an utility that can be used to create and change passwords
262 for websites used by L<clive(1)>. The passwords are encrypted and saved
263 along with the username information. Access is restricted by using a
266 Historically, a similar utility, clive-passwd, was part of clive 1.x but
267 was written in Python instead of Perl.
279 =item B<-v --version>
281 Show version and exit.
285 Create a new passwd file. See also L</FILES>.
287 =item B<-a --add=>I<username>
289 Add a new login with the I<username>.
291 =item B<-e --edit=>I<username>
293 Change login password for I<username>.
295 =item B<-g --get=>I<username>
297 Print the decrypted login password for the I<username>
300 =item B<-d --delete=>I<username>
302 Delete the login with the I<username>.
310 =item % clivepass -a myusername
312 =item % clivepass -g myusername
318 By default, clivepass searches the ~/.config/clivepass directory for the
319 password file. The B<CLIVEPASS_CONFIGDIR> environment variable can be used
320 to override this behaviour.
324 =item ~/.config/clivepass/passwd
326 Password file. Contains the salted passphrase hash and login usernames and
331 L<clive(1)> L<clivescan(1)> L<clivefeed(1)>
335 Project: http://googlecode.com/p/clive-utils/
337 A clive-utils development repository can be obtained from:
339 % git clone git://repo.or.cz/clive-utils.git
345 Written by Toni Gundogdu <legatvs@gmail.com>