keychain-2.7.1/0000775000000000000000000000000011371046301012010 5ustar rootrootkeychain-2.7.1/img/0000775000000000000000000000000011371046276012577 5ustar rootrootkeychain-2.7.1/img/keychain-1.png0000664000000000000000000001276511371046276015251 0ustar rootrootPNG  IHDReSIDATxc``Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`9sĉ`$`~p(a ?>1 J7`,ͰL=P-{+ax!= Th Jd 9wP#A@m(0@ heP Rԁu}ڵ`~:gM聗TzQBP1h0PdIC<} .q j{z'~ >` (qB{Ӡv+es0s`jKE +T L؀Rt}d!|f/(maq C KC"DI<,{0fҠ90.0!nz68H'V- hR懆ª_h) r+Q pߛp08.U=D<9 A5 "\>Dl`<.Gه8;4Ual\<4Emc4?%/R\Y;@@. cKaxB `9Hplv10 ^4TB cB?RRGD #KAe=Qs@bDF0ܨU[W H(4 j:G.)aRF FcSDjK%iR #4N)R|S 4" .n@)Q(H{)E(:Rck1E) QW5c8Ja]F1Ka`i}x6sf) ,y"C/M`9E"ku qi<#4q1BF &>+r8ez,,r`L-GD) _[C*(Hjd| ąr@G  R `D5; D #WJTQѻiR :Ev:kMX:8Jv, K#Hcd30(PfMH[pA2" uQ+lvA]VK``ď̎A ̒(3 .r4c Ij3cgQ0 F(`Q0 F(`Q0 F(`Q0 F(`@Cƹb1  8P{(`DR@rtR)\:̡)0|6 F($/\ Fr# ` @VePl.Y]9QKzvqn( qP)\T^\G8t'zDU˿xQ0 #J(8b(* Kia@T Ii\B,qb/5p(Q8m GC-@pR:*Pih0‹Rn J!Fl)كݙQF$AVk8r'1` FKRx0V LW)"j8Ja\G8r'82-GKRxd¨PUh)Tĕ˜@0J1H P 80pNw+qi$I|Q0Z $# &F+1qy0%z:0őEx܉eBeHh)_z.多#py|G=_x/S}&|G=_x|q/[=Z z1G=_x| Vf!Ra|G=_x|as/>棄C£ /_S=~H59`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 #m% ,PܳanorQruBb"dQ0 F/ PT% f )MI?{2B{V8 F(@ H'ڠ*H[t{BJ[pa,P` F=UEEX܉@Ja`@ݨ* 1Qt[q9<m0 C?ryhy8` 6qX܉ c祡7pq&05ztkA5󅑲?.ݎ]EF*$ $vq '[!Y|Ș0.F(Cb= 07. n;'RDb6[b-GKaS Oa;oGK Liu^0 ] 86\d`U(17.wX:z艗'^/@Y,.rb8fWVP|^0dBLm[ٙ+PC#(P8"@d \sh)Vn"Ɲz9X.'@ aw<@(ɟP3Њf$/ VO0=` ;G؎pDAKg h@k>`km<`GO\(}JAp塡5pQSbe>8IrH#H g0f.{O)/qۋ!k S=.wJ?FKU ci C$ 0Zni'1R$+ӱ e)а$\6E{`AbuR0/qۋYpM S8(ygRO:"FO`yB |RKaJDKaQORؔPwc/-KaeH}#"(!hRUPEEx%-Wr/Ra>0!ƖQ CZ)ff.{k:[#a鉓_MheDbF$NnhxQ{EH}#Dy DPB{0A$xJ0\=R$B@BxXG.qT=fYp0mv{q3`O'xXKX*;/E>q$FKQ B@voH@k{?G` 5>(b`Q0 F(`Q0Yݣ8; F(`Q0 F(`Q0 F(@,q; h x;0P@9=ci}hKӈA\tY,ŸZ:znCdjRa8UmΣ%,N, ʠ|RCb:@4h04`~!Q@ (q Cަu 퉠X (EImHPu%0 Ke>r1 Y3p/Z=T/̆!%&ɣtl75OT\N")Gq8XCq|XKa<R*a/V֐!E=N܀*=/01y87yL%*f@Q)jAm@Eq(HɄzjmn<{:x܃3p?.P9BGM=7yğJ9@(Xa)+ T)LL>_h*(\j|jҸ6%!BGM=7&Dw(%b8c qk(aC1"|0|02E7R܃+^p?P1p{[2C 0ĸ'.q'z_nq< ( @@>VqS(IMPc E!K!GT EC#g:k@0:&Ezl_{_88cD3`  anƓ_/q P8(`dsGM=7yd,&Q0 F(`Q0 F(luh(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(qQ0 F(h)w##ȁA]tb4"2ڀ<=jw?MaXURx-GKaKaN0Ξ> EjBVwFa;"7{E0 s11`ϝTh)*n@#8i>B _H+r~90%"& l tPk:>d>r# 8X! Ji$`=K@3iuc _XAm7Nsp`p4)`CCa.}zߔTq W3(pMlUAK"t؜ё4NP&T 5`!(@RWm?r8 TR.(DF[RK1J0X!B*Uh| eEKv(yhMZ̏,|m DQ`7*`k JpB A8.O=)q;0K1!6ML "7oQMxTG֎P nqxs?0P+|X0 Li ,z 2Pp!En7I@h/RP*\i/< 7jUգ:"~tsO`E,&͘)|A)mXbr qHe=S$KP b R^bQ0 ϪCZLQJ@ a0f LXlub_ϰ^nT\Y \' Xgژp5H\G;(n&Mp (|y+|rB.b ƭKي F \—ːG ZR#2=qaCwHCf/|)Q U|Vn.5 fVQNa MK!B"+8& 8 52D\pCCTA[%]=D%6s&̡((QQ0(`Y TVF7lZA'#k( l:Q@]0;9vF(`Q0 F(`Q0 F(`Q0 F(`Q0  <_Ȁ[`| 'G$P eras{plN~ &,r@yEK) 6/I>0|p mٸ/Aы\Zk r@yLh>F149#`G!"$,Yx6EJD 1a̅*@y78g7'aqnqP[T^\)ܰxӝxӿ nRJPBe)=W3օ/٣h-kx _<ҰEUGn)yhnB&s~L艅@%K7M(qËK uzh pp7>p1M\Rq ]xXjj.q/6a$= ;Pݝ㣅h;)R3 8ijnRS!8PLG-1ő'|HU}(mBR _@>2jwW7O1:,3@w۱gBlXGF!O r?ܩ&p1+F(Pa"zf(`\`Q0 F(`Q@ss$wQ0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`Q0 F(`@`Q0 hF w-|G w-|G w(sJ{zP9ZhKz᫶?4)!q }5B*G[-іh˗/u@=| _`4ZhKX`_ Us7-\o*PjpP 90se+؋՝TCOh;Z/q/Q/="SoxdJ@ *[ځ(#H X= OQ^ 6Cjqw-|G _ _Xb6'HPZ1,A\zR EnBFN؆&" | sed -e 's/^.*"acct"=\(".*"\)$/\1/' keychain-2.7.1/Makefile0000664000000000000000000000440011371046276013461 0ustar rootrootV:=$(shell cat VERSION) D:=$(shell date +'%d %b %Y') TARBALL_CONTENTS=keychain README.rst ChangeLog COPYING keychain.pod keychain.1 \ keychain.spec all: keychain.1 keychain keychain.spec .PHONY : tmpclean tmpclean: rm -rf dist keychain.1.orig keychain.txt .PHONY : clean clean: tmpclean rm -rf keychain.1 keychain keychain.spec keychain.spec: keychain.spec.in keychain.sh sed 's/KEYCHAIN_VERSION/$V/' keychain.spec.in > keychain.spec keychain.1: keychain.pod keychain.sh pod2man --name=keychain --release=$V \ --center='http://www.funtoo.org' \ keychain.pod keychain.1 sed -i.orig -e "s/^'br/.br/" keychain.1 keychain.1.gz: keychain.1 gzip -9 keychain.1 GENKEYCHAINPL = open P, "keychain.txt" or die "cant open keychain.txt"; \ while (

) { \ $$printing = 0 if /^\w/; \ $$printing = 1 if /^(SYNOPSIS|OPTIONS)/; \ $$printing || next; \ s/\$$/\\\$$/g; \ s/\`/\\\`/g; \ s/\\$$/\\\\/g; \ s/\*(\w+)\*/\$${CYAN}$$1\$${OFF}/g; \ s/(^|\s)(-+[-\w]+)/$$1\$${GREEN}$$2\$${OFF}/g; \ $$pod .= $$_; \ }; \ open B, "keychain.sh" or die "cant open keychain.sh"; \ $$/ = undef; \ $$_ = ; \ s/INSERT_POD_OUTPUT_HERE\n/$$pod/ || die; \ s/\#\#VERSION\#\#/$V/g || die; \ print keychain: keychain.sh keychain.txt perl -e '$(GENKEYCHAINPL)' >keychain || rm -f keychain chmod +x keychain keychain.txt: keychain.pod pod2text keychain.pod keychain.txt keychain-$V.tar.gz: $(TARBALL_CONTENTS) @case $V in *-test*) \ echo "**** Version is $V, please remove -test"; \ exit 1 ;; \ esac @if ! grep -qF '* keychain $V ' ChangeLog; then \ echo "**** Need to update the ChangeLog for version $V"; \ exit 1; \ fi mkdir keychain-$V cp $(TARBALL_CONTENTS) keychain-$V sudo chown -R root:root keychain-$V /bin/tar cjvf keychain-$V.tar.bz2 keychain-$V sudo rm -rf keychain-$V ls -l keychain-$V.tar.bz2 # Building noarch.rpm builds src.rpm at the same time. I haven't # found an elegant way yet to prevent parallel builds from messing # this up, so all deps in the Makefile refer only to noarch.rpm keychain-$V-1.noarch.rpm: keychain-$V.tar.gz rpmbuild -ta keychain-$V.tar.bz2 mv ~/redhat/RPMS/noarch/keychain-$V-1.noarch.rpm \ ~/redhat/SRPMS/keychain-$V-1.src.rpm . rpm --addsign keychain-$V-1.noarch.rpm keychain-$V-1.src.rpm keychain-2.7.1/release.sh0000775000000000000000000000371311371046276014006 0ustar rootroot#!/bin/bash # This script is used by the keychain maintainer to generate new keychain releases. PKG=keychain VERSION=`cat VERSION` versionsub() { # For keychain, this substitution stuff is done by the Makefile... cat $1 | sed -e "s/##VERSION##/$VERSION/g" } die() { echo $* exit 1 } prep() { rm -rf dist/$PKG-$VERSION* install -d dist/$PKG-$VERSION } commit() { # Last step of a release is for the maintainer to update Changelog, README.rst and VERSIOn, # and then run "./release.sh all", which will run the following to make the release commit # and generate a release tarball. The release tarball is the current git tarball with "make" # run inside it, so that keychain, keychain.1 and keychain.spec are pre-generated for the # end-user. Since keychain is a script and the automated Makefile exists as a convenience # for the maintainer, we don't want to pass this complexity on to the consumers of this # package. git commit -a -m "$VERSION distribution release" || die "commit failed" git archive --format=tar --prefix=${PKG}-${VERSION}/ HEAD | tar xf - -C dist || die "git archive fail" git push || die "keychain git push failed" cd dist/$PKG-$VERSION || die "pkg cd fail" # tmpclean target cleans up temporary intermediate files that were produced. make clean all || die "make dist failed" make tmpclean || die "make tmpclean failed" cd .. || die "pkg cd .. fail" tar cjf $PKG-$VERSION.tar.bz2 $PKG-$VERSION || die "release tarball failed" cd .. || die "pkg cd .. again fail" } web() { cp dist/$PKG-$VERSION.tar.bz2 /root/git/website/archive/$PKG/ || die "web cp failed" cd /root/git/website || die "cd failed" git add archive/$PKG/* || die "git add failed" git commit -a -m "new $PKG $VERSION" || die "git commit failed" git push || die "git push failed" ./install.sh || die "web update failed" } if [ "$1" = "prep" ] then prep elif [ "$1" = "commit" ] then commit elif [ "$1" = "web" ] then web elif [ "$1" = "all" ] then prep commit web fi keychain-2.7.1/COPYING.txt0000664000000000000000000004300111371046276013672 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. keychain-2.7.1/keychain.pod0000775000000000000000000002012011371046276014320 0ustar rootroot=head1 NAME keychain - re-use ssh-agent and/or gpg-agent between logins =head1 SYNOPSIS S S<--nocolor --nogui --nolock --quick --quiet --version ]> S<[ --agents I ] [ --attempts I ] [ --dir I ]> S<[ --host I ] [ --lockwait I ]> S<[ --stop I ] [ --timeout I ] [ keys... ]> =head1 DESCRIPTION keychain is a manager for ssh-agent, typically run from ~/.bash_profile. It allows your shells and cron jobs to share a single ssh-agent process. By default, the ssh-agent started by keychain is long-running and will continue to run, even after you have logged out from the system. If you want to change this behavior, take a look at the --clear and --timeout options, described below. When keychain is run, it checks for a running ssh-agent, otherwise it starts one. It saves the ssh-agent environment variables to ~/.keychain/${HOSTNAME}-sh, so that subsequent logins and non-interactive shells such as cron jobs can source the file and make passwordless ssh connections. In addition, when keychain runs, it verifies that the key files specified on the command-line are known to ssh-agent, otherwise it loads them, prompting you for a password if necessary. Keychain also supports gpg-agent in the same ways that ssh-agent is supported. By default keychain attempts to start all available agents but will fall back to only gpg-agent or only ssh-agent if either is unavailable. You can specifically limit keychain using the --agents option. keychain supports most UNIX-like operating systems, including Cygwin. It works with Bourne-compatible, csh-compatible and fish shells. =head1 OPTIONS =over =item B<--agents> I Start the agents listed. By default keychain will build the list automatically based on the existence of ssh-agent and/or gpg-agent on the system. The list should be comma-separated, for example "gpg,ssh" =item B<--attempts> I Try num times to add keys before giving up. The default is 1. =item B<--clear> Delete all of ssh-agent's keys. Typically this is used in .bash_profile. The theory behind this is that keychain should assume that you are an intruder until proven otherwise. However, while this option increases security, it still allows your cron jobs to use your ssh keys when you're logged out. =item B<--confirm> Keys are subject to interactive confirmation by the SSH_ASKPASS program before being used for authentication. See the -c option for ssh-add(1). =item B<--dir> I Keychain will use dirname rather than $HOME/.keychain =item B<--eval> Keychain will print lines to be evaluated in the shell on stdout. It respects the SHELL environment variable to determine if Bourne shell or C shell output is expected. =item B<--env> I After parsing options, keychain will load additional environment settings from "filename". By default, if "--env" is not given, then keychain will attempt to load from ~/.keychain/[hostname]-env or alternatively ~/.keychain/env. The purpose of this file is to override settings such as PATH, in case ssh is stored in a non-standard place. =item B<-h --help> Show help that looks remarkably like this man-page. As of 2.6.10, help is sent to stdout so it can be easily piped to a pager. =item B<--host> I Set alternate hostname for creation of pidfiles =item B<--ignore-missing> Don't warn if some keys on the command-line can't be found. This is useful for situations where you have a shared .bash_profile, but your keys might not be available on every machine where keychain is run. =item B<--inherit> I Attempt to inherit agent variables from the environment. This can be useful in a variety of circumstances, for example when ssh-agent is started by gdm. The following values are valid for "which": =over 12 =item B Inherit when a pid (e.g. SSH_AGENT_PID) is set in the environment. This disallows inheriting a forwarded agent. =item B Inherit when a sock (e.g. SSH_AUTH_SOCK) is set in the environment. This allows inheriting a forwarded agent. =item B Same as "local", but only inherit if keychain isn't already providing an agent. =item B Same as "any", but only inherit if keychain isn't already providing an agent. =back By default, keychain-2.5.0 and later will behave as if "--inherit local-once" is specified. You should specify "--noinherit" if you want the older behavior. =item B<--lockwait> I How long to wait for the lock to become available. Defaults to 5 seconds. Specify a value of zero or more. If the lock cannot be acquired within the specified number of seconds, then this keychain process will forcefully acquire the lock. =item B<--noask> This option tells keychain do everything it normally does (ensure ssh-agent is running, set up the ~/.keychain/[hostname]-{c}sh files) except that it will not prompt you to add any of the keys you specified if they haven't yet been added to ssh-agent. =item B<--nocolor> Disable color hilighting for non ANSI-compatible terms. =item B<--nogui> Don't honor SSH_ASKPASS, if it is set. This will cause ssh-add to prompt on the terminal instead of using a graphical program. =item B<--noinherit> Don't inherit any agent processes, overriding the default "--inherit local-once" =item B<--nolock> Don't attempt to use a lockfile while manipulating files, pids and keys. =item B<-k --stop> I Kill currently running agent processes. The following values are valid for "which": =over 9 =item all Kill all agent processes and quit keychain immediately. Prior to keychain-2.5.0, this was the behavior of the bare "--stop" option. =item others Kill agent processes other than the one keychain is providing. Prior to keychain-2.5.0, keychain would do this automatically. The new behavior requires that you specify it explicitly if you want it. =item mine Kill keychain's agent processes, leaving other agents alone. =back =item B<-Q --quick> If an ssh-agent process is running then use it. Don't verify the list of keys, other than making sure it's non-empty. This option avoids locking when possible so that multiple terminals can be opened simultaneously without waiting on each other. =item B<-q --quiet> Only print messages in case of warning, error or required interactivity. As of version 2.6.10, this also suppresses "Identities added" messages for ssh-agent. =item B<--timeout> I Set a timeout in minutes on your keys. This is conveyed to ssh-agent which does the actual timing out of keys since keychain doesn't run continuously. =item B<-V --version> Show version information. =back =head1 EXAMPLES This snippet should work in any shell to load two ssh keys and one gpg key: eval `keychain --eval id_rsa id_dsa 0123ABCD` If you have trouble with that in csh: setenv SHELL /bin/csh eval `keychain --eval id_rsa id_dsa 0123ABCD` This is equivalent for Bourne shells (including bash and zsh) but doesn't use keychain's --eval feature: keychain id_rsa id_dsa 0123ABCD [ -z "$HOSTNAME" ] && HOSTNAME=`uname -n` [ -f $HOME/.keychain/$HOSTNAME-sh ] && \ . $HOME/.keychain/$HOSTNAME-sh [ -f $HOME/.keychain/$HOSTNAME-sh-gpg ] && \ . $HOME/.keychain/$HOSTNAME-sh-gpg This is equivalent for C shell (including tcsh): keychain id_rsa id_dsa 0123ABCD host=`uname -n` if (-f $HOME/.keychain/$host-csh) then source $HOME/.keychain/$host-csh endif if (-f $HOME/.keychain/$host-csh-gpg) then source $HOME/.keychain/$host-csh-gpg endif To load keychain variables from a script (for example from cron) and abort unless id_dsa is available: # Load keychain variables and check for id_dsa [ -z "$HOSTNAME" ] && HOSTNAME=`uname -n` . $HOME/.keychain/$HOSTNAME-sh 2>/dev/null ssh-add -l 2>/dev/null | grep -q id_dsa || exit 1 =head1 SEE ALSO L =head1 NOTES Keychain was created and is currently maintained by Daniel Robbins. If you need to report a bug or request an enhancement, please post to the funtoo-dev mailing list L. For more information about keychain, please visit L. keychain-2.7.1/keychain.sh0000775000000000000000000012552111371046276014163 0ustar rootroot#!/bin/sh # Copyright 1999-2005 Gentoo Foundation # Copyright 2007 Aron Griffis # Copyright 2009-2010 Funtoo Technologies, LLC # lockfile() Copyright 2009 Parallels, Inc. # Distributed under the terms of the GNU General Public License v2 # Originally authored by Daniel Robbins # Maintained August 2002 - April 2003 by Seth Chandler # Maintained and rewritten April 2004 - July 2007 by Aron Griffis # Maintained July 2009 - present by Daniel Robbins version=##VERSION## PATH="/usr/bin:/bin:/sbin:/usr/sbin:/usr/ucb:${PATH}" maintainer="drobbins@funtoo.org" zero=`basename "$0"` unset mesglog unset myaction unset agentsopt havelock=false unset hostopt ignoreopt=false noaskopt=false noguiopt=false nolockopt=false lockwait=5 openssh=unknown sunssh=unknown quickopt=false quietopt=false clearopt=false color=true inheritwhich=local-once unset stopwhich unset timeout unset ssh_timeout attempts=1 unset sshavail unset sshkeys unset gpgkeys unset mykeys keydir="${HOME}/.keychain" unset envf evalopt=false confirmopt=false unset ssh_confirm unset GREP_OPTIONS BLUE="" CYAN="" CYANN="" GREEN="" RED="" PURP="" OFF="" # GNU awk and sed have regex issues in a multibyte environment. If any locale # variables are set, then override by setting LC_ALL unset pinentry_locale lvars=`locale 2>/dev/null | egrep -v '="?(|POSIX|C)"?$' 2>/dev/null` if [ -n "$lvars$LANG$LC_ALL" ]; then # save LC_ALL so that pinentry-curses works right. This has always worked # correctly for me but peper and kloeri had problems with it. pinentry_lc_all="$LC_ALL" LC_ALL=C export LC_ALL fi # synopsis: qprint "message" qprint() { $quietopt || echo "$*" >&2 } # synopsis: mesg "message" # Prettily print something to stderr, honors quietopt mesg() { qprint " ${GREEN}*${OFF} $*" } # synopsis: warn "message" # Prettily print a warning to stderr warn() { echo " ${RED}* Warning${OFF}: $*" >&2 } # synopsis: error "message" # Prettily print an error error() { echo " ${RED}* Error${OFF}: $*" >&2 } # synopsis: die "message" # Prettily print an error, then abort die() { [ -n "$1" ] && error "$*" qprint $evalopt && { echo; echo "false;"; } exit 1 } # synopsis: versinfo # Display the version information versinfo() { qprint qprint " Copyright ${CYANN}2002-2006${OFF} Gentoo Foundation;" qprint " Copyright ${CYANN}2007${OFF} Aron Griffis;" qprint " Copyright ${CYANN}2009-2010${OFF} Funtoo Technologies, LLC;" qprint " lockfile() Copyright ${CYANN}2009${OFF} Parallels, Inc." qprint qprint " Keychain is free software: you can redistribute it and/or modify" qprint " it under the terms of the ${CYANN}GNU General Public License version 2${OFF} as" qprint " published by the Free Software Foundation." qprint } # synopsis: helpinfo # Display the help information. There's no really good way to use qprint for # this... helpinfo() { cat >&1 <&1`" in *OpenSSH*) openssh=true ;; *Sun?SSH*) sunssh=true ;; esac } # synopsis: getuser # Set the global string $me getuser() { # whoami gives euid, which might be different from USER or LOGNAME me=`whoami` || die "Who are you? whoami doesn't know..." } # synopsis: getos # Set the global string $OSTYPE getos() { OSTYPE=`uname` || die 'uname failed' } # synopsis: verifykeydir # Make sure the key dir is set up correctly. Exits on error. verifykeydir() { # Create keydir if it doesn't exist already if [ -f "${keydir}" ]; then die "${keydir} is a file (it should be a directory)" # Solaris 9 doesn't have -e; using -d.... elif [ ! -d "${keydir}" ]; then ( umask 0077 && mkdir "${keydir}"; ) || die "can't create ${keydir}" fi } lockfile() { # This function originates from Parallels Inc.'s OpenVZ vpsreboot script # Description: This function attempts to acquire the lock. If it succeeds, # it returns 0. If it fails, it returns 1. This function retuns immediately # and only tries to acquire the lock once. local tmpfile="$lockf.$$" echo $$ >"$tmpfile" 2>/dev/null || exit if ln "$tmpfile" "$lockf" 2>/dev/null; then rm -f "$tmpfile" havelock=true && return 0 fi if kill -0 `cat $lockf 2>/dev/null` 2>/dev/null; then rm -f "$tmpfile" return 1 fi if ln "$tmpfile" "$lockf" 2>/dev/null; then rm -f "$tmpfile" havelock=true && return 0 fi rm -f "$tmpfile" "$lockf" && return 1 } takelock() { # Description: This function calls lockfile() multiple times if necessary # to try to acquire the lock. It returns 0 on success and 1 on failure. # Change in behavior: if timeout expires, we will forcefully acquire lock. [ "$havelock" = "true" ] && return 0 [ "$nolockopt" = "true" ] && return 0 # First attempt: lockfile && return 0 local counter=0 mesg "Waiting $lockwait seconds for lock..." while [ "$counter" -lt "$(( $lockwait * 2 ))" ] do lockfile && return 0 sleep 0.5; counter=$(( $counter + 1 )) done rm -f "$lockf" && lockfile && return 0 return 1 } # synopsis: droplock # Drops the lock if we're holding it. droplock() { $havelock && [ -n "$lockf" ] && rm -f "$lockf" } # synopsis: findpids [prog] # Returns a space-separated list of agent pids. # prog can be ssh or gpg, defaults to ssh. Note that if another prog is ever # added, need to pay attention to the length for Solaris compatibility. findpids() { fp_prog=${1-ssh} unset fp_psout # Different systems require different invocations of ps. Try to generalize # the best we can. The only requirement is that the agent command name # appears in the line, and the PID is the first item on the line. [ -n "$OSTYPE" ] || getos # Try systems where we know what to do first case "$OSTYPE" in AIX|*bsd*|*BSD*|CYGWIN|darwin*|Linux|linux-gnu|OSF1) fp_psout=`ps x 2>/dev/null` ;; # BSD syntax HP-UX) fp_psout=`ps -u $me 2>/dev/null` ;; # SysV syntax SunOS) case `uname -r` in [56]*) fp_psout=`ps -u $me 2>/dev/null` ;; # SysV syntax *) fp_psout=`ps x 2>/dev/null` ;; # BSD syntax esac ;; GNU|gnu) fp_psout=`ps -g 2>/dev/null` ;; # GNU Hurd syntax esac # If we didn't get a match above, try a list of possibilities... # The first one will probably fail on systems supporting only BSD syntax. if [ -z "$fp_psout" ]; then fp_psout=`UNIX95=1 ps -u $me -o pid,comm 2>/dev/null | grep '^ *[0-9]'` [ -z "$fp_psout" ] && fp_psout=`ps x 2>/dev/null` fi # Return the list of pids; ignore case for Cygwin. # Check only 8 characters since Solaris truncates at that length. # Ignore defunct ssh-agents (bug 28599) if [ -n "$fp_psout" ]; then echo "$fp_psout" | \ awk "BEGIN{IGNORECASE=1} /defunct/{next} /$fp_prog-[a]gen/{print \$1}" | xargs return 0 fi # If none worked, we're stuck error "Unable to use \"ps\" to scan for $fp_prog-agent processes" error "Please report to $maintainer via http://bugs.gentoo.org" return 1 } # synopsis: stopagent [prog] # --stop tells keychain to kill the existing agent(s) # prog can be ssh or gpg, defaults to ssh. stopagent() { stop_prog=${1-ssh} eval stop_except=\$\{${stop_prog}_agent_pid\} stop_mypids=`findpids "$stop_prog"` [ $? = 0 ] || die if [ -z "$stop_mypids" ]; then mesg "No $stop_prog-agent(s) found running" return 0 fi case "$stopwhich" in all) kill $stop_mypids >/dev/null 2>&1 mesg "All ${CYANN}$me${OFF}'s $stop_prog-agents stopped: ${CYANN}$stop_mypids${OFF}" ;; others) # Try to handle the case where we *will* inherit a pid kill -0 $stop_except >/dev/null 2>&1 if [ -z "$stop_except" -o $? != 0 -o \ "$inheritwhich" = local -o "$inheritwhich" = any ]; then if [ "$inheritwhich" != none ]; then eval stop_except=\$\{inherit_${stop_prog}_agent_pid\} kill -0 $stop_except >/dev/null 2>&1 if [ -z "$stop_except" -o $? != 0 ]; then # Handle ssh2 eval stop_except=\$\{inherit_${stop_prog}2_agent_pid\} fi fi fi # Filter out the running agent pid unset stop_mynewpids for stop_x in $stop_mypids; do [ $stop_x -eq $stop_except ] 2>/dev/null && continue stop_mynewpids="${stop_mynewpids+$stop_mynewpids }$stop_x" done if [ -n "$stop_mynewpids" ]; then kill $stop_mynewpids >/dev/null 2>&1 mesg "Other ${CYANN}$me${OFF}'s $stop_prog-agents stopped: ${CYANN}$stop_mynewpids${OFF}" else mesg "No other $stop_prog-agent(s) than keychain's $stop_except found running" fi ;; mine) if [ $stop_except -gt 0 ] 2>/dev/null; then kill $stop_except >/dev/null 2>&1 mesg "Keychain $stop_prog-agents stopped: ${CYANN}$stop_except${OFF}" else mesg "No keychain $stop_prog-agent found running" fi ;; esac # remove pid files if keychain-controlled if [ "$stopwhich" != others ]; then if [ "$stop_prog" != ssh ]; then rm -f "${pidf}-$stop_prog" "${cshpidf}-$stop_prog" "${fishpidf}-$stop_prog" 2>/dev/null else rm -f "${pidf}" "${cshpidf}" "${fishpidf}" 2>/dev/null fi eval unset ${stop_prog}_agent_pid fi } # synopsis: inheritagents # Save agent variables from the environment before they get wiped out inheritagents() { # Verify these global vars are null unset inherit_ssh_auth_sock inherit_ssh_agent_pid unset inherit_ssh2_auth_sock inherit_ssh2_agent_sock unset inherit_gpg_agent_info inherit_gpg_agent_pid # Save variables so we can inherit a running agent if [ "$inheritwhich" != none ]; then if wantagent ssh; then if [ -n "$SSH_AUTH_SOCK" ]; then inherit_ssh_auth_sock="$SSH_AUTH_SOCK" inherit_ssh_agent_pid="$SSH_AGENT_PID" fi if [ -n "$SSH2_AUTH_SOCK" ]; then inherit_ssh2_auth_sock="$SSH2_AUTH_SOCK" inherit_ssh2_agent_pid="$SSH2_AGENT_PID" fi fi if wantagent gpg; then if [ -n "$GPG_AGENT_INFO" ]; then inherit_gpg_agent_info="$GPG_AGENT_INFO" inherit_gpg_agent_pid=`echo "$GPG_AGENT_INFO" | cut -f2 -d:` fi fi fi } # synopsis: validinherit # Test inherit_* variables for validity validinherit() { vi_agent="$1" vi_status=0 if [ "$vi_agent" = ssh ]; then if [ -n "$inherit_ssh_auth_sock" ]; then ls "$inherit_ssh_auth_sock" >/dev/null 2>&1 if [ $? != 0 ]; then warn "SSH_AUTH_SOCK in environment is invalid; ignoring it" unset inherit_ssh_auth_sock inherit_ssh_agent_pid vi_status=1 fi fi if [ -n "$inherit_ssh2_auth_sock" ]; then ls "$inherit_ssh2_auth_sock" >/dev/null 2>&1 if [ $? != 0 ]; then warn "SSH2_AUTH_SOCK in environment is invalid; ignoring it" unset inherit_ssh2_auth_sock inherit_ssh2_agent_pid vi_status=1 fi fi elif [ "$vi_agent" = gpg ]; then if [ -n "$inherit_gpg_agent_pid" ]; then kill -0 "$inherit_gpg_agent_pid" >/dev/null 2>&1 if [ $? != 0 ]; then unset inherit_gpg_agent_pid inherit_gpg_agent_info warn "GPG_AGENT_INFO in environment is invalid; ignoring it" vi_status=1 fi fi fi return $vi_status } # synopsis: catpidf_shell shell agents... # cat the pid files for the given agents. This is used by loadagents and also # for keychain output when --eval is given. catpidf_shell() { case "$1" in */fish|fish) cp_pidf="$fishpidf" ;; *csh) cp_pidf="$cshpidf" ;; *) cp_pidf="$pidf" ;; esac shift for cp_a in "$@"; do case "${cp_a}" in ssh) [ -f "$cp_pidf" ] && cat "$cp_pidf" ;; *) [ -f "${cp_pidf}-$cp_a" ] && cat "${cp_pidf}-$cp_a" ;; esac echo done return 0 } # synopsis: catpidf agents... # cat the pid files for the given agents, appropriate for the current value of # $SHELL. This is used for keychain output when --eval is given. catpidf() { catpidf_shell "$SHELL" "$@" } # synopsis: loadagents agents... # Load agent variables from $pidf and copy implementation-specific environment # variables into generic global strings loadagents() { for la_a in "$@"; do case "$la_a" in ssh) unset SSH_AUTH_SOCK SSH_AGENT_PID SSH2_AUTH_SOCK SSH2_AGENT_PID eval "`catpidf_shell sh $la_a`" if [ -n "$SSH_AUTH_SOCK" ]; then ssh_auth_sock=$SSH_AUTH_SOCK ssh_agent_pid=$SSH_AGENT_PID elif [ -n "$SSH2_AUTH_SOCK" ]; then ssh_auth_sock=$SSH2_AUTH_SOCK ssh_agent_pid=$SSH2_AGENT_PID else unset ssh_auth_sock ssh_agent_pid fi ;; gpg) unset GPG_AGENT_INFO eval "`catpidf_shell sh $la_a`" if [ -n "$GPG_AGENT_INFO" ]; then la_IFS="$IFS" # save current IFS IFS=':' # set IFS to colon to separate PATH set -- $GPG_AGENT_INFO IFS="$la_IFS" # restore IFS gpg_agent_pid=$2 fi ;; *) eval "`catpidf_shell sh $la_a`" ;; esac done return 0 } # synopsis: startagent [prog] # Starts an agent if it isn't already running. # Requires $ssh_agent_pid startagent() { start_prog=${1-ssh} unset start_pid start_inherit_pid=none start_mypids=`findpids "$start_prog"` [ $? = 0 ] || die # Unfortunately there isn't much way to genericize this without introducing # a lot more supporting code/structures. if [ "$start_prog" = ssh ]; then start_pidf="$pidf" start_cshpidf="$cshpidf" start_fishpidf="$fishpidf" start_pid="$ssh_agent_pid" if [ -n "$inherit_ssh_auth_sock" -o -n "$inherit_ssh2_auth_sock" ]; then if [ -n "$inherit_ssh_agent_pid" ]; then start_inherit_pid="$inherit_ssh_agent_pid" elif [ -n "$inherit_ssh2_agent_pid" ]; then start_inherit_pid="$inherit_ssh2_agent_pid" else start_inherit_pid="forwarded" fi fi else start_pidf="${pidf}-$start_prog" start_cshpidf="${cshpidf}-$start_prog" start_fishpidf="${fishpidf}-$start_prog" if [ "$start_prog" = gpg ]; then start_pid="$gpg_agent_pid" if [ -n "$inherit_gpg_agent_pid" ]; then start_inherit_pid="$inherit_gpg_agent_pid" fi else error "I don't know how to start $start_prog-agent (1)" return 1 fi fi [ "$start_pid" -gt 0 ] 2>/dev/null || start_pid=none # This hack makes the case statement easier if [ "$inheritwhich" = any -o "$inheritwhich" = any-once ]; then start_fwdflg=forwarded else unset start_fwdflg fi # Check for an existing agent start_tester="$inheritwhich: $start_mypids $start_fwdflg " case "$start_tester" in none:*" $start_pid "*|*-once:*" $start_pid "*) mesg "Found existing ${start_prog}-agent: ${CYANN}$start_pid${OFF}" return 0 ;; *:*" $start_inherit_pid "*) # This test was postponed until now to prevent generating warnings validinherit "$start_prog" if [ $? != 0 ]; then # inherit_* vars have been removed from the environment. Try # again now startagent "$start_prog" return $? fi mesg "Inheriting ${start_prog}-agent ($start_inherit_pid)" ;; *) # start_inherit_pid might be "forwarded" which we don't allow with, # for example, local-once (the default setting) start_inherit_pid=none ;; esac # Init the bourne-formatted pidfile ( umask 0177 && :> "$start_pidf"; ) if [ $? != 0 ]; then rm -f "$start_pidf" "$start_cshpidf" "$start_fishpidf" 2>/dev/null error "can't create $start_pidf" return 1 fi # Init the csh-formatted pidfile ( umask 0177 && :> "$start_cshpidf"; ) if [ $? != 0 ]; then rm -f "$start_pidf" "$start_cshpidf" "$start_fishpidf" 2>/dev/null error "can't create $start_cshpidf" return 1 fi # Init the fish-formatted pidfile ( umask 0177 && :> "$start_fishpidf"; ) if [ $? != 0 ]; then rm -f "$start_pidf" "$start_cshpidf" "$start_fishpidf" 2>/dev/null error "can't create $start_fishpidf" return 1 fi # Determine content for files unset start_out if [ "$start_inherit_pid" = none ]; then # Start the agent. # Branch again since the agents start differently mesg "Starting ${start_prog}-agent..." if [ "$start_prog" = ssh ]; then start_out=`ssh-agent` elif [ "$start_prog" = gpg ]; then if [ -n "${timeout}" ]; then start_gpg_timeout="--default-cache-ttl `expr $timeout \* 60`" else unset start_gpg_timeout fi # the 1.9.x series of gpg spews debug on stderr start_out=`gpg-agent --daemon $start_gpg_timeout 2>/dev/null` else error "I don't know how to start $start_prog-agent (2)" return 1 fi if [ $? != 0 ]; then rm -f "$start_pidf" "$start_cshpidf" "$start_fishpidf" 2>/dev/null error "Failed to start ${start_prog}-agent" return 1 fi elif [ "$start_prog" = ssh -a -n "$inherit_ssh_auth_sock" ]; then start_out="SSH_AUTH_SOCK=$inherit_ssh_auth_sock; export SSH_AUTH_SOCK;" if [ "$inherit_ssh_agent_pid" -gt 0 ] 2>/dev/null; then start_out="$start_out SSH_AGENT_PID=$inherit_ssh_agent_pid; export SSH_AGENT_PID;" fi elif [ "$start_prog" = ssh -a -n "$inherit_ssh2_auth_sock" ]; then start_out="SSH2_AUTH_SOCK=$inherit_ssh2_auth_sock; export SSH2_AUTH_SOCK; SSH2_AGENT_PID=$inherit_ssh2_agent_pid; export SSH2_AGENT_PID;" if [ "$inherit_ssh2_agent_pid" -gt 0 ] 2>/dev/null; then start_out="$start_out SSH2_AGENT_PID=$inherit_ssh2_agent_pid; export SSH2_AGENT_PID;" fi elif [ "$start_prog" = gpg -a -n "$inherit_gpg_agent_info" ]; then start_out="GPG_AGENT_INFO=$inherit_gpg_agent_info; export GPG_AGENT_INFO;" else die "something bad happened" # should never be here fi # Add content to pidfiles. # Some versions of ssh-agent don't understand -s, which means to # generate Bourne shell syntax. It appears they also ignore SHELL, # according to http://bugs.gentoo.org/show_bug.cgi?id=52874 # So make no assumptions. start_out=`echo "$start_out" | grep -v 'Agent pid'` case "$start_out" in setenv*) echo "$start_out" >"$start_cshpidf" echo "$start_out" | awk '{print $2"="$3" export "$2";"}' >"$start_pidf" ;; *) echo "$start_out" >"$start_pidf" echo "$start_out" | sed 's/;.*/;/' | sed 's/=/ /' | sed 's/^/setenv /' >"$start_cshpidf" echo "$start_out" | sed 's/;.*/;/' | sed 's/^\(.*\)=\(.*\);/set -e \1; and set -x -U \1 \2/' >"$start_fishpidf" ;; esac # Hey the agent should be started now... load it up! loadagents "$start_prog" } # synopsis: extract_fingerprints # Extract the fingerprints from standard input, returns space-separated list. # Utility routine for ssh_l and ssh_f extract_fingerprints() { while read ef_line; do case "$ef_line" in *\ *\ [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:*) # Sun SSH spits out different things depending on the type of # key. For example: # md5 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_dsa(DSA) # 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_rsa.pub echo "$ef_line" | cut -f3 -d' ' ;; *\ [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:*) # The more consistent OpenSSH format, we hope # 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_dsa (DSA) echo "$ef_line" | cut -f2 -d' ' ;; *) # Fall back to filename. Note that commercial ssh is handled # explicitly in ssh_l and ssh_f, so hopefully this rule will # never fire. warn "Can't determine fingerprint from the following line, falling back to filename" mesg "$ef_line" basename "$ef_line" | sed 's/[ (].*//' ;; esac done | xargs } # synopsis: ssh_l # Return space-separated list of known fingerprints ssh_l() { sl_mylist=`ssh-add -l 2>/dev/null` sl_retval=$? if $openssh; then # Error codes: # 0 success # 1 OpenSSH_3.8.1p1 on Linux: no identities (not an error) # OpenSSH_3.0.2p1 on HP-UX: can't connect to auth agent # 2 can't connect to auth agent case $sl_retval in 0) echo "$sl_mylist" | extract_fingerprints ;; 1) case "$sl_mylist" in *"open a connection"*) sl_retval=2 ;; esac ;; esac return $sl_retval elif $sunssh; then # Error codes (from http://docs.sun.com/db/doc/817-3936/6mjgdbvio?a=view) # 0 success (even when there are no keys) # 1 error case $sl_retval in 0) echo "$sl_mylist" | extract_fingerprints ;; 1) case "$sl_mylist" in *"open a connection"*) sl_retval=2 ;; esac ;; esac return $sl_retval else # Error codes: # 0 success - however might say "The authorization agent has no keys." # 1 can't connect to auth agent # 2 bad passphrase # 3 bad identity file # 4 the agent does not have the requested identity # 5 unspecified error if [ $sl_retval = 0 ]; then # Output of ssh-add -l: # The authorization agent has one key: # id_dsa_2048_a: 2048-bit dsa, agriffis@alpha.zk3.dec.com, Fri Jul 25 2003 10:53:49 -0400 # Since we don't have a fingerprint, just get the filenames *shrug* echo "$sl_mylist" | sed '2,$s/:.*//' | xargs fi return $sl_retval fi } # synopsis: ssh_f filename # Return finger print for a keyfile # Requires $openssh and $sunssh ssh_f() { sf_filename="$1" if $openssh || $sunssh; then if [ ! -f "$sf_filename.pub" ]; then warn "$sf_filename.pub missing; can't tell if $sf_filename is loaded" return 1 fi sf_fing=`ssh-keygen -l -f "$sf_filename.pub"` || return 1 echo "$sf_fing" | extract_fingerprints else # can't get fingerprint for ssh2 so use filename *shrug* basename "$sf_filename" fi return 0 } # synopsis: gpg_listmissing # Uses $gpgkeys # Returns a newline-separated list of keys found to be missing. gpg_listmissing() { unset glm_missing GPG_TTY=`tty` # Parse $gpgkeys into positional params to preserve spaces in filenames set -f # disable globbing glm_IFS="$IFS" # save current IFS IFS=" " # set IFS to newline set -- $gpgkeys IFS="$glm_IFS" # restore IFS set +f # re-enable globbing for glm_k in "$@"; do # Check if this key is known to the agent. Don't know another way... if echo | env -i GPG_TTY="$GPG_TTY" PATH="$PATH" GPG_AGENT_INFO="$GPG_AGENT_INFO" \ gpg --no-options --use-agent --no-tty --sign --local-user "$glm_k" -o- >/dev/null 2>&1; then # already know about this key mesg "Known gpg key: ${CYANN}${glm_k}${OFF}" continue else # need to add this key if [ -z "$glm_missing" ]; then glm_missing="$glm_k" else glm_missing="$glm_missing $glm_k" fi fi done echo "$glm_missing" } # synopsis: ssh_listmissing # Uses $sshkeys and $sshavail # Returns a newline-separated list of keys found to be missing. ssh_listmissing() { unset slm_missing # Parse $sshkeys into positional params to preserve spaces in filenames set -f # disable globbing slm_IFS="$IFS" # save current IFS IFS=" " # set IFS to newline set -- $sshkeys IFS="$slm_IFS" # restore IFS set +f # re-enable globbing for slm_k in "$@"; do # Fingerprint current user-specified key slm_finger=`ssh_f "$slm_k"` || continue # Check if it needs to be added case " $sshavail " in *" $slm_finger "*) # already know about this key mesg "Known ssh key: ${CYANN}${slm_k}${OFF}" ;; *) # need to add this key if [ -z "$slm_missing" ]; then slm_missing="$slm_k" else slm_missing="$slm_missing $slm_k" fi ;; esac done echo "$slm_missing" } # synopsis: add_gpgkey # Adds a key to $gpgkeys add_gpgkey() { gpgkeys=${gpgkeys+"$gpgkeys "}"$1" } # synopsis: add_sshkey # Adds a key to $sshkeys add_sshkey() { sshkeys=${sshkeys+"$sshkeys "}"$1" } # synopsis: parse_mykeys # Sets $sshkeys and $gpgkeys based on $mykeys parse_mykeys() { # Parse $mykeys into positional params to preserve spaces in filenames set -f # disable globbing pm_IFS="$IFS" # save current IFS IFS=" " # set IFS to newline set -- $mykeys IFS="$pm_IFS" # restore IFS set +f # re-enable globbing for pm_k in "$@"; do # Check for ssh if wantagent ssh; then if [ -f "$pm_k" ]; then add_sshkey "$pm_k" ; continue elif [ -f "$HOME/.ssh/$pm_k" ]; then add_sshkey "$HOME/.ssh/$pm_k" ; continue elif [ -f "$HOME/.ssh2/$pm_k" ]; then add_sshkey "$HOME/.ssh2/$pm_k" ; continue fi fi # Check for gpg if wantagent gpg; then if [ -z "$pm_gpgsecrets" ]; then pm_gpgsecrets="`gpg --list-secret-keys 2>/dev/null | cut -d/ -f2 | cut -d' ' -f1 | xargs`" [ -z "$pm_gpgsecrets" ] && pm_gpgsecrets='/' # arbitrary fi case " $pm_gpgsecrets " in *" $pm_k "*) add_gpgkey "$pm_k" ; continue ;; esac fi $ignoreopt || warn "can't find $pm_k; skipping" continue done return 0 } # synopsis: setaction # Sets $myaction or dies if $myaction is already set setaction() { if [ -n "$myaction" ]; then die "you can't specify --$myaction and $1 at the same time" else myaction="$1" fi } # synopsis: in_path # Look for executables in the path in_path() { ip_lookfor="$1" # Parse $PATH into positional params to preserve spaces ip_IFS="$IFS" # save current IFS IFS=':' # set IFS to colon to separate PATH set -- $PATH IFS="$ip_IFS" # restore IFS for ip_x in "$@"; do [ -x "$ip_x/$ip_lookfor" ] || continue echo "$ip_x/$ip_lookfor" return 0 done return 1 } # synopsis: setagents # Check validity of agentsopt setagents() { if [ -n "$agentsopt" ]; then agentsopt=`echo "$agentsopt" | sed 's/,/ /g'` unset new_agentsopt for a in $agentsopt; do if in_path ${a}-agent >/dev/null; then new_agentsopt="${new_agentsopt+$new_agentsopt }${a}" else warn "can't find ${a}-agent, removing from list" fi done agentsopt="${new_agentsopt}" else for a in ssh gpg; do in_path ${a}-agent >/dev/null || continue agentsopt="${agentsopt+$agentsopt }${a}" done fi if [ -z "$agentsopt" ]; then die "no agents available to start" fi } # synopsis: wantagent prog # Return 0 (true) or 1 (false) depending on whether prog is one of the agents in # agentsopt wantagent() { case "$agentsopt" in "$1"|"$1 "*|*" $1 "*|*" $1") return 0 ;; *) return 1 ;; esac } # # MAIN PROGRAM # # parse the command-line while [ -n "$1" ]; do case "$1" in --help|-h) setaction help ;; --stop|-k) # As of version 2.5, --stop takes an argument. For the sake of # backward compatibility, only eat the arg if it's one we recognize. if [ "$2" = mine ]; then stopwhich=mine; shift elif [ "$2" = others ]; then stopwhich=others; shift elif [ "$2" = all ]; then stopwhich=all; shift else # backward compat stopwhich=all-warn fi ;; --version|-V) setaction version ;; --agents) shift agentsopt="$1" ;; --attempts) shift if [ "$1" -gt 0 ] 2>/dev/null; then attempts=$1 else die "--attempts requires a numeric argument greater than zero" fi ;; --clear) clearopt=true $quickopt && die "--quick and --clear are not compatible" ;; --confirm) confirmopt=true ;; --dir) shift case "$1" in */.*) keydir="$1" ;; '') die "--dir requires an argument" ;; *) keydir="$1/.keychain" ;; # be backward-compatible esac ;; --env) shift if [ -z "$1" ]; then die "--env requires an argument" else envf="$1" fi ;; --eval) evalopt=true ;; --host) shift hostopt="$1" ;; --ignore-missing) ignoreopt=true ;; --inherit) shift case "$1" in local|any|local-once|any-once) inheritwhich="$1" ;; *) die "--inherit requires an argument (local, any, local-once or any-once)" ;; esac ;; --noinherit) inheritwhich=none ;; --noask) noaskopt=true ;; --nogui) noguiopt=true ;; --nolock) nolockopt=true ;; --lockwait) shift if [ "$1" -ge 0 ] 2>/dev/null; then lockwait="$1" else die "--lockwait requires an argument zero or greater." fi ;; --quick|-Q) quickopt=true $clearopt && die "--quick and --clear are not compatible" ;; --quiet|-q) quietopt=true ;; --nocolor) color=false ;; --timeout) shift if [ "$1" -gt 0 ] 2>/dev/null; then timeout=$1 else die "--timeout requires a numeric argument greater than zero" fi ;; --) shift IFS=" " mykeys=${mykeys+"$mykeys "}"$*" unset IFS break ;; -*) echo "$zero: unknown option $1" >&2 $evalopt && { echo; echo "false;"; } exit 1 ;; *) mykeys=${mykeys+"$mykeys "}"$1" ;; esac shift done # Set filenames *after* parsing command-line options to allow # modification of $keydir and/or $hostopt # # pidf holds the specific name of the keychain .ssh-agent-myhostname file. # We use the new hostname extension for NFS compatibility. cshpidf is the # .ssh-agent file with csh-compatible syntax. fishpidf is the .ssh-agent # file with fish-compatible syntax. lockf is the lockfile, used # to serialize the execution of multiple ssh-agent processes started # simultaneously [ -z "$hostopt" ] && hostopt="${HOSTNAME}" [ -z "$hostopt" ] && hostopt=`uname -n 2>/dev/null || echo unknown` pidf="${keydir}/${hostopt}-sh" cshpidf="${keydir}/${hostopt}-csh" fishpidf="${keydir}/${hostopt}-fish" olockf="${keydir}/${hostopt}-lock" lockf="${keydir}/${hostopt}-lockf" # Read the env snippet (especially for things like PATH, but could modify # basically anything) if [ -z "$envf" ]; then envf="${keydir}/${hostopt}-env" [ -f "$envf" ] || envf="${keydir}/env" [ -f "$envf" ] || unset envf fi if [ -n "$envf" ]; then . "$envf" fi # Don't use color if there's no terminal on stderr if [ -n "$OFF" ]; then tty <&2 >/dev/null 2>&1 || color=false fi #disable color if necessary, right before our initial newline $color || unset BLUE CYAN CYANN GREEN PURP OFF RED qprint #initial newline mesg "${PURP}keychain ${OFF}${CYANN}${version}${OFF} ~ ${GREEN}http://www.funtoo.org${OFF}" [ "$myaction" = version ] && { versinfo; exit 0; } [ "$myaction" = help ] && { versinfo; helpinfo; exit 0; } # Set up traps # Don't use signal names because they don't work on Cygwin. if $clearopt; then trap '' 2 # disallow ^C until we've had a chance to --clear trap 'droplock; exit 1' 1 15 # drop the lock on signal trap 'droplock; exit 0' 0 # drop the lock on exit else # Don't use signal names because they don't work on Cygwin. trap 'droplock; exit 1' 1 2 15 # drop the lock on signal trap 'droplock; exit 0' 0 # drop the lock on exit fi setagents # verify/set $agentsopt verifykeydir # sets up $keydir wantagent ssh && testssh # sets $openssh and $sunssh getuser # sets $me # Inherit agent info from the environment before loadagents wipes it out. # Always call this since it checks $inheritopt and sets variables accordingly. inheritagents # --stop: kill the existing ssh-agent(s) and quit if [ -n "$stopwhich" ]; then if [ "$stopwhich" = all-warn ]; then warn "--stop without an argument is deprecated; see --help" stopwhich=all fi takelock || die if [ "$stopwhich" = mine -o "$stopwhich" = others ]; then loadagents $agentsopt fi for a in $agentsopt; do stopagent $a done if [ "$stopwhich" != others ]; then qprint exit 0 # stopagent is always successful fi fi # Note regarding locking: if we're trying to be quick, then don't take the lock. # It will be taken later if we discover we can't be quick. if $quickopt; then loadagents $agentsopt # sets ssh_auth_sock, ssh_agent_pid, etc unset nagentsopt for a in $agentsopt; do needstart=true # Trying to be quick has a price... If we discover the agent isn't running, # then we'll have to check things again (in startagent) after taking the # lock. So don't do the initial check unless --quick was specified. if [ $a = ssh ]; then sshavail=`ssh_l` # try to use existing agent # 0 = found keys, 1 = no keys, 2 = no agent if [ $? = 0 -o \( $? = 1 -a -z "$mykeys" \) ]; then mesg "Found existing ssh-agent: ${CYANN}$ssh_agent_pid${OFF}" needstart=false fi elif [ $a = gpg ]; then # not much way to be quick on this if [ -n "$gpg_agent_pid" ]; then case " `findpids gpg` " in *" $gpg_agent_pid "*) mesg "Found existing gpg-agent: ${CYANN}$gpg_agent_pid${OFF}" needstart=false ;; esac fi fi if $needstart; then nagentsopt="$nagentsopt $a" elif $evalopt; then catpidf $a fi done agentsopt="$nagentsopt" fi # If there are no agents remaining, then bow out now... [ -n "$agentsopt" ] || { qprint; exit 0; } # There are agents remaining to start, and we now know we can't be quick. Take # the lock before continuing takelock || die loadagents $agentsopt unset nagentsopt for a in $agentsopt; do if startagent $a; then nagentsopt="${nagentsopt+$nagentsopt }$a" $evalopt && catpidf $a fi done agentsopt="$nagentsopt" # If there are no agents remaining, then duck out now... [ -n "$agentsopt" ] || { qprint; exit 0; } # --timeout translates almost directly to ssh-add -t, but ssh.com uses # minutes and OpenSSH uses seconds if [ -n "$timeout" ] && wantagent ssh; then ssh_timeout=$timeout if $openssh || $sunssh; then ssh_timeout=`expr $ssh_timeout \* 60` fi ssh_timeout="-t $ssh_timeout" fi # --confirm translates to ssh-add -c if $confirmopt && wantagent ssh; then if $openssh || $sunssh; then ssh_confirm=-c else warn "--confirm only works with OpenSSH" fi fi # --clear: remove all keys from the agent(s) if $clearopt; then for a in ${agentsopt}; do if [ $a = ssh ]; then sshout=`ssh-add -D 2>&1` if [ $? = 0 ]; then mesg "ssh-agent: $sshout" else warn "ssh-agent: $sshout" fi elif [ $a = gpg ]; then kill -1 $gpg_agent_pid 2>/dev/null mesg "gpg-agent: All identities removed." else warn "--clear not supported for ${a}-agent" fi done trap 'droplock' 2 # done clearing, safe to ctrl-c fi # --noask: "don't ask for keys", so we're all done $noaskopt && { qprint; exit 0; } # Parse $mykeys into ssh vs. gpg keys; it may be necessary in the future to # differentiate on the cmdline parse_mykeys || die # Load ssh keys if wantagent ssh; then sshavail=`ssh_l` # update sshavail now that we're locked sshkeys="`ssh_listmissing`" # cache list of missing keys, newline-separated sshattempts=$attempts savedisplay="$DISPLAY" # Attempt to add the keys while [ -n "$sshkeys" ]; do mesg "Adding ${CYANN}"`echo "$sshkeys" | wc -l`"${OFF} ssh key(s): `echo $sshkeys`" # Parse $sshkeys into positional params to preserve spaces in filenames. # This *must* happen after any calls to subroutines because pure Bourne # shell doesn't restore "$@" following a call. Eeeeek! set -f # disable globbing old_IFS="$IFS" # save current IFS IFS=" " # set IFS to newline set -- $sshkeys IFS="$old_IFS" # restore IFS set +f # re-enable globbing if $noguiopt || [ -z "$SSH_ASKPASS" -o -z "$DISPLAY" ]; then unset DISPLAY # DISPLAY="" can cause problems unset SSH_ASKPASS # make sure ssh-add doesn't try SSH_ASKPASS sshout=`ssh-add ${ssh_timeout} ${ssh_confirm} "$@" 2>&1` else sshout=`ssh-add ${ssh_timeout} ${ssh_confirm} "$@" 2>&1 /dev/null 2>&1 [ $? != 0 ] && tryagain=true done $tryagain || break if [ $gpgattempts = 1 ]; then die "Problem adding (is pinentry installed?); giving up" else warn "Problem adding; trying again" fi # Update the list of missing keys gpgkeys="`gpg_listmissing`" # remember, newline-separated # Decrement the countdown gpgattempts=`expr $gpgattempts - 1` done fi qprint # trailing newline # vim:sw=4 expandtab tw=80 keychain-2.7.1/keychain.spec0000644000000000000000000000224311371046301014456 0ustar rootrootName: keychain Version: 2.7.1 Release: 1 Summary: agent manager for OpenSSH, ssh.com, Sun SSH, and GnuPG Packager: Daniel Robbins URL: http://www.funtoo.org Source0: %{url}%{name}-%{version}.tar.bz2 License: GPL v2 Group: Applications/Internet BuildArch: noarch Requires: /bin/sh sh-utils Prefix: /usr/bin BuildRoot: %{_tmppath}/%{name}-root %description Keychain is a manager for OpenSSH, ssh.com, Sun SSH and GnuPG agents. It acts as a front-end to the agents, allowing you to easily have one long-running agent process per system, rather than per login session. This reduces the number of times you need to enter your passphrase from once per new login session to once every time your local machine is rebooted. %prep %setup -q %build %install [ $RPM_BUILD_ROOT != / ] && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/%{_bindir} $RPM_BUILD_ROOT/%{_mandir}/man1 install -m0755 keychain $RPM_BUILD_ROOT/%{_bindir}/keychain install -m0644 keychain.1 $RPM_BUILD_ROOT/%{_mandir}/man1 %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_bindir}/* %doc %{_mandir}/*/* %doc ChangeLog COPYING keychain.pod README.rst keychain-2.7.1/VERSION0000664000000000000000000000000611371046276013067 0ustar rootroot2.7.1 keychain-2.7.1/README.rst0000664000000000000000000003350011371046276013513 0ustar rootroot======================== Introduction to Keychain ======================== :keywords: keychain, funtoo, gentoo, Daniel Robbins :description: This page contains information about Keychain, an OpenSSH and commercial SSH2-compatible RSA/DSA key management application. :version: 2010.05.07 :author: Daniel Robbins :contact: drobbins@funtoo.org :copyright: funtoo :language: English Introduction ============ .. _keychain git repository: http://www.github.com/funtoo/keychain .. _Common Threads\: OpenSSH key management, Part 1: http://www.ibm.com/developerworks/library/l-keyc.html .. _Common Threads\: OpenSSH key management, Part 2: http://www.ibm.com/developerworks/library/l-keyc2/ .. _Common Threads\: OpenSSH key management, Part 3: http://www.ibm.com/developerworks/library/l-keyc3/ .. _OpenSSH: http://www.openssh.com .. _funtoo-dev mailing list: http://groups.google.com/group/funtoo-dev .. _#funtoo irc channel: irc://irc.freenode.net/funtoo ``Keychain`` helps you to manage ssh and GPG keys in a convenient and secure manner. It acts as a frontend to ``ssh-agent`` and ``ssh-add``, but allows you to easily have one long running ``ssh-agent`` process per system, rather than the norm of one ``ssh-agent`` per login session. This dramatically reduces the number of times you need to enter your passphrase. With ``keychain``, you only need to enter a passphrase once every time your local machine is rebooted. ``Keychain`` also makes it easy for remote cron jobs to securely "hook in" to a long running ``ssh-agent`` process, allowing your scripts to take advantage of key-based logins. Download and Resources ====================== The latest release of keychain is version ``2.7.1``, and was released on May 7, 2010. The current version of keychain supports ``gpg-agent`` as well as ``ssh-agent``. Keychain is compatible with many operating systems, including ``AIX``, ``*BSD``, ``Cygwin``, ``MacOS X``, ``Linux``, ``HP/UX``, ``Tru64 UNIX``, ``IRIX``, ``Solaris`` and ``GNU Hurd``. .. _keychain 2.7.1: http://www.funtoo.org/archive/keychain/keychain-2.7.1.tar.bz2 .. _keychain 2.7.0 MacOS X package: http://www.funtoo.org/archive/keychain/keychain-2.7.0-macosx.tar.gz .. _keychain 2.6.9 MacOS X package: http://www.funtoo.org/archive/keychain/keychain-2.6.9-macosx.tar.gz Download -------- - *Release Archive* - `keychain 2.7.1`_ - *Apple MacOS X Packages* - `keychain 2.7.0 MacOS X package`_ - `keychain 2.6.9 MacOS X package`_ Keychain development sources can be found in the `keychain git repository`_. Please use the `funtoo-dev mailing list`_ and `#funtoo irc channel`_ for keychain support questions as well as bug reports. Quick Setup =========== Linux ----- To install under Gentoo or Funtoo Linux, type ``emerge keychain``. For other Linux distributions, use your distribution's package manager. Then generate RSA/DSA keys if necessary. The quick install docs assume you have a DSA key pair named ``id_dsa`` and ``id_dsa.pub`` in your ``~/.ssh/`` directory. Add the following to your ``~/.bash_profile``:: eval `keychain --eval --agents ssh id_dsa` If you want to take advantage of GPG functionality, ensure that GNU Privacy Guard is installed and omit the ``--agents ssh`` option above. Apple MacOS X ------------- To install under MacOS X, install the MacOS X package for keychain. Assuming you have an ``id_dsa`` and ``id_dsa.pub`` key pair in your ``~/.ssh/`` directory, add the following to your ``~/.bash_profile``:: eval `keychain --eval --agents ssh --inherit any id_dsa` The ``--inherit any`` option above causes keychain to inherit any ssh key passphrases stored in your Apple MacOS Keychain. If you would prefer for this to not happen, then this option can be omitted. Background ========== You're probably familiar with ``ssh``, which has become a secure replacement for the venerable ``telnet`` and ``rsh`` commands. Typically, when one uses ``ssh`` to connect to a remote system, one supplies a secret passphrase to ``ssh``, which is then passed in encrypted form over the network to the remote server. This passphrase is used by the remote ``sshd`` server to determine if you should be granted access to the system. However, `OpenSSH` and nearly all other SSH clients and servers have the ability to perform another type of authentication, called asymmetric public key authentication, using the RSA or DSA authentication algorithms. They are very useful, but can also be complicated to use. ``keychain`` has been designed to make it easy to take advantage of the benefits of RSA and DSA authentication. Generating a Key Pair ===================== To use RSA and DSA authentication, first you use a program called ``ssh-keygen`` (included with OpenSSH) to generate a *key pair* -- two small files. One of the files is the *public key*. The other small file contains the *private key*. ``ssh-keygen`` will ask you for a passphrase, and this passphrase will be used to encrypt your private key. You will need to supply this passphrase to use your private key. If you wanted to generate a DSA key pair, you would do this:: # ssh-keygen -t dsa Generating public/private dsa key pair. You would then be prompted for a location to store your key pair. If you do not have one currently stored in ``~/.ssh``, it is fine to accept the default location:: Enter file in which to save the key (/root/.ssh/id_dsa): /var/tmp/id_dsa Then, you are prompted for a passphrase. This passphrase is used to encrypt the *private key* on disk, so even if it is stolen, it will be difficult for someone else to use it to successfully authenticate as you with any accounts that have been configured to recognize your public key. Note that conversely, if you **do not** provide a passphrase for your private key file, then your private key file **will not** be encrypted. This means that if someone steals your private key file, *they will have the full ability to authenticate with any remote accounts that are set up with your public key.* Below, I have supplied a passphrase so that my private key file will be encrypted on disk:: Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /var/tmp/id_dsa. Your public key has been saved in /var/tmp/id_dsa.pub. The key fingerprint is: 5c:13:ff:46:7d:b3:bf:0e:37:1e:5e:8c:7b:a3:88:f4 root@devbox-ve The key's randomart image is: +--[ DSA 1024]----+ | . | | o . | | o . ..o| | . . . o +| | S o. | | . o.| | . ..++| | . o . =o*| | . E .+*.| +-----------------+ Setting up Authentication ========================= Here's how you use these files to authenticate with a remote server. On the remote server, you would append the contents of your *public key* to the ``~.ssh/authorized_keys`` file, if such a file exists. If it doesn't exist, you can simply create a new ``authorized_keys`` file in the remote account's ``~/.ssh`` directory that contains the contents of your local ``id_dsa.pub`` file. Then, if you weren't going to use ``keychain``, you'd perform the following steps. On your local client, you would start a program called ``ssh-agent``, which runs in the background. Then you would use a program called ``ssh-add`` to tell ``ssh-agent`` about your secret private key. Then, if you've set up your environment properly, the next time you run ``ssh``, it will find ``ssh-agent`` running, grab the private key that you added to ``ssh-agent`` using ``ssh-add``, and use this key to authenticate with the remote server. Again, the steps in the previous paragraph is what you'd do if ``keychain`` wasn't around to help. If you are using ``keychain``, and I hope you are, you would simply add the following line to your ``~/.bash_profile``:: eval `keychain --eval id_dsa` The next time you log in or source your ``~/.bash_profile``, ``keychain`` will start, start ``ssh-agent`` for you if it has not yet been started, use ``ssh-add`` to add your ``id_dsa`` private key file to ``ssh-agent``, and set up your shell environment so that ``ssh`` will be able to find ``ssh-agent``. If ``ssh-agent`` is already running, ``keychain`` will ensure that your ``id_dsa`` private key has been added to ``ssh-agent`` and then set up your environment so that ``ssh`` can find the already-running ``ssh-agent``. It will look something like this: .. figure:: keychain-1.png :alt: Keychain starts for the first time after login Note that when ``keychain`` runs for the first time after your local system has booted, you will be prompted for a passphrase for your private key file if it is encrypted. But here's the nice thing about using ``keychain`` -- even if you are using an encrypted private key file, you will only need to enter your passphrase when your system first boots (or in the case of a server, when you first log in.) After that, ``ssh-agent`` is already running and has your decrypted private key cached in memory. So if you open a new shell, you will see something like this: .. figure:: keychain-2.png :alt: Keychain finds existing ssh-agent and gpg-agent, and doesn't prompt for passphrase This means that you can now ``ssh`` to your heart's content, without supplying a passphrase. You can also execute batch ``cron`` jobs and scripts that need to use ``ssh`` or ``scp``, and they can take advantage of passwordless RSA/DSA authentication as well. To do this, you would add the following line to the top of a bash script:: eval `keychain --noask --eval id_dsa` || exit 1 The extra ``--noask`` option tells ``keychain`` that it should not prompt for a passphrase if one is needed. Since it is not running interactively, it is better for the script to fail if the decrypted private key isn't cached in memory via ``ssh-agent``. Keychain Options ================ Specifying Agents ----------------- In the images above, you will note that ``keychain`` starts ``ssh-agent``, but also starts ``gpg-agent``. Modern versions of ``keychain`` also support caching decrypted GPG keys via use of ``gpg-agent``, and will start ``gpg-agent`` by default if it is available on your system. To avoid this behavior and only start ``ssh-agent``, modify your ``~/.bash_profile`` as follows:: eval `keychain --agents ssh --eval id_dsa` || exit 1 The additional ``--agents ssh`` option tells ``keychain`` just to manage ``ssh-agent``, and ignore ``gpg-agent`` even if it is available. Clearing Keys ------------- Sometimes, it might be necessary to flush all cached keys in memory. To do this, type:: keychain --clear Any agent(s) will continue to run. Improving Security ------------------ To improve the security of ``keychain``, some people add the ``--clear`` option to their ``~/.bash_profile`` ``keychain`` invocation. The rationale behind this is that any user logging in should be assumed to be an intruder until proven otherwise. This means that you will need to re-enter any passphrases when you log in, but cron jobs will still be able to run when you log out. Stopping Agents --------------- If you want to stop all agents, which will also of course cause your keys/identities to be flushed from memory, you can do this as follows:: keychain -k all If you have other agents running under your user account, you can also tell ``keychain`` to just stop only the agents that ``keychain`` started:: keychain -k mine Learning More ============= The instructions above will work on any system that uses ``bash`` as its default shell, such as most Linux systems and Mac OS X. To learn more about the many things that ``keychain`` can do, including alternate shell support, consult the keychain man page, or type ``keychain --help | less`` for a full list of command options. I also recommend you read my original series of articles about `OpenSSH`_ that I wrote for IBM developerWorks, called ``OpenSSH Key Management``. Please note that ``keychain`` 1.0 was released along with Part 2 of this article, which was written in 2001. ``keychain`` has changed quite a bit since then. In other words, read these articles for the conceptual and `OpenSSH`_ information, but consult the ``keychain`` man page for command-line options and usage instructions :) - `Common Threads: OpenSSH key management, Part 1`_ - Understanding RSA/DSA Authentication - `Common Threads: OpenSSH key management, Part 2`_ - Introducing ``ssh-agent`` and ``keychain`` - `Common Threads: OpenSSH key management, Part 3`_ - Agent forwarding and ``keychain`` improvements As mentioned at the top of the page, ``keychain`` development sources can be found in the `keychain git repository`_. Please use the `funtoo-dev mailing list`_ and `#funtoo irc channel`_ for keychain support questions as well as bug reports. Project History =============== Daniel Robbins originally wrote ``keychain`` 1.0 through 2.0.3. 1.0 was written around June 2001, and 2.0.3 was released in late August, 2002. After 2.0.3, ``keychain`` was maintained by various Gentoo developers, including Seth Chandler, Mike Frysinger and Robin H. Johnson, through July 3, 2003. On April 21, 2004, Aron Griffis committed a major rewrite of ``keychain`` which was released as 2.2.0. Aron continued to actively maintain and improve ``keychain`` through October 2006 and the ``keychain`` 2.6.8 release. He also made a few commits after that date, up through mid-July, 2007. At this point, ``keychain`` had reached a point of maturity. .. _bugs.gentoo.org: http://bugs.gentoo.org In mid-July, 2009, Daniel Robbins migrated Aron's mercurial repository to git and set up a new project page on funtoo.org, and made a few bug fix commits to the git repo that had been collecting in `bugs.gentoo.org`_. Daniel continues to maintain ``keychain`` and supporting documentation on funtoo.org, and plans to make regular maintenance releases of ``keychain`` as needed. keychain-2.7.1/ChangeLog0000664000000000000000000005310311371046276013577 0ustar rootroot# ChangeLog for Keychain; http://www.funtoo.org # # Copyright 2002-2006 Gentoo Foundation http://www.gentoo.org/ # Copyright 2007 Aron Griffis # Copyright 2009-2010 Funtoo Technolgies, LLC. # lockfile() Copyright 2009 Parallels, Inc. # Distributed under the GNU General Public License version 2 # Originally authored by Daniel Robbins # Maintained August 2002 - April 2003 by Seth Chandler # Maintained and rewritten April 2004 - July 2007 by Aron Griffis # Maintained July 2009 - present by Daniel Robbins * keychain 2.7.1 (07 May 2010) 07 May 2010; Daniel Robbins : Addition of a "make clean" target. removal of runtests as it is currently broken. 07 May 2010; Daniel Robbins : New release process in Makefile and release.sh - keychain release tarball will now contain pre-generated keychain, keychain.1 and keychain.spec so that users do not need to run "make". Updated README.rst to refer to the "source code" as a "release archive" since it contains both source code and ready-to-go script and man page. 14 Apr 2010; Daniel Robbins : GPG fix from Gentoo bug 203871; from Frederic Bathelery. This fix will fix the issue with pinentry starting in the background and not showing up in the terminal. 20 Feb 2010; Daniel Robbins : MacOS X documentation fix from James Turnbull. * keychain 2.7.0 (23 Oct 2009) 23 Oct 2009; Daniel Robbins : updated README.rst with 2.7.0 and MacOS X package update. 18 Oct 2009; Daniel Robbins : lockfile() replacement from Parallels Inc. OpenVZ code, takelock() rewrite, resulting in ~100 line code savings. Default lock timeout set to 5 seconds, and now keychain will try to forcefully acquire the lock if the timeout aborts, rather than simply failing and aborting. 30 Sep 2009; Daniel Robbins : MacOS X/BSD improvements: fix sed call in Makefile for MacOS X and presumably other *BSD environments, Rename COPYING to COPYING.txt, slight COPYING.txt formatting changes to allow license to display more cleanly from MacOS X .pkg automated install. Fixed POD errors (removed '=end'). 29 Sep 2009; Daniel Robbins : disable "Identity added" messages when --quiet is specified (Gentoo bug #250328, thanks to Richard Laager,) --help will print output to stdout (Gentoo bug #196060, thanks to Elan Ruusame,) output cleanup and colorization changes - moving away from blue and over to cyan as it displays better terminals with black background. Also some additional colorization. Version bump to 2.6.10. * keychain 2.6.9 (26 Jul 2009) 26 Jul 2009; Daniel Robbins : Close Gentoo bug 222953 from Bernd Petrovitsch to fix potential issues with GNU grep, Mac OS X color fix when called with --eval from Aron Griffis , Perl 5.10 Makefile fix from Aron Griffis . Transition README to README.rst (reStructuredText). Updated maintainership information. Simplified default output ( --version or --help now required to show version, copyright and license information.) * keychain 2.6.8 (24 Oct 2006) 24 Oct 2006; Aron Griffis : Save LC_ALL for gpg invocation so that pinentry-curses works. This affected peper and kloeri, though it seems to work for me in any case. * keychain 2.6.7 (24 Oct 2006) 24 Oct 2006; Aron Griffis : Prevent gpg_listmissing from accidentally loading keys * keychain 2.6.6 (08 Sep 2006) 08 Sep 2006; Aron Griffis : Make --lockwait -1 mean forever. Previously 0 meant forever but was undocumented. Add more locking regression tests #137981 * keychain 2.6.5 (08 Sep 2006) 08 Sep 2006; Aron Griffis : Break out of loop when empty lockfile can't be removed #127471. Add locking regression tests: 100_lock_stale 101_lock_held 102_lock_empty 103_lock_empty_cant_remove * keychain 2.6.4 (08 Sep 2006) 08 Sep 2006; Aron Griffis : Add validinherit function so that validity of SSH_AUTH_SOCK and friends can be validated from startagent rather than up front. The advantage is that warning messages aren't emitted unnecessarily when --inherit *-once. Fix --eval for fish, and add new testcases: 053_start_with_--eval_ksh 054_start_with_--eval_fish 055_start_with_--eval_csh * keychain 2.6.3 (07 Sep 2006) 07 Sep 2006; Aron Griffis : Support fish: http://roo.no-ip.org/fish/ Thanks to Ilkka Poutanen for the patch. * keychain 2.6.2 (20 Mar 2006) 20 Mar 2006; Aron Griffis : Add --confirm option and corresponding regression tests for Debian bug 296382. Thanks to Liyang HU for the patch. Also add initialization for $ssh_timeout which was being inherited from the environment and add regression tests for --timeout * keychain 2.6.1 (10 Oct 2005) 10 Oct 2005; Aron Griffis : Change "unset evalopt" to "evalopt=false" and run through *all* the regression tests instead of just the new ones. *sigh* * keychain 2.6.0 (10 Oct 2005) 10 Oct 2005; Aron Griffis : Add the --eval option which makes keychain startup easier. See the man-page for examples. Get rid of the release notes from README, so now this file is where changes are tracked. * keychain 2.5.5 (28 Jul 2005) 28 Jul 2005; Aron Griffis : Add the --env option and automatic reading of .keychain/env. This allows variables such as PATH to be overridden for peculiar environments * keychain 2.5.4.1 (11 May 2005) 11 May 2005; Aron Griffis : 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 * keychain 2.5.4 (11 May 2005) 11 May 2005; Aron Griffis : Fix bug 92316: If any locale variables are set, override them with LC_ALL=C. This fixes a multibyte issue with awk that could keep a running ssh-agent from being found. Fix bug 87340: Use files instead of symlinks for locking, since symlink creation is not atomic on cygwin. * keychain 2.5.3.1 (10 Mar 2005) 10 Mar 2005; Aron Griffis : Fix problem introduced in 2.5.3 wrt adding gpg keys to the agent. Thanks to Azarah for spotting it. * keychain 2.5.3 (09 Mar 2005) 09 Mar 2005; Aron Griffis : Improve handling of DISPLAY by unsetting if blank. Call gpg with --use-agent explicitly. * keychain 2.5.2 (06 Mar 2005) 06 Mar 2005; Aron Griffis : Fix bug 78974 "keychain errors on Big/IP (x86 BSD variant)" by refraining from using ! in conditional expressions. Fix RSA fingerprint extraction on Solaris, reported in email by Travis Fitch. Use $HOSTNAME when possible instead of calling uname -n to improve bash_profile compatibility. * keychain 2.5.1 (12 Jan 2005) 12 Jan 2005; Aron Griffis : Don't accidentally inherit a forwarded agent when inheritwhich=local-once. Move the --stop warning after the version splash. * keychain 2.5.0 (07 Jan 2005) 07 Jan 2005; Aron Griffis : Add inheritance support via --inherit. Add parameters to --stop for more control. Change the default behavior of keychain to inherit if there's no keychain agent running ("--inherit local-once"), and refrain from killing other agents unless "--stop others" is specified. * keychain 2.4.3 (17 Nov 2004) 17 Nov 2004; Aron Griffis : Fix bug 69879: Update findpids to work again on BSD; it has been broken since the changes in version 2.4.2. Now we use OSTYPE (bash) or uname to determine the system type and call ps appropriately. * keychain 2.4.2.1 (30 Sep 2004) 30 Sep 2004; Aron Griffis : Fix minor issues in the test for existing gpg keys wrt DISPLAY * keychain 2.4.2 (29 Sep 2004) 29 Sep 2004; Aron Griffis : Make gpg support more complete. Allow adding keys, clearing the agent, etc. Fix --quick support to work properly again; it was broken since 2.4.0. Change default --attempts to 1 since the progs ask multiple times anyway. * keychain 2.4.1 (22 Sep 2004) 22 Sep 2004; Aron Griffis : Fix bugs 64174 and 64178; support Sun SSH, which is really OpenSSH in disguise and a few critical outputs changed. Thanks to Nathan Bardsley for lots of help debugging on Solaris 9 15 Sep 2004; Aron Griffis : Fix pod2man output so it formats properly on SGI systems. Thanks to Matthew Moore for reporting the problem. * keychain 2.4.0 (09 Sep 2004) 09 Sep 2004; Aron Griffis : Fix bug 26970 with first pass at gpg-agent support Fix Debian bug 269722; don't filter output of ssh-add Fix bug reported by Marko Myllynen regarding keychain and Solaris awk's inability to process -F'[ :]' Fix bug in now_seconds calculation, noticed by me. * keychain 2.3.5 (28 Jul 2004) 28 Jul 2004; Aron Griffis : Fix bug 58623 with patch from Daniel Westermann-Clark; don't put an extra newline in the output of listmissing Generate keychain.spec from keychain.spec.in automatically so that the version can be set appropriately. * keychain 2.3.4 (24 Jul 2004) 24 Jul 2004; Aron Griffis : Fix bug 28599 reported by Bruno Pelaia; ignore defunct processes in ps output * keychain 2.3.3 (30 Jun 2004) 30 Jun 2004; Aron Griffis : Fix bug reported by Matthew S. Moore in email; escape the backticks in --help output Fix bug reported by Herbie Ong in email; set pidf, cshpidf and lockf variables after parsing command-line to honor --dir setting Fix bug reported by Stephan Stahl in email; make spaces in filenames work throughout keychain, even in pure Bourne shell Fix operation on HP-UX with older OpenSSH by interpreting output of ssh-add as well as the error status * keychain 2.3.2 (16 Jun 2004) 16 Jun 2004; Aron Griffis : Fix bug 53837 (keychain needs ssh-askpass) by unsetting SSH_ASKPASS when --nogui is specified * keychain 2.3.1 (03 Jun 2004) 03 Jun 2004; Aron Griffis : Fix bug 52874: problems when the user is running csh * keychain 2.3.0 (14 May 2004) 14 May 2004; Aron Griffis : Rewrite the locking code to avoid procmail * keychain 2.2.2 (03 May 2004) 03 May 2004; Aron Griffis : Call loadagent prior to generating HOSTNAME-csh file so that variables are set. * keychain 2.2.1 (27 Apr 2004) 27 Apr 2004; Aron Griffis : Find running ssh-agent processes by searching for /[s]sh-agen/ instead of /[s]sh-agent/ for the sake of Solaris, which cuts off ps -u output at 8 characters. Thanks to Clay England for reporting the problem and testing the fix. * keychain 2.2.0 (21 Apr 2004) 21 Apr 2004; Aron Griffis : Rewrote most of the code, organized into functions, fixed speed issues involving ps, fixed compatibility issues for various UNIXes, hopefully didn't introduce too many bugs. This version has a --quick option (for me) and a --timeout option (for carpaski). Also added a Makefile and converted the man-page to pod for easier editing. See perlpod(1) for information on the format. Note that the pod is sucked into keychain and colorized when you run make. * keychain 2.0.3 (06 Apr 2003) 06 Apr 2003; Seth Chandler : Added keychain man page, fixed bugs with displaying colors for keychain --help. Also added a $grepopts to fix the grepping for a pid on cygwin Also added a TODO document color fix based on submission by Luke Holden * keychain 2.0.2 (26 Aug 2002) 26 Aug 2002; the Tru64 fix didn't work; it was being caused by "trap - foo" rather than "tail +2 -". Now really fixed. 26 Aug 2002; fixed "ssh-add" call to only redirect stdin (thus enabling ssh-askpass) if ssh_askpass happens to be set; this is to work around a bug in openssh were redirecting stdin will enable ssh-askpass even if ssh_askpass isn't set, which contradicts the openssh 3.4_p1 man page. to enable ssh-askpass, keychain now requires that the ssh_askpass var be set to point to your askpass program. * keychain 2.0.1 (24 Aug 2002) 24 Aug 2002; "--help" fixes; the keychain files were listed as sh-${HOSTNAME} rather than ${HOSTNAME}-sh. Now consistent with the actual program. Thanks to Christian Plessl , others for reporting this issue. 24 Aug 2002; cycloon : "If you add < /dev/null when adding the missingkeys via "ssh-add ${missingkeys}" (at line 454 of version 2.0) so that it reads: "ssh-add ${missingkeys} < /dev/null" then users can use program like x11-ssh-askpass in xfree to type in their passphrase. It then still works for users on shell, depending if $DISPLAY is set." Added. 24 Aug 2002; A fix to calling "tail" that *should* fix things for Tru64 Unix; unfortunately, I have no way to test but the solution should be portable to all other flavors of systems. Thanks to Mark Scarborough for reporting the issue. 24 Aug 2002; Changed around the psopts detection stuff so that "-x -u $me f" is used; this is needed on MacOS X. Thanks to Brian Bergstrand , others for reporting this issue. * keychain 2.0 (17 Aug 2002) 17 Aug 2002; (Many submitters): A fix for keychain when running on HP-UX 10.20. 17 Aug 2002; Patrice DUMAS - DOCT : Now perform help early on to avoid unnecessary processing. Also added --dir option to allow keychain to look in an alternate location for the .keychain directory (use like this: "keychain --dir /var/foo") 17 Aug 2002; Martial MICHEL : Martial also suggested moving help processing to earlier in the script. He also submitted a patch to place .ssh-agent-* files in a ~/.keychain/ directory, which makes sense particularly for NFS users so I integrated the concept into the code. 17 Aug 2002; Fred Carter : Cygwin fix to use proper "ps" options. 17 Aug 2002; Adrian Howard : patch so that lockfile gets removed even if --noask is specified. 17 Aug 2002; Mario Wolff : Replaced an awk dependency with a shell construct for improved performance. 17 Aug 2002; Marcus Stoegbauer , Dmitry Frolov : I (Daniel Robbins) solved problems reported by Marcus and Dmitry (mis-parsed command line issues) by following Dmitry's good suggestion of performing argument parsing all at once at the top of the script. 17 Aug 2002; Brian W. Curry : Added commercial SSH2 client support; improved output readability by initializing myfail=0; integrated Cygwin support into the main keychain script; improved Cygwin support by setting "trap" appropriately. Thanks Brian! * keychain 1.9 (04 Mar 2002) 04 Mar 2002; changed license from "GPL, v2 or later" to "GPL v2". 04 Mar 2002; added "keychain.cygwin" for Cygwin systems. It may be time to follow this pattern and start building separate, optimized scripts for each platform so they don't get too sluggish. Maybe I could use a C preprocessor for this. 06 Dec 2001; several people: Solaris doesn't like '-e' comparisons; switched to '-f' * keychain 1.8 (29 Nov 2001) 29 Nov 2001; Philip Hallstrom (philip@adhesivemedia.com) Added a "--local" option for removing the ${HOSTNAME} from the various files that keychain creates. Handy for non-NFS users. 29 Nov 2001; Aron Griffis (agriffis@gentoo.org) Using the Bourne shell "type" builtin rather than using the external "which" command. Should make things a lot more robust and slightly faster. 09 Nov 2001; Mike Briseno (mike@radik.com) Solaris' "which" command outputs "no lockfile in..." to stdout rather than stderr. A one-line fix (test the error condition) has been applied. 09 Nov 2001; lockfile settings tweak 09 Nov 2001; Rewrote how keychain detects failed passphrase attempts. If you stop making progress providing valid passphrases, it's three strikes and you're out. 09 Nov 2001; Constantine P. Sapuntzakis (csapuntz@stanford.edu) Some private keys can't be "ssh-keygen -l -f"'d; this patch causes keychain to look for the corresponding public key if the private key doesn't work. Thanks Constantine! 09 Nov 2001; Victor Leitman (vleitman@yahoo.com) CYAN color misdefined; fixed. 27 Oct 2001; Brian Wellington (bwelling@xbill.org) A "quiet mode" (--quiet) fix; I missed an "echo". 27 Oct 2001; J.A. Neitzel (jan@belvento.org) Missed another "kill -9"; it's now gone. * keychain 1.7 (21 Oct 2001) 21 Oct 2001; Frederic Gobry (frederic.gobry@smartdata.ch) Frederic suggested using procmail's lockfile to serialize the execution of critical parts of keychain, thus avoiding multiple ssh-agent processes being started if you happen to have multiple xterms open automatically when you log in. Initially, I didn't think I could add this, since systems may not have the lockfile command; however, keychain will now auto-detect whether lockfile is installed; if it is, keychain will automatically use it, thus preventing multiple ssh-agent processes from being spawned. 21 Oct 2001; Raymond Wu (ursus@usa.net): --nocolor test is no longer inside the test for whether "echo -e" works. According to Raymond, this works optimally on his Solaris box. 21 Oct 2001; J.A. Neitzel (jan@belvento.org): No longer "kill -9" our ssh-agent processes. SIGTERM should be sufficient and will allow ssh-agent to clean up after itself (this reverses a previously-applied patch). 21 Oct 2001; Thomas Finneid (tfinneid@online.no): Added argument "--quiet | -q" to make the program less intrusive to the user; with it, only error and interactive messages will appear. 21 Oct 2001; Thomas Finneid (tfinneid@online.no): Changed the format of some arguments to bring them more in line with common *nix programs: added "-h" as alias for "--help"; added "-k" as alias for "--stop" 21 Oct 2001; Mark Stosberg (mark@summersault.com): $pidf to "$pidf" fixes to allow keychain to work with paths that include spaces (for Darwin and MacOS X in particular). 21 Oct 2001; Jonathan Wakely (redi@redi.uklinux.net): Small patch to convert "echo -n -e" to "echo -e "\c"" for FreeBSD compatibility. * keychain 1.6 (15 Oct 2001) 13 Oct 2001; Ralf Horstmann (ralf.horstmann@webwasher.com): Add /usr/ucb to path for Solaris systems. 11 Oct 2001; Idea from Joe Reid (jreid@vnet.net): Try to add multiple keys using ssh-add; avoid typing in identical passphrases more than once. Good idea! *keychain 1.5 (21 Sep 2001) 21 Sep 2001; David Hull (hull@paracel.com): misc. compatibility, signal handling, cleanup fixes 21 Sep 2001; "ps" test to find the right one for your OS. 20 Sep 2001; Marko Myllynen (myllynen@lut.fi): "grep [s]sh-agent" to "grep [s]sh-agent" (zsh fix) *keychain 1.4 (20 Sep 2001) 20 Sep 2001; David Hull (hull@paracel.com): "touch $foo" to ">$foo" optimization and other "don't fork" fixes. Converted ${foo#--} to a case statement for Solaris sh compatibility. 20 Sep 2001; Try an alternate "ps" syntax if our default one fails. This should give us Solaris and IRIX (sysV) compatibility without breaking BSD. 20 Sep 2001; Hans Peter Verne (h.p.verne@usit.uio.no); "echo -e" to "echo $E" (for IRIX compatibility with --nocolor), optimization of grep ("grep [s]sh-agent") 17 Sep 2001; Marko Myllynen (myllynen@lut.fi): Various fixes: trap signal 2 if signal INT not supported (NetBSD); handle invalid keys correctly; ancient version of ash didn't support ~, so using $HOME; correct zsh instruction; minor cleanups *keychain 1.3 (12 Sep 2001) 12 Sep 2001; Minor color changes; the cyan was hard to read on xterm-colored terms so it was switched to bold. Additional --help text added. 10 Sep 2001; We now use .ssh-agent-[hostname] instead of .ssh-agent. We now create a .ssh-agent-csh-[hostname] file that can be sourced by csh-compatible shells. We also now kill all our existing ssh-agent processes before starting a new one. 10 Sep 2001; Robert R. Wal (rrw@hell.pl): Very nice NFS fixes, colorization fixes, tcsh redirect -> grep -v fix. Thanks go out to others who sent me similar patches. 10 Sep 2001; Johann Visagie (johann@egenetics.com): "source" to "." shell-compatibility fixes. Thanks for the FreeBSD port. 10 Sep 2001; Marko Myllynen (myllynen@lut.fi): rm -f $pidf after stopping ssh-agent fix *keychain 1.2 09 Sep 2001; README updates to reflect new changes. 09 Sep 2001; Marko Myllynen (myllynen@lut.fi): bash 1/zsh/sh compatibility; now only tries to kill *your* ssh-agent processes, version fix, .ssh-agent file creation error detection. Thanks! *keychain 1.1; fixes for calling "pidof"; README; ChangeLog 07 Sep 2001; Addition of README stating that keychain requires bash 2.0 or greater, as well as quick install directions and web URL. 07 Sep 2001; Explicitly added /sbin and /usr/sbin to path, and then called "pidof". I think that this is a bit more robust. 06 Sep 2001; from John Ellson (ellson@lucent.com): "pidof" changed to "/sbin/pidof", since it's probably not in $PATH 06 Sep 2001; New ChangeLog! :) *keychain 1.0; initial release (Aug 2001) keychain-2.7.1/keychain.spec.in0000664000000000000000000000225611371046276015104 0ustar rootrootName: keychain Version: KEYCHAIN_VERSION Release: 1 Summary: agent manager for OpenSSH, ssh.com, Sun SSH, and GnuPG Packager: Daniel Robbins URL: http://www.funtoo.org Source0: %{url}%{name}-%{version}.tar.bz2 License: GPL v2 Group: Applications/Internet BuildArch: noarch Requires: /bin/sh sh-utils Prefix: /usr/bin BuildRoot: %{_tmppath}/%{name}-root %description Keychain is a manager for OpenSSH, ssh.com, Sun SSH and GnuPG agents. It acts as a front-end to the agents, allowing you to easily have one long-running agent process per system, rather than per login session. This reduces the number of times you need to enter your passphrase from once per new login session to once every time your local machine is rebooted. %prep %setup -q %build %install [ $RPM_BUILD_ROOT != / ] && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/%{_bindir} $RPM_BUILD_ROOT/%{_mandir}/man1 install -m0755 keychain $RPM_BUILD_ROOT/%{_bindir}/keychain install -m0644 keychain.1 $RPM_BUILD_ROOT/%{_mandir}/man1 %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %{_bindir}/* %doc %{_mandir}/*/* %doc ChangeLog COPYING keychain.pod README.rst keychain-2.7.1/keychain0000755000000000000000000014247211371046301013541 0ustar rootroot#!/bin/sh # Copyright 1999-2005 Gentoo Foundation # Copyright 2007 Aron Griffis # Copyright 2009-2010 Funtoo Technologies, LLC # lockfile() Copyright 2009 Parallels, Inc. # Distributed under the terms of the GNU General Public License v2 # Originally authored by Daniel Robbins # Maintained August 2002 - April 2003 by Seth Chandler # Maintained and rewritten April 2004 - July 2007 by Aron Griffis # Maintained July 2009 - present by Daniel Robbins version=2.7.1 PATH="/usr/bin:/bin:/sbin:/usr/sbin:/usr/ucb:${PATH}" maintainer="drobbins@funtoo.org" zero=`basename "$0"` unset mesglog unset myaction unset agentsopt havelock=false unset hostopt ignoreopt=false noaskopt=false noguiopt=false nolockopt=false lockwait=5 openssh=unknown sunssh=unknown quickopt=false quietopt=false clearopt=false color=true inheritwhich=local-once unset stopwhich unset timeout unset ssh_timeout attempts=1 unset sshavail unset sshkeys unset gpgkeys unset mykeys keydir="${HOME}/.keychain" unset envf evalopt=false confirmopt=false unset ssh_confirm unset GREP_OPTIONS BLUE="" CYAN="" CYANN="" GREEN="" RED="" PURP="" OFF="" # GNU awk and sed have regex issues in a multibyte environment. If any locale # variables are set, then override by setting LC_ALL unset pinentry_locale lvars=`locale 2>/dev/null | egrep -v '="?(|POSIX|C)"?$' 2>/dev/null` if [ -n "$lvars$LANG$LC_ALL" ]; then # save LC_ALL so that pinentry-curses works right. This has always worked # correctly for me but peper and kloeri had problems with it. pinentry_lc_all="$LC_ALL" LC_ALL=C export LC_ALL fi # synopsis: qprint "message" qprint() { $quietopt || echo "$*" >&2 } # synopsis: mesg "message" # Prettily print something to stderr, honors quietopt mesg() { qprint " ${GREEN}*${OFF} $*" } # synopsis: warn "message" # Prettily print a warning to stderr warn() { echo " ${RED}* Warning${OFF}: $*" >&2 } # synopsis: error "message" # Prettily print an error error() { echo " ${RED}* Error${OFF}: $*" >&2 } # synopsis: die "message" # Prettily print an error, then abort die() { [ -n "$1" ] && error "$*" qprint $evalopt && { echo; echo "false;"; } exit 1 } # synopsis: versinfo # Display the version information versinfo() { qprint qprint " Copyright ${CYANN}2002-2006${OFF} Gentoo Foundation;" qprint " Copyright ${CYANN}2007${OFF} Aron Griffis;" qprint " Copyright ${CYANN}2009-2010${OFF} Funtoo Technologies, LLC;" qprint " lockfile() Copyright ${CYANN}2009${OFF} Parallels, Inc." qprint qprint " Keychain is free software: you can redistribute it and/or modify" qprint " it under the terms of the ${CYANN}GNU General Public License version 2${OFF} as" qprint " published by the Free Software Foundation." qprint } # synopsis: helpinfo # Display the help information. There's no really good way to use qprint for # this... helpinfo() { cat >&1 <&1`" in *OpenSSH*) openssh=true ;; *Sun?SSH*) sunssh=true ;; esac } # synopsis: getuser # Set the global string $me getuser() { # whoami gives euid, which might be different from USER or LOGNAME me=`whoami` || die "Who are you? whoami doesn't know..." } # synopsis: getos # Set the global string $OSTYPE getos() { OSTYPE=`uname` || die 'uname failed' } # synopsis: verifykeydir # Make sure the key dir is set up correctly. Exits on error. verifykeydir() { # Create keydir if it doesn't exist already if [ -f "${keydir}" ]; then die "${keydir} is a file (it should be a directory)" # Solaris 9 doesn't have -e; using -d.... elif [ ! -d "${keydir}" ]; then ( umask 0077 && mkdir "${keydir}"; ) || die "can't create ${keydir}" fi } lockfile() { # This function originates from Parallels Inc.'s OpenVZ vpsreboot script # Description: This function attempts to acquire the lock. If it succeeds, # it returns 0. If it fails, it returns 1. This function retuns immediately # and only tries to acquire the lock once. local tmpfile="$lockf.$$" echo $$ >"$tmpfile" 2>/dev/null || exit if ln "$tmpfile" "$lockf" 2>/dev/null; then rm -f "$tmpfile" havelock=true && return 0 fi if kill -0 `cat $lockf 2>/dev/null` 2>/dev/null; then rm -f "$tmpfile" return 1 fi if ln "$tmpfile" "$lockf" 2>/dev/null; then rm -f "$tmpfile" havelock=true && return 0 fi rm -f "$tmpfile" "$lockf" && return 1 } takelock() { # Description: This function calls lockfile() multiple times if necessary # to try to acquire the lock. It returns 0 on success and 1 on failure. # Change in behavior: if timeout expires, we will forcefully acquire lock. [ "$havelock" = "true" ] && return 0 [ "$nolockopt" = "true" ] && return 0 # First attempt: lockfile && return 0 local counter=0 mesg "Waiting $lockwait seconds for lock..." while [ "$counter" -lt "$(( $lockwait * 2 ))" ] do lockfile && return 0 sleep 0.5; counter=$(( $counter + 1 )) done rm -f "$lockf" && lockfile && return 0 return 1 } # synopsis: droplock # Drops the lock if we're holding it. droplock() { $havelock && [ -n "$lockf" ] && rm -f "$lockf" } # synopsis: findpids [prog] # Returns a space-separated list of agent pids. # prog can be ssh or gpg, defaults to ssh. Note that if another prog is ever # added, need to pay attention to the length for Solaris compatibility. findpids() { fp_prog=${1-ssh} unset fp_psout # Different systems require different invocations of ps. Try to generalize # the best we can. The only requirement is that the agent command name # appears in the line, and the PID is the first item on the line. [ -n "$OSTYPE" ] || getos # Try systems where we know what to do first case "$OSTYPE" in AIX|*bsd*|*BSD*|CYGWIN|darwin*|Linux|linux-gnu|OSF1) fp_psout=`ps x 2>/dev/null` ;; # BSD syntax HP-UX) fp_psout=`ps -u $me 2>/dev/null` ;; # SysV syntax SunOS) case `uname -r` in [56]*) fp_psout=`ps -u $me 2>/dev/null` ;; # SysV syntax *) fp_psout=`ps x 2>/dev/null` ;; # BSD syntax esac ;; GNU|gnu) fp_psout=`ps -g 2>/dev/null` ;; # GNU Hurd syntax esac # If we didn't get a match above, try a list of possibilities... # The first one will probably fail on systems supporting only BSD syntax. if [ -z "$fp_psout" ]; then fp_psout=`UNIX95=1 ps -u $me -o pid,comm 2>/dev/null | grep '^ *[0-9]'` [ -z "$fp_psout" ] && fp_psout=`ps x 2>/dev/null` fi # Return the list of pids; ignore case for Cygwin. # Check only 8 characters since Solaris truncates at that length. # Ignore defunct ssh-agents (bug 28599) if [ -n "$fp_psout" ]; then echo "$fp_psout" | \ awk "BEGIN{IGNORECASE=1} /defunct/{next} /$fp_prog-[a]gen/{print \$1}" | xargs return 0 fi # If none worked, we're stuck error "Unable to use \"ps\" to scan for $fp_prog-agent processes" error "Please report to $maintainer via http://bugs.gentoo.org" return 1 } # synopsis: stopagent [prog] # --stop tells keychain to kill the existing agent(s) # prog can be ssh or gpg, defaults to ssh. stopagent() { stop_prog=${1-ssh} eval stop_except=\$\{${stop_prog}_agent_pid\} stop_mypids=`findpids "$stop_prog"` [ $? = 0 ] || die if [ -z "$stop_mypids" ]; then mesg "No $stop_prog-agent(s) found running" return 0 fi case "$stopwhich" in all) kill $stop_mypids >/dev/null 2>&1 mesg "All ${CYANN}$me${OFF}'s $stop_prog-agents stopped: ${CYANN}$stop_mypids${OFF}" ;; others) # Try to handle the case where we *will* inherit a pid kill -0 $stop_except >/dev/null 2>&1 if [ -z "$stop_except" -o $? != 0 -o \ "$inheritwhich" = local -o "$inheritwhich" = any ]; then if [ "$inheritwhich" != none ]; then eval stop_except=\$\{inherit_${stop_prog}_agent_pid\} kill -0 $stop_except >/dev/null 2>&1 if [ -z "$stop_except" -o $? != 0 ]; then # Handle ssh2 eval stop_except=\$\{inherit_${stop_prog}2_agent_pid\} fi fi fi # Filter out the running agent pid unset stop_mynewpids for stop_x in $stop_mypids; do [ $stop_x -eq $stop_except ] 2>/dev/null && continue stop_mynewpids="${stop_mynewpids+$stop_mynewpids }$stop_x" done if [ -n "$stop_mynewpids" ]; then kill $stop_mynewpids >/dev/null 2>&1 mesg "Other ${CYANN}$me${OFF}'s $stop_prog-agents stopped: ${CYANN}$stop_mynewpids${OFF}" else mesg "No other $stop_prog-agent(s) than keychain's $stop_except found running" fi ;; mine) if [ $stop_except -gt 0 ] 2>/dev/null; then kill $stop_except >/dev/null 2>&1 mesg "Keychain $stop_prog-agents stopped: ${CYANN}$stop_except${OFF}" else mesg "No keychain $stop_prog-agent found running" fi ;; esac # remove pid files if keychain-controlled if [ "$stopwhich" != others ]; then if [ "$stop_prog" != ssh ]; then rm -f "${pidf}-$stop_prog" "${cshpidf}-$stop_prog" "${fishpidf}-$stop_prog" 2>/dev/null else rm -f "${pidf}" "${cshpidf}" "${fishpidf}" 2>/dev/null fi eval unset ${stop_prog}_agent_pid fi } # synopsis: inheritagents # Save agent variables from the environment before they get wiped out inheritagents() { # Verify these global vars are null unset inherit_ssh_auth_sock inherit_ssh_agent_pid unset inherit_ssh2_auth_sock inherit_ssh2_agent_sock unset inherit_gpg_agent_info inherit_gpg_agent_pid # Save variables so we can inherit a running agent if [ "$inheritwhich" != none ]; then if wantagent ssh; then if [ -n "$SSH_AUTH_SOCK" ]; then inherit_ssh_auth_sock="$SSH_AUTH_SOCK" inherit_ssh_agent_pid="$SSH_AGENT_PID" fi if [ -n "$SSH2_AUTH_SOCK" ]; then inherit_ssh2_auth_sock="$SSH2_AUTH_SOCK" inherit_ssh2_agent_pid="$SSH2_AGENT_PID" fi fi if wantagent gpg; then if [ -n "$GPG_AGENT_INFO" ]; then inherit_gpg_agent_info="$GPG_AGENT_INFO" inherit_gpg_agent_pid=`echo "$GPG_AGENT_INFO" | cut -f2 -d:` fi fi fi } # synopsis: validinherit # Test inherit_* variables for validity validinherit() { vi_agent="$1" vi_status=0 if [ "$vi_agent" = ssh ]; then if [ -n "$inherit_ssh_auth_sock" ]; then ls "$inherit_ssh_auth_sock" >/dev/null 2>&1 if [ $? != 0 ]; then warn "SSH_AUTH_SOCK in environment is invalid; ignoring it" unset inherit_ssh_auth_sock inherit_ssh_agent_pid vi_status=1 fi fi if [ -n "$inherit_ssh2_auth_sock" ]; then ls "$inherit_ssh2_auth_sock" >/dev/null 2>&1 if [ $? != 0 ]; then warn "SSH2_AUTH_SOCK in environment is invalid; ignoring it" unset inherit_ssh2_auth_sock inherit_ssh2_agent_pid vi_status=1 fi fi elif [ "$vi_agent" = gpg ]; then if [ -n "$inherit_gpg_agent_pid" ]; then kill -0 "$inherit_gpg_agent_pid" >/dev/null 2>&1 if [ $? != 0 ]; then unset inherit_gpg_agent_pid inherit_gpg_agent_info warn "GPG_AGENT_INFO in environment is invalid; ignoring it" vi_status=1 fi fi fi return $vi_status } # synopsis: catpidf_shell shell agents... # cat the pid files for the given agents. This is used by loadagents and also # for keychain output when --eval is given. catpidf_shell() { case "$1" in */fish|fish) cp_pidf="$fishpidf" ;; *csh) cp_pidf="$cshpidf" ;; *) cp_pidf="$pidf" ;; esac shift for cp_a in "$@"; do case "${cp_a}" in ssh) [ -f "$cp_pidf" ] && cat "$cp_pidf" ;; *) [ -f "${cp_pidf}-$cp_a" ] && cat "${cp_pidf}-$cp_a" ;; esac echo done return 0 } # synopsis: catpidf agents... # cat the pid files for the given agents, appropriate for the current value of # $SHELL. This is used for keychain output when --eval is given. catpidf() { catpidf_shell "$SHELL" "$@" } # synopsis: loadagents agents... # Load agent variables from $pidf and copy implementation-specific environment # variables into generic global strings loadagents() { for la_a in "$@"; do case "$la_a" in ssh) unset SSH_AUTH_SOCK SSH_AGENT_PID SSH2_AUTH_SOCK SSH2_AGENT_PID eval "`catpidf_shell sh $la_a`" if [ -n "$SSH_AUTH_SOCK" ]; then ssh_auth_sock=$SSH_AUTH_SOCK ssh_agent_pid=$SSH_AGENT_PID elif [ -n "$SSH2_AUTH_SOCK" ]; then ssh_auth_sock=$SSH2_AUTH_SOCK ssh_agent_pid=$SSH2_AGENT_PID else unset ssh_auth_sock ssh_agent_pid fi ;; gpg) unset GPG_AGENT_INFO eval "`catpidf_shell sh $la_a`" if [ -n "$GPG_AGENT_INFO" ]; then la_IFS="$IFS" # save current IFS IFS=':' # set IFS to colon to separate PATH set -- $GPG_AGENT_INFO IFS="$la_IFS" # restore IFS gpg_agent_pid=$2 fi ;; *) eval "`catpidf_shell sh $la_a`" ;; esac done return 0 } # synopsis: startagent [prog] # Starts an agent if it isn't already running. # Requires $ssh_agent_pid startagent() { start_prog=${1-ssh} unset start_pid start_inherit_pid=none start_mypids=`findpids "$start_prog"` [ $? = 0 ] || die # Unfortunately there isn't much way to genericize this without introducing # a lot more supporting code/structures. if [ "$start_prog" = ssh ]; then start_pidf="$pidf" start_cshpidf="$cshpidf" start_fishpidf="$fishpidf" start_pid="$ssh_agent_pid" if [ -n "$inherit_ssh_auth_sock" -o -n "$inherit_ssh2_auth_sock" ]; then if [ -n "$inherit_ssh_agent_pid" ]; then start_inherit_pid="$inherit_ssh_agent_pid" elif [ -n "$inherit_ssh2_agent_pid" ]; then start_inherit_pid="$inherit_ssh2_agent_pid" else start_inherit_pid="forwarded" fi fi else start_pidf="${pidf}-$start_prog" start_cshpidf="${cshpidf}-$start_prog" start_fishpidf="${fishpidf}-$start_prog" if [ "$start_prog" = gpg ]; then start_pid="$gpg_agent_pid" if [ -n "$inherit_gpg_agent_pid" ]; then start_inherit_pid="$inherit_gpg_agent_pid" fi else error "I don't know how to start $start_prog-agent (1)" return 1 fi fi [ "$start_pid" -gt 0 ] 2>/dev/null || start_pid=none # This hack makes the case statement easier if [ "$inheritwhich" = any -o "$inheritwhich" = any-once ]; then start_fwdflg=forwarded else unset start_fwdflg fi # Check for an existing agent start_tester="$inheritwhich: $start_mypids $start_fwdflg " case "$start_tester" in none:*" $start_pid "*|*-once:*" $start_pid "*) mesg "Found existing ${start_prog}-agent: ${CYANN}$start_pid${OFF}" return 0 ;; *:*" $start_inherit_pid "*) # This test was postponed until now to prevent generating warnings validinherit "$start_prog" if [ $? != 0 ]; then # inherit_* vars have been removed from the environment. Try # again now startagent "$start_prog" return $? fi mesg "Inheriting ${start_prog}-agent ($start_inherit_pid)" ;; *) # start_inherit_pid might be "forwarded" which we don't allow with, # for example, local-once (the default setting) start_inherit_pid=none ;; esac # Init the bourne-formatted pidfile ( umask 0177 && :> "$start_pidf"; ) if [ $? != 0 ]; then rm -f "$start_pidf" "$start_cshpidf" "$start_fishpidf" 2>/dev/null error "can't create $start_pidf" return 1 fi # Init the csh-formatted pidfile ( umask 0177 && :> "$start_cshpidf"; ) if [ $? != 0 ]; then rm -f "$start_pidf" "$start_cshpidf" "$start_fishpidf" 2>/dev/null error "can't create $start_cshpidf" return 1 fi # Init the fish-formatted pidfile ( umask 0177 && :> "$start_fishpidf"; ) if [ $? != 0 ]; then rm -f "$start_pidf" "$start_cshpidf" "$start_fishpidf" 2>/dev/null error "can't create $start_fishpidf" return 1 fi # Determine content for files unset start_out if [ "$start_inherit_pid" = none ]; then # Start the agent. # Branch again since the agents start differently mesg "Starting ${start_prog}-agent..." if [ "$start_prog" = ssh ]; then start_out=`ssh-agent` elif [ "$start_prog" = gpg ]; then if [ -n "${timeout}" ]; then start_gpg_timeout="--default-cache-ttl `expr $timeout \* 60`" else unset start_gpg_timeout fi # the 1.9.x series of gpg spews debug on stderr start_out=`gpg-agent --daemon $start_gpg_timeout 2>/dev/null` else error "I don't know how to start $start_prog-agent (2)" return 1 fi if [ $? != 0 ]; then rm -f "$start_pidf" "$start_cshpidf" "$start_fishpidf" 2>/dev/null error "Failed to start ${start_prog}-agent" return 1 fi elif [ "$start_prog" = ssh -a -n "$inherit_ssh_auth_sock" ]; then start_out="SSH_AUTH_SOCK=$inherit_ssh_auth_sock; export SSH_AUTH_SOCK;" if [ "$inherit_ssh_agent_pid" -gt 0 ] 2>/dev/null; then start_out="$start_out SSH_AGENT_PID=$inherit_ssh_agent_pid; export SSH_AGENT_PID;" fi elif [ "$start_prog" = ssh -a -n "$inherit_ssh2_auth_sock" ]; then start_out="SSH2_AUTH_SOCK=$inherit_ssh2_auth_sock; export SSH2_AUTH_SOCK; SSH2_AGENT_PID=$inherit_ssh2_agent_pid; export SSH2_AGENT_PID;" if [ "$inherit_ssh2_agent_pid" -gt 0 ] 2>/dev/null; then start_out="$start_out SSH2_AGENT_PID=$inherit_ssh2_agent_pid; export SSH2_AGENT_PID;" fi elif [ "$start_prog" = gpg -a -n "$inherit_gpg_agent_info" ]; then start_out="GPG_AGENT_INFO=$inherit_gpg_agent_info; export GPG_AGENT_INFO;" else die "something bad happened" # should never be here fi # Add content to pidfiles. # Some versions of ssh-agent don't understand -s, which means to # generate Bourne shell syntax. It appears they also ignore SHELL, # according to http://bugs.gentoo.org/show_bug.cgi?id=52874 # So make no assumptions. start_out=`echo "$start_out" | grep -v 'Agent pid'` case "$start_out" in setenv*) echo "$start_out" >"$start_cshpidf" echo "$start_out" | awk '{print $2"="$3" export "$2";"}' >"$start_pidf" ;; *) echo "$start_out" >"$start_pidf" echo "$start_out" | sed 's/;.*/;/' | sed 's/=/ /' | sed 's/^/setenv /' >"$start_cshpidf" echo "$start_out" | sed 's/;.*/;/' | sed 's/^\(.*\)=\(.*\);/set -e \1; and set -x -U \1 \2/' >"$start_fishpidf" ;; esac # Hey the agent should be started now... load it up! loadagents "$start_prog" } # synopsis: extract_fingerprints # Extract the fingerprints from standard input, returns space-separated list. # Utility routine for ssh_l and ssh_f extract_fingerprints() { while read ef_line; do case "$ef_line" in *\ *\ [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:*) # Sun SSH spits out different things depending on the type of # key. For example: # md5 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_dsa(DSA) # 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_rsa.pub echo "$ef_line" | cut -f3 -d' ' ;; *\ [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:*) # The more consistent OpenSSH format, we hope # 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_dsa (DSA) echo "$ef_line" | cut -f2 -d' ' ;; *) # Fall back to filename. Note that commercial ssh is handled # explicitly in ssh_l and ssh_f, so hopefully this rule will # never fire. warn "Can't determine fingerprint from the following line, falling back to filename" mesg "$ef_line" basename "$ef_line" | sed 's/[ (].*//' ;; esac done | xargs } # synopsis: ssh_l # Return space-separated list of known fingerprints ssh_l() { sl_mylist=`ssh-add -l 2>/dev/null` sl_retval=$? if $openssh; then # Error codes: # 0 success # 1 OpenSSH_3.8.1p1 on Linux: no identities (not an error) # OpenSSH_3.0.2p1 on HP-UX: can't connect to auth agent # 2 can't connect to auth agent case $sl_retval in 0) echo "$sl_mylist" | extract_fingerprints ;; 1) case "$sl_mylist" in *"open a connection"*) sl_retval=2 ;; esac ;; esac return $sl_retval elif $sunssh; then # Error codes (from http://docs.sun.com/db/doc/817-3936/6mjgdbvio?a=view) # 0 success (even when there are no keys) # 1 error case $sl_retval in 0) echo "$sl_mylist" | extract_fingerprints ;; 1) case "$sl_mylist" in *"open a connection"*) sl_retval=2 ;; esac ;; esac return $sl_retval else # Error codes: # 0 success - however might say "The authorization agent has no keys." # 1 can't connect to auth agent # 2 bad passphrase # 3 bad identity file # 4 the agent does not have the requested identity # 5 unspecified error if [ $sl_retval = 0 ]; then # Output of ssh-add -l: # The authorization agent has one key: # id_dsa_2048_a: 2048-bit dsa, agriffis@alpha.zk3.dec.com, Fri Jul 25 2003 10:53:49 -0400 # Since we don't have a fingerprint, just get the filenames *shrug* echo "$sl_mylist" | sed '2,$s/:.*//' | xargs fi return $sl_retval fi } # synopsis: ssh_f filename # Return finger print for a keyfile # Requires $openssh and $sunssh ssh_f() { sf_filename="$1" if $openssh || $sunssh; then if [ ! -f "$sf_filename.pub" ]; then warn "$sf_filename.pub missing; can't tell if $sf_filename is loaded" return 1 fi sf_fing=`ssh-keygen -l -f "$sf_filename.pub"` || return 1 echo "$sf_fing" | extract_fingerprints else # can't get fingerprint for ssh2 so use filename *shrug* basename "$sf_filename" fi return 0 } # synopsis: gpg_listmissing # Uses $gpgkeys # Returns a newline-separated list of keys found to be missing. gpg_listmissing() { unset glm_missing GPG_TTY=`tty` # Parse $gpgkeys into positional params to preserve spaces in filenames set -f # disable globbing glm_IFS="$IFS" # save current IFS IFS=" " # set IFS to newline set -- $gpgkeys IFS="$glm_IFS" # restore IFS set +f # re-enable globbing for glm_k in "$@"; do # Check if this key is known to the agent. Don't know another way... if echo | env -i GPG_TTY="$GPG_TTY" PATH="$PATH" GPG_AGENT_INFO="$GPG_AGENT_INFO" \ gpg --no-options --use-agent --no-tty --sign --local-user "$glm_k" -o- >/dev/null 2>&1; then # already know about this key mesg "Known gpg key: ${CYANN}${glm_k}${OFF}" continue else # need to add this key if [ -z "$glm_missing" ]; then glm_missing="$glm_k" else glm_missing="$glm_missing $glm_k" fi fi done echo "$glm_missing" } # synopsis: ssh_listmissing # Uses $sshkeys and $sshavail # Returns a newline-separated list of keys found to be missing. ssh_listmissing() { unset slm_missing # Parse $sshkeys into positional params to preserve spaces in filenames set -f # disable globbing slm_IFS="$IFS" # save current IFS IFS=" " # set IFS to newline set -- $sshkeys IFS="$slm_IFS" # restore IFS set +f # re-enable globbing for slm_k in "$@"; do # Fingerprint current user-specified key slm_finger=`ssh_f "$slm_k"` || continue # Check if it needs to be added case " $sshavail " in *" $slm_finger "*) # already know about this key mesg "Known ssh key: ${CYANN}${slm_k}${OFF}" ;; *) # need to add this key if [ -z "$slm_missing" ]; then slm_missing="$slm_k" else slm_missing="$slm_missing $slm_k" fi ;; esac done echo "$slm_missing" } # synopsis: add_gpgkey # Adds a key to $gpgkeys add_gpgkey() { gpgkeys=${gpgkeys+"$gpgkeys "}"$1" } # synopsis: add_sshkey # Adds a key to $sshkeys add_sshkey() { sshkeys=${sshkeys+"$sshkeys "}"$1" } # synopsis: parse_mykeys # Sets $sshkeys and $gpgkeys based on $mykeys parse_mykeys() { # Parse $mykeys into positional params to preserve spaces in filenames set -f # disable globbing pm_IFS="$IFS" # save current IFS IFS=" " # set IFS to newline set -- $mykeys IFS="$pm_IFS" # restore IFS set +f # re-enable globbing for pm_k in "$@"; do # Check for ssh if wantagent ssh; then if [ -f "$pm_k" ]; then add_sshkey "$pm_k" ; continue elif [ -f "$HOME/.ssh/$pm_k" ]; then add_sshkey "$HOME/.ssh/$pm_k" ; continue elif [ -f "$HOME/.ssh2/$pm_k" ]; then add_sshkey "$HOME/.ssh2/$pm_k" ; continue fi fi # Check for gpg if wantagent gpg; then if [ -z "$pm_gpgsecrets" ]; then pm_gpgsecrets="`gpg --list-secret-keys 2>/dev/null | cut -d/ -f2 | cut -d' ' -f1 | xargs`" [ -z "$pm_gpgsecrets" ] && pm_gpgsecrets='/' # arbitrary fi case " $pm_gpgsecrets " in *" $pm_k "*) add_gpgkey "$pm_k" ; continue ;; esac fi $ignoreopt || warn "can't find $pm_k; skipping" continue done return 0 } # synopsis: setaction # Sets $myaction or dies if $myaction is already set setaction() { if [ -n "$myaction" ]; then die "you can't specify --$myaction and $1 at the same time" else myaction="$1" fi } # synopsis: in_path # Look for executables in the path in_path() { ip_lookfor="$1" # Parse $PATH into positional params to preserve spaces ip_IFS="$IFS" # save current IFS IFS=':' # set IFS to colon to separate PATH set -- $PATH IFS="$ip_IFS" # restore IFS for ip_x in "$@"; do [ -x "$ip_x/$ip_lookfor" ] || continue echo "$ip_x/$ip_lookfor" return 0 done return 1 } # synopsis: setagents # Check validity of agentsopt setagents() { if [ -n "$agentsopt" ]; then agentsopt=`echo "$agentsopt" | sed 's/,/ /g'` unset new_agentsopt for a in $agentsopt; do if in_path ${a}-agent >/dev/null; then new_agentsopt="${new_agentsopt+$new_agentsopt }${a}" else warn "can't find ${a}-agent, removing from list" fi done agentsopt="${new_agentsopt}" else for a in ssh gpg; do in_path ${a}-agent >/dev/null || continue agentsopt="${agentsopt+$agentsopt }${a}" done fi if [ -z "$agentsopt" ]; then die "no agents available to start" fi } # synopsis: wantagent prog # Return 0 (true) or 1 (false) depending on whether prog is one of the agents in # agentsopt wantagent() { case "$agentsopt" in "$1"|"$1 "*|*" $1 "*|*" $1") return 0 ;; *) return 1 ;; esac } # # MAIN PROGRAM # # parse the command-line while [ -n "$1" ]; do case "$1" in --help|-h) setaction help ;; --stop|-k) # As of version 2.5, --stop takes an argument. For the sake of # backward compatibility, only eat the arg if it's one we recognize. if [ "$2" = mine ]; then stopwhich=mine; shift elif [ "$2" = others ]; then stopwhich=others; shift elif [ "$2" = all ]; then stopwhich=all; shift else # backward compat stopwhich=all-warn fi ;; --version|-V) setaction version ;; --agents) shift agentsopt="$1" ;; --attempts) shift if [ "$1" -gt 0 ] 2>/dev/null; then attempts=$1 else die "--attempts requires a numeric argument greater than zero" fi ;; --clear) clearopt=true $quickopt && die "--quick and --clear are not compatible" ;; --confirm) confirmopt=true ;; --dir) shift case "$1" in */.*) keydir="$1" ;; '') die "--dir requires an argument" ;; *) keydir="$1/.keychain" ;; # be backward-compatible esac ;; --env) shift if [ -z "$1" ]; then die "--env requires an argument" else envf="$1" fi ;; --eval) evalopt=true ;; --host) shift hostopt="$1" ;; --ignore-missing) ignoreopt=true ;; --inherit) shift case "$1" in local|any|local-once|any-once) inheritwhich="$1" ;; *) die "--inherit requires an argument (local, any, local-once or any-once)" ;; esac ;; --noinherit) inheritwhich=none ;; --noask) noaskopt=true ;; --nogui) noguiopt=true ;; --nolock) nolockopt=true ;; --lockwait) shift if [ "$1" -ge 0 ] 2>/dev/null; then lockwait="$1" else die "--lockwait requires an argument zero or greater." fi ;; --quick|-Q) quickopt=true $clearopt && die "--quick and --clear are not compatible" ;; --quiet|-q) quietopt=true ;; --nocolor) color=false ;; --timeout) shift if [ "$1" -gt 0 ] 2>/dev/null; then timeout=$1 else die "--timeout requires a numeric argument greater than zero" fi ;; --) shift IFS=" " mykeys=${mykeys+"$mykeys "}"$*" unset IFS break ;; -*) echo "$zero: unknown option $1" >&2 $evalopt && { echo; echo "false;"; } exit 1 ;; *) mykeys=${mykeys+"$mykeys "}"$1" ;; esac shift done # Set filenames *after* parsing command-line options to allow # modification of $keydir and/or $hostopt # # pidf holds the specific name of the keychain .ssh-agent-myhostname file. # We use the new hostname extension for NFS compatibility. cshpidf is the # .ssh-agent file with csh-compatible syntax. fishpidf is the .ssh-agent # file with fish-compatible syntax. lockf is the lockfile, used # to serialize the execution of multiple ssh-agent processes started # simultaneously [ -z "$hostopt" ] && hostopt="${HOSTNAME}" [ -z "$hostopt" ] && hostopt=`uname -n 2>/dev/null || echo unknown` pidf="${keydir}/${hostopt}-sh" cshpidf="${keydir}/${hostopt}-csh" fishpidf="${keydir}/${hostopt}-fish" olockf="${keydir}/${hostopt}-lock" lockf="${keydir}/${hostopt}-lockf" # Read the env snippet (especially for things like PATH, but could modify # basically anything) if [ -z "$envf" ]; then envf="${keydir}/${hostopt}-env" [ -f "$envf" ] || envf="${keydir}/env" [ -f "$envf" ] || unset envf fi if [ -n "$envf" ]; then . "$envf" fi # Don't use color if there's no terminal on stderr if [ -n "$OFF" ]; then tty <&2 >/dev/null 2>&1 || color=false fi #disable color if necessary, right before our initial newline $color || unset BLUE CYAN CYANN GREEN PURP OFF RED qprint #initial newline mesg "${PURP}keychain ${OFF}${CYANN}${version}${OFF} ~ ${GREEN}http://www.funtoo.org${OFF}" [ "$myaction" = version ] && { versinfo; exit 0; } [ "$myaction" = help ] && { versinfo; helpinfo; exit 0; } # Set up traps # Don't use signal names because they don't work on Cygwin. if $clearopt; then trap '' 2 # disallow ^C until we've had a chance to --clear trap 'droplock; exit 1' 1 15 # drop the lock on signal trap 'droplock; exit 0' 0 # drop the lock on exit else # Don't use signal names because they don't work on Cygwin. trap 'droplock; exit 1' 1 2 15 # drop the lock on signal trap 'droplock; exit 0' 0 # drop the lock on exit fi setagents # verify/set $agentsopt verifykeydir # sets up $keydir wantagent ssh && testssh # sets $openssh and $sunssh getuser # sets $me # Inherit agent info from the environment before loadagents wipes it out. # Always call this since it checks $inheritopt and sets variables accordingly. inheritagents # --stop: kill the existing ssh-agent(s) and quit if [ -n "$stopwhich" ]; then if [ "$stopwhich" = all-warn ]; then warn "--stop without an argument is deprecated; see --help" stopwhich=all fi takelock || die if [ "$stopwhich" = mine -o "$stopwhich" = others ]; then loadagents $agentsopt fi for a in $agentsopt; do stopagent $a done if [ "$stopwhich" != others ]; then qprint exit 0 # stopagent is always successful fi fi # Note regarding locking: if we're trying to be quick, then don't take the lock. # It will be taken later if we discover we can't be quick. if $quickopt; then loadagents $agentsopt # sets ssh_auth_sock, ssh_agent_pid, etc unset nagentsopt for a in $agentsopt; do needstart=true # Trying to be quick has a price... If we discover the agent isn't running, # then we'll have to check things again (in startagent) after taking the # lock. So don't do the initial check unless --quick was specified. if [ $a = ssh ]; then sshavail=`ssh_l` # try to use existing agent # 0 = found keys, 1 = no keys, 2 = no agent if [ $? = 0 -o \( $? = 1 -a -z "$mykeys" \) ]; then mesg "Found existing ssh-agent: ${CYANN}$ssh_agent_pid${OFF}" needstart=false fi elif [ $a = gpg ]; then # not much way to be quick on this if [ -n "$gpg_agent_pid" ]; then case " `findpids gpg` " in *" $gpg_agent_pid "*) mesg "Found existing gpg-agent: ${CYANN}$gpg_agent_pid${OFF}" needstart=false ;; esac fi fi if $needstart; then nagentsopt="$nagentsopt $a" elif $evalopt; then catpidf $a fi done agentsopt="$nagentsopt" fi # If there are no agents remaining, then bow out now... [ -n "$agentsopt" ] || { qprint; exit 0; } # There are agents remaining to start, and we now know we can't be quick. Take # the lock before continuing takelock || die loadagents $agentsopt unset nagentsopt for a in $agentsopt; do if startagent $a; then nagentsopt="${nagentsopt+$nagentsopt }$a" $evalopt && catpidf $a fi done agentsopt="$nagentsopt" # If there are no agents remaining, then duck out now... [ -n "$agentsopt" ] || { qprint; exit 0; } # --timeout translates almost directly to ssh-add -t, but ssh.com uses # minutes and OpenSSH uses seconds if [ -n "$timeout" ] && wantagent ssh; then ssh_timeout=$timeout if $openssh || $sunssh; then ssh_timeout=`expr $ssh_timeout \* 60` fi ssh_timeout="-t $ssh_timeout" fi # --confirm translates to ssh-add -c if $confirmopt && wantagent ssh; then if $openssh || $sunssh; then ssh_confirm=-c else warn "--confirm only works with OpenSSH" fi fi # --clear: remove all keys from the agent(s) if $clearopt; then for a in ${agentsopt}; do if [ $a = ssh ]; then sshout=`ssh-add -D 2>&1` if [ $? = 0 ]; then mesg "ssh-agent: $sshout" else warn "ssh-agent: $sshout" fi elif [ $a = gpg ]; then kill -1 $gpg_agent_pid 2>/dev/null mesg "gpg-agent: All identities removed." else warn "--clear not supported for ${a}-agent" fi done trap 'droplock' 2 # done clearing, safe to ctrl-c fi # --noask: "don't ask for keys", so we're all done $noaskopt && { qprint; exit 0; } # Parse $mykeys into ssh vs. gpg keys; it may be necessary in the future to # differentiate on the cmdline parse_mykeys || die # Load ssh keys if wantagent ssh; then sshavail=`ssh_l` # update sshavail now that we're locked sshkeys="`ssh_listmissing`" # cache list of missing keys, newline-separated sshattempts=$attempts savedisplay="$DISPLAY" # Attempt to add the keys while [ -n "$sshkeys" ]; do mesg "Adding ${CYANN}"`echo "$sshkeys" | wc -l`"${OFF} ssh key(s): `echo $sshkeys`" # Parse $sshkeys into positional params to preserve spaces in filenames. # This *must* happen after any calls to subroutines because pure Bourne # shell doesn't restore "$@" following a call. Eeeeek! set -f # disable globbing old_IFS="$IFS" # save current IFS IFS=" " # set IFS to newline set -- $sshkeys IFS="$old_IFS" # restore IFS set +f # re-enable globbing if $noguiopt || [ -z "$SSH_ASKPASS" -o -z "$DISPLAY" ]; then unset DISPLAY # DISPLAY="" can cause problems unset SSH_ASKPASS # make sure ssh-add doesn't try SSH_ASKPASS sshout=`ssh-add ${ssh_timeout} ${ssh_confirm} "$@" 2>&1` else sshout=`ssh-add ${ssh_timeout} ${ssh_confirm} "$@" 2>&1 /dev/null 2>&1 [ $? != 0 ] && tryagain=true done $tryagain || break if [ $gpgattempts = 1 ]; then die "Problem adding (is pinentry installed?); giving up" else warn "Problem adding; trying again" fi # Update the list of missing keys gpgkeys="`gpg_listmissing`" # remember, newline-separated # Decrement the countdown gpgattempts=`expr $gpgattempts - 1` done fi qprint # trailing newline # vim:sw=4 expandtab tw=80 keychain-2.7.1/keychain.10000644000000000000000000003217511371046301013673 0ustar rootroot.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" .br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' .br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "keychain 1" .TH keychain 1 "2010-05-07" "2.7.1" "http://www.funtoo.org" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" keychain \- re\-use ssh\-agent and/or gpg\-agent between logins .SH "SYNOPSIS" .IX Header "SYNOPSIS" keychain\ [\ \-hkQqV\ ]\ [\ \-\-clear\ \-\-help\ \-\-ignore\-missing\ \-\-noask \&\-\-nocolor\ \-\-nogui\ \-\-nolock\ \-\-quick\ \-\-quiet\ \-\-version\ ] [\ \-\-agents\ \fIlist\fR\ ]\ [\ \-\-attempts\ \fInum\fR\ ]\ [\ \-\-dir\ \fIdirname\fR\ ] [\ \-\-host\ \fIname\fR\ ]\ [\ \-\-lockwait\ \fIseconds\fR\ ] [\ \-\-stop\ \fIwhich\fR\ ]\ [\ \-\-timeout\ \fIminutes\fR\ ]\ [\ keys...\ ] .SH "DESCRIPTION" .IX Header "DESCRIPTION" keychain is a manager for ssh-agent, typically run from ~/.bash_profile. It allows your shells and cron jobs to share a single ssh-agent process. By default, the ssh-agent started by keychain is long-running and will continue to run, even after you have logged out from the system. If you want to change this behavior, take a look at the \-\-clear and \-\-timeout options, described below. .PP When keychain is run, it checks for a running ssh-agent, otherwise it starts one. It saves the ssh-agent environment variables to ~/.keychain/${\s-1HOSTNAME\s0}\-sh, so that subsequent logins and non-interactive shells such as cron jobs can source the file and make passwordless ssh connections. In addition, when keychain runs, it verifies that the key files specified on the command-line are known to ssh-agent, otherwise it loads them, prompting you for a password if necessary. .PP Keychain also supports gpg-agent in the same ways that ssh-agent is supported. By default keychain attempts to start all available agents but will fall back to only gpg-agent or only ssh-agent if either is unavailable. You can specifically limit keychain using the \-\-agents option. .PP keychain supports most UNIX-like operating systems, including Cygwin. It works with Bourne-compatible, csh-compatible and fish shells. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-\-agents\fR \fIlist\fR" 4 .IX Item "--agents list" Start the agents listed. By default keychain will build the list automatically based on the existence of ssh-agent and/or gpg-agent on the system. The list should be comma-separated, for example \*(L"gpg,ssh\*(R" .IP "\fB\-\-attempts\fR \fInum\fR" 4 .IX Item "--attempts num" Try num times to add keys before giving up. The default is 1. .IP "\fB\-\-clear\fR" 4 .IX Item "--clear" Delete all of ssh-agent's keys. Typically this is used in \&.bash_profile. The theory behind this is that keychain should assume that you are an intruder until proven otherwise. However, while this option increases security, it still allows your cron jobs to use your ssh keys when you're logged out. .IP "\fB\-\-confirm\fR" 4 .IX Item "--confirm" Keys are subject to interactive confirmation by the \s-1SSH_ASKPASS\s0 program before being used for authentication. See the \-c option for \&\fIssh\-add\fR\|(1). .IP "\fB\-\-dir\fR \fIdirname\fR" 4 .IX Item "--dir dirname" Keychain will use dirname rather than \f(CW$HOME\fR/.keychain .IP "\fB\-\-eval\fR" 4 .IX Item "--eval" Keychain will print lines to be evaluated in the shell on stdout. It respects the \s-1SHELL\s0 environment variable to determine if Bourne shell or C shell output is expected. .IP "\fB\-\-env\fR \fIfilename\fR" 4 .IX Item "--env filename" After parsing options, keychain will load additional environment settings from \*(L"filename\*(R". By default, if \*(L"\-\-env\*(R" is not given, then keychain will attempt to load from ~/.keychain/[hostname]\-env or alternatively ~/.keychain/env. The purpose of this file is to override settings such as \s-1PATH\s0, in case ssh is stored in a non-standard place. .IP "\fB\-h \-\-help\fR" 4 .IX Item "-h --help" Show help that looks remarkably like this man-page. As of 2.6.10, help is sent to stdout so it can be easily piped to a pager. .IP "\fB\-\-host\fR \fIname\fR" 4 .IX Item "--host name" Set alternate hostname for creation of pidfiles .IP "\fB\-\-ignore\-missing\fR" 4 .IX Item "--ignore-missing" Don't warn if some keys on the command-line can't be found. This is useful for situations where you have a shared .bash_profile, but your keys might not be available on every machine where keychain is run. .IP "\fB\-\-inherit\fR \fIwhich\fR" 4 .IX Item "--inherit which" Attempt to inherit agent variables from the environment. This can be useful in a variety of circumstances, for example when ssh-agent is started by gdm. The following values are valid for \*(L"which\*(R": .RS 4 .IP "\fBlocal\fR" 12 .IX Item "local" Inherit when a pid (e.g. \s-1SSH_AGENT_PID\s0) is set in the environment. This disallows inheriting a forwarded agent. .IP "\fBany\fR" 12 .IX Item "any" Inherit when a sock (e.g. \s-1SSH_AUTH_SOCK\s0) is set in the environment. This allows inheriting a forwarded agent. .IP "\fBlocal-once\fR" 12 .IX Item "local-once" Same as \*(L"local\*(R", but only inherit if keychain isn't already providing an agent. .IP "\fBany-once\fR" 12 .IX Item "any-once" Same as \*(L"any\*(R", but only inherit if keychain isn't already providing an agent. .RE .RS 4 .Sp By default, keychain\-2.5.0 and later will behave as if \*(L"\-\-inherit local-once\*(R" is specified. You should specify \*(L"\-\-noinherit\*(R" if you want the older behavior. .RE .IP "\fB\-\-lockwait\fR \fIseconds\fR" 4 .IX Item "--lockwait seconds" How long to wait for the lock to become available. Defaults to 5 seconds. Specify a value of zero or more. If the lock cannot be acquired within the specified number of seconds, then this keychain process will forcefully acquire the lock. .IP "\fB\-\-noask\fR" 4 .IX Item "--noask" This option tells keychain do everything it normally does (ensure ssh-agent is running, set up the ~/.keychain/[hostname]\-{c}sh files) except that it will not prompt you to add any of the keys you specified if they haven't yet been added to ssh-agent. .IP "\fB\-\-nocolor\fR" 4 .IX Item "--nocolor" Disable color hilighting for non ANSI-compatible terms. .IP "\fB\-\-nogui\fR" 4 .IX Item "--nogui" Don't honor \s-1SSH_ASKPASS\s0, if it is set. This will cause ssh-add to prompt on the terminal instead of using a graphical program. .IP "\fB\-\-noinherit\fR" 4 .IX Item "--noinherit" Don't inherit any agent processes, overriding the default \&\*(L"\-\-inherit local-once\*(R" .IP "\fB\-\-nolock\fR" 4 .IX Item "--nolock" Don't attempt to use a lockfile while manipulating files, pids and keys. .IP "\fB\-k \-\-stop\fR \fIwhich\fR" 4 .IX Item "-k --stop which" Kill currently running agent processes. The following values are valid for \*(L"which\*(R": .RS 4 .IP "all" 9 .IX Item "all" Kill all agent processes and quit keychain immediately. Prior to keychain\-2.5.0, this was the behavior of the bare \*(L"\-\-stop\*(R" option. .IP "others" 9 .IX Item "others" Kill agent processes other than the one keychain is providing. Prior to keychain\-2.5.0, keychain would do this automatically. The new behavior requires that you specify it explicitly if you want it. .IP "mine" 9 .IX Item "mine" Kill keychain's agent processes, leaving other agents alone. .RE .RS 4 .RE .IP "\fB\-Q \-\-quick\fR" 4 .IX Item "-Q --quick" If an ssh-agent process is running then use it. Don't verify the list of keys, other than making sure it's non-empty. This option avoids locking when possible so that multiple terminals can be opened simultaneously without waiting on each other. .IP "\fB\-q \-\-quiet\fR" 4 .IX Item "-q --quiet" Only print messages in case of warning, error or required interactivity. As of version 2.6.10, this also suppresses \*(L"Identities added\*(R" messages for ssh-agent. .IP "\fB\-\-timeout\fR \fIminutes\fR" 4 .IX Item "--timeout minutes" Set a timeout in minutes on your keys. This is conveyed to ssh-agent which does the actual timing out of keys since keychain doesn't run continuously. .IP "\fB\-V \-\-version\fR" 4 .IX Item "-V --version" Show version information. .SH "EXAMPLES" .IX Header "EXAMPLES" This snippet should work in any shell to load two ssh keys and one gpg key: .PP .Vb 1 \& eval \`keychain \-\-eval id_rsa id_dsa 0123ABCD\` .Ve .PP If you have trouble with that in csh: .PP .Vb 2 \& setenv SHELL /bin/csh \& eval \`keychain \-\-eval id_rsa id_dsa 0123ABCD\` .Ve .PP This is equivalent for Bourne shells (including bash and zsh) but doesn't use keychain's \-\-eval feature: .PP .Vb 6 \& keychain id_rsa id_dsa 0123ABCD \& [ \-z "$HOSTNAME" ] && HOSTNAME=\`uname \-n\` \& [ \-f $HOME/.keychain/$HOSTNAME\-sh ] && \e \& . $HOME/.keychain/$HOSTNAME\-sh \& [ \-f $HOME/.keychain/$HOSTNAME\-sh\-gpg ] && \e \& . $HOME/.keychain/$HOSTNAME\-sh\-gpg .Ve .PP This is equivalent for C shell (including tcsh): .PP .Vb 8 \& keychain id_rsa id_dsa 0123ABCD \& host=\`uname \-n\` \& if (\-f $HOME/.keychain/$host\-csh) then \& source $HOME/.keychain/$host\-csh \& endif \& if (\-f $HOME/.keychain/$host\-csh\-gpg) then \& source $HOME/.keychain/$host\-csh\-gpg \& endif .Ve .PP To load keychain variables from a script (for example from cron) and abort unless id_dsa is available: .PP .Vb 4 \& # Load keychain variables and check for id_dsa \& [ \-z "$HOSTNAME" ] && HOSTNAME=\`uname \-n\` \& . $HOME/.keychain/$HOSTNAME\-sh 2>/dev/null \& ssh\-add \-l 2>/dev/null | grep \-q id_dsa || exit 1 .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIssh\-agent\fR\|(1) .SH "NOTES" .IX Header "NOTES" Keychain was created and is currently maintained by Daniel Robbins. If you need to report a bug or request an enhancement, please post to the funtoo-dev mailing list . For more information about keychain, please visit .