#!/usr/bin/env ruby # -*- ruby -*- # Author: William (B.J.) Snow Orvis # # == Synopsis # getpassword: Queries the Apple Keychain for Internet passwords using the # `security' command. Also uses a lockfile, to ensure that Keychain does not # prompt for unlocking the same keychain multiple times. # # requires the lockfile ruby gem. # # == Usage # # getpassword [OPTIONS] # # --help, -h: # show help # # --debug, -d: # show the actual security command to be run. # # --getpass, -p: # return the password for the given account # # --account name, -a name: # find password item with account named name # # --server name, -s name: # find password item with server named name require 'getoptlong' require 'rdoc/usage' require 'rubygems' gem 'lockfile', '>=1.3' require 'lockfile' SECURITY = '/usr/bin/security' COMMAND = 'find-internet-password' opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--getpass', '-p', GetoptLong::NO_ARGUMENT ], [ '--account', '-a', GetoptLong::REQUIRED_ARGUMENT ], [ '--server', '-s', GetoptLong::REQUIRED_ARGUMENT ], [ '--debug', '-d', GetoptLong::NO_ARGUMENT ] ) getpass = false debug = false account = nil server = nil opts.each do |opt, arg| case opt when '--help' RDoc::usage('Synopsis','Usage') when '--getpass' getpass = true if debug then $stderr.puts "--getpass" end when '--account' account = arg if debug then $stderr.puts "--account #{arg}" end when '--server' server = arg if debug then $stderr.puts "--server #{arg}" end when '--debug' debug = true if debug then $stderr.puts "--debug" end end end newargs = "#{(account!=nil ? "-a #{account}":'')} #{(server!=nil ? "-s #{server}":'')}" if getpass == true # get the password onto STDOUT instead of STDERR, and disregard the # normal output. seccmd = "#{SECURITY} #{COMMAND} -g #{newargs} 2>&1 1>/dev/null" else seccmd = "#{SECURITY} #{COMMAND} #{newargs}" end if debug == true $stderr.puts seccmd end if getpass == true tmpdir = ENV['TMPDIR'] if tmpdir == nil tmpdir = '/tmp' end uid = Process.uid lockfile = Lockfile.new("#{tmpdir}/getpassword.#{uid}.lock", :timeout => 60, :max_age => 8, :refresh => 2, :debug => false) lockfile.lock do print `#{seccmd}`.sub(/password: "(.*)"/,'\1') end else puts `#{seccmd}` end