/[gentoo-src]/keychain/keychain.sh
Gentoo

Contents of /keychain/keychain.sh

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.22 - (show annotations) (download) (as text)
Thu May 12 01:39:43 2005 UTC (9 years, 3 months ago) by agriffis
Branch: MAIN
CVS Tags: HEAD
Changes since 1.21: +9 -8 lines
File MIME type: text/x-sh
keychain-2.5.4.1:
- A minor bug in 2.5.4 resulted in always exiting with non-zero status.  Change
  back to the correct behavior of zero for success, non-zero for failure

1 #!/bin/sh
2 # Copyright 1999-2005 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4 # Originally authored by Daniel Robbins <drobbins@gentoo.org>
5 # Maintained August 2002 - April 2003 by Seth Chandler <sethbc@gentoo.org>
6 # Maintained April 2004 - present by Aron Griffis <agriffis@gentoo.org>
7 # $Header: /var/cvsroot/gentoo-src/keychain/keychain.sh,v 1.21 2005/05/11 23:45:35 agriffis Exp $
8
9 version=2.5.4.1
10
11 PATH="/usr/bin:/bin:/sbin:/usr/sbin:/usr/ucb:${PATH}"
12
13 maintainer="agriffis@gentoo.org"
14 zero=`basename "$0"`
15 unset mesglog
16 unset myaction
17 unset agentsopt
18 havelock=false
19 unset hostopt
20 ignoreopt=false
21 noaskopt=false
22 noguiopt=false
23 nolockopt=false
24 lockwait=30
25 openssh=unknown
26 sunssh=unknown
27 quickopt=false
28 quietopt=false
29 clearopt=false
30 inheritwhich=local-once
31 unset stopwhich
32 unset timeout
33 attempts=1
34 unset sshavail
35 unset sshkeys
36 unset gpgkeys
37 unset mykeys
38 keydir="${HOME}/.keychain"
39
40 BLUE=""
41 CYAN=""
42 GREEN=""
43 RED=""
44 OFF=""
45
46 # GNU awk and sed have regex issues in a multibyte environment. If any locale
47 # variables are set, then override by setting LC_ALL
48 lvars=`locale 2>/dev/null | egrep -v '="?(|POSIX|C)"?$' 2>/dev/null`
49 if [ -n "$lvars$LANG$LC_ALL" ]; then
50 LC_ALL=C
51 export LC_ALL
52 fi
53
54 # synopsis: qprint "message"
55 qprint() {
56 $quietopt || echo "$*" >&2
57 }
58
59 # synopsis: mesg "message"
60 # Prettily print something to stderr, honors quietopt
61 mesg() {
62 qprint " ${GREEN}*${OFF} $*"
63 }
64
65 # synopsis: warn "message"
66 # Prettily print a warning to stderr
67 warn() {
68 echo " ${RED}* Warning${OFF}: $*" >&2
69 }
70
71 # synopsis: error "message"
72 # Prettily print an error
73 error() {
74 echo " ${RED}* Error${OFF}: $*" >&2
75 }
76
77 # synopsis: die "message"
78 # Prettily print an error, then abort
79 die() {
80 [ -n "$1" ] && error "$*"
81 qprint
82 exit 1
83 }
84
85 # synopsis: versinfo
86 # Display the version information
87 versinfo() {
88 qprint
89 qprint "${GREEN}KeyChain ${version}; ${BLUE}http://www.gentoo.org/proj/en/keychain/${OFF}"
90 qprint "Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL"
91 qprint
92 }
93
94 # synopsis: helpinfo
95 # Display the help information. There's no really good way to use qprint for
96 # this...
97 helpinfo() {
98 cat >&2 <<EOHELP
99 INSERT_POD_OUTPUT_HERE
100 EOHELP
101 }
102
103 # synopsis: testssh
104 # Figure out which ssh is in use, set the global boolean $openssh and $sunssh
105 testssh() {
106 # Query local host for SSH application, presently supporting
107 # OpenSSH, Sun SSH, and ssh.com
108 openssh=false
109 sunssh=false
110 case "`ssh -V 2>&1`" in
111 *OpenSSH*) openssh=true ;;
112 *Sun?SSH*) sunssh=true ;;
113 esac
114 }
115
116 # synopsis: getuser
117 # Set the global string $me
118 getuser() {
119 # whoami gives euid, which might be different from USER or LOGNAME
120 me=`whoami` || die "Who are you? whoami doesn't know..."
121 }
122
123 # synopsis: getos
124 # Set the global string $OSTYPE
125 getos() {
126 OSTYPE=`uname` || die 'uname failed'
127 }
128
129 # synopsis: verifykeydir
130 # Make sure the key dir is set up correctly. Exits on error.
131 verifykeydir() {
132 # Create keydir if it doesn't exist already
133 if [ -f "${keydir}" ]; then
134 die "${keydir} is a file (it should be a directory)"
135 # Solaris 9 doesn't have -e; using -d....
136 elif [ ! -d "${keydir}" ]; then
137 ( umask 0077 && mkdir "${keydir}"; ) || die "can't create ${keydir}"
138 fi
139 }
140
141 # synopsis: now previous_now
142 # Returns some seconds value on stdout, for timing things. Accepts a
143 # previous_now parameter which should be the last value returned. (No data can
144 # be persistent because this is called from a subshell.) If this is called less
145 # than once per minute on a non-GNU system then it might skip a minute.
146 now() {
147 if [ -n "$BASH_VERSION" -a "$SECONDS" -ge 0 ] 2>/dev/null; then
148 echo $SECONDS
149 return 0
150 fi
151
152 if now_seconds=`date +%s 2>/dev/null` \
153 && [ "$now_seconds" -gt 0 ] 2>/dev/null; then
154 if [ $now_seconds -lt "$1" ] 2>/dev/null; then
155 warn "time went backwards, taking countermeasures"
156 echo `expr $1 + 1`
157 else
158 echo $now_seconds
159 fi
160 return 0
161 fi
162
163 # Don't use awk -F'[: ]' here because Solaris awk can't handle it, a regex
164 # field separator needs gawk or nawk. It's easier to simply avoid awk in
165 # this case.
166 if now_seconds=`LC_ALL=C date 2>/dev/null | sed 's/:/ /g' | xargs | cut -d' ' -f6` \
167 && [ "$now_seconds" -ge 0 ] 2>/dev/null; then
168 if [ -n "$1" ]; then
169 # how many minutes have passed previously?
170 now_mult=`expr $1 / 60`
171 if [ "$now_seconds" -lt `expr $1 % 60` ]; then
172 # another minute has passed
173 now_mult=`expr $now_mult + 1`
174 fi
175 # accumulate minutes in now_seconds
176 now_seconds=`expr 60 \* $now_mult + $now_seconds`
177 fi
178 echo $now_seconds
179 return 0
180 fi
181
182 return 1
183 }
184
185 # synopsis: takelock
186 # Attempts to get the lockfile $lockf. If locking isn't available, just returns.
187 # If locking is available but can't get the lock, exits with error.
188 takelock() {
189 # Check if we already have the lock. Since this is not a threaded prog,
190 # using this global is safe
191 $havelock && return 0
192
193 # Honor --nolock
194 if $nolockopt; then
195 unset lockf
196 return 0
197 fi
198
199 # Check for old-style lock; unlikely.
200 # Redirect stderr since -h might not be implemented, in which case we
201 # blunder ahead.
202 if [ -h "$olockf" ] 2>/dev/null; then
203 error "please remove old-style lock: $olockf"
204 return 1
205 fi
206
207 # Catch the case that an existing lockfile might, for some strange reason,
208 # have the wrong permissions
209 chmod 0400 "$lockf" 2>/dev/null
210
211 tl_faking=false
212 tl_emptyonce=false
213 unset tl_oldpid tl_lastmesg
214
215 # Set up timer
216 if [ $lockwait -eq 0 ]; then
217 true # don't bother to set tl_start, tl_end, tl_current
218 elif tl_start=`now`; then
219 tl_end=`expr $tl_start + $lockwait`
220 tl_current=$tl_start
221 else
222 # we'll fake it the best we can
223 tl_faking=true
224 tl_start=0
225 tl_end=`expr $lockwait \* 10`
226 tl_current=0
227 fi
228 tl_nextmesg=$tl_current
229
230 # Try to lock for $lockwait seconds
231 while [ $lockwait -eq 0 -o $tl_current -lt $tl_end ]; do
232
233 if tl_error=`umask 0377; echo $$ 2>&1 >"$lockf"`; then
234 havelock=true
235 return 0
236 fi
237
238 # advance our timer
239 if [ $lockwait -gt 0 ]; then
240 if $tl_faking; then
241 tl_current=`expr $tl_current + 1`
242 else
243 tl_current=`now $tl_current`
244 fi
245 fi
246
247 # read the lock
248 tl_pid=`cat "$lockf" 2>/dev/null`
249
250 if [ -n "$tl_pid" ]; then
251 # test for a stale lock
252 kill -0 "$tl_pid" 2>/dev/null
253 if [ $? != 0 ]; then
254 # Avoid a race condition; another keychain might have started at
255 # this point. If the pid is the same as the last time we
256 # checked, then go ahead and remove the stale lock. Otherwise
257 # remember the pid and try again.
258 if [ "$tl_pid" = "$tl_oldpid" ]; then
259 warn "removing stale lock for pid $tl_pid"
260 rm -f "$lockf"
261 else
262 tl_oldpid="$tl_pid"
263 fi
264 # try try again, no sleep required
265 continue
266 fi
267
268 # don't keep the user in suspense
269 if [ $lockwait -gt 0 ]; then
270 if [ $tl_current -eq $tl_nextmesg ]; then
271 tl_timeleft=`expr $tl_end - $tl_current`
272 if [ $tl_timeleft -gt 0 ]; then
273 mesg "Waiting $tl_timeleft seconds for lock, held by pid $tl_pid"
274 fi
275 tl_nextmesg=`expr $tl_current + 1`
276 fi
277 fi
278
279 # nb: fall through to sleep...
280
281 else # tl_pid is blank
282 if $tl_emptyonce; then
283 warn "removing empty lock file"
284 rm -f "$lockf"
285 tl_emptyonce=false
286 # give this another go-around, no sleep required
287 continue
288 fi
289 tl_emptyonce=true
290 # fall through to sleep
291 fi
292
293 # sleep for a bit to wait for the keychain process holding the lock
294 sleep 0.1 >/dev/null 2>&1 && continue
295 perl -e 'select(undef, undef, undef, 0.1)' \
296 >/dev/null 2>&1 && continue
297 # adjust granularity of tl_current stepping
298 $tl_faking && tl_current=`expr $tl_current + 9`
299 sleep 1
300 done
301
302 # no luck
303 [ -n "$tl_pid" ] || unset tl_pid # ${var+...} relies on set vs. unset
304 error "failed to get the lock${tl_pid+, held by pid $tl_pid}: $tl_error"
305 return 1
306 }
307
308 # synopsis: droplock
309 # Drops the lock if we're holding it.
310 droplock() {
311 $havelock && [ -n "$lockf" ] && rm -f "$lockf"
312 }
313
314 # synopsis: findpids [prog]
315 # Returns a space-separated list of agent pids.
316 # prog can be ssh or gpg, defaults to ssh. Note that if another prog is ever
317 # added, need to pay attention to the length for Solaris compatibility.
318 findpids() {
319 fp_prog=${1-ssh}
320 unset fp_psout
321
322 # Different systems require different invocations of ps. Try to generalize
323 # the best we can. The only requirement is that the agent command name
324 # appears in the line, and the PID is the first item on the line.
325 [ -n "$OSTYPE" ] || getos
326
327 # Try systems where we know what to do first
328 case "$OSTYPE" in
329 AIX|*bsd*|*BSD*|CYGWIN|darwin*|Linux|OSF1)
330 fp_psout=`ps x 2>/dev/null` ;; # BSD syntax
331 HP-UX)
332 fp_psout=`ps -u $me 2>/dev/null` ;; # SysV syntax
333 SunOS)
334 case `uname -r` in
335 [56]*)
336 fp_psout=`ps -u $me 2>/dev/null` ;; # SysV syntax
337 *)
338 fp_psout=`ps x 2>/dev/null` ;; # BSD syntax
339 esac ;;
340 esac
341
342 # If we didn't get a match above, try a list of possibilities...
343 # The first one will probably fail on systems supporting only BSD syntax.
344 if [ -z "$fp_psout" ]; then
345 fp_psout=`UNIX95=1 ps -u $me -o pid,comm 2>/dev/null | grep '^ *[0-9]'`
346 [ -z "$fp_psout" ] && fp_psout=`ps x 2>/dev/null`
347 fi
348
349 # Return the list of pids; ignore case for Cygwin.
350 # Check only 8 characters since Solaris truncates at that length.
351 # Ignore defunct ssh-agents (bug 28599)
352 if [ -n "$fp_psout" ]; then
353 echo "$fp_psout" | \
354 awk "BEGIN{IGNORECASE=1} /defunct/{next}
355 /$fp_prog-[a]gen/{print \$1}" | xargs
356 return 0
357 fi
358
359 # If none worked, we're stuck
360 error "Unable to use \"ps\" to scan for $fp_prog-agent processes"
361 error "Please report to $maintainer via http://bugs.gentoo.org"
362 return 1
363 }
364
365 # synopsis: stopagent [prog]
366 # --stop tells keychain to kill the existing agent(s)
367 # prog can be ssh or gpg, defaults to ssh.
368 stopagent() {
369 stop_prog=${1-ssh}
370 eval stop_except=\$\{${stop_prog}_agent_pid\}
371 stop_mypids=`findpids "$stop_prog"`
372 [ $? = 0 ] || die
373
374 if [ -z "$stop_mypids" ]; then
375 mesg "No $stop_prog-agent(s) found running"
376 return 0
377 fi
378
379 case "$stopwhich" in
380 all)
381 kill $stop_mypids >/dev/null 2>&1
382 mesg "All $me's $stop_prog-agent(s) ($stop_mypids) are now stopped"
383 ;;
384
385 others)
386 # Try to handle the case where we *will* inherit a pid
387 kill -0 $stop_except >/dev/null 2>&1
388 if [ -z "$stop_except" -o $? != 0 -o \
389 "$inheritwhich" = local -o "$inheritwhich" = any ]; then
390 if [ "$inheritwhich" != none ]; then
391 eval stop_except=\$\{inherit_${stop_prog}_agent_pid\}
392 kill -0 $stop_except >/dev/null 2>&1
393 if [ -z "$stop_except" -o $? != 0 ]; then
394 # Handle ssh2
395 eval stop_except=\$\{inherit_${stop_prog}2_agent_pid\}
396 fi
397 fi
398 fi
399
400 # Filter out the running agent pid
401 unset stop_mynewpids
402 for stop_x in $stop_mypids; do
403 [ $stop_x -eq $stop_except ] 2>/dev/null && continue
404 stop_mynewpids="${stop_mynewpids+$stop_mynewpids }$stop_x"
405 done
406
407 if [ -n "$stop_mynewpids" ]; then
408 kill $stop_mynewpids >/dev/null 2>&1
409 mesg "Other $me's $stop_prog-agent(s) ($stop_mynewpids) are now stopped"
410 else
411 mesg "No other $stop_prog-agent(s) than keychain's $stop_except found running"
412 fi
413 ;;
414
415 mine)
416 if [ $stop_except -gt 0 ] 2>/dev/null; then
417 kill $stop_except >/dev/null 2>&1
418 mesg "Keychain $stop_prog-agent $stop_except is now stopped"
419 else
420 mesg "No keychain $stop_prog-agent found running"
421 fi
422 ;;
423 esac
424
425 # remove pid files if keychain-controlled
426 if [ "$stopwhich" != others ]; then
427 if [ "$stop_prog" != ssh ]; then
428 rm -f "${pidf}-$stop_prog" "${cshpidf}-$stop_prog" 2>/dev/null
429 else
430 rm -f "${pidf}" "${cshpidf}" 2>/dev/null
431 fi
432
433 eval unset ${stop_prog}_agent_pid
434 fi
435 }
436
437 # synopsis: inheritagents
438 # Save agent variables from the environment before they get wiped out
439 inheritagents() {
440 # Verify these global vars are null
441 unset inherit_ssh_auth_sock inherit_ssh_agent_pid
442 unset inherit_ssh2_auth_sock inherit_ssh2_agent_sock
443 unset inherit_gpg_agent_info inherit_gpg_agent_pid
444
445 # Save variables so we can inherit a running agent
446 if [ "$inheritwhich" != none ]; then
447 if wantagent ssh; then
448 if [ -n "$SSH_AUTH_SOCK" ]; then
449 if ls "$SSH_AUTH_SOCK" >/dev/null 2>&1; then
450 inherit_ssh_auth_sock="$SSH_AUTH_SOCK"
451 inherit_ssh_agent_pid="$SSH_AGENT_PID"
452 else
453 warn "SSH_AUTH_SOCK in environment is invalid; ignoring it"
454 fi
455 fi
456
457 if [ -z "$inherit_ssh_auth_sock" -a -n "$SSH2_AUTH_SOCK" ]; then
458 if ls "$SSH2_AUTH_SOCK" >/dev/null 2>&1; then
459 inherit_ssh2_auth_sock="$SSH2_AUTH_SOCK"
460 inherit_ssh2_agent_pid="$SSH2_AGENT_PID"
461 else
462 warn "SSH2_AUTH_SOCK in environment is invalid; ignoring it"
463 fi
464 fi
465 fi
466
467 if wantagent gpg; then
468 if [ -n "$GPG_AGENT_INFO" ]; then
469 la_IFS="$IFS" # save current IFS
470 IFS=':' # set IFS to colon to separate PATH
471 set -- $GPG_AGENT_INFO
472 IFS="$la_IFS" # restore IFS
473 if kill -0 "$2" >/dev/null 2>&1; then
474 inherit_gpg_agent_pid="$2"
475 inherit_gpg_agent_info="$GPG_AGENT_INFO"
476 else
477 warn "GPG_AGENT_INFO in environment is invalid; ignoring it"
478 fi
479 fi
480 fi
481 fi
482 }
483
484 # synopsis: loadagents
485 # Load agent variables from $pidf and copy implementation-specific environment
486 # variables into generic global strings
487 loadagents() {
488 unset SSH_AUTH_SOCK SSH_AGENT_PID SSH2_AUTH_SOCK SSH2_AGENT_PID
489 unset GPG_AGENT_INFO # too bad we have to do this explicitly
490
491 # Load agent pid files
492 for ql_x in "$pidf" "$pidf"-*; do
493 # Ignore some backup files
494 case "$ql_x" in
495 *~|*.bak) continue ;;
496 esac
497 [ -f "$ql_x" ] && . "$ql_x"
498 done
499
500 # Copy implementation-specific environment variables into generic local
501 # variables.
502 if [ -n "$SSH_AUTH_SOCK" ]; then
503 ssh_auth_sock=$SSH_AUTH_SOCK
504 ssh_agent_pid=$SSH_AGENT_PID
505 elif [ -n "$SSH2_AUTH_SOCK" ]; then
506 ssh_auth_sock=$SSH2_AUTH_SOCK
507 ssh_agent_pid=$SSH2_AGENT_PID
508 else
509 unset ssh_auth_sock ssh_agent_pid
510 fi
511
512 if [ -n "$GPG_AGENT_INFO" ]; then
513 la_IFS="$IFS" # save current IFS
514 IFS=':' # set IFS to colon to separate PATH
515 set -- $GPG_AGENT_INFO
516 IFS="$la_IFS" # restore IFS
517 gpg_agent_pid=$2
518 fi
519
520 return 0
521 }
522
523 # synopsis: startagent [prog]
524 # Starts an agent if it isn't already running.
525 # Requires $ssh_agent_pid
526 startagent() {
527 start_prog=${1-ssh}
528 unset start_pid
529 start_inherit_pid=none
530 start_mypids=`findpids "$start_prog"`
531 [ $? = 0 ] || die
532
533 # Unfortunately there isn't much way to genericize this without introducing
534 # a lot more supporting code/structures.
535 if [ "$start_prog" = ssh ]; then
536 start_pidf="$pidf"
537 start_cshpidf="$cshpidf"
538 start_pid="$ssh_agent_pid"
539 if [ -n "$inherit_ssh_auth_sock" -o -n "$inherit_ssh2_auth_sock" ]; then
540 if [ -n "$inherit_ssh_agent_pid" ]; then
541 start_inherit_pid="$inherit_ssh_agent_pid"
542 elif [ -n "$inherit_ssh2_agent_pid" ]; then
543 start_inherit_pid="$inherit_ssh2_agent_pid"
544 else
545 start_inherit_pid="forwarded"
546 fi
547 fi
548 else
549 start_pidf="${pidf}-$start_prog"
550 start_cshpidf="${cshpidf}-$start_prog"
551 if [ "$start_prog" = gpg ]; then
552 start_pid="$gpg_agent_pid"
553 if [ -n "$inherit_gpg_agent_pid" ]; then
554 start_inherit_pid="$inherit_gpg_agent_pid"
555 fi
556 else
557 error "I don't know how to start $start_prog-agent (1)"
558 return 1
559 fi
560 fi
561 [ "$start_pid" -gt 0 ] 2>/dev/null || start_pid=none
562
563 # This hack makes the case statement easier
564 if [ "$inheritwhich" = any -o "$inheritwhich" = any-once ]; then
565 start_fwdflg=forwarded
566 else
567 unset start_fwdflg
568 fi
569
570 # Check for an existing agent
571 case "$inheritwhich: $start_mypids $start_fwdflg " in
572 any:*" $start_inherit_pid "*|local:*" $start_inherit_pid "*)
573 mesg "Inheriting ${start_prog}-agent ($start_inherit_pid)"
574 ;;
575
576 none:*" $start_pid "*|*-once:*" $start_pid "*)
577 mesg "Found existing ${start_prog}-agent ($start_pid)"
578 return 0
579 ;;
580
581 *-once:*" $start_inherit_pid "*)
582 mesg "Inheriting ${start_prog}-agent ($start_inherit_pid)"
583 ;;
584
585 *)
586 # start_inherit_pid might be "forwarded" which we don't allow with,
587 # for example, local-once (the default setting)
588 start_inherit_pid=none
589 ;;
590 esac
591
592 # Init the bourne-formatted pidfile
593 mesg "Initializing $start_pidf file..."
594 ( umask 0177 && :> "$start_pidf"; )
595 if [ $? != 0 ]; then
596 rm -f "$start_pidf" "$start_cshpidf" 2>/dev/null
597 error "can't create $start_pidf"
598 return 1
599 fi
600
601 # Init the csh-formatted pidfile
602 mesg "Initializing $start_cshpidf file..."
603 ( umask 0177 && :> "$start_cshpidf"; )
604 if [ $? != 0 ]; then
605 rm -f "$start_pidf" "$start_cshpidf" 2>/dev/null
606 error "can't create $start_cshpidf"
607 return 1
608 fi
609
610 # Determine content for files
611 unset start_out
612 if [ "$start_inherit_pid" = none ]; then
613
614 # Start the agent.
615 # Branch again since the agents start differently
616 mesg "Starting ${start_prog}-agent"
617 if [ "$start_prog" = ssh ]; then
618 start_out=`ssh-agent`
619 elif [ "$start_prog" = gpg ]; then
620 if [ -n "${timeout}" ]; then
621 start_gpg_timeout="--default-cache-ttl `expr $timeout \* 60`"
622 else
623 unset start_gpg_timeout
624 fi
625 # the 1.9.x series of gpg spews debug on stderr
626 start_out=`gpg-agent --daemon $start_gpg_timeout 2>/dev/null`
627 else
628 error "I don't know how to start $start_prog-agent (2)"
629 return 1
630 fi
631 if [ $? != 0 ]; then
632 rm -f "$start_pidf" "$start_cshpidf" 2>/dev/null
633 error "Failed to start ${start_prog}-agent"
634 return 1
635 fi
636
637 elif [ "$start_prog" = ssh -a -n "$inherit_ssh_auth_sock" ]; then
638 start_out="SSH_AUTH_SOCK=$inherit_ssh_auth_sock; export SSH_AUTH_SOCK;"
639 if [ "$inherit_ssh_agent_pid" -gt 0 ] 2>/dev/null; then
640 start_out="$start_out
641 SSH_AGENT_PID=$inherit_ssh_agent_pid; export SSH_AGENT_PID;"
642 fi
643 elif [ "$start_prog" = ssh -a -n "$inherit_ssh2_auth_sock" ]; then
644 start_out="SSH2_AUTH_SOCK=$inherit_ssh2_auth_sock; export SSH2_AUTH_SOCK;
645 SSH2_AGENT_PID=$inherit_ssh2_agent_pid; export SSH2_AGENT_PID;"
646 if [ "$inherit_ssh2_agent_pid" -gt 0 ] 2>/dev/null; then
647 start_out="$start_out
648 SSH2_AGENT_PID=$inherit_ssh2_agent_pid; export SSH2_AGENT_PID;"
649 fi
650
651 elif [ "$start_prog" = gpg -a -n "$inherit_gpg_agent_info" ]; then
652 start_out="GPG_AGENT_INFO=$inherit_gpg_agent_info; export GPG_AGENT_INFO;"
653
654 else
655 die "something bad happened" # should never be here
656 fi
657
658 # Add content to pidfiles.
659 # Some versions of ssh-agent don't understand -s, which means to
660 # generate Bourne shell syntax. It appears they also ignore SHELL,
661 # according to http://bugs.gentoo.org/show_bug.cgi?id=52874
662 # So make no assumptions.
663 start_out=`echo "$start_out" | grep -v 'Agent pid'`
664 case "$start_out" in
665 setenv*)
666 echo "$start_out" >"$start_cshpidf"
667 echo "$start_out" | awk '{print $2"="$3" export "$2";"}' >"$start_pidf"
668 ;;
669 *)
670 echo "$start_out" >"$start_pidf"
671 echo "$start_out" | sed 's/;.*/;/' | sed 's/=/ /' | sed 's/^/setenv /' >"$start_cshpidf"
672 ;;
673 esac
674
675 # Hey the agent should be started now... load it up!
676 loadagents
677 }
678
679 # synopsis: extract_fingerprints
680 # Extract the fingerprints from standard input, returns space-separated list.
681 # Utility routine for ssh_l and ssh_f
682 extract_fingerprints() {
683 while read ef_line; do
684 case "$ef_line" in
685 *\ *\ [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:*)
686 # Sun SSH spits out different things depending on the type of
687 # key. For example:
688 # md5 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_dsa(DSA)
689 # 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_rsa.pub
690 echo "$ef_line" | cut -f3 -d' '
691 ;;
692 *\ [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:*)
693 # The more consistent OpenSSH format, we hope
694 # 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_dsa (DSA)
695 echo "$ef_line" | cut -f2 -d' '
696 ;;
697 *)
698 # Fall back to filename. Note that commercial ssh is handled
699 # explicitly in ssh_l and ssh_f, so hopefully this rule will
700 # never fire.
701 warn "Can't determine fingerprint from the following line, falling back to filename"
702 mesg "$ef_line"
703 basename "$ef_line" | sed 's/[ (].*//'
704 ;;
705 esac
706 done | xargs
707 }
708
709 # synopsis: ssh_l
710 # Return space-separated list of known fingerprints
711 ssh_l() {
712 sl_mylist=`ssh-add -l 2>/dev/null`
713 sl_retval=$?
714
715 if $openssh; then
716 # Error codes:
717 # 0 success
718 # 1 OpenSSH_3.8.1p1 on Linux: no identities (not an error)
719 # OpenSSH_3.0.2p1 on HP-UX: can't connect to auth agent
720 # 2 can't connect to auth agent
721 case $sl_retval in
722 0)
723 echo "$sl_mylist" | extract_fingerprints
724 ;;
725 1)
726 case "$sl_mylist" in
727 *"open a connection"*) sl_retval=2 ;;
728 esac
729 ;;
730 esac
731 return $sl_retval
732
733 elif $sunssh; then
734 # Error codes (from http://docs.sun.com/db/doc/817-3936/6mjgdbvio?a=view)
735 # 0 success (even when there are no keys)
736 # 1 error
737 case $sl_retval in
738 0)
739 echo "$sl_mylist" | extract_fingerprints
740 ;;
741 1)
742 case "$sl_mylist" in
743 *"open a connection"*) sl_retval=2 ;;
744 esac
745 ;;
746 esac
747 return $sl_retval
748
749 else
750 # Error codes:
751 # 0 success - however might say "The authorization agent has no keys."
752 # 1 can't connect to auth agent
753 # 2 bad passphrase
754 # 3 bad identity file
755 # 4 the agent does not have the requested identity
756 # 5 unspecified error
757 if [ $sl_retval = 0 ]; then
758 # Output of ssh-add -l:
759 # The authorization agent has one key:
760 # id_dsa_2048_a: 2048-bit dsa, agriffis@alpha.zk3.dec.com, Fri Jul 25 2003 10:53:49 -0400
761 # Since we don't have a fingerprint, just get the filenames *shrug*
762 echo "$sl_mylist" | sed '2,$s/:.*//' | xargs
763 fi
764 return $sl_retval
765 fi
766 }
767
768 # synopsis: ssh_f filename
769 # Return finger print for a keyfile
770 # Requires $openssh and $sunssh
771 ssh_f() {
772 sf_filename="$1"
773 if $openssh || $sunssh; then
774 if [ ! -f "$sf_filename.pub" ]; then
775 warn "$sf_filename.pub missing; can't tell if $sf_filename is loaded"
776 return 1
777 fi
778 sf_fing=`ssh-keygen -l -f "$sf_filename.pub"` || return 1
779 echo "$sf_fing" | extract_fingerprints
780 else
781 # can't get fingerprint for ssh2 so use filename *shrug*
782 basename "$sf_filename"
783 fi
784 return 0
785 }
786
787 # synopsis: gpg_listmissing
788 # Uses $gpgkeys
789 # Returns a newline-separated list of keys found to be missing.
790 gpg_listmissing() {
791 unset glm_missing
792
793 glm_disp="$DISPLAY"
794 unset DISPLAY
795
796 # Parse $gpgkeys into positional params to preserve spaces in filenames
797 set -f; # disable globbing
798 glm_IFS="$IFS" # save current IFS
799 IFS="
800 " # set IFS to newline
801 set -- $gpgkeys
802 IFS="$glm_IFS" # restore IFS
803 set +f # re-enable globbing
804
805 for glm_k in "$@"; do
806 # Check if this key is known to the agent. Don't know another way...
807 if echo | gpg --use-agent --no-tty --sign --local-user "$glm_k" -o - >/dev/null 2>&1; then
808 # already know about this key
809 mesg "Known gpg key: ${BLUE}${glm_k}${OFF}"
810 continue
811 else
812 # need to add this key
813 if [ -z "$glm_missing" ]; then
814 glm_missing="$glm_k"
815 else
816 glm_missing="$glm_missing
817 $glm_k"
818 fi
819 fi
820 done
821
822 [ -n "$glm_disp" ] && DISPLAY="$glm_disp"
823
824 echo "$glm_missing"
825 }
826
827 # synopsis: ssh_listmissing
828 # Uses $sshkeys and $sshavail
829 # Returns a newline-separated list of keys found to be missing.
830 ssh_listmissing() {
831 unset slm_missing
832
833 # Parse $sshkeys into positional params to preserve spaces in filenames
834 set -f; # disable globbing
835 slm_IFS="$IFS" # save current IFS
836 IFS="
837 " # set IFS to newline
838 set -- $sshkeys
839 IFS="$slm_IFS" # restore IFS
840 set +f # re-enable globbing
841
842 for slm_k in "$@"; do
843 # Fingerprint current user-specified key
844 slm_finger=`ssh_f "$slm_k"` || continue
845
846 # Check if it needs to be added
847 case " $sshavail " in
848 *" $slm_finger "*)
849 # already know about this key
850 mesg "Known ssh key: ${BLUE}${slm_k}${OFF}"
851 ;;
852 *)
853 # need to add this key
854 if [ -z "$slm_missing" ]; then
855 slm_missing="$slm_k"
856 else
857 slm_missing="$slm_missing
858 $slm_k"
859 fi
860 ;;
861 esac
862 done
863
864 echo "$slm_missing"
865 }
866
867 # synopsis: add_gpgkey
868 # Adds a key to $gpgkeys
869 add_gpgkey() {
870 gpgkeys=${gpgkeys+"$gpgkeys
871 "}"$1"
872 }
873
874 # synopsis: add_sshkey
875 # Adds a key to $sshkeys
876 add_sshkey() {
877 sshkeys=${sshkeys+"$sshkeys
878 "}"$1"
879 }
880
881 # synopsis: parse_mykeys
882 # Sets $sshkeys and $gpgkeys based on $mykeys
883 parse_mykeys() {
884 # Parse $mykeys into positional params to preserve spaces in filenames
885 set -f; # disable globbing
886 pm_IFS="$IFS" # save current IFS
887 IFS="
888 " # set IFS to newline
889 set -- $mykeys
890 IFS="$pm_IFS" # restore IFS
891 set +f # re-enable globbing
892
893 for pm_k in "$@"; do
894 # Check for ssh
895 if wantagent ssh; then
896 if [ -f "$pm_k" ]; then
897 add_sshkey "$pm_k" ; continue
898 elif [ -f "$HOME/.ssh/$pm_k" ]; then
899 add_sshkey "$HOME/.ssh/$pm_k" ; continue
900 elif [ -f "$HOME/.ssh2/$pm_k" ]; then
901 add_sshkey "$HOME/.ssh2/$pm_k" ; continue
902 fi
903 fi
904
905 # Check for gpg
906 if wantagent gpg; then
907 if [ -z "$pm_gpgsecrets" ]; then
908 pm_gpgsecrets="`gpg --list-secret-keys 2>/dev/null | cut -d/ -f2 | cut -d' ' -f1 | xargs`"
909 [ -z "$pm_gpgsecrets" ] && pm_gpgsecrets='/' # arbitrary
910 fi
911 case " $pm_gpgsecrets " in *" $pm_k "*)
912 add_gpgkey "$pm_k" ; continue ;;
913 esac
914 fi
915
916 $ignoreopt || warn "can't find $pm_k; skipping"
917 continue
918 done
919
920 return 0
921 }
922
923 # synopsis: setaction
924 # Sets $myaction or dies if $myaction is already set
925 setaction() {
926 if [ -n "$myaction" ]; then
927 die "you can't specify --$myaction and $1 at the same time"
928 else
929 myaction="$1"
930 fi
931 }
932
933 # synopsis: in_path
934 # Look for executables in the path
935 in_path() {
936 ip_lookfor="$1"
937
938 # Parse $PATH into positional params to preserve spaces
939 ip_IFS="$IFS" # save current IFS
940 IFS=':' # set IFS to colon to separate PATH
941 set -- $PATH
942 IFS="$ip_IFS" # restore IFS
943
944 for ip_x in "$@"; do
945 [ -x "$ip_x/$ip_lookfor" ] || continue
946 echo "$ip_x/$ip_lookfor"
947 return 0
948 done
949
950 return 1
951 }
952
953 # synopsis: setagents
954 # Check validity of agentsopt
955 setagents() {
956 if [ -n "$agentsopt" ]; then
957 agentsopt=`echo "$agentsopt" | sed 's/,/ /g'`
958 unset new_agentsopt
959 for a in $agentsopt; do
960 if in_path ${a}-agent >/dev/null; then
961 new_agentsopt="${new_agentsopt+$new_agentsopt }${a}"
962 else
963 warn "can't find ${a}-agent, removing from list"
964 fi
965 done
966 agentsopt="${new_agentsopt}"
967 else
968 for a in ssh gpg; do
969 in_path ${a}-agent >/dev/null || continue
970 agentsopt="${agentsopt+$agentsopt }${a}"
971 done
972 fi
973
974 if [ -z "$agentsopt" ]; then
975 die "no agents available to start"
976 fi
977 }
978
979 # synopsis: wantagent prog
980 # Return 0 (true) or 1 (false) depending on whether prog is one of the agents in
981 # agentsopt
982 wantagent() {
983 case "$agentsopt" in
984 "$1"|"$1 "*|*" $1 "*|*" $1")
985 return 0 ;;
986 *)
987 return 1 ;;
988 esac
989 }
990
991 #
992 # MAIN PROGRAM
993 #
994
995 # parse the command-line
996 while [ -n "$1" ]; do
997 case "$1" in
998 --help|-h)
999 setaction help
1000 ;;
1001 --stop|-k)
1002 # As of version 2.5, --stop takes an argument. For the sake of
1003 # backward compatibility, only eat the arg if it's one we recognize.
1004 if [ "$2" = mine ]; then
1005 stopwhich=mine; shift
1006 elif [ "$2" = others ]; then
1007 stopwhich=others; shift
1008 elif [ "$2" = all ]; then
1009 stopwhich=all; shift
1010 else
1011 # backward compat
1012 stopwhich=all-warn
1013 fi
1014 ;;
1015 --version|-V)
1016 setaction version
1017 ;;
1018 --agents)
1019 shift
1020 agentsopt="$1"
1021 ;;
1022 --attempts)
1023 shift
1024 if [ "$1" -gt 0 ] 2>/dev/null; then
1025 attempts=$1
1026 else
1027 die "--attempts requires a numeric argument greater than zero"
1028 fi
1029 ;;
1030 --dir)
1031 shift
1032 case "$1" in
1033 */.*) keydir="$1" ;;
1034 '') die "--dir requires an argument" ;;
1035 *) keydir="$1/.keychain" ;; # be backward-compatible
1036 esac
1037 ;;
1038 --clear)
1039 clearopt=true
1040 $quickopt && die "--quick and --clear are not compatible"
1041 ;;
1042 --host)
1043 shift
1044 hostopt="$1"
1045 ;;
1046 --ignore-missing)
1047 ignoreopt=true
1048 ;;
1049 --inherit)
1050 shift
1051 case "$1" in
1052 local|any|local-once|any-once)
1053 inheritwhich="$1"
1054 ;;
1055 *)
1056 die "--inherit requires an argument (local, any, local-once or any-once)"
1057 ;;
1058 esac
1059 ;;
1060 --noinherit)
1061 inheritwhich=none
1062 ;;
1063 --noask)
1064 noaskopt=true
1065 ;;
1066 --nogui)
1067 noguiopt=true
1068 ;;
1069 --nolock)
1070 nolockopt=true
1071 ;;
1072 --lockwait)
1073 shift
1074 if [ "$1" -ge 0 ] 2>/dev/null; then
1075 lockwait="$1"
1076 else
1077 die "--lockwait requires an argument 0 <= n <= 50"
1078 fi
1079 ;;
1080 --quick|-Q)
1081 quickopt=true
1082 $clearopt && die "--quick and --clear are not compatible"
1083 ;;
1084 --quiet|-q)
1085 quietopt=true
1086 ;;
1087 --nocolor)
1088 unset BLUE CYAN GREEN OFF RED
1089 ;;
1090 --timeout)
1091 shift
1092 if [ "$1" -gt 0 ] 2>/dev/null; then
1093 timeout=$1
1094 else
1095 die "--timeout requires a numeric argument greater than zero"
1096 fi
1097 ;;
1098 --)
1099 shift
1100 IFS="
1101 "
1102 mykeys=${mykeys+"$mykeys
1103 "}"$*"
1104 unset IFS
1105 break
1106 ;;
1107 -*)
1108 echo "$zero: unknown option $1" >&2
1109 exit 1
1110 ;;
1111 *)
1112 mykeys=${mykeys+"$mykeys
1113 "}"$1"
1114 ;;
1115 esac
1116 shift
1117 done
1118
1119 # Set filenames *after* parsing command-line options to allow
1120 # modification of $keydir and/or $hostopt
1121 #
1122 # pidf holds the specific name of the keychain .ssh-agent-myhostname file.
1123 # We use the new hostname extension for NFS compatibility. cshpidf is the
1124 # .ssh-agent file with csh-compatible syntax. lockf is the lockfile, used
1125 # to serialize the execution of multiple ssh-agent processes started
1126 # simultaneously
1127 [ -z "$hostopt" ] && hostopt="${HOSTNAME}"
1128 [ -z "$hostopt" ] && hostopt=`uname -n 2>/dev/null || echo unknown`
1129 pidf="${keydir}/${hostopt}-sh"
1130 cshpidf="${keydir}/${hostopt}-csh"
1131 olockf="${keydir}/${hostopt}-lock"
1132 lockf="${keydir}/${hostopt}-lockf"
1133
1134 # Don't use color if there's no terminal on stdout
1135 if [ -n "$OFF" ]; then
1136 tty <&1 >/dev/null 2>&1 || unset BLUE CYAN GREEN OFF RED
1137 fi
1138
1139 # versinfo uses qprint, which honors --quiet
1140 versinfo
1141 [ "$myaction" = version ] && exit 0
1142 [ "$myaction" = help ] && { helpinfo; exit 0; }
1143
1144 # Set up traps
1145 # Don't use signal names because they don't work on Cygwin.
1146 if $clearopt; then
1147 trap '' 2 # disallow ^C until we've had a chance to --clear
1148 trap 'droplock; exit 1' 1 15 # drop the lock on signal
1149 trap 'droplock; exit 0' 0 # drop the lock on exit
1150 else
1151 # Don't use signal names because they don't work on Cygwin.
1152 trap 'droplock; exit 1' 1 2 15 # drop the lock on signal
1153 trap 'droplock; exit 0' 0 # drop the lock on exit
1154 fi
1155
1156 setagents # verify/set $agentsopt
1157 verifykeydir # sets up $keydir
1158 wantagent ssh && testssh # sets $openssh and $sunssh
1159 getuser # sets $me
1160
1161 # Inherit agent info from the environment before loadagents wipes it out.
1162 # Always call this since it checks $inheritopt and sets variables accordingly.
1163 inheritagents
1164
1165 # --stop: kill the existing ssh-agent(s) and quit
1166 if [ -n "$stopwhich" ]; then
1167 if [ "$stopwhich" = all-warn ]; then
1168 warn "--stop without an argument is deprecated; see --help"
1169 stopwhich=all
1170 fi
1171 takelock || die
1172 if [ "$stopwhich" = mine -o "$stopwhich" = others ]; then
1173 loadagents
1174 fi
1175 for a in $agentsopt; do
1176 stopagent $a
1177 done
1178 if [ "$stopwhich" != others ]; then
1179 qprint
1180 exit 0 # stopagent is always successful
1181 fi
1182 fi
1183
1184 # Note regarding locking: if we're trying to be quick, then don't take the lock.
1185 # It will be taken later if we discover we can't be quick.
1186 if $quickopt; then
1187 loadagents # sets ssh_auth_sock, ssh_agent_pid, etc
1188 unset nagentsopt
1189 for a in $agentsopt; do
1190 needstart=true
1191
1192 # Trying to be quick has a price... If we discover the agent isn't running,
1193 # then we'll have to check things again (in startagent) after taking the
1194 # lock. So don't do the initial check unless --quick was specified.
1195 if [ $a = ssh ]; then
1196 sshavail=`ssh_l` # try to use existing agent
1197 # 0 = found keys, 1 = no keys, 2 = no agent
1198 if [ $? = 0 -o \( $? = 1 -a -z "$mykeys" \) ]; then
1199 mesg "Found existing ssh-agent ($ssh_agent_pid)"
1200 needstart=false
1201 fi
1202 elif [ $a = gpg ]; then
1203 # not much way to be quick on this
1204 if [ -n "$gpg_agent_pid" ]; then
1205 case " `findpids gpg` " in
1206 *" $gpg_agent_pid "*)
1207 mesg "Found existing gpg-agent ($gpg_agent_pid)"
1208 needstart=false ;;
1209 esac
1210 fi
1211 fi
1212
1213 $needstart && nagentsopt="$nagentsopt $a"
1214 done
1215 agentsopt="$nagentsopt"
1216 fi
1217
1218 # If there are no agents remaining, then bow out now...
1219 [ -n "$agentsopt" ] || { qprint; exit 0; }
1220
1221 # There are agents remaining to start, and we now know we can't be quick. Take
1222 # the lock before continuing
1223 takelock || die
1224 loadagents
1225 unset nagentsopt
1226 for a in $agentsopt; do
1227 startagent $a && nagentsopt="${nagentsopt+$nagentsopt }$a"
1228 done
1229 agentsopt="$nagentsopt"
1230
1231 # If there are no agents remaining, then duck out now...
1232 [ -n "$agentsopt" ] || { qprint; exit 0; }
1233
1234 # --timeout translates almost directly to ssh-add -t, but ssh.com uses
1235 # minutes and OpenSSH uses seconds
1236 if [ -n "$timeout" ] && wantagent ssh; then
1237 ssh_timeout=$timeout
1238 if $openssh || $sunssh; then
1239 ssh_timeout=`expr $ssh_timeout \* 60`
1240 fi
1241 ssh_timeout="-t $ssh_timeout"
1242 fi
1243
1244 # --clear: remove all keys from the agent(s)
1245 if $clearopt; then
1246 for a in ${agentsopt}; do
1247 if [ $a = ssh ]; then
1248 sshout=`ssh-add -D 2>&1`
1249 if [ $? = 0 ]; then
1250 mesg "ssh-agent: $sshout"
1251 else
1252 warn "ssh-agent: $sshout"
1253 fi
1254 elif [ $a = gpg ]; then
1255 kill -1 $gpg_agent_pid 2>/dev/null
1256 mesg "gpg-agent: All identities removed."
1257 else
1258 warn "--clear not supported for ${a}-agent"
1259 fi
1260 done
1261 trap 'droplock' 2 # done clearing, safe to ctrl-c
1262 fi
1263
1264 # --noask: "don't ask for keys", so we're all done
1265 $noaskopt && { qprint; exit 0; }
1266
1267 # Parse $mykeys into ssh vs. gpg keys; it may be necessary in the future to
1268 # differentiate on the cmdline
1269 parse_mykeys || die
1270
1271 # Load ssh keys
1272 if wantagent ssh; then
1273 sshavail=`ssh_l` # update sshavail now that we're locked
1274 sshkeys="`ssh_listmissing`" # cache list of missing keys, newline-separated
1275 sshattempts=$attempts
1276 savedisplay="$DISPLAY"
1277
1278 # Attempt to add the keys
1279 while [ -n "$sshkeys" ]; do
1280
1281 mesg "Adding ${BLUE}"`echo "$sshkeys" | wc -l`"${OFF} ssh key(s)..."
1282
1283 # Parse $sshkeys into positional params to preserve spaces in filenames.
1284 # This *must* happen after any calls to subroutines because pure Bourne
1285 # shell doesn't restore "$@" following a call. Eeeeek!
1286 set -f; # disable globbing
1287 old_IFS="$IFS" # save current IFS
1288 IFS="
1289 " # set IFS to newline
1290 set -- $sshkeys
1291 IFS="$old_IFS" # restore IFS
1292 set +f # re-enable globbing
1293
1294 if $noguiopt || [ -z "$SSH_ASKPASS" -o -z "$DISPLAY" ]; then
1295 unset DISPLAY # DISPLAY="" can cause problems
1296 unset SSH_ASKPASS # make sure ssh-add doesn't try SSH_ASKPASS
1297 sshout=`ssh-add ${ssh_timeout} "$@"`
1298 else
1299 sshout=`ssh-add ${ssh_timeout} "$@" </dev/null`
1300 fi
1301 [ $? = 0 ] && break
1302
1303 if [ $sshattempts = 1 ]; then
1304 die "Problem adding; giving up"
1305 else
1306 warn "Problem adding; trying again"
1307 fi
1308
1309 # Update the list of missing keys
1310 sshavail=`ssh_l`
1311 [ $? = 0 ] || die "problem running ssh-add -l"
1312 sshkeys="`ssh_listmissing`" # remember, newline-separated
1313
1314 # Decrement the countdown
1315 sshattempts=`expr $sshattempts - 1`
1316 done
1317
1318 [ -n "$savedisplay" ] && DISPLAY="$savedisplay"
1319 fi
1320
1321 # Load gpg keys
1322 if wantagent gpg; then
1323 gpgkeys="`gpg_listmissing`" # cache list of missing keys, newline-separated
1324 gpgattempts=$attempts
1325
1326 $noguiopt && unset DISPLAY
1327 [ -n "$DISPLAY" ] || unset DISPLAY # DISPLAY="" can cause problems
1328 GPG_TTY=`tty` ; export GPG_TTY # fall back to ncurses pinentry
1329
1330 # Attempt to add the keys
1331 while [ -n "$gpgkeys" ]; do
1332 tryagain=false
1333
1334 mesg "Adding ${BLUE}"`echo "$gpgkeys" | wc -l`"${OFF} gpg key(s)..."
1335
1336 # Parse $gpgkeys into positional params to preserve spaces in filenames.
1337 # This *must* happen after any calls to subroutines because pure Bourne
1338 # shell doesn't restore "$@" following a call. Eeeeek!
1339 set -f; # disable globbing
1340 old_IFS="$IFS" # save current IFS
1341 IFS="
1342 " # set IFS to newline
1343 set -- $gpgkeys
1344 IFS="$old_IFS" # restore IFS
1345 set +f # re-enable globbing
1346
1347 for k in "$@"; do
1348 echo | gpg --use-agent --no-tty --sign --local-user "$k" -o - >/dev/null 2>&1
1349 [ $? != 0 ] && tryagain=true
1350 done
1351 $tryagain || break
1352
1353 if [ $gpgattempts = 1 ]; then
1354 die "Problem adding (is pinentry installed?); giving up"
1355 else
1356 warn "Problem adding; trying again"
1357 fi
1358
1359 # Update the list of missing keys
1360 gpgkeys="`gpg_listmissing`" # remember, newline-separated
1361
1362 # Decrement the countdown
1363 gpgattempts=`expr $gpgattempts - 1`
1364 done
1365 fi
1366
1367 qprint # trailing newline
1368
1369 # vim:sw=4 expandtab tw=80

  ViewVC Help
Powered by ViewVC 1.1.20