├── .github └── workflows │ └── lint.yml ├── .gitignore ├── COPYING.txt ├── ChangeLog.md ├── MAINTAINERS.txt ├── Makefile ├── README.md ├── VERSION ├── keychain.pod ├── keychain.sh └── keychain.spec.in /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | shellcheck: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | - name: make keychain 11 | run: | 12 | make keychain 13 | - name: run shellcheck 14 | run: | 15 | shellcheck keychain 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /keychain.1.orig 2 | .idea/ 3 | keychain.iml 4 | keychain 5 | keychain.1 6 | keychain.txt 7 | keychain.spec 8 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # ChangeLog for Keychain 2 | https://www.funtoo.org/Funtoo:Keychain 3 | 4 | ## keychain 2.9.5 (16 May 2025) 5 | 6 | This is a bugfix release. 7 | 8 | * Hardening checks were failing on Android and some MacOS environments. Make them 9 | more compatible and lower to warnings instead of aborting the script, until 10 | they have been tested in more environments. 11 | ([#177](https://github.com/funtoo/keychain/issues/177)) 12 | 13 | * Fixed issues with indentation of `note()`, `warn()`, `mesg()`. 14 | 15 | * Convert `SSH_AUTH_SOCK in pidfile is invalid; ignoring it` into a debug message, 16 | as this is normal when rebooting your system so is not really useful to show 17 | typically. ([#176](https://github.com/funtoo/keychain/issues/176)) 18 | 19 | ## keychain 2.9.4 (14 May 2025) 20 | 21 | This is a minor bugfix release. 22 | 23 | * Fix minor regression which allowed some warnings to display with `--quiet`. 24 | ([#175](https://github.com/funtoo/keychain/issues/175)) 25 | 26 | * "Cannot find separate public key" turned into a `note()` rather than `warn()`, 27 | along with several other non-critical notices. `note()` can be suppressed with 28 | `--quiet`, unlike `warn()`. ([#157](https://github.com/funtoo/keychain/issues/157)) 29 | 30 | * Minor improvement when wiping GnuPG keys with `--wipe` option so keychain output 31 | is more understandable when gpg-agent is not running. 32 | 33 | ## keychain 2.9.3 (14 May 2025) 34 | 35 | This is a security and bug fix release. Many thanks to those who have reported 36 | issues to GitHub, send in pull requests, and tested out fixes. 2.9.3 includes 37 | the following updates: 38 | 39 | * The `--quick` option logic had several bugs which have been resolved. Thanks 40 | to Filipe Fernandes (@ffernand) for reporting the issue and for assistance 41 | testing fixes. ([#167](https://github.com/funtoo/keychain/issues/167)) 42 | 43 | * Fix keychain `--query` exit code when no pidfile exists. 44 | ([#171](https://github.com/funtoo/keychain/issues/171)) 45 | 46 | * `--systemd` option should now be fixed. 47 | ([[#168](https://github.com/funtoo/keychain/issues/168)]) 48 | 49 | * Harden keychain so the use of the `--dir` and `--absolute` options cannot be 50 | used to instruct keychain to write pidfiles into insecure areas. 51 | ([#174](https://github.com/funtoo/keychain/issues/174)) 52 | 53 | Prior to this release, it was possible to use these options in combination 54 | with bad (empty) default umask to write pidfiles into a public area on disk 55 | where they were writable by other users. In the worst case, this could allow 56 | arbitrary execution of the contents of the malicious pidfile by keychain. 57 | 58 | This hardening now makes it difficult for a user to configure their keychain 59 | in a way that would allow this to happen. Note that if you are not using the 60 | `--dir` or `--absolute` options, keychain will use the `$HOME/.keychain` 61 | directory by default, which is typically under the full control of the 62 | current user and thus not exploitable. 63 | 64 | The hardening changes include: 65 | 66 | * Setting a global restrictive `umask` in the script. 67 | * Remove pidfiles before redirecting data to them to ensure they are created 68 | with restrictive permissions from the `umask`. 69 | * Check the keychain pidfile directory to ensure it is owned by the current 70 | user, and only the current user can access it (mode 700). If not, abort 71 | with an informative error message. 72 | * Check any existing pidfiles prior to use to make sure they are owned by the 73 | current user, and only the current user can access them. If not, abort with 74 | an informative error message. 75 | 76 | Thanks to Eisuke Kawashima (@e-kwsm) for reporting this issue, the `--systemd` 77 | issue, as well as for the `--query` fix. 78 | 79 | 80 | ## keychain 2.9.2 (2 May 2025) 81 | 82 | This is primarily a bug fix release, but also introduces the new `--extended` 83 | option -- see below: 84 | 85 | * Deprecate `--confhost` option and replace with `--extended` option. The old 86 | `--confhost myhost` would now be `--extended host:myhost`. This also allows 87 | specifying SSH keys (`sshk:` prefix), GPG keys ( `gpgk:` prefix) and hosts 88 | (`host:` prefix) together without confusion. 89 | * Well, I became intimately familiar with `IFS` the hard way. Fix 2.9.1 bug 90 | [#159](https://github.com/funtoo/keychain/issues/159) by reworking IFS settings and 91 | adding proper documentation to the right places. This fixes the `--timeout` option 92 | and also now allows `--stop` to work properly which was broken. 93 | * Improve `--agents` deprecation warning. 94 | * Have keychain properly adopt a currently-running gpg-agent providing ssh-agent 95 | functionality when `--ssh-use-gpg` is specified. 96 | * Explicitly clean up known-bad pidfiles during processing. 97 | * Deprecate `--confhost` option and replace with new `--extended` option. 98 | * Improve host-based key processing by using `ssh -G` to officially extract 99 | host-based keys. 100 | * Make `Makefile` BSD-compatible. 101 | 102 | ## keychain 2.9.1 (1 May 2025) 103 | 104 | This release fixes a major bug related to the `--eval` option with non-Bourne shells. 105 | 106 | * Fix `--eval` option so it works with non-Bourne shells ([#158](https://github.com/funtoo/keychain/issues/158)). 107 | * Last-minute option change: replace `--ssh-wipe` and `--gpg-wipe` with `--wipe [ssh|gpg|all]`. 108 | * Deprecate `--attempts` option which doesn't work with gpg-agent pinentry nor modern OpenSSH. 109 | * More script rewriting -- default to IFS of newline in the script, totally rework SSH and GPG 110 | key adding code. 111 | * Remove undocumented and likely unused `--` option. 112 | * Script is now at a svelte 1049 lines of code. 113 | 114 | ## keychain 2.9.0 (30 Apr 2025) 115 | 116 | These release notes contain a summary of all changes, including cumulative 117 | changes in pre-releases: 118 | 119 | * A new release after 8 years, with Daniel Robbins (script creator) returning as maintainer. 120 | * 60% of the script has been rewritten, and is now compliant with 121 | [ShellCheck](https://shellcheck.net). 122 | * `--agents` and `--inherit` options have been deprecated to improve ease-of-use. 123 | * `gpg-agent` no longer started by default -- only when a GPG key has been provided on the 124 | command-line. GnuPG 2.1+ supported. 125 | * GnuPG pidfiles with `-gpg` extension are deprecated and no longer used. 126 | * Better GnuPG integration: `gpg-agent` can be used for SSH key storage. This can be enabled 127 | by specifying one of the new `--ssh-allow-gpg` and `--ssh-spawn-gpg` options. Agent information 128 | for `gpg-agent`'s SSH socket will be stored in the regular pidfile for compatibility. 129 | * Add `--ssh-rm`, `--ssh-wipe`, `--gpg-wipe` options for removing/wiping SSH and GPG keys. This addresses 130 | GitHub Issue [#153](https://github.com/funtoo/keychain/issues/153). 131 | * `--clear` option is now designed to be used for "initial clearing" of keys only. 132 | * Many user interface output improvements, to provide additional detail. 133 | * `--debug` option which can be used to troubleshoot issues with keychain. 134 | * Manual page significantly improved: New section on invocation, as well as documentation of 135 | the startup and agent detection algorithm. 136 | * Addition of `--ssh-agent-socket` option to manually specify desired path of the ssh-agent socket 137 | when starting. 138 | * Addition of `--confallhosts` to load identity files for all hosts. 139 | * Various bug fixes and improvements. 140 | * Script size reduced from 1500 to 1133 lines. 141 | 142 | ## keychain 2.9.0_beta4 (26 Apr 2025) 143 | 144 | * Rewrite key parsing code to remove unwanted use of `wantagent gpg` in the code. This may fix previous 145 | bugs related to identifying and loading GPG keys. 146 | * Fix GitHub Issue [#61](https://github.com/funtoo/keychain/issues/61) by ensuring that any error messages 147 | generated when adding SSH or GPG keys are printed as warnings to facilitate troubleshooting by users. 148 | * Manually merge in fish shell examples into `keychain.pod`. 149 | * Resolve GitHub Issue [#75](https://github.com/funtoo/keychain/issues/75) and ensure that "IdentityFile" 150 | allows case variations. 151 | 152 | ## keychain 2.9.0_beta3 (25 Apr 2025) 153 | 154 | * The previous beta of keychain attempted to use gpg-agent by default instead of ssh-agent. This behavior has been 155 | changed so that now you must opt-in to using gpg-agent. There are two new options to allow you to do this: 156 | `--ssh-allow-gpg` and `--ssh-spawn-gpg`, which are documented in the man page. 157 | * Displayed information about found/started agents has been greatly enhanced. 158 | * New option `--debug`, which currently allows display of more information regarding 159 | keychain's decisions. 160 | * Full technical documentation for keychain's agent-detection algorithm in the man page. 161 | * Key decision points in keychain's internal code now have better comments. 162 | * Fixing behavior of `--noinherit` to match previous versions. 163 | * Fixing behavior of `--quick` to match previous versions. 164 | * Tweaking agent detection to match legacy `--inherit=local-once` option. 165 | * Many documentation updates and improvements. 166 | * Now at 1119 lines of code (from 1500 lines of code in keychain 2.8.5) 167 | 168 | ## keychain 2.9.0_beta2 (23 Apr 2025) 169 | 170 | * Code has been overhauled to be more maintainable and various parts of the codebase have been rewritten. During this 171 | process, which started with 2.9.0_alpha1, various things were broken. THIS IS THE FIRST POTENTIALLY VIABLE WORKING 172 | RELEASE since 2.8.5, so PLEASE TEST AND PROVIDE FEEDBACK. It will be marked as a non-prerelease on GitHub to get 173 | more active testing and feedback. 174 | * Please note -- this version of keychain uses gpg-agent by default, if available. We are evaluating the consequences 175 | of this change at the moment, request feedback on complications related to this change, and THIS DECISION MAY BE 176 | REVERSED in the final release of 2.9.0 (we may go back to defaulting to ssh-agent, and have an option to use gpg-agent 177 | in place of ssh-agent, instead of just automatically using gpg-agent.) Please provide feedback in GitHub issues 178 | based on your experience. We have already found some challenges with the gpg-agent-by-default strategy, so no need 179 | to convince anyone. Just share your feedback/opinion. 180 | * ChangeLog has been converted to ChangeLog.md (thanks @d4g33z) to facilitate better interoperability with GitHub and 181 | modern conventions. 182 | 183 | ## keychain 2.9.0_beta1 (15 Apr 2025) 184 | 185 | * Keychain will now detect when gpg-agent is available and has ssh-agent functionality, and use gpg-agent by default. To disable this behavior, use the '--nosub' option to disable auto-substitution of gpg-agent for ssh-agent. This implements GitHub issue #67 requested by Martin Väth. 186 | * Begin removal of support for gpg-agent earlier than 2.1. This release is about 9 years old at this point, and if you have a newer version of keychain on a system, it's likely you also have updated GNUPG. 187 | * Update of keychain project URL to point to GitHub, and minor copyright updates. 188 | 189 | ## keychain 2.9.0_alpha1 (9 Apr 2025) 190 | 191 | * Daniel Robbins returns as keychain maintainer. 192 | * 'keychain' and 'keychain.1' removed from git repo and added to .gitignore. 193 | * Make 'keychain.sh' fully-compliant with ShellCheck, and add necessary exception comments to the codebase. These changes require testing, as some of the suggested fixes are not desired, and I tried to catch all of these. Thus the \_alpha1 status. 194 | * Merge in typographical errors from Peter Pentchev (@ppentchev). (commit d8a566d6402a2e93ce1664cb9c7e9df3233323de) 195 | * Merge in validity checking for malformed SSH public key files, also from Peter Pentchev (@ppentchev). (commit 2722fdcc5d86725dd72995a83694862849494471) 196 | * Merge in support for --agents, which adds detection of gpg-agent which was disabled. From Mikko Koivunalho (@mikkoi). (commit 1d170da33be908c742a0840191533fe90b82db5b) 197 | * Merge in support for --agent-socket option, to specify the path for SSH_AUTH_SOCK manually. From Mikhail f. Shiryaev (@felixoid). (commit 2a3dfcd46e91c32a620d64035c42c8d2971c926f) 198 | * Fix handling of exit codes. This fix is from Manolis Androulidakis (@manolis-andr). (commit ced07855cca34664c382aaaf536e719113f9e4e4) 199 | * Add --confallhosts option to allow loading of keys from all hosts. This is from Ole Martin Ruud (@barskern). (commit 004107877d0258076653b291f25c1e6083fec0fb) 200 | * Update GPL-2 license file. This is from Karol Babioch (@ghost). (commit 15ad9e1c8d5624dd762e503c4da014bcc8ebe890) 201 | 202 | ## keychain 2.8.5 (24 Jan 2018) 203 | 204 | * Summary: Various fixes and support systemd gnupg sockets 205 | * Some shells don't support local builtin (Roy Marples) 206 | * Support systemd managed gnupg sockets (Pedro Romano) 207 | * Fix some lintian warnings in the man page (Chris West) 208 | * Fix issues loading pem keys (Jack Twilley) 209 | 210 | ## keychain 2.8.4 (19 Oct 2017) 211 | 212 | * Summary: Support to GPG2 (Ryan Harris) 213 | * Support busybox ps (Alastair Hughes) 214 | * Various optimizations 215 | 216 | ## keychain 2.8.3 (24 Jun 2016) 217 | 218 | * Summary: fix gpg key addition (Clemens Kaposi) 219 | 220 | ## keychain 2.8.2 (06 Nov 2015) 221 | 222 | * Summary: Support new ssh features, bug fix release. 223 | * Support for new hash algorithms (Ben Boeckel) 224 | * Remove bashisms (Daniel Hertz) 225 | * Various optimizations (Daniel Hahler) 226 | * --timeout option now gets passed to agent, doc fixes (Andrew Bezella, Emil Lundberg) 227 | * RPM, Makefile fixes (Mike Frysinger) 228 | 229 | ## keychain 2.8.1 (29 May 2015) 230 | 231 | * Summary: POSIX compatibility and bug fix release. 232 | * Only set PATH to a standard value if PATH is not set. Otherwise, do not modify. 233 | * Makefile Cygwin and RPM spec fixes (thanks Luke Bakken and Ricardo Silva) 234 | * Confhost fixes. Deprecate in_path. Use command -v instead. 235 | * Find_pids: Modify "ps" call to work with non-GNU ps. (Bryan Drewery) 236 | * Re-introduce POSIX compatibility (remove shopt.) (vaeth) 237 | 238 | ## keychain 2.8.0 (21 Mar 2015) 239 | 240 | * Support for OpenSSH 6.8 fingerprints. 241 | * Support for GnuPG 2.1.0. 242 | * Handle private keys that are symlinks, even if the associated public key is in the target directory rather than alongside the symlink. 243 | * Allow private keys to have extensions, such as foo.priv. When looking for matching public keys, look for foo.priv.pub, but also strip extension and look for foo.pub if foo.priv.pub doesn't exist. 244 | * Initial support for --list/-l option to list SSH keys. 245 | * Updated docs for fish shell usage. 246 | 247 | ## keychain 2.7.2_beta1 (07 July 2014) 248 | 249 | * Various changes and updates: 250 | * Fixes for fish from Marc Joliet. 251 | * Keychain will default to start only ssh-agent unless GPG is explicitly updated using --agents. 252 | * Write ~/.gpg-agent-info when launching gpg-agent - fix from Thomas Spura. 253 | * Add support for injecting agents into systemd (Ben Boeckel) 254 | * Add support for --query option (Ben Boeckel) 255 | * Add --absolute flag, allowing user to set a full path without getting a .keychain suffix automatically appended. 256 | * Add --confhost option to scan ~/.ssh/config file to locate private key path specified there. 257 | 258 | ## keychain 2.7.1 (07 May 2010) 259 | 260 | * 07 May 2010; Daniel Robbins : Addition of a "make clean" target. removal of runtests as it is currently broken. 261 | * 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. 262 | * 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. 263 | * 20 Feb 2010; Daniel Robbins : MacOS X documentation fix from James Turnbull. 264 | 265 | ## keychain 2.7.0 (23 Oct 2009) 266 | 267 | * 23 Oct 2009; Daniel Robbins : updated README.rst with 2.7.0 and MacOS X package update. 268 | * 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. 269 | * 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'). 270 | * 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 Ruusamäe,) 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. 271 | 272 | ## keychain 2.6.9 (26 Jul 2009) 273 | 274 | * 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.) 275 | 276 | ## keychain 2.6.8 (24 Oct 2006) 277 | 278 | * 24 Oct 2006; Aron Griffis : 279 | 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. 280 | 281 | ## keychain 2.6.7 (24 Oct 2006) 282 | 283 | * 24 Oct 2006; Aron Griffis : 284 | Prevent `gpg_listmissing` from accidentally loading keys 285 | 286 | ## keychain 2.6.6 (08 Sep 2006) 287 | 288 | * 08 Sep 2006; Aron Griffis : 289 | Make --lockwait -1 mean forever. Previously 0 meant forever but was undocumented. Add more locking regression tests #137981 290 | 291 | ## keychain 2.6.5 (08 Sep 2006) 292 | 293 | * 08 Sep 2006; Aron Griffis : 294 | Break out of loop when empty lockfile can't be removed #127471. Add locking regression tests: 295 | `100_lock_stale` `101_lock_held` `102_lock_empty` `103_lock_empty_cant_remove` 296 | 297 | ## keychain 2.6.4 (08 Sep 2006) 298 | 299 | * 08 Sep 2006; Aron Griffis : 300 | 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`. 301 | Fix `--eval` for fish, and add new testcases: 302 | * `053_start_with_--eval_ksh` 303 | * `054_start_with_--eval_fish` 304 | * `055_start_with_--eval_csh` 305 | 306 | ## keychain 2.6.3 (07 Sep 2006) 307 | 308 | * 07 Sep 2006; Aron Griffis : 309 | Support fish: http://roo.no-ip.org/fish/ 310 | Thanks to Ilkka Poutanen for the patch. 311 | 312 | ## keychain 2.6.2 (20 Mar 2006) 313 | 314 | * 20 Mar 2006; Aron Griffis : 315 | 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` 316 | 317 | ## keychain 2.6.1 (10 Oct 2005) 318 | 319 | * 10 Oct 2005; Aron Griffis : 320 | Change `unset evalopt` to `evalopt=false` and run through *all* the regression tests instead of just the new ones. *sigh* 321 | 322 | ## keychain 2.6.0 (10 Oct 2005) 323 | 324 | * 10 Oct 2005; Aron Griffis : 325 | 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. 326 | 327 | ## keychain 2.5.5 (28 Jul 2005) 328 | 329 | * 28 Jul 2005; Aron Griffis : 330 | Add the `--env` option and automatic reading of `.keychain/env`. This allows variables such as PATH to be overridden for peculiar environments 331 | 332 | ## keychain 2.5.4.1 (11 May 2005) 333 | 334 | * 11 May 2005; Aron Griffis : 335 | 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 336 | 337 | ## keychain 2.5.4 (11 May 2005) 338 | 339 | * 11 May 2005; Aron Griffis : 340 | 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. 341 | Fix bug 87340: Use files instead of symlinks for locking, since symlink creation is not atomic on cygwin. 342 | 343 | ## keychain 2.5.3.1 (10 Mar 2005) 344 | 345 | * 10 Mar 2005; Aron Griffis : 346 | Fix problem introduced in 2.5.3 wrt adding gpg keys to the agent. Thanks to Azarah for spotting it. 347 | 348 | ## keychain 2.5.3 (09 Mar 2005) 349 | 350 | * 09 Mar 2005; Aron Griffis : 351 | Improve handling of DISPLAY by unsetting if blank. Call gpg with `--use-agent` explicitly. 352 | 353 | ## keychain 2.5.2 (06 Mar 2005) 354 | 355 | * 06 Mar 2005; Aron Griffis : 356 | 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. 357 | 358 | ## keychain 2.5.1 (12 Jan 2005) 359 | 360 | * 12 Jan 2005; Aron Griffis : 361 | Don't accidentally inherit a forwarded agent when inheritwhich=local-once. Move the --stop warning after the version splash. 362 | 363 | ## keychain 2.5.0 (07 Jan 2005) 364 | 365 | * 07 Jan 2005; Aron Griffis : 366 | 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. 367 | 368 | ## keychain 2.4.3 (17 Nov 2004) 369 | 370 | * 17 Nov 2004; Aron Griffis : 371 | 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. 372 | 373 | ## keychain 2.4.2.1 (30 Sep 2004) 374 | 375 | * 30 Sep 2004; Aron Griffis : 376 | Fix minor issues in the test for existing gpg keys wrt DISPLAY 377 | 378 | ## keychain 2.4.2 (29 Sep 2004) 379 | 380 | * 29 Sep 2004; Aron Griffis : 381 | 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. 382 | 383 | ## keychain 2.4.1 (22 Sep 2004) 384 | 385 | * 22 Sep 2004; Aron Griffis : 386 | 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 387 | * 15 Sep 2004; Aron Griffis : 388 | Fix pod2man output so it formats properly on SGI systems. Thanks to Matthew Moore for reporting the problem. 389 | 390 | ## keychain 2.4.0 (09 Sep 2004) 391 | 392 | * 09 Sep 2004; Aron Griffis : 393 | Fix bug 26970 with first pass at gpg-agent support 394 | * Fix Debian bug 269722; don't filter output of ssh-add 395 | * Fix bug reported by Marko Myllynen regarding keychain and Solaris awk's inability to process -F'[ :]' 396 | * Fix bug in now_seconds calculation, noticed by me. 397 | 398 | ## keychain 2.3.5 (28 Jul 2004) 399 | 400 | * 28 Jul 2004; Aron Griffis : 401 | Fix bug 58623 with patch from Daniel Westermann-Clark; don't put an extra newline in the output of listmissing 402 | * Generate keychain.spec from keychain.spec.in automatically so that the version can be set appropriately. 403 | 404 | ## keychain 2.3.4 (24 Jul 2004) 405 | 406 | * 24 Jul 2004; Aron Griffis : 407 | Fix bug 28599 reported by Bruno Pelaia; ignore defunct processes in ps output 408 | 409 | ## keychain 2.3.3 (30 Jun 2004) 410 | 411 | * 30 Jun 2004; Aron Griffis : 412 | Fix bug reported by Matthew S. Moore in email; escape the backticks in --help output 413 | * Fix bug reported by Herbie Ong in email; set pidf, cshpidf and lockf variables after parsing command-line to honor --dir setting 414 | * Fix bug reported by Stephan Stahl in email; make spaces in filenames work throughout keychain, even in pure Bourne shell 415 | * Fix operation on HP-UX with older OpenSSH by interpreting output of ssh-add as well as the error status 416 | 417 | ## keychain 2.3.2 (16 Jun 2004) 418 | 419 | * 16 Jun 2004; Aron Griffis : 420 | Fix bug 53837 (keychain needs ssh-askpass) by unsetting SSH_ASKPASS when --nogui is specified 421 | 422 | ## keychain 2.3.1 (03 Jun 2004) 423 | 424 | * 03 Jun 2004; Aron Griffis : 425 | Fix bug 52874: problems when the user is running csh 426 | 427 | ## keychain 2.3.0 (14 May 2004) 428 | 429 | * 14 May 2004; Aron Griffis : 430 | Rewrite the locking code to avoid procmail 431 | 432 | ## keychain 2.2.2 (03 May 2004) 433 | 434 | * 03 May 2004; Aron Griffis : 435 | Call loadagent prior to generating `$HOSTNAME-csh` file so that variables are set. 436 | 437 | ## keychain 2.2.1 (27 Apr 2004) 438 | 439 | * 27 Apr 2004; Aron Griffis : 440 | 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. 441 | 442 | ## keychain 2.2.0 (21 Apr 2004) 443 | 444 | * 21 Apr 2004; Aron Griffis : 445 | 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). 446 | * 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. 447 | 448 | ## keychain 2.0.3 (06 Apr 2003) 449 | 450 | * 06 Apr 2003; Seth Chandler : 451 | 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 452 | 453 | ## keychain 2.0.2 (26 Aug 2002) 454 | 455 | * 26 Aug 2002; the Tru64 fix didn't work; it was being caused by "trap - foo" rather than "tail +2 -". Now really fixed. 456 | * 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. 457 | 458 | ## keychain 2.0.1 (24 Aug 2002) 459 | 460 | * 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. 461 | * 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. 462 | * 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. 463 | * 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. 464 | 465 | ## keychain 2.0 (17 Aug 2002) 466 | 467 | * 17 Aug 2002; (Many submitters): A fix for keychain when running on HP-UX 10.20. 468 | * 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") 469 | * 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. 470 | * 17 Aug 2002; Fred Carter : Cygwin fix to use proper "ps" options. 471 | * 17 Aug 2002; Adrian Howard : patch so that lockfile gets removed even if --noask is specified. 472 | * 17 Aug 2002; Mario Wolff : Replaced an awk dependency with a shell construct for improved performance. 473 | * 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. 474 | * 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! 475 | 476 | ## keychain 1.9 (04 Mar 2002) 477 | 478 | * 04 Mar 2002; changed license from "GPL, v2 or later" to "GPL v2". 479 | * 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. 480 | * 06 Dec 2001; several people: Solaris doesn't like '-e' comparisons; switched to '-f' 481 | 482 | ## keychain 1.8 (29 Nov 2001) 483 | 484 | * 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. 485 | * 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. 486 | * 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. 487 | * 09 Nov 2001; lockfile settings tweak 488 | * 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. 489 | * 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! 490 | * 09 Nov 2001; Victor Leitman (vleitman@yahoo.com) CYAN color misdefined; fixed. 491 | * 27 Oct 2001; Brian Wellington (bwelling@xbill.org) A "quiet mode" (--quiet) fix; I missed an "echo". 492 | * 27 Oct 2001; J.A. Neitzel (jan@belvento.org) Missed another "kill -9"; it's now gone. 493 | 494 | ## keychain 1.7 (21 Oct 2001) 495 | 496 | * 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. 497 | * 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. 498 | * 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). 499 | * 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. 500 | * 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" 501 | * 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). 502 | * 21 Oct 2001; Jonathan Wakely (redi@redi.uklinux.net): Small patch to convert "echo -n -e" to "echo -e "\c"" for FreeBSD compatibility. 503 | 504 | ## keychain 1.6 (15 Oct 2001) 505 | 506 | * 13 Oct 2001; Ralf Horstmann (ralf.horstmann@webwasher.com): Add /usr/ucb to path for Solaris systems. 507 | * 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! 508 | 509 | ## keychain 1.5 (21 Sep 2001) 510 | 511 | * 21 Sep 2001; David Hull (hull@paracel.com): misc. compatibility, signal handling, cleanup fixes 512 | * 21 Sep 2001; "ps" test to find the right one for your OS. 513 | * 20 Sep 2001; Marko Myllynen (myllynen@lut.fi): "grep [s]sh-agent" to "grep [s]sh-agent" (zsh fix) 514 | 515 | ## keychain 1.4 (20 Sep 2001) 516 | 517 | * 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. 518 | * 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. 519 | * 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") 520 | * 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 521 | 522 | ## keychain 1.3 (12 Sep 2001) 523 | 524 | * 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. 525 | * 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. 526 | * 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. 527 | * 10 Sep 2001; Johann Visagie (johann@egenetics.com): "source" to "." shell-compatibility fixes. Thanks for the FreeBSD port. 528 | * 10 Sep 2001; Marko Myllynen (myllynen@lut.fi): rm -f \$pidf after stopping ssh-agent fix 529 | 530 | ## keychain 1.2 (09 Sep 2001) 531 | 532 | * 09 Sep 2001; README updates to reflect new changes. 533 | * 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! 534 | 535 | ## keychain 1.1 (07 Sep 2001) 536 | 537 | * 07 Sep 2001; Addition of README stating that keychain requires bash 2.0 or greater, as well as quick install directions and web URL. 538 | * 07 Sep 2001; Explicitly added /sbin and /usr/sbin to path, and then called "pidof". I think that this is a bit more robust. 539 | * 06 Sep 2001; from John Ellson (ellson@lucent.com): "pidof" changed to "/sbin/pidof", since it's probably not in \$PATH 540 | * 06 Sep 2001; New ChangeLog! :) 541 | 542 | ## keychain 1.0 (Aug 2001) 543 | * initial release 544 | -------------------------------------------------------------------------------- /MAINTAINERS.txt: -------------------------------------------------------------------------------- 1 | Originally authored by Daniel Robbins 2 | Maintained August 2002 - April 2003 by Seth Chandler 3 | Maintained and rewritten April 2004 - July 2007 by Aron Griffis 4 | Maintained July 2009 - Sept 2017 by Daniel Robbins 5 | Maintained September 2017 - 2018 by Ryan Harris 6 | Maintained currently by Daniel Robbins 7 | 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # For BSD, AIX, Solaris: 2 | V:sh = cat VERSION 3 | D:sh = date +'%d %b %Y' 4 | Y:sh = date +'%Y' 5 | 6 | # for GNU Make: 7 | V ?= $(shell cat VERSION) 8 | D ?= $(shell date +'%d %b %Y') 9 | Y ?= $(shell date +'%Y') 10 | 11 | TARBALL_CONTENTS=keychain README.md ChangeLog.md COPYING.txt MAINTAINERS.txt keychain.pod keychain.1 keychain.spec 12 | 13 | all: keychain.1 keychain keychain.spec 14 | 15 | .PHONY : tmpclean 16 | tmpclean: 17 | rm -rf dist keychain.1.orig keychain.txt 18 | 19 | .PHONY : clean 20 | clean: tmpclean 21 | rm -rf keychain.1 keychain keychain.spec 22 | 23 | keychain.spec: keychain.spec.in keychain.sh 24 | sed 's/KEYCHAIN_VERSION/$V/' keychain.spec.in > keychain.spec 25 | 26 | keychain.1: keychain.pod keychain.sh 27 | pod2man --name=keychain --release=$V \ 28 | --center='https://www.funtoo.org' \ 29 | keychain.pod keychain.1 30 | sed -i.orig -e "s/^'br/.br/" keychain.1 31 | 32 | keychain.1.gz: keychain.1 33 | gzip -9 keychain.1 34 | 35 | GENKEYCHAINPL = open P, "keychain.txt" or die "cannot open keychain.txt"; \ 36 | while (

) { \ 37 | $$printing = 0 if /^\w/; \ 38 | $$printing = 1 if /^(SYNOPSIS|OPTIONS)/; \ 39 | $$printing || next; \ 40 | s/\$$/\\\$$/g; \ 41 | s/\`/\\\`/g; \ 42 | s/\\$$/\\\\/g; \ 43 | s/\*(\w+)\*/\$${CYAN}$$1\$${OFF}/g; \ 44 | s/(^|\s)(-+[-\w]+)/$$1\$${GREEN}$$2\$${OFF}/g; \ 45 | $$pod .= $$_; \ 46 | }; \ 47 | open B, "keychain.sh" or die "cannot open keychain.sh"; \ 48 | $$/ = undef; \ 49 | $$_ = ; \ 50 | s/INSERT_POD_OUTPUT_HERE[\r\n]/$$pod/ || die; \ 51 | s/\#\#VERSION\#\#/$V/g || die; \ 52 | print 53 | 54 | keychain: keychain.sh keychain.txt VERSION MAINTAINERS.txt 55 | perl -e '$(GENKEYCHAINPL)' | sed -e 's/##CUR_YEAR##/$(Y)/g' >keychain || rm -f keychain 56 | chmod +x keychain 57 | 58 | keychain.txt: keychain.pod 59 | pod2text keychain.pod keychain.txt 60 | 61 | keychain-$V.tar.gz: $(TARBALL_CONTENTS) 62 | mkdir keychain-$V 63 | cp $(TARBALL_CONTENTS) keychain-$V 64 | /bin/tar czvf keychain-$V.tar.gz keychain-$V 65 | rm -rf keychain-$V 66 | ls -l keychain-$V.tar.gz 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Introduction to Keychain 3 | ======================== 4 | 5 | `Keychain` helps you to manage SSH and GPG keys in a convenient and secure 6 | manner. It acts as a frontend to `ssh-agent` and `ssh-add`, but allows you 7 | to easily have one long running `ssh-agent` process per system, rather than 8 | the norm of one `ssh-agent` per login session. 9 | 10 | This dramatically reduces the number of times you need to enter your 11 | passphrase. With `keychain`, you only need to enter a passphrase once every 12 | time your local machine is rebooted. `Keychain` also makes it easy for remote 13 | cron jobs to securely "hook in" to a long running `ssh-agent` process, 14 | allowing your scripts to take advantage of key-based logins. 15 | 16 | `Keychain` also integrates with `gpg-agent`, so that GPG keys can be cached 17 | at the same time as SSH keys. 18 | 19 | **Additional documentation for Keychain can be found on [the Keychain 20 | wiki page](https://www.funtoo.org/Funtoo:Keychain).** 21 | 22 | 23 | IMPORTANT - GitHub Contributors 24 | =============================== 25 | 26 | Please submit pull requests against the `master` branch which should track official 27 | releases. Before submitting your PR, please: 28 | 29 | 1. Make sure that you have [ShellCheck](https://shellcheck.net) enabled in your 30 | IDE and that your changes don't introduce any bashisms or other non-POSIX things. 31 | For any *intended* exceptions, such as non-quoting of expanded variables, please 32 | insert a commented ShellCheck exception to disable the warning, and if not totally 33 | obvious, then add a comment to the exception like this: 34 | 35 | # shellcheck disable=SC2086 # this is intentional: 36 | 37 | If you do not understand a ShellCheck warning, then don't just blindly disable it. 38 | Do some research first, make any necessary changes, and then submit your PR. 39 | 2. Please use tabs for initial indentation, not spaces. 40 | 3. Don't use tabs at the end of lines, such as to align comments. Either use a full 41 | line to add a comment or add a short comment at the end of a command, separating 42 | the "#" from the actual command with just a single space. 43 | 4. For any new features or options, update `keychain.pod` with documentation on how 44 | to use the new feature. 45 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 2.9.5 2 | -------------------------------------------------------------------------------- /keychain.pod: -------------------------------------------------------------------------------- 1 | =head1 NAME 2 | 3 | keychain - Manager for ssh-agent, gpg-agent and private keys. Compatible with POSIX systems. 4 | 5 | =head1 SYNOPSIS 6 | 7 | S 8 | S<--extended --gpg2 --help --ignore-missing --list --noask --nocolor --nogui> 9 | S<--noinherit --nolock --quick --quiet --ssh-allow-forwarded --ssh-allow-gpg> 10 | S<--ssh-rm --ssh-spawn-gpg --systemd --version ] [ --ssh-agent-socket I ]> 11 | S<[ --dir I ] [ --host I ] [ --lockwait I ]> 12 | S<[ --stop I ] [ --timeout I ] [ --wipe I ] [ keys... ]> 13 | 14 | =head1 INTRODUCTION 15 | 16 | B helps you to manage SSH and GPG keys in a convenient and secure 17 | manner. It acts as a frontend to C and C, but allows you 18 | to easily have one long-running C process per system, rather than 19 | the norm of one C per login session. 20 | 21 | This dramatically reduces the number of times you need to enter your 22 | passphrase. With C, you only need to enter a passphrase once every 23 | time your local machine is rebooted. Keychain also makes it easy for remote 24 | cron jobs to securely "hook in" to a long running C process, 25 | allowing your scripts to take advantage of key-based logins. 26 | 27 | Keychain also supports GnuPG 2.1 and later, and will automatically start 28 | gpg-agent if any GPG keys are referenced on the command-line, and will ensure 29 | these credentials are cached in memory and available for use. 30 | 31 | Keychain supports most UNIX-like operating systems. It supports integration 32 | with Bourne-compatible, csh-compatible and fish shells. 33 | 34 | Additional documentation for Keychain can be found on 35 | L. 36 | 37 | =head1 LIFECYCLE 38 | 39 | Typically, you configure keychain to run when you first log in to a system. 40 | If you are using Bourne shell or bash, you will create a F<~/.profile> or 41 | F<~/.bash_profile> file and include the following line in it: 42 | 43 | eval "$(keychain --eval id_rsa)" 44 | 45 | Keychain will start ssh-agent if one isn't already running. Keychain then 46 | checks to make sure your private keys (in this example, "id_rsa") are loaded 47 | into the agent. If they are not, you are prompted for any passphrase necessary 48 | to decrypt them, so that they are cached in memory and available for use. 49 | 50 | In addition to printing some user-friendly output to your terminal, keychain 51 | will also output important ssh-agent environment variables, which the S<"$( )"> 52 | (you can also use S<"` `">) captures, and the "eval" evaluates, setting these 53 | variables in your current shell. 54 | 55 | These ssh-agent environment variables are also written to 56 | F<~/.keychain/${HOSTNAME}-sh>, so that subsequent logins and non-interactive 57 | shells such as cron jobs can source the file to access the running ssh-agent 58 | and make passwordless ssh connections using the cached private keys -- 59 | even when you are logged out. These files are collectively called B. 60 | 61 | The key files specified on the command-line will be searched for in the 62 | F<~/.ssh/> directory, and keychain will expect to find the private key file 63 | with the same name, as well as a C<.pub> public key. Keychain will also 64 | see if any GPG keys are specified, and if so, prompt for any passphrases 65 | to cache these keys into C. 66 | 67 | Typically, private SSH key files are specified by filename only, without path, 68 | although it is possible to specify an absolute or relative 69 | path to the private key file as well. Private key files can be symlinks 70 | to the actual key as long as your system has the C command available. 71 | More advanced features are available for specifying keys as well -- see the 72 | B<--extended> and B<--confallhosts> options for more information. 73 | 74 | In addition, for GPG keys specified, similar steps will be taken to ensure 75 | that gpg-agent has the GPG key cached in memory and ready for use. 76 | 77 | =head1 STREAMLINING AND SIMPLIFICATION 78 | 79 | Keychain 2.9.0 has been streamlined, and with this maintenance several 80 | command-line options have been retired as they are not completely necessary. 81 | This simplifies the use of the tool by making it more intuitive to use. 82 | The files created in F<~/.keychain> have also been cleaned up. This section 83 | details all the important changes. 84 | 85 | =head2 PIDFILE CHANGES 86 | 87 | "Pidfile" is the nickname for files created in F<~/.keychain> which can then 88 | be sourced by your scripts to access a running agent. 89 | 90 | When using gpg-agent for GPG keys, keychain will no longer create a 91 | F<~/.keychain/${HOSTNAME}-sh-gpg> pidfile. This file is no longer needed 92 | as the canonical GPG socket inside F<~/.gnupg/> will be used to detect the 93 | running gpg-agent, which is the modern convention. GnuPG 2.1 and later 94 | have stopped using environment variables to find the agent, so we follow 95 | this upstream change. 96 | 97 | =head2 IMPROVED DEBUGGING 98 | 99 | A new B<--debug> option is now available which will print additional information 100 | related to keychain's decisions regarding why and how an agent was found -- or 101 | not. 102 | 103 | =head2 NEW (AND DEPRECATED) OPTIONS 104 | 105 | This section provides an overview of new and deprecated command-line options. 106 | For full details on each option, see the respective option definition under 107 | L. 108 | 109 | =head3 Keychain 2.9.2 110 | 111 | The C<--confhost> option has been deprecated. Instead of C<--confhost hostname>, 112 | use C<--extended host:hostname>. This extended format allows multiple keys of 113 | multiple types (SSH, GPG and SSH-from-hostname) to be specified on the 114 | command-line together. This is also fully compatible with C<--confallhosts>, 115 | and keychain now de-duplicates the list of keys to be loaded. 116 | 117 | =head3 Keychain 2.9.1 118 | 119 | The short-lived C<--ssh-wipe> and C<--gpg-wipe> options that appeared only in 120 | version 2.9.0 were replaced with C<--wipe I> to work similarly to 121 | the C<--stop> option, and allows you to specify "ssh", "gpg" or "all". 122 | 123 | =head3 Keychain 2.9.0 124 | 125 | The C<--agents> option is now deprecated. Keychain will always ensure an 126 | ssh-agent or equivalent is running, or if C<--ssh-spawn-gpg> is used, 127 | potentially a gpg-agent for the purpose of storing SSH keys if no running 128 | ssh-agent is available. To simply use a gpg-agent if one is already running, 129 | falling back to launching ssh-agent if no agent is available, use the 130 | C<--ssh-allow-gpg> option. 131 | 132 | Specifying a GPG key on the command-line will instruct keychain to 133 | enable gpg-agent functionality automatically. This eliminates an option 134 | that you need to specify (C<--agents ssh,gpg>) when invoking keychain, 135 | and for many will avoid spawning a GPG agent you may not be using. 136 | 137 | Specifying the C<--agents> option will now display a warning that it's 138 | deprecated, but keychain will not abort. 139 | 140 | The C<--inherit> option, which took one of four arguments, has been 141 | deprecated. Keychain's default behavior remains that of preferring to 142 | use an ssh-agent or equivalent referenced by its pidfile, falling 143 | back to finding an ssh-agent in its environment. By default, keychain 144 | will not use a gpg-agent socket for SSH keys unless at least C<--ssh-allow-gpg> 145 | is specified. Similarly, the use of any forwarded SSH agent connection 146 | is disabled by default and can be enabled via C<--ssh-allow-forwarded>. 147 | Again, see the full documentation for each option in the L 148 | section. 149 | 150 | You can still influence keychain's behavior via the still-present 151 | C<--noinherit> option which will prevent all detection of existing 152 | SSH agents via the environment. 153 | 154 | The C<--clear> option is still available, but isn't intended to be a 155 | "standalone" option, meaning that it is used to perform an initial clearing 156 | of cached keys before loading any specified keys when Keychain is run. 157 | To perform the sole action of wiping all cached keys, use the C<--wipe> 158 | action. To remove an individual cached SSH private 159 | key or keys, use the C<--ssh-rm> I option. 160 | 161 | The C<--stop> option will now only stop any running ssh-agent processes, 162 | and still supports three possible options: "mine", "others" and "all". 163 | It no longer stops gpg-agent processes, which tend to get auto-respawned 164 | by GPG tools, so killing gpg-agent typically doesn't make a lot of sense. 165 | 166 | =head2 BETTER GNUPG INTEGRATION 167 | 168 | Keychain can now use an existing gpg-agent that has been started in your 169 | environment to store ssh keys, rather than spawning its own ssh-agent, by 170 | using the C<--ssh-allow-gpg> option. 171 | 172 | If you would like keychain to spawn gpg-agent instead of ssh-agent, and 173 | use it to store SSH keys, specify the "--ssh-spawn-gpg" option. 174 | 175 | Without either option, keychain will not use an SSH_AUTH_SOCK that is 176 | provided by gpg-agent, and will spawn an official ssh-agent process. 177 | 178 | In addition, behind the scenes, keychain now uses the gpg-connect-agent 179 | executable to restart the agent, get official PID and socket information, etc. 180 | 181 | Please note that while gpg-agent provides full compatibility with ssh-agent, 182 | its password prompt is handled by pinentry and its store may encrypt your 183 | in-memory keys. For this reason, consider 184 | this new feature experimental, and use GitHub issues to report back any 185 | anomalies or suggested improvements for gpg-agent integration. 186 | 187 | =head2 DISPLAY CHANGES 188 | 189 | When keychain uses gpg-agent for either GnuPG or SSH support, then keychain will display 190 | the GnuPG socket file in its output, rather than the PID. Since the socket 191 | file has the F<~/.gnupg> path in it, this communicates to you that gpg-agent, 192 | not ssh-agent, is active. If you see an integer PID, this means that ssh-agent 193 | is being used. 194 | 195 | =head2 STREAMLINED STARTUP 196 | 197 | By default, keychain will always ensure that an ssh-agent should be started. 198 | It will only start a gpg-agent if a GPG key is referenced on the command-line. 199 | 200 | Modern versions of gpg-agent also support the caching of SSH keys, allowing it 201 | to be a drop-in replacement for ssh-agent. With keychain 2.9.0, a new 202 | "--ssh-spawn-gpg" option has been added, which when specified will give 203 | keychain permission to spawn a gpg-agent in place of ssh-agent. 204 | 205 | =head2 CODE OPTIMIZATION 206 | 207 | With keychain 2.9.0, there has been significant code cleanup, reducing the size 208 | of the script from 1500 lines to about 1100 lines. In addition, the script is 209 | now fully compliant with L, which will be 210 | hugely helpful to ensure continued POSIX shell compatibility moving forward. 211 | 212 | =head1 AGENT DETECTION AND STARTUP ALGORITHM 213 | 214 | This section documents the official algorithm used for detecting and if necessary 215 | starting ssh-agent, to facilitate understanding as well as developer maintenance 216 | of the codebase. 217 | 218 | =head2 DEFINITIONS 219 | 220 | There are several important definition related to the algorithm: 221 | 222 | =over 223 | 224 | =item 1. The B, "ssh-agent", which is a long-running daemon. This can also 225 | in some cases be "gpg-agent", depending on command-line options. 226 | 227 | =item 2. The B, which is the agent or forwarded agent that was not started by keychain, 228 | but is detected in the environment or by other means. 229 | 230 | =item 3. The B, which is an B whose information has 231 | been persisted by being written to the B (see below). 232 | 233 | =item 4. The B C, which points to the socket file 234 | used to communicate with ssh-agent, and optionally C, which indicates 235 | its process ID if running locally (although gpg-agent does not define C, 236 | even if running locally.) 237 | 238 | =item 5. The file F<~/.keychain/${HOSTNAME}-sh> and related files, which are 239 | collectively referred to as "B". 240 | Pidfiles are used to persistently store C and C 241 | environment variables for use by other scripts, as well as by keychain itself, 242 | formatted so that they can be "sourced" by shells of various types. 243 | 244 | =item 6. Relevant B affecting behavior, which include B<--noinherit>, 245 | B<--ssh-allow-gpg>, B<--ssh-spawn-gpg>, and B<--ssh-allow-forwarded>. 246 | 247 | =back 248 | 249 | =head2 ALGORITHM OVERVIEW 250 | 251 | When the keychain script is run, it will first attempt to find a running ssh-agent. 252 | 253 | =over 254 | 255 | =item Phase 1: pidfile: To do this, it will first look for an existing B. If one exists, it will 256 | be inspected and used to find a running agent, in alignment with specified 257 | B. If this process is successful, a "keychain-spawned" agent is 258 | found and this process is complete. Otherwise, we continue to the next step. 259 | 260 | =item Phase 2: environment: If keychain's B did not yield a running agent, keychain looks at 261 | B defined in the current environment. This step will be skipped if the 262 | B<--noinherit> option is specified. If an agent is found 263 | that is in alignment with specified B, it is considered "B" by keychain, 264 | and the process is complete. Otherwise, we continue to the next step. 265 | 266 | =item Phase 3: spawn agent: In the absence of finding a keychain-spawned or existing agent that can be 267 | adopted, keychain will spawn a new ssh-agent, or a new gpg-agent if 268 | B<--ssh-spawn-gpg> is specified and gpg-agent is available. 269 | 270 | =item Final Phase: update pidfile: In addition, the Bs will be updated to reflect the keychain-spawned or 271 | B<"inherited"> agent. An B<"inherited"> agent, once written to the B, is now considered 272 | to be B<"adopted">. 273 | 274 | =item Pidfile update exception: If the B<--ssh-allow-forwarded> option was specified, 275 | and a forwarded SSH socket was found -- which is identified as a valid SSH 276 | socket defined in a C variable, which has no associated or 277 | valid C also defined in the environment and is also determined to not 278 | be the socket of any running gpg-agent -- then this agent will simply be used, B in any 279 | B. This is because this SSH-supplied 280 | socket will disappear when the underlying SSH connection terminates, and thus 281 | it cannot be relied on to be available persistently. 282 | 283 | =back 284 | 285 | =head2 THE QUICK SHORT-CIRCUIT 286 | 287 | When the B<--quick> option is specified, a special algorithm will run prior to the 288 | main agent-detection algorithm listed above. A pidfile, if it exists, will be 289 | evaluated as per Phase 1 of the main algorithm. If a valid running agent 290 | is found, it will be queried for valid keys. If at least one valid key is loaded 291 | into the agent, the quick start is considered successful, and keychain will skip 292 | the regular agent startup algorithm, and will use this found agent. 293 | 294 | =head2 SUMMARY AND RATIONALE 295 | 296 | The keychain ssh-agent detection and startup algorithm is somewhat sophisticated for 297 | a reason. There is an intention behind its behavior. 298 | 299 | The algorithm has been specifically designed to prefer an agent spawned by keychain, 300 | or previously adopted, if that agent is currently available. This is by design, because 301 | other system software could spawn ssh-agent and/or gpg-agent processes, and we want keychain to 302 | not coerced into using these new agents which may suddenly appear in the environment 303 | unexpectedly when new desktop sessions start and in other circumstances. If keychain 304 | is too "suggestible", it will lose track of the agent which currently holds valid keys, 305 | which can result in unnecessary prompting for passphrases, and general confusion. 306 | 307 | =head1 OPTIONS 308 | 309 | =over 310 | 311 | =item B<--absolute> 312 | 313 | This option can be used with the B<--dir> option, if you would like to specify a 314 | non-default directory to store pidfiles (defaults to F<~/.keychain>). When this 315 | option is used, the script does not automatically append F to the 316 | path, allowing you to use any arbitrary directory name for the storing of pidfiles. 317 | Please note that Keychain 2.9.3 adds some extra security checks related to 318 | directory and file permissions -- you must have exclusive ownership of any 319 | directory that keychain uses to store pidfiles, or keychain will abort. 320 | 321 | =item B<--clear> 322 | 323 | When specified, this option adds an initial step prior to adding any keys 324 | to the agents of wiping all existing cached keys/passphrases. 325 | This is intended to be used alongside keychain --eval to ensure that only the specified 326 | keys are loaded, and that keychain should assume that you are an intruder 327 | until proven otherwise and force all interactive logins to specify valid 328 | passphrases. This option increases security and still allows your 329 | cron jobs to use your ssh keys when you're logged out. 330 | 331 | =item B<--confallhosts> 332 | 333 | In addition to any keys specified on the command-line, this option will 334 | tell keychain to scour F<~/.ssh/config> for all private keys referenced 335 | in all C lines, and load all keys for all hosts. 336 | 337 | =item B<--confirm> 338 | 339 | Keys are subject to interactive confirmation by the SSH_ASKPASS 340 | program before being used for authentication. See the -c option for 341 | ssh-add(1). 342 | 343 | =item B<--debug> 344 | 345 | Keychain 2.9.0 introduces the B<--debug> option, which will output 346 | additional information related to how Keychain makes its agent-selection 347 | process. Specifically, it will output when an B is rejected 348 | because it is being supplied by gpg-agent -- and this is not allowed 349 | due to no B<--ssh-allow-gpg> option, or when it is rejected because it 350 | appears to be from a forwarded SSH connection, and B<--ssh-allow-forwarded> 351 | was not supplied. 352 | 353 | =item B<--dir> I 354 | 355 | This option allows you to use another directory besides F<$HOME/.keychain> 356 | for the storing of pidfiles. Please note that Keychain 2.9.3 adds some 357 | extra security checks related to directory and file permissions -- you 358 | must have exclusive ownership of any directory that keychain uses to store 359 | pidfiles, or the script will abort. Also see the B<--absolute> option. 360 | 361 | =item B<--env> I 362 | 363 | After parsing options, keychain will load additional environment 364 | settings from "filename". By default, if "--env" is not given, then 365 | keychain will attempt to load from F<~/.keychain/[hostname]-env> or 366 | alternatively F<~/.keychain/env>. The purpose of this file is to 367 | override settings such as PATH, in case ssh is stored in 368 | a non-standard place. 369 | 370 | =item B<--eval> 371 | 372 | Keychain will print lines to be evaluated in the shell on stdout. It 373 | respects the SHELL environment variable to determine if Bourne shell 374 | or C shell output is expected. 375 | 376 | =item B<--extended> 377 | 378 | This enables extended command-line key processing with more features, 379 | and is a replacement for the old C<--confhost> option. When specified, 380 | each key specified on the command-line must have a prefix to explicitly 381 | categorize it. SSH keys must have a prefix of "sshk:" immediately 382 | followed by the path or key name (the part after the "sshk:" is processed 383 | just like a SSH key is without the C<--extended> option). GPG keys must 384 | be in the format "gpgk:" immediately followed by the 8 or 16-character 385 | fingerprint. If "host:" is specified, then Keychain will 386 | extract the SSH configuration for the specified hostname, grab all 387 | identityfile options (private keys) specified, and these keys will be 388 | included in the set of keys to be loaded by keychain. This allows 389 | multiple keys of multiple types, including SSH-keys-by-host, to be 390 | specified together, which wasn't possible with C<--confhost>. 391 | 392 | =item B<--gpg2> 393 | 394 | This option changes the default gpg calls to use gpg2 instead to support 395 | distributions such as Ubuntu which has both gpg and gpg2 396 | 397 | =item B<--help -h> 398 | 399 | Show help that looks remarkably like this man-page. As of 2.6.10, 400 | help is sent to stdout so it can be easily piped to a pager. 401 | 402 | =item B<--host> I 403 | 404 | Set alternate hostname for creation of pidfiles 405 | 406 | =item B<--ignore-missing> 407 | 408 | Don't warn if some keys on the command-line can't be found. This is 409 | useful for situations where you have a shared .bash_profile, but your 410 | keys might not be available on every machine where keychain is run. 411 | 412 | =item B<-l --list> 413 | 414 | List signatures of all active SSH keys, and exit, similar to "ssh-add -l". 415 | 416 | =item B<-L --list-fp> 417 | 418 | List fingerprints of all active SSH keys, and exit, similar to "ssh-add -L". 419 | 420 | =item B<--lockwait> I 421 | 422 | How long to wait for the lock to become available. Defaults to 5 423 | seconds. Specify a value of zero or more. If the lock cannot be 424 | acquired within the specified number of seconds, then this keychain 425 | process will forcefully acquire the lock. 426 | 427 | =item B<--noask> 428 | 429 | This option tells keychain do everything it normally does (ensure 430 | ssh-agent is running, set up the F<~/.keychain/[hostname]-{c}sh> files) 431 | except that it will not prompt you to add any of the keys you 432 | specified if they haven't yet been added to ssh-agent. 433 | 434 | =item B<--nocolor> 435 | 436 | Disable color highlighting for non ANSI-compatible terms. 437 | 438 | =item B<--nogui> 439 | 440 | Don't honor SSH_ASKPASS, if it is set. This will cause ssh-add to 441 | prompt on the terminal instead of using a graphical program. 442 | 443 | =item B<--noinherit> 444 | 445 | Don't inherit any agent processes, overriding the default behavior 446 | of inheriting all non-forwarded ssh-agent and any existing 447 | gpg-agent processes. Also see L. 448 | 449 | =item B<--nolock> 450 | 451 | Don't attempt to use a lockfile while manipulating files, pids and 452 | keys. 453 | 454 | =item B<--query> 455 | 456 | Keychain will print lines in KEY=value format representing the values 457 | which are set by the agents. 458 | 459 | =item B<--quick -Q> 460 | 461 | If an ssh-agent process is running then use it. Don't verify the list 462 | of keys, other than making sure it's non-empty. This option avoids 463 | locking when possible so that multiple terminals can be opened 464 | simultaneously without waiting on each other. See the 465 | L section for more information regarding 466 | how this fits into the overall startup algorithm. 467 | 468 | =item B<--quiet -q> 469 | 470 | Only print messages in case of warning, error or required interactivity. As of 471 | version 2.6.10, this also suppresses "Identities added" messages for ssh-agent. 472 | 473 | =item B<--stop -k> I 474 | 475 | Kill currently running ssh-agent processes and exit. 476 | 477 | Note that previous versions of keychain (2.8.5 and earlier) allowed 478 | killing of gpg-agent as well. This functionality was removed as 479 | ssh-agent and gpg-agent have a bit different design philosophies 480 | and you almost always only have at most one gpg-agent running at 481 | a time. Use "killall gpg-agent" if you really want to kill gpg-agent. 482 | However, since this option also removes pidfiles, it will remove 483 | any gpg-agent processes adopted by keychain that were being used to 484 | store ssh keys. 485 | 486 | The following values are valid for "which" which controls which 487 | ssh-agents to target: 488 | 489 | =over 9 490 | 491 | =item all 492 | 493 | Kill all ssh-agent processes and quit keychain immediately. Prior to 494 | keychain-2.5.0, this was the behavior of the bare "--stop" option. 495 | 496 | =item others 497 | 498 | Kill agent processes other than the ones keychain is providing. Prior 499 | to keychain-2.5.0, keychain would do this automatically. The new 500 | behavior requires that you specify it explicitly if you want it. 501 | 502 | =item mine 503 | 504 | Kill keychain's agent processes, leaving other agents alone. 505 | 506 | =back 507 | 508 | =item B<--ssh-agent-socket> I 509 | 510 | Use this option to specify the path to the socket file that you would 511 | like ssh-agent to create and use as its official socket. By default, 512 | ssh-agent will create its own socket file, typically in /tmp. 513 | 514 | =item B<--ssh-allow-forwarded> 515 | 516 | By default, keychain will not use a forwarded ssh-agent connection, 517 | which is a ssh-agent socket created by SSH that has no associated 518 | local process. To permit keychain to use a forwarded ssh-agent 519 | connection, specify this option. If a SSH-forwarded socket is used, 520 | it will not be persisted in the pidfiles, as it is not likely to 521 | be available outside of the currently-active SSH session. 522 | 523 | =item B<--ssh-allow-gpg> 524 | 525 | Would you like to have keychain use an already-running gpg-agent to 526 | store your SSH keys, rather than spawning a new ssh-agent? This option 527 | does just that. When this option is specified, keychain will 528 | accept an SSH_AUTH_SOCK environment variable in its environment, even 529 | if it was created by gpg-agent. Modern versions of gpg-agent are also 530 | able to store SSH keys. By default, keychain has a special 531 | check to avoid using a gpg-agent that has set the SSH_AUTH_SOCK 532 | environment variable, and will instead spawn its own ssh-agent. With 533 | this option enabled, this restriction is turned off. 534 | Please note that this option does not actually instruct keychain to I a 535 | gpg-agent for storing SSH keys if no agent is available -- if you want that, 536 | see the B<--ssh-spawn-gpg> option, below. 537 | 538 | ALSO NOTE: When a gpg-agent is adopted for ssh-agent duties in this way, the 539 | F<~/.keychain/${HOSTNAME}-sh> pidfile will be updated to reference the 540 | gpg-agent socket, so it will be seamlessly used by future cron jobs needing 541 | an ssh-agent, as well as by future invocations of keychain, as long as the 542 | B<--ssh-allow-gpg> or B<--ssh-spawn-gpg> (which implies B<--ssh-allow-gpg>) 543 | are specified. 544 | 545 | =item B<--ssh-spawn-gpg> 546 | 547 | This is the option to use if you're really on-board with using gpg-agent 548 | as a replacement for ssh-agent. Not only will keychain use a running 549 | gpg-agent if found as per the B<--ssh-allow-gpg>, but if it needs to spawn 550 | a new ssh-agent, it will go ahead and spawn a gpg-agent in its place, 551 | and use it instead. Also see notes for the B<--ssh-allow-gpg> option, 552 | as this option also implies B<--ssh-allow-gpg>. 553 | 554 | =item B<--ssh-rm -r> I 555 | 556 | Only perform the single action of removing the specified cached keys from the 557 | running ssh-agent, and then exit. 558 | 559 | =item B<--systemd> 560 | 561 | Inject environment variables into the systemd --user session. 562 | 563 | =item B<--timeout> I 564 | 565 | Allows a timeout to be set for identities added to ssh-agent. When this option 566 | is used with a keychain invocation that starts ssh-agent itself, then keychain 567 | uses the appropriate ssh-agent option to set the default timeout for ssh-agent. 568 | The --timeout option also gets passed to ssh-add invocations, so any keys added 569 | to a running ssh-agent will be individually configured to have the timeout 570 | specified, overriding any ssh-agent default. 571 | 572 | Most users can simply use the timeout setting they desire and get the result 573 | they want -- with all identities having the specified timeout, whether added by 574 | keychain or not. More advanced users can use one invocation of keychain to set 575 | the default timeout, and optionally set different timeouts for keys added by 576 | using a subsequent invocation of keychain. 577 | 578 | =item B<--version -V> 579 | 580 | Show version information. 581 | 582 | =item B<--wipe> I 583 | 584 | Only perform the single action of wiping all agent's cached keys. Specify 585 | 'ssh', 'gpg' or 'all' for SSH keys, GPG keys and all agents respectively. 586 | Also see the C<--ssh-rm> action and the C<--clear> option. 587 | 588 | =back 589 | 590 | =head1 EXAMPLES 591 | 592 | This snippet should work in most shells to load two ssh keys and one gpg 593 | key: 594 | 595 | eval `keychain --eval id_rsa id_dsa 0123ABCD` 596 | 597 | For the fish shell, use the following format: 598 | 599 | if status --is-interactive 600 | keychain --eval --quiet -Q id_rsa | source 601 | end 602 | 603 | If you have trouble with that in csh: 604 | 605 | setenv SHELL /bin/csh 606 | eval `keychain --eval id_rsa id_dsa 0123ABCD` 607 | 608 | This is equivalent for Bourne shells (including bash and zsh) but 609 | doesn't use keychain's --eval feature: 610 | 611 | keychain id_rsa id_dsa 0123ABCD 612 | [ -z "$HOSTNAME" ] && HOSTNAME=`uname -n` 613 | [ -f $HOME/.keychain/$HOSTNAME-sh ] && \ 614 | . $HOME/.keychain/$HOSTNAME-sh 615 | 616 | This is equivalent for C shell (including tcsh): 617 | 618 | keychain id_rsa id_dsa 0123ABCD 619 | host=`uname -n` 620 | if (-f $HOME/.keychain/$host-csh) then 621 | source $HOME/.keychain/$host-csh 622 | endif 623 | 624 | Likewise, the following commands can be used in fish: 625 | 626 | keychain id_rsa id_dsa 0123ABCD 627 | test -z "$hostname"; and set hostname (uname -n) 628 | if test -f "$HOME/.keychain/$hostname-fish" 629 | source $HOME/.keychain/$hostname-fish 630 | end 631 | 632 | To load keychain variables from a script (for example from cron) and 633 | abort unless id_dsa is available: 634 | 635 | # Load keychain variables and check for id_dsa 636 | [ -z "$HOSTNAME" ] && HOSTNAME=`uname -n` 637 | . $HOME/.keychain/$HOSTNAME-sh 2>/dev/null 638 | ssh-add -l 2>/dev/null | grep -q id_dsa || exit 1 639 | 640 | =head1 SEE ALSO 641 | 642 | L, L, L, L 643 | 644 | =head1 NOTES 645 | 646 | Keychain was created and is currently maintained by Daniel Robbins. If you need 647 | to report a bug or request an enhancement, please report it to the GitHub 648 | project page at L. For more information 649 | about keychain, please visit L. 650 | -------------------------------------------------------------------------------- /keychain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | versinfo() { 4 | qprint 5 | qprint " Copyright ${CYANN}2009-##CUR_YEAR##${OFF} Daniel Robbins, Funtoo Solutions, Inc;" 6 | qprint " lockfile() Copyright ${CYANN}2009${OFF} Parallels, Inc." 7 | qprint " Copyright ${CYANN}2007${OFF} Aron Griffis;" 8 | qprint " Copyright ${CYANN}2002-2006${OFF} Gentoo Foundation;" 9 | qprint 10 | qprint " Keychain is free software: you can redistribute it and/or modify" 11 | qprint " it under the terms of the ${CYANN}GNU General Public License version 2${OFF} as" 12 | qprint " published by the Free Software Foundation." 13 | qprint 14 | } 15 | 16 | umask 0077 17 | NEWLINE=" 18 | " 19 | version=##VERSION## 20 | PATH="${PATH}${PATH:+:}/usr/bin:/bin:/sbin:/usr/sbin:/usr/ucb" 21 | unset pidfile_out 22 | unset myaction 23 | havelock=false 24 | unset hostopt 25 | extended=false 26 | confallhosts=false 27 | ignoreopt=false 28 | noaskopt=false 29 | noguiopt=false 30 | nolockopt=false 31 | lockwait=5 32 | openssh=unknown 33 | sunssh=unknown 34 | quickopt=false 35 | quietopt=false 36 | clearopt=false 37 | allow_inherited=true 38 | color=true 39 | unset stopwhich 40 | unset timeout 41 | unset ssh_agent_socket 42 | unset ssh_timeout 43 | unset sshavail 44 | unset sshkeys 45 | unset gpgkeys 46 | unset cmdline_keys 47 | keydir="${HOME}/.keychain" 48 | unset envf 49 | evalopt=false 50 | confirmopt=false 51 | absoluteopt=false 52 | systemdopt=false 53 | unset ssh_confirm 54 | unset GREP_OPTIONS 55 | gpg_prog_name="gpg" 56 | gpg_started=false 57 | ssh_allow_forwarded=false 58 | ssh_allow_gpg=false 59 | ssh_spawn_gpg=false 60 | debugopt=false 61 | CYAN="" 62 | CYANN="" 63 | GREEN="" 64 | RED="" 65 | PURP="" 66 | YEL="" 67 | OFF="" 68 | 69 | # GNU awk and sed have regex issues in a multibyte environment. If any locale 70 | # variables are set, then override by setting LC_ALL 71 | unset pinentry_locale 72 | if [ -n "$LANG$LC_ALL" ] || locale 2>/dev/null | grep -E -qv '="?(|POSIX|C)"?$' 2>/dev/null; then 73 | # save LC_ALL so that pinentry-curses works right. This has always worked 74 | # correctly for me but peper and kloeri had problems with it. 75 | pinentry_lc_all="$LC_ALL" 76 | LC_ALL=C 77 | export LC_ALL 78 | fi 79 | 80 | qprint() { 81 | # shellcheck disable=SC2048,SC2086 82 | $quietopt || echo "$@" >&2; return 0 83 | } 84 | 85 | mesg() { # general information; suppressed with --quiet 86 | qprint " ${GREEN}*${OFF} $*" 87 | } 88 | 89 | warn() { # important warning; not suppressed with --quiet 90 | # shellcheck disable=SC2048,SC2086 91 | echo " ${RED}* Warning${OFF}: "$* >&2 92 | } 93 | 94 | note() { # important notice; suppressed with --quiet 95 | # shellcheck disable=SC2048,SC2086 96 | qprint " ${YEL}* Note${OFF}: "$* >&2 97 | } 98 | 99 | debug() { 100 | # shellcheck disable=SC2048,SC2086 101 | $debugopt && echo " ${CYAN}debug>" $*"${OFF}" >&2; return 0 102 | } 103 | 104 | error() { 105 | # shellcheck disable=SC2048,SC2086 106 | echo " ${RED}* Error${OFF}:" $* >&2 107 | } 108 | 109 | die() { 110 | [ -n "$1" ] && error "$*" 111 | qprint 112 | $evalopt && { echo; echo "false;"; } 113 | exit 1 114 | } 115 | 116 | helpinfo() { 117 | cat >&1 <&1)" in 133 | *OpenSSH*) openssh=true ;; 134 | *Sun?SSH*) sunssh=true ;; 135 | esac 136 | # See if gpg-agent is available and provides ssh-agent functionality: 137 | if $ssh_spawn_gpg; then 138 | if ! out="$(gpg-agent --help | grep enable-ssh-support)" || [ -z "$out" ]; then 139 | warn "gpg-agent ssh functionality not available; not using..." 140 | ssh_spawn_gpg=false 141 | fi 142 | fi 143 | } 144 | 145 | # synopsis: verifykeydir 146 | # Make sure the key dir is set up correctly. Exits on error. 147 | verifykeydir() { 148 | # Create keydir if it doesn't exist already 149 | if [ -f "${keydir}" ]; then 150 | die "${keydir} is a file (it should be a directory)" 151 | # Solaris 9 doesn't have -e; using -d.... 152 | elif [ ! -d "${keydir}" ]; then 153 | mkdir "${keydir}" || die "can't create ${keydir}" 154 | fi 155 | # shellcheck disable=SC2012 # The "stat" command is not in POSIX, but "ls" output is. So for compliance, do this: 156 | dir_owner="$(ls -ld "${keydir}" | awk '{print $3}')" 157 | [ "$dir_owner" != "$me" ] && warn "${keydir} is owned by ${dir_owner}, not ${me}. Please fix." 158 | # shellcheck disable=SC2012 # POSIX defines the first 9 chars of ls -l: 159 | [ "$(ls -ld "${keydir}" | cut -c5-10)" != "------" ] && warn "Keychain dir has lax permissions. Use ${CYAN}chmod -R go-rwx '${keydir}'${OFF} to fix." 160 | if ! :> "$pidf.foo"; then 161 | die "can't write inside $pidf" 162 | else 163 | rm -f "$pidf.foo" 164 | fi 165 | } 166 | 167 | lockfile() { 168 | # This function originates from Parallels Inc.'s OpenVZ vpsreboot script. 169 | 170 | # Description: This function attempts to acquire the lock. If it succeeds, 171 | # it returns 0. If it fails, it returns 1. This function retuns immediately 172 | # and only tries to acquire the lock once. 173 | 174 | tmpfile="$lockf.$$" 175 | 176 | echo $$ >"$tmpfile" 2>/dev/null || exit 177 | if ln "$tmpfile" "$lockf" 2>/dev/null; then 178 | rm -f "$tmpfile" 179 | havelock=true && return 0 180 | fi 181 | if kill -0 "$(cat "$lockf" 2>/dev/null)" 2>/dev/null; then 182 | rm -f "$tmpfile" 183 | return 1 184 | fi 185 | if ln "$tmpfile" "$lockf" 2>/dev/null; then 186 | rm -f "$tmpfile" 187 | havelock=true && return 0 188 | fi 189 | rm -f "$tmpfile" "$lockf" && return 1 190 | } 191 | 192 | takelock() { 193 | # Description: This function calls lockfile() multiple times if necessary 194 | # to try to acquire the lock. It returns 0 on success and 1 on failure. 195 | # Change in behavior: if timeout expires, we will forcefully acquire lock. 196 | 197 | [ "$havelock" = "true" ] && return 0 198 | [ "$nolockopt" = "true" ] && return 0 199 | 200 | # First attempt: 201 | lockfile && return 0 202 | 203 | counter=0 204 | mesg "Waiting $lockwait seconds for lock..." 205 | while [ "$counter" -lt "$(( lockwait * 10 ))" ] 206 | do 207 | lockfile && return 0 208 | sleep 0.1; counter=$(( counter + 1 )) 209 | done 210 | rm -f "$lockf" && lockfile && return 0 211 | return 1 212 | } 213 | 214 | # synopsis: droplock 215 | # Drops the lock if we're holding it. 216 | droplock() { 217 | $havelock && [ -n "$lockf" ] && rm -f "$lockf" 218 | } 219 | 220 | # synopsis: findpids [prog] 221 | # Returns a space-separated list of agent pids. 222 | # prog can be ssh or gpg, defaults to ssh. Note that if another prog is ever 223 | # added, need to pay attention to the length for Solaris compatibility. 224 | findpids() { 225 | fp_prog=${1-ssh} 226 | unset fp_psout 227 | 228 | # Different systems require different invocations of ps. Try to generalize 229 | # the best we can. The only requirement is that the agent command name 230 | # appears in the line, and the PID is the first item on the line. 231 | if [ -z "$OSTYPE" ]; then 232 | OSTYPE=$(uname) || die 'uname failed' 233 | fi 234 | 235 | # Try systems where we know what to do first 236 | case "$OSTYPE" in 237 | AIX|*bsd*|*BSD*|CYGWIN|darwin*|Linux|linux-gnu|OSF1) 238 | fp_psout=$(ps x 2>/dev/null) ;; # BSD syntax 239 | HP-UX) 240 | fp_psout=$(ps -u "$me" 2>/dev/null) ;; # SysV syntax 241 | SunOS) 242 | case $(uname -r) in 243 | [56]*) 244 | fp_psout=$(ps -u "$me" 2>/dev/null) ;; # SysV syntax 245 | *) 246 | fp_psout=$(ps x 2>/dev/null) ;; # BSD syntax 247 | esac ;; 248 | GNU|gnu) 249 | fp_psout=$(ps -g 2>/dev/null) ;; # GNU Hurd syntax 250 | esac 251 | 252 | # If we didn't get a match above, try a list of possibilities... 253 | # The first one will probably fail on systems supporting only BSD syntax. 254 | if [ -z "$fp_psout" ]; then 255 | # shellcheck disable=SC2009 256 | fp_psout=$(UNIX95=1 ps -u "$me" -o pid,comm 2>/dev/null | grep '^ *[0-9]+') 257 | [ -z "$fp_psout" ] && fp_psout=$(ps x 2>/dev/null) 258 | [ -z "$fp_psout" ] && fp_psout=$(ps w 2>/dev/null) # Busybox syntax 259 | fi 260 | 261 | # Return the list of pids; ignore case for Cygwin. 262 | # Check only 8 characters since Solaris truncates at that length. 263 | # Ignore defunct ssh-agents (bug 28599) 264 | if [ -n "$fp_psout" ]; then 265 | echo "$fp_psout" | \ 266 | awk "BEGIN{IGNORECASE=1} /defunct/{next} 267 | /$fp_prog-[a]gen/{print \$1}" | xargs 268 | return 0 269 | fi 270 | 271 | # If none worked, we're stuck 272 | error "Unable to use \"ps\" to scan for $fp_prog-agent processes" 273 | error "Please report to https://github.com/funtoo/keychain/issues." 274 | return 1 275 | } 276 | 277 | stop_ssh_agents() { 278 | mesg "Stopping ssh-agent(s)..." 279 | takelock || die 280 | [ "$stopwhich" != all ] && eval "$(catpidf_shell sh)" # get SSH_AGENT_PID if defined 281 | ssh_pids=$(findpids ssh) || die 282 | if [ -z "$ssh_pids" ]; then 283 | mesg "No ssh-agent(s) found running" 284 | elif [ "$stopwhich" = all ]; then 285 | # shellcheck disable=SC2086 286 | kill $ssh_pids >/dev/null 2>&1 287 | mesg "All ${CYANN}$me${OFF}'s ssh-agents stopped: ${CYANN}$ssh_pids${OFF}" 288 | elif [ -n "$SSH_AGENT_PID" ]; then 289 | if [ "$stopwhich" = mine ]; then 290 | kill "$SSH_AGENT_PID" >/dev/null 2>&1 291 | mesg "Keychain ssh-agents stopped: ${CYANN}$SSH_AGENT_PID${OFF}" 292 | else # others 293 | for ssh_pid in $ssh_pids; do 294 | [ "$ssh_pid" = "$SSH_AGENT_PID" ] && continue 295 | kill "$ssh_pid" >/dev/null 2>&1 296 | killed_pids="$killed_pids $ssh_pid" 297 | done 298 | mesg "Other ${CYANN}$me${OFF}'s ssh-agents stopped:${CYANN}$killed_pids${OFF}" 299 | fi 300 | else 301 | mesg "No keychain ssh-agent found running" 302 | fi 303 | 304 | # remove pid files if keychain-controlled 305 | if [ "$stopwhich" != others ]; then 306 | rm -f "${pidf}" "${cshpidf}" "${fishpidf}" 2>/dev/null 307 | fi 308 | qprint && exit 0 309 | } 310 | 311 | # synopsis: catpidf_shell shell 312 | # cat the pid file for the specified shell. 313 | catpidf_shell() { 314 | case "$1" in 315 | */fish|fish) cp_pidf="$fishpidf" ;; 316 | *csh) cp_pidf="$cshpidf" ;; 317 | *) cp_pidf="$pidf" ;; 318 | esac 319 | if [ ! -f "$cp_pidf" ]; then 320 | debug "pidfile doesn't exist"; return 1 321 | else 322 | cat "${cp_pidf}"; echo; return 0 323 | fi 324 | } 325 | 326 | startagent_gpg() { 327 | if $gpg_started; then 328 | return 0 329 | else 330 | gpg_started=true 331 | fi 332 | if gpg_agent_sock="$( echo "GETINFO socket_name" | gpg-connect-agent --no-autostart | head -n1 | sed -n 's/^D //;1p' )" && [ -S "$gpg_agent_sock" ]; then 333 | mesg "Using existing gpg-agent: ${CYANN}$gpg_agent_sock${OFF}" 334 | pidfile_out="SSH_AUTH_SOCK=\"$gpg_agent_sock\"; export SSH_AUTH_SOCK" # make sure we adopt it 335 | else 336 | gpg_opts="--daemon" 337 | [ -n "${timeout}" ] && gpg_opts="$gpg_opts --default-cache-ttl $(( timeout * 60 )) --max-cache-ttl $(( timeout * 60 ))" 338 | $ssh_spawn_gpg && gpg_opts="$gpg_opts --enable-ssh-support" 339 | mesg "Starting gpg-agent..." 340 | # shellcheck disable=SC2086 # this is intentionalh 341 | pidfile_out="$(gpg-agent --sh $gpg_opts)" 342 | return $? 343 | fi 344 | } 345 | 346 | ssh_envcheck() { 347 | # Initial short-circuits for known abort cases: 348 | [ -z "$SSH_AUTH_SOCK" ] && return 1 349 | if [ ! -S "$SSH_AUTH_SOCK" ]; then 350 | debug "SSH_AUTH_SOCK in $1 is invalid; ignoring it" 351 | unset SSH_AUTH_SOCK && return 1 352 | fi 353 | 354 | # Throw away the PID with a devug warning if it's invalid: 355 | 356 | if [ -n "$SSH_AGENT_PID" ] && ! kill -0 "$SSH_AGENT_PID" >/dev/null 2>&1; then 357 | unset SSH_AGENT_PID && debug "SSH_AGENT_PID in $1 is invalid; ignoring it" 358 | fi 359 | 360 | # Now, find potential agents: 361 | 362 | if [ -z "$SSH_AGENT_PID" ]; then 363 | 364 | # There are some cases where we can accept a socket without an associated SSH_AGENT_PID: 365 | 366 | if gpg_socket="$(echo "GETINFO ssh_socket_name" | gpg-connect-agent --no-autostart 2>/dev/null | head -n1 | sed -n 's/^D //;1p' )"; then 367 | if [ "$gpg_socket" = "$SSH_AUTH_SOCK" ]; then 368 | if $ssh_allow_gpg; then 369 | $quickopt || mesg "Using ssh-agent ($1): ${CYANN}$gpg_socket${OFF} (GnuPG)" 370 | return 0 371 | else 372 | unset SSH_AUTH_SOCK && debug "Ignoring SSH_AUTH_SOCK -- this is the GnuPG-supplied socket" && return 1 373 | fi 374 | fi 375 | fi 376 | 377 | if $ssh_allow_forwarded; then 378 | SSH_AGENT_PID="forwarded" 379 | $quickopt || mesg "Using ${GREEN}forwarded${OFF} ssh-agent: ${GREEN}$SSH_AUTH_SOCK${OFF}" 380 | return 0 381 | else 382 | unset SSH_AUTH_SOCK && debug "Ignoring SSH_AUTH_SOCK -- this is a forwarded socket" && return 1 383 | fi 384 | else 385 | # We have valid SSH_AGENT_PID, so we accept the socket too: 386 | $quickopt || mesg "Existing ssh-agent ($1): ${CYANN}$SSH_AGENT_PID${OFF}" 387 | return 0 388 | fi 389 | } 390 | 391 | # synopsis: startagent_ssh 392 | # This function specifically handles (potential) starting of ssh-agent. Unlike the 393 | # classic startagent function, it does not handle writing out contents of pidfiles, 394 | # which will be done in a combined way after startagent_gpg() is called as well. 395 | 396 | startagent_ssh() { 397 | if $quickopt; then 398 | if ( unset SSH_AGENT_PID SSH_AUTH_SOCK && eval "$(catpidf_shell sh)" && ssh_envcheck quick && ssh_l > /dev/null ); then 399 | mesg "Found existing populated ssh-agent (quick)" 400 | return 0 401 | else 402 | if ( eval "$(catpidf_shell sh)" && ssh_envcheck quick ); then 403 | note "Quick start unsuccessful -- no keys loaded..." 404 | else 405 | note "Quick start unsuccessful -- no agent found..." 406 | fi 407 | quickopt=false 408 | fi 409 | fi 410 | takelock || die 411 | # See if our pidfile is valid without wiping env: 412 | if ( unset SSH_AGENT_PID SSH_AUTH_SOCK && eval "$(catpidf_shell sh)" && ssh_envcheck pidfile ); then 413 | # Our pidfile is valid! :) We can simply use it: 414 | debug "pidfile is valid" && unset SSH_AGENT_PID SSH_AUTH_SOCK && eval "$(catpidf_shell sh)" 415 | elif $allow_inherited && ssh_envcheck env; then 416 | # If our env is OK, then let's grab it for our pidfile, as long as we don't have a forwarded ssh connection: 417 | if [ "$SSH_AGENT_PID" != forwarded ]; then 418 | pidfile_out="SSH_AUTH_SOCK=\"$SSH_AUTH_SOCK\"; export SSH_AUTH_SOCK" 419 | if [ -n "$SSH_AGENT_PID" ]; then 420 | pidfile_out="$pidfile_out 421 | SSH_AGENT_PID=$SSH_AGENT_PID; export SSH_AGENT_PID" 422 | fi 423 | fi 424 | else # spawn, we must... 425 | rm -f "${pidf}" "${cshpidf}" "${fishpidf}" 2>/dev/null # pidfile is either non-existant or invalid 426 | if $ssh_spawn_gpg; then 427 | startagent_gpg ssh # this function will set pidfile_out itself 428 | return $? 429 | else 430 | mesg "Starting ssh-agent..." 431 | # shellcheck disable=SC2086 # We purposely don't want to double-quote the args to ssh-agent so they disappear if not used: 432 | pidfile_out="$(ssh-agent ${ssh_timeout} ${ssh_agent_socket})" 433 | return $? 434 | fi 435 | fi 436 | } 437 | 438 | write_pidfile() { 439 | if [ -n "$pidfile_out" ]; then 440 | pidfile_out=$(echo "$pidfile_out" | grep -v 'Agent pid') 441 | rm -f "$pidf" "$cshpidf" "$fishpidf" # Remove first, so we can recreate with our umask 442 | case "$pidfile_out" in 443 | setenv*) 444 | echo "$pidfile_out" >"$cshpidf" 445 | echo "$pidfile_out" | awk '{print $2"="$3" export "$2";"}' >"$pidf" 446 | ;; 447 | *) 448 | echo "$pidfile_out" >"$pidf" 449 | echo "$pidfile_out" | sed 's/;.*/;/' | sed 's/=/ /' | sed 's/^/setenv /' >"$cshpidf" 450 | echo "$pidfile_out" | sed 's/;.*/;/' | sed 's/^\(.*\)=\(.*\);/set -e \1; set -x -U \1 \2;/' >"$fishpidf" 451 | ;; 452 | esac 453 | else 454 | debug skipping creation of pidfiles! 455 | fi 456 | } 457 | 458 | # synopsis: extract_fingerprints 459 | # Extract the fingerprints from standard input, returns space-separated list. 460 | # Utility routine for ssh_l and ssh_f 461 | extract_fingerprints() { 462 | while read -r ef_line; do 463 | case "$ef_line" in 464 | *\ *\ [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:*) 465 | # Sun SSH spits out different things depending on the type of 466 | # key. For example: 467 | # md5 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_dsa(DSA) 468 | # 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_rsa.pub 469 | echo "$ef_line" | cut -f3 -d' ' 470 | ;; 471 | *\ [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:*) 472 | # The more consistent OpenSSH format, we hope 473 | # 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 /home/barney/.ssh/id_dsa (DSA) 474 | echo "$ef_line" | cut -f2 -d' ' 475 | ;; 476 | *\ [A-Z0-9][A-Z0-9]*:[A-Za-z0-9+/][A-Za-z0-9+/]*) 477 | # The new OpenSSH 6.8+ format, 478 | # 1024 SHA256:mVPwvezndPv/ARoIadVY98vAC0g+P/5633yTC4d/wXE /home/barney/.ssh/id_dsa (DSA) 479 | echo "$ef_line" | cut -f2 -d' ' 480 | ;; 481 | *) 482 | # Fall back to filename. Note that commercial ssh is handled 483 | # explicitly in ssh_l and ssh_f, so hopefully this rule will 484 | # never fire. 485 | warn "Can't determine fingerprint from the following line, falling back to filename" 486 | mesg "$ef_line" 487 | basename "$ef_line" | sed 's/[ (].*//' 488 | ;; 489 | esac 490 | done | xargs 491 | } 492 | 493 | # synopsis: ssh_l 494 | # Return space-separated list of known fingerprints 495 | ssh_l() { 496 | sl_mylist=$(ssh-add -l 2>/dev/null) 497 | sl_retval=$? 498 | 499 | if $openssh; then 500 | # Error codes: 501 | # 0 success 502 | # 1 OpenSSH_3.8.1p1 on Linux: no identities (not an error) 503 | # OpenSSH_3.0.2p1 on HP-UX: can't connect to auth agent 504 | # 2 can't connect to auth agent 505 | case $sl_retval in 506 | 0) 507 | echo "$sl_mylist" | extract_fingerprints 508 | ;; 509 | 1) 510 | case "$sl_mylist" in 511 | *"open a connection"*) sl_retval=2 ;; 512 | esac 513 | ;; 514 | esac 515 | return $sl_retval 516 | 517 | elif $sunssh; then 518 | # Error codes (from http://docs.sun.com/db/doc/817-3936/6mjgdbvio?a=view) 519 | # 0 success (even when there are no keys) 520 | # 1 error 521 | case $sl_retval in 522 | 0) 523 | echo "$sl_mylist" | extract_fingerprints 524 | ;; 525 | 1) 526 | case "$sl_mylist" in 527 | *"open a connection"*) sl_retval=2 ;; 528 | esac 529 | ;; 530 | esac 531 | return $sl_retval 532 | else 533 | # Error codes: 534 | # 0 success - however might say "The authorization agent has no keys." 535 | # 1 can't connect to auth agent 536 | # 2 bad passphrase 537 | # 3 bad identity file 538 | # 4 the agent does not have the requested identity 539 | # 5 unspecified error 540 | if [ $sl_retval = 0 ]; then 541 | # Output of ssh-add -l: 542 | # The authorization agent has one key: 543 | # id_dsa_2048_a: 2048-bit dsa, agriffis@alpha.zk3.dec.com, Fri Jul 25 2003 10:53:49 -0400 544 | # Since we don't have a fingerprint, just get the filenames *shrug* 545 | echo "$sl_mylist" | sed '2,$s/:.*//' | xargs 546 | fi 547 | return $sl_retval 548 | fi 549 | } 550 | 551 | # synopsis: ssh_f filename 552 | # Return fingerprint for a keyfile 553 | # Requires $openssh or $sunssh 554 | ssh_f() { 555 | sf_filename="$1" 556 | 557 | if $openssh || $sunssh; then 558 | realpath_bin="$(command -v realpath)" 559 | # if private key is symlink and symlink to *.pub is missing: 560 | if [ -L "$sf_filename" ] && [ -n "$realpath_bin" ]; then 561 | sf_filename="$($realpath_bin "$sf_filename")" 562 | fi 563 | lsf_filename="$sf_filename.pub" 564 | if [ ! -f "$lsf_filename" ]; then 565 | # try to remove extension from private key, *then* add .pub, and see if we now find it: 566 | if [ -L "$sf_filename" ] && [ -n "$realpath_bin" ]; then 567 | sf_filename="$($realpath_bin "$sf_filename")" 568 | fi 569 | lsf_filename=$(echo "$sf_filename" | sed 's/\.[^\.]*$//').pub 570 | if [ ! -f "$lsf_filename" ]; then 571 | note "Cannot find separate public key for $1." 572 | lsf_filename="$sf_filename" 573 | fi 574 | fi 575 | sf_fing=$(ssh-keygen -l -f "$lsf_filename") || return 1 576 | echo "$sf_fing" | extract_fingerprints 577 | else 578 | # can't get fingerprint for ssh2 so use filename *shrug* 579 | basename "$sf_filename" 580 | fi 581 | return 0 582 | } 583 | 584 | # synopsis: gpg_listmissing 585 | # Accepts piped input from stdin. Returns a newline-separated list of keys found to be missing. 586 | gpg_listmissing() { 587 | unset glm_missing 588 | GPG_TTY=$(tty) 589 | 590 | while IFS= read -r glm_k; do 591 | [ -z "$glm_k" ] && continue 592 | # Check if this key is known to the agent. Don't know another way... 593 | if env -i GPG_TTY="$GPG_TTY" PATH="$PATH" GPG_AGENT_INFO="$GPG_AGENT_INFO" "${gpg_prog_name}" --no-autostart --no-options --use-agent --no-tty --sign --local-user "$glm_k" -o- >/dev/null 2>&1 " if they exist or "miss:" otherwise. 647 | all_host_identities() { 648 | if [ ! -e ~/.ssh/config ]; then 649 | warn "No ~/.ssh/config -- can't extract host identities" && return 650 | fi 651 | while IFS= read -r line; do 652 | case $line in 653 | *[Ii][Dd][Ee][Nn][Tt][Ii][Tt][Yy][Ff][Ii][Ll][Ee]*) 654 | keyf="$(echo "$line" | awk '{print $2}')" 655 | if [ -f "$keyf" ]; then 656 | echo "sshk:${keyf}" 657 | else 658 | echo "miss:${keyf}" 659 | fi 660 | esac 661 | done < ~/.ssh/config 662 | } 663 | 664 | # Synopsis: this is the default logic for categorizing command-line keys. If a file is 665 | # specified and is found in ~/.ssh, or just exists, it's a SSH key. If gpg recognizes it, 666 | # then it's a GPG key. Otherwise, it's a missing key. 667 | cmdline_keys_to_extkey() { 668 | while read -r pm_k; do 669 | [ -z "$pm_k" ] && continue 670 | if [ -f "$pm_k" ]; then 671 | echo "sshk:$pm_k" 672 | elif [ -f "$HOME/.ssh/$pm_k" ]; then 673 | echo "sshk:$HOME/.ssh/$pm_k" 674 | elif "${gpg_prog_name}" --list-secret-keys "$pm_k" >/dev/null 2>&1; then 675 | echo "gpgk:$pm_k" 676 | else 677 | echo "miss:$pm_k" 678 | fi 679 | done 680 | } 681 | 682 | # Synopsis: sees if specified stdin $keyf exists; converts to "sshk:" or "miss:" lines 683 | keyf_expand() { 684 | while read -r keyf; do 685 | if [ -f "$keyf" ]; then 686 | echo "sshk:$keyf" 687 | else 688 | echo "miss:$keyf" 689 | fi 690 | done 691 | } 692 | 693 | # Synopsis: We allow sshk:id_rsa from the command-line, with no path, but this needs 694 | # to be expanded to the actual filename internally -- or "miss:". Logic is a bit different 695 | # so we can't use cmdline_keys_to_extkey() code. 696 | sshk_fixup() { 697 | while read -r extkey; do 698 | key_pref="$(echo "$extkey" | cut -b1-5)" 699 | if [ "$key_pref" != "sshk:" ]; then 700 | echo "$extkey" 701 | else 702 | pm_k="$(echo "$extkey" | cut -b6-)" 703 | if [ -f "$pm_k" ]; then 704 | echo "sshk:$pm_k" 705 | elif [ -f "$HOME/.ssh/$pm_k" ]; then 706 | echo "sshk:$HOME/.ssh/$pm_k" 707 | else 708 | echo "miss:$pm_k" 709 | fi 710 | fi 711 | done 712 | } 713 | 714 | # Synopsis: performs final processing on extended keys. Currently converts each "host:" 715 | # extkeys to (possibly many) "sshk:" or "miss:" lines. Also validates all keys for basic 716 | # syntax. 717 | extkey_expand() { 718 | while read -r extkey; do 719 | [ -z "$extkey" ] && continue 720 | key_pref="$(echo "$extkey" | cut -b1-5)" 721 | if [ "$key_pref" = "host:" ]; then 722 | ssh -nG "$(echo "$extkey" | cut -b6-)" 2>/dev/null | grep -e ^identityfile | awk '{print $2}' | keyf_expand 723 | elif [ "$key_pref" = "sshk:" ] || [ "$key_pref" = "gpgk:" ] || [ "$key_pref" = "miss:" ]; then 724 | echo "$extkey" 725 | else 726 | warn "Unrecognized extended key \"$extkey\". Should have a sshk:, gpgk: or host: prefix." 727 | fi 728 | done 729 | } 730 | 731 | # Synopsis: gets all extended keys. SSH keys are in "sshk:" format. GPG fingerprints 732 | # are in "gpgk:" format. Any SSH keys that cannot be found are expanded to "miss:, 733 | # which is used for warnings later. If --extended is specified, we expect "sshk:foo" format on 734 | # the command-line. Otherwise, we use cmdline_keys_to_extkey() to convert the standard command- 735 | # line arguments into a format that keychain internals expect. 736 | 737 | get_all_extkeys() { 738 | if $confallhosts; then 739 | all_host_identities 740 | fi 741 | if ! $extended; then 742 | echo "$cmdline_keys" | cmdline_keys_to_extkey | extkey_expand 743 | else 744 | echo "$cmdline_keys" | sshk_fixup | extkey_expand 745 | fi 746 | } 747 | 748 | setaction() { 749 | if [ -n "$myaction" ]; then 750 | die "you can't specify --$myaction and $1 at the same time" 751 | else 752 | myaction="$1" 753 | fi 754 | } 755 | 756 | wantagent() { 757 | [ "$1" = "gpg" ] && [ -n "$gpgkeys" ] && return 0 758 | return 1 759 | } 760 | 761 | gpg_wipe() { 762 | out="$( echo RELOADAGENT | gpg-connect-agent --no-autostart 2>/dev/null )" 763 | if [ "$out" = "OK" ]; then 764 | mesg "gpg-agent: All identities removed." 765 | else 766 | mesg "gpg-agent: Could not remove identities; possibly not running. (output: $out)" 767 | fi 768 | } 769 | 770 | ssh_wipe() { 771 | if sshout=$(ssh-add -D 2>&1); then 772 | mesg "ssh-agent: $sshout" 773 | else 774 | warn "ssh-agent: $sshout" 775 | fi 776 | 777 | } 778 | 779 | while [ -n "$1" ]; do 780 | case "$1" in 781 | --absolute) absoluteopt=true ;; 782 | --agents) shift; warn "--agents is deprecated, ignoring." ;; 783 | --confhost) die "--confhost is deprecated; use \"${CYANN}--extended host:${OFF}\" instead." ;; 784 | --confallhosts) confallhosts=true ;; 785 | --confirm) confirmopt=true ;; 786 | --debug|-D) debugopt=true ;; 787 | --eval) evalopt=true ;; 788 | --extended|--ext|-e) extended=true ;; 789 | --gpg2) gpg_prog_name="gpg2" ;; 790 | --help|-h) setaction help ;; 791 | --host) shift; hostopt="$1" ;; 792 | --ignore-missing) ignoreopt=true ;; 793 | --inherit) shift; warn "--inherit is deprecated, ignoring. Use --ssh-allow-forwarded, --noinherit as needed instead.";; 794 | --list|-l) setaction list ;; 795 | --list-fp|-L) setaction list-fp ;; 796 | --noask) noaskopt=true ;; 797 | --nocolor) color=false ;; 798 | --nogui) noguiopt=true ;; 799 | --noinherit) allow_inherited=false ;; 800 | --nolock) nolockopt=true ;; 801 | --query) setaction query; quietopt=true ;; 802 | --quiet|-q) quietopt=true ;; 803 | --ssh-allow-gpg) ssh_allow_gpg=true ;; 804 | --ssh-spawn-gpg) ssh_spawn_gpg=true; ssh_allow_gpg=true ;; 805 | --ssh-agent-socket) shift; ssh_agent_socket="-a $1" ;; 806 | --ssh-allow-forwarded) ssh_allow_forwarded=true ;; 807 | --ssh-rm|-r) setaction ssh_rm ;; 808 | --systemd) systemdopt=true ;; 809 | --version|-V) setaction version ;; 810 | --attempts) warn "--attempts is now deprecated." ;; 811 | --clear) 812 | clearopt=true 813 | $quickopt && die "--quick and --clear are not compatible" 814 | ;; 815 | --dir) 816 | shift 817 | case "$1" in 818 | */.*) keydir="$1" ;; 819 | '') die "--dir requires an argument" ;; 820 | *) 821 | if $absoluteopt; then 822 | keydir="$1" 823 | else 824 | keydir="$1/.keychain" # be backward-compatible 825 | fi 826 | ;; 827 | esac 828 | ;; 829 | --env) 830 | shift 831 | if [ -z "$1" ]; then 832 | die "--env requires an argument" 833 | else 834 | envf="$1" 835 | fi 836 | ;; 837 | --lockwait) 838 | shift 839 | if [ "$1" -ge 0 ] 2>/dev/null; then 840 | lockwait="$1" 841 | else 842 | die "--lockwait requires an argument zero or greater." 843 | fi 844 | ;; 845 | --quick|-Q) 846 | quickopt=true 847 | $clearopt && die "--quick and --clear are not compatible" 848 | ;; 849 | --stop|-k) 850 | setaction stop 851 | case $2 in 852 | all|mine|others) stopwhich="$2" ;; 853 | *) die "Please specify 'all', 'mine' or 'others' for --stop" ;; 854 | esac 855 | ;; 856 | --timeout) 857 | shift 858 | if [ "$1" -gt 0 ] 2>/dev/null; then 859 | timeout=$1 860 | else 861 | die "--timeout requires a numeric argument greater than zero" 862 | fi 863 | ;; 864 | --wipe) 865 | shift 866 | case $1 in 867 | gpg) setaction gpg_wipe ;; 868 | ssh) setaction ssh_wipe ;; 869 | all) setaction all_wipe ;; 870 | *) die "Please specify ssh, gpg or all for --wipe action" 871 | esac 872 | ;; 873 | -*) 874 | zero=$(basename "$0") 875 | echo "$zero: unknown option $1" >&2 876 | $evalopt && { echo; echo "false;"; } 877 | exit 1 878 | ;; 879 | *) 880 | cmdline_keys="$1${NEWLINE}${cmdline_keys}" 881 | ;; 882 | esac 883 | shift 884 | done 885 | if [ -z "$hostopt" ]; then 886 | if [ -z "$HOSTNAME" ]; then 887 | hostopt=$(uname -n 2>/dev/null || echo unknown) 888 | else 889 | hostopt="$HOSTNAME" 890 | fi 891 | fi 892 | 893 | pidf="${keydir}/${hostopt}-sh" 894 | cshpidf="${keydir}/${hostopt}-csh" 895 | fishpidf="${keydir}/${hostopt}-fish" 896 | lockf="${keydir}/${hostopt}-lockf" 897 | for keyf in "$pidf" "$cshpidf" "$fishpidf"; do 898 | if [ -f "$keyf" ]; then 899 | # shellcheck disable=SC2012 # POSIX defines the first 9 chars of ls -l: 900 | go_modes="$(ls -ld "${keyf}" | cut -c5-10 )" 901 | [ "$go_modes" != "------" ] && warn "Some pidfiles have lax permissions. Use ${CYAN}chmod -R go-rwx '${keydir}'${OFF} to fix." 902 | # shellcheck disable=SC2012 903 | keyf_owner="$(ls -ld "${keyf}" | awk '{print $3}')" && [ "$keyf_owner" != "$me" ] && warn "${keyf} is owned by ${keyf_owner}, not ${me}. Please fix." 904 | fi 905 | done 906 | 907 | # Read the env snippet (especially for things like PATH, but could modify basically anything) 908 | if [ -z "$envf" ]; then 909 | envf="${keydir}/${hostopt}-env" 910 | [ -f "$envf" ] || envf="${keydir}/env" 911 | [ -f "$envf" ] || unset envf 912 | fi 913 | if [ -n "$envf" ]; then 914 | # shellcheck disable=SC1090 915 | . "$envf" 916 | fi 917 | 918 | # Don't use color if there's no terminal on stderr 919 | if [ -n "$OFF" ]; then 920 | tty <&2 >/dev/null 2>&1 || color=false 921 | fi 922 | 923 | $color || unset BLUE CYAN CYANN GREEN PURP OFF RED 924 | 925 | # TODO: we can't assume pidfile has been created yet? Or not a big deal? 926 | [ "$myaction" = list ] && eval "$(catpidf_shell sh)" && exec ssh-add -l 927 | [ "$myaction" = list-fp ] && eval "$(catpidf_shell sh)" && exec ssh-add -L 928 | 929 | qprint #initial newline 930 | mesg "${PURP}keychain ${OFF}${CYANN}${version}${OFF} ~ ${GREEN}https://www.funtoo.org/Funtoo:Keychain${OFF}" 931 | 932 | [ "$myaction" = version ] && { versinfo; exit 0; } 933 | [ "$myaction" = help ] && { versinfo; helpinfo; exit 0; } 934 | 935 | # Don't use signal names because they don't work on Cygwin. 936 | if $clearopt; then 937 | trap '' 2 # disallow ^C until we've had a chance to --clear 938 | trap 'droplock; exit 1' 1 15 # drop the lock on signal 939 | trap 'droplock;' 0 # drop the lock on exit 940 | else 941 | # Don't use signal names because they don't work on Cygwin. 942 | trap 'droplock; exit 1' 1 2 15 # drop the lock on signal 943 | trap 'droplock;' 0 # drop the lock on exit 944 | fi 945 | 946 | testssh # sets $openssh, $sunssh and tweaks $ssh_spawn_gpg 947 | verifykeydir # sets up $keydir 948 | 949 | # --stop: kill the existing ssh-agent(s) (not gpg-agent) and quit 950 | [ "$myaction" = stop ] && stop_ssh_agents 951 | 952 | # --timeout translates almost directly to ssh-add/ssh-agent -t, but ssh.com uses 953 | # minutes and OpenSSH uses seconds 954 | if [ -n "$timeout" ]; then 955 | ssh_timeout=$timeout 956 | if $openssh || $sunssh; then 957 | ssh_timeout=$(( ssh_timeout * 60 )) 958 | fi 959 | ssh_timeout="-t $ssh_timeout" 960 | fi 961 | 962 | all_keys="$(get_all_extkeys | sort -u)" 963 | if ! $ignoreopt; then 964 | for key in $(echo "$all_keys" | grep ^miss:); do 965 | warn "Can't find key \"${GREEN}$( echo "$key" | cut -c6- )${OFF}\"" 966 | done 967 | fi 968 | sshkeys="$(echo "$all_keys" | sed -n '/^sshk:/s/sshk://p')" 969 | gpgkeys="$(echo "$all_keys" | sed -n '/^gpgk:/s/gpgk://p')" 970 | if [ "$myaction" = gpg_wipe ]; then 971 | gpg_wipe; qprint; exit 0 972 | elif [ "$myaction" = ssh_wipe ]; then 973 | ssh_wipe; qprint; exit 0 974 | elif [ "$myaction" = all_wipe ]; then 975 | ssh_wipe; gpg_wipe; qprint; exit 0 976 | elif [ "$myaction" = query ]; then 977 | # --query displays current settings, but does not start an agent: 978 | if catpidf_shell sh > /dev/null; then 979 | catpidf_shell sh | cut -d\; -f1 && exit 0 980 | else 981 | die "Can't query. Does pidfile exist?" 982 | fi 983 | elif [ "$myaction" = ssh_rm ]; then 984 | if [ -n "$sshkeys" ]; then 985 | die "No ssh keys specified to remove." 986 | fi 987 | for key in $sshkeys; do 988 | if sshout=$(ssh-add -d "$key" 2>&1); then 989 | mesg "ssh-agent key $key removed." 990 | else 991 | die "keychain was unable to remove ssh-agent key $key. output: $sshout" 992 | fi 993 | done 994 | qprint; exit 0 995 | else 996 | # This will start gpg-agent as an ssh-agent if such functionality is enabled (default) 997 | startagent_ssh || warn "Unable to start an ssh-agent (error code: $?)" 998 | [ -n "$pidfile_out" ] && write_pidfile && eval "$pidfile_out" > /dev/null 999 | if ! $gpg_started && wantagent gpg; then 1000 | # If we also want gpg, and it hasn't been started yet, start it also. We don't need to 1001 | # look for pidfile output, as this would have been output from the startagent_ssh->startagent_gpg 1002 | # call above, and gpg doesn't use pidfiles for gpg stuff anymore. 1003 | startagent_gpg || warn "Unable to start gpg-agent (error code: $?)" 1004 | fi 1005 | if $clearopt; then 1006 | ssh_wipe 1007 | if wantagent gpg; then 1008 | gpg_wipe 1009 | fi 1010 | trap 'droplock' 2 # done clearing, safe to ctrl-c 1011 | fi 1012 | fi 1013 | 1014 | if $evalopt; then 1015 | catpidf_shell "$SHELL" 1016 | fi 1017 | 1018 | $systemdopt && systemctl --user set-environment "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" 1019 | $systemdopt && [ -n "$SSH_AGENT_PID" ] && systemctl --user set-environment "SSH_AGENT_PID=$SSH_AGENT_PID" 1020 | # These options don't need to load keys, so terminate early: 1021 | $noaskopt && { qprint; exit 0; } 1022 | $quickopt && { qprint; exit 0; } 1023 | 1024 | load_ssh_keys() { 1025 | missing="$(echo "${sshkeys}" | ssh_listmissing)" 1026 | savedisplay="$DISPLAY" 1027 | if $confirmopt; then 1028 | if $openssh || $sunssh; then 1029 | ssh_confirm=-c 1030 | else 1031 | warn "--confirm only works with OpenSSH" 1032 | fi 1033 | fi 1034 | # Put $missing into args to access $# and other goodies. Since $missing is a line-delimited 1035 | # list of files with (potentially) spaces, we must do an IFS hack to get each file in 1036 | # $1, $2, $3, etc. For Bourne-shell compatibility, we don't have another good option: 1037 | IFS_BAK="$IFS"; IFS="$NEWLINE" 1038 | # shellcheck disable=SC2086 1039 | set -- $missing 1040 | IFS="$IFS_BAK" 1041 | [ $# -eq 0 ] && return 1042 | mesg "Adding ${CYANN}$#${OFF} ssh key(s): ${CYANN}$*${OFF}" 1043 | if $noguiopt || [ -z "$SSH_ASKPASS" ] || [ -z "$DISPLAY" ]; then 1044 | unset DISPLAY # DISPLAY="" can cause problems 1045 | unset SSH_ASKPASS # make sure ssh-add doesn't try SSH_ASKPASS 1046 | fi 1047 | # shellcheck disable=SC2086 1048 | sshout=$(ssh-add ${ssh_timeout} ${ssh_confirm} "$@" 2>&1) 1049 | ret=$? 1050 | if [ $ret = 0 ]; then 1051 | blurb="" 1052 | [ -n "$timeout" ] && blurb="life=${timeout}m" 1053 | [ -n "$timeout" ] && $confirmopt && blurb="${blurb}," 1054 | $confirmopt && blurb="${blurb}confirm" 1055 | [ -n "$blurb" ] && blurb=" (${blurb})" 1056 | mesg "ssh-add: Identities added: $sshkeys${blurb}" 1057 | else 1058 | warn "ssh-add failed: (return code: $ret; output: $sshout)" 1059 | fi 1060 | [ -n "$savedisplay" ] && DISPLAY="$savedisplay" 1061 | return $ret 1062 | } 1063 | 1064 | load_gpg_keys() { 1065 | $noguiopt && unset DISPLAY 1066 | [ -n "$DISPLAY" ] || unset DISPLAY # DISPLAY="" can cause problems 1067 | GPG_TTY=$(tty) ; export GPG_TTY # fall back to ncurses pinentry 1068 | for key in "$@"; do 1069 | [ -z "$key" ] && continue 1070 | mesg "Adding gpg key: $key" 1071 | # the 3>&1, etc. is a temp fd to allow us to capture stderr, while throwing away stdout which is encrypted data, and avoid a "null byte on input" bash warning: 1072 | gpgout="$(env LC_ALL="$pinentry_lc_all" "${gpg_prog_name}" --no-autostart --no-options --use-agent --sign --local-user "$key" -o- 3>&1 1>/dev/null 2>&3 6 | URL: https://github.com/funtoo/keychain 7 | Source0: %{name}-%{version}.tar.bz2 8 | License: GPL v2 9 | Group: Applications/Internet 10 | BuildArch: noarch 11 | Requires: /bin/sh sh-utils 12 | Prefix: /usr/bin 13 | BuildRoot: %{_tmppath}/%{name}-root 14 | 15 | %description 16 | Keychain is a manager for OpenSSH, ssh.com, Sun SSH and GnuPG agents. 17 | It acts as a front-end to the agents, allowing you to easily have one 18 | long-running agent process per system, rather than per login session. 19 | This reduces the number of times you need to enter your passphrase 20 | from once per new login session to once every time your local machine 21 | is rebooted. 22 | 23 | %prep 24 | %setup -q 25 | 26 | %build 27 | 28 | %install 29 | [ $RPM_BUILD_ROOT != / ] && rm -rf $RPM_BUILD_ROOT 30 | mkdir -p $RPM_BUILD_ROOT/%{_bindir} $RPM_BUILD_ROOT/%{_mandir}/man1 31 | install -m0755 keychain $RPM_BUILD_ROOT/%{_bindir}/keychain 32 | install -m0644 keychain.1 $RPM_BUILD_ROOT/%{_mandir}/man1 33 | 34 | %clean 35 | rm -rf $RPM_BUILD_ROOT 36 | 37 | %files 38 | %defattr(-,root,root) 39 | %{_bindir}/* 40 | %doc %{_mandir}/*/* 41 | %doc ChangeLog COPYING.txt keychain.pod README.md 42 | --------------------------------------------------------------------------------