# password store management tool
-# Copyright (c) 2008 Peter Palfrader <peter@palfrader.org>
+# Copyright (c) 2008, 2009 Peter Palfrader <peter@palfrader.org>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
STDIN.reopen(inR)
STDOUT.reopen(outW)
STDERR.reopen(errW)
- exec(GNUPG, "--status-fd=#{statW.fileno}", *args)
+ begin
+ exec(GNUPG, "--status-fd=#{statW.fileno}", *args)
+ rescue Exception => e
+ outW.puts("[PWSEXECERROR]: #{e}")
+ exit(1)
+ end
raise ("Calling gnupg failed")
end
inR.close
throw "Unexpected pid: #{pid} vs #{wpid}" unless pid == wpid
throw "Process has not exited!?" unless status.exited?
throw "gpg call did not exit sucessfully" if (require_success and status.exitstatus != 0)
+ if m=/^\[PWSEXECERROR\]: (.*)/.match(outtxt) then
+ STDERR.puts "Could not run GnuPG: #{m[1]}"
+ exit(1)
+ end
return outtxt, stderrtxt, statustxt, status.exitstatus
end
while true
print "#{query} #{append} "
- i = STDIN.readline.chomp.downcase
+ begin
+ i = STDIN.readline.chomp.downcase
+ rescue EOFError
+ return default_yes
+ end
if i==""
return default_yes
elsif i=="y"
trusted.push line
end
- (outtxt, stderrtxt, statustxt, exitstatus) = GnuPG.gpgcall(content, %w{}, true)
+ (outtxt, stderrtxt, statustxt, exitstatus) = GnuPG.gpgcall(content, %w{})
goodsig = false
validsig = nil
statustxt.split("\n").each do |line|
end
if not goodsig
- STDERR.puts ".users file is not signed properly"
+ STDERR.puts ".users file is not signed properly. GnuPG said on stdout:"
+ STDERR.puts outtxt
+ STDERR.puts "and on stderr:"
+ STDERR.puts stderrtxt
+ STDERR.puts "and via statusfd:"
+ STDERR.puts statustxt
exit(1)
end
exit(1)
end
+ if not exitstatus==0
+ STDERR.puts "gpg verify failed for .users file"
+ exit(1)
+ end
+
return outtxt
end
group['keys'] = [] unless group['keys']
still_contains_groups = false
- group['members_to_do'].each do |member|
+ group['members_to_do'].clone.each do |member|
if is_group(member)
if @groups[member]['members_to_do'].size == 0
group['keys'].concat @groups[member]['keys']
end
return ok, fprs.uniq
end
+
+ def get_users()
+ return @users
+ end
end
class EncryptedFile
end
@accessible = true
@encrypted_content = File.read(filename)
- (outtxt, stderrtxt, statustxt) = GnuPG.gpgcall(@encrypted_content, %w{--with-colons --no-default-keyring --secret-keyring=/dev/null --keyring=/dev/null})
+ (outtxt, stderrtxt, statustxt) = GnuPG.gpgcall(@encrypted_content, %w{--with-colons --no-options --no-default-keyring --secret-keyring=/dev/null --keyring=/dev/null})
@encrypted = !(statustxt =~ /\[GNUPG:\] NODATA/)
if @encrypted
@readers = EncryptedFile.list_readers(statustxt)
def encrypt(content, recipients)
args = recipients.collect{ |r| "--recipient=#{r}"}
args.push "--trust-model=always"
+ args.push "--keyring=./.keyring" if FileTest.exists?(".keyring")
+ args.push "--armor"
args.push "--encrypt"
(outtxt, stderrtxt, statustxt, exitstatus) = GnuPG.gpgcall(content, args)
proceed = read_input("Warning: Editor did not exit successfully (exit code #{status.exitstatus}. Proceed?")
exit(0) unless proceed
end
- tempfile.seek(0, IO::SEEK_SET)
- content = tempfile.read
- # zero the file
+ # some editors do not write new content in place, but instead
+ # make a new file and more it in the old file's place.
+ begin
+ reopened = File.open(tempfile.path, "r+")
+ rescue Exception => e
+ STDERR.puts e
+ exit(1)
+ end
+ content = reopened.read
+
+ # zero the file, well, both of them.
newsize = content.length
- tempfile.seek(0, IO::SEEK_SET)
clearsize = (newsize > oldsize) ? newsize : oldsize
- tempfile.print "\0"*clearsize
- tempfile.fsync
+
+ [tempfile, reopened].each do |f|
+ f.seek(0, IO::SEEK_SET)
+ f.print "\0"*clearsize
+ f.fsync
+ end
+ reopened.close
tempfile.close(true)
if content.length == 0
def initialize()
ARGV.options do |opts|
opts.on_tail("-h", "--help" , "Display this help screen") { help(opts) }
- opts.on_tail("-n", "--new" , "Edit new file") { |@new| }
- opts.on_tail("-f", "--force" , "Spawn an editor even if the file is probably not readable") { |@force| }
+ opts.on_tail("-n", "--new" , "Edit new file") { |new| @new=new }
+ opts.on_tail("-f", "--force" , "Spawn an editor even if the file is probably not readable") { |force| @force=force }
opts.parse!
end
help(ARGV.options, 1, STDERR) if ARGV.length != 1
end
end
+class KeyringUpdater
+ def help(parser, code=0, io=STDOUT)
+ io.puts "Usage: #{$program_name} update-keyring [<keyserver>]"
+ io.puts parser.summarize
+ io.puts "Updates the local .keyring file"
+ exit(code)
+ end
+
+ def initialize()
+ ARGV.options do |opts|
+ opts.on_tail("-h", "--help" , "Display this help screen") { help(opts) }
+ opts.parse!
+ end
+ help(ARGV.options, 1, STDERR) if ARGV.length > 1
+ keyserver = ARGV.shift
+ keyserver = 'keys.gnupg.net' unless keyserver
+
+ groupconfig = GroupConfig.new
+ users = groupconfig.get_users()
+ args = %w{--with-colons --no-options --no-default-keyring --keyring=./.keyring}
+
+ system('touch', '.keyring')
+ users.each_pair() do |uid, keyid|
+ cmd = args.clone()
+ cmd << "--keyserver=#{keyserver}"
+ cmd << "--recv-keys"
+ cmd << keyid
+ puts "Fetching key for #{uid}"
+ (outtxt, stderrtxt, statustxt) = GnuPG.gpgcall('', cmd)
+ unless (statustxt =~ /^\[GNUPG:\] IMPORT_OK /)
+ STDERR.puts "Warning: did not find IMPORT_OK token in status output"
+ STDERR.puts "gpg exited with exit code #{ecode})"
+ STDERR.puts "Command was gpg #{cmd.join(' ')}"
+ STDERR.puts "stdout was #{outtxt}"
+ STDERR.puts "stderr was #{stderrtxt}"
+ STDERR.puts "statustxt was #{statustxt}"
+ end
+
+ cmd = args.clone()
+ cmd << '--batch' << '--edit' << keyid << 'minimize' << 'save'
+ (outtxt, stderrtxt, statustxt, ecode) = GnuPG.gpgcall('', cmd)
+ end
+
+
+ end
+end
def help(code=0, io=STDOUT)
io.puts "Usage: #{$program_name} ed"
io.puts " #{$program_name} ls"
+ io.puts " #{$program_name} update-keyring"
io.puts " #{$program_name} help"
io.puts "Call #{$program_name} <command> --help for additional options/parameters"
exit(code)
def parse_command
case ARGV.shift
- when 'ls': Ls.new
- when 'ed': Ed.new
- when 'help':
+ when 'ls' then Ls.new
+ when 'ed' then Ed.new
+ when 'update-keyring' then KeyringUpdater.new
+ when 'help' then
case ARGV.length
- when 0: help
- when 1:
+ when 0 then help
+ when 1 then
ARGV.push "--help"
parse_command
else help(1, STDERR)