pax_global_header00006660000000000000000000000064146513546720014527gustar00rootroot0000000000000052 comment=0e197b6de34324058f3d76074c90c5c734a30278 cryptmount-6.3.0/000077500000000000000000000000001465135467200137615ustar00rootroot00000000000000cryptmount-6.3.0/.gitignore000066400000000000000000000014541465135467200157550ustar00rootroot00000000000000# cryptmount source artefacts to be ignored by 'git' aclocal.m4 autom4te.cache/ compile configure config.guess config.sub cryptmount install-sh stamp-h? tags .depend .*.swp [a-z]*.o cm-*.so config.h config.log config.status debian/*-debtx debian/patches/docfiles-pathnames.patch delegates.h doxygen.conf luks/Makefile luks/Makefile.in luks/libcmluks.a Makefile Makefile.in man/cmtab.5 man/cryptmount.8 man/cryptmount-setup.8 man/Makefile man/*/cryptmount.8 man/*/cmtab.5 man/*/Makefile po/Makefile po/Makefile.in po/messages.mo po/POTFILES po/stamp-po po/*.gmo sysinit/cryptmount.service sysinit/initscript sysinit/Makefile.in sysinit/setupscript testing/keys/3.1.2_luks_md5_blowfish_0 testing/keys/4.1_luks_ripemd160_twofish_0 testing/logs/ testing/Makefile.in testing/mudslinger testing/mudslinger*.log cryptmount-6.3.0/AUTHORS000066400000000000000000000035331465135467200150350ustar00rootroot00000000000000cryptmount was written by RW Penney (England, UK) The author gratefully recognizes the assistance of being able to refer to the source-code for the following packages: cryptsetup-1.0.6 et seq. openssl-0.9.8 (specifically apps/enc.c, by Eric Young) devicemapper-1.01.05 (by Sistina UK) utillinux-2.12q (specifically mount/lomount.c) Although cryptmount contains no code taken directly from any of these or other packages, certain similarities of structure cannot be avoided in some areas. Thanks are also due to the following people who have been very helpful in testing and improving cryptmount: Carl Banks (idea behind --safetynet option) Lszl Bszrmnyi (debian-specific packaging) Raphal Droz (advice on use of libcryptsetup) Piotr Dziwinski (patch for --status option) Harald Dunkel (debian chroot-installation testing) Baruch Even (patches for man-pages) Levente Farkas (patches to RH spec-file) Glenn Golden (documentation cleanups & systemd testing) Rennie deGraaf (tracing pathname canonicalization issues) Daniel Grund (tracing cmstatus-corruption vulnerability) Jens Guenther (improving compatibility with cryptsetup-2.x) Helge Kreutzmann (updating German translations) Holger Mller (RH spec-file, Makefile.in patches, LARGEFILE testing) Bjrn Nilsson (suggestions for /dev/disk/by-id in documentation) Dan O'Huiginn (patch for Debian examples directory) Sebastian Rasmussen (patches for readonly loopback devices) Petter Reinholdtsen (patches for /etc/init.d dependencies) Gilles Sadowski (guide to using sshfs with cryptmount) Erich Schubert (patches to initscript) Kai Wasserbch (German localization) Eriks Zelenka (improved portability of RPM spec-file) cryptmount-6.3.0/COPYING000066400000000000000000000431031465135467200150150ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. cryptmount-6.3.0/ChangeLog000066400000000000000000000533321465135467200155410ustar00rootroot00000000000000ChangeLog for cryptmount (https://github.com/rwpenney/cryptmount) 28Jul24 - *** cryptmount-6.3 released 21Jul24 - Migrated devmapper naming assumptions to /dev/disk/by-id/dm-name-* 11Jul24 - Fixed duplicated loopback free device search Replaced udev-settle mechanisms with new await_device() mechanism Removed use of libudev 17Jun23 - Improved zeroing of inputs to getopt_long() (as highlighted by dukpt/@ptef) 30Apr23 - Incorporated Debian patch for cmtab.example installation 23Apr23 - Improved configurability of systemd unit path 07Jan23 - *** cryptmount-6.2 released 02Jan23 - Enabled libudev by default 20Dec22 - Updated various maintainer URLs to point to github.com Reduced verbosity of manual-page variable substitution Improved unit-test support for NVME devices 08Oct22 - *** cryptmount-6.1 released 01Oct22 - Improved udev settling schedule and filesystem syncs Added partial support for compiling against libgcrypt-1.7 25Sep22 - Improved waiting schedule for inter-process status locks Improved stability of tests against legacy cryptsetup 11Sep22 - Revised installation instructions and top-level README 03Sep22 - *** cryptmount-6.0 released 14Aug22 - Revised algorithm test-cases in mudslinger script to align to OpenSSL-3.0 06Aug22 - Refreshed cipher algorithm names to match OpenSSL/libgcrypt conventions Converted default libgcrypt keycipher to aes256-xts and keyhash to sha256 24Jul22 - Converted setup-script to use LUKS format by default 27Dec20 - Incorporated updated German translations from Helge Kreutzmann 06Sep20 - Refreshed cipher-mode and loop-device selection in "mudslinger" testing script 16Nov19 - Refined handling of passwords in "mudslinger" testing script 06Oct19 - Improved documentation of default values in cmtab manual page 28Sep19 - Removed use of 'minix' filesystem in testing script 06Jan19 - Fixed various memory leaks in mount/unmount pathways 05Jan19 - Fixed memory cleanup error on closedown when using multiple targets 17Mar18 - *** cryptmount-5.3 released 27Jan18 - Improved handling of LUKS plain files for libcryptsetup-2.x. Changed default location of cmtab to /etc/cryptmount/cmtab 17Jan18 - Minor updates to documentation & Debian packaging 16Dec17 - Patched to support cryptsetup-2.x Updated to automake-1.15 30Sep16 - Suppressed benign error codes when handling '--all' targets 11Aug16 - Improved detection of already configured targets 05Aug16 - Improved handling of '--all' with already mounted filesystems 02Apr16 - Updated bug-report email address 25Oct15 - *** cryptmount-5.2 released 22Oct15 - Added "supath" option to configure PATH via /etc/cryptmount/cmtab 07Oct15 - Improved setup of PATH when invoking fsck 18Aug15 - Dispensed with debian/dirs installation-directory list 17Aug15 - Allowed multiple attempts for password entry in setup script 16Aug15 - Updated debian/rules build-script to use debhelper v7 07Jul15 - Removed support for dynamically loadable key-managers 06Jul15 - Various cleanups to avoid warnings when compiled as C++ 04May15 - *** cryptmount-5.1 released 03May15 - Updated to automake-1.14.1 30Aug14 - Resolved libgcrypt/libcryptsetup versioning in Debian packaging 28Aug14 - Patched rpm build-script to better support redhat/fedora distros 30Apr14 - *** cryptmount-5.0 released 13Apr14 - Added further error checks on LUKS password changing 12Apr14 - *** cryptmount-5.0beta1 released 05Apr14 - Removed legacy LUKS wrappers in favour of libcryptsetup Various improvements to Doxygen documentation. 25Mar14 - Converted LUKS key-writing to use libcryptsetup 21Mar14 - Added '--status' option for querying filesystem mount status 18Mar14 - Converted LUKS key-reading to use libcryptsetup 14Mar14 - Updated LUKS functions to mirror cryptsetup-1.6.4 12Mar14 - Removed support for using LUKS partitions without UUID library. 12Feb14 - Patched unexpanded @ETCDIR@ in cryptmount-setup script 14Jan14 - *** cryptmount-4.5 released 01Jan13 - Removed legacy non-64bit loop-device support 31Dec13 - Added support for /dev/loop-control interface of kernel >= 3.1 23Dec13 - *** cryptmount-4.5beta1 released 22Dec13 - Updated LUKS functions to mirror cryptsetup-1.6.3 20Dec13 - Added runtime warning about deprecated 'fsoptions' in cmtab 16Dec13 - Added support for trim/allow_discards option within dm-crypt 13Dec13 - Moved /etc/cryptmount/cmstatus into /var/run/cryptmount.status Added '--with-sysrundir' option to configure 13Oct13 - Removed support for /etc/init.d/cryptmount-early bootup script 03Aug13 - Added mechanism for validating contents of target-status file 19May13 - *** cryptmount-4.4 released 18May13 - Improved consistency of terminology within cmtab.5 manual page. 17May13 - Added automatic modprobe for dm-crypt etc. as part of installation Improved documentation of need for kernel-support for /dev/loop etc. 10May13 - Updated to autoconf-2.69 Updated Debian packaging to require package-hardening tools 22Apr13 - *** cryptmount-4.4beta1 released 14Apr13 - Moved various /etc/init.d & systemd files into new sysinit/ directory 24Feb13 - Added support for '--system-boot' command-line option Added deprecation notice for /etc/default/cryptmount in bootup script 13Feb13 - Reorganized command-line parser to unify mode & flag declarations 09Feb13 - Added support for 'bootaction' option within configuration file 05Feb13 - Updated LUKS functions to mirror cryptsetup-1.6.0 19Dec12 - Adjusted key-generation to reduce risk of blocking on /dev/random 18Mar12 - *** cryptmount-4.3 released 28Jan12 - *** cryptmount-4.3beta1 released 26Jan12 - Added unit-test for config-files containing environmental variables 22Jan12 - Improved robustness to random combinations of compilation options 01Jan12 - Updated LUKS functions to mirror cryptsetup-1.4.1 31Dec11 - Updated LUKS functions to mirror cryptsetup-1.3.1 29Dec11 - Added support for variables (e.g. $(USERNAME)) in configuration file 08Oct11 - Added support for udev queue hosted beneath /run 17Jun11 - *** cryptmount-4.2 released 11Jun11 - Updated French & German localizations 03May10 - *** cryptmount-4.2beta1 released 02May11 - Added check for working '--size' in cryptsetup-compatibility test 26Apr11 - Added unit-tests for 'mkswap' protection & entropy calculation 26Mar11 - *** cryptmount-4.2alpha1 released 28Feb11 - Patched block-size calculations to consistently use 512-byte blocks 20Feb11 - Added entropy-based check on filesystem before forcing 'mkswap' 21Dec10 - Updated LUKS functions to mirror cryptsetup-1.2.0 23Aug10 - Adjusted configure.ac to use pkg-config to find uuid-dev library 22Aug10 - Updated LUKS functions to mirror cryptsetup-1.1.3 02Jun10 - *** cryptmount-4.1 released 14May10 - Improved logging of system information in testing logfile 02May10 - *** cryptmount-4.1beta1 released 30Apr10 - Extended udev_settle() to support queue.bin of recent udev packages 25Apr10 - Added udev-settling operations to LUKS key manager 06Mar10 - *** cryptmount-4.1alpha1 released 02Mar10 - Added support for 'fsckoptions' flag in cmtab 27Feb10 - Improved legacy-key unit-test to allow for optional key-managers 24Jan10 - Updated LUKS functions to mirror cryptsetup-1.1.0 16Jan10 - Added test of installing in chroot for debian/postinst script 06Dec09 - Patched /etc/init.d script to apply --safety-net option to all targets 17Sep09 - Patched /etc/init.d scripts to correct startup dependencies 13Sep09 - Renamed 'fsoptions' flag to 'mountoptions' in cmtab & internals 08Aug09 - Updated LUKS functions to mirror cryptsetup-1.0.7 17Jun09 - Migrated version control from Subversion to Git 04May09 - *** cryptmount-4.0 released 02May09 - Improved error-trapping in writing of target-status file 25Apr09 - Updated to autoconf-2.61 07Mar09 - Added various udev-waits to avoid race-conditions in mudslinger tests 03Mar09 - Added waits to allow udev events to settle on device creation/deletion 22Feb09 - Added automated test for pure-password key-manager 22Feb09 - *** cryptmount-4.0beta1 released 21Feb09 - Replaced accented chars in French man-pages with groff named chars 01Feb09 - Added mudslinger unit-test for file-format overrides 31Jan09 - Added means for overriding file-format version in builtin key-manager Added various unit-tests for string-processing functions 28Jan09 - Neatened checks on file read/write failures 07Jan09 - *** cryptmount-4.0alpha1 released 06Jan09 - Added support for enhanced password-fortifying in builtin key-manager Added automated test for reading keyfiles created by earlier releases 04Jan09 - Refactored & improved password-fortifying algorithm Purged (redundant) hashing methods from keymanager_t interface 02Jan09 - Extended LUKS-compatibility tests to explore multiple ciphers Improved LUKS key-writing to support choice of cipher+modes 01Jan09 - Refactored linkages between target-definitions & key-managers Neatened installation of default parameters in key-managers 31Dec08 - Renamed 'cment_t' to 'tgtdefn_t' to better align with documentation 16Nov08 - Increased strength of pure-password key derivation function 01Nov08 - Added basic pure-password keymanager, without external keyfile 31Oct08 - Added explicit warnings in documentation about deleting keyfiles 27Oct08 - Patched call to fsck so that fixed f/s errors are treated as success 23Oct08 - Added configuration of /etc/init.d scripts to rpm build-script 20Oct08 - Neatened rpm build-script based on version by Dag Wieers 03Oct08 - *** cryptmount-3.1 released 16Aug08 - tidied internal tests for presence of exising LUKS headers extended LUKS unit-tests to include re-formatting protection 03Aug08 - *** cryptmount-3.1beta1 released 02Aug08 - added basic documentation of LUKS usage to man-pages 01Aug08 - added LUKS inverse-compatibility unit-test 27Jul08 - *** cryptmount-3.1alpha2 released 27Jul08 - added user-confirmation mechanism before formatting LUKS partitions added password-changing mechanisms to LUKS key-manager 26Jul08 - added support for formatting LUKS partitions 19Jul08 - extended keymanager interface to support fixed keyfile locations (e.g. LUKS) 20Jun08 - added auto loopback creation for LUKS targets within ordinary files 19Jun08 - *** cryptmount-3.1alpha1 released 19Jun08 - added unit-test for LUKS compatibility layer 16Jun08 - added prototypical mechanisms for mounting LUKS partitions 15Jun08 - preparing basic infrastructure for LUKS compatibility layer 07Jun08 - *** cryptmount-3.0 released 06Jun08 - added German localization of messages, provided by Kai Wasserbäch 18May08 - converted charset of French manpages from latin1 to utf8 16May08 - tidied more OpenSSL artefacts 12May08 - titied debian build-directory 11May08 - *** cryptmount-3.0beta1 released 10May08 - added basic French localization of cryptmount-setup script 05May08 - began internationalizing cryptmount-setup script 26Apr08 - added support for multiple password attempts on key-extraction improved consistency of usage of baddecrypt error-flag 24Mar08 - added unit-test for '_DEFAULTS_' pseudo-target 11Mar08 - added support for '_DEFAULTS_' pseudo-target 18Feb08 - neatened licence statements in *.c, *.h 03Feb08 - began removing dependence on OpenSSL library 27Jan08 - updated to automake-1.10 20Jan08 - *** cryptmount-2.2 released 20Jan08 - enhanced error-trapping on loop-device setup failure 18Jan08 - added further explanation of device-mapper error messages to README 20Dec07 - updated French translations 14Dec07 - *** cryptmount-2.2beta1 released 09Dec07 - removed (spurious) restriction of '--passwd-fd' option to root only 08Dec07 - altered relative priority of libgcrypt & openssl in configure script 07Dec07 - refactored command-line password reading into km_get_passwd() wired-together reading of passwords from file-descriptor 25Nov07 - tidied various whitespace anomalies 04Nov07 - added lintian-override file to quieten complaints about setuid binary 27Oct07 - changed OpenSSL key-manager to use internal password dialogue function added posix-compliant version of getpass() when termios.h is available 06Oct07 - improved memory-cleanup within gcrypt key-extraction 05Oct07 - patched module-installation to give better control over strip/no-strip adjusted key-manager def'ns to prepare for reading passwds via streams 05Aug07 - refactored cleanup mechanisms in 'mudslinger' testing script 04Aug07 - *** cryptmount-2.1 released 04Aug07 - split /etc/init.d script into separate early & normal phases added basic man-page for cryptmount-setup 17Jul07 - *** branch-2.1 forked from trunk 15Jul07 - added notices about migration plans for avoiding OpenSSL library added 'reuse-key' option 14Jul07 - add OpenSSL-compatible key reading/writing via libgcrypt extended tests for cipher/digest name-mapping in armour-gcry.c added unit-test for extraction of OpenSSL keys via libgcrypt extended automatic cipher/digest name-mapping in armour-gcry.c 13Jul07 - reorganized libgcrypt key/iv-init to allow OpenSSL-compatible algo 12Jul07 - adjusted add_keymgr() to allow adding pre-built lists of key-managers 30May07 - extended commentary messaging in auto-setup script 28May07 - added beginning of auto-setup script 06May07 - added basic '--safetynet' option 04May07 - added precautionary modprobe for dm-mod to /etc/init.d startup script 29Apr07 - patched BLKGETSIZE test to cope better with block-size != 512bytes added comments in documentation about bad keysizes added explicit casting on converting uint32 to uchar updated to autoconf-1.9.6 & gettext-0.16.1 18Apr07 - added more return-code checks in password-changing 10Apr07 - *** cryptmount-2.0 released 02Apr07 - updated French manual pages 29Mar07 - added extra checks for fwrite()-success on key-generation 27Mar07 - widened use of size_t, to improve 64bit-cleanliness 24Mar07 - added 'splint' target to Makefile patched various type imperfections identified by 'splint' 19Mar07 - added basic security check on key-manager module directory 18Mar07 - extended README discussion of configuration at boot 15Mar07 - patched unsigned/size_t conflict in km_aug_key() 12Mar07 - *** cryptmount-2.0beta1 released 10Mar07 - reduced dependency of mudslinger testing-script on OpenSSL support adjusted configure.ac to use OpenSSL & libgcrypt by default if available 07Mar07 - made random-key generation less excessively greedy for entropy 06Mar07 - neatened internal special cases for unencrypted (raw) keys 04Mar07 - re-prioritized keymanagers to make builtin-type default for new keys added '--key-managers' option for listing available crypto engines 03Mar07 - increased security of memory management in armour-gcry key-extraction 01Mar07 - extracted armour-gcry key augmentation/checksum routines into utils.c 27Feb07 - added beginnings of built-in sha1/blowfish key-manager mechanisms added unit-test for internal Blowfish algorithm 25Feb07 - added unit-test for internal SHA1 algorithm added implementation of Blowfish algorithm (from http://www.schneier.com/code/bfsh-sch.zip (declared as "public domain")) 24Feb07 - extracted various armour/tables functions into new utils.{h,c} added basic implementation of SHA1 message-digest replaced crude raw-keymanager hashing algorithm with SHA1 23Feb07 - added basic support for dynamically loadable keymanager modules 19Feb07 - extracted OpenSSL & libgcrypt routines into separate armour-*.c files adjusted key-manager list-mechanisms to prepare for loadable modules 17Feb07 - added support for 'early' setup of cryptmount devices on system boot 13Feb07 - improved cleanup on test-failure in testing script 11Feb07 - improved configure.ac tests for libdevmapper components 10Feb07 - added randomized time-delay to config-file locking mechanisms 28Jan07 - added outline description of boot-time mounting/swap-on to README 26Jan07 - added new getblkcount() method for 32/64 bit filesystem block-count added unit-test for relationship between BLKGETSIZE64 & BLKGETSIZE 25Jan07 - changed block-start/length & iv-offset to int64 type to support v.large filesystems 05Nov06 - automated translation of install-paths in debian setup 15Oct06 - *** cryptmount-1.2 released 15Oct06 - added debian/* entries to default distribution 10Oct06 - augmented initscript to automatically include pathname of executable 05Oct06 - adjusted is_mounted() to use device-IDs rather than pathnames 01Oct06 - enhanced checking for missing command-line parameters 30Sep06 - added support for reading config-info from command-line via stream added separate unit-test for locks on privileged operations 02Sep06 - added support for 'pri=' flag in fsoptions for crypto-swap patched is_mounted() to mitigate pathname canonicalization in /etc/mtab added tests for pathname oddities in testing script 29Aug06 - incorporated Erich Schubert's patch for posix-compliant init script 14Aug06 - *** cryptmount-1.1 released 06Aug06 - added /etc/init.d script for setting up swap/filesystems at boot-up 30Jul06 - added '--enable-swap' option to configure.ac for crypto-swap 17Jul06 - *** cryptmount-1.1_beta released 16Jul06 - added support for encrypted swap partitions via '--swapon' option 08Jul06 - incorporated Baruch Even's '\-' patches into man-pages 30Jun06 - added unit-test for keyfile r/w across all key formats 24Jun06 - added support for keyfiles protected by libgcrypt library 18Jun06 - added clarifications to licence relating to OpenSSL linkage 17Jun06 - added simple unit-testing mechanisms for internal routines 16Jun06 - added '--with-openssl' option to configure 14Jun06 - abstracted cipher functions to enable support for multiple crypto-libs 27May06 - added default cipher-algorithm variables to configure.ac 26May06 - patched bug relating to loopbacks on readonly devices 08May06 - *** cryptmount-1.0rc1 forked & released 07May06 - added testing of multiple quasi-simultaneous mounts to testing script 06May06 - added cmstatus file to store user-locks rather than chown() keyfiles 30Apr06 - added argv[0] switches to allow invocation via 'cryptumount' etc 28Apr06 - updated man-page and README to include easier keyfile generation added testing of --change-password to testing script 27Apr06 - added testing of --generate-key to testing script 23Apr06 - added password-changing facilities added user-friendly facility for generating new key-files 21Apr06 - added preliminary French message translations (.po file) 20Apr06 - added French versions of manual pages 16Apr06 - changed delegation and fsck to be enabled by default moved man-pages into separate sub-directory (to prepare to i18n) 14Apr06 - patched rpm .spec file to allow building by non-root user ------ 08Apr06 - *** cryptmount-0.4 released 08Apr06 - added test for user/nouser flags adjusted man-page preprocessing to reflect fsck compilation-flag 07Apr06 - added 'flags' parameter to control privileged actions + auto-fsck 01Apr06 - added optional automatic fsck before mounting 24Mar06 - added optional delegation of (un)mounting to /bin/mount, /bin/umount 22Mar06 - created new fsutils.{h,c} & prepared fsoptions for mount-delegation 14Mar06 - added facility for unprotected (plain) decryption key 11Mar06 - added separate man-page for configuration file improved configure/Makefile expansion of @etcdir@ macro in man-pages 10Mar06 - changed output of --list to go to stdout rather than stderr added testing of --list and null-cmtab to testing script ------ 05Mar06 - *** cryptmount-0.3 released 02Mar06 - added password-changing & fsck examples to man-page 28Feb06 - added debianization scripts 26Feb06 - added test for /etc/mtab updating to testing script 25Feb06 - added connection to syslog for mount/unmount/prepare/release actions neatened configure tests for openssl & libdevmapper 24Feb06 - patched to improve support for LARGEFILEs 22Feb06 - made testing-script more tolerant of miscompiled executable 17Feb06 - changed /etc/mtab entries to use full name of mounted device adjusted unmount/release modes to continue beyond unconfigured targets 11Feb06 - added facilities for multiple-targets & '--all' option on command-line 10Feb06 - added security checks on directory containing cmtab ------ 02Feb06 - *** cryptmount-0.2 released 28Jan06 - added 'loop' parameter test to testing script improved syntax-error catching in cmtab added basic checks on security of target specification 23Jan06 - added 'loop' parameter to cmtab parser added basic checks on security of cmtab 22Jan06 - added rpm spec-file (based on version by Holger Mueller) 21Jan06 - added 'ivoffset' parameter to cmtab parser neatened delegation mechanisms for cmtab token-processing added cryptsetup-compatibility test to testing-script 20Jan06 - moved various security-related routines into new armour.{c,h} 15Jan06 - increased speed of startsector/numsector unit-test with new bingrep.c 14Jan06 - added 'startsector' & 'numsectors' parameters to cmtab parser ------ 06Jan06 - *** cryptmount-0.1 released 04Jan06 - added more informative error-messages for (un)mount failures 25Dec05 - patched command-line options to prefer 'unmount' over 'umount' added option-synonym test to testing-script 23Dec05 - patched to ease compilation on FedoraCore-4 (+ kernel-2.4 headers) 22Dec05 - neatened usage examples in README & man-page 18Dec05 - added mechanisms for updating /etc/mtab on (un)mounting ------ 16Dec05 - *** cryptmount-0.0.3 released 16Dec05 - allowed for automatic creation of device-nodes by libdevmapper 15Dec05 - added key-decryption failure detection 14Dec05 - patched bug in handling non-default keycipher & keyhash algorithms 12Dec05 - informative return-codes wired-in automatic testing script ("mudslinger") created ------ 09Dec05 - *** cryptmount-0.0.2 released 06Dec05 - added basic man-page added locking mechanism to avoid unmounting by different user 04Dec05 - added facility for configuring devices without mounting 03Dec05 - config-files below ${sysconfdir}/cryptmount/ improved error-handling & debris-removal on mount-failures ------ 02Dec05 - *** cryptmount-0.0.1 released cryptmount-6.3.0/INSTALL.md000066400000000000000000000153011465135467200154110ustar00rootroot00000000000000Installing cryptmount ===================== There are three main routes by which cryptmount can be installed on a Linux-based system: * Using a pre-compiled package provided by your flavour of Linux * Compiling from a source bundle containing the "configure" script * Compiling from a clone of the GitHub repository and using "autoconf" tools All of these options will, at some stage, require root-level permissions, such as "sudo". Distro-provided packages ------------------------ A variety of flavours of Linux provide official pre-built cryptmount packages, and these can be installed using normal package-management tools. In general, this is by far the easiest method of installing cryptmount. For example, on Debian or Ubuntu systems, one can simply run sudo apt-get install cryptmount Manual compilation ------------------ If you want to compile cryptmount from its source-code, perhaps because you want to customize some of its features, then this may require additional packages to be available, and should be driven by the "configure" script. If the configure script is missing, for example if working with a clone of cryptmount's [GitHub repository](https://github.com/rwpenney/cryptmount), then you may need to set up [autoconf](https://www.gnu.org/software/autoconf/) (version 2.61 or later), and run autoreconf -v -i Dependencies ------------ A number of development packages will need to be pre-installed in order to provide library functions on which cryptmount depends. (The precise naming of these packages may differ between Linux systems.) The following packages are essential: * kernel-headers (matching the running linux-image) * libdevmapper (version 1.02 or later) The following packages are also strongly recommended, and allow a wider range of much stronger cryptographic tools: * libcryptsetup (version 1.6 or later; this is essential for LUKS support) * libgcrypt (version 1.8 or later) * libudev (version 232 or later) * pkgconf or pkg-config You will also need to ensure that your system has support for the loopback and device-mapper devices, which may require loading of kernel modules when you first use cryptmount, e.g. sudo modprobe -a loop dm-crypt This is automatically performed on system reboot by setup scripts supplied with cryptmount. Source configuration -------------------- The "configure" script will automatically identify the location of key libraries and header files needed by cryptmount, and allow customization of the directory locations where cryptmount will be installed. Typically, one can simply run: ./configure although additional command-line options can also be supplied, such as: --prefix=/usr # To install beneath /usr rather than /usr/local --sysconfdir=/etc/cryptmount # To specify the directory where the "cmtab" will be stored --disable-luks # Turn-off support for LUKS encrypted containers --with-systemd # Use systemd boot-up configuration, rather than sysvinit A full list of options can be obtained by running ./configure --help Compilation and installation ---------------------------- If "configure" has run successfully (generating a `config.h` file), it should now be sufficient to run: make sudo make install This should install both the `cryptmount` and `cryptmount-setup` executables, together with manual pages and an empty filesystem configuration file. Running sudo cryptmount-setup will allow interactive creation of a basic encrypted filesystem (using LUKS, if available). More sophisticated scenarios can be handled by manual editing of the `cmtab`, following the guidance in the manual pages: man cryptmount man 5 cmtab In outline, if not using the cryptmount-setup script, one can add an entry to /etc/cryptmount/cmtab that describes the encrypted filesystem that we want to create: crypt { dev=/home/crypt.fs dir=/mnt/crypt fstype=ext4 mountoptions=defaults keyformat=luks } Thereafter, one can prepare the key-file and filing system as follows: test -e /home/crypt.fs || sudo dd if=/dev/zero of=/home/crypt.fs bs=1M count=128 sudo mkdir /mnt/crypt sudo cryptmount --generate-key 32 crypt sudo cryptmount --prepare crypt sudo mke2fs -t ext4 /dev/disk/by-id/dm-name-crypt sudo cryptmount --release crypt Configuring filesystems at system bootup ---------------------------------------- If you want to have encrypted filesystems setup at system boot-up, this can be achieved using either 'systemd' or the supplied 'initscript' program which is normally automatically installed as /etc/init.d/cryptmount . Both of these mechanisms use the `bootaction` parameter within `/etc/cryptmount/cmtab` to adjust how each filesystem is handled on system bootup. If using the `initscript` program, you may need to create symbolic links from /etc/rc?.d to `/etc/init.d/cryptmount` (in a way that depends on the precise details of your distribution), with something like sudo update-rc.d cryptmount defaults 28 being suitable under Debian systems. Common problems --------------- When configuring the system devices needed to support an encrypted filesystem, cryptmount will issue various requests through the device-mapper library. Unfortunately, some of the error messages issued by that library (as of version 1.02) are not easy to interpret. In situations where the device-mapper is compiled as a kernel module, an error of the form /proc/misc: No entry for device-mapper found Is device-mapper driver missing from kernel? Failure to communicate with kernel device-mapper driver. then this may indicate that the dm-mod kernel-module is not loaded. This can be (temporarily) solved by issuing the command: sudo modprobe -a dm-mod dm-crypt In order to ensure that this happens automatically when you reboot, you can add a line containing `dm-mod` to `/etc/modules`, or add a line of the form modprobe -q -a dm-mod dm-crypt || true to `/etc/rc.local`, or ensure that the cryptmount-startup scripts installed in /etc/init.d are run on system startup (e.g. by installing suitable symbolic-links from /etc/rc\*.d). When setting up a new encrypted filing system, typically when issuing a `cryptmount --prepare` command, you may receive an error message of the form device-mapper ioctl cmd 9 failed: Invalid argument which may mean that you have chosen a key-size that isn't supported by your chosen cipher algorithm. You can get some information about suitable key-sizes by checking the output from `more /proc/crypto`, and looking at the 'min keysize' and 'max keysize' fields.) ** *** ***** ******* Please note that cryptmount comes with NO WARRANTY - see the "COPYING" file in the top-level directory for further details. cryptmount-6.3.0/Makefile.am000066400000000000000000000065051465135467200160230ustar00rootroot00000000000000# automake script for 'cryptmount' # RW Penney, November 2005 AM_CPPFLAGS = -DCM_SYSCONF_DIR="\"$(CM_SYSCONF_DIR)\"" \ -DCM_SYSRUN_DIR="\"$(CM_SYSRUN_DIR)\"" bin_PROGRAMS=cryptmount cryptmount_SOURCES=cryptmount.c cryptmount.h \ armour.c armour.h \ armour-builtin.c armour-gcry.c armour-luks.c \ blowfish.c blowfish.h \ dmutils.c dmutils.h \ fsutils.c fsutils.h \ looputils.c looputils.h \ tables.c tables.h \ utils.c utils.h \ cmtesting.c cmtesting.h cryptmount_NONHEADERS = $(shell echo "${cryptmount_SOURCES}" | sed 's%\<[^ ]*\.h\>%%g') if BUILD_LUKSCOMPAT cryptmount_LDADD = ${libcryptsetup_LIBS} endif localedir=$(datadir)/locale AM_CPPFLAGS += -DLOCALEDIR=\"$(localedir)\" EXTRA_DIST = config.rpath mkinstalldirs cmtab.example \ INSTALL.md README.md README.sshfs RELNOTES cryptmount.spec \ debian/changelog debian/control \ debian/copyright debian/docs \ debian/rules debian/cryptmount.lintian-overrides \ debian/postinst debian/postrm debian/watch debian/source/format \ debian/upstream/signing-key.asc SUBDIRS = man po sysinit testing install-exec-hook: install-etcdir chown root:root $(DESTDIR)$(bindir)/cryptmount$(EXEEXT) chmod u+srwx,go-w,go+r $(DESTDIR)$(bindir)/cryptmount$(EXEEXT) @if test -z "$(DESTDIR)" -o "$(DESTDIR)" = "/"; then \ modprobe -a loop dm-crypt || true; \ ( egrep -q '\' /proc/devices \ && egrep -q '\' /proc/devices ) || \ echo "Warning: kernel support for /dev/loop and /dev/mapper is needed by cryptmount"; \ fi .PHONY: install-etcdir install-etcdir: if test ! -d "${DESTDIR}${CM_SYSCONF_DIR}" ; then \ ${mkdir_p} "${DESTDIR}${CM_SYSCONF_DIR}" ; \ fi if test ! -f "${DESTDIR}${CM_SYSCONF_DIR}/cmtab" ; then \ echo -e "# ${CM_SYSCONF_DIR}/cmtab - encrypted filesystem information for cryptmount\n# try 'man 8 cryptmount' or 'man 5 cmtab' for more details\n# or refer to ${CM_SYSCONF_DIR}/cmtab.example\n" >> "${DESTDIR}${CM_SYSCONF_DIR}/cmtab"; \ fi ${mkdir_p} "${DESTDIR}$(datarootdir)/doc/cryptmount/examples" ${INSTALL_PROGRAM_ENV} ${INSTALL_DATA} cmtab.example "${DESTDIR}$(datarootdir)/doc/cryptmount/examples/cmtab" install-setup: setupscript test -d "${DESTDIR}${sbindir}" || ${mkdir_p} "${DESTDIR}${sbindir}" ${INSTALL_PROGRAM_ENV} ${INSTALL_SCRIPT} setupscript "${DESTDIR}${sbindir}/cryptmount-setup" clean-local: -rm -f splint.log dist-hook: sed -e "s,^\(Version:\s*\)[0-9].*,\1${VERSION}," cryptmount.spec > cm_spec.new; cmp -q cryptmount.spec cm_spec.new || mv cm_spec.new cryptmount.spec; rm -f cm_spec.new pedantic: CFLAGS = -Wall -W -pedantic -g pedantic: ${bin_PROGRAMS} if HAVE_DOXYGEN doxydocs: doxygen.conf doxygen doxygen.conf endif .PHONY: splint splint: @echo -n "" > splint.log for src in ${cryptmount_NONHEADERS}; do \ echo "==== $${src} ====" >> splint.log; \ splint ${DEFS} ${DEFAULT_INCLUDES} ${INCLUDES} ${AM_CPFLAGS} ${CPPFLAGS} -D__signed__="" -posix-lib -checks $${src} >> splint.log 2>&1 ; \ echo -e "\n\n" >> splint.log || true; \ done # 'cmtest' target is for use with 'mudslinger' testing script: cmtest: CFLAGS = -Wall -g -DTESTING -DCM_SRCDIR=\"${abs_srcdir}\" cmtest: ${bin_PROGRAMS} ${MAKE} -C testing autokeys mudslinger test: cmtest cd testing && sudo ./mudslinger .PHONY: depend depend: ${CC} -MM ${DEFS} ${DEFAULT_INCLUDES} ${INCLUDES} ${AM_CPFLAGS} ${CPPFLAGS} ${cryptmount_NONHEADERS} > .depend -include .depend cryptmount-6.3.0/README.md000066400000000000000000000066631465135467200152530ustar00rootroot00000000000000# Cryptmount - user-mode management of Linux encrypted filesystems cryptmount allows any user to access encrypted filing systems on demand under GNU/Linux systems running at least a 2.6-series kernel. It also assists the system administrator in creating and managing encrypted filesystems based on the kernel's dm-crypt device-mapper target. After initial configuration by the superuser, an ordinary user can mount or unmount filesystems managed by cryptmount solely by providing the decryption password, with any system devices needed to access the filing system being configured automatically. A wide variety of encryption schemes (provided by the kernel and the libgcrypt library) can be used to protect both the filing system and the access key. The protected filing systems can reside in either ordinary files, or raw disk partitions. ## Installation To build cryptmount from source, please follow the instructions in the [INSTALL.md](https://github.com/rwpenney/cryptmount/blob/master/INSTALL.md) file in the top directory of the source package. cryptmount has been tested on a wide variety of GNU/Linux platforms including: [ArchLinux](https://aur.archlinux.org/packages/cryptmount), CentOS, [Debian](https://packages.debian.org/stable/cryptmount), Fedora, [Gentoo](https://packages.gentoo.org/packages/sys-fs/cryptmount), [Mageia](https://madb.mageia.org/package/show/source/1/application/0/release/cauldron/name/cryptmount), [Ubuntu](https://packages.ubuntu.com/jammy/cryptmount) etc. For the most recent source-bundles of cryptmount, please see [GitHub](https://github.com/rwpenney/cryptmount/releases), where the latest [developer versions](https://github.com/rwpenney/cryptmount) can also be found. An encrypted filing system must initially be created by the superuser. A basic setup can be created interactively by running the `cryptmount-setup` program, which is typically installed in `/usr/local/sbin/`, and will use the [LUKS](https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup) encryption format by default. More elaborate situations can be handled by manual editing of the filesystem definition, typically in `/etc/cryptmount/cmtab`. For example, an entry of the form: ``` crypt { dev=/home/crypt.fs dir=/mnt/crypt fstype=ext4 mountoptions=defaults keyformat=luks } ``` describes a LUKS-encrypted filesystem to be contained in an ordinary file, and which will be mounted beneath `/mnt/crypt`. Such a filesystem could be initialized as follows: ``` test -e /home/crypt.fs || dd if=/dev/zero of=/home/crypt.fs bs=1M count=128 mkdir /mnt/crypt cryptmount --generate-key 32 crypt cryptmount --prepare crypt mke2fs -t ext4 /dev/disk/by-id/dm-name-crypt cryptmount --release crypt ``` Further details are available in the installed manual pages. Thereafter, the following command, executed by an ordinary user, will make the filing system accessible below /mnt/crypt: ``` cryptmount crypt ``` and the following will unmount it: ``` cryptmount -u crypt ``` If using a separate keyfile, please take great care that you do not delete that file, as this will make access to your filesystem (essentially) impossible. You are strongly advised to keep a backup copy of the key-file. ## Signing keys The current GPG signature used for cryptmount releases has fingerprint `7A09 0051 9745 19A3 ED1B D4CB A6CF D54C 4405 160E`. (The previous key, `78BC 1A99 61DC 2DAA 7BF8 99DB A6D8 2C65 B8CE F5E7`, expired in May 2023.) cryptmount-6.3.0/README.sshfs000066400000000000000000000050711465135467200157710ustar00rootroot00000000000000Encrypted filesystem on a remote host using "cryptmount" (A) Assumptions * Remote machine is called "rmach" * User login on the local machine is "luser" * User login on the remote machine is "ruser" * No firewall (otherwise an error "read: connection reset by peer" can occur). * SSH public key of user "luser" is present in ~ruser/.ssh/authorized_keys on "rmach" * User "luser" is a member of the "fuse" group, to allow reading of /etc/fuse.conf * Option user_allow_other is enabled in /etc/fuse.conf (B) Preparing a "virtual device" (operations to be performed once) The following must be performed as the ordinary user on the local machine. 1. Mount the remote home on the local machine: $ mkdir -p mnt/remote $ sshfs ruser@rmach: mnt/remote 2. Create a 100 GB (sparse) file that will contain the filesystem: $ cd mnt/remote $ truncate -s 100G virtual_disk.img 3. Release the mount point: $ cd $ fusermount -u mnt/remote 4. Define a mount point whose contents will be stored encrypted, e.g. $ mkdir enc_remote The following must be performed as "root" on the local machine. 5. Create an entry in "/etc/cryptmount/cmtab" luser_data { dev=/home/luser/mnt/remote/virtual_disk.img dir=/home/luser/enc_remote loop=auto fstype=ext4 mountoptions=defaults cipher=aes-cbc-plain keyformat=luks } 6. Mount the remote filesystem: # cd ~luser # sshfs -o IdentityFile=~luser/.ssh/id_rsa ruser@rmach: mnt/remote 7. Prepare the encrypted device (setting the password to access the encrypted filesystem data): # cryptmount --prepare luser_data 8. Create the filesystem (must be same as defined in the "cmtab" entry) # mkfs.ext4 /dev/mapper/luser_data # chown luser.luser 9. Finalize: # cryptmount --release luser_data 10. Mount encrypted filesystem in order to set appropriate ownership: # cryptmount luser_data # chown luser.luser /home/luser/enc_remote 11. Release all resources: # cryptmount -u luser_data # fusermount -u mnt/remote (C) Saving data to the remote encrypted filesystem 1. Mounting the remote home (as an ordinary user): $ sshfs -o allow_root ruser@rmach: mnt/remote 2. Mounting the encrypted filesystem (password will be requested): $ cryptmount luser_data 3. Checking the available space on the encrypted filsystem: $ df -k enc_remote cryptmount-6.3.0/RELNOTES000066400000000000000000000535251465135467200151510ustar00rootroot00000000000000 Release notes for cryptmount-6.3 RW Penney, July 2024 Introduction ============ cryptmount is a utility for GNU/Linux operating systems which allows an ordinary user to mount an encrypted filing system without requiring superuser privileges, and which assists the system-administrator in creating and managing encrypted filesystems & swap-partitions. cryptmount automatically performs the various stages of configuring any supporting loopback and device-mapper targets needed to access an encrypted filing system before actually mounting it, but without requiring the user to be explicitly granted root privileges through either knowing the root password or through tools such as sudo. Filesystems managed by cryptmount can also be designated so that only the superuser can (un)mount them. By allowing user-level, on-demand, mounting of encrypted filing systems, cryptmount allows filesystems that are only used intermittently to be left in a more secure state than if they have to be made available by the system administrator whenever the system is booted. cryptmount also provides an aid to the system manager in allowing easier control over the configuration and mounting of encrypted filesystems, especially within system start-up scripts. Summary of new features in cryptmount-6.3 ========================================= This (stable) release offers the following improvements: * Safer interaction with system automatic creation of devmapper nodes * Replacement of device-settling mechanisms to remove dependency on libudev It has been tested on the following systems: * Arch Linux (late-Jul-2024) (x86_64) * Debian GNU/Linux 13.x ("trixie"/"testing", late-Jul-2024) (amd64) * Debian GNU/Linux 12.6 ("bookworm") (amd64) * Debian GNU/Linux 11.10 ("bullseye") (amd64) * Fedora 40 (x86_64) * Fedora 39 (x86_64) * openSUSE Leap 15.6 (x86_64) * Ubuntu 24.04 ("noble") (x86_64) * Ubuntu 18.04 ("bionic") (x86_64) Summary of new features in cryptmount-6.2 ========================================= This (stable) release offers the following improvements: * More robust handshaking on device setup using libudev It has been tested on the following systems: * Arch Linux (early-Jan-2023) (x86_64) * Debian GNU/Linux 12.x ("bookworm"/"testing", early-Jan-2023) (amd64) * Debian GNU/Linux 11.6 ("bullseye") (amd64) * Debian GNU/Linux 10.13 ("buster") (x86) * Fedora 37 (x86_64) * openSUSE Leap 15.4 (x86_64) * Ubuntu 22.10 ("kinetic") (x86_64) Summary of new features in cryptmount-6.1 ========================================= This (stable) release offers the following improvements: * Improved deconfliction when operating simultaneously with other device-mapper tools * Revised installation instructions, now in markdown format It has been tested on the following systems: * Alma Linux 9.0 (x86_64, lacking libcryptsetup headers) * Arch Linux (mid-Dec-2022) (x86_64) * Debian GNU/Linux 12.x ("bookworm"/"testing", early-Oct-2022) (amd64) * Debian GNU/Linux 11.6 ("bullseye") (amd64) * Debian GNU/Linux 10.13 ("buster") (x86) * Fedora 37 (x86_64) * Ubuntu 22.10 ("kinetic") (x86_64) Summary of new features in cryptmount-6.0 ========================================= This (stable) release offers the following enhancements: * cryptmount-setup script uses LUKS format by default * Support for wider range of libgcrypt & OpenSSL cipher algorithms It has been tested on the following systems: * Arch Linux (mid-Aug-2022) (x86_64) * Debian GNU/Linux 12.x ("bookworm"/"testing", early-Sep-2022) (amd64) * Debian GNU/Linux 11.4 ("bullseye") (amd64) * Debian GNU/Linux 10.12 ("buster") (x86) * Fedora 36 (x86_64) * Ubuntu 22.04 ("jammy") (x86_64) Summary of new features in cryptmount-5.3 ========================================= This (stable) release offers the following enhancements: * Improved compatability with libcryptsetup-2.x It has been tested on the following systems: * Arch Linux (late-Dec-2020) (x86_64) * CentOS 8.3.2011 (x86_64) * Debian GNU/Linux 11.x ("bullseye"/"testing", late-Dec-2020) (amd64) * Debian GNU/Linux 10.7 ("buster") (amd64, x86) * Debian GNU/Linux 9.13 ("stretch") (x86) * Fedora 33 (x86_64) * Gentoo (late-Dec-2020) (x86) * Ubuntu 20.10 ("groovy") (x86_64) Summary of new features in cryptmount-5.2 ========================================= This (stable) release offers the following enhancements: * Fixes to filesystem-check (fsck) PATH setup * Allowing multiple password attempts within setup script * Various code cleanups It has been tested on the following systems: * Arch Linux (mid-Jan-2018) (x86_64) * CentOS 7.4 (x86_64) * Debian GNU/Linux 10.x ("buster"/"testing", mid-Jan-2018) (x86) * Debian GNU/Linux 9.3 ("stretch") (amd64) * Debian GNU/Linux 8.10 ("jessie") (x86) * Gentoo (mid-Dec-2017) (x86) * Ubuntu 17.10 ("artful") (x86_64) Summary of new features in cryptmount-5.1 ========================================= This (stable) release offers the following enhancements: * Improved portability of RPM build scripts It has been tested on the following systems: * Arch Linux (early-May-2015) (x86) * CentOS 7.1 (x86_64) * Debian GNU/Linux 8.0 ("jessie") (x86, amd64) * Debian GNU/Linux 7.3 ("wheezy") (x86) * Fedora 21 (x86_64) * OpenSuSE 13.2 ("harlequin") (x86) * Ubuntu 15.04 ("vivid") (x86_64) Summary of new features in cryptmount-5.0 ========================================= This (stable) release offers the following enhancements: * Delegation of all LUKS functionality to libcryptsetup * Addition of '--status' option to query filesystem mounting status It has been tested on the following systems: * Arch Linux (late-Apr-2014) (x86) * Gentoo (late-Apr-2014) (x86) * Debian GNU/Linux 7.x ("jessie"/"testing", late-Apr-2014) (x86) * Debian GNU/Linux 7.3 ("wheezy") (x86, amd64) * Mageia 4 (x86) * OpenSuSE 12.3 ("dartmouth") (x86_64) * Ubuntu 14.04 ("trusty") (x86_64) Summary of new features in cryptmount-4.5 ========================================= This (stable) release offers the following enhancements: * Support for TRIM/allow_discards options suitable for solid-state disks * Moving run-time state information from /etc into /run * Updating of loop-device management to use /dev/loop-control interface It has been tested on the following systems: * Arch Linux (early-Jan-2014) (x86) * CentOS 6.5 (x86_64) * Debian GNU/Linux 7.x ("jessie"/"testing", early-Jan-2014) (x86) * Debian GNU/Linux 7.3 ("wheezy") (x86, amd64) * Debian GNU/Linux 6.0 ("squeeze") (x86) * Debian GNU/Linux 5.0 ("lenny") (x86) * Fedora 20 ("heisenbug") (x86_64) * Gentoo (early-Jan-2014) (x86) * Mageia 3 (x86) * OpenSuSE 12.3 ("dartmouth") (x86_64) * Ubuntu 13.10 ("saucy") (x86_64) Summary of new features in cryptmount-4.4 ========================================= This (stable) release offers the following enhancements: * Support for systemd * Unified support for automatic filesystem setup on system boot * Improved handling of kernel module loading on initial setup * Improved support for management of LUKS partitions to mirror cryptsetup-1.6 It has been tested on the following systems: * Arch Linux (mid-May-2013) (x86) * CentOS 6.4 (x86_64) * Debian GNU/Linux 7.x ("jessie"/"testing", mid-May-2013) (x86) * Debian GNU/Linux 7.0 ("wheezy") (x86, amd64) * Debian GNU/Linux 6.0 ("squeeze") (x86) * Debian GNU/Linux 5.0 ("lenny") (x86) * Fedora 18 ("spherical cow") (x86_64) * Gentoo (x86, mid-May-2013) * OpenSuSE 12.2 ("mantis") (x86_64) * Ubuntu 13.04 ("raring ringtail") (x86_64) Summary of new features in cryptmount-4.3 ========================================= This (stable) release offers the following enhancements: * Support for environmental variables within target definitions * Improved support for management of LUKS partitions to mirror cryptsetup-1.4 It has been tested on the following systems: * CentOS 5.7 (x86) * Debian GNU/Linux 6.1 ("wheezy"/"testing", mid-March-2012) (x86) * Debian GNU/Linux 6.0 ("squeeze") (x86, amd64) * Fedora 16 (x86_64) * Gentoo (x86, mid-February-2012) * Linux Mint 11 ("kataya") * OpenSuSE 11.4 (x86) * Ubuntu 10.04 ("lucid lynx") (x86_64) Summary of new features in cryptmount-4.2 ========================================= This (stable) release offers the following enhancements: * Improved protection against accidental formatting of swap partitions * Improved support for management of LUKS partitions to mirror cryptsetup-1.2 It has been tested on the following systems: * CentOS 5.6 (x86) * Debian GNU/Linux 6.1 ("wheezy"/"testing", mid-June-2011) (x86) * Debian GNU/Linux 6.0 ("squeeze") (x86, amd64) * Debian GNU/Linux 5.0 ("lenny") (x86) * Fedora 13 (x86_64) * Gentoo (x86, early-June-2011) * OpenSuSE 11.4 (x86) * Ubuntu 10.04 ("lucid lynx") (x86_64) * Ubuntu 8.04 ("hardy heron") (x86) Summary of new features in cryptmount-4.1 ========================================= This (stable) release focuses on compatibility improvements including: * Facilities for user-supplied options to 'fsck' for automatic checking of filesystems on mounting * Improved support for management of LUKS partitions to mirror cryptsetup-1.1 including user-selected hashing functions and code-cleanup It has been tested on the following systems: * Debian GNU/Linux 5.1 ("squeeze"/"testing", mid-May-2010) (x86) * Debian GNU/Linux 5.0 ("lenny") (x86, amd64, ppc) * Fedora 12 (x86) * FedoraCore-7 (x86) * Gentoo (x86, late-May-2010) * OpenSuSE 11.1 (x86) * Slackware 12.2 (x86) * Ubuntu 10.04 ("lucid lynx") (amd64) * Ubuntu 8.04 ("hardy heron") (x86) Summary of new features in cryptmount-4.0 ========================================= This (stable) release focuses on security & functionality improvements including: * Support for encrypted filesystems protected by password, without the need for a separate keyfile or partition header * Enhanced protection against password attacks in the builtin key-manager through additional hash-based password strengthening * Improved support for selecting different encryption schemes when creating LUKS partitions * Substantial tidying of internal interfaces & removal of legacy code It has been tested on the following systems: * Debian GNU/Linux 5.1 ("squeeze"/"testing", late-Apr09) (x86) * Debian GNU/Linux 5.0 ("lenny") (x86, ppc) * Debian GNU/Linux 4.0 ("etch") (x86, amd64) * Fedora 9 (x86) * FedoraCore-7 (x86) * OpenSuSE 11.1 (x86) * Slackware 12.2 (x86) * Ubuntu 8.04 ("hardy heron") (x86) * Ubuntu 7.10 ("gutsy gibbon") (x86) Summary of new features in cryptmount-3.1 ========================================= This (stable) release focuses on adding support for LUKS partitions * Support for mounting of existing LUKS partitions was added * Support for basic formatting of LUKS partitions was added * Support for changing passwords on LUKS partitions was added It has been tested on the following systems: * Debian GNU/Linux 4.1 ("lenny"/testing, mid-Sep08) (x86) * Debian GNU/Linux 4.0 ("etch") (x86, amd64) * Fedora 9 (x86) * FedoraCore-7 (x86) * OpenSuSE Linux 10.2 OSS (x86) * Ubuntu 8.04 ("hardy heron") (x86) * Ubuntu 7.10 ("gutsy gibbon") (x86) Summary of new features in cryptmount-3.0 ========================================= This (stable) release focuses on code-tidying and usability improvements * Support for default settings within filesystem configuration file * Support for multiple password attempts when interactively mounting encrypted filesystems * Improved internationalization infrastructure in filesystem setup-script, including French localization * German localization of message in main application * Removed dependence on OpenSSL library for OpenSSL-compatible access-keys It has been tested on the following systems: * Debian GNU/Linux 4.1 ("lenny"/testing, mid-May08) (x86) * Debian GNU/Linux 4.0 ("etch") (x86, amd64) * FedoraCore-7 (x86) * FedoraCore-5 (x86) * OpenSuSE Linux 10.2 OSS (x86) * Ubuntu 8.04 ("hardy heron") (x86) * Ubuntu 7.10 ("gutsy gibbon") (x86) Summary of new features in cryptmount-2.2 ========================================= This (stable) release focuses on code-tidying and usability improvements * Support for reading passwords from streams, to allow integration with scripts or GUI wrappers * Prioritization of libgcrypt (with OpenSSL compatibility layer) over libssl for access-key security It has been tested on the following systems: * Debian GNU/Linux 4.0 ("etch") (x86, amd64) * Debian GNU/Linux 3.1 ("sarge") (x86) * FedoraCore-7 (x86) * FedoraCore-5 (x86) * OpenSuSE Linux 10.2 OSS (x86) * Ubuntu 7.10 ("gutsy gibbon") (x86) Summary of new features in cryptmount-2.1 ========================================= This (stable) release focuses on extended functionality and consolidation * Setup script added for basic configuration of new encrypted filesystems * Support for OpenSSL key-files via the libgcrypt library * Facilities for translating between access-keys stored in different formats * Improved handling of system shutdown while loopback filesystems are active It has been tested on the following systems: * Debian GNU/Linux 4.0 ("etch") (x86, amd64) * Debian GNU/Linux 3.1 ("sarge") (x86) * FedoraCore-7 (x86) * FedoraCore-5 (x86) * OpenSuSE Linux 10.2 OSS (x86) * Ubuntu 7.04 ("feisty fawn") (x86) (may need 'modprobe dm-crypt' and creation of extra /dev/loop? nodes) Summary of new features in cryptmount-2.0 ========================================= This (stable) release focuses on extended functionality and improved internal structure, including: * Built-in key management based on SHA1 + Blowfish crypto-algorithms, which can be used when OpenSSL or libgcrypt are not available (e.g. during system boot-up, or if not installed at all) * OpenSSL & libgcrypt key-management now available through dynamically loadable modules * Improved support for very large (64bit) filing systems * Improved support for setup of encrypted devices at system boot * Various improvements to error-trapping and portability It has been tested on the following systems: * Debian GNU/Linux 4.0 ("etch") (x86, amd64) * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * OpenSuSE Linux 10.2 OSS (x86) * FedoraCore-5 (x86) Summary of new features in cryptmount-1.2 ========================================= This (stable) release focuses on extensions in functionality, including: * support for reading configuration data via the command-line * support for priority-setting on crypto-swap * improved robustness to pathological (un)mount operations It has been tested on the following systems: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * Ubuntu 6.06.1 ("dapper drake") (x86) (may need patching of 'dd' and creation of extra /dev/loop? nodes) * SuSE Linux 10.0 OSS (x86) * Mandriva Linux 2005 (x86) * FedoraCore-5 (x86) * FedoraCore-4 (x86) Summary of new features in cryptmount-1.1 ========================================= This (stable) release focuses on extensions in functionality, including: * support for encrypted swap partitions * multiple formats for key-files, currently either OpenSSL or libgcrypt * addition of a script for mounting filesystems/swap partitions at boot It has been tested on the following systems: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * SuSE Linux 10.0 OSS (x86) * Mandriva Linux 2005 (x86) * FedoraCore-5 (x86) * FedoraCore-4 (x86) Summary of new features in cryptmount-1.0 ========================================= This (stable) release focuses on extensions in robustness, user-friendliness and internationalization, including: * addition of options for changing the access password for each target * addition of mechanisms for generating random decryption keys for new filesystems * addition of compile-time option for responding to invocation via linked executables named "cryptumount", "cryptunmount" etc. * added support for GNU gettext, including French translations of manual pages and common messages * improved mechanisms for preventing unauthorized unmounting of filesystems It has been tested on the following systems: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * SuSE Linux 10.0 OSS (x86) * Mandriva Linux 2005 (x86) * FedoraCore-4 (x86) (may need extra configuration of security policies governing losetup, mke2fs etc) Summary of new features in cryptmount-0.4 ========================================= This (beta) release focuses on extensions in functionality and robustness, including: * addition of switches allowing filesystem mounting to be restricted only to superuser * addition of automatic filesystem checking (via fsck) prior to mounting * compile-time choice between in-built mount, or /bin/mount etc * addition of facility for unencrypted filesystem key (e.g. stored on removable device such as a USB key) It has been tested on the following systems: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * FedoraCore-4 (x86) (may need extra configuration of security policies governing losetup, mke2fs etc) * Mandriva Linux 2005 (x86) * SuSE Linux 10.0 OSS (x86) Summary of new features in cryptmount-0.3 ========================================= This (beta) release focuses on extensions in functionality and robustness, including: * addition of '--all' command-line option, for example to allow easier unmounting of all encrypted filing systems via 'cryptmount --unmount --all' * multiple targets can be specified on the command-line, for example for mounting multiple filing systems at the same time * support for loopback filingsystems >2GB has been improved * all mounting/unmounting activity is now recorded via syslog * security checks on the configuration file have been extended * improved documentation of password-changing & fsck tasks It has been tested on the following systems: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * FedoraCore-4 (x86) (may need extra configuration of security policies governing losetup, mke2fs etc) * Mandriva Linux 2005 (x86) * SuSE Linux 10.0 OSS (x86) Summary of new features in cryptmount-0.2 ========================================= This (beta) release focuses on extensions in functionality, including: * addition of optional configuration-file parameters for selecting a subset of blocks within a device for hosting the filing system * addition of optional configuration-file parameter for selecting a particular loopback device rather than having one chosen automatically * addition of optional cipher-IV parameter to configuration-file * improved detection of errors in the configuration-file * basic security checks performed on configuration-file and target-description before any privileged action is taken It has been tested on the following systems: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * FedoraCore-4 (x86) (may need extra configuration of security policies governing losetup, mke2fs etc) * Mandriva Linux 2005 (x86) * SuSE Linux 10.0 OSS (x86) Summary of new features in cryptmount-0.1 ========================================= This (beta) release focuses on improvements in robustness, portability and documentation, including: * improved support for systems with glibc built against kernel-2.4 headers * addition of mechanisms for updating /etc/mtab on (un)mounting filing systems, so the programs such as df can operate normally on filesystems controlled by cryptmount * clearer examples on usage within README & the cryptmount man-page (avoiding ambiguities about whether 'aes256', rather than 'aes', is a valid kernel-module name) It has been tested on the following systems: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * FedoraCore-4 (x86) (may need extra configuration of security policies governing losetup, mke2fs etc) * Mandriva Linux 2005 (x86) * SuSE Linux 10.0 OSS (x86) Summary of new features in cryptmount-0.0.3 =========================================== This (alpha) release further improves robustness, and portability including: * a bug which restricted protection of cipher-key to the Blowfish and md5 algorithms has been fixed, thereby allowing any cipher/hash supported by the openssl library to be used * differences in behaviour of libdevmapper which may or may not create device-nodes below /dev/mapper, have been allowed for * an automatic testing script has been written * improved detection of failure to decrypt the cipher-key has been added It has been tested on the following systems: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) * SuSE Linux 10.0 OSS (x86) Summary of new features in cryptmount-0.0.2 =========================================== This (alpha) release of cryptmount improves general robustness and documentation as follows: * a basic manual-page has been written * a locking mechanism has been added, to ensure that only the (non-root) user that mounted a filing system can unmount it * tidying-up of devices occurs if mounting fails It has been tested on the following system: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) Summary of features in cryptmount-0.0.1 ======================================= This initial (pre-alpha) release of cryptmount offers the following features: * support for all encryption algorithms supported by the kernel * encryption of cipher-key by Blowfish algorithm & md5 message-digest It has been tested on the following system: * Debian GNU/Linux 3.1 ("sarge") (x86, kernel-2.6) Acknowledgements ================ Please see the file 'AUTHORS' in the source package for a list of contributors. cryptmount-6.3.0/armour-builtin.c000066400000000000000000000350271465135467200171050ustar00rootroot00000000000000/* * Methods for encryption/security mechanisms for cryptmount * (C)Copyright 2007-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "armour.h" #include "blowfish.h" #include "cryptmount.h" #include "utils.h" #ifdef TESTING # include "cmtesting.h" #endif /*! \addtogroup keymgrs * @{ */ typedef struct { unsigned fversion; /*!< File-format version, default==1 since version 4.0 */ } blti_overrides_t; /* * ==== Built-in sha1/blowfish key-management routines ==== */ /* * Keyfile format is: * char magic[7]="cm-blti"; * uchar version; * uint16{LSB-first} keylength; * uint32{LSB-first} hash-iterations (version>=1); * char salt[kmblti_saltlen]; * [64-bit block][64-bit block][...]; * uint64{LSB-first} xor-checksum of key */ static const char kmblti_magstr[]="cm-blti"; static const uint8_t kmblti_version = (uint8_t)1; static const size_t kmblti_maglen = 7; /* = strlen(kmblti_magstr) */ enum { kmblti_saltlen = 10, kmblti_default_iterations = 1 << 14 }; static int kmblti_checkversion(uint8_t fversion) { if (fversion > kmblti_version) { fprintf(stderr, "Bad keyfile version [%d]\n", (int)fversion); return ERR_BADFILE; } return ERR_NOERROR; } static cm_bf_ctxt_t *kmblti_initcipher_v0(const uint8_t *salt, const char *pass, size_t passlen, uint32_t iv[2]) /** Initialize cipher key (for file-format version-0) */ { cm_bf_ctxt_t *ctxt; cm_sha1_ctxt_t *md; uint8_t *ckey = NULL; size_t ckeysz; int i; /* Generate cipher key by sha1-hashing password: */ md = cm_sha1_init(); for (i=16; i--; ) { cm_sha1_block(md, (const uint8_t*)pass, passlen); cm_sha1_block(md, salt, (size_t)kmblti_saltlen); } iv[0] = md->H[0]; iv[1] = md->H[3]; cm_sha1_block(md, salt, (size_t)kmblti_saltlen); cm_sha1_final(md, &ckey, &ckeysz); cm_sha1_free(md); /* Initialize Blowfish cipher with hashed password: */ ctxt = cm_bf_init(ckey, ckeysz); sec_free((void*)ckey); return ctxt; } static cm_bf_ctxt_t *kmblti_initcipher_v1(const uint8_t *salt, const char *pass, size_t passlen, uint32_t iterations, uint32_t iv[2]) /** Initialize cipher key (for file-format version-1) */ { cm_bf_ctxt_t *ctxt; uint8_t *ckey = NULL; const size_t ckeysz = 56; cm_pwd_fortify(pass, iterations, salt, (size_t)kmblti_saltlen, &ckey, ckeysz); iv[0] = pack_uint32(ckey + 48); iv[1] = pack_uint32(ckey + 52); /* Initialize Blowfish cipher with hashed password: */ ctxt = cm_bf_init(ckey, ckeysz - 8); sec_free((void*)ckey); return ctxt; } static int kmblti_init_algs(void) { /* Nothing needed */ return 0; } static int kmblti_free_algs(void) { /* Nothing needed */ return 0; } static int kmblti_bind(bound_tgtdefn_t *bound, FILE *fp_key) { keyinfo_t *keyinfo = &bound->tgt->key; const char *fmtptr; char buff[32]; int compat = 1; /* Be prepared to act as default key-manager */ if (keyinfo->format != NULL) { fmtptr = keyinfo->format; compat = cm_startswith(&fmtptr, "builtin"); if (*fmtptr == ':') { /* Extract file-format version from suffix: */ blti_overrides_t *bltior; bltior = (blti_overrides_t*)malloc(sizeof(blti_overrides_t)); bltior->fversion = atoi(fmtptr + 1); bound->km_data = (void*)bltior; } else if (*fmtptr != '\0') compat = 0; } else { if (fp_key != NULL) { /* Check header of existing key-file: */ buff[0] = '\0'; compat = (cm_fread((void*)buff, kmblti_maglen, fp_key) == 0 && strncmp(buff, kmblti_magstr, kmblti_maglen) == 0); } } if (compat) { if (keyinfo->digestalg == NULL) { keyinfo->digestalg = cm_strdup("sha1"); } if (keyinfo->cipheralg == NULL) { keyinfo->cipheralg = cm_strdup("blowfish-cbc"); } } return compat; } static unsigned kmblti_get_properties(const bound_tgtdefn_t *boundtgt) { return (KM_PROP_HASPASSWD | KM_PROP_NEEDSKEYFILE); } static int kmblti_get_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, uint8_t **key, int *keylen, FILE *fp_key) /** Extract key from sha1/blowfish encrypted file */ { const keyinfo_t *keyinfo = &boundtgt->tgt->key; cm_bf_ctxt_t *ctxt; enum { BUFFSZ = 512 }; uint8_t *hbuff = NULL, fversion, salt[kmblti_saltlen], *buff = NULL, *bptr; uint32_t iv[2], cv[2], pl[2], iterations = kmblti_default_iterations; char *passwd = NULL; uint32_t chksum, chksum0; int cnt, rd_errs=0, eflag=ERR_NOERROR; *key = NULL; *keylen = 0; eflag = km_get_passwd(boundtgt->tgt->ident, pw_ctxt, &passwd, 0, 0); if (eflag != ERR_NOERROR) goto bail_out; /* Read key header: */ hbuff = (uint8_t*)malloc((size_t)(kmblti_maglen + 4)); hbuff[0] = '\0'; rd_errs += cm_fread((void*)hbuff, kmblti_maglen, fp_key); if (strncmp((const char*)hbuff, kmblti_magstr, kmblti_maglen) != 0) { fprintf(stderr, "Bad keyfile format (builtin)\n"); eflag = ERR_BADFILE; goto bail_out; } rd_errs += cm_fread((void*)&fversion, (size_t)1, fp_key); eflag = kmblti_checkversion(fversion); if (eflag != ERR_NOERROR) goto bail_out; rd_errs += cm_fread((void*)hbuff, (size_t)2, fp_key); *keylen = pack_uint16(hbuff); /* Read iteration-count from keyfile: */ if (fversion == 1) { rd_errs += cm_fread((void*)hbuff, (size_t)4, fp_key); iterations = pack_uint32(hbuff); } /* Read salt from keyfile: */ rd_errs += cm_fread((void*)salt, sizeof(salt), fp_key); /* Read encrypted key from keyfile: */ switch (fversion) { case 0: ctxt = kmblti_initcipher_v0(salt, passwd, strlen(passwd), iv); break; case 1: /* Fall-through: */ default: ctxt = kmblti_initcipher_v1(salt, passwd, strlen(passwd), iterations, iv); break; } cnt = km_aug_keysz((unsigned)*keylen, 8u) / 8; buff = (uint8_t*)sec_realloc(buff, (size_t)(cnt * 8)); rd_errs += cm_fread((void*)buff, (size_t)(8 * cnt), fp_key); bptr = buff; while (cnt--) { cv[0] = pack_uint32(bptr+4); cv[1] = pack_uint32(bptr); /* Apply cipher block-chaining: */ pl[0] = cv[0]; pl[1] = cv[1]; cm_bf_decipher(ctxt, pl, pl+1); pl[0] ^= iv[0]; pl[1] ^= iv[1]; iv[0] = cv[0]; iv[1] = cv[1]; bptr[7] = (uint8_t)((pl[0] >> 24) & 0xff); bptr[6] = (uint8_t)((pl[0] >> 16) & 0xff); bptr[5] = (uint8_t)((pl[0] >> 8) & 0xff); bptr[4] = (uint8_t)(pl[0] & 0xff); bptr[3] = (uint8_t)((pl[1] >> 24) & 0xff); bptr[2] = (uint8_t)((pl[1] >> 16) & 0xff); bptr[1] = (uint8_t)((pl[1] >> 8) & 0xff); bptr[0] = (uint8_t)(pl[1] & 0xff); bptr += 8; } cm_bf_free(ctxt); /* Verify checksum: */ if (!km_aug_verify(buff, (unsigned)*keylen, &chksum0, &chksum)) { switch (pw_ctxt->debug_level) { case 0: fprintf(stderr, _("Password mismatch when extracting key\n")); break; case 1: /* fall through... */ default: fprintf(stderr, "Checksum mismatch in keyfile (builtin, %x != %x)\n", (unsigned)chksum, (unsigned)chksum0); break; } eflag = ERR_BADDECRYPT; } if (keyinfo->maxlen > 0 && *keylen > keyinfo->maxlen) { *keylen = keyinfo->maxlen; } *key = (uint8_t*)sec_realloc((void*)*key, (size_t)*keylen); memcpy(*key, buff, (size_t)*keylen); if (rd_errs > 0 || ferror(fp_key) != 0) { fprintf(stderr, _("Key-extraction failed for \"%s\"\n"), keyinfo->filename); eflag = ERR_BADFILE; } bail_out: if (buff != NULL) sec_free((void*)buff); if (passwd != NULL) sec_free((void*)passwd); if (hbuff != NULL) free((void*)hbuff); return eflag; } static int kmblti_put_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, const uint8_t *key, const int keylen, FILE *fp_key) /** Store key in sha1/blowfish encrypted file */ { cm_bf_ctxt_t *ctxt; uint8_t fversion, salt[kmblti_saltlen], hbuff[4], *buff=NULL, *bptr; uint32_t iv[2], cv[2], iterations = kmblti_default_iterations; char *passwd=NULL; size_t buffsz; blti_overrides_t *bltior=NULL; int cnt, wr_errs=0, eflag=ERR_NOERROR; eflag = km_get_passwd(boundtgt->tgt->ident, pw_ctxt, &passwd, 1, 1); if (eflag != ERR_NOERROR) goto bail_out; fversion = kmblti_version; if (boundtgt->km_data != NULL) { bltior = (blti_overrides_t*)boundtgt->km_data; fversion = bltior->fversion; } eflag = kmblti_checkversion(fversion); if (eflag != ERR_NOERROR) goto bail_out; /* Write key header: */ wr_errs += cm_fwrite((const void*)kmblti_magstr, kmblti_maglen, fp_key); wr_errs += cm_fwrite((const void*)&fversion, (size_t)1, fp_key); unpack_uint16(hbuff, (uint16_t)keylen); wr_errs += cm_fwrite((const void*)hbuff, (size_t)2, fp_key); /* Write iteration-count: */ if (fversion == 1) { unpack_uint32(hbuff, iterations); wr_errs += cm_fwrite((const void*)hbuff, (size_t)4, fp_key); } /* Generate salt & record in key-file: */ cm_generate_key(salt, sizeof(salt)); wr_errs += cm_fwrite((const void*)salt, sizeof(salt), fp_key); /* Augment key with simple checksum: */ buff = km_aug_key(key, (unsigned)keylen, 8u, &buffsz); /* Write encrypted key into keyfile: */ switch (fversion) { case 0: ctxt = kmblti_initcipher_v0(salt, passwd, strlen(passwd), iv); case 1: /* Fall-through: */ default: ctxt = kmblti_initcipher_v1(salt, passwd, strlen(passwd), iterations, iv); break; } cnt = buffsz / 8; bptr = buff; while (cnt--) { cv[0] = (((uint32_t)bptr[7]) << 24) | (((uint32_t)bptr[6]) << 16) | (((uint32_t)bptr[5]) << 8) | ((uint32_t)bptr[4]); cv[1] = (((uint32_t)bptr[3]) << 24) | (((uint32_t)bptr[2]) << 16) | (((uint32_t)bptr[1]) << 8) | ((uint32_t)bptr[0]); /* Apply cipher block-chaining: */ cv[0] ^= iv[0]; cv[1] ^= iv[1]; cm_bf_encipher(ctxt, cv, cv+1); iv[0] = cv[0]; iv[1] = cv[1]; bptr[7] = (uint8_t)((cv[0] >> 24) & 0xff); bptr[6] = (uint8_t)((cv[0] >> 16) & 0xff); bptr[5] = (uint8_t)((cv[0] >> 8) & 0xff); bptr[4] = (uint8_t)(cv[0] & 0xff); bptr[3] = (uint8_t)((cv[1] >> 24) & 0xff); bptr[2] = (uint8_t)((cv[1] >> 16) & 0xff); bptr[1] = (uint8_t)((cv[1] >> 8) & 0xff); bptr[0] = (uint8_t)(cv[1] & 0xff); bptr += 8; } wr_errs += cm_fwrite((const void*)buff, buffsz, fp_key); cm_bf_free(ctxt); if (wr_errs > 0 || ferror(fp_key) != 0) { fprintf(stderr, _("Failed to create new key file\n")); eflag = ERR_BADFILE; goto bail_out; } bail_out: if (buff != NULL) sec_free((void*)buff); if (passwd != NULL) sec_free((void*)passwd); return eflag; } /* * ==== Pure password based key-manager ==== */ static int kmpswd_init_algs(void) { /* Nothing needed */ return 0; } static int kmpswd_free_algs(void) { /* Nothing needed */ return 0; } static int kmpswd_bind(bound_tgtdefn_t *bound, FILE *fp_key) { keyinfo_t *keyinfo = &bound->tgt->key; int compat = 0; if (keyinfo->format != NULL) { compat = (strcmp(keyinfo->format, "password") == 0); } if (compat) { if (keyinfo->digestalg == NULL) { keyinfo->digestalg = cm_strdup("sha1"); } } return compat; } static unsigned kmpswd_get_properties(const bound_tgtdefn_t *boundtgt) { return (KM_PROP_HASPASSWD | KM_PROP_FIXEDLOC | KM_PROP_FORMATTED); } static int kmpswd_get_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, uint8_t **key, int *keylen, FILE *fp_key) { const keyinfo_t *keyinfo = &boundtgt->tgt->key; char *passwd=NULL; int eflag=ERR_NOERROR; const unsigned iterations = 1 << 14; eflag = km_get_passwd(boundtgt->tgt->ident, pw_ctxt, &passwd, 0, 0); if (eflag != ERR_NOERROR) goto bail_out; *keylen = (keyinfo->maxlen >= 0 ? keyinfo->maxlen : 16); cm_pwd_fortify(passwd, iterations, NULL, 16, key, (size_t)*keylen); /* { size_t pos; fprintf(stderr,"pass-key: 0x"); for (pos=0; pos<*keylen; ++pos) fprintf(stderr,"%02x",(unsigned)(*key)[pos]); fprintf(stderr,"\n"); } */ bail_out: if (passwd != NULL) sec_free((void*)passwd); return eflag; } static int kmpswd_put_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, const uint8_t *key, const int keylen, FILE *fp_key) { /* This operation isn't valid for a pure-password key */ return ERR_NOTSUPPORTED; } keymanager_t keymgr_pswd = { "password", 0, kmpswd_init_algs, kmpswd_free_algs, kmpswd_bind, kmpswd_get_properties, kmpswd_get_key, kmpswd_put_key, NULL #ifdef TESTING , NULL, NULL, 0 #endif }; keymanager_t keymgr_blti = { "builtin", 0, kmblti_init_algs, kmblti_free_algs, kmblti_bind, kmblti_get_properties, kmblti_get_key, kmblti_put_key, &keymgr_pswd #ifdef TESTING , NULL, NULL, CM_HASLEGACY #endif }; keymanager_t *kmblti_gethandle(void) { return &keymgr_blti; } /** @} */ /* * (C)Copyright 2007-2024, RW Penney */ cryptmount-6.3.0/armour-gcry.c000066400000000000000000000671121465135467200164030ustar00rootroot00000000000000/* * Methods for encryption/security mechanisms for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include "armour.h" #include "cryptmount.h" #include "utils.h" #ifdef TESTING # include "cmtesting.h" #endif /*! \addtogroup keymgrs * @{ */ /* * ==== libgcrypt key-management routines ==== */ #if HAVE_LIBGCRYPT # include /* * Keyfile format is: * char magic[7]="cm-gcry"; * char version; * uint16{LSB-first} cipher_blocklength, keylength; * char salt[kmgcry_saltlen]; * [block][block][block]; * (last block ends with uint32 xor-checksum of key * (post-padded with zeros to next 4-byte boundary), * post-padded with zeros to next cipher_blocklength boundary); */ const char kmgcry_magstr[]="cm-gcry", kmgcryossl_magstr[]="Salted__"; const char kmgcry_version = (char)0; static const size_t kmgcry_maglen = 7, /* = strlen(kmgcry_magstr) */ kmgcryossl_maglen = 8; enum { kmgcry_saltlen = 12, kmgcryossl_saltlen = 8 }; static struct kmgcry_mode { const char *name; unsigned mode; } kmgcry_modes[] = { { "aeswrap", GCRY_CIPHER_MODE_AESWRAP }, { "cbc", GCRY_CIPHER_MODE_CBC }, { "cfb", GCRY_CIPHER_MODE_CFB }, { "cfb8", GCRY_CIPHER_MODE_CFB8 }, { "ccm", GCRY_CIPHER_MODE_CCM }, { "ctr", GCRY_CIPHER_MODE_CTR }, { "ecb", GCRY_CIPHER_MODE_ECB }, { "gcm", GCRY_CIPHER_MODE_GCM }, { "ocb", GCRY_CIPHER_MODE_OCB }, { "ofb", GCRY_CIPHER_MODE_OFB }, { "poly1305", GCRY_CIPHER_MODE_POLY1305 }, #if GCRYPT_VERSION_NUMBER >= 0x010800 { "xts", GCRY_CIPHER_MODE_XTS }, #endif { NULL, GCRY_CIPHER_MODE_NONE } }; static void kmgcry_tx_algnames(const keyinfo_t *keyinfo, char **algstr, char **modestr, char **dgststr) /* Parse/translate algorithm string into cipher/mode/digest fields */ { char *buff=NULL, *pos; struct map_t { /* map OpenSSL name to libgcrypt name, if different */ const char *ssl_name, *gcy_name; } *mapent; struct map_t ctable[] = { { "aes-128", "aes" }, { "aes128", "aes" }, { "aes-192", "aes192" }, { "aes-256", "aes256" }, { "bf", "blowfish" }, { "camellia-128", "camellia128" }, { "camellia-192", "camellia192" }, { "camellia-256", "camellia256" }, { "cast", "cast5" }, { "des3", "3des" }, { NULL, NULL } }; struct map_t htable[] = { { "rmd160", "ripemd160" }, { NULL, NULL } }; const char *default_cipher="aes256", *default_mode="cbc", *default_hash="sha256"; *algstr = NULL; *modestr = NULL; *dgststr = NULL; if (keyinfo->cipheralg != NULL && keyinfo->cipheralg[0] != '\0') { buff = cm_strdup(keyinfo->cipheralg); /* Extract cipher-mode from trailing -[^-]* of cipher-name: */ pos = strrchr(buff, '-'); if (pos != NULL) { *modestr = cm_strdup(pos + 1); *pos = '\0'; } /* Translate cipher-name to canonical libgcrypt name: */ for (mapent=ctable; mapent->ssl_name!=NULL; ++mapent) { if (cm_strcasecmp(buff, mapent->ssl_name) == 0) { *algstr = cm_strdup(mapent->gcy_name); break; } } if (*algstr == NULL) { *algstr = buff; buff = NULL; } } if (*algstr == NULL) *algstr = cm_strdup(default_cipher); if (*modestr == NULL) *modestr = cm_strdup(default_mode); if (keyinfo->digestalg != NULL && keyinfo->digestalg[0] != '\0') { /* Translate digest-name to canonical libgcrypt name: */ for (mapent=htable; mapent->ssl_name!=NULL; ++mapent) { if (cm_strcasecmp(mapent->ssl_name, keyinfo->digestalg) == 0) { *dgststr = cm_strdup(mapent->gcy_name); break; } } if (*dgststr == NULL) *dgststr = cm_strdup(keyinfo->digestalg); } if (*dgststr == NULL) *dgststr = cm_strdup(default_hash); if (buff != NULL) free((void*)buff); } static int kmgcry_get_algos(const keyinfo_t *keyinfo, int *cipher, int *ciphermode, int *digest) /* Get libgcrypt algorithms for encoding key */ { char *algstr=NULL, *mdstr=NULL, *dgststr=NULL; struct kmgcry_mode *cmd; int eflag=ERR_NOERROR; kmgcry_tx_algnames(keyinfo, &algstr, &mdstr, &dgststr); *cipher = gcry_cipher_map_name(algstr); if (*cipher == 0) { fprintf(stderr, _("Couldn't find libgcrypt cipher \"%s\"\n"), algstr); eflag = ERR_BADALGORITHM; goto bail_out; } for (cmd=kmgcry_modes; cmd->name!=NULL; ++cmd) { if (cm_strcasecmp(cmd->name, mdstr) == 0) break; } if (cmd->name == NULL) { fprintf(stderr, _("Couldn't find libgcrypt cipher mode \"%s\" - using fallback\n"), mdstr); } *ciphermode = cmd->mode; *digest = gcry_md_map_name(dgststr); if (*digest == 0) { fprintf(stderr, _("Couldn't find libgcrypt digest \"%s\"\n"), dgststr); eflag = ERR_BADALGORITHM; goto bail_out; } bail_out: if (algstr != NULL) free((void*)algstr); if (mdstr != NULL) free((void*)mdstr); if (dgststr != NULL) free((void*)dgststr); return eflag; } # ifdef TESTING static int kmgcry_test_getalgos() { keyinfo_t keyinfo; int cipher=0, mode=0, digest=0, cnt; struct cmap { const char *cname, *dname; const int cipher, mode, digest; } *mapptr; struct cmap map[] = { { "aes-128-cfb", "ripemd160", GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB, GCRY_MD_RMD160 }, { "aes192-ECB", "md4", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB, GCRY_MD_MD4 }, { "bf-cbc", "rmd160", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, GCRY_MD_RMD160 }, { "CAST5-CFB", "ripemd160", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB, GCRY_MD_RMD160 }, { "Camellia-128-cfb8", "sha256", GCRY_CIPHER_CAMELLIA128, GCRY_CIPHER_MODE_CFB8, GCRY_MD_SHA256 }, #if GCRYPT_VERSION_NUMBER >= 0x010800 { "ChaCha20-xts", "blake2b_512", GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_XTS, GCRY_MD_BLAKE2B_512 }, #endif { "DES-ofb", "md5", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_OFB, GCRY_MD_MD5 }, { "twofish", "sha1", GCRY_CIPHER_TWOFISH, GCRY_CIPHER_MODE_CBC, GCRY_MD_SHA1 }, { NULL, NULL, -1, -1, -1 } }; CM_TEST_START("libgcrypt algorithm-identification"); keyinfo.cipheralg = NULL; keyinfo.digestalg = NULL; CM_ASSERT_EQUAL(ERR_NOERROR, kmgcry_get_algos(&keyinfo, &cipher, &mode, &digest)); CM_ASSERT_DIFFERENT(0, cipher); CM_ASSERT_DIFFERENT(0, mode); CM_ASSERT_DIFFERENT(0, digest); keyinfo.cipheralg = ""; keyinfo.digestalg = ""; CM_ASSERT_EQUAL(ERR_NOERROR, kmgcry_get_algos(&keyinfo, &cipher, &mode, &digest)); for (mapptr=map,cnt=0; mapptr->cipher!=-1; ++mapptr,++cnt) { keyinfo.cipheralg = (char*)mapptr->cname; keyinfo.digestalg = (char*)mapptr->dname; CM_ASSERT_EQUAL(ERR_NOERROR, kmgcry_get_algos(&keyinfo, &cipher, &mode, &digest)); CM_ASSERT_EQUAL(mapptr->cipher, cipher); CM_ASSERT_EQUAL(mapptr->mode, mode); CM_ASSERT_EQUAL(mapptr->digest, digest); } CM_ASSERT_DIFFERENT(0, cnt); CM_TEST_OK(); } # endif /* TESTING */ typedef void kmgcry_keybuilder_t(gcry_md_hd_t md, int digest, const size_t mdlen, const uint8_t *salt, const uint8_t *pass, const size_t passlen, uint8_t *ckey, const size_t ckeysz, uint8_t *civ, const size_t civsz); static void kmgcry_keybuilder(gcry_md_hd_t md_hand, int digest, const size_t mdlen, const uint8_t *salt, const uint8_t *pass, const size_t passlen, uint8_t *ckey, const size_t ckeysz, uint8_t *civ, const size_t civsz) /*! Generate cipher key & IV from password & salt (default variant) */ { size_t kpos, ivpos, pos; uint8_t *buff; kpos = ivpos = 0; do { /* Fold-together password & salt using message-digest: */ gcry_md_reset(md_hand); gcry_md_write(md_hand, (const void*)salt, (size_t)kmgcry_saltlen); gcry_md_write(md_hand, (const void*)pass, passlen); if (kpos > 0) { gcry_md_write(md_hand, (const void*)ckey, kpos); } if (ivpos > 0) { gcry_md_write(md_hand, (const void*)civ, ivpos); } buff = gcry_md_read(md_hand, digest); /* Transfer message digest into cipher key & initialization vector: */ pos = 0; while (kpos < ckeysz && pos < mdlen) { ckey[kpos++] = buff[pos++]; } while (ivpos < civsz && pos < mdlen) { civ[ivpos++] = buff[pos++]; } } while (kpos < ckeysz || ivpos < civsz); } static void kmgcryossl_keybuilder(gcry_md_hd_t md_hand, int digest, const size_t mdlen, const uint8_t *salt, const uint8_t *pass, const size_t passlen, uint8_t *ckey, const size_t ckeysz, uint8_t *civ, const size_t civsz) /*! Generate cipher key & IV from password & salt (a la OpenSSL) */ { size_t kpos, ivpos, pos; uint8_t *buff, *prev=NULL; unsigned cnt=0; prev = (uint8_t*)sec_realloc(prev, mdlen); kpos = ivpos = 0; do { /* Fold-together password & salt using message-digest: */ gcry_md_reset(md_hand); if (cnt > 0) { gcry_md_write(md_hand, (const void*)prev, mdlen); } gcry_md_write(md_hand, (const void*)pass, passlen); gcry_md_write(md_hand, (const void*)salt, kmgcryossl_saltlen); buff = gcry_md_read(md_hand, digest); /* Transfer message digest into cipher key & initialization vector: */ pos = 0; while (kpos < ckeysz && pos < mdlen) { ckey[kpos++] = buff[pos++]; } while (ivpos < civsz && pos < mdlen) { civ[ivpos++] = buff[pos++]; } /* Keep copy of digest to add to next fold: */ memcpy((void*)prev, (const void*)buff, mdlen); ++cnt; } while (kpos < ckeysz || ivpos < civsz); sec_free(prev); } static int kmgcry_initcipher(int cipher, int ciphermode, int digest, const uint8_t *salt, kmgcry_keybuilder_t keybuilder, const char *pass, size_t passlen, gcry_cipher_hd_t *hd) /*! Initialize block cipher from given password, salt & hashing scheme */ { gcry_md_hd_t md_hand; size_t ckeysz, cblksz, mdlen; uint8_t *ckey=NULL, *civ=NULL; int eflag=ERR_BADALGORITHM; if (gcry_cipher_open(hd, cipher, ciphermode, 0) != 0) { fprintf(stderr, "Cannot open libgcrypt cipher[%d,%d]\n", cipher, ciphermode); goto bail_out; } (void)gcry_cipher_algo_info(cipher, GCRYCTL_GET_KEYLEN, NULL, &ckeysz); ckey = (uint8_t*)sec_realloc(ckey, ckeysz); (void)gcry_cipher_algo_info(cipher, GCRYCTL_GET_BLKLEN, NULL, &cblksz); civ = (uint8_t*)sec_realloc(civ, cblksz); /* generate cipher key & iv by hashing password: */ if (keybuilder == NULL) keybuilder = kmgcry_keybuilder; if (gcry_md_open(&md_hand, digest, 0) != 0) { fprintf(stderr, "Cannot open libgcrypt digest[%d]\n", digest); goto bail_out; } mdlen = gcry_md_get_algo_dlen(digest); keybuilder(md_hand, digest, mdlen, salt, (const uint8_t*)pass, passlen, ckey, ckeysz, civ, cblksz); gcry_md_close(md_hand); /* setup cipher initial state: */ if (gcry_cipher_setkey(*hd, (void*)ckey, ckeysz) != 0 || gcry_cipher_setiv(*hd, (void*)civ, cblksz) != 0) { fprintf(stderr, "Failed to setup libgcrypt cipher iv[%d,%d]\n", (int)ckeysz, (int)cblksz); goto bail_out; } sec_free(ckey); sec_free(civ); eflag = ERR_NOERROR; bail_out: return eflag; } static int kmgcry_init_algs() { if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { (void)gcry_check_version(NULL); /* Initializes library as side-effect */ (void)gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } return 0; } static int kmgcry_free_algs() { /* Nothing needed */ return 0; } static int kmgcry_bind(bound_tgtdefn_t *bound, FILE *fp_key) { keyinfo_t *keyinfo = &bound->tgt->key; char buff[32]; int compat = 0; if (keyinfo->format != NULL) { compat = (strcmp(keyinfo->format, "libgcrypt") == 0); } else { if (fp_key != NULL) { /* Check header of existing key-file: */ compat = (cm_fread((void*)buff, kmgcry_maglen, fp_key) == 0 && strncmp(buff, kmgcry_magstr, kmgcry_maglen) == 0); } } if (compat) { if (keyinfo->digestalg == NULL) { keyinfo->digestalg = cm_strdup("sha256"); } if (keyinfo->cipheralg == NULL) { #if GCRYPT_VERSION_NUMBER >= 0x010800 keyinfo->cipheralg = cm_strdup("aes256-xts"); #else keyinfo->cipheralg = cm_strdup("aes256-cbc"); #endif } } return compat; } static int kmgcryossl_bind(bound_tgtdefn_t *bound, FILE *fp_key) /*! OpenSSL-compatibility version of kmgcy_bind */ { keyinfo_t *keyinfo = &bound->tgt->key; char buff[32]; int compat = 0; if (keyinfo->format != NULL) { compat |= (strcmp(keyinfo->format, "openssl-compat") == 0); compat |= (strcmp(keyinfo->format, "openssl") == 0); } else { if (fp_key != NULL) { /* Check header of existing key-file: */ compat = (cm_fread((void*)buff, kmgcryossl_maglen, fp_key) == 0 && strncmp(buff, kmgcryossl_magstr, kmgcryossl_maglen) == 0); } } if (compat) { if (keyinfo->digestalg == NULL) { keyinfo->digestalg = cm_strdup("md5"); } if (keyinfo->cipheralg == NULL) { keyinfo->cipheralg = cm_strdup("blowfish"); } } return compat; } static unsigned kmgcry_get_properties(const bound_tgtdefn_t *boundtgt) { return (KM_PROP_HASPASSWD | KM_PROP_NEEDSKEYFILE); } static int kmgcry_get_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, uint8_t **key, int *keylen, FILE *fp_key) /*! Extract key from libgcrypt-encrypted file */ { const keyinfo_t *keyinfo = &boundtgt->tgt->key; gcry_cipher_hd_t chd; char *passwd=NULL; uint8_t *hbuff = NULL, salt[kmgcry_saltlen], *buff = NULL, *bptr; size_t cblksz; uint32_t chksum, chksum0; int cnt, rd_errs=0, cipher, ciphermode, digest, eflag=ERR_NOERROR; *key = NULL; *keylen = 0; hbuff = (uint8_t*)sec_realloc(hbuff, (kmgcry_maglen + 4)); eflag = kmgcry_get_algos(keyinfo, &cipher, &ciphermode, &digest); if (eflag != ERR_NOERROR) goto bail_out; gcry_cipher_algo_info(cipher, GCRYCTL_GET_BLKLEN, NULL, &cblksz); eflag = km_get_passwd(boundtgt->tgt->ident, pw_ctxt, &passwd, 0, 0); if (eflag != ERR_NOERROR) goto bail_out; /* Read key header: */ rd_errs += cm_fread((void*)hbuff, kmgcry_maglen, fp_key); if (strncmp((const char*)hbuff, kmgcry_magstr, kmgcry_maglen) != 0) { fprintf(stderr, _("Bad keyfile format (libgcrypt)\n")); eflag = ERR_BADFILE; goto bail_out; } rd_errs += cm_fread((void*)hbuff, (size_t)1, fp_key); if (hbuff[0] != '\0') { fprintf(stderr, "Bad keyfile version [%d]\n", (int)buff[0]); eflag = ERR_BADFILE; goto bail_out; } rd_errs += cm_fread((void*)hbuff, (size_t)4, fp_key); if (pack_uint16(hbuff) != cblksz) { fprintf(stderr, "Mismatched cipher block size\n"); eflag = ERR_BADFILE; goto bail_out; } *keylen = pack_uint16(hbuff + 2); /* Read salt from keyfile: */ rd_errs += cm_fread((void*)salt, sizeof(salt), fp_key); /* Read encrypted key from keyfile: */ eflag = kmgcry_initcipher(cipher, ciphermode, digest, salt, NULL, passwd, strlen(passwd), &chd); if (eflag != ERR_NOERROR) goto bail_out; cnt = km_aug_keysz((unsigned)*keylen, (unsigned)cblksz) / cblksz; buff = (uint8_t*)sec_realloc(buff, cnt * cblksz); bptr = buff; while (cnt--) { rd_errs += cm_fread((void*)bptr, cblksz, fp_key); gcry_cipher_decrypt(chd, (void*)bptr, cblksz, NULL, 0); bptr += cblksz; } gcry_cipher_close(chd); /* Verify checksum: */ if (!km_aug_verify(buff, (unsigned)*keylen, &chksum0, &chksum)) { switch (pw_ctxt->debug_level) { case 0: fprintf(stderr, _("Password mismatch when extracting key\n")); break; case 1: /* fall through... */ default: fprintf(stderr, _("Checksum mismatch in keyfile (gcry, %x != %x)\n"), (unsigned)chksum, (unsigned)chksum0); break; } eflag = ERR_BADDECRYPT; } if (keyinfo->maxlen > 0 && *keylen > keyinfo->maxlen) { *keylen = keyinfo->maxlen; } *key = (uint8_t*)sec_realloc((void*)*key, (size_t)*keylen); memcpy(*key, buff, (size_t)*keylen); if (rd_errs > 0 || ferror(fp_key) != 0) { fprintf(stderr, _("Key-extraction failed for \"%s\"\n"), keyinfo->filename); eflag = ERR_BADFILE; } bail_out: if (buff != NULL) sec_free((void*)buff); if (passwd != NULL) sec_free((void*)passwd); if (hbuff != NULL) sec_free((void*)hbuff); return eflag; } static int kmgcry_put_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, const uint8_t *key, const int keylen, FILE *fp_key) /*! Store key in libgcrypt-encrypted file */ { const keyinfo_t *keyinfo = &boundtgt->tgt->key; gcry_cipher_hd_t chd; char *passwd=NULL; uint8_t hbuff[4], salt[kmgcry_saltlen], *buff=NULL, *bptr; size_t buffsz, cblksz; int cnt, wr_errs = 0, cipher, ciphermode, digest, eflag=ERR_NOERROR; eflag = kmgcry_get_algos(keyinfo, &cipher, &ciphermode, &digest); if (eflag != ERR_NOERROR) goto bail_out; gcry_cipher_algo_info(cipher, GCRYCTL_GET_BLKLEN, NULL, &cblksz); eflag = km_get_passwd(boundtgt->tgt->ident, pw_ctxt, &passwd, 1, 1); if (eflag != ERR_NOERROR) goto bail_out; /* Write key header: */ wr_errs += cm_fwrite((const void*)kmgcry_magstr, kmgcry_maglen, fp_key); wr_errs += cm_fwrite((const void*)&kmgcry_version, (size_t)1, fp_key); unpack_uint16(hbuff, (uint16_t)cblksz); unpack_uint16(hbuff + 2, (uint16_t)keylen); wr_errs += cm_fwrite((const void*)hbuff, (size_t)4, fp_key); /* Generate salt & record in keyfile: */ cm_generate_key(salt, sizeof(salt)); wr_errs += cm_fwrite((const void*)salt, sizeof(salt), fp_key); /* Augment key with simple checksum: */ buff = km_aug_key(key, (unsigned)keylen, (unsigned)cblksz, &buffsz); /* Write encrypted key into keyfile: */ eflag = kmgcry_initcipher(cipher, ciphermode, digest, salt, NULL, passwd, strlen(passwd), &chd); if (eflag != ERR_NOERROR) goto bail_out; cnt = buffsz / cblksz; bptr = buff; while (cnt--) { gcry_cipher_encrypt(chd, (void*)bptr, cblksz, NULL, 0); wr_errs += cm_fwrite((const void*)bptr, cblksz, fp_key); bptr += cblksz; } gcry_cipher_close(chd); if (wr_errs > 0 || ferror(fp_key) != 0) { fprintf(stderr, _("Failed to create new key file\n")); eflag = ERR_BADFILE; goto bail_out; } bail_out: if (buff != NULL) sec_free((void*)buff); if (passwd != NULL) sec_free((void*)passwd); return eflag; } #if USE_GCRYOSSL static int kmgcryossl_get_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, uint8_t **key, int *keylen, FILE *fp_key) /*! Extract key from OpenSSL-compatible file via libgcrypt */ { const keyinfo_t *keyinfo = &boundtgt->tgt->key; gcry_cipher_hd_t chd; char *passwd=NULL; uint8_t *hbuff=NULL, salt[kmgcryossl_saltlen], *buff=NULL; size_t cblksz, buffsz=0, pos, ofs, idx; int kbad=0, cipher, ciphermode, digest, rd_errs=0, eflag=ERR_NOERROR; *key = NULL; *keylen = 0; hbuff = (uint8_t*)sec_realloc(hbuff, kmgcryossl_maglen); eflag = kmgcry_get_algos(keyinfo, &cipher, &ciphermode, &digest); if (eflag != ERR_NOERROR) goto bail_out; gcry_cipher_algo_info(cipher, GCRYCTL_GET_BLKLEN, NULL, &cblksz); eflag = km_get_passwd(boundtgt->tgt->ident, pw_ctxt, &passwd, 0, 0); if (eflag != ERR_NOERROR) goto bail_out; /* Read key header: */ rd_errs += cm_fread((void*)hbuff, kmgcryossl_maglen, fp_key); if (strncmp((const char*)hbuff, kmgcryossl_magstr, kmgcryossl_maglen) != 0) { fprintf(stderr, _("Bad keyfile format (openssl-compat)\n")); eflag = ERR_BADFILE; goto bail_out; } /* Read salt from keyfile: */ rd_errs += cm_fread((void*)salt, sizeof(salt), fp_key); /* read encrypted key from keyfile: */ eflag = kmgcry_initcipher(cipher, ciphermode, digest, salt, kmgcryossl_keybuilder, passwd, strlen(passwd), &chd); if (eflag != ERR_NOERROR) goto bail_out; pos = 0; while (!feof(fp_key)) { if ((pos + cblksz) > buffsz) { buffsz = (buffsz * 2) + 4 * cblksz; buff = (uint8_t*)sec_realloc(buff, buffsz); } if (cm_fread((void*)(buff + pos), cblksz, fp_key) != 0) break; gcry_cipher_decrypt(chd, (void*)(buff + pos), cblksz, NULL, 0); pos += cblksz; } gcry_cipher_close(chd); /* Remove & check end-marker from key-data: */ ofs = 0; idx = 0; kbad = 0; if (pos > 0) ofs = buff[pos - 1]; else kbad |= 1; if (ofs > cblksz) kbad |= 1; while (idx < ofs && !kbad) { kbad |= (buff[--pos] != ofs); ++idx; } if (kbad) { switch (pw_ctxt->debug_level) { case 0: fprintf(stderr, _("Password mismatch when extracting key\n")); break; case 1: /* fall through... */ default: fprintf(stderr, _("Checksum mismatch in keyfile (openssl-compat, ofs=%u,idx=%u)\n"), (unsigned)ofs, (unsigned)idx); break; } eflag = ERR_BADDECRYPT; } *keylen = pos; if (keyinfo->maxlen > 0 && *keylen > keyinfo->maxlen) { *keylen = keyinfo->maxlen; } *key = (uint8_t*)sec_realloc((void*)*key, (size_t)*keylen); memcpy(*key, buff, (size_t)*keylen); if (rd_errs > 0 || ferror(fp_key) != 0) { fprintf(stderr, _("Key-extraction failed for \"%s\"\n"), keyinfo->filename); eflag = ERR_BADFILE; } bail_out: if (buff != NULL) sec_free((void*)buff); if (passwd != NULL) sec_free((void*)passwd); if (hbuff != NULL) sec_free((void*)hbuff); return eflag; } static int kmgcryossl_put_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, const uint8_t *key, const int keylen, FILE *fp_key) /*! Store key in OpenSSL-compatible file via libgcrypt */ { const keyinfo_t *keyinfo = &boundtgt->tgt->key; gcry_cipher_hd_t chd; char *passwd = NULL; uint8_t salt[kmgcryossl_saltlen], *buff = NULL; size_t buffsz, cblksz, pos; int wr_errs=0, cipher, ciphermode, digest, eflag=ERR_NOERROR; eflag = kmgcry_get_algos(keyinfo, &cipher, &ciphermode, &digest); if (eflag != ERR_NOERROR) goto bail_out; gcry_cipher_algo_info(cipher, GCRYCTL_GET_BLKLEN, NULL, &cblksz); eflag = km_get_passwd(boundtgt->tgt->ident, pw_ctxt, &passwd, 1, 1); if (eflag != ERR_NOERROR) goto bail_out; /* Write key header: */ wr_errs += cm_fwrite((const void*)kmgcryossl_magstr, kmgcryossl_maglen, fp_key); /* Generate salt & record in keyfile: */ cm_generate_key(salt, sizeof(salt)); wr_errs += cm_fwrite((const void*)salt, sizeof(salt), fp_key); /* Pad key-data with end-marker: */ buffsz = cblksz * ((keylen + cblksz) / cblksz); buff = (uint8_t*)sec_realloc(buff, buffsz); memcpy((void*)buff, (const void*)key, (size_t)keylen); for (pos=keylen; pos 0 || ferror(fp_key) != 0) { fprintf(stderr, _("Failed to create new key file\n")); eflag = ERR_BADFILE; goto bail_out; } bail_out: if (buff != NULL) sec_free((void*)buff); if (passwd != NULL) sec_free((void*)passwd); return eflag; } #endif /* USE_GCRYOSSL */ # ifdef TESTING static int kmgcry_test_hash() { gcry_md_hd_t mdcontext; int algo; uint8_t *mdval = NULL; size_t mdlen, i; unsigned q; const char *str = "noisy\n"; const char *hash = "7c1c9261fa774475ec1c0d887eaf00c19b0eb218"; CM_TEST_START("libgcrypt hashing"); gcry_md_open(&mdcontext, GCRY_MD_SHA1, 0); gcry_md_write(mdcontext, (const void*)str, strlen(str)); gcry_md_final(mdcontext); algo = gcry_md_get_algo(mdcontext); mdlen = gcry_md_get_algo_dlen(algo); mdval = gcry_md_read(mdcontext, algo); CM_ASSERT_DIFFERENT(NULL, mdval); CM_ASSERT_EQUAL(strlen(hash)/2, mdlen); for (i=0; i #include #include #include #include #include #include "armour.h" #include "cryptmount.h" #include "dmutils.h" #include "utils.h" #ifdef TESTING # include "cmtesting.h" #endif /*! \addtogroup keymgrs * @{ */ #ifndef GCRYPT_REQ_VERSION # define GCRYPT_REQ_VERSION "1.1.42" #endif typedef struct { unsigned keyslot; } luks_overrides_t; /* * ==== LUKS key-management routines ==== */ #if USE_LUKSCOMPAT # include # include static int kmluks_hdrvalid(FILE *fp_key) /* Check whether a valid LUKS header is present */ { const uint8_t luks_magic[] = { 'L','U','K','S', 0xba, 0xbe }; const size_t magic_len = sizeof(luks_magic); char buff[32]; int flg = 0; if (fp_key == NULL) return 0; if (cm_fread((void*)buff, magic_len, fp_key) == 0) { fseek(fp_key, -((long)magic_len), SEEK_CUR); flg = (strncmp(buff, (const char*)luks_magic, (size_t)magic_len) == 0); } return flg; } static void kmluks_splitmode(const char *fullname, char **cipher, char **mode) /* Split fully-qualified cipher name into algorithm + mode */ { size_t divpos=0, nlen=0; const char *pos=fullname; if (*cipher != NULL) free((void*)*cipher); if (*mode != NULL) free((void*)*mode); *cipher = *mode = NULL; if (fullname != NULL) { /* Split name according to 'ALGO-MODE' pattern: */ while (*pos != '\0' && *pos != '-') { ++pos; ++nlen; } divpos = nlen; while (*pos != '\0') { ++pos; ++nlen; } if (divpos > 0) { *cipher = (char*)malloc(divpos + 1); strncpy(*cipher, fullname, divpos); (*cipher)[divpos] = '\0'; } if (divpos < nlen) { *mode = (char*)malloc((nlen - divpos)); strcpy(*mode, fullname + divpos + 1); } } if (*cipher == NULL) *cipher = cm_strdup("aes"); if (*mode == NULL) *mode = cm_strdup("cbc-plain"); } static int kmluks_init_algs() { static int done_secmem = 0; int flg = 0; if (!done_secmem || !gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { if (!gcry_check_version(GCRYPT_REQ_VERSION)) return -1; /* Disable gcrypt secure-memory initialization as cryptmount makes * its own arrangements for locking pages in memory. * gcrypt secmem facilities will also drop setuid privileges, * which would conflict with device-mapper system calls * within cryptmount */ (void)gcry_control(GCRYCTL_DISABLE_SECMEM); (void)gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); done_secmem = 1; } return flg; } static int kmluks_free_algs() { /* Nothing needed */ return 0; } static int kmluks_bind(bound_tgtdefn_t *bound, FILE *fp_key) { int compat = 0; if (bound->tgt->key.format != NULL) { compat = (strcmp(bound->tgt->key.format, "luks") == 0); } else { /* Check header of existing key-file: */ compat |= kmluks_hdrvalid(fp_key); } if (compat) { tgtdefn_t *tgt = bound->tgt; if (tgt->key.filename == NULL && tgt->dev != NULL) { tgt->key.filename = cm_strdup(tgt->dev); } if (tgt->key.digestalg == NULL) { tgt->key.digestalg = cm_strdup("sha1"); } if (tgt->key.cipheralg == NULL) { tgt->key.cipheralg = cm_strdup("aes128"); } } return compat; } static unsigned kmluks_get_properties(const bound_tgtdefn_t *boundtgt) { unsigned props; FILE *fp; props = KM_PROP_HASPASSWD | KM_PROP_FIXEDLOC; fp = fopen(boundtgt->tgt->key.filename, "rb"); if (fp != NULL) { if (kmluks_hdrvalid(fp)) { props |= KM_PROP_FORMATTED; } fclose(fp); } return props; } /*! @brief Change UID to match EUID when mounting via loopback device * * This is a workaround for recent versions of libcryptsetup * (since January 2017), which check that both uid==0 and euid==0 * before attempting to create a loopback device * for a filesystem in an ordinary file. Setting up the loopback * device usually only requires euid==0. * * For filesystems in ordinary block devices, this function has no effect. * Otherwise, this will call setuid() to attempt to make uid==euid==0, * which appears to be an irreversible change, so will persist * across any other actions taken by cryptmount within the same process. * * @returns The previous value of UID. */ static uid_t luks_patch_uid(const bound_tgtdefn_t* boundtgt) { const uid_t olduid = getuid(); const char* filename = boundtgt->tgt->key.filename; struct stat sbuff; if (stat(filename, &sbuff) == 0 && S_ISREG(sbuff.st_mode)) { if (setuid(geteuid()) != 0) { fprintf(stderr, _("Failed to acquire privileges for LUKS container\n")); } } return olduid; } /*! @brief Change the password associated with a given LUKS key-slot. * * This will either create an entirely new keyslot with the given password, * or attempt to change the password associated with a particular keyslot * while taking a temporary backup of the key in that slot. This requires * that there is at least one spare keyslot available to take that backup. * * @param key The volume key for the LUKS device * @param keyslot Either CRYPT_ANY_SLOT or a nominated slot. * * @return The slot associated with the new password. */ int kmluks_change_slot_passwd(struct crypt_device *cd, int keyslot, const uint8_t *key, const int keylen, const char *passwd) { const size_t passwdlen = strlen(passwd); int new_slot = -1, bckp_slot = -1, r; char logmsg[256]; if (keyslot != CRYPT_ANY_SLOT) { bckp_slot = crypt_keyslot_add_by_volume_key(cd, CRYPT_ANY_SLOT, (const char*)key, keylen, passwd, passwdlen); if (bckp_slot < 0) return bckp_slot; r = crypt_keyslot_destroy(cd, keyslot); if (r < 0) return r; sprintf(logmsg, "kmluks created keyslot backup %d -> %d", keyslot, bckp_slot); crypt_log(cd, CRYPT_LOG_NORMAL, logmsg); } new_slot = crypt_keyslot_add_by_volume_key(cd, keyslot, (const char*)key, keylen, passwd, passwdlen); if (new_slot < 0) return new_slot; sprintf(logmsg, "kmluks added keyslot %d", new_slot); crypt_log(cd, CRYPT_LOG_NORMAL, logmsg); if (keyslot != CRYPT_ANY_SLOT && bckp_slot >= 0 && bckp_slot != new_slot) { crypt_keyslot_destroy(cd, bckp_slot); sprintf(logmsg, "kmluks removed keyslot backup %d", bckp_slot); crypt_log(cd, CRYPT_LOG_NORMAL, logmsg); } return new_slot; } void kmluks_log(int level, const char *msg, void *data) /*! stderr-based logging function for libcryptsetup */ { fprintf(stderr, "LUKS[%d] - %s\n", level, msg); } static int kmluks_get_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, uint8_t **key, int *keylen, FILE *fp_key) /*! Extract key from LUKS header file */ { tgtdefn_t *tgt = boundtgt->tgt; char *passwd = NULL, label[256]; struct crypt_device *luks_ctxt = NULL; int slot = -1, eflag = ERR_NOERROR; luks_overrides_t *luksor; int64_t delta; size_t lcs_keylen = 256; const size_t namesz = 128; /* This is vulnerable to permission-issues created by libgcrypt * -- see http://code.google.com/p/cryptsetup/issues/detail?id=47, * which are mitigated by kmluks_init_algs(). */ luks_patch_uid(boundtgt); snprintf(label, sizeof(label), "cm-luks-tmp-%d-%x", getpid(), (unsigned)(size_t)tgt); eflag = km_get_passwd(tgt->ident, pw_ctxt, &passwd, 0, 0); if (eflag != ERR_NOERROR) goto bail_out; if (crypt_init(&luks_ctxt, tgt->key.filename) < 0 || crypt_load(luks_ctxt, NULL, NULL) < 0) { fprintf(stderr, _("Failed to initialize device for LUKS keyfile\n")); eflag = ERR_BADDECRYPT; goto bail_out; } //crypt_set_log_callback(luks_ctxt, kmluks_log, NULL); // FIXME - remove soon slot = crypt_activate_by_passphrase(luks_ctxt, label, CRYPT_ANY_SLOT, passwd, strlen(passwd), CRYPT_ACTIVATE_READONLY); if (slot < 0) { fprintf(stderr, _("Failed to extract LUKS key for \"%s\" (errno=%d)\n"), tgt->ident, -slot); eflag = ERR_BADDECRYPT; goto bail_out; } /* Extract cipher-algorithm parameters from LUKS header: */ delta = (crypt_get_data_offset(luks_ctxt) - tgt->start); if (delta >= 0) { tgt->start += delta; if (tgt->length >= 0) tgt->length -= delta; } if (tgt->cipher != NULL) free((void*)tgt->cipher); tgt->cipher = (char*)malloc(namesz); snprintf(tgt->cipher, namesz, "%s-%s", crypt_get_cipher(luks_ctxt), crypt_get_cipher_mode(luks_ctxt)); tgt->ivoffset = crypt_get_iv_offset(luks_ctxt); if (boundtgt->km_data != NULL) free((void*)boundtgt->km_data); luksor = (luks_overrides_t*)malloc(sizeof(luks_overrides_t)); luksor->keyslot = slot; boundtgt->km_data = (void*)luksor; /* Take copy of LUKS master-key: */ *key = (uint8_t*)sec_realloc((void*)*key, lcs_keylen); crypt_volume_key_get(luks_ctxt, slot, (char*)*key, &lcs_keylen, passwd, strlen(passwd)); *keylen = lcs_keylen; bail_out: crypt_deactivate(luks_ctxt, label); crypt_free(luks_ctxt); await_devmap(label, 0, 5000); if (passwd != NULL) sec_free((void*)passwd); return eflag; } static int kmluks_put_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, const uint8_t *key, const int keylen, FILE *fp_key) /** Store or create key in LUKS header */ { const keyinfo_t *keyinfo = &boundtgt->tgt->key; char *passwd = NULL, *ciphername = NULL, *ciphermode = NULL; struct crypt_device *luks_ctxt = NULL; unsigned keyslot = 0; luks_overrides_t *luksor = NULL; int formatting = 0, r, eflag = ERR_NOERROR; formatting = (boundtgt->km_data == NULL) && !kmluks_hdrvalid(fp_key); if (boundtgt->km_data != NULL) { luksor = (luks_overrides_t*)boundtgt->km_data; } if (formatting) { #ifndef TESTING char msgbuff[1024]; snprintf(msgbuff, sizeof(msgbuff), _("Formatting \"%s\", will probably destroy all existing data"), keyinfo->filename); if (!cm_confirm(msgbuff)) { eflag = ERR_ABORT; goto bail_out; } #endif /* !TESTING */ } eflag = km_get_passwd(boundtgt->tgt->ident, pw_ctxt, &passwd, 1, 1); if (eflag != ERR_NOERROR) goto bail_out; if (crypt_init(&luks_ctxt, keyinfo->filename) < 0) { fprintf(stderr, _("Failed to initialize device for LUKS keyfile\n")); eflag = ERR_BADDECRYPT; goto bail_out; } //crypt_set_log_callback(luks_ctxt, kmluks_log, NULL); // FIXME - remove soon if (formatting) { struct crypt_params_luks1 luks_params = { boundtgt->tgt->key.digestalg, 0, NULL }; kmluks_splitmode(boundtgt->tgt->cipher, &ciphername, &ciphermode); r = crypt_format(luks_ctxt, CRYPT_LUKS1, ciphername, ciphermode, NULL, (const char*)key, keylen, &luks_params); if (r < 0) { fprintf(stderr, _("Failed to create LUKS header for \"%s\"\n"), boundtgt->tgt->ident); eflag = ERR_BADDEVICE; goto bail_out; } r = crypt_keyslot_add_by_volume_key(luks_ctxt, 0, (const char*)key, keylen, passwd, strlen(passwd)); if (r < 0) { fprintf(stderr, _("Failed to create LUKS key for \"%s\"\n"), boundtgt->tgt->ident); } } else { int lukserr = 0; keyslot = (luksor != NULL ? luksor->keyslot : 0); if (crypt_load(luks_ctxt, NULL, NULL) < 0) { eflag = ERR_BADDEVICE; goto bail_out; } printf(_("Setting password on LUKS keyslot-%u\n"), keyslot); lukserr = kmluks_change_slot_passwd(luks_ctxt, keyslot, key, keylen, passwd); if (lukserr < 0) { fprintf(stderr, "LUKS error code %d\n", -lukserr); eflag = ERR_BADENCRYPT; goto bail_out; } } bail_out: crypt_free(luks_ctxt); if (passwd != NULL) sec_free((void*)passwd); if (ciphername != NULL) free((void*)ciphername); if (ciphermode != NULL) free((void*)ciphermode); await_devmap(boundtgt->tgt->ident, 0, 5000); return eflag; } # ifdef TESTING static int kmluks_test_modesplit() { struct tcase { const char *orig, *cipher, *mode; }; struct tcase tcases[] = { { "", "aes", "cbc-plain" }, { "nothing", "nothing", "cbc-plain" }, { "alg-mode", "alg", "mode" }, { "blowfish-cfb-essiv", "blowfish", "cfb-essiv" }, { "-mode:suffix", "aes", "mode:suffix" }, { NULL, "aes", "cbc-plain" } }; char *head=NULL, *tail=NULL; unsigned idx, cnt; CM_TEST_START("LUKS cipher-mode parsing"); cnt = sizeof(tcases) / sizeof(struct tcase); for (idx=0; idx #include #include #include #include #include #include #include #include #include #include #include "armour.h" #include "cryptmount.h" #include "tables.h" #include "utils.h" #ifdef TESTING # include # include # include "cmtesting.h" #endif /*! \addtogroup keymgrs * @{ */ keymanager_t *kmblti_gethandle(void); keymanager_t *kmgcry_gethandle(void); keymanager_t *kmluks_gethandle(void); keymanager_t *init_keymanager(keymanager_t *km); /* List of all available key-managers (to be constructed later): */ static keymanager_t *keymgrs = NULL; /* * ==== Raw key-management routines ==== */ static int kmraw_init_algs(void) { return 0; } static int kmraw_free_algs(void) { return 0; } static int kmraw_bind(bound_tgtdefn_t *bound, FILE *fp_key) { keyinfo_t *keyinfo = &bound->tgt->key; int compat = 0; if (keyinfo->format != NULL) { compat = (strcmp(keyinfo->format, "raw") == 0); } else { if (keyinfo->cipheralg != NULL) { return (strcmp(keyinfo->cipheralg, "none") == 0); } } if (compat) { if (keyinfo->digestalg == NULL) { keyinfo->digestalg = cm_strdup("none"); } if (keyinfo->cipheralg == NULL) { keyinfo->cipheralg = cm_strdup("none"); } } return compat; } static unsigned kmraw_get_properties(const bound_tgtdefn_t *boundtgt) { struct stat sbuff; unsigned props; /* We must flag that we have no password & have fixed location, otherwise keyfile=/dev/random could be renamed on password-changing! */ props = KM_PROP_NEEDSKEYFILE | KM_PROP_FIXEDLOC; if (stat(boundtgt->tgt->key.filename, &sbuff) == 0) { props |= KM_PROP_FORMATTED; } return props; } static int kmraw_get_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, uint8_t **key, int *keylen, FILE *fp_key) /** Extract key from unencrypted (plain) file */ { const keyinfo_t *keyinfo = &boundtgt->tgt->key; enum { BUFFSZ=512 }; char buff[BUFFSZ]; size_t len, lmt; int eflag=ERR_NOERROR; *key = NULL; *keylen = 0; if (fp_key == NULL) { eflag = ERR_BADFILE; goto bail_out; } /* Read data directly from keyfile: */ for (;;) { lmt = (keyinfo->maxlen > 0 && (*keylen + BUFFSZ) > keyinfo->maxlen ? (size_t)(keyinfo->maxlen - *keylen) : (size_t)BUFFSZ); len = fread((void*)buff, (size_t)1, (size_t)lmt, fp_key); if (len == 0) break; /* Copy new block of data onto end of current key: */ *key = (uint8_t*)sec_realloc((void*)*key, (size_t)(*keylen+len)); memcpy((void*)(*key + *keylen), (const void*)buff, len); *keylen += len; } if (ferror(fp_key) != 0) { fprintf(stderr, _("Key-extraction failed for \"%s\"\n"), keyinfo->filename); /* This is a trivial case of decryption failure: */ eflag = ERR_BADDECRYPT; } bail_out: return eflag; } static int kmraw_put_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, const uint8_t *key, const int keylen, FILE *fp_key) /** Store key in unencrypted (plain) file */ { const keyinfo_t *keyinfo = &boundtgt->tgt->key; int eflag=ERR_NOERROR; /* Write data directly into keyfile: */ if (cm_fwrite((const void*)key, (size_t)keylen, fp_key) != 0 || ferror(fp_key) != 0) { fprintf(stderr, _("Key-writing failed for \"%s\"\n"), keyinfo->filename); eflag = ERR_BADENCRYPT; } return eflag; } static keymanager_t keymgr_raw = { "raw", 0, kmraw_init_algs, kmraw_free_algs, kmraw_bind, kmraw_get_properties, kmraw_get_key, kmraw_put_key, NULL #ifdef TESTING , NULL, NULL, CM_HASLEGACY #endif }; /* * ==== Abstract key-management interfaces ==== */ static keymanager_t **add_keymgr(keymanager_t **ptr, keymanager_t *km) /* Add key-manager interface definition(s) to list of available managers */ { if (km == NULL) return ptr; *ptr = km; /* Allow for addend itself being a list of key-managers: */ for (;;) { #ifdef TESTING if (km->install_testctxt != NULL) km->install_testctxt(test_ctxtptr); #endif if (km->next == NULL) break; km = km->next; } return &km->next; } static void build_keymgrs(void) /** Construct list of available key-managers */ { keymanager_t **ptr; if (keymgrs != NULL) return; /* already initialized */ ptr = &keymgrs; ptr = add_keymgr(ptr, kmblti_gethandle()); ptr = add_keymgr(ptr, kmgcry_gethandle()); ptr = add_keymgr(ptr, kmluks_gethandle()); ptr = add_keymgr(ptr, &keymgr_raw); } const char **get_keymgr_list(void) /** Construct list of key-manager names */ { keymanager_t *km; const char **arr=NULL; int i, cnt; build_keymgrs(); for (km=keymgrs,cnt=0; km!=NULL; km=km->next,++cnt); arr = (const char**)malloc((size_t)((cnt+1)*sizeof(const char*))); for (i=0,km=keymgrs; inext,++i) { arr[i] = km->ident; } arr[i] = NULL; return arr; } keymanager_t *init_keymanager(keymanager_t *km) { if (km != NULL) { if ((km->initialized & KM_INIT_ALGS) == 0) { if (km->init_algs() == 0) { km->initialized |= KM_INIT_ALGS; } else { fprintf(stderr, "Failed to initialize keymanager \"%s\"\n", km->ident); } } } return km; } int free_keymanagers(void) { keymanager_t *km; for (km=keymgrs; km!=NULL; km=km->next) { if ((km->initialized & KM_INIT_ALGS) != 0) { km->free_algs(); km->initialized = 0; } } return 0; } bound_tgtdefn_t *alloc_boundtgt(const tgtdefn_t *tgt) { bound_tgtdefn_t *bound; bound = (bound_tgtdefn_t*)malloc(sizeof(bound_tgtdefn_t)); bound->tgt = clone_tgtdefn(tgt); bound->keymgr = NULL; bound->km_data = NULL; return bound; } void free_boundtgt(bound_tgtdefn_t *boundtgt) { if (boundtgt == NULL) return; free_tgtdefn(boundtgt->tgt); if (boundtgt->km_data != NULL) free((void*)boundtgt->km_data); free((void*)boundtgt); } bound_tgtdefn_t *bind_tgtdefn(const tgtdefn_t *tgt) /** Find keymanager that is able to handle given target & keyfile */ { bound_tgtdefn_t *bound; keymanager_t *km; FILE *fp_key = NULL; if (tgt == NULL) return NULL; build_keymgrs(); bound = alloc_boundtgt(tgt); if (tgt->key.filename != NULL) { fp_key = fopen(tgt->key.filename, "rb"); } km = keymgrs; while (km != NULL) { if (fp_key != NULL) (void)fseek(fp_key, 0L, SEEK_SET); if (km->bind(bound, fp_key)) { bound->keymgr = init_keymanager(km); break; } km = km->next; } if (bound->keymgr == NULL) { free_boundtgt(bound); bound = NULL; } if (fp_key != NULL) fclose(fp_key); return bound; } /*! * Extract the filesystem encryption key for a particular target. * * This delegates most functionality to the methods defined * in the \ref keymanager_t structure. */ int cm_get_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, uint8_t **key, int *keylen) { keyinfo_t *keyinfo = &boundtgt->tgt->key; FILE *fp = NULL; unsigned props, attempts = 0; int eflag=ERR_NOERROR; if (keyinfo->filename != NULL) { fp = fopen(keyinfo->filename, "rb"); if (fp == NULL) { fprintf(stderr, _("Failed to open keyfile \"%s\" for target \"%s\"\n"), keyinfo->filename, boundtgt->tgt->ident); eflag = ERR_BADFILE; goto bail_out; } } else { props = boundtgt->keymgr->get_properties(boundtgt); if ((props & KM_PROP_NEEDSKEYFILE) != 0) { fprintf(stderr, _("Missing keyfile for target \"%s\"\n"), boundtgt->tgt->ident); eflag = ERR_BADFILE; goto bail_out; } } do { if (fp != NULL) (void)fseek(fp, 0L, SEEK_SET); eflag = boundtgt->keymgr->get_key(boundtgt, pw_ctxt, key, keylen, fp); if (eflag == ERR_BADDECRYPT) sleep(1); } while (++attempts < keyinfo->retries && eflag == ERR_BADDECRYPT); bail_out: if (fp != NULL) fclose(fp); return eflag; } int cm_put_key(bound_tgtdefn_t *boundtgt, const km_pw_context_t *pw_ctxt, const uint8_t *key, const int keylen, FILE *fp_key) { unsigned props; int eflag = ERR_NOERROR; props = boundtgt->keymgr->get_properties(boundtgt); if ((props & KM_PROP_NEEDSKEYFILE) != 0 && fp_key == NULL) { fprintf(stderr, _("Missing output keyfile for target \"%s\"\n"), boundtgt->tgt->ident); return ERR_BADFILE; } eflag = boundtgt->keymgr->put_key(boundtgt, pw_ctxt, key, keylen, fp_key); if (fp_key != NULL) { int fd = fileno(fp_key); #if HAVE_SYNCFS syncfs(fd); #else fsync(fd); #endif } return eflag; } unsigned cm_get_keyproperties(const bound_tgtdefn_t *boundtgt) /** Extract information about key, e.g. whether encrypted */ { unsigned props; if (boundtgt != NULL && boundtgt->keymgr != NULL) { props = boundtgt->keymgr->get_properties(boundtgt); } else { /* Safest to assume that key shouldn't be overwritten: */ props = KM_PROP_FIXEDLOC | KM_PROP_FORMATTED; } return props; } #ifdef TESTING /*! \addtogroup unit_tests * @{ */ const char *km_legacy_key = "cryptmount012345"; const char *km_legacy_passwd = "nothing"; int km_test_managers(void) { keymanager_t *km; int flg = 0; build_keymgrs(); for (km=keymgrs; km!=NULL; km=km->next) { if (km->run_tests == NULL) continue; km->init_algs(); flg |= km->run_tests(); } #if 0 km_archive_keys(); #endif return flg; } int km_test_keyrw(void) /* Test key read-writing (creation/extraction) */ { enum { MAXKEY=256 }; const keymanager_t *km; tgtdefn_t *target; bound_tgtdefn_t *bound=NULL; int i, keylen=0, keylen1, eflag; char str[256]; uint8_t key0[MAXKEY], *key1=NULL; FILE *fp; extern cm_testinfo_t *test_ctxtptr; CM_TEST_START("Key read-write"); build_keymgrs(); for (km=keymgrs; km!=NULL; km=km->next) { if ((km->test_flags & CM_READONLY) != 0) continue; km->init_algs(); target = alloc_tgtdefn(NULL); target->key.format = cm_strdup(km->ident); target->key.filename = cm_strdup("NOWHERE"); target->key.digestalg = NULL; target->key.cipheralg = NULL; target->key.maxlen = -1; for (keylen=1; keylen<=MAXKEY; keylen<<=2) { sprintf(str, "Key read-write, %s, keylen=%d", km->ident, keylen); CM_TEST_IDENT(str); /* Generate (low-entropy) key: */ for (i=0; ibind(bound, fp)) CM_TEST_FAIL(); eflag = km->put_key(bound, NULL, key0, keylen, fp); if (eflag != ERR_NOTSUPPORTED) { CM_ASSERT_EQUAL(ERR_NOERROR, eflag); key1 = NULL; keylen1 = -keylen; /* Try reading key back from file: */ rewind(fp); eflag = km->get_key(bound, NULL, &key1, &keylen1, fp); CM_ASSERT_EQUAL(ERR_NOERROR, eflag); CM_ASSERT_EQUAL(keylen, keylen1); CM_ASSERT_DIFFERENT(key0, key1); CM_ASSERT_DIFFERENT(NULL, key1); for (i=0; ifree_algs(); free_tgtdefn(target); } CM_ASSERT_DIFFERENT(keylen, 0); CM_TEST_OK(context); } int km_archive_keys(void) /** Generate fixed-pattern keys for testing reading by later releases */ { keymanager_t *km; tgtdefn_t *target; bound_tgtdefn_t *bound=NULL; FILE *fp; int flg = 0; char filename[256]; km_pw_context_t pw_ctxt; pw_ctxt.fd_pw_source = NULL; pw_ctxt.argpasswd[0] = pw_ctxt.argpasswd[1] = km_legacy_passwd; build_keymgrs(); for (km=keymgrs; km!=NULL; km=km->next) { if ((km->test_flags & CM_READONLY) != 0) continue; km->init_algs(); target = alloc_tgtdefn(NULL); target->key.format = cm_strdup(km->ident); target->key.filename = NULL; target->key.digestalg = NULL; target->key.cipheralg = NULL; target->key.maxlen = -1; bound = alloc_boundtgt(target); km->bind(bound, NULL); sprintf(filename, "/tmp/%s_%s_%s_%s_0", PACKAGE_VERSION, km->ident, bound->tgt->key.digestalg, bound->tgt->key.cipheralg); bound->tgt->key.filename = cm_strdup(filename); /* Write key to file: */ fp = fopen(filename, "wb"); /* May need to be "r+b" for LUKS */ flg |= km->put_key(bound, &pw_ctxt, (const uint8_t*)km_legacy_key, strlen(km_legacy_key), fp); fclose(fp); if (bound != NULL) free_boundtgt(bound); km->free_algs(); free_tgtdefn(target); } return flg; } int km_test_legacy(void) /** Check that keyfiles from earlier releases can be read */ { keymanager_t *km; glob_t keyfiles; struct stat sbuff; tgtdefn_t *target; bound_tgtdefn_t *bound=NULL; km_pw_context_t pw_ctxt; uint8_t *key=NULL; int idx, n_legacy = 0, keylen, flg; char *tokbuff, keyglob[1024]; const char *basepath; CM_TEST_START("Legacy key support"); pw_ctxt.fd_pw_source = NULL; pw_ctxt.verify = 0; pw_ctxt.argpasswd[0] = pw_ctxt.argpasswd[1] = km_legacy_passwd; snprintf(keyglob, sizeof(keyglob), CM_SRCDIR "/testing/keys/[0-9]*[0-9]"); glob(keyglob, 0, NULL, &keyfiles); for (km=keymgrs; km!=NULL; km=km->next) { km->initialized &= ~KM_TESTED; } for (idx=0; idx<(int)keyfiles.gl_pathc; ++idx) { const char *keypath = keyfiles.gl_pathv[idx]; if (stat(keypath, &sbuff) != 0) CM_TEST_FAIL(); if (!S_ISREG(sbuff.st_mode)) continue; ++n_legacy; strcpy(keyglob, keypath); basepath = basename(keyglob); tokbuff = cm_strdup(basepath); (void)strtok(tokbuff, "_"); target = alloc_tgtdefn(NULL); target->ident = cm_strdup(basepath); target->key.format = cm_strdup(strtok(NULL, "_")); target->key.filename = cm_strdup(keypath); target->key.digestalg = cm_strdup(strtok(NULL, "_")); target->key.cipheralg = cm_strdup(strtok(NULL, "_")); bound = bind_tgtdefn(target); if (bound != NULL) { ((keymanager_t*)bound->keymgr)->initialized |= KM_TESTED; } else { continue; /* No available key manager - possibly not compiled? */ } key = NULL; keylen = 0; flg = cm_get_key(bound, &pw_ctxt, &key, &keylen); if (flg == ERR_BADDEVICE && getuid() != 0) { fprintf(stderr, "Skipping \"%s\" (after %d keys) - possibly requires root privileges\n", keypath, (n_legacy - 1)); goto skip_jail; } CM_ASSERT_EQUAL(ERR_NOERROR, flg); CM_ASSERT_EQUAL(strlen(km_legacy_key), keylen); if (key != NULL) { CM_ASSERT_EQUAL(0, memcmp(key, km_legacy_key, (size_t)keylen)); } else { CM_TEST_FAIL(); } skip_jail: if (key != NULL) sec_free((void*)key); if (bound != NULL) free_boundtgt(bound); if (target != NULL) free_tgtdefn(target); free((void*)tokbuff); } globfree(&keyfiles); if (n_legacy < 4) CM_TEST_FAIL(); /* Check that all available keymanagers with legacy keys have been tested */ for (km=keymgrs; km!=NULL; km=km->next) { if ((km->test_flags & CM_HASLEGACY) != 0 && (km->initialized & KM_TESTED) == 0) { CM_TEST_FAIL(); } } CM_TEST_OK(); } /** @} */ #endif /* TESTING */ /* * ==== Miscellaneous routines ==== */ size_t mk_key_string(const uint8_t *key, const size_t keylen, char *buff) /** Create text version of crypto key */ { size_t i; for (i=0; i0 && cmtab[pos-1] != '/'; --pos) dirname[pos] = '\0'; while (--pos >= 0) dirname[pos] = cmtab[pos]; eflag = sycheck_directory(dirname); if (eflag != ERR_NOERROR) goto bail_out; if (stat(cmtab,&sfile) != 0) { fprintf(stderr, "Cannot open \"%s\"\n", cmtab); eflag = ERR_INSECURE; goto bail_out; } /* Check file ownerships: */ if (sfile.st_uid != (uid_t)0) { fprintf(stderr, "\"%s\" must be owned by root\n", cmtab); eflag = ERR_INSECURE; goto bail_out; } /* Check that file isn't globally writable: */ if (!S_ISREG(sfile.st_mode) || (sfile.st_mode & S_IWOTH) != 0) { fprintf(stderr, "Lax permissions on \"%s\"\n", cmtab); eflag = ERR_INSECURE; goto bail_out; } bail_out: if (dirname != NULL) free((void*)dirname); return eflag; } static int sy_path(const char *path) /** Check whether pathname is considered secure */ { if (path == NULL) return ERR_NOERROR; if (path[0] == '/') return ERR_NOERROR; return ERR_INSECURE; } int sycheck_target(const tgtdefn_t *tgt) /** Check that paths within target-specification are sensible */ { int eflag=ERR_NOERROR; if (tgt == NULL) return 0; eflag |= sy_path(tgt->dev); eflag |= sy_path(tgt->dir); eflag |= sy_path(tgt->key.filename); if (eflag != ERR_NOERROR) { fprintf(stderr, _("Specification for target \"%s\" contains non-absolute pathname\n"), tgt->ident); } return eflag; } /* * ==== Mutex-locking on configuration directory ==== */ static const char *cm_lock_filename = "_cryptmount_lock_"; int cm_mutex_lock(void) /** Try to acquire lock on configuration directory (via symlink marker) */ { char *fname=NULL, ident[64]; int delay_ms, eflag = ERR_BADMUTEX; unsigned dither = ((size_t)&fname % 250) + 1; const unsigned MAX_ATTEMPTS = 10; (void)cm_path(&fname, CM_SYSRUN_PFX, cm_lock_filename); snprintf(ident, sizeof(ident), "%u-%u", (unsigned)getpid(), (unsigned)getuid()); for (unsigned attempt=0; attempt #include #include #include #include "blowfish.h" #ifdef TESTING # include "cmtesting.h" #endif enum { CM_BF_nrounds = 16, CM_BF_keybytes = 8, CM_BF_maxkeybytes = 56 }; static const uint32_t bf_p[18] = { 0x243f6a88U , 0x85a308d3U , 0x13198a2eU , 0x03707344U , 0xa4093822U , 0x299f31d0U , 0x082efa98U , 0xec4e6c89U , 0x452821e6U , 0x38d01377U , 0xbe5466cfU , 0x34e90c6cU , 0xc0ac29b7U , 0xc97c50ddU , 0x3f84d5b5U , 0xb5470917U , 0x9216d5d9U , 0x8979fb1bU }; static const uint32_t bf_sbox[4][256] = { { 0xd1310ba6U , 0x98dfb5acU , 0x2ffd72dbU , 0xd01adfb7U , 0xb8e1afedU , 0x6a267e96U , 0xba7c9045U , 0xf12c7f99U , 0x24a19947U , 0xb3916cf7U , 0x0801f2e2U , 0x858efc16U , 0x636920d8U , 0x71574e69U , 0xa458fea3U , 0xf4933d7eU , 0x0d95748fU , 0x728eb658U , 0x718bcd58U , 0x82154aeeU , 0x7b54a41dU , 0xc25a59b5U , 0x9c30d539U , 0x2af26013U , 0xc5d1b023U , 0x286085f0U , 0xca417918U , 0xb8db38efU , 0x8e79dcb0U , 0x603a180eU , 0x6c9e0e8bU , 0xb01e8a3eU , 0xd71577c1U , 0xbd314b27U , 0x78af2fdaU , 0x55605c60U , 0xe65525f3U , 0xaa55ab94U , 0x57489862U , 0x63e81440U , 0x55ca396aU , 0x2aab10b6U , 0xb4cc5c34U , 0x1141e8ceU , 0xa15486afU , 0x7c72e993U , 0xb3ee1411U , 0x636fbc2aU , 0x2ba9c55dU , 0x741831f6U , 0xce5c3e16U , 0x9b87931eU , 0xafd6ba33U , 0x6c24cf5cU , 0x7a325381U , 0x28958677U , 0x3b8f4898U , 0x6b4bb9afU , 0xc4bfe81bU , 0x66282193U , 0x61d809ccU , 0xfb21a991U , 0x487cac60U , 0x5dec8032U , 0xef845d5dU , 0xe98575b1U , 0xdc262302U , 0xeb651b88U , 0x23893e81U , 0xd396acc5U , 0x0f6d6ff3U , 0x83f44239U , 0x2e0b4482U , 0xa4842004U , 0x69c8f04aU , 0x9e1f9b5eU , 0x21c66842U , 0xf6e96c9aU , 0x670c9c61U , 0xabd388f0U , 0x6a51a0d2U , 0xd8542f68U , 0x960fa728U , 0xab5133a3U , 0x6eef0b6cU , 0x137a3be4U , 0xba3bf050U , 0x7efb2a98U , 0xa1f1651dU , 0x39af0176U , 0x66ca593eU , 0x82430e88U , 0x8cee8619U , 0x456f9fb4U , 0x7d84a5c3U , 0x3b8b5ebeU , 0xe06f75d8U , 0x85c12073U , 0x401a449fU , 0x56c16aa6U , 0x4ed3aa62U , 0x363f7706U , 0x1bfedf72U , 0x429b023dU , 0x37d0d724U , 0xd00a1248U , 0xdb0fead3U , 0x49f1c09bU , 0x075372c9U , 0x80991b7bU , 0x25d479d8U , 0xf6e8def7U , 0xe3fe501aU , 0xb6794c3bU , 0x976ce0bdU , 0x04c006baU , 0xc1a94fb6U , 0x409f60c4U , 0x5e5c9ec2U , 0x196a2463U , 0x68fb6fafU , 0x3e6c53b5U , 0x1339b2ebU , 0x3b52ec6fU , 0x6dfc511fU , 0x9b30952cU , 0xcc814544U , 0xaf5ebd09U , 0xbee3d004U , 0xde334afdU , 0x660f2807U , 0x192e4bb3U , 0xc0cba857U , 0x45c8740fU , 0xd20b5f39U , 0xb9d3fbdbU , 0x5579c0bdU , 0x1a60320aU , 0xd6a100c6U , 0x402c7279U , 0x679f25feU , 0xfb1fa3ccU , 0x8ea5e9f8U , 0xdb3222f8U , 0x3c7516dfU , 0xfd616b15U , 0x2f501ec8U , 0xad0552abU , 0x323db5faU , 0xfd238760U , 0x53317b48U , 0x3e00df82U , 0x9e5c57bbU , 0xca6f8ca0U , 0x1a87562eU , 0xdf1769dbU , 0xd542a8f6U , 0x287effc3U , 0xac6732c6U , 0x8c4f5573U , 0x695b27b0U , 0xbbca58c8U , 0xe1ffa35dU , 0xb8f011a0U , 0x10fa3d98U , 0xfd2183b8U , 0x4afcb56cU , 0x2dd1d35bU , 0x9a53e479U , 0xb6f84565U , 0xd28e49bcU , 0x4bfb9790U , 0xe1ddf2daU , 0xa4cb7e33U , 0x62fb1341U , 0xcee4c6e8U , 0xef20cadaU , 0x36774c01U , 0xd07e9efeU , 0x2bf11fb4U , 0x95dbda4dU , 0xae909198U , 0xeaad8e71U , 0x6b93d5a0U , 0xd08ed1d0U , 0xafc725e0U , 0x8e3c5b2fU , 0x8e7594b7U , 0x8ff6e2fbU , 0xf2122b64U , 0x8888b812U , 0x900df01cU , 0x4fad5ea0U , 0x688fc31cU , 0xd1cff191U , 0xb3a8c1adU , 0x2f2f2218U , 0xbe0e1777U , 0xea752dfeU , 0x8b021fa1U , 0xe5a0cc0fU , 0xb56f74e8U , 0x18acf3d6U , 0xce89e299U , 0xb4a84fe0U , 0xfd13e0b7U , 0x7cc43b81U , 0xd2ada8d9U , 0x165fa266U , 0x80957705U , 0x93cc7314U , 0x211a1477U , 0xe6ad2065U , 0x77b5fa86U , 0xc75442f5U , 0xfb9d35cfU , 0xebcdaf0cU , 0x7b3e89a0U , 0xd6411bd3U , 0xae1e7e49U , 0x00250e2dU , 0x2071b35eU , 0x226800bbU , 0x57b8e0afU , 0x2464369bU , 0xf009b91eU , 0x5563911dU , 0x59dfa6aaU , 0x78c14389U , 0xd95a537fU , 0x207d5ba2U , 0x02e5b9c5U , 0x83260376U , 0x6295cfa9U , 0x11c81968U , 0x4e734a41U , 0xb3472dcaU , 0x7b14a94aU , 0x1b510052U , 0x9a532915U , 0xd60f573fU , 0xbc9bc6e4U , 0x2b60a476U , 0x81e67400U , 0x08ba6fb5U , 0x571be91fU , 0xf296ec6bU , 0x2a0dd915U , 0xb6636521U , 0xe7b9f9b6U , 0xff34052eU , 0xc5855664U , 0x53b02d5dU , 0xa99f8fa1U , 0x08ba4799U , 0x6e85076aU } , { 0x4b7a70e9U , 0xb5b32944U , 0xdb75092eU , 0xc4192623U , 0xad6ea6b0U , 0x49a7df7dU , 0x9cee60b8U , 0x8fedb266U , 0xecaa8c71U , 0x699a17ffU , 0x5664526cU , 0xc2b19ee1U , 0x193602a5U , 0x75094c29U , 0xa0591340U , 0xe4183a3eU , 0x3f54989aU , 0x5b429d65U , 0x6b8fe4d6U , 0x99f73fd6U , 0xa1d29c07U , 0xefe830f5U , 0x4d2d38e6U , 0xf0255dc1U , 0x4cdd2086U , 0x8470eb26U , 0x6382e9c6U , 0x021ecc5eU , 0x09686b3fU , 0x3ebaefc9U , 0x3c971814U , 0x6b6a70a1U , 0x687f3584U , 0x52a0e286U , 0xb79c5305U , 0xaa500737U , 0x3e07841cU , 0x7fdeae5cU , 0x8e7d44ecU , 0x5716f2b8U , 0xb03ada37U , 0xf0500c0dU , 0xf01c1f04U , 0x0200b3ffU , 0xae0cf51aU , 0x3cb574b2U , 0x25837a58U , 0xdc0921bdU , 0xd19113f9U , 0x7ca92ff6U , 0x94324773U , 0x22f54701U , 0x3ae5e581U , 0x37c2dadcU , 0xc8b57634U , 0x9af3dda7U , 0xa9446146U , 0x0fd0030eU , 0xecc8c73eU , 0xa4751e41U , 0xe238cd99U , 0x3bea0e2fU , 0x3280bba1U , 0x183eb331U , 0x4e548b38U , 0x4f6db908U , 0x6f420d03U , 0xf60a04bfU , 0x2cb81290U , 0x24977c79U , 0x5679b072U , 0xbcaf89afU , 0xde9a771fU , 0xd9930810U , 0xb38bae12U , 0xdccf3f2eU , 0x5512721fU , 0x2e6b7124U , 0x501adde6U , 0x9f84cd87U , 0x7a584718U , 0x7408da17U , 0xbc9f9abcU , 0xe94b7d8cU , 0xec7aec3aU , 0xdb851dfaU , 0x63094366U , 0xc464c3d2U , 0xef1c1847U , 0x3215d908U , 0xdd433b37U , 0x24c2ba16U , 0x12a14d43U , 0x2a65c451U , 0x50940002U , 0x133ae4ddU , 0x71dff89eU , 0x10314e55U , 0x81ac77d6U , 0x5f11199bU , 0x043556f1U , 0xd7a3c76bU , 0x3c11183bU , 0x5924a509U , 0xf28fe6edU , 0x97f1fbfaU , 0x9ebabf2cU , 0x1e153c6eU , 0x86e34570U , 0xeae96fb1U , 0x860e5e0aU , 0x5a3e2ab3U , 0x771fe71cU , 0x4e3d06faU , 0x2965dcb9U , 0x99e71d0fU , 0x803e89d6U , 0x5266c825U , 0x2e4cc978U , 0x9c10b36aU , 0xc6150ebaU , 0x94e2ea78U , 0xa5fc3c53U , 0x1e0a2df4U , 0xf2f74ea7U , 0x361d2b3dU , 0x1939260fU , 0x19c27960U , 0x5223a708U , 0xf71312b6U , 0xebadfe6eU , 0xeac31f66U , 0xe3bc4595U , 0xa67bc883U , 0xb17f37d1U , 0x018cff28U , 0xc332ddefU , 0xbe6c5aa5U , 0x65582185U , 0x68ab9802U , 0xeecea50fU , 0xdb2f953bU , 0x2aef7dadU , 0x5b6e2f84U , 0x1521b628U , 0x29076170U , 0xecdd4775U , 0x619f1510U , 0x13cca830U , 0xeb61bd96U , 0x0334fe1eU , 0xaa0363cfU , 0xb5735c90U , 0x4c70a239U , 0xd59e9e0bU , 0xcbaade14U , 0xeecc86bcU , 0x60622ca7U , 0x9cab5cabU , 0xb2f3846eU , 0x648b1eafU , 0x19bdf0caU , 0xa02369b9U , 0x655abb50U , 0x40685a32U , 0x3c2ab4b3U , 0x319ee9d5U , 0xc021b8f7U , 0x9b540b19U , 0x875fa099U , 0x95f7997eU , 0x623d7da8U , 0xf837889aU , 0x97e32d77U , 0x11ed935fU , 0x16681281U , 0x0e358829U , 0xc7e61fd6U , 0x96dedfa1U , 0x7858ba99U , 0x57f584a5U , 0x1b227263U , 0x9b83c3ffU , 0x1ac24696U , 0xcdb30aebU , 0x532e3054U , 0x8fd948e4U , 0x6dbc3128U , 0x58ebf2efU , 0x34c6ffeaU , 0xfe28ed61U , 0xee7c3c73U , 0x5d4a14d9U , 0xe864b7e3U , 0x42105d14U , 0x203e13e0U , 0x45eee2b6U , 0xa3aaabeaU , 0xdb6c4f15U , 0xfacb4fd0U , 0xc742f442U , 0xef6abbb5U , 0x654f3b1dU , 0x41cd2105U , 0xd81e799eU , 0x86854dc7U , 0xe44b476aU , 0x3d816250U , 0xcf62a1f2U , 0x5b8d2646U , 0xfc8883a0U , 0xc1c7b6a3U , 0x7f1524c3U , 0x69cb7492U , 0x47848a0bU , 0x5692b285U , 0x095bbf00U , 0xad19489dU , 0x1462b174U , 0x23820e00U , 0x58428d2aU , 0x0c55f5eaU , 0x1dadf43eU , 0x233f7061U , 0x3372f092U , 0x8d937e41U , 0xd65fecf1U , 0x6c223bdbU , 0x7cde3759U , 0xcbee7460U , 0x4085f2a7U , 0xce77326eU , 0xa6078084U , 0x19f8509eU , 0xe8efd855U , 0x61d99735U , 0xa969a7aaU , 0xc50c06c2U , 0x5a04abfcU , 0x800bcadcU , 0x9e447a2eU , 0xc3453484U , 0xfdd56705U , 0x0e1e9ec9U , 0xdb73dbd3U , 0x105588cdU , 0x675fda79U , 0xe3674340U , 0xc5c43465U , 0x713e38d8U , 0x3d28f89eU , 0xf16dff20U , 0x153e21e7U , 0x8fb03d4aU , 0xe6e39f2bU , 0xdb83adf7U } , { 0xe93d5a68U , 0x948140f7U , 0xf64c261cU , 0x94692934U , 0x411520f7U , 0x7602d4f7U , 0xbcf46b2eU , 0xd4a20068U , 0xd4082471U , 0x3320f46aU , 0x43b7d4b7U , 0x500061afU , 0x1e39f62eU , 0x97244546U , 0x14214f74U , 0xbf8b8840U , 0x4d95fc1dU , 0x96b591afU , 0x70f4ddd3U , 0x66a02f45U , 0xbfbc09ecU , 0x03bd9785U , 0x7fac6dd0U , 0x31cb8504U , 0x96eb27b3U , 0x55fd3941U , 0xda2547e6U , 0xabca0a9aU , 0x28507825U , 0x530429f4U , 0x0a2c86daU , 0xe9b66dfbU , 0x68dc1462U , 0xd7486900U , 0x680ec0a4U , 0x27a18deeU , 0x4f3ffea2U , 0xe887ad8cU , 0xb58ce006U , 0x7af4d6b6U , 0xaace1e7cU , 0xd3375fecU , 0xce78a399U , 0x406b2a42U , 0x20fe9e35U , 0xd9f385b9U , 0xee39d7abU , 0x3b124e8bU , 0x1dc9faf7U , 0x4b6d1856U , 0x26a36631U , 0xeae397b2U , 0x3a6efa74U , 0xdd5b4332U , 0x6841e7f7U , 0xca7820fbU , 0xfb0af54eU , 0xd8feb397U , 0x454056acU , 0xba489527U , 0x55533a3aU , 0x20838d87U , 0xfe6ba9b7U , 0xd096954bU , 0x55a867bcU , 0xa1159a58U , 0xcca92963U , 0x99e1db33U , 0xa62a4a56U , 0x3f3125f9U , 0x5ef47e1cU , 0x9029317cU , 0xfdf8e802U , 0x04272f70U , 0x80bb155cU , 0x05282ce3U , 0x95c11548U , 0xe4c66d22U , 0x48c1133fU , 0xc70f86dcU , 0x07f9c9eeU , 0x41041f0fU , 0x404779a4U , 0x5d886e17U , 0x325f51ebU , 0xd59bc0d1U , 0xf2bcc18fU , 0x41113564U , 0x257b7834U , 0x602a9c60U , 0xdff8e8a3U , 0x1f636c1bU , 0x0e12b4c2U , 0x02e1329eU , 0xaf664fd1U , 0xcad18115U , 0x6b2395e0U , 0x333e92e1U , 0x3b240b62U , 0xeebeb922U , 0x85b2a20eU , 0xe6ba0d99U , 0xde720c8cU , 0x2da2f728U , 0xd0127845U , 0x95b794fdU , 0x647d0862U , 0xe7ccf5f0U , 0x5449a36fU , 0x877d48faU , 0xc39dfd27U , 0xf33e8d1eU , 0x0a476341U , 0x992eff74U , 0x3a6f6eabU , 0xf4f8fd37U , 0xa812dc60U , 0xa1ebddf8U , 0x991be14cU , 0xdb6e6b0dU , 0xc67b5510U , 0x6d672c37U , 0x2765d43bU , 0xdcd0e804U , 0xf1290dc7U , 0xcc00ffa3U , 0xb5390f92U , 0x690fed0bU , 0x667b9ffbU , 0xcedb7d9cU , 0xa091cf0bU , 0xd9155ea3U , 0xbb132f88U , 0x515bad24U , 0x7b9479bfU , 0x763bd6ebU , 0x37392eb3U , 0xcc115979U , 0x8026e297U , 0xf42e312dU , 0x6842ada7U , 0xc66a2b3bU , 0x12754cccU , 0x782ef11cU , 0x6a124237U , 0xb79251e7U , 0x06a1bbe6U , 0x4bfb6350U , 0x1a6b1018U , 0x11caedfaU , 0x3d25bdd8U , 0xe2e1c3c9U , 0x44421659U , 0x0a121386U , 0xd90cec6eU , 0xd5abea2aU , 0x64af674eU , 0xda86a85fU , 0xbebfe988U , 0x64e4c3feU , 0x9dbc8057U , 0xf0f7c086U , 0x60787bf8U , 0x6003604dU , 0xd1fd8346U , 0xf6381fb0U , 0x7745ae04U , 0xd736fcccU , 0x83426b33U , 0xf01eab71U , 0xb0804187U , 0x3c005e5fU , 0x77a057beU , 0xbde8ae24U , 0x55464299U , 0xbf582e61U , 0x4e58f48fU , 0xf2ddfda2U , 0xf474ef38U , 0x8789bdc2U , 0x5366f9c3U , 0xc8b38e74U , 0xb475f255U , 0x46fcd9b9U , 0x7aeb2661U , 0x8b1ddf84U , 0x846a0e79U , 0x915f95e2U , 0x466e598eU , 0x20b45770U , 0x8cd55591U , 0xc902de4cU , 0xb90bace1U , 0xbb8205d0U , 0x11a86248U , 0x7574a99eU , 0xb77f19b6U , 0xe0a9dc09U , 0x662d09a1U , 0xc4324633U , 0xe85a1f02U , 0x09f0be8cU , 0x4a99a025U , 0x1d6efe10U , 0x1ab93d1dU , 0x0ba5a4dfU , 0xa186f20fU , 0x2868f169U , 0xdcb7da83U , 0x573906feU , 0xa1e2ce9bU , 0x4fcd7f52U , 0x50115e01U , 0xa70683faU , 0xa002b5c4U , 0x0de6d027U , 0x9af88c27U , 0x773f8641U , 0xc3604c06U , 0x61a806b5U , 0xf0177a28U , 0xc0f586e0U , 0x006058aaU , 0x30dc7d62U , 0x11e69ed7U , 0x2338ea63U , 0x53c2dd94U , 0xc2c21634U , 0xbbcbee56U , 0x90bcb6deU , 0xebfc7da1U , 0xce591d76U , 0x6f05e409U , 0x4b7c0188U , 0x39720a3dU , 0x7c927c24U , 0x86e3725fU , 0x724d9db9U , 0x1ac15bb4U , 0xd39eb8fcU , 0xed545578U , 0x08fca5b5U , 0xd83d7cd3U , 0x4dad0fc4U , 0x1e50ef5eU , 0xb161e6f8U , 0xa28514d9U , 0x6c51133cU , 0x6fd5c7e7U , 0x56e14ec4U , 0x362abfceU , 0xddc6c837U , 0xd79a3234U , 0x92638212U , 0x670efa8eU , 0x406000e0U } , { 0x3a39ce37U , 0xd3faf5cfU , 0xabc27737U , 0x5ac52d1bU , 0x5cb0679eU , 0x4fa33742U , 0xd3822740U , 0x99bc9bbeU , 0xd5118e9dU , 0xbf0f7315U , 0xd62d1c7eU , 0xc700c47bU , 0xb78c1b6bU , 0x21a19045U , 0xb26eb1beU , 0x6a366eb4U , 0x5748ab2fU , 0xbc946e79U , 0xc6a376d2U , 0x6549c2c8U , 0x530ff8eeU , 0x468dde7dU , 0xd5730a1dU , 0x4cd04dc6U , 0x2939bbdbU , 0xa9ba4650U , 0xac9526e8U , 0xbe5ee304U , 0xa1fad5f0U , 0x6a2d519aU , 0x63ef8ce2U , 0x9a86ee22U , 0xc089c2b8U , 0x43242ef6U , 0xa51e03aaU , 0x9cf2d0a4U , 0x83c061baU , 0x9be96a4dU , 0x8fe51550U , 0xba645bd6U , 0x2826a2f9U , 0xa73a3ae1U , 0x4ba99586U , 0xef5562e9U , 0xc72fefd3U , 0xf752f7daU , 0x3f046f69U , 0x77fa0a59U , 0x80e4a915U , 0x87b08601U , 0x9b09e6adU , 0x3b3ee593U , 0xe990fd5aU , 0x9e34d797U , 0x2cf0b7d9U , 0x022b8b51U , 0x96d5ac3aU , 0x017da67dU , 0xd1cf3ed6U , 0x7c7d2d28U , 0x1f9f25cfU , 0xadf2b89bU , 0x5ad6b472U , 0x5a88f54cU , 0xe029ac71U , 0xe019a5e6U , 0x47b0acfdU , 0xed93fa9bU , 0xe8d3c48dU , 0x283b57ccU , 0xf8d56629U , 0x79132e28U , 0x785f0191U , 0xed756055U , 0xf7960e44U , 0xe3d35e8cU , 0x15056dd4U , 0x88f46dbaU , 0x03a16125U , 0x0564f0bdU , 0xc3eb9e15U , 0x3c9057a2U , 0x97271aecU , 0xa93a072aU , 0x1b3f6d9bU , 0x1e6321f5U , 0xf59c66fbU , 0x26dcf319U , 0x7533d928U , 0xb155fdf5U , 0x03563482U , 0x8aba3cbbU , 0x28517711U , 0xc20ad9f8U , 0xabcc5167U , 0xccad925fU , 0x4de81751U , 0x3830dc8eU , 0x379d5862U , 0x9320f991U , 0xea7a90c2U , 0xfb3e7bceU , 0x5121ce64U , 0x774fbe32U , 0xa8b6e37eU , 0xc3293d46U , 0x48de5369U , 0x6413e680U , 0xa2ae0810U , 0xdd6db224U , 0x69852dfdU , 0x09072166U , 0xb39a460aU , 0x6445c0ddU , 0x586cdecfU , 0x1c20c8aeU , 0x5bbef7ddU , 0x1b588d40U , 0xccd2017fU , 0x6bb4e3bbU , 0xdda26a7eU , 0x3a59ff45U , 0x3e350a44U , 0xbcb4cdd5U , 0x72eacea8U , 0xfa6484bbU , 0x8d6612aeU , 0xbf3c6f47U , 0xd29be463U , 0x542f5d9eU , 0xaec2771bU , 0xf64e6370U , 0x740e0d8dU , 0xe75b1357U , 0xf8721671U , 0xaf537d5dU , 0x4040cb08U , 0x4eb4e2ccU , 0x34d2466aU , 0x0115af84U , 0xe1b00428U , 0x95983a1dU , 0x06b89fb4U , 0xce6ea048U , 0x6f3f3b82U , 0x3520ab82U , 0x011a1d4bU , 0x277227f8U , 0x611560b1U , 0xe7933fdcU , 0xbb3a792bU , 0x344525bdU , 0xa08839e1U , 0x51ce794bU , 0x2f32c9b7U , 0xa01fbac9U , 0xe01cc87eU , 0xbcc7d1f6U , 0xcf0111c3U , 0xa1e8aac7U , 0x1a908749U , 0xd44fbd9aU , 0xd0dadecbU , 0xd50ada38U , 0x0339c32aU , 0xc6913667U , 0x8df9317cU , 0xe0b12b4fU , 0xf79e59b7U , 0x43f5bb3aU , 0xf2d519ffU , 0x27d9459cU , 0xbf97222cU , 0x15e6fc2aU , 0x0f91fc71U , 0x9b941525U , 0xfae59361U , 0xceb69cebU , 0xc2a86459U , 0x12baa8d1U , 0xb6c1075eU , 0xe3056a0cU , 0x10d25065U , 0xcb03a442U , 0xe0ec6e0eU , 0x1698db3bU , 0x4c98a0beU , 0x3278e964U , 0x9f1f9532U , 0xe0d392dfU , 0xd3a0342bU , 0x8971f21eU , 0x1b0a7441U , 0x4ba3348cU , 0xc5be7120U , 0xc37632d8U , 0xdf359f8dU , 0x9b992f2eU , 0xe60b6f47U , 0x0fe3f11dU , 0xe54cda54U , 0x1edad891U , 0xce6279cfU , 0xcd3e7e6fU , 0x1618b166U , 0xfd2c1d05U , 0x848fd2c5U , 0xf6fb2299U , 0xf523f357U , 0xa6327623U , 0x93a83531U , 0x56cccd02U , 0xacf08162U , 0x5a75ebb5U , 0x6e163697U , 0x88d273ccU , 0xde966292U , 0x81b949d0U , 0x4c50901bU , 0x71c65614U , 0xe6c6c7bdU , 0x327a140aU , 0x45e1d006U , 0xc3f27b9aU , 0xc9aa53fdU , 0x62a80f00U , 0xbb25bfe2U , 0x35bdd2f6U , 0x71126905U , 0xb2040222U , 0xb6cbcf7cU , 0xcd769c2bU , 0x53113ec0U , 0x1640e3d3U , 0x38abbd60U , 0x2547adf0U , 0xba38209cU , 0xf746ce76U , 0x77afa1c5U , 0x20756060U , 0x85cbfe4eU , 0x8ae88dd8U , 0x7aaaf9b0U , 0x4cf9aa7eU , 0x1948c25cU , 0x02fb8a8cU , 0x01c36ae4U , 0xd6ebe1f9U , 0x90d4f869U , 0xa65cdea0U , 0x3f09252dU , 0xc208e69fU , 0xb74e6132U , 0xce77e25bU , 0x578fdfe3U , 0x3ac372e6U } }; static uint32_t cm_bf_feist(const cm_bf_ctxt_t *ctxt, uint32_t x) { uint32_t a, b, c, d, y; d = (x & 0xff); c = (x & 0xff00) >> 8; b = (x & 0xff0000) >> 16; a = (x & 0xff000000) >> 24; y = ctxt->sbox[0][a] + ctxt->sbox[1][b]; y = y ^ ctxt->sbox[2][c]; y = y + ctxt->sbox[3][d]; return y; } void cm_bf_encipher(const cm_bf_ctxt_t *ctxt, uint32_t *xl, uint32_t *xr) { uint32_t Xl, Xr, temp; int round; Xl = *xl; Xr = *xr; for (round=0; roundp[round]; Xr = cm_bf_feist(ctxt, Xl) ^ Xr; temp = Xl; Xl = Xr; Xr = temp; } temp = Xl; Xl = Xr; Xr = temp; Xr = Xr ^ ctxt->p[CM_BF_nrounds]; Xl = Xl ^ ctxt->p[CM_BF_nrounds + 1]; *xl = Xl; *xr = Xr; } void cm_bf_decipher(const cm_bf_ctxt_t *ctxt, uint32_t *xl, uint32_t *xr) { uint32_t Xl, Xr, temp; int round; Xl = *xl; Xr = *xr; for (round=CM_BF_nrounds+1; round>1; --round) { Xl = Xl ^ ctxt->p[round]; Xr = cm_bf_feist(ctxt, Xl) ^ Xr; temp = Xl; Xl = Xr; Xr = temp; } temp = Xl; Xl = Xr; Xr = temp; Xr = Xr ^ ctxt->p[1]; Xl = Xl ^ ctxt->p[0]; *xl = Xl; *xr = Xr; } cm_bf_ctxt_t *cm_bf_init(uint8_t *key, size_t keybytes) { cm_bf_ctxt_t *ctxt; uint32_t data, datal, datar; size_t i, j, k; ctxt = (cm_bf_ctxt_t*)malloc(sizeof(cm_bf_ctxt_t)); memcpy((void*)ctxt->p, (const void*)bf_p, sizeof(bf_p)); memcpy((void*)ctxt->sbox, (const void*)bf_sbox, sizeof(bf_sbox)); j = 0; for (i=0; i= keybytes) j = 0; } ctxt->p[i] =ctxt->p[i] ^ data; } datal = datar = 0; for (i=0; ip[i] = datal; ctxt->p[i + 1] = datar; } for (i=0; i<4; ++i) { for (j=0; j<256; j+=2) { cm_bf_encipher(ctxt, &datal, &datar); ctxt->sbox[i][j] = datal; ctxt->sbox[i][j + 1] = datar; } } return ctxt; } void cm_bf_free(cm_bf_ctxt_t *ctxt) { if (ctxt == NULL) return; memset((void*)ctxt->p, 0, sizeof(bf_p)); memset((void*)ctxt->sbox, 0, sizeof(bf_sbox)); free((void*)ctxt); } #ifdef TESTING int bf_test_blowfish() /* Check Blowfish encryption against known test-vectors */ { struct tvec { const char *key; uint32_t in0, in1; uint32_t out0, out1; } tvecs[] = { { "abcdefgh", 0x01234567, 0x89abcdef, 0x89fc0a5b, 0x074df537, }, { "ABCDwxyz", 0x12345678, 0x9abcdef0, 0x061dab8f, 0x33a16a10}, { "alphabetti spaghetti", 0xaa55aa55, 0x55aa55aa, 0x927079bb, 0xb275bad0 }, { "Blowfish algorithm", 0x5555aaaa, 0x01234567, 0x731ae03a, 0xda77789e }, { NULL, 0, 0 } }; cm_bf_ctxt_t *ctxt; uint32_t vals[2]; unsigned idx; CM_TEST_START("Internal Blowfish"); idx = 0; while (tvecs[idx].key != NULL) { ctxt = cm_bf_init((uint8_t*)tvecs[idx].key, strlen(tvecs[idx].key)); vals[0] = tvecs[idx].in0; vals[1] = tvecs[idx].in1; cm_bf_encipher(ctxt, vals, vals+1); CM_ASSERT_EQUAL(tvecs[idx].out0, vals[0]); CM_ASSERT_EQUAL(tvecs[idx].out1, vals[1]); cm_bf_decipher(ctxt, vals, vals+1); CM_ASSERT_EQUAL(tvecs[idx].in0, vals[0]); CM_ASSERT_EQUAL(tvecs[idx].in1, vals[1]); cm_bf_free(ctxt); ++idx; } CM_TEST_OK(); return 0; } #endif /* TESTING */ cryptmount-6.3.0/blowfish.h000066400000000000000000000011161465135467200157460ustar00rootroot00000000000000/* * Declarations for "Blowfish" cipher algorithm * (Based on Bruce Schneier's implementation at http://www.schneier.com * subsequently edited by RW Penney for "cryptmount") */ /* This file is part of cryptmount */ #include typedef struct cm_bf_ctxt { uint32_t p[18]; uint32_t sbox[4][256]; } cm_bf_ctxt_t; cm_bf_ctxt_t *cm_bf_init(uint8_t *key, size_t keybytes); void cm_bf_encipher(const cm_bf_ctxt_t *ctxt, uint32_t *xl, uint32_t *xr); void cm_bf_decipher(const cm_bf_ctxt_t *ctxt, uint32_t *xl, uint32_t *xr); void cm_bf_free(cm_bf_ctxt_t *ctxt); cryptmount-6.3.0/cmtab.example000066400000000000000000000027141465135467200164300ustar00rootroot00000000000000# Sample configuration file for cryptmount # The following target uses a raw file to act as a LUKS encrypted container. # cryptmount will automatically configure a vacant loopback device on mounting crypt_basic { dev=/home/crypt.fs dir=/home/some_username/crypt fstype=ext4 keyformat=luks } # The following target uses a raw file to contain the encrypted fs # but uses a separate key-file managed via libgcrypt crypt_detached { dev=/home/crypt.fs dir=/mnt/crypt fstype=ext3 mountoptions=defaults cipher=aes keyfile=/home/secretiveuser/crypt.key keyformat=libgcrypt } # The following target uses part of a raw disk partition as the encrypted fs: # (sectors 512-16895 are used here. Remove the 'startsector' and 'numsector' # parameters to use the whole partition.) crypt_sdb63 { dev=/dev/sdb63 startsector=512 numsectors=16384 dir=/mnt/crypt63 fstype=ext3 mountoptions=defaults \ cipher=serpent # filesystem encryption # information about file used to store decryption key: keyfile=/etc/cryptmount/crypt_sdb63.key keyformat=openssl-compat keyhash=md5 keycipher=bf-cbc } # The following target uses part of a raw disk partition to create # an encrypted swap (paging) area. crypto_swap { dev=/dev/sdb63 startsector=16896 numsectors=1024 fstype=swap flags=mkswap cipher=twofish keyfile=/dev/random keymaxlen=16 keyformat=raw bootaction=swap } cryptmount-6.3.0/cmtesting.c000066400000000000000000000055551465135467200161340ustar00rootroot00000000000000/* * Methods for unit-testing utiltities for cryptmount * (C)Copyright 2006-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef TESTING #include "config.h" #include #include "cmtesting.h" /*! \addtogroup unit_tests * @{ */ static void cm_tests_init(); static int cm_tests_close(); static void cm_tests_init() { int i; test_ctxtptr->current = NULL; test_ctxtptr->tests_run = 0; for (i=0; itest_stats[i] = 0; } } int cm_tests_close() { int i,nt; for (i=0,nt=0; itest_stats[i]; } if (nt != test_ctxtptr->tests_run) { fprintf(stderr, "mismatch in test-statistics (%d != %d)\n", nt, test_ctxtptr->tests_run); } if (test_ctxtptr->test_stats[CM_TEST_PASSED] == test_ctxtptr->tests_run) { fprintf(stderr, "++++ all %d tests PASSED ++++\n", test_ctxtptr->tests_run); } else { fprintf(stderr, "!!!! %2d tests FAILED !!!!\n", test_ctxtptr->test_stats[CM_TEST_FAILED]); fprintf(stderr, "!!!! %2d tests passed !!!!\n", test_ctxtptr->test_stats[CM_TEST_PASSED]); fprintf(stderr, "!!!! %2d tests aborted !!!!\n", test_ctxtptr->test_stats[CM_TEST_ABORTED]); } return (test_ctxtptr->test_stats[CM_TEST_PASSED] != test_ctxtptr->tests_run); } int cm_run_tests() /* Front-end to self-testing routines */ { int bf_test_blowfish(), fs_test_blkgetsz(), fs_test_splitopts(), fs_test_entropy(), km_test_managers(), km_test_keyrw(), km_test_legacy(), tb_test_expand(), ut_test_strings(), ut_test_strops(), ut_test_sha1(), ut_pwfort(); cm_tests_init(); ut_test_strings(); ut_test_strops(); tb_test_expand(); fs_test_blkgetsz(); fs_test_splitopts(); fs_test_entropy(); ut_test_sha1(); ut_pwfort(); bf_test_blowfish(); km_test_managers(); km_test_keyrw(); km_test_legacy(); return cm_tests_close(); } /** @} */ #else /* !TESTING */ int _keep_ansi_pedantic_quiet = 0; #endif /* TESTING */ /* * (C)Copyright 2006-2024, RW Penney */ cryptmount-6.3.0/cmtesting.h000066400000000000000000000077121465135467200161360ustar00rootroot00000000000000/* * Declarations for unit-test utilities for cryptmoumt * (C)Copyright 2006-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _CMTEST_H #define _CMTEST_H #include "config.h" /*! \addtogroup unit_tests * @{ */ enum { CM_TEST_PASSED = 0, CM_TEST_FAILED, CM_TEST_ABORTED, CM_TEST_LAST }; enum { CM_READONLY = 0x001, /* Omit tests of key-creation */ CM_HASLEGACY = 0x002 /* Test against legacy key files */ }; typedef struct cm_testinfo { const char *current; /* name of current test */ int tests_run; /* total number of tests initiated */ int test_stats[CM_TEST_LAST]; /* statistics of test outcomes */ const char *argconfigdir; /* adjustable config-directory */ } cm_testinfo_t; extern cm_testinfo_t *test_ctxtptr; #define CM_TEST_START(name) \ { \ fprintf(stderr, "starting test \"%s\"...", name); \ ++test_ctxtptr->tests_run; \ test_ctxtptr->current = NULL; \ } #define CM_TEST_IDENT(ident) \ { \ test_ctxtptr->current = (const char*)ident; \ } #define CM_ASSERT_EQUAL(expected, actual) \ if ((expected) != (actual)) { \ fprintf(stderr, " test failed %s:%d (%s != %s)\n", \ __FILE__, __LINE__, #expected, #actual); \ if (test_ctxtptr->current != NULL) { \ fprintf(stderr, " [%s]\n", test_ctxtptr->current); } \ ++test_ctxtptr->test_stats[CM_TEST_FAILED]; \ return CM_TEST_FAILED; \ } #define CM_ASSERT_STR_EQUAL(expected, actual) \ if (strcmp(expected, actual) != 0) { \ fprintf(stderr, " test failed %s:%d (\"%s\" != \"%s\")\n", \ __FILE__, __LINE__, expected, actual); \ if (test_ctxtptr->current != NULL) { \ fprintf(stderr, " [%s]\n", test_ctxtptr->current); } \ ++test_ctxtptr->test_stats[CM_TEST_FAILED]; \ return CM_TEST_FAILED; \ } #define CM_ASSERT_DIFFERENT(expected, actual) \ if ((expected) == (actual)) { \ fprintf(stderr, " test failed %s:%d\n (%s == %s)", \ __FILE__, __LINE__, #expected, #actual); \ if (test_ctxtptr->current != NULL) { \ fprintf(stderr, " [%s]\n", test_ctxtptr->current); } \ ++test_ctxtptr->test_stats[CM_TEST_FAILED]; \ return CM_TEST_FAILED; \ } #define CM_TEST_OK(TI) \ { \ fprintf(stderr, " ok\n"); \ ++test_ctxtptr->test_stats[CM_TEST_PASSED]; \ return CM_TEST_PASSED; \ } #define CM_TEST_FAIL(TI) \ { \ fprintf(stderr, " FAILED at %s:%d\n", __FILE__, __LINE__); \ if (test_ctxtptr->current != NULL) { \ fprintf(stderr, " [%s]\n", test_ctxtptr->current); } \ ++test_ctxtptr->test_stats[CM_TEST_FAILED]; \ return CM_TEST_FAILED; \ } #define CM_TEST_ABORT(TI) \ { \ fprintf(stderr, " ABORTED at %s:%d\n", __FILE__, __LINE__); \ if (test_ctxtptr->current != NULL) { \ fprintf(stderr, " [%s]\n", test_ctxtptr->current); } \ ++test_ctxtptr->test_stats[CM_TEST_ABORTED]; \ return CM_TEST_ABORTED; \ } int cm_run_tests(); /** @} */ #endif /* _CMTEST_H */ /* * (C)Copyright 2006-2024, RW Penney */ cryptmount-6.3.0/config.h.in000066400000000000000000000162431465135467200160120ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Default filesystem encryption algorithm */ #undef CM_DEFAULT_CIPHER /* Define to 1 if translation of program messages to the user's native language is requested. */ #undef ENABLE_NLS /* Define to 1 if you have the Mac OS X function CFLocaleCopyPreferredLanguages in the CoreFoundation framework. */ #undef HAVE_CFLOCALECOPYPREFERREDLANGUAGES /* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in the CoreFoundation framework. */ #undef HAVE_CFPREFERENCESCOPYAPPVALUE /* Define if the GNU dcgettext() function is already present or preinstalled. */ #undef HAVE_DCGETTEXT /* Define to 1 if you have the declaration of `dm_task_secure_data', and to 0 if you don't. */ #undef HAVE_DECL_DM_TASK_SECURE_DATA /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define if the GNU gettext() function is already present or preinstalled. */ #undef HAVE_GETTEXT /* Define if you have the iconv() function and it works. */ #undef HAVE_ICONV /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `ioctl' function. */ #undef HAVE_IOCTL /* Define to 1 if you have the libcryptsetup header files */ #undef HAVE_LIBCRYPTSETUP /* Is libcryptsetup >= 1.6.0 available? */ #undef HAVE_LIBCRYPTSETUP_1_6 /* Define to 1 if you have libdevmapper header files */ #undef HAVE_LIBDEVMAP /* Define to 1 to enable libgcrypt support */ #undef HAVE_LIBGCRYPT /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_FS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_LOOP_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the header file. */ #undef HAVE_MINIX_CONFIG_H /* Define to 1 if you have the `mknod' function. */ #undef HAVE_MKNOD /* Define to 1 if you have the header file. */ #undef HAVE_MNTENT_H /* Define to 1 if you have nanosleep() */ #undef HAVE_NANOSLEEP /* Define to 1 if you have the `open' function. */ #undef HAVE_OPEN /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strncpy' function. */ #undef HAVE_STRNCPY /* Define to 1 if you have the `syncfs' function. */ #undef HAVE_SYNCFS /* Define to 1 if you have the `syslog' function. */ #undef HAVE_SYSLOG /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SYSMACROS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have tcgetattr() */ #undef HAVE_TERMIOS /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define to 1 to enable OpenSSL-compatible keys via libgcrypt */ #undef USE_GCRYOSSL /* Define to 1 to enable LUKS compatbility layer */ #undef USE_LUKSCOMPAT /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # undef _DARWIN_C_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable X/Open compliant socket functions that do not require linking with -lxnet on HP-UX 11.11. */ #ifndef _HPUX_ALT_XOPEN_SOCKET_API # undef _HPUX_ALT_XOPEN_SOCKET_API #endif /* Identify the host operating system as Minix. This macro does not affect the system headers' behavior. A future release of Autoconf may stop defining this macro. */ #ifndef _MINIX # undef _MINIX #endif /* Enable general extensions on NetBSD. Enable NetBSD compatibility extensions on Minix. */ #ifndef _NETBSD_SOURCE # undef _NETBSD_SOURCE #endif /* Enable OpenBSD compatibility extensions on NetBSD. Oddly enough, this does nothing on OpenBSD. */ #ifndef _OPENBSD_SOURCE # undef _OPENBSD_SOURCE #endif /* Define to 1 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_SOURCE # undef _POSIX_SOURCE #endif /* Define to 2 if needed for POSIX-compatible behavior. */ #ifndef _POSIX_1_SOURCE # undef _POSIX_1_SOURCE #endif /* Enable POSIX-compatible threading on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ #ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ # undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ # undef __STDC_WANT_IEC_60559_BFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif /* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif /* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ #ifndef __STDC_WANT_LIB_EXT2__ # undef __STDC_WANT_LIB_EXT2__ #endif /* Enable extensions specified by ISO/IEC 24747:2009. */ #ifndef __STDC_WANT_MATH_SPEC_FUNCS__ # undef __STDC_WANT_MATH_SPEC_FUNCS__ #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable X/Open extensions. Define to 500 only if necessary to make mbstate_t available. */ #ifndef _XOPEN_SOURCE # undef _XOPEN_SOURCE #endif /* Version number of package */ #undef VERSION /* use program-name to alter default action */ #undef WITH_ARGV0 /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const cryptmount-6.3.0/config.rpath000077500000000000000000000374441465135467200163050ustar00rootroot00000000000000#! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2006 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # Known limitations: # - On IRIX 6.5 with CC="cc", the run time search patch must not be longer # than 256 bytes, otherwise the compiler driver will dump core. The only # known workaround is to choose shorter directory names for the build # directory and/or the installation directory. # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a shrext=.so host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` # Code taken from libtool.m4's _LT_CC_BASENAME. for cc_temp in $CC""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` # Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix*) wl='-Wl,' ;; darwin*) case $cc_basename in xlc*) wl='-Wl,' ;; esac ;; mingw* | pw32* | os2*) ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6* | nonstopux*) wl='-Wl,' ;; newsos6) ;; linux*) case $cc_basename in icc* | ecc*) wl='-Wl,' ;; pgcc | pgf77 | pgf90) wl='-Wl,' ;; ccc*) wl='-Wl,' ;; como) wl='-lopt=' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) wl='-Wl,' ;; esac ;; esac ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; sco3.2v5*) ;; solaris*) wl='-Wl,' ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) wl='-Wl,' ;; sysv4*MP*) ;; unicos*) wl='-Wl,' ;; uts4*) ;; esac fi # Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. # Unlike libtool, we use -rpath here, not --rpath, since the documented # option of GNU ld is called -rpath, not --rpath. hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' case "$host_os" in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we cannot use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then : else ld_shlibs=no fi ;; interix3*) hardcode_direct=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; netbsd*) ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' else ld_shlibs=no fi ;; esac ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then hardcode_libdir_flag_spec= fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac fi # Begin _LT_AC_SYS_LIBPATH_AIX. echo 'int main () { return 0; }' > conftest.c ${CC} ${LDFLAGS} conftest.c -o conftest aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` fi if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib" fi rm -f conftest.c conftest # End _LT_AC_SYS_LIBPATH_AIX. if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" fi fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi[45]*) ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=no if test "$GCC" = yes ; then : else case $cc_basename in xlc*) ;; *) ld_shlibs=no ;; esac fi ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; freebsd1*) ld_shlibs=no ;; freebsd2.2*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; freebsd2*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd* | kfreebsd*-gnu | dragonfly*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; hpux10*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no ;; *) hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; openbsd*) hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) case $host_vendor in sni) hardcode_direct=yes # is this really true??? ;; siemens) hardcode_direct=no ;; motorola) hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac ;; sysv4.3*) ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) ;; sysv5* | sco3.2v5* | sco5v6*) hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator=':' ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics # Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. libname_spec='lib$name' case "$host_os" in aix3*) ;; aix4* | aix5*) ;; amigaos*) ;; beos*) ;; bsdi[45]*) ;; cygwin* | mingw* | pw32*) shrext=.dll ;; darwin* | rhapsody*) shrext=.dylib ;; dgux*) ;; freebsd1*) ;; kfreebsd*-gnu) ;; freebsd* | dragonfly*) ;; gnu*) ;; hpux9* | hpux10* | hpux11*) case $host_cpu in ia64*) shrext=.so ;; hppa*64*) shrext=.sl ;; *) shrext=.sl ;; esac ;; interix3*) ;; irix5* | irix6* | nonstopux*) case "$host_os" in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac ;; linux*oldld* | linux*aout* | linux*coff*) ;; linux*) ;; knetbsd*-gnu) ;; netbsd*) ;; newsos6) ;; nto-qnx*) ;; openbsd*) ;; os2*) libname_spec='$name' shrext=.dll ;; osf3* | osf4* | osf5*) ;; solaris*) ;; sunos4*) ;; sysv4 | sysv4.3*) ;; sysv4*MP*) ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) ;; uts4*) ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` shlibext=`echo "$shrext" | sed -e 's,^\.,,'` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <]) dnl -------- dnl libgcrypt key-manager dnl AC_CHECK_HEADER([gcrypt.h], [dfltGCRY="yes"], [dfltGCRY="no"]) AC_ARG_WITH([libgcrypt], AS_HELP_STRING([--with-libgcrypt], [support libgcrypt-encryption of keys]), [libgcrypt="${withval}"], [libgcrypt="${dfltGCRY}"]) if test "x${libgcrypt}" = "xyes"; then AC_SEARCH_LIBS(gcry_cipher_open, gcrypt, [AC_DEFINE(HAVE_LIBGCRYPT, [1], [Define to 1 if you have libgcrypt header files])], [AC_MSG_ERROR([cannot find libgcrypt libraries])]) else AC_DEFINE(HAVE_LIBGCRYPT, [0], [Define to 1 to enable libgcrypt support]) fi dnl -------- dnl OpenSSL emulation with libgcrypt dnl AC_ARG_ENABLE([openssl-compat], AS_HELP_STRING([--enable-openssl-compat], [enable libgcrypt-based OpenSSL compatible key-files (default is YES)]), [sslcompat="${enableval}"], [sslcompat="yes"]) if test "x${sslcompat}" = "xyes"; then AC_DEFINE(USE_GCRYOSSL, [1], [Define to 1 to enable OpenSSL-compatible keys via libgcrypt]) else AC_DEFINE(USE_GCRYOSSL, [0]) fi dnl -------- dnl libcryptsetup libraries (needed for LUKS/cryptsetup key-manager) dnl PKG_CHECK_MODULES([libcryptsetup], [libcryptsetup >= 1.4], [libcs="yes"], [libcs="no"]) if test "x${libcs}" = "xyes"; then AC_DEFINE(HAVE_LIBCRYPTSETUP, [1], [Define to 1 if you have the libcryptsetup header files]) fi dnl -------- dnl LUKS key-management (implicitly dependent on libgcrypt) dnl AC_ARG_ENABLE([luks], AS_HELP_STRING([--enable-luks], [enable key-management via Linux Unified Key Setup (default is YES)]), [use_lukscompat="${enableval}"], [use_lukscompat="${libgcrypt}"]) if test "x${use_lukscompat}" = "xyes" \ -a \( "x${libgcrypt}" != "xyes" -o "x${libcs}" != "xyes" \); then AC_MSG_WARN([LUKS support requires libcryptsetup and libgcrypt libraries]) use_lukscompat="no" fi if test "x${use_lukscompat}" = "xyes"; then AC_DEFINE(USE_LUKSCOMPAT, [1], [Define to 1 to enable LUKS compatbility layer]) LIBS="${LIBS} ${libcryptsetup_LIBS}" CPPFLAGS="${CPPFLAGS} ${libcryptsetup_CFLAGS}" AC_SEARCH_LIBS(crypt_keyslot_change_by_passphrase, libcryptsetup, [AC_DEFINE(HAVE_LIBCRYPTSETUP_1_6, [1], [Is libcryptsetup >= 1.6.0 available?])], [AC_DEFINE(HAVE_LIBCRYPTSETUP_1_6, [0])]) else AC_DEFINE(USE_LUKSCOMPAT, [0]) fi AM_CONDITIONAL(BUILD_LUKSCOMPAT, test "x$use_lukscompat" = "xyes") dnl -------- dnl delegation of mount/umount functionality dnl AC_ARG_ENABLE([delegation], AS_HELP_STRING([--enable-delegation], [delegate (un)mounting to /bin/(u)mount (default is YES)]), [delegation="${enableval}"], [delegation="yes"]) if test "x${delegation}" = "xyes"; then dfltERSATZ=0; else dlftERSATZ=1; fi AC_CHECK_PROG([ERSATZ_MOUNT], [mount], [${dfltERSATZ}], [1], ${SYSPATH}) AC_PATH_PROG([PATH_MOUNT], [mount], [NOTHING], ${SYSPATH}) AC_CHECK_PROG([ERSATZ_UMOUNT], [umount], [${dfltERSATZ}], [1], ${SYSPATH}) AC_PATH_PROG([PATH_UMOUNT], [umount], [NOTHING], ${SYSPATH}) dnl -------- dnl crypt-swap support dnl AC_ARG_ENABLE([cswap], AS_HELP_STRING([--enable-cswap], [enable crypto-swap support (default is YES)]), [use_cswap="${enableval}"], [use_cswap="yes"]) if test "x${use_cswap}" = "xyes"; then dfltSWAP=1; AC_SEARCH_LIBS(swapon, c, [], [AC_MSG_ERROR([swapon() system-call is needed for crypto-swap])]) else dfltSWAP=0; fi AC_CHECK_PROG([WITH_CSWAP], [mkswap], [${dfltSWAP}], [0], ${SYSPATH}) AC_PATH_PROG([PATH_MKSWAP], [mkswap], [NOTHING], ${SYSPATH}) dnl -------- dnl automatic filesystem checking dnl AC_ARG_ENABLE([fsck], AS_HELP_STRING([--enable-fsck], [check filesystems before mounting (default is YES)]), [fsck="${enableval}"], [fsck="yes"]) if test "x${fsck}" = "xyes"; then dfltFSCK=1; else dfltFSCK=0; fi AC_CHECK_PROG([WITH_FSCK], [fsck], [${dfltFSCK}], [0], ${SYSPATH}) AC_PATH_PROG([PATH_FSCK], [fsck], [NOTHING], ${SYSPATH}) dnl -------- dnl internationalization dnl AM_GNU_GETTEXT_VERSION([0.16.1]) AM_GNU_GETTEXT([external]) dnl -------- dnl argv[0] switches of default mode dnl AC_ARG_ENABLE([argv0switch], AS_HELP_STRING([--enable-argv0switch], [default action given by progname (default is NO)]), [argv0switch="${enableval}"], [argv0switch="no"]) if test "x${argv0switch}" = "xyes"; then AC_DEFINE(WITH_ARGV0, 1, [use program-name to alter default action]) fi dnl -------- dnl Doxygen documentation dnl AC_CHECK_PROG([use_doxygen], [doxygen], [yes], [no], ${SYSPATH}) AC_ARG_WITH([docdir], AS_HELP_STRING([--with-docdir], [directory for assembling source-code documentation]), [], [with_docdir=./DoxyDocs]) if test "x${with_docdir}" != "xno"; then DOXYGEN_DOCDIR="${with_docdir}" fi AM_CONDITIONAL(HAVE_DOXYGEN, test "x$use_doxygen" = "xyes") AC_SUBST(DOXYGEN_DOCDIR) dnl -------- dnl systemd vs sysv boot support dnl if test -d "/lib/systemd/system"; then default_sysd_unitdir="/lib/systemd/system"; else default_sysd_unitdir="/usr/lib/systemd/system"; fi AC_ARG_WITH([systemd-unit-dir], AS_HELP_STRING([--with-systemd-unit-dir], [directory for systemd unit files]), [CM_SYSD_UNITDIR="${withval}"], [CM_SYSD_UNITDIR="${default_sysd_unitdir}"]) AC_ARG_WITH([systemd], AS_HELP_STRING([--with-systemd], [whether boot-up support should be via systemd or sysvinit (default is NO)])) AM_CONDITIONAL(USE_SYSTEMD, test "x$with_systemd" = "xyes") dnl -------- dnl substitute variables for location of configuration files etc dnl AC_SUBST(CM_SYSCONF_DIR) AC_SUBST(CM_SYSRUN_DIR) AC_SUBST(CM_SYSD_UNITDIR) AC_SUBST(LIBS_GCRY) AC_SUBST(LIBS_LUKS) AC_SUBST(CM_DEFAULT_CIPHER) AC_SUBST(CM_DEFAULT_SUPATH) AC_DEFINE(CM_DEFAULT_CIPHER, [], [Default filesystem encryption algorithm]) AC_DEFINE_UNQUOTED(CM_DEFAULT_CIPHER, ["${CM_DEFAULT_CIPHER}"]) AC_CONFIG_FILES([ Makefile delegates.h man/Makefile man/fr/Makefile po/Makefile.in sysinit/Makefile testing/Makefile doxygen.conf ]) AC_CONFIG_HEADERS([config.h]) AC_OUTPUT dnl -------- dnl configuration-summary messages dnl eval msg_conf="${CM_SYSCONF_DIR}" if test "${ERSATZ_MOUNT}" -ne 0; then msg_mount="(internal)"; else msg_mount="${PATH_MOUNT}"; fi if test "${ERSATZ_UMOUNT}" -ne 0; then msg_umount="(internal)"; else msg_umount="${PATH_UMOUNT}"; fi if test "${WITH_FSCK}" -ne 0; then msg_fsck="${PATH_FSCK}"; else msg_fsck="(disabled)"; fi msg_gcry="${libgcrypt}" if test "x${libgcrypt}" = "xyes"; then if test "x${sslcompat}" = "xyes"; then msg_gcry="${msg_gcry} (with OpenSSL emulator)"; else msg_gcry="${msg_gcry} (without OpenSSL emulator)"; fi fi msg_luks="${use_lukscompat}" AC_MSG_NOTICE([ cryptmount-${PACKAGE_VERSION} is now configured with: Source location: $srcdir Installation prefix: $prefix Configuration directory: $msg_conf Run-state directory: ${CM_SYSRUN_DIR} Filesystem mounting: $msg_mount Filesystem unmounting: $msg_umount Filesystem checking: $msg_fsck Crypto-swap support: $use_cswap libgcrypt support: $msg_gcry LUKS support: $msg_luks ]) dnl vim: set ts=4 sw=4 et: cryptmount-6.3.0/cryptmount.c000066400000000000000000001411701465135467200163550ustar00rootroot00000000000000/* * cryptmount - a utility for user-level mounting of encrypted filesystems * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYSLOG # include #endif #include "armour.h" #include "cryptmount.h" #include "delegates.h" #include "dmutils.h" #include "fsutils.h" #include "looputils.h" #include "tables.h" #include "utils.h" #if WITH_CSWAP # include #endif #ifdef TESTING # include "cmtesting.h" #endif /** Record of getuid() output at start of process */ uid_t cm_initial_uid = ~0u; /** * An element within a linked-list of filesystem-targets, * typically supplied from command-line. */ typedef struct targelt { const tgtdefn_t *tgt; struct targelt *nx; } targelt_t; /** Identifiers of top-level operating mode, and configuration switches * * The lower-order bits specify one of a sequence of mutuall-exclusive * operating modes. The higher-order bits consist of a few control flags, * some of which may be set implicitly according the the operating mode. */ typedef enum { M_UNSET, M_HELP, M_PREPARE, M_RELEASE, M_MOUNT, M_UNMOUNT, M_SWAPON, M_SWAPOFF, M_LIST, M_KEYMGRS, M_STATUS, M_PASSWORD, M_KEYGEN, M_KEYREU, M_SYSBOOT, M_SYSQUIT, M_SAFETYNET, M_VERSION, M_SELFTEST, M_MODE_MASK = 0x00ff, F_NEEDS_TGT = 0x0100, /*!< command requires a filesystem target */ F_ALL_TARGETS = 0x0200, /*!< command will be applied to all known targets */ F_NOWARN_ALL = 0x0400, /*!< suppress warnings with '--all' targets */ F_VERIFY_PW = 0x0800 /*!< encryption password should be double-checked */ } cmmode_t; static int64_t getblk512count(const char *device, int *blklen); static int execute_list(cmmode_t mode, const tgtdefn_t *tgttable, const km_pw_context_t *pw_ctxt, const char *params, const targelt_t *eltlist); static int do_list(const targelt_t *eltlist); static int do_status(const targelt_t *eltlist); static int do_keymgrlist(); static int do_sysboot_updown(int booting, const tgtdefn_t *tgttable, const km_pw_context_t *pw_ctxt); static int do_devsetup(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt, char **mntdev); static int do_devshutdown(const bound_tgtdefn_t *boundtgt); static int do_mount(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt); static int do_unmount(const bound_tgtdefn_t *boundtgt); static int do_swapon(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt); static int do_swapoff(const bound_tgtdefn_t *boundtgt); static int do_passwd(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt); static int do_keygen(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt, const char *params, int reuse, const tgtdefn_t *tgttable); static int do_safetynet(); static const char *USAGE_STRING = N_("\ usage: cryptmount [OPTION [target ...]]\n\ \n\ available options are as follows:\n\ \n\ -h | --help\n\ -a | --all\n\ -c | --change-password \n\ -k | --key-managers\n\ -l | --list\n\ -S | --status\n\ -m | --mount \n\ -u | --unmount \n\ --generate-key \n\ --reuse-key \n\ --prepare \n\ --release \n\ --config-fd \n\ --passwd-fd \n\ --swapon \n\ --swapoff \n\ --version\n\ \n\ please report bugs to \n\ "); #ifdef TESTING cm_testinfo_t test_context; cm_testinfo_t *test_ctxtptr = &test_context; int fs_test_blkgetsz() /** Check that 32bit & 64bit device size calculations agree */ { #ifdef BLKGETSIZE64 int fd, n_open, seclen; long len; uint64_t len64; const char **dev; const char *devices[] = { "/dev/hda", "/dev/hda1", "/dev/hda2", "/dev/hda3", "/dev/nvme0n1", "/dev/nvme0n2", "/dev/nvme1n1", "/dev/nvme1n2", "/dev/sda", "/dev/sda1", "/dev/sda2", "/dev/sda3", "/dev/sdb", "/dev/sdb1", "/dev/sdb2", "/dev/sdb3", "/dev/vda", "/dev/vda1", "/dev/xvda", "/dev/xvda1", "/dev/sr0", "/dev/sr1", NULL }; #endif CM_TEST_START("BLKGETSIZE ioctl calls"); #ifndef BLKGETSIZE64 /* Assume that there is no ambiguity with BLKGETSIZE */ CM_TEST_PASS(); #else dev = devices; n_open = 0; while (*dev != NULL) { fd = open(*dev, O_RDONLY); if (fd >= 0) { ++n_open; if (ioctl(fd, BLKSSZGET, &seclen) != 0 || ioctl(fd, BLKGETSIZE, &len) != 0 || ioctl(fd, BLKGETSIZE64, &len64) != 0) { CM_TEST_FAIL(); } close(fd); if (len64 < (1<<31)) { CM_ASSERT_EQUAL(len64, ((int64_t)len * (int64_t)512)); } } #if 0 if (fd >= 0) fprintf(stderr, "%s: %d %ld %lld\n", *dev, seclen, len * 512, len64); #endif ++dev; } if (n_open > 0) { CM_TEST_OK(); } else { CM_TEST_ABORT(); } #endif /* BLKGETSIZE64 */ } #endif /* TESTING */ static int64_t getblk512count(const char *device, int *blklen) /** Find size of raw device in blocks of size 512-bytes */ { int64_t count = -1; int fd; #ifndef BLKGETSIZE64 long len; #endif *blklen = 512; fd = open(device, O_RDONLY); if (fd < 0) return (int64_t)-1; #ifdef BLKGETSIZE64 if (ioctl(fd, BLKGETSIZE64, &count) == 0 && ioctl(fd, BLKSSZGET, blklen) == 0) { count /= (int64_t)512; } else { count = -1; } #else if (ioctl(fd, BLKGETSIZE, &len) == 0) { /* This directly gives the number of 512-byte blocks */ count = (int64_t)len; } #endif (void)close(fd); return count; } /*! @brief Print list of available filing-system targets to stdout * * This provides the back-end functionality for * the '--list' command-line option. */ static int do_list(const targelt_t *eltlist) { const targelt_t *elt; for (elt=eltlist; elt!=NULL; elt=elt->nx) { const tgtdefn_t *tgt = elt->tgt; /* TRANSLATORS: this string is marked as 'no-c-format' because some localizations may require the mount-point and filesystem type to be printed in a different order, but the untranslated string needs to remain an ordinary string that can be printed without gettext. */ /* xgettext:no-c-format */ printf(_("%-16s [to mount on \"%s\" as \"%s\"]\n"), tgt->ident, tgt->dir, tgt->fstype); } return ERR_NOERROR; } /*! @brief Print mounting status of set of targets to stdout * * This provides the back-end functionality for * the '--status' command-line option. */ static int do_status(const targelt_t *eltlist) { const targelt_t *elt; tgtstat_t *tgtstats = NULL, *ts; tgtstats = get_all_tgtstatus(); for (elt=eltlist; elt!=NULL; elt=elt->nx) { const tgtdefn_t *tgt = elt->tgt; for (ts=tgtstats; ts!=NULL; ts=ts->nx) { if (strcmp(ts->ident, tgt->ident) == 0) break; } printf("%-16s %s\n", tgt->ident, (ts != NULL ? "mounted" : "not_mounted")); } free_tgtstatus(tgtstats); return ERR_NOERROR; } /*! @brief Print a list of all available key managers to stdout. * * This provides the back-end functionality for * the '--key-managers' command-line option. */ static int do_keymgrlist() { const char **keymgrs = get_keymgr_list(); int i = 0; while (keymgrs[i] != NULL) { printf("%s", keymgrs[i]); ++i; if (keymgrs[i] != NULL) { printf(", "); } else { printf("\n"); } } free((void*)keymgrs); return ERR_NOERROR; } /*! @brief Setup all devices which have a bootaction option specified * * This provides the back-end functionality for * the '--system-boot' and '--system-shutdown' command-line options. * * \see do_mount(), do_swapon(), do_devsetup(). */ static int do_sysboot_updown(int booting, const tgtdefn_t *tgttable, const km_pw_context_t *pw_ctxt) { const tgtdefn_t *tgt; bound_tgtdefn_t *boundtgt = NULL; int eflag = ERR_NOERROR; for (tgt=tgttable; tgt!=NULL && eflagnx) { const unsigned boot_mode = (tgt->flags & FLG_BOOT_MASK); if (boot_mode == 0) continue; boundtgt = bind_tgtdefn(tgt); if (boundtgt == NULL) continue; switch (boot_mode) { case FLG_BOOT_MOUNT: eflag = (booting ? do_mount(pw_ctxt, boundtgt) : do_unmount(boundtgt)); break; case FLG_BOOT_SWAP: eflag = (booting ? do_swapon(pw_ctxt, boundtgt) : do_swapoff(boundtgt)); break; case FLG_BOOT_PREP: eflag = (booting ? do_devsetup(pw_ctxt, boundtgt, NULL) : do_devshutdown(boundtgt)); break; default: break; } free_boundtgt(boundtgt); } return eflag; } /*! @brief Setup all devices needed to access encrypted target * * This will wrap any file-based targets within a loopback device, * and then setup the device-mapper to provide encryption/decryption * of the target block device after obtaining the access password * from the user. * * This provides the back-end functionality for * the '--prepare' command-line option. * * \see cm_get_key(), blockify_file(), devmap_create(), do_devshutdown(). */ static int do_devsetup(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt, char **mntdev) { enum { BUFFMIN=1024 }; uint8_t *key = NULL; int buffpos, blklen, readonly, isloop = 0, killloop = 0, keylen = 0, eflag = ERR_NOERROR; int64_t devlen = 0, fslen = 0; size_t dpsize; char *dmparams = NULL; const char *tgtdev = NULL; const tgtdefn_t *tgt = NULL; /* Get crypto-key for filing system: */ eflag = cm_get_key(boundtgt, pw_ctxt, &key, &keylen); if (eflag != ERR_NOERROR) { fprintf(stderr, _("Failed to extract cipher key\n")); goto bail_out; } tgt = boundtgt->tgt; readonly = is_readonlyfs(tgt->dev); eflag = blockify_file(tgt->dev, (readonly ? O_RDONLY : O_RDWR), tgt->loopdev, &tgtdev, &isloop); if (eflag != ERR_NOERROR) { fprintf(stderr, _("Cannot open device \"%s\" for target \"%s\"\n"), (tgt->dev != NULL ? tgt->dev : "(NULL)"), tgt->ident); goto bail_out; } /* Get size in blocks of target device: */ devlen = getblk512count(tgtdev, &blklen); if (devlen < 0) { fprintf(stderr, _("Failed to get size of \"%s\"\n"), tgtdev); eflag = ERR_BADIOCTL; goto bail_out; } if (tgt->length < 0 || (tgt->start + tgt->length) > devlen) { fslen = devlen - tgt->start; } else { fslen = tgt->length; } if (tgt->start < 0 || fslen <= 0) { fprintf(stderr,_("Bad device-mapper start/length")); fprintf(stderr, " (%" PRId64 ",%" PRId64 ")\n", tgt->start, tgt->length); eflag = ERR_BADDEVICE; goto bail_out; } /* Setup device-mapper crypt table (CIPHER KEY IV_OFFSET DEV START): */ dpsize = 2 * keylen + BUFFMIN; dmparams = (char*)sec_realloc(dmparams, dpsize); buffpos = snprintf(dmparams, dpsize, "%s ", (tgt->cipher != NULL ? tgt->cipher : CM_DEFAULT_CIPHER)); buffpos += mk_key_string(key, (size_t)keylen, dmparams + buffpos); buffpos += snprintf(dmparams + buffpos, (dpsize - buffpos), " %" PRId64 " %s %" PRId64, tgt->ivoffset, tgtdev, tgt->start); if ((tgt->flags & FLG_TRIM) != 0) { buffpos += snprintf(dmparams + buffpos, (dpsize - buffpos), " 1 allow_discards"); } /* Setup device-mapper target: */ eflag = devmap_create(tgt->ident, (uint64_t)0, (uint64_t)fslen, "crypt", dmparams); if (eflag != ERR_NOERROR) { fprintf(stderr, _("Device-mapper target-creation failed for \"%s\"\n"), tgt->ident); killloop = 1; goto bail_out; } if (mntdev != NULL) { devmap_path(mntdev, tgt->ident); } bail_out: if (killloop) unblockify_file(&tgtdev, isloop); /* mounting failed? */ if (tgtdev) free((void*)tgtdev); sec_free(dmparams); sec_free(key); return eflag; } /* do_devsetup() */ /*! @brief Remove all devices attached to encrypted target * * This will close-down device-mapper and loopback devices * configured by do_setup(). * * This provides the back-end functionality for * the '--release' command-line option. * * \see do_devsetup(), devmap_remove(), loop_dellist(). */ int do_devshutdown(const bound_tgtdefn_t *boundtgt) { const tgtdefn_t *tgt = boundtgt->tgt; struct stat sbuff; unsigned devcnt = 0; dev_t *devids = NULL; int eflag = ERR_NOERROR; /* Check if filing system has been configured at all: */ if (!is_configured(tgt->ident, NULL)) { fprintf(stderr, _("Target \"%s\" does not appear to be configured\n"), tgt->ident); eflag = WRN_UNCONFIG; goto bail_out; } /* Delay to allow udev to settle */ millisleep(500); /* FIXME - find more deterministic solution! */ /* Find any underlying (e.g. loopback) devices for device-mapper target: */ (void)devmap_dependencies(tgt->ident, &devcnt, &devids); #ifdef DEBUG fprintf(stderr, "Shutting down %s [%u dependencies]\n", tgt->ident, devcnt); #endif memset((void*)&sbuff, 0, sizeof(sbuff)); if (stat(tgt->dev, &sbuff) != 0) { fprintf(stderr, _("Cannot stat \"%s\"\n"), tgt->dev); sbuff.st_mode |= S_IFREG; eflag = ERR_BADDEVICE; } /* Remove demice-mapper target: */ eflag = devmap_remove(tgt->ident); if (eflag != ERR_NOERROR) { fprintf(stderr, _("Failed to remove device-mapper target \"%s\"\n"), tgt->ident); } await_devmap(tgt->ident, 0, 2000); /* Tidy-up any associated loopback devices: */ if (S_ISREG(sbuff.st_mode) && devids != NULL) { (void)loop_dellist(devcnt, devids); } bail_out: if (devids != NULL) free((void*)devids); return eflag; } /*! @brief Mount an encrypted filesystem * * This provides the back-end functionality for * the '--mount' command-line option. * * \see do_unmount(), do_devsetup(), fs_mount(). */ static int do_mount(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt) { const tgtdefn_t *tgt = NULL; int freedev = 0, eflag = ERR_NOERROR; char *mntdev = NULL; tgtstat_t *tstat; if (is_mounted(boundtgt->tgt)) { fprintf(stderr, _("Target \"%s\" is already mounted\n"), boundtgt->tgt->ident); eflag = WRN_MOUNTED; goto bail_out; } eflag = do_devsetup(pw_ctxt, boundtgt, &mntdev); if (eflag != ERR_NOERROR) goto bail_out; tgt = boundtgt->tgt; await_device(mntdev, 1, 5000); #if WITH_FSCK if ((tgt->flags & FLG_FSCK) != 0) { const int fsck_flag = fs_check(mntdev, tgt); if (fsck_flag != ERR_NOERROR) { freedev = 1; eflag = fsck_flag; goto bail_out; } } #endif if (fs_mount(mntdev, tgt) != ERR_NOERROR) { freedev = 1; eflag = ERR_BADMOUNT; goto bail_out; } tstat = alloc_tgtstatus(tgt); tstat->uid = (unsigned long)cm_initial_uid; put_tgtstatus(tgt, tstat); free_tgtstatus(tstat); bail_out: if (freedev) { /* Tidy-up debris if mount failed */ do_devshutdown(boundtgt); } if (mntdev != NULL) free((void*)mntdev); return eflag; } /*! @brief Unmount an encrypted filesystem * * This provides the back-end functionality for * the '--unmount' command-line option. * * \see do_mount(), do_devshutdown(), fs_unmount(). */ static int do_unmount(const bound_tgtdefn_t *boundtgt) { const tgtdefn_t *tgt = boundtgt->tgt; int eflag=ERR_NOERROR; struct passwd *pwent; char *mntdev = NULL; tgtstat_t *tstat = NULL; /* Check if filing system has been configured at all: */ if (!is_mounted(tgt) || (tstat = get_tgtstatus(tgt)) == NULL) { fprintf(stderr, _("Target \"%s\" does not appear to be mounted\n"), tgt->ident); eflag = WRN_UNCONFIG; goto bail_out; } /* Check if filing system has been mounted & locked by another user: */ if (getuid() != 0 && (uid_t)tstat->uid != cm_initial_uid) { pwent = getpwuid((uid_t)tstat->uid); if (pwent != NULL) { fprintf(stderr, _("Only \"%s\" can unmount \"%s\"\n"), pwent->pw_name, tgt->ident); } else { /* TRANSLATORS: the following expands to include the *numerical* user-identity in place of '%lu', e.g. giving 'only user-16 can unmount "target"': */ fprintf(stderr, _("Only user-%lu can unmount \"%s\"\n"), tstat->uid, tgt->ident); } eflag = ERR_BADPRIV; goto bail_out; } /* Unmount filing system: */ if (fs_unmount(tgt) != ERR_NOERROR) { eflag = ERR_BADMOUNT; goto bail_out; } put_tgtstatus(tgt, NULL); /* Remove supporting device-mapper target etc */ if (do_devshutdown(boundtgt) != ERR_NOERROR) { eflag = ERR_BADDEVICE; } bail_out: if (mntdev != NULL) free((void*)mntdev); if (tstat != NULL) free_tgtstatus(tstat); return eflag; } /*! @brief Setup an encrypted swap partition * * This provides the back-end functionality for * the '--swapon' command-line option. * * \see do_swapoff(), do_devsetup(), fs_swapon(). */ static int do_swapon(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt) { const tgtdefn_t *tgt = NULL; int freedev = 0, eflag = ERR_NOERROR; char *mntdev = NULL; tgtstat_t *tstat = NULL; #if WITH_CSWAP if (is_configured(boundtgt->tgt->ident, NULL)) { fprintf(stderr, _("Target \"%s\" is already configured\n"), boundtgt->tgt->ident); eflag = WRN_MOUNTED; goto bail_out; } eflag = do_devsetup(pw_ctxt, boundtgt, &mntdev); if (eflag != ERR_NOERROR) goto bail_out; tgt = boundtgt->tgt; await_device(mntdev, 1, 5000); if (fs_swapon(mntdev, tgt) != ERR_NOERROR) { freedev = 1; eflag = ERR_BADSWAP; goto bail_out; } tstat = alloc_tgtstatus(tgt); tstat->uid = (unsigned long)cm_initial_uid; put_tgtstatus(tgt, tstat); free_tgtstatus(tstat); #else /* !WITH_CSWAP */ fprintf(stderr, _("Crypto-swap is not supported by this installation of cryptmount\n")); eflag = ERR_BADSWAP; #endif bail_out: if (freedev) { /* Tidy-up debris if swapon failed */ do_devshutdown(boundtgt); } if (mntdev != NULL) free((void*)mntdev); return eflag; } /*! @brief Close down an encrypted swap partition * * This provides the back-end functionality for * the '--swapoff' command-line option. * * \see do_swapon(), do_devshutdown(), fs_swapoff(). */ static int do_swapoff(const bound_tgtdefn_t *boundtgt) { const tgtdefn_t *tgt = boundtgt->tgt; int eflag=ERR_NOERROR; char *mntdev=NULL; tgtstat_t *tstat; #if WITH_CSWAP /* Check if device has been configured at all: */ if ((tstat = get_tgtstatus(tgt)) == NULL) { fprintf(stderr, _("Target \"%s\" does not appear to be configured\n"), tgt->ident); eflag = WRN_UNCONFIG; goto bail_out; } /* Remove swap-partition: */ if (fs_swapoff(tgt) != ERR_NOERROR) { eflag = ERR_BADSWAP; goto bail_out; } put_tgtstatus(tgt, NULL); /* Remove supporting device-mapper target etc */ if (do_devshutdown(boundtgt) != ERR_NOERROR) { eflag = ERR_BADDEVICE; } #else /* !WITH_CSWAP */ fprintf(stderr, _("Crypto-swap is not supported by this installation of cryptmount\n")); eflag = ERR_BADSWAP; #endif bail_out: if (mntdev != NULL) free((void*)mntdev); return eflag; } /*! @brief Change access password on particular target * * This provides the back-end functionality for * the '--change-password' command-line option. * * \see cm_get_key(), cm_put_key(). */ static int do_passwd(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt) { tgtdefn_t *tgt = boundtgt->tgt; uint8_t *key = NULL; unsigned keyprops; int keylen = 0, eflag = ERR_NOERROR; char *newfname = NULL, *oldfname = NULL; struct stat sbuff; size_t sz; FILE *fp = NULL; keyprops = cm_get_keyproperties(boundtgt); if ((keyprops & KM_PROP_HASPASSWD) == 0) { fprintf(stderr, _("Key-file for \"%s\" isn't password-protected\n"), tgt->ident); eflag = WRN_NOPASSWD; goto bail_out; } /* Attempt to read current key: */ eflag = cm_get_key(boundtgt, pw_ctxt, &key, &keylen); if (eflag != ERR_NOERROR) goto bail_out; /* Setup location to re-encrypt key: */ if (tgt->key.filename != NULL) { const char *outfname=NULL; if ((keyprops & KM_PROP_FIXEDLOC) == 0) { sz = strlen(tgt->key.filename) + 16; oldfname = (char*)malloc(2 * sz); newfname = oldfname + sz; snprintf(oldfname, sz, "%s-old", tgt->key.filename); snprintf(newfname, sz, "%s-new", tgt->key.filename); fp = fopen(newfname, "wb"); outfname = newfname; } else { fp = fopen(tgt->key.filename, "r+b"); outfname = tgt->key.filename; } if (fp == NULL) { fprintf(stderr, _("Cannot open \"%s\" for writing\n"), outfname); eflag = ERR_BADFILE; goto bail_out; } } eflag = cm_put_key(boundtgt, pw_ctxt, key, keylen, fp); if (fclose(fp) != 0) eflag = ERR_BADFILE; if (eflag != ERR_NOERROR) goto bail_out; /* Replace old key-container with new key-container: */ if (oldfname != NULL && newfname != NULL) { if (stat(tgt->key.filename, &sbuff) != 0 || rename(tgt->key.filename, oldfname) != 0 || chown(oldfname, 0, 0) != 0 || chmod(oldfname, S_IRUSR | S_IWUSR) != 0) { fprintf(stderr, _("Retiring old key (%s -> %s) failed\n"), tgt->key.filename, oldfname); goto bail_out; } if (rename(newfname, tgt->key.filename) != 0 || chown(tgt->key.filename, sbuff.st_uid, sbuff.st_gid) != 0 || chmod(tgt->key.filename, sbuff.st_mode) != 0) { fprintf(stderr, _("Installing new key (%s -> %s) failed\n"), newfname, tgt->key.filename); goto bail_out; } newfname = NULL; fprintf(stderr, _("Backup of previous key is in \"%s\"\n"), oldfname); } bail_out: if (newfname != NULL) { unlink(newfname); } if (oldfname != NULL) free((void*)oldfname); return eflag; } /*! @brief Create new filesystem crypto-key * * This provides the back-end functionality for * the '--generate-key' command-line option. * * \see cm_generate_key(), cm_put_key(). */ static int do_keygen(const km_pw_context_t *pw_ctxt, bound_tgtdefn_t *boundtgt, const char *params, int reuse, const tgtdefn_t *tgttable) { uint8_t *key = NULL; unsigned keyprops; int keylen = 0, fileexists = 0, eflag = ERR_NOERROR; char *newfname = NULL; tgtdefn_t *tgt = boundtgt->tgt; const tgtdefn_t *parent = NULL; bound_tgtdefn_t *boundparent = NULL; size_t sz; struct stat sbuff; FILE *fp = NULL; const unsigned mask_fmtfxd = KM_PROP_FIXEDLOC | KM_PROP_FORMATTED; if (params != NULL) { if (reuse) { parent = get_tgtdefn(tgttable, params); boundparent = bind_tgtdefn(parent); if (parent == NULL || boundparent == NULL) { fprintf(stderr, _("Target name \"%s\" is not recognized\n"), params); eflag = ERR_BADPARAM; } } else { if (sscanf(params, "%i", &keylen) != 1 || keylen < 1) { fprintf(stderr, _("Bad key-length parameter")); eflag = ERR_BADPARAM; } } } if (params == NULL || eflag != ERR_NOERROR) goto bail_out; /* Check if keyfile already exists: */ keyprops = cm_get_keyproperties(boundtgt); fileexists = (tgt->key.filename != NULL && stat(tgt->key.filename, &sbuff) == 0); if (fileexists && (keyprops & mask_fmtfxd) != KM_PROP_FIXEDLOC) { fprintf(stderr,_("Key-file \"%s\" already exists for target \"%s\"\n"), tgt->key.filename, tgt->ident); eflag = ERR_BADFILE; goto bail_out; } /* Assemble new key material: */ if (reuse) { eflag = cm_get_key(boundparent, pw_ctxt, &key, &keylen); } else { fprintf(stderr, _("Generating random key; please be patient...\n")); key = (uint8_t*)sec_realloc(NULL, (size_t)keylen); eflag = cm_generate_key(key, (size_t)keylen); if (eflag != ERR_NOERROR) { fprintf(stderr, _("Failed to generate new key\n")); goto bail_out; } } /* Setup location for new key: */ if (tgt->key.filename != NULL) { const char *outfname=NULL; if ((keyprops & KM_PROP_FIXEDLOC) == 0) { sz = strlen(tgt->key.filename) + 16; newfname = (char*)malloc(sz); snprintf(newfname, sz, "%s-new", tgt->key.filename); fp = fopen(newfname, "wb"); outfname = newfname; } else { fp = fopen(tgt->key.filename, (fileexists ? "r+b" : "wb")); outfname = tgt->key.filename; } if (fp == NULL) { fprintf(stderr, _("Cannot open \"%s\" for writing\n"), outfname); eflag = ERR_BADFILE; goto bail_out; } } eflag = cm_put_key(boundtgt, pw_ctxt, key, keylen, fp); if (fp != NULL && fclose(fp) != 0) eflag = ERR_BADFILE; if (eflag != ERR_NOERROR) goto bail_out; /* Move new key file into prefered location: */ if (newfname != NULL) { if (rename(newfname, tgt->key.filename) != 0 || chown(tgt->key.filename, 0, 0) != 0 || chmod(tgt->key.filename, S_IRUSR | S_IWUSR) != 0) { fprintf(stderr, _("Installation of new keyfile \"%s\" failed"), tgt->key.filename); eflag = ERR_BADFILE; } free((void*)newfname); newfname = NULL; } bail_out: if (newfname != NULL) { unlink(newfname); free((void*)newfname); } if (key != NULL) sec_free((void*)key); if (boundparent != NULL) free_boundtgt(boundparent); return eflag; } /*! @brief Attempt to unmount/shutdown all targets currently mounted. * * This will identify all filesystems listed in cryptmount's own * mounting table (typically /run/cryptmount.status), and try * to unmount, or de-configure, any targets that seem still to be in use. * * This will generally only be useful during a system shutdown, * to provide a safety mechanism for filesystems that have * not been unmounted normally. Accordingly, this routine * is more aggressive in its approach than do_unmount(), do_swapoff(), etc. * * This provides the back-end functionality for * the '--safetynet' command-line option. */ static int do_safetynet() { tgtstat_t *all_tsts=NULL, *tst; char *devname=NULL; const char *old_ident=NULL; tgtdefn_t *tgt=NULL; dev_t *devids=NULL; unsigned devcnt=0; int mflag; struct { unsigned targets, unmounted, unswapped, undeviced, unlooped; } counts = { 0, 0, 0, 0, 0 }; /* This routine is ugly, but may be the best we can do to prevent * damage to filesystems that should have been properly removed * by other mechanisms (e.g. --unmount, --swapoff) */ tgt = alloc_tgtdefn(NULL); old_ident = tgt->ident; /* Get list of all targets in status-file: */ all_tsts = get_all_tgtstatus(); for (tst=all_tsts; tst!=NULL; tst=tst->nx) { ++counts.targets; devmap_path(&devname, tst->ident); tgt->ident = tst->ident; #ifdef DLGT_UMOUNT /* Attempt to unmount filesystem: */ switch (fork()) { case -1: break; case 0: execl(DLGT_UMOUNT, "umount", devname, NULL); break; default: (void)wait(&mflag); break; } if (mflag == 0) ++counts.unmounted; #endif /* DLGT_UMOUNT */ #if WITH_CSWAP /* Attempt to remove swap partition: */ if (swapoff(devname) == 0) ++counts.unswapped; #endif /* WITH_CSWAP */ /* Remove device-mapper device: */ (void)devmap_dependencies(tst->ident, &devcnt, &devids); if (devmap_remove(tst->ident) == ERR_NOERROR) ++counts.undeviced; await_device(devname, 0, 500); /* Free any associated loopback devices: */ if (devcnt > 0 && loop_dellist(devcnt, devids) == 0) ++counts.unlooped; if (devids != NULL) { free((void*)devids); devids = NULL; } /* Remove entry in status-file, having done our best to clean-up: */ (void)put_tgtstatus(tgt, NULL); if (devname != NULL) { free((void*)devname); devname = NULL; } } free_tgtstatus(all_tsts); if (!is_cmstatus_intact()) { char *statpath = NULL; (void)cm_path(&statpath, CM_SYSRUN_PFX, cm_status_filename); if (statpath != NULL) { fprintf(stderr, "%s has been corrupted - removing\n", statpath); unlink(statpath); free(statpath); } } tgt->ident = old_ident; free_tgtdefn(tgt); if (counts.targets != 0) { fprintf(stderr, "Safety-net caught %u targets:\n" "\t%u unmounted, %u swaps removed\n" "\t%u devices removed, %u loopbacks freed\n", counts.targets, counts.unmounted, counts.unswapped, counts.undeviced, counts.unlooped); } return (counts.targets != counts.undeviced); } static void check_priv_opt(const char *opt) /** Check if ordinary user is allowed to perform privileged actions */ { if (getuid() != 0) { fprintf(stderr, _("Only root can use option \"%s\"\n"), opt); exit(EXIT_PRIV); } /* Remove effect of any setuid flags, reverting to real user-id: */ if (seteuid(getuid()) != 0) exit(EXIT_PRIV); } static int check_priv_tgt(const tgtdefn_t *tgt) /** Check if ordinary user is allowed to perform privileged actions */ { if ((tgt->flags & FLG_USER) == 0 && cm_initial_uid != 0) { fprintf(stderr, _("Only root can configure \"%s\"\n"), tgt->ident); return ERR_BADPRIV; } return ERR_NOERROR; } /*! @brief Apply top-level mode-dependent operation to list of targets * * This will mount/unmount/swapon/swapoff the give set of encrypted * filesystems, according to an application-level choice of operating mode. * * \see do_mount(), do_swapon(), do_list(), do_safetynet(), parse_options(). */ static int execute_list(cmmode_t mode, const tgtdefn_t *tgttable, const km_pw_context_t *pw_ctxt, const char *params, const targelt_t *eltlist) { const targelt_t *elt = NULL; bound_tgtdefn_t *boundtgt = NULL; int ignore_eltlist = 1, prio = 0, eflag = ERR_NOERROR; struct passwd *pwent = NULL; const char *username = NULL, *syslogmsg = NULL; pwent = getpwuid(cm_initial_uid); username = (pwent != NULL ? pwent->pw_name : "UNKNOWN"); #if defined(HAVE_SYSLOG) && !defined(TESTING) openlog(PACKAGE, LOG_PID, LOG_AUTHPRIV); #endif /* Execute special-cases of user-selected task: */ switch ((mode & M_MODE_MASK)) { case M_VERSION: fprintf(stderr, "%s-%s\n", PACKAGE_NAME, PACKAGE_VERSION); break; case M_KEYMGRS: do_keymgrlist(); break; case M_LIST: do_list(eltlist); break; case M_STATUS: do_status(eltlist); break; case M_SYSBOOT: do_sysboot_updown(1, tgttable, pw_ctxt); break; case M_SYSQUIT: do_sysboot_updown(0, tgttable, pw_ctxt); break; case M_SAFETYNET: do_safetynet(); break; default: ignore_eltlist = 0; break; } if (ignore_eltlist) eltlist = NULL; /* Apply user-selected operation to list of targets (if present): */ for (elt=eltlist; elt!=NULL && eflagnx) { boundtgt = bind_tgtdefn(elt->tgt); if (boundtgt == NULL) { fprintf(stderr, _("Cannot find key-manager to match target \"%s\"\n"), elt->tgt->ident); eflag = ERR_BADKEYFORMAT; break; } syslogmsg = NULL; prio = LOG_AUTHPRIV | LOG_NOTICE; switch ((mode & M_MODE_MASK)) { case M_PREPARE: syslogmsg = "prepare of \"%s\" by %s %s"; eflag = do_devsetup(pw_ctxt, boundtgt, NULL); break; case M_RELEASE: syslogmsg = "release of \"%s\" by %s %s"; prio = LOG_AUTHPRIV | LOG_NOTICE; eflag = do_devshutdown(boundtgt); if (eflag == WRN_UNCONFIG) syslogmsg = NULL; break; case M_MOUNT: if ((eflag = check_priv_tgt(boundtgt->tgt)) != ERR_NOERROR) break; syslogmsg = "mount of \"%s\" by %s %s"; eflag = do_mount(pw_ctxt, boundtgt); if (eflag == WRN_MOUNTED) syslogmsg = NULL; break; case M_UNMOUNT: if ((eflag = check_priv_tgt(boundtgt->tgt)) != ERR_NOERROR) break; syslogmsg = "unmount of \"%s\" by %s %s"; eflag = do_unmount(boundtgt); if (eflag == WRN_UNCONFIG) syslogmsg = NULL; break; case M_SWAPON: syslogmsg = "swapon \"%s\" by %s %s"; eflag = do_swapon(pw_ctxt, boundtgt); if (eflag == WRN_MOUNTED) syslogmsg = NULL; break; case M_SWAPOFF: syslogmsg = "swapoff \"%s\" by %s %s"; eflag = do_swapoff(boundtgt); if (eflag == WRN_UNCONFIG) syslogmsg = NULL; break; case M_PASSWORD: if ((eflag = check_priv_tgt(boundtgt->tgt)) != ERR_NOERROR) break; syslogmsg = "changing password for \"%s\" by %s %s"; eflag = do_passwd(pw_ctxt, boundtgt); break; case M_KEYGEN: if ((eflag = check_priv_tgt(boundtgt->tgt)) != ERR_NOERROR) break; syslogmsg = "key generation for \"%s\" by %s %s"; eflag = do_keygen(pw_ctxt, boundtgt, params, 0, NULL); break; case M_KEYREU: if ((eflag = check_priv_tgt(boundtgt->tgt)) != ERR_NOERROR) break; syslogmsg = "key generation for \"%s\" by %s %s"; eflag = do_keygen(pw_ctxt, boundtgt, params, 1, tgttable); break; default: break; } /* Suppress benign warning messages when '--all' option is selected: */ if (eflag != 0 && eflag < ERR_threshold && (mode & F_ALL_TARGETS) && (mode & F_NOWARN_ALL)) { eflag = 0; } #ifndef TESTING # ifdef HAVE_SYSLOG if (syslogmsg != NULL) { syslog(prio, syslogmsg, elt->tgt->ident, username, (eflag == ERR_NOERROR ? "succeeded" : "failed")); } # endif #else /* TESTING */ /* Avoid compiler warnings about unused variables: */ eflag += 0 * (prio + (username == NULL) + (syslogmsg == NULL)); #endif free_boundtgt(boundtgt); } #ifdef HAVE_SYSLOG closelog(); #endif return eflag; } static cmmode_t get_defaultmode(int argc, char *argv[]) /** Translate program-name into default action (or just assume M_MOUNT) */ { cmmode_t mode = M_MOUNT; #ifdef WITH_ARGV0 struct modename { cmmode_t mode; const char *name; } modetable[] = { { M_MOUNT, "cryptmount" }, { M_UNMOUNT, "cryptumount" }, { M_UNMOUNT, "cryptunmount" }, #if WITH_CSWAP { M_SWAPON, "cryptswapon" }, { M_SWAPOFF, "cryptswapoff", }, #endif { M_PREPARE, "cryptprepare" }, { M_RELEASE, "cryptrelease" }, { M_MOUNT, NULL } }, *mp; const char *base; if (argc >= 1) { base = strrchr(argv[0], '/'); if (base != NULL) ++base; else base = argv[0]; for (mp=modetable; mp->name!=NULL; ++mp) { if (strcmp(base, mp->name) == 0) { mode = mp->mode; break; } } } #endif return mode; } /** * Parse command-line options to identify a top-level processing mode, * and extract configuration parameters such as key-length, * password source etc. * This routine will also ensure that 'privileged' options are * only accessible to the super-user. */ cmmode_t parse_options(int argc, char *argv[], const char **mode_params, int *passwd_fd, int *config_fd, km_pw_context_t *pw_ctxt) { cmmode_t bare_mode = M_UNSET, mode_flags = 0; enum { ALL_USERS = 0x01, NEEDS_ARG = 0x02, SET_MODE = 0x04, SET_FLAGS = 0x08, NEEDS_TGT = 0x10 }; const char *passwd_fd_str = NULL, *config_fd_str = NULL; struct cm_option { char shortopt; const char *longopt; unsigned flags; const char **argument; cmmode_t newmode; unsigned newflags; }; struct cm_option opt_table[] = { { 'a', "all", ALL_USERS | SET_FLAGS, NULL, M_UNSET, F_ALL_TARGETS }, { 'c', "change-password", ALL_USERS | SET_MODE | SET_FLAGS, NULL, M_PASSWORD, F_NEEDS_TGT }, { 'f', "config-fd", NEEDS_ARG, &config_fd_str, M_UNSET, 0 }, { 'g', "generate-key", NEEDS_ARG | SET_MODE | SET_FLAGS, mode_params, M_KEYGEN, F_NEEDS_TGT }, { 'h', "help", ALL_USERS | SET_MODE, NULL, M_HELP, 0 }, { 'k', "key-managers", ALL_USERS | SET_MODE, NULL, M_KEYMGRS, 0 }, { 'l', "list", ALL_USERS | SET_MODE, NULL, M_LIST, 0 }, { 'm', "mount", ALL_USERS | SET_MODE | SET_FLAGS, NULL, M_MOUNT, F_NEEDS_TGT|F_NOWARN_ALL }, { 'w', "passwd-fd", ALL_USERS | NEEDS_ARG, &passwd_fd_str, M_UNSET, 0 }, { 'p', "prepare", SET_MODE | SET_FLAGS, NULL, M_PREPARE, F_NEEDS_TGT|F_NOWARN_ALL }, { 'r', "release", SET_MODE | SET_FLAGS, NULL, M_RELEASE, F_NEEDS_TGT|F_NOWARN_ALL }, { 'e', "reuse-key", NEEDS_ARG | SET_MODE | SET_FLAGS, mode_params, M_KEYREU, F_NEEDS_TGT }, { 'n', "safetynet", SET_MODE, NULL, M_SAFETYNET, 0 }, { 'S', "status", ALL_USERS | SET_MODE | SET_FLAGS, NULL, M_STATUS }, { 's', "swapon", SET_MODE | SET_FLAGS, NULL, M_SWAPON, F_NEEDS_TGT|F_NOWARN_ALL }, { 'x', "swapoff", SET_MODE | SET_FLAGS, NULL, M_SWAPOFF, F_NEEDS_TGT|F_NOWARN_ALL }, { 'B', "system-boot", SET_MODE, NULL, M_SYSBOOT, 0 }, { 'Q', "system-shutdown", SET_MODE, NULL, M_SYSQUIT, 0 }, { 'u', "unmount", ALL_USERS | SET_MODE | SET_FLAGS, NULL, M_UNMOUNT, F_NEEDS_TGT|F_NOWARN_ALL }, { 'y', "verify-password", ALL_USERS | SET_FLAGS, NULL, M_UNSET, F_VERIFY_PW }, /* FIXME - not implemented? */ { 'v', "version", ALL_USERS | SET_MODE, NULL, M_VERSION, 0 }, #ifdef TESTING { 'D', "config-dir", ALL_USERS | NEEDS_ARG, &test_context.argconfigdir, M_UNSET, 0 }, { 'W', "password", ALL_USERS | NEEDS_ARG, &pw_ctxt->argpasswd[0], M_UNSET, 0 }, { 'N', "newpassword", ALL_USERS | NEEDS_ARG, &pw_ctxt->argpasswd[1], M_UNSET, 0 }, { 'T', "self-test", ALL_USERS | SET_MODE, NULL, M_SELFTEST, 0 }, #endif { '?', NULL, 0, NULL, M_UNSET, 0 } }; const size_t n_options = (sizeof(opt_table) / sizeof(opt_table[0]) - 1); char *shortopts, *spos; int idx = 0, optchar = '\0'; size_t i; shortopts = (char*)malloc(n_options * 2 + 1); spos = shortopts; for (i=0; iflags & ALL_USERS)) { check_priv_opt(selected->longopt); } if ((selected->flags & NEEDS_ARG)) { *selected->argument = optarg; } if ((selected->flags & SET_MODE)) { if (bare_mode == M_UNSET) { bare_mode = selected->newmode; } else { fprintf(stderr, _("Multiple operating modes not supported\n")); exit(1); } } if ((selected->flags & SET_FLAGS)) { mode_flags |= selected->newflags; } } if (optchar == '?') { fprintf(stderr, "%s", _(USAGE_STRING)); exit(EXIT_BADOPT); } if (bare_mode == M_UNSET) bare_mode = get_defaultmode(argc, argv); if (config_fd_str != NULL) sscanf(config_fd_str, "%d", config_fd); if (passwd_fd_str != NULL) sscanf(passwd_fd_str, "%d", passwd_fd); #ifdef _GNU_SOURCE free((void*)longopts); #endif free((void*)shortopts); return (bare_mode | mode_flags); } int main(int argc, char *argv[]) { cmmode_t mode = M_UNSET; const char *mode_params = NULL; char *cmtab = NULL; int config_fd = -1, passwd_fd = -1, eflag = ERR_NOERROR; tgtdefn_t *tgttable=NULL; km_pw_context_t pw_ctxt; const tgtdefn_t *tgt = NULL; targelt_t *eltlist = NULL, **eltptr = &eltlist; #ifdef HAVE_GETTEXT /* setup internationalization of message-strings via gettext(): */ setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif cm_initial_uid = getuid(); init_env_dictionary(); #ifdef TESTING fprintf(stderr, "WARNING!!! cryptmount has been compiled for TESTING only - DO NOT INSTALL\n"); pw_ctxt.argpasswd[0] = pw_ctxt.argpasswd[1] = NULL; test_context.argconfigdir = NULL; #endif if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) { fprintf(stderr, _("Memory-locking failed...\n")); } pw_ctxt.verify = 0; pw_ctxt.debug_level = 0; mode = parse_options(argc, argv, &mode_params, &passwd_fd, &config_fd, &pw_ctxt); #ifdef TESTING if (mode == M_SELFTEST) { eflag = cm_run_tests(); clear_env_dictionary(); return eflag; } #endif (void)cm_path(&cmtab, CM_SYSCONF_PFX, "cmtab"); if ((mode & M_MODE_MASK) == M_HELP) { fprintf(stderr, "%s", _(USAGE_STRING)); exit(EXIT_OK); } /* Configure source of passwords: */ if (passwd_fd >= 0) { pw_ctxt.fd_pw_source = fdopen(passwd_fd, "r"); if (pw_ctxt.fd_pw_source == NULL) { fprintf(stderr, _("Bad file-descriptor (%d)\n"), passwd_fd); exit(EXIT_BADOPT); } } else { pw_ctxt.fd_pw_source = NULL; } /* Check & read-in configuration file: */ #ifndef TESTING if (sycheck_cmtab(cmtab) != ERR_NOERROR) { fprintf(stderr, _("Security failure\n")); exit(EXIT_INSECURE); } #endif if (config_fd >= 0) { tgttable = parse_config_fd(config_fd); } else { tgttable = parse_config(cmtab); } free((void*)cmtab); if (((mode & M_MODE_MASK) == M_LIST || (mode & M_MODE_MASK) == M_STATUS) && optind >= argc) { mode |= F_ALL_TARGETS; } /* if '--all' given, assemble list of targets from entire config-file */ if ((mode & F_ALL_TARGETS) != 0) { if (optind < argc) { fprintf(stderr, _("Trailing command-line arguments given with '--all' option\n")); exit(EXIT_BADOPT); } for (tgt=tgttable; tgt!=NULL; tgt=tgt->nx) { *eltptr = (targelt_t*)malloc(sizeof(targelt_t)); (*eltptr)->tgt = tgt; (*eltptr)->nx = NULL; eltptr = &((*eltptr)->nx); } } /* Assemble list of targets from remaining command-line arguments: */ while (optind < argc) { tgt = get_tgtdefn(tgttable, argv[optind]); if (tgt != NULL) { *eltptr = (targelt_t*)malloc(sizeof(targelt_t)); (*eltptr)->tgt = tgt; (*eltptr)->nx = NULL; eltptr = &((*eltptr)->nx); } else { fprintf(stderr, _("Target name \"%s\" is not recognized\n"), argv[optind]); exit(EXIT_BADTGT); } ++optind; } /* Check security of all targets being processed: */ for (eltptr=&eltlist; *eltptr!=NULL; eltptr=&((*eltptr)->nx)) { tgt = (*eltptr)->tgt; if (sycheck_target(tgt) != ERR_NOERROR) { fprintf(stderr, _("Target security failure for \"%s\"\n"), tgt->ident); exit(EXIT_INSECURE); } } /* Execute user-selected task: */ if ((mode & F_NEEDS_TGT) && eltlist == NULL) { fprintf(stderr, _("No targets specified\n")); exit(EXIT_BADTGT); } eflag = execute_list(mode, tgttable, &pw_ctxt, mode_params, eltlist); free_keymanagers(); /* Tidy-up: */ while (eltlist != NULL) { const targelt_t *elt_rm = eltlist; eltlist = eltlist->nx; free((void*)elt_rm); } free_config(&tgttable); munlockall(); clear_env_dictionary(); return eflag; } /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/cryptmount.h000066400000000000000000000116511465135467200163620ustar00rootroot00000000000000/* * General declarations for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _CRYPTMOUNT_H #define _CRYPTMOUNT_H #include "config.h" #include #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # else typedef unsigned char uint8_t; typedef long int32_t; typedef unsigned long uint32_t; typedef long long int64_t; typedef unsigned long long uint64_t; # endif # define PRId64 "lld" # define SCNi64 "lli" #endif #ifdef HAVE_GETTEXT # include # include # define _(String) gettext(String) # define gettext_noop(String) String # define N_(String) gettext_noop(String) #else # define _(String) (String) # define N_(String) String # define textdomain(Domain) /* empty */ # define bindtextdomain(Package, Directory) /* empty */ #endif extern uid_t cm_initial_uid; enum /*! Exit-codes */ { EXIT_OK = 0, EXIT_BADOPT = 1, EXIT_BADTGT = 2, EXIT_BADEXEC = 3, EXIT_PRIV = 100, EXIT_INSECURE = 101 }; enum /*! Error flags */ { ERR_NOERROR = 0, WRN_UNCONFIG, /*!< Filesystem is already unmounted */ WRN_NOPASSWD, WRN_LOWENTROPY, WRN_MOUNTED, /*!< Filesystem is already mounted */ ERR_threshold = 0x10, /*!< Dividing-line between warnings & errors */ ERR_NOTSUPPORTED, ERR_BADKEYFORMAT, ERR_BADALGORITHM, ERR_BADFILE, /*!< Serious problem with accessing file */ ERR_BADDECRYPT, /*!< Failure to extract cipher key from file */ ERR_BADENCRYPT, ERR_MEMSPACE, ERR_DMSETUP, ERR_BADDEVICE, ERR_BADIOCTL, ERR_BADSUID, ERR_BADPRIV, ERR_BADMOUNT, ERR_BADFSCK, ERR_BADSWAP, ERR_INSECURE, ERR_BADPASSWD, ERR_BADPARAM, ERR_BADMUTEX, ERR_ABORT }; enum /*! Target configuration switches */ { FLG_USER = 0x0001, FLG_FSCK = 0x0002, FLG_MKSWAP = 0x0004, FLG_TRIM = 0x0008, /*!< trim/allow-discards on SSD writes */ FLG_BOOT_MASK = 0xf000, FLG_BOOT_MOUNT = 0x1000, FLG_BOOT_SWAP = 0x2000, FLG_BOOT_PREP = 0x3000, FLG_DEFAULTS = FLG_USER | FLG_FSCK }; /*! @brief Information about the access key for an encrypted filesystem * * Depending on the choice of key-manager, this will either describe * a separate key-file, or a header within the encrypted fileystem itself. * * \see keymanager_t, tgtdefn_t */ typedef struct keyinfo { const char *format; /*!< Type of key file, e.g. 'raw', 'libgcrypt' */ char *filename; char *digestalg; char *cipheralg; long maxlen; /*!< Maximum number of bytes to read from keyfile */ unsigned retries; /*!< Limit on password-entry attempts */ } keyinfo_t; /*! @brief Description of an available encrypted filesystem or device. * * This is typically extracted from a configuration file, containing * details of its name, underlying device, encryption type etc. * This structure can be used to form a linked-list of * cryptmount filesystem-targets. * * \see parse_config(). */ typedef struct tgtdefn { const char *ident; /*!< Unique identifying name */ unsigned flags; /*!< Configuration switches */ char *dev; /*!< Device node or raw file */ int64_t start, length; /*!< Starting sector + num of sectors (or 0, -1) */ char *dir; /*!< Mount-point */ char *fstype; /*!< Filesystem type */ char *mountoptions; /*!< Options passed to 'mount' command */ char *fsckoptions; /*!< Options passed to 'fsck' command */ char *loopdev; /*!< Loopback device to wrap around raw file */ char *supath; /*!< PATH to setup for commands run as root */ char *cipher; /*!< Cipher used on filesystem */ int64_t ivoffset; /*!< Cipher initialization-vector offset */ keyinfo_t key; /*!< Location/format of key */ struct tgtdefn *nx; /*!< Form into linked list */ } tgtdefn_t; #endif /* _CRYPTMOUNT_H */ /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/cryptmount.spec000066400000000000000000000101571465135467200170650ustar00rootroot00000000000000# # rpm spec-file for cryptmount # Copyright 2006-2024, Holger Mueller, Eriks Zelenka & RW Penney # Summary: Let ordinary users mount an encrypted file system Name: cryptmount Version: 6.3.0 Release: 1%{?dist} License: GPL URL: https://github.com/rwpenney/cryptmount Group: System/Filesystems Source0: https://github.com/rwpenney/cryptmount/archive/refs/tags/v%{version}.tar.gz %if 0%{?fedora} #{ # Fedora BuildRequires: cryptsetup-devel libgcrypt-devel systemd-devel Requires: cryptsetup-libs libgcrypt device-mapper #} %else #{ %if 0%{?rhel} #{ # RHEL, CentOS %if 0%{?rhl} >= 7 BuildRequires: cryptsetup-devel libgcrypt-devel systemd-devel Requires: cryptsetup-libs libgcrypt device-mapper %else BuildRequires: cryptsetup-luks-devel libgcrypt-devel Requires: cryptsetup-luks-libs libgcrypt device-mapper %endif #} %else #{ # Default ~openSUSE BuildRequires: libcryptsetup-devel libgcrypt-devel Requires: libcryptsetup12 libgcrypt20 device-mapper #} %endif #} %endif BuildRoot: %{_tmppath}/%{name}-%{version}-root %description cryptmount is a utility for the GNU/Linux operating system which allows an ordinary user to mount an encrypted filing system without requiring superuser privileges. Filesystems can reside on raw disk partitions or ordinary files, with cryptmount automatically configuring device-mapper and loopback devices before mounting. %prep %setup -n %{name}-%{version} %{__perl} -pi.orig -e ' s|^(\s*)chown(\s*root)|\1#chown\2|g; s|/etc/init.d|%{_initrddir}|g; ' Makefile.am Makefile.in %build %configure --enable-delegation --enable-fsck %{__make} %{?_smp_mflags} %install %{__rm} -rf %{buildroot} %{__install} -d -m0755 %{buildroot}%{_initrddir} %{__install} -d -m0755 %{buildroot}%{_sbindir} %{__install} -d -m0755 %{buildroot}/usr/lib/systemd/system %{__make} DESTDIR=%{buildroot} install %find_lang %{name} %clean %{__rm} -rf %{buildroot} %files -f %{name}.lang %defattr(-, root, root, 0755) %doc AUTHORS ChangeLog COPYING README* RELNOTES %doc %{_mandir}/man5/cmtab.5* %doc %{_mandir}/man8/cryptmount*.8* %doc %{_mandir}/*/man5/cmtab.5* %doc %{_mandir}/*/man8/cryptmount*.8* %config(noreplace) %{_sysconfdir}/cryptmount/ %config %{_initrddir}/cryptmount %config /etc/modules-load.d/cryptmount.conf %config /usr/lib/systemd/system/cryptmount.service %{_sbindir}/cryptmount-setup %attr(4751, root, root) %{_bindir}/cryptmount %post /sbin/chkconfig --add cryptmount %preun if [ "$1" = 0 ]; then /sbin/chkconfig --del cryptmount fi %changelog * Sun Jul 28 2024 RW Penney - 6.3.0 -- Preferred device-mapper paths relocated to /dev/disk/by-id * Sat Jan 07 2023 RW Penney - 6.2.0 -- Enabled libudev by default * Sat Oct 08 2022 RW Penney - 6.1.0 -- Refreshed installation documentation and inter-process locking * Sat Sep 03 2022 RW Penney - 6.0 -- Refreshed default ciphers and keymanager * Wed Feb 07 2018 RW Penney - 5.3 -- Improved support for cryptsetup-2.x * Thu Oct 08 2015 RW Penney - 5.2 -- Various bug-fixes and cleanups * Mon May 04 2015 RW Penney - 5.1 -- Improved portability across RPM-based systems * Mon Apr 28 2014 RW Penney - 5.0 -- Migrated LUKS functionality to use libcryptsetup * Mon Dec 23 2013 RW Penney - 4.5 -- Added support for TRIM on SSDs * Tue May 21 2013 RW Penney - 4.4 -- Added support systemd * Thu Dec 29 2011 RW Penney - 4.3 -- Added support for environmental variables in configuration file * Tue May 03 2011 RW Penney - 4.2 -- Added entropy-based protection against accidental swap formatting * Wed Mar 10 2010 RW Penney - 4.1 -- Improved compatability with cryptsetup-1.1 * Mon Jan 05 2009 RW Penney - 4.0 -- Improved password fortification via iterated hashing * Sun Jan 22 2006 Holger Mueller - 0.1-1mr -- RPM spec created cryptmount-6.3.0/debian/000077500000000000000000000000001465135467200152035ustar00rootroot00000000000000cryptmount-6.3.0/debian/changelog000066400000000000000000000271201465135467200170570ustar00rootroot00000000000000cryptmount (6.3.0-1) unstable; urgency=low * New upstream release - Replaced (long-defunct) maintainer forwarding address - Migrated preferred device paths to /dev/disk/by-id/ (Closes: bug#1072996) * Updated to Debian Standards Version 4.7.0 * Relocated systemd files from /lib to /usr/lib (Closes: bug#1073753) -- Dr RW Penney (cryptmount signing key) Sun, 28 Jul 2024 06:30:00 +0000 cryptmount (6.2.0-1+deb12u1) bookworm; urgency=low * Fix for memory-initialization in command-line parser (bug#1038384) - one-line change to source-code, replacing malloc() with calloc() - reduces risk of SEGV crashes when handling unrecognized command-line options -- RW Penney Sat, 15 Jul 2023 10:30:00 +0000 cryptmount (6.2.0-2) unstable; urgency=low * Fix for memory-initialization in command-line parser (Closes: bug#1038384) -- RW Penney Sun, 09 Jul 2023 05:00:00 +0000 cryptmount (6.2.0-1) unstable; urgency=low * New upstream release - migrated device-setup handshaking using libudev -- RW Penney Sat, 07 Jan 2023 16:30:00 +0000 cryptmount (6.1.0-1) unstable; urgency=low * New upstream release - updated German translations (Closes: bug#1019550) - resolved missing French translations - improved inter-process deconfliction -- RW Penney Sat, 08 Oct 2022 16:45:00 +0000 cryptmount (6.0-1) unstable; urgency=low * New upstream release - changed default fileformat in cryptmount-setup to LUKS - broadened support for libgcrypt cipher modes -- RW Penney Sat, 03 Sep 2022 14:45:00 +0000 cryptmount (5.3.3-1) unstable; urgency=low * New upstream release - updated German translations (Closes: bug#978114) * Updated to Debian Standards Version 4.5.1 -- RW Penney Sat, 02 Jan 2021 08:00:00 +0000 cryptmount (5.3.2-1) unstable; urgency=low * New upstream release - various documentation cleanups - fixed (benign) memory leak * Updated to Debian Standards Version 4.4.1 -- RW Penney Sun, 17 Nov 2019 16:20:00 +0000 cryptmount (5.3.1-1) unstable; urgency=low * New upstream release: - fixed memory cleanup error on application exit * Updated to Debian Standards Version 4.3.0 -- RW Penney Sat, 05 Jan 2019 16:20:00 +0000 cryptmount (5.3-1) unstable; urgency=low * New upstream release: - better support of LUKS plain files for cryptsetup 2.x (Closes: bug#888444) -- RW Penney Sat, 17 Mar 2018 18:00:00 +0000 cryptmount (5.2.4-1) unstable; urgency=low * Updated to Debian Standards Version 4.1.3, and debhelper-10 * Added e2fsprogs as recommended package (Closes: bug#887286) * New upstream (minor) release - documentation corrections. -- RW Penney Fri, 19 Jan 2018 06:00:00 +0000 cryptmount (5.2.3-1) unstable; urgency=low * Updated to Debian Standards Version 4.1.2 * New upstream release: - better support for cryptsetup 2.x versions, - better GCC 7.2 support. -- RW Penney Sat, 16 Dec 2017 16:30:00 +0000 cryptmount (5.2.2-1) unstable; urgency=low * Improved error-handling with '--all' command-line option -- RW Penney Sun, 02 Oct 2016 06:00:00 +0000 cryptmount (5.2.1-1) unstable; urgency=low * Updated to Debian Standards Version 3.9.8 * Improved logging output of LSB init.d script (Closes: bug#823076) -- RW Penney Tue, 07 Jun 2016 19:00:00 +0000 cryptmount (5.2-1) unstable; urgency=low * Improved handling of mistyped password in setup script (Closes: bug#795440) * Allow setup of PATH before invoking fsck (Closes: bug#779851) -- RW Penney Sun, 25 Oct 2015 15:00:00 +0000 cryptmount (5.1-3) unstable; urgency=medium * Delegated setup in postinst/postrm to dh-systemd (Closes: bug#798358) -- RW Penney Tue, 08 Sep 2015 16:00:00 +0000 cryptmount (5.1-2) unstable; urgency=medium * Patched installation path for cryptmount.service to be beneath /lib/systemd * Improved postinst/postrm support for systemd * Removed duplicated example configuration file * Rebuilt debian/rules script to use debhelper v7 and dh_autoreconf -- RW Penney Sun, 26 Jul 2015 12:00:00 +0000 cryptmount (5.1-1) unstable; urgency=low * Updated to version 5.1 of upstream package -- RW Penney Sat, 20 Jun 2015 15:00:00 +0000 cryptmount (5.0-2) unstable; urgency=medium * Fixed unprivileged access to LUKS partitions under libcryptsetup-1.6.6 (Closes: bug#759263) * Added cryptographic signature verification to uscan watch file -- RW Penney Sat, 30 Aug 2014 15:40:00 +0000 cryptmount (5.0-1) unstable; urgency=low * Updated to version 5.0 of upstream package -- RW Penney Wed, 30 Apr 2014 18:30:00 +0000 cryptmount (4.5.1-1) unstable; urgency=medium * Patched unexpanded @ETCDIR@ in cryptmount-setup script (Closes: bug#738736) -- RW Penney Sun, 16 Feb 2014 06:30:00 +0000 cryptmount (4.5-1) unstable; urgency=low * Updated to version 4.5 of upstream package * Updated Debian standards version to 3.9.5 -- RW Penney Tue, 14 Jan 2014 20:30:00 +0000 cryptmount (4.4.1-1) unstable; urgency=low * Updated to version 4.4.1 of upstream package * Fixes lintian systemd-related warnings -- RW Penney Fri, 25 Oct 2013 20:00:00 +0000 cryptmount (4.4-1) unstable; urgency=low * Updated to version 4.4 of upstream package * Fixes lintian hardening-no-fortify-functions & hardening-no-relro warnings -- RW Penney Sun, 19 May 2013 20:00:00 +0000 cryptmount (4.3.1-1) unstable; urgency=low * Patched version-specific dependency on libdevmapper (Closes: bug#672678) -- RW Penney Sun, 13 May 2012 20:00:00 +0000 cryptmount (4.3-1) unstable; urgency=low * Added support for setting ownership of vfat partitions (Closes: bug#641476) -- RW Penney Sun, 18 Mar 2012 08:00:00 +0000 cryptmount (4.2.1-1) unstable; urgency=low * Added 'build-arch' and 'build-indep' rules * Updated use of /dev/.udev to first try /run/udev (Closes: bug#644311) -- RW Penney Sun, 09 Oct 2011 12:00:00 +0000 cryptmount (4.2-1) unstable; urgency=low * Updated Debian standards version to 3.9.2 * Fixed wrong fileystem size on optical media (Closes: bug#615865) -- RW Penney Fri, 17 Jun 2011 19:30:00 +0000 cryptmount (4.1-3) unstable; urgency=low * Updated Debian standards version to 3.9.0 -- RW Penney Sun, 01 Aug 2010 20:00:00 +0000 cryptmount (4.1-2) unstable; urgency=low * Updated Debian packaging format to "3.0 (quilt)" -- RW Penney Sun, 20 Jun 2010 20:00:00 +0000 cryptmount (4.1-1) unstable; urgency=low * Updated to version 4.1 of upstream package * Fixed modprobe to work within chroot environment (Closes: bug#562680) * Fixed missing /sbin/udevsettle for LUKS target (Closes: bug#570877) -- RW Penney Thu, 03 Jun 2010 20:00:00 +0000 cryptmount (4.0.2-1) unstable; urgency=low * Updated to version 4.0.2 of upstream package * Fixed deconfiguring targets during system shutdown (Closes: bug#558347) -- RW Penney Sun, 13 Dec 2009 08:00:00 +0000 cryptmount (4.0.1-1) unstable; urgency=low * Updated to version 4.0.1 of upstream package * Patched incorrect dependencies with /etc/init.d scripts (Closes: bug#546502) -- RW Penney Mon, 14 Sep 2009 20:00:00 +0000 cryptmount (4.0-1) unstable; urgency=low * Updated to version 4.0 of upstream package -- RW Penney Mon, 04 May 2009 08:00:00 +0000 cryptmount (3.1.2-1) unstable; urgency=low * Minor update to version 3.1.2 of upstream package * Closes: bug#516922 (Initialization of libgcrypt library) * Clears lintian warnings about sourceforge-redirector in watch-file, and redirection of output of updaterc.d -- RW Penney Sat, 28 Feb 2009 09:00:00 +0000 cryptmount (3.1.1-1) unstable; urgency=low * Minor update to version 3.1.1 of upstream package * Closes: bug#507899 (Latest upstream version not in 'sid') -- RW Penney Fri, 05 Dec 2008 21:00:00 +0000 cryptmount (3.1-1) unstable; urgency=low * Initial release of 3.1-series -- RW Penney Fri, 03 Oct 2008 14:00:00 +0000 cryptmount (3.0.1-1) unstable; urgency=low * Minor update to version 3.0.1 of upstream package * Closes: bug#486687 (Updating German localization) -- RW Penney Sat, 07 Aug 2008 11:00:00 +0000 cryptmount (3.0-1) unstable; urgency=low * Initial release of 3.0-series. * Closes: bug#436676 (Handling of nostrip build-option) * Closes: bug#479682 (Clarifying translation query) * Closes: bug#484727 (Adding German localization) -- RW Penney Sat, 07 Jun 2008 11:00:00 +0000 cryptmount (2.2-1) unstable; urgency=low * Initial release of 2.2-series. * Uploading closes: bug#436676 -- RW Penney Sun, 20 Jan 2008 10:00:00 +0000 cryptmount (2.1-1) unstable; urgency=low * Initial release of 2.1-series. * Uploading closes: bug#420066 -- RW Penney Sun, 05 Aug 2007 10:00:00 +0000 cryptmount (2.0-1) unstable; urgency=low * Initial release of 2.0-series. -- RW Penney Tue, 10 Apr 2007 08:00:00 +0000 cryptmount (1.2.1-1) unstable; urgency=low * Updated to include upstream version 1.2.1 -- RW Penney Fri, 06 Apr 2007 08:00:00 +0000 cryptmount (1.2-3) unstable; urgency=low * Patched /etc/init.d script to ensure dm-crypt kernel-module is loaded * Patched documentation to explain devmapper error messages for bad key-size * Incorporated minor robustness improvements from upstream version 1.2.1 -- RW Penney Sat, 23 Jun 2007 14:00:00 +0000 cryptmount (1.2-2) unstable; urgency=low * Patched postinst script to update rc.d more sensibly * Incorporated Dan O'Huiginn's patch for installation of cmtab.example * Uploading closes: bug#415054 -- RW Penney Fri, 16 Mar 2007 21:00:00 +0000 cryptmount (1.2-1) unstable; urgency=low * Initial release of 1.2-series. -- RW Penney Sun, 15 Oct 2006 16:00:00 +0000 cryptmount (1.1-2) unstable; urgency=low * Added Erich Schubert's patch for init-script to improve POSIX compliance closes: bug#385157 * Added basic LSB headers to init-script -- RW Penney Thu, 31 Aug 2006 19:00:00 +0000 cryptmount (1.1-1) unstable; urgency=low * Initial release of 1.1-series. -- RW Penney Tue, 15 Aug 2006 20:00:00 +0000 cryptmount (1.0.2-1) unstable; urgency=low * Initial release. * Uploading closes: bug#375008 -- RW Penney Tue, 18 Jul 2006 22:00:00 +0000 cryptmount-6.3.0/debian/control000066400000000000000000000027411465135467200166120ustar00rootroot00000000000000Source: cryptmount Section: admin Priority: optional Maintainer: RW Penney Homepage: https://github.com/rwpenney/cryptmount Build-Depends: automake, debhelper-compat (= 12), libcryptsetup-dev (>= 2.0), libdevmapper-dev, libgcrypt20-dev (>= 1.8), pkgconf Rules-Requires-Root: binary-targets Standards-Version: 4.7.0 Package: cryptmount Architecture: linux-any Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: e2fsprogs (>= 1.42.12) Suggests: dmsetup Description: Management of encrypted file systems cryptmount is a utility for creating encrypted filesystems & swap partitions and which allows an ordinary user to mount/unmount filesystems without requiring superuser privileges. . It offers the following features: * easy and safe on-demand access to filesystems without su/sudo; * access passwords can be changed easily without involving the sys-admin; * filesystems can reside on raw disk partitions or ordinary files; * supports LUKS encrypted filesystems created by cryptsetup; * encrypted access keys can be stored on removable media (e.g. USB flash disks); * includes support for encrypted swap partitions; * multiple filesystems can be stored in a single disk partition; * encrypted filesystems can be initialized at boot-up or on demand; * temporary filesystems can be setup via command-line, for use in shell-scripts; * transparent configuration of dm-crypt & loopback devices during mounting; cryptmount-6.3.0/debian/copyright000066400000000000000000000023401465135467200171350ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: cryptmount Upstream-Contact: https://github.com/rwpenney/cryptmount/issues Source: https://github.com/rwpenney/cryptmount License: GPL-2+ Files: * Copyright: (C) 2005 - 2024 RW Penney License: GPL-2+ Files: blowfish.c blowfish.h Copyright: (C) Bruce Schneier License: GPL-2+ License: GPL-2+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file `/usr/share/common-licenses/GPL-2'. cryptmount-6.3.0/debian/cryptmount.lintian-overrides000066400000000000000000000002631465135467200230100ustar00rootroot00000000000000# lintian-override for cryptmount # cryptmount needs to have setuid privileges to be usable by ordinary users cryptmount: elevated-privileges 4755 root/root [usr/bin/cryptmount] cryptmount-6.3.0/debian/docs000066400000000000000000000000401465135467200160500ustar00rootroot00000000000000README.md README.sshfs RELNOTES cryptmount-6.3.0/debian/mkDebPkg000077500000000000000000000060151465135467200166170ustar00rootroot00000000000000#!/bin/sh # Construct debianized package for cryptmount # RW Penney, June 2010 PACKAGE=cryptmount VERSION=`sed -n 's/^AC_INIT[^,]*, *\([^,)]*\).*/\1/p' ../configure.ac` PSEUDO_VERSION="" DEBDIR=$(dirname $(realpath $0)) UPSDIR=.. # $VERSION refers to the true version number associated with a *.tar.gz file # $PSEUDO_VERSION is the stable release number for which a .deb should be generated printHelp() { cat < ${fl}-debtx && mv ${fl}-debtx ${fl} done cat < Forwarded: not-needed EOF quilt refresh cd "${TMPDIR}" cp ${SRCPKG} ${TMPDIR}/${PACKAGE}_${PSEUDO_VERSION}.orig.tar.gz test -e ${SRCPKG}.sig && cp ${SRCPKG}.sig ${TMPDIR}/${PACKAGE}_${PSEUDO_VERSION}.orig.tar.gz.sig dpkg-source -b ${TMPDIR}/${PACKAGE}-${PSEUDO_VERSION} cd "${DEBDIR}" mv ${TMPDIR}/${PACKAGE}_* ./ rm -rf ${TMPDIR} # vim: set ts=4 sw=4 et: cryptmount-6.3.0/debian/patches/000077500000000000000000000000001465135467200166325ustar00rootroot00000000000000cryptmount-6.3.0/debian/patches/init.d-script.patch000066400000000000000000000043731465135467200223510ustar00rootroot00000000000000Description: Add link to /lib/lsb/init-functions /lib/lsb/init-functions is not available in all distros, even if commonplace Author: RW Penney Forwarded: not-needed --- a/sysinit/initscript.in +++ b/sysinit/initscript.in @@ -16,6 +16,8 @@ # filesystems and swap-partitions managed by cryptmount ### END INIT INFO +. /lib/lsb/init-functions + CM_EXE=@EXENAME@ DISK_ID_PATH=/dev/disk/by-id/ @@ -79,7 +79,7 @@ dofilesys() { doALL() { if test -n "${CM_BOOTDV}" -o -n "${CM_BOOTSW}" \ -o -n "${CM_BOOTFS}" -o -n "${CM_EARLYDV}"; then - echo "Using /etc/default/cryptmount is DEPRECATED - please use 'bootaction={mount|swap|prepare}' flags within @SYSCONF_DIR@/cmtab" + log_warning_msg "Using /etc/default/cryptmount is DEPRECATED - please use 'bootaction={mount|swap|prepare}' flags within @SYSCONF_DIR@/cmtab" fi case "$1" in @@ -105,18 +105,20 @@ case "$1" in ${CM_EXE} --system-boot if configured; then - echo "cryptmount ${STAGE}auto-filesystems seem to be already configured" + log_action_msg "cryptmount ${STAGE}auto-filesystems seem to be already configured" else - echo "Starting cryptmount ${STAGE}targets (hit shift/ctrl if short of entropy):" + log_action_begin_msg "Starting cryptmount ${STAGE}targets (hit shift/ctrl if short of entropy)" doALL start + log_action_end_msg 0 fi ;; stop) ${CM_EXE} --system-shutdown if configured; then - echo "Stopping cryptmount ${STAGE}targets:" + log_action_begin_msg "Stopping cryptmount ${STAGE}targets" doALL stop + log_action_end_msg 0 fi ${CM_EXE} --safetynet || true ;; @@ -134,9 +136,9 @@ case "$1" in ;; status) if configured; then - echo "cryptmount ${STAGE}auto-filesystems are in use" + log_action_msg "cryptmount ${STAGE}auto-filesystems are in use" else - echo "cryptmount ${STAGE}auto-filesystems do not appear to be in use" + log_action_msg "cryptmount ${STAGE}auto-filesystems do not appear to be in use" exit 3 fi ;; cryptmount-6.3.0/debian/patches/series000066400000000000000000000000241465135467200200430ustar00rootroot00000000000000init.d-script.patch cryptmount-6.3.0/debian/postinst000066400000000000000000000022521465135467200170120ustar00rootroot00000000000000#! /bin/sh # postinst script for cryptmount # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package # case "$1" in configure) if [ -r /proc/1/root -a /proc/1/root/ -ef /proc/self/root/ ]; then modprobe -q -a dm-mod dm-crypt || true else echo "A chroot environment has been detected - not running 'modprobe dm-crypt'" fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 # vim: set ts=4 sw=4 et: cryptmount-6.3.0/debian/postrm000066400000000000000000000003121465135467200164460ustar00rootroot00000000000000#! /bin/sh # postrm script for cryptmount # # see: dh_installdeb(1) set -e # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 cryptmount-6.3.0/debian/preinst000066400000000000000000000014151465135467200166130ustar00rootroot00000000000000#! /bin/sh # preinst script for cryptmount # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `install' # * `install' # * `upgrade' # * `abort-upgrade' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in install|upgrade) test -L /etc/init.d/cryptmount-early && rm -f /etc/init.d/cryptmount-early ;; abort-upgrade) ;; *) echo "preinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 cryptmount-6.3.0/debian/prerm.ex000066400000000000000000000015631465135467200166730ustar00rootroot00000000000000#! /bin/sh # prerm script for cryptmount # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `upgrade' # * `failed-upgrade' # * `remove' `in-favour' # * `deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in remove|upgrade|deconfigure) ;; failed-upgrade) ;; *) echo "prerm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 cryptmount-6.3.0/debian/rules000077500000000000000000000023221465135467200162620ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. #DH_VERBOSE = 1 # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/default.mk # see FEATURE AREAS in dpkg-buildflags(1) export DEB_BUILD_MAINT_OPTIONS = hardening=+all # see ENVIRONMENT in dpkg-buildflags(1) # package maintainers to append CFLAGS #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic # package maintainers to append LDFLAGS #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed # main packaging script based on dh7 syntax %: dh $@ .PHONY: override_dh_auto_configure override dh_auto_test override_dh_fixperms # debmake generated override targets override_dh_auto_configure: dh_auto_configure -- \ --prefix=/usr --sysconfdir=/etc --with-sysrundir=/run \ --with-systemd --with-systemd-unit-dir=/usr/lib/systemd/system \ --with-libgcrypt --enable-luks \ --enable-delegation --enable-fsck \ --enable-cswap --enable-openssl-compat override_dh_auto_test: true # disable "make test" stage because of strong dependence on system devices override_dh_fixperms: dh_fixperms --exclude usr/bin/cryptmount cryptmount-6.3.0/debian/source/000077500000000000000000000000001465135467200165035ustar00rootroot00000000000000cryptmount-6.3.0/debian/source/format000066400000000000000000000000141465135467200177110ustar00rootroot000000000000003.0 (quilt) cryptmount-6.3.0/debian/upstream/000077500000000000000000000000001465135467200170435ustar00rootroot00000000000000cryptmount-6.3.0/debian/upstream/metadata000066400000000000000000000003261465135467200205470ustar00rootroot00000000000000Reference: Author: RW Penney URL: http://www.rwpenney.uk/software/index.html#cryptmount Bug-Database: https://github.com/rwpenney/cryptmount/issues Repository-Browse: https://github.com/rwpenney/cryptmount cryptmount-6.3.0/debian/upstream/signing-key.asc000066400000000000000000000063411465135467200217630ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- mQGNBGODAZoBDADnlAj2PXQobZJlImVDcffm/OVc+/mHemAJHm7XfsgITRiD0lLb SKDFi/i7IsQizRCydC/gSHtxU48rWLEkho/V7wvj/HxyQg30+wOBMZSmYM9nrEdH 6HT8rCyTvwqjoEci1hJnU8zUeLivum6iIYpQcINocv05eo+ivMAEDJY23EaQyuIT 3WmdwyaLctuqk51P1l42+vh7LQvaSrf7wlOT2Ry+j1KQe0jKGH2+vsdbYre0Pfjy yAF/72ca9pWe8A27kZh5iRYnk/KLP6ZtTzZ69RK7hAErSscGCd7YFSAiB/TI1iTR 3tT0v2VUm4xoL0COJy0KujRRwVVeDIa/SKiuBKKB3c0PHUOsIwNrfqgYMWV21vd6 XRMBNQ0Aj/UvYV/ZOixW659+pMCoCx5Mit26KrzyqMRJNaoSjO44r0bh/TK87wq3 zrfbmeqBlSKWZVrtdKEaf7omhaDlJPIhhlUlExLk8AEY3QS0ONqpOCOOi0qbnh9T 1aqHGC3sYKLNXLUAEQEAAbQ+RHIgUlcgUGVubmV5IChjcnlwdG1vdW50IHNpZ25p bmcga2V5KSA8Y3J5cHRtb3VudEByd3Blbm5leS51az6JAc4EEwEKADgWIQR6CQBR l0UZo+0b1Mumz9VMRAUWDgUCY4MBmgIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIX gAAKCRCmz9VMRAUWDorEDACwDuuSr6OUgaEkEcHFRcwH9YPzc4HrPv72LiKjszgh eAz3z6nvBitM8WJ7bEitZVmgJjZmgr/H7UIS//o9OkDpRUs6XSyvwCzhdBiT3RTF WHLb4v/8MF/A7Nfb/tdZ0Ydn0641j492YUVbt7YmY+1u6wtv8gDi8ewWS4QYPoMj 1x5bYP2YKNBVEdzgKy+kJzPqbDieWuPlBht/bnsp7QG9GdVGMe1/M9xjUoaZDgWF a683P86BSJ8JkotpxIQtKYUISFq+Iwql6ZP48ieQOGq0G4UhREGyjFv0+ZNR/WQC CNz572lZ/BtHHpVAzjjcPjjqFPDAc3/kFJ/juNFZp0MOdBk29Q2LYf7ALlkFtcuk MXtRps8EwQZPVJYYza/VmoGr6OdlJsIJQHk59LIYXBBw3Pe+9gEx4smOwLkfWOH2 Jxc3pcz+ZcLfvQrnRiqiJI3gsaNQPHL3JdrH4hnMpSaAMqn3WAYFkPY8wWHHO8tY hc0cF0hM/kt9ufm40hfW+wmIXQQQEQIAHRYhBHi8Gplh3C2qe/iZ26bYLGW4zvXn BQJjgwewAAoJEKbYLGW4zvXnhGsAoK0HIkI9FT6fcnnUBBqTauxC0UMxAKCdbmE8 Hluo4bUz3Mf+4NKICtr33LQqUlcgUGVubmV5IDxyd3Blbm5leUB1c2Vycy5zb3Vy Y2Vmb3JnZS5uZXQ+iQHOBBMBCgA4FiEEegkAUZdFGaPtG9TLps/VTEQFFg4FAmOD CKoCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQps/VTEQFFg5G3QwAosIe kHpgwxLcy6PjbW1y3GvLVW1KDOhnLuKZU+K3i2aFVvtCHGr4f475N/S9bT7tNyuZ axnBcNi6BgyykCYICZ/iRVXqH/9gYbAzv0aRnUklIveChJ+x4dPKeoj5q8qp74b8 B2e5u8SR80OXN+YPT0IZXY43i7HfLbZMVNuWf9oNH/6eNnY7OT+x00Pb92Xk39Sg oBrvgD9ErbuF6ZFAoqDSiaWiPVdw7wpymZBmPfmJkUpCCDSxf/3kTXXRlzgwRnRe IEVoQ2txGMvmfKstCePpY4aToeyPMIBnhUnoT/bVqt8T8cBqkYj65kfQnyCfHD4f BQdUy46ovm9wYdTSnYfJKt0NTSwEYDlwG8kNM6n+68LThyzbvViaZSswNFn0yeb8 ypEnPT0h44vXIixmDCxc3SVOm0lWbEK32lcWsEquCvoKpdHb1GJIqo2iiM7xHiqx lCRdnvlzBsnas1nzDrd7VuGoz4SbP5yNZsCEUC2BtbF5i0PoHCgfQzTpFHJmuQGN BGODAZoBDADP19WjqA21UAtLYYWPEKWXxbcVpHno5wV5d2KWv7FOtb8i0cdVT2U+ YPH2kebLueDdy4m1YaeG9aJlj4dvzU/gfcAA2zXn2M5bymq7YMoHGqNUIltBAYHU GTnnyMHvWKB7RsCFhDmF5TQowsEf8Fsi6gKQodDJ1yLyOjev//ryyCaIKMU/x/lV hLdf+UCC9DNIGl9JJpoxHHQDnfcq9OvL7mi0aiSSKtmEeok0k9l4T4o1+coHEyTx RjhDnchTVSPWxMsln6/epErIssCSKQG76IRMFcIq5nFprpphHlAevRgd3yOLqj6z TwahAccBlZY63se949UhWtsZTH5V9OPZECpkK94VWev46UYU0o7qPzzGWnUkhBj+ 8Li27rxqibJ6phwfKhUr3YpESfpoUnOFblOod/2UMT9rebYUAyfrfO52Of6eXZVs ZZ9WfKQ97F4kUfsgzuE0Mn39sidw9F/dt36MgsgsLUT9Mo7aBMQ+43DJ4JAOG6mz De1b+S618pkAEQEAAYkBtgQYAQoAIBYhBHoJAFGXRRmj7RvUy6bP1UxEBRYOBQJj gwGaAhsMAAoJEKbP1UxEBRYO9/4L/3mdgaNdl5GsUIDciPH1wiIl6xcLI5idbVPn 0k8Xnlf4E7/ERbyaWhzdZiXnOWSdTxar5KJHQiyCAuEanau/ybs72nXYesKlpPeV lcsnjzHJ+nWxrgWgEURz+nz6kePT9rNxm60NSrN7c7FPwm6hfcqJM376wDFjl750 XkLK2r7cG71KJuT0ePxPo8GQD6TE8KkubIlR2WhS7P+Wmp7BgaBfgQ8YX/mEJqYX tLQmlYTO+uaS4KT5cR3WN741tfn+m21E/3SIJgTS8bPWqIjySKrV3eIVwUZmMvU1 h0WBPdhsJ4Kn0LVcp0EYFm9ODU9UzfK5SihxrltLP9e0kagdBLl0cYcV9xkTj0Zn Po+in6p6dwzlstJVAJQ3JgOgr8RZZruowHZEAwCPIcf/wih8nCbJvXhufH26uYS9 7E+dCWHc5CmzkVz3iOQc8qfND0rEUj8/GSREcxCYvl+vPCMhXjd00tmc54uSllq6 w2VJqS5exof/mNjNSYVsFCl/hk5ofg== =yqIk -----END PGP PUBLIC KEY BLOCK----- cryptmount-6.3.0/debian/watch000066400000000000000000000010141465135467200162300ustar00rootroot00000000000000# uscan watch for cryptmount # run the "uscan" command to check for upstream updates and more. # See uscan(1) for format # Compulsory format-version line: version=4 # Location of cryptographic signature of upstream package: opts=filenamemangle=s%(?:.*?)?[vV]?(\d[\d.]*@ARCHIVE_EXT@)%@PACKAGE@-$1%,\ pgpsigurlmangle=s%(.*?)/tags/[vV]?(\d[\d.]*)(@ARCHIVE_EXT@)%https://github.com/rwpenney/cryptmount/releases/download/v$2/@PACKAGE@-$2$3.asc% \ https://github.com/rwpenney/cryptmount/tags \ (?:|.*/)[vV]?(\d\S*)@ARCHIVE_EXT@ cryptmount-6.3.0/delegates.h.in000066400000000000000000000037121465135467200164770ustar00rootroot00000000000000/* * Delegation-related declations for cryptmount * (C)Copyright 2006-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _DELEGATES_H #define _DELEGATES_H /*! Default PATH to use when running subprocesses as root */ #define CM_DEFAULT_SUPATH "@CM_DEFAULT_SUPATH@" /* Whether to use internal substitutes for mount(8) or umount(8): */ #ifndef ERSATZ_MOUNT # define ERSATZ_MOUNT @ERSATZ_MOUNT@ #endif #ifndef ERSATZ_UMOUNT # define ERSATZ_UMOUNT @ERSATZ_UMOUNT@ #endif /* whether to enable crypto-swap support: */ #ifndef WITH_CSWAP # define WITH_CSWAP @WITH_CSWAP@ #endif /* whether to automatically check filesystem before mounting: */ #ifndef WITH_FSCK # define WITH_FSCK @WITH_FSCK@ #endif #if !ERSATZ_MOUNT /* path of mount(8), e.g. from util-linux package: */ # define DLGT_MOUNT "@PATH_MOUNT@" #endif #if !ERSATZ_UMOUNT /* path of umount(8), e.g. from util-linux package: */ # define DLGT_UMOUNT "@PATH_UMOUNT@" #endif #if WITH_CSWAP /* path of mkswap(8), e.g. from util-linux package: */ # define DLGT_MKSWAP "@PATH_MKSWAP@" #endif #if WITH_FSCK /* path of fsck(8), e.g. from e2fsprogs package: */ # define DLGT_FSCK "@PATH_FSCK@" #endif #endif /* _DELEGATES_H */ /* * (C)Copyright 2006-2023, RW Penney */ cryptmount-6.3.0/dmutils.c000066400000000000000000000205311465135467200156070ustar00rootroot00000000000000/* * Device-mapper utilities for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #if HAVE_SYS_SYSMACROS_H # include #endif #include #include #if HAVE_LIBUDEV # include #endif #if defined(HAVE_LIBDEVMAP) # include #else # error libdevmapper headers are needed to build cryptmount #endif #include "cryptmount.h" #include "dmutils.h" #include "utils.h" #if !HAVE_LIBUDEV struct udev_queue_loc { const char *path; int is_file; } udev_queue_locations[] = { { "/run/udev/queue.bin", 1 }, /* Debian-7.0 has queue beneath /run */ { "/dev/.udev/queue.bin", 1 }, /* Recent udev has file in /dev/.udev */ { "/dev/.udev/queue", 0 } /* Older udev has directory of events */ }; int udev_queue_size(const char *path); int udev_active_dir(const char *path, time_t starttime, double timeout); #endif // !HAVE_LIBUDEV struct dm_task *devmap_prepare(int type, const char *ident) /*! Prepare device-mapper task structure */ { struct dm_task *dmt = NULL; dmt = dm_task_create(type); if (dmt != NULL) { if (!dm_task_set_name(dmt, ident)) { dm_task_destroy(dmt); dmt = NULL; } } return dmt; } /*! @brief Create device-mapper full pathname from target description */ int devmap_path(char **buff, const char *ident) { const char prefix[] = "/dev/disk/by-id/dm-name"; size_t bufflen; // FIXME - kernel 6.9 appears prone to automatically moving devices from /dev/mapper/* into /dev/disk/by-name/dm-name-* bufflen = sizeof(prefix) + strlen(ident) + 1; *buff = (char*)realloc((void*)(*buff), bufflen); snprintf(*buff, bufflen, "%s-%s", prefix, ident); return (int)(bufflen - 1); } int devmap_create(const char *ident, uint64_t blk0, uint64_t blklen, const char *tgttype, const char *params) /* create new device-mapper target & associated device node: */ { struct dm_task *dmt=NULL; struct dm_info dmi; char *devpath=NULL; struct stat sbuff; mode_t mode; dev_t dev; /* create device-mapper target: */ if ((dmt = devmap_prepare(DM_DEVICE_CREATE, ident)) == NULL) { fprintf(stderr, "failed to initialize device-mapper task\n"); return ERR_DMSETUP; } if (!dm_task_add_target(dmt, blk0, blklen, tgttype, params)) { fprintf(stderr, "failed to add device-mapper target \"%s\" { %s }\n", tgttype, params); return ERR_DMSETUP; } if (!dm_task_run(dmt)) { fprintf(stderr, "device-mapper task failed\n"); return ERR_DMSETUP; } if (!dm_task_get_info(dmt, &dmi)) { fprintf(stderr, "device-mapper info not available\n"); return ERR_DMSETUP; } dm_task_destroy(dmt); /* create device node (below /dev?): */ mode = S_IFBLK | S_IRUSR | S_IWUSR; dev = makedev(dmi.major, dmi.minor); devmap_path(&devpath, ident); if (stat(devpath, &sbuff) != 0 && mknod(devpath, mode, dev) != 0) { fprintf(stderr, "device \"%s\" (%u,%u) creation failed\n", devpath, dmi.major, dmi.minor); return ERR_BADDEVICE; } if (devpath != NULL) free((void*)devpath); return ERR_NOERROR; } int devmap_dependencies(const char *ident, unsigned *count, dev_t **devids) { struct dm_task *dmt = NULL; struct dm_deps *deps; unsigned i; int eflag=ERR_NOERROR; if ((dmt = devmap_prepare(DM_DEVICE_DEPS, ident)) == NULL) { fprintf(stderr, "failed to initialize device-mapper task\n"); eflag = ERR_DMSETUP; goto bail_out; } if (!dm_task_run(dmt)) { fprintf(stderr, "device-mapper task failed\n"); eflag = ERR_DMSETUP; goto bail_out; } if ((deps = dm_task_get_deps(dmt)) == NULL) { eflag = ERR_DMSETUP; goto bail_out; } /* copy device info into fresh array: */ *count = deps->count; *devids = (dev_t*)malloc((size_t)(deps->count * sizeof(dev_t))); for (i=0; icount; ++i) (*devids)[i] = (dev_t)deps->device[i]; bail_out: if (dmt != NULL) dm_task_destroy(dmt); return eflag; } /*! @brief Remove device-mapper target and associated device */ int devmap_remove(const char *ident) { struct dm_task *dmt = NULL; struct dm_info dmi; struct stat sbuff; char *devpath = NULL; int eflag = ERR_NOERROR; /* Check device-mapper target is configured & get info: */ if (!is_configured(ident, &dmi)) { eflag = ERR_BADDEVICE; goto bail_out; } /* Remove device node (below /dev?): */ devmap_path(&devpath, ident); if (stat(devpath, &sbuff) != 0) { fprintf(stderr, "unable to stat() device node for %s at %s\n", ident, devpath); eflag = ERR_DMSETUP; goto bail_out; } if ((uint32_t)major(sbuff.st_rdev) == dmi.major && (uint32_t)minor(sbuff.st_rdev) == dmi.minor) { unlink(devpath); } else { fprintf(stderr,"device \"%s\" doesn't match device-mapper info (%d,%d)\n", devpath, dmi.major, dmi.minor); eflag = ERR_BADDEVICE; goto bail_out; } /* Remove device-mapper target: */ if ((dmt = devmap_prepare(DM_DEVICE_REMOVE, ident)) == NULL) { fprintf(stderr, "failed to initialize device-mapper task\n"); eflag = ERR_DMSETUP; goto bail_out; } if (!dm_task_run(dmt)) { fprintf(stderr, "device-mapper task failed\n"); eflag = ERR_DMSETUP; goto bail_out; } bail_out: if (dmt != NULL) dm_task_destroy(dmt); if (devpath != NULL) free((void*)devpath); return eflag; } int is_configured(const char *ident, struct dm_info *dminfo) /*! Check if device-mapper target has been setup & (optionally) get info */ { struct dm_task *dmt = NULL; struct dm_info *dmi, dmi_local; int config = 1; dmi = (dminfo != NULL ? dminfo : &dmi_local); /* Create device-mapper target: */ if (ident == NULL || (dmt = devmap_prepare(DM_DEVICE_INFO, ident)) == NULL || !dm_task_run(dmt) || !dm_task_get_info(dmt, dmi) || !dmi->exists) { config = 0; } if (dmt != NULL) dm_task_destroy(dmt); return config; } int await_device(const char *path, int present, unsigned timeout_ms) /*! Repeatedly check for presence (or absence) of block device */ { int st = -1, t_waited = 0, resolved = 0; struct stat sbuff; struct timespec start_time, now; clock_gettime(CLOCK_REALTIME, &start_time); do { st = stat(path, &sbuff); if (present) { resolved = (st == 0 && (sbuff.st_mode & S_IFMT) == S_IFBLK); } else { resolved = (st != 0 && errno == ENOENT); } if (!resolved) { millisleep(250); } clock_gettime(CLOCK_REALTIME, &now); t_waited = (now.tv_sec - start_time.tv_sec) * 1000 + (now.tv_nsec - start_time.tv_nsec) / 1000000; } while (!resolved && (t_waited < timeout_ms)); if (t_waited >= timeout_ms) { fprintf(stderr, "Timeout in await_device(%s, %d, %u)\n", path, present, timeout_ms); } return (resolved ? 0 : 1); } int await_devmap(const char *ident, int present, unsigned timeout_ms) /*! Wrapper around await_device(), using device-mapper target name */ { char *tgt = NULL; int status = -1; devmap_path(&tgt, ident); status = await_device(tgt, present, timeout_ms); free((void*)tgt); return status; } /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/dmutils.h000066400000000000000000000031461465135467200156170ustar00rootroot00000000000000/* * Declarations for device-mapper utilities for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _DMUTILS_H #define _DMUTILS_H #include "config.h" #include /*! \addtogroup dev_mapper * @{ */ struct dm_task *devmap_prepare(int type, const char *devname); int devmap_path(char **buff, const char *ident); int devmap_create(const char *ident, uint64_t blk0, uint64_t blklen, const char *tgttype, const char *params); int devmap_dependencies(const char *ident, unsigned *count, dev_t **devids); int devmap_remove(const char *ident); int is_configured(const char *ident, struct dm_info *dminfo); int await_device(const char *path, int present, unsigned timeout_ms); int await_devmap(const char *ident, int present, unsigned timeout_ms); /** @} */ #endif /* _DMUTILS_H */ /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/doxyfront.txt000066400000000000000000000032751465135467200165650ustar00rootroot00000000000000/* * Doxygen introductory sections for cryptmount * (C)Copyright 2012-2020, RW Penney */ /*! \mainpage Cryptmount source documentation * * \section sec_intro Introduction * * This document contains details of the source-code of 'cryptmount', * a tool for management of encrypted filesystems under GNU/Linux. * * \sa https://github.com/rwpenney/cryptmount * * \section sec_overview Overview * * Principal components within the within the software archicture * are as follows: * *
    *
  • Top-level routines for setting-up encrypted devices, * e.g. do_devsetup(), do_mount(), do_swapon();
  • *
  • Top-level routines for generating cryptographic keys, * and changing passwords, * e.g. do_keygen(), do_passwd();
  • *
  • Supporting routines for ingesting configuration information * about the available encrypted devices, in the form of * a \ref tgtdefn "target-definition" structure: * e.g. parse_config()
  • *
  • Interfaces to various formats of cryptographic keys * specified by the \ref keymanager "keymanager_t" structure, * with static instances visible via, e.g.: *
      *
    • kmblti_gethandle() - built-in cryptographic functions
    • *
    • kmgcry_gethandle() - libgcrypt
    • *
    • kmluks_gethandle() - LUKS/cryptsetup
    • *
    *
* * \defgroup keymgrs Encryption key management * \defgroup cmtab_utils Target definition and status parsers * \defgroup dev_mapper Device-mapper utilities * \defgroup loop_utils Loop-back device utilities * \defgroup fsys_utils Filesystem setup utilities * \defgroup unit_tests Built-in unit-tests */ # vim: set ts=4 sw=4 et: cryptmount-6.3.0/doxygen.conf.in000066400000000000000000000236061465135467200167210ustar00rootroot00000000000000# Doxyfile 1.7.6.1 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = @PACKAGE@ PROJECT_NUMBER = @PACKAGE_VERSION@ PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = @DOXYGEN_DOCDIR@ CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO SYMBOL_CACHE_SIZE = 0 LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = . luks INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c *.h doxyfront.txt RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = NO GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO GENERATE_TREEVIEW = NO ENUM_VALUES_PER_LINE = 4 USE_INLINE_TREES = NO TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES USE_MATHJAX = NO MATHJAX_RELPATH = http://www.mathjax.org/mathjax MATHJAX_EXTENSIONS = SEARCHENGINE = YES SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4 EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = TESTING=1 EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png INTERACTIVE_SVG = NO DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = YES GENERATE_LEGEND = YES DOT_CLEANUP = YES cryptmount-6.3.0/fsutils.c000066400000000000000000000456441465135467200156330ustar00rootroot00000000000000/* * Filesystem-related utilities for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_SYSMACROS_H # include #endif #include #include #include "cryptmount.h" #include "delegates.h" #include "dmutils.h" #include "fsutils.h" #if WITH_CSWAP # include #endif #ifdef TESTING # include "cmtesting.h" #endif static const char *ETCMTAB = "/etc/mtab", *ETCMTABTMP = "/etc/mtab.cm", *STDPATH = CM_DEFAULT_SUPATH; enum { F_MATCHUID = 0x01, /*!< Set real UID to match effective UID */ F_CLOSE1 = 0x02, /*!< Close stdout on child process */ F_SETPATH = 0x04 /*!< Set standard PATH for child process */ }; static int run_sucommand(const char *path, const char *argv[], const char *supath, unsigned switches); int do_addmntent(const tgtdefn_t *tgt); int do_rmvmntent(const tgtdefn_t *tgt); static char **split_fsckopts(const char *fsckoptions, unsigned *argc) /*! Split options separated by ';' into vector of strings */ { const char SEP = ';'; const char *pos, *posnext; size_t optlen; char **opttable=NULL; size_t tablesize = 0; *argc = 0; if (fsckoptions == NULL || *fsckoptions == '\0') return opttable; pos = fsckoptions; do { if (*argc >= tablesize) { tablesize = (tablesize + 8) * 2; opttable = (char**)realloc((void*)opttable, (size_t)(tablesize * sizeof(char*))); } posnext = pos; optlen = 0; while (*posnext != SEP && *posnext != '\0') { ++posnext; ++optlen; } opttable[*argc] = (char*)malloc(optlen + 1); strncpy(opttable[*argc], pos, optlen); opttable[*argc][optlen] = '\0'; ++*argc; pos = posnext + 1; } while (*posnext != '\0'); return opttable; } #if ERSATZ_MOUNT static int parse_mountoptions(const char *buff, unsigned long *mflags) /*! Convert string of mount-options into binary flags */ { struct fsopt_t { const char *str; unsigned long mask; }; struct fsopt_t fsopts[] = { { "defaults", 0 }, { "noatime", MS_NOATIME }, { "nodev", MS_NODEV }, { "noexec", MS_NOEXEC }, { "nosuid", MS_NOSUID }, { "ro", MS_RDONLY }, { "sync", MS_SYNCHRONOUS }, { NULL, 0 } }; unsigned idx,len; *mflags = 0; if (buff == NULL) return 0; for (;;) { for (len=0; buff[len]!='\0' && buff[len]!=','; ++len); for (idx=0; fsopts[idx].str!=NULL; ++idx) { if (strncmp(buff, fsopts[idx].str, (size_t)len) == 0) { *mflags |= fsopts[idx].mask; break; } } if (fsopts[idx].str == NULL) { fprintf(stderr, "bad option \"%s\"\n", buff); return 1; } if (buff[len] == '\0') break; buff += len + 1; } return 0; } int fs_mount(const char *mntdev, const tgtdefn_t *tgt) /*! Fallback version of mount(8) using mount(2) */ { unsigned long mflags; int eflag=ERR_NOERROR; char *errstr=NULL; if (parse_mountoptions(tgt->mountoptions, &mflags) != 0) { return ERR_BADMOUNT; } errstr = (char*)malloc((size_t)(strlen(mntdev) + strlen(tgt->dir) + 64)); sprintf(errstr, "mounting \"%s\" on \"%s\" failed", mntdev, tgt->dir); if (mount(mntdev, tgt->dir, tgt->fstype, mflags, NULL) == 0) { (void)do_addmntent(tgt); } else { perror(errstr); eflag = ERR_BADMOUNT; } free((void*)errstr); return eflag; } #else /* !ERSATZ_MOUNT */ int fs_mount(const char *dev, const tgtdefn_t *tgt) /*! Delegate filesystem mounting to mount(8) */ { int idx, stat, eflag=ERR_NOERROR; const char *argv[16]; /* Construct argument list for mount -t ... -o ... */ idx = 0; argv[idx++] = "[cryptmount-mount]"; if (tgt->fstype != NULL) { argv[idx++] = "-t"; argv[idx++] = tgt->fstype; } if (tgt->mountoptions != NULL) { argv[idx++] = "-o"; argv[idx++] = tgt->mountoptions; } argv[idx++] = dev; argv[idx++] = tgt->dir; argv[idx++] = NULL; stat = run_sucommand(DLGT_MOUNT, argv, tgt->supath, F_MATCHUID); eflag = (stat != 0 ? ERR_BADMOUNT: ERR_NOERROR); return eflag; } #endif /* ERSATZ_MOUNT */ #if ERSATZ_UMOUNT int fs_unmount(const tgtdefn_t *tgt) /*! Fallback version of umount(8) using umount(2) */ { int eflag=ERR_NOERROR; char *errstr=NULL; errstr = (char*)malloc((size_t)(strlen(tgt->dir) + 64)); sprintf(errstr, "unmounting \"%s\" failed", tgt->dir); if (umount(tgt->dir) == 0) { (void)do_rmvmntent(tgt); } else { perror(errstr); eflag = ERR_BADMOUNT; } free((void*)errstr); return eflag; } #else /* !ERSATZ_UMOUNT */ int fs_unmount(const tgtdefn_t *tgt) /*! Delegate filesystem mounting to umount(8) */ { int idx, stat, eflag=ERR_NOERROR; const char *argv[16]; /* Construct argument list for umount -t ... */ idx = 0; argv[idx++] = "[cryptmount-umount]"; #ifdef PARANOID if (tgt->fstype != NULL) { argv[idx++] = "-t"; argv[idx++] = tgt->fstype; } if (tgt->mountoptions != NULL) { argv[idx++] = "-O"; argv[idx++] = tgt->mountoptions; } #endif argv[idx++] = tgt->dir; argv[idx++] = NULL; stat = run_sucommand(DLGT_UMOUNT, argv, tgt->supath, F_MATCHUID); eflag = (stat != 0 ? ERR_BADMOUNT: ERR_NOERROR); return eflag; } #endif /* ERSATZ_UMOUNT */ #if WITH_CSWAP int fs_swapon(const char *mntdev, const tgtdefn_t *tgt) /*! Install \a mntdev as a new swap device */ { int idx, stat, prio, rawprio = 0x100, expendable = 0, eflag=ERR_NOERROR; const char *argv[8]; double cry_entropy = 0.0, raw_entropy = 0.0; const size_t entrosize = 1 << 20; const double blank_thresh = 1e-5, noise_thresh = 7.0; if (strcmp(tgt->fstype,"swap") != 0) { fprintf(stderr, _("Unsuitable filesystem type \"%s\" for swapping\n"), tgt->fstype); eflag = ERR_BADSWAP; goto bail_out; } /* Measure entropy of filesystem and underlying raw device to check whether it's safe to force mkswap to format what it thinks is a whole disk(!), or which could be a file containing wanted data: */ raw_entropy = fs_entropy(tgt->dev, entrosize); cry_entropy = fs_entropy(mntdev, entrosize); expendable = (raw_entropy < blank_thresh) || (cry_entropy < blank_thresh) || (raw_entropy > noise_thresh && cry_entropy > noise_thresh); if ((tgt->flags & FLG_MKSWAP) != 0) { if (expendable) { /* Construct argument list for mkswap */ idx = 0; argv[idx++] = "[cryptmount-mkswap]"; if (expendable) argv[idx++] = "-f"; argv[idx++] = mntdev; argv[idx++] = NULL; stat = run_sucommand(DLGT_MKSWAP, argv, tgt->supath, F_CLOSE1); eflag = (stat != 0 ? ERR_BADSWAP : ERR_NOERROR); if (eflag != ERR_NOERROR) goto bail_out; } else { fprintf(stderr, _("Device \"%s\" appears to contain data (entropy=%.3g,%.3g) - please run mkswap manually\n"), tgt->dev, raw_entropy, cry_entropy); } } if (tgt->mountoptions != NULL && sscanf(tgt->mountoptions, "pri=%i", &prio) == 1) { rawprio = prio; } prio = ( SWAP_FLAG_PREFER | ((rawprio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK) ); if (swapon(mntdev, prio) != 0) { eflag = ERR_BADSWAP; goto bail_out; } bail_out: return eflag; } int fs_swapoff(const tgtdefn_t *tgt) { char *mntdev=NULL; int eflag=ERR_NOERROR; if (strcmp(tgt->fstype,"swap") != 0) { eflag = ERR_BADSWAP; goto bail_out; } devmap_path(&mntdev, tgt->ident); if (swapoff(mntdev) != 0) { eflag = ERR_BADSWAP; goto bail_out; } bail_out: if (mntdev != NULL) free((void*)mntdev); return eflag; } #endif /* WITH_CSWAP */ int do_addmntent(const tgtdefn_t *tgt) /*! Add entry into /etc/mtab for newly-mounted filing system */ { char *mntdev = NULL; struct mntent mntinfo; FILE *fp; int eflag=ERR_NOERROR; devmap_path(&mntdev, tgt->ident); mntinfo.mnt_fsname = mntdev; mntinfo.mnt_dir = tgt->dir; mntinfo.mnt_type = tgt->fstype; mntinfo.mnt_opts = "none"; mntinfo.mnt_freq = 0; mntinfo.mnt_passno = 0; fp = setmntent(ETCMTAB, "a"); if (fp == NULL) { eflag = ERR_BADFILE; goto bail_out; } (void)addmntent(fp, &mntinfo); endmntent(fp); bail_out: if (mntdev != NULL) free((void*)mntdev); return eflag; } int do_rmvmntent(const tgtdefn_t *tgt) /*! Remove entry from /etc/mtab after unmounting filing system */ { char *mntdev=NULL; struct mntent *mntinfo; FILE *fp_in=NULL,*fp_out=NULL; struct stat sbuff; int i,eflag=ERR_NOERROR,found=0; /* FIXME - add lots more checks on integrity: */ devmap_path(&mntdev, tgt->ident); /* Open old /etc/mtab & create temporary replacement: */ fp_in = setmntent(ETCMTAB, "r"); fp_out = setmntent(ETCMTABTMP, "w"); if (fp_in == NULL || fp_out == NULL) { eflag = ERR_BADFILE; goto bail_out; } i = stat(ETCMTAB, &sbuff); if (i != 0 || !S_ISREG(sbuff.st_mode)) { fprintf(stderr, "%s is not a valid file\n", ETCMTAB); eflag = ERR_BADFILE; goto bail_out; } /* Transfer entries from old /etc/mtab to prototype replacement file: */ while ((mntinfo = getmntent(fp_in)) != NULL) { if (strcmp(mntinfo->mnt_fsname, mntdev) == 0 && strcmp(mntinfo->mnt_dir, tgt->dir) == 0) { ++found; } else { addmntent(fp_out, mntinfo); } } /* Transfer ownership & permissions from old /etc/mtab to new: */ if (chown(ETCMTABTMP, sbuff.st_uid, sbuff.st_gid) != 0 || chmod(ETCMTABTMP, sbuff.st_mode) != 0) { fprintf(stderr, "cannot transfer ownership/modes to \"%s\"\n", ETCMTABTMP); eflag = ERR_BADFILE; goto bail_out; } endmntent(fp_in); fp_in = NULL; if (rename(ETCMTABTMP, ETCMTAB)) { fprintf(stderr, "Failed to recreate %s\n", ETCMTAB); } bail_out: if (fp_in != NULL) endmntent(fp_in); if (fp_out != NULL) endmntent(fp_out); if (mntdev != NULL) free((void*)mntdev); return eflag; } /*! * Check whether a filesystem target is mounted. * * This will examine entries in /etc/mtab via getmntent(), * looking for a filesystem whose major and minor device numbers * match those of the block device associated with the supplied target. * * Note that this will return false for targets that refer * to swap partitions, even if they are active. */ int is_mounted(const tgtdefn_t *tgt) { int mounted = 0; char *mntdev = NULL; struct mntent *mntinfo; struct stat st_mtb, st_tgt; FILE *fp; /* check if underlying device has been configured at all: */ if (!is_configured(tgt->ident, NULL)) return 0; /* find path to device that would have been mounted & device info: */ devmap_path(&mntdev, tgt->ident); if (stat(mntdev, &st_tgt) != 0) { mounted = 0; goto bail_out; } /* check entries in /etc/mtab: */ fp = setmntent(ETCMTAB, "r"); if (fp == NULL) { /* indeterminate case - assume not mounted */ mounted = 0; goto bail_out; } while ((mntinfo = getmntent(fp)) != NULL && !mounted) { if (stat(mntinfo->mnt_fsname, &st_mtb) != 0) continue; /* compare to mounted device on basis of kernel device maj/min: */ if (major(st_mtb.st_rdev) == major(st_tgt.st_rdev) && minor(st_mtb.st_rdev) == minor(st_tgt.st_rdev)) { mounted = 1; } } endmntent(fp); bail_out: if (mntdev) free((void*)mntdev); return mounted; } int is_readonlyfs(const char *path) /*! Check if filesystem containing *path is read-only */ { struct statvfs sbuff; return (path == NULL || (statvfs(path, &sbuff) != 0 || (sbuff.f_flag & ST_RDONLY) != 0)); } #if WITH_FSCK int fs_check(const char *dev, const tgtdefn_t *tgt) /*! Run 'fsck' on target filesystem */ { int idx, stat, eflag=ERR_NOERROR; unsigned pos, n_opts = 0; const char **opts = NULL, **argv = NULL; if (tgt->fsckoptions != NULL) { opts = (const char**)split_fsckopts(tgt->fsckoptions, &n_opts); } argv = (const char**)malloc((16 + n_opts) * sizeof(char*)); /* Construct argument list for fsck -T -t ... */ idx = 0; argv[idx++] = "[cryptmount-fsck]"; argv[idx++] = "-T"; if (tgt->fstype != NULL) { argv[idx++] = "-t"; argv[idx++] = tgt->fstype; } for (pos=0; possupath, F_MATCHUID | F_SETPATH); eflag = ((stat == 0 || stat == 1) ? ERR_NOERROR : ERR_BADFSCK); if (opts != NULL) { for (pos=0; pos sizeof(buff)) chunk = sizeof(buff); step = read(fd, (void*)buff, chunk); if (step <= 0) break; for (i=0; i 0) { for (i=0; i<256; ++i) { if (counts[i] == 0) continue; plogp -= counts[i] * log((double)counts[i]); } plogp = (plogp / totcount) + log((double)totcount); } plogp /= log(2.0); free((void*)counts); close(fd); return plogp; } #if !ERSATZ_MOUNT || !ERSATZ_UMOUNT || WITH_FSCK || WITH_CSWAP static int run_sucommand(const char *path, const char **argv, const char *supath, unsigned switches) /*! Fork (& wait for) system-command as root */ { pid_t child; int stat=-1, fd; switch ((child = fork())) { case -1: /* fork failed */ fprintf(stderr, "failed to fork (%s)\n", path); break; case 0: /* child fork */ if ((switches & F_MATCHUID) != 0) { /* change real UID to match effective UID (probably only useful if euid==root): */ if (setuid(geteuid()) != 0) exit(EXIT_BADEXEC); } if ((switches & F_CLOSE1) != 0) { /* redirect standard output to /dev/null */ fd = open("/dev/null", O_WRONLY); if (fd >= 0) (void)dup2(fd, STDOUT_FILENO); else (void)close(STDOUT_FILENO); } if ((switches & F_SETPATH) != 0) { if (supath == NULL) supath = STDPATH; if (setenv("PATH", supath, 1) != 0) { exit(EXIT_BADEXEC); } } execv(path, (char *const *)argv); fprintf(stderr, "failed to invoke \"%s\"\n", path); exit(EXIT_BADEXEC); break; default: /* parent fork */ if (waitpid(child, &fd, 0) == child) { stat = fd; } break; } return stat; } #endif /* !ERSATZ_MOUNT ... */ #ifdef TESTING /*! \addtogroup unit_tests * @{ */ int fs_test_splitopts() { char **opttable, buff[256]; unsigned argc, idx, limit; const char *SEP = ";", *optsrc[] = { "The", "rain", "in", "Spain", "falls", "mainly", "in", "the", "plain", ",allegedly", NULL }; CM_TEST_START("Splitting fsck options"); argc = 17; opttable = split_fsckopts(NULL, &argc); CM_ASSERT_EQUAL(0, argc); CM_ASSERT_EQUAL(NULL, opttable); argc = 34; opttable = split_fsckopts("", &argc); CM_ASSERT_EQUAL(0, argc); CM_ASSERT_EQUAL(NULL, opttable); for (limit=0; optsrc[limit] != NULL; ++limit) { buff[0] = '\0'; for (idx=0; idx<=limit; ++idx) { strcat(buff, optsrc[idx]); if (idx < limit) strcat(buff, SEP); } opttable = split_fsckopts(buff, &argc); CM_ASSERT_EQUAL((limit+1), argc); for (idx=0; idx 1e-2) CM_TEST_FAIL("Mismatch"); } (void)unlink(fname); CM_TEST_OK(); } /** @} */ #endif /* TESTING */ /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/fsutils.h000066400000000000000000000026531465135467200156310ustar00rootroot00000000000000/* * Declarations for filesytem-related utilities for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _FSUTILS_H #define _FSUTILS_H /*! \addtogroup fsys_utils * @{ */ struct tgtdefn; int fs_check(const char *dev, const struct tgtdefn *tgt); int fs_mount(const char *dev, const struct tgtdefn *tgt); int fs_unmount(const struct tgtdefn *tgt); int fs_swapon(const char *dev, const struct tgtdefn *tgt); int fs_swapoff(const struct tgtdefn *tgt); int is_mounted(const struct tgtdefn *tgt); int is_readonlyfs(const char *path); double fs_entropy(const char *dev, const size_t blklen); /** @} */ #endif /* _FSUTILS_H */ /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/looputils.c000066400000000000000000000203521465135467200161610ustar00rootroot00000000000000/* * Loopback-device utilities for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #if HAVE_SYS_SYSMACROS_H # include #endif #include #ifdef HAVE_LINUX_LOOP_H # include #else # error loop.h kernel-header is needed to build cryptmount #endif #include #include "cryptmount.h" #include "looputils.h" char *cm_strdup(const char *orig); /** * Format-strings for loopback devices, * covering legacy /dev/loop/0 style * as well as current /dev/loop0 style. */ static const char *loop_formats[] = { "/dev/loop%u", "/dev/loop/%u", NULL }; /** * Search for vacant loopback device. * * For recent kernels (>=3.1), this will use the /dev/loop-control * interface, while for older kernels this will involve explicit * search through /dev/loop0..255 for a device whose status indicates * that it not associated with a backing file. */ int loop_findfree(char *buff, size_t buffsz) { unsigned found = 0; int devfd, devno; char loopname[256] = ""; #ifdef LOOP_CTL_GET_FREE devfd = open("/dev/loop-control", O_RDWR); devno = ioctl(devfd, LOOP_CTL_GET_FREE); close(devfd); if (devfd >=0 && devno >= 0) { snprintf(loopname, sizeof(loopname), "/dev/loop%d", devno); found = 1; } #else for (devno=0; devno<256 && !found; ++devno) { unsigned idx; struct loop_info64 linfo; struct stat sbuff; for (idx=0; loop_formats[idx]!=NULL && !found; ++idx) { snprintf(loopname, sizeof(loopname), loop_formats[idx], (unsigned)devno); if (stat(loopname, &sbuff) || !S_ISBLK(sbuff.st_mode)) continue; devfd = open(loopname, O_RDONLY); if (devfd < 0) continue; if (ioctl(devfd, LOOP_GET_STATUS64, &linfo) && errno == ENXIO) { found = 1; } close(devfd); } } #endif /* LOOP_CTL_GET_FREE */ if (found && buff != NULL) strncpy(buff, loopname, buffsz); return !found; } int loop_setup(const char *dev, const char *file, int flags) /** Setup loopback device to point to regular file */ { int devfd = -1, filefd = -1, eflag = ERR_NOERROR; struct loop_info64 lpinfo; memset((void*)&lpinfo, 0, sizeof(lpinfo)); strncpy((char*)lpinfo.lo_file_name, file, (size_t)LO_NAME_SIZE); lpinfo.lo_offset = 0; lpinfo.lo_encrypt_key_size = 0; devfd = open(dev, flags); #ifdef LOOP_CTL_ADD if (devfd < 0) { unsigned devno = ~0u; int ctlfd; sscanf(dev, loop_formats[0], &devno); ctlfd = open("/dev/loop-control", O_RDWR); (void)ioctl(ctlfd, LOOP_CTL_ADD, devno); close(ctlfd); devfd = open(dev, flags); } #endif if (devfd < 0) { fprintf(stderr, "Cannot open \"%s\" for reading\n", dev); eflag = ERR_BADFILE; goto bail_out; } filefd = open(file, flags); if (filefd < 0) { fprintf(stderr, "Cannot open \"%s\" for reading\n", file); eflag = ERR_BADFILE; goto bail_out; } if (ioctl(devfd, LOOP_SET_FD, filefd) || ioctl(devfd, LOOP_SET_STATUS64, &lpinfo)) { fprintf(stderr, "LOOP_SET_FD ioctl() failed on \"%s\"\n", dev); eflag = ERR_BADIOCTL; goto bail_out; } bail_out: if (filefd >= 0) close(filefd); if (devfd >= 0) close(devfd); return eflag; } int loop_destroy(const char *dev) /** Detach loopback device from underlying file */ { int devfd; int eflag = ERR_NOERROR; devfd = open(dev, O_RDONLY); if (devfd < 0) { fprintf(stderr, "Cannot open \"%s\" for reading\n", dev); eflag = ERR_BADFILE; goto bail_out; } if (ioctl(devfd, LOOP_CLR_FD, 0)) { fprintf(stderr, "LOOP_CLR_FD ioctl() failed on \"%s\"\n", dev); eflag = ERR_BADIOCTL; goto bail_out; } #ifdef LOOP_CTL_REMOVE { int devno = -1, ctlfd; sscanf(dev, loop_formats[0], &devno); ctlfd = open("/dev/loop-control", O_RDWR); (void)ioctl(ctlfd, LOOP_CTL_REMOVE, devno); close(ctlfd); } #endif bail_out: if (devfd >= 0) (void)close(devfd); return eflag; } int loop_ident(unsigned maj, unsigned min, char *buff, size_t buffsz) /** Find device node for given minor device number */ { unsigned idx; int found=0; char str[256]; struct stat sbuff; if (maj != LOOP_MAJOR) return !found; for (idx=0; loop_formats[idx]!=NULL && !found; ++idx) { sprintf(str, loop_formats[idx], min); if (stat(str, &sbuff) || !S_ISBLK(sbuff.st_mode)) continue; found = ((unsigned)major(sbuff.st_rdev) == maj && (unsigned)minor(sbuff.st_rdev) == min); } if (found && buff != NULL) strncpy(buff, str, buffsz); return !found; } int loop_dellist(unsigned devcnt, const dev_t *devids) /** Tidy-up list of loopback devices */ { unsigned i; char buff[256]; int eflag = 0; if (devids == NULL) return eflag; for (i=0; i #include /*! \addtogroup loop_utils * @{ */ int loop_findfree(char *buff, size_t buffsz); int loop_setup(const char *dev, const char *file, int flags); int loop_ident(unsigned maj, unsigned min, char *buff, size_t buffsz); int loop_destroy(const char *dev); int loop_dellist(unsigned devcnt, const dev_t *devids); int blockify_file(const char *filename, int fmode, const char *prefdev, const char **devname, int *isloop); int unblockify_file(const char **devname, int isloop); /** @} */ #endif /* _LOOPUTILS_H */ /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/man/000077500000000000000000000000001465135467200145345ustar00rootroot00000000000000cryptmount-6.3.0/man/Makefile.am000066400000000000000000000003261465135467200165710ustar00rootroot00000000000000man_MANS = cmtab.5 cryptmount.8 cryptmount-setup.8 EXTRA_DIST = makeman.defs cmtab.5.in cryptmount.8.in cryptmount-setup.8.in SUBDIRS = fr include ${top_srcdir}/man/makeman.defs clean-local: -rm -f ${man_MANS} cryptmount-6.3.0/man/cmtab.5.in000066400000000000000000000457421465135467200163310ustar00rootroot00000000000000.\" cmtab (cryptmount) manual page .\" (C)Copyright 2005-2024 RW Penney .\" .\" ---- macro definitions ---- .de Sh \" Subsection heading .br .ne 5 .PP \fB\\$1\fR .PP .. .TH CMTAB 5 "2024-07-28" "@PACKAGE_VERSION@" "User commands" .SH NAME cmtab \- static information about filesystems managed by cryptmount .\" -------------------------------- .SH DESCRIPTION Information about the encrypted filesystems managed by .B cryptmount is contained in the file @CM_SYSCONF_DIR@/cmtab. Each filesystem is labelled by a target name which can be used as an argument to .B cryptmount and which appears in @CM_SYSCONF_DIR@/cmtab in front of a list of parameters describing where that filesystem is stored, and how it is encrypted. The format of the cmtab is flexible, with the description of each target being delimited by braces, parameters being specified by KEY=VALUE pairs, and white-space being freely usable. Comments are prefixed by a \(aq#' character, and can start at any point in a line, lasting to the end of the line. The backslash character \(aq\\' can be used to ignore any special significance of the following character, for example to include a space in a filename. @CM_SYSCONF_DIR@/cmtab contains entries of the following form: .sp .nf TARGET_NAME { dev=DEVICE # REQUIRED flags=FLAG,FLAG,... startsector=STARTSECTOR numsectors=NUMSECTORS loop=LOOPDEV dir=MOUNT_POINT # REQUIRED fstype=TYPE # REQUIRED mountoptions=MOPT,MOPT,... fsckoptions=FOPT;FOPT;... supath=SUPATH bootaction=BOOTACTION cipher=CIPHER ivoffset=IVOFFSET keyformat=KEYMANAGER keyfile=KEYFILE # REQUIRED keyhash=KEYHASH keycipher=KEYCIPHER keymaxlen=KEYMAXLEN passwdretries=NUMATTEMPTS } .fi Some fields, such as \(aqdev' and \(aqfstype' are mandatory, although many fields have sensible default values. Depending on the choice of KEYMANAGER, fields such as \(aqkeyhash', \(aqkeycipher', \(aqkeymaxlen' may need to be set explicitly. Any field which contains non-numerical values (e.g. not \(aqstartsector', \(aqivoffset' etc.) can contain references to environmental variables of the form $(HOME). The following variables are recognized, all based on the characteristics of the user currently running .B cryptmount : .sp .nf $(HOME) # the home directory, as obtained from /etc/passwd $(UID) # the numerical identifier of the user $(USERNAME) # the printable name of the user $(GID) # the numerical identifier of the user's current group $(GROUPNAME) # the printable name of the user's current group .fi .\" -------------------------------- .SH TARGET DEFINITIONS The components in each target definition have the following meaning: .TP .B TARGET_NAME { ... } specifies the name that cryptmount uses to refer to a particular filesystem, with configuration options for that filesystem contained within the matching braces. The special name "_DEFAULTS_" may be used to set default values in subsequent targets for various parameters such as 'flags', 'fstype', 'mountoptions', 'cipher', 'keyformat', 'keyhash', 'keycipher', 'keymaxlen', 'passwdretries'. Note that if the "_DEFAULTS_" target appears more than once, each will undo the effects of previous default values - i.e. this pseudo-target does not operate incrementally. .\" ---- .TP .B dev=DEVICE\t(required) sets the name of the raw device (e.g. /dev/sdb63) or ordinary file (e.g. /home/secretiveuser/private.fs) that contains the encrypted filesystem. Note that it may be useful to use a symbolic name based on an entry beneath /dev/disk/by-id, /dev/disk/by-path, to reduce the risk of device nodes being renamed when new disks are added to the system, etc. .\" ---- .TP .B flags=FLAG,FLAG,... sets configuration switches, such as .br * "user" (any user can mount), .br * "nouser" (only root can mount), .br * "fsck" (automatically check filesystem before mounting), .br * "nofsck" (don't check filesystem before mounting), .br * "mkswap" (format swap partition before use), .br * "nomkswap" (don't format swap partition) .br * "trim" (enable TRIM/discard support on solid-state disks), .br * "notrim" (disable SSD TRIM/discard support) .br This parameter is optional and defaults to "user,fsck,nomkswap,notrim". .\" ---- .TP .B startsector=STARTSECTOR gives the number of sectors (512-byte blocks) into .B DEVICE at which the filesystem is to start. This parameter is optional, and defaults to zero. .\" ---- .TP .B numsectors=NUMSECTORS gives the total length of the filesystem in sectors (512-byte blocks). This parameter is optional, and defaults to \-1 which is shorthand for the total available length of .BR DEVICE . .\" ---- .TP .B loop=LOOPDEV can be used to specify a particular loopback device (e.g. /dev/loop0) to be used when DEVICE is an ordinary file. This parameter is optional and defaults to "auto". .TP .B dir=MOUNT_POINT\t(required) specifies the directory onto which the encrypted filesystem will be mounted. .\" ---- .TP .B fstype=TYPE\t(required) sets the filesystem type (as used by .B mount (8)). This must be set to "swap" if the device is to be used as an encrypted swap partition. .\" ---- .TP .B mountoptions=MOPT,MOPT,... sets filesystem mounting options, as used by .B mount (8). MOPT can typically be "default", "noatime", "noexec", "nosuid", "ro", "sync" etc. .\" ---- .TP .B fsckoptions=FOPT;FOPT;... sets filesystem-checking options understood by .B fsck (8). FOPT can typically be "\-C", "\-V" etc. Note that the list of fsck options uses semicolons as a separator to allow passing options that themselves contain commas. .\" ---- .TP .B supath=SUPATH sets the PATH environment variable when running subprocesses as the super-user. This may be necessary when commands such as .B fsck and .B mount need to run subcommands (e.g. fsck.ext4). By default, this PATH is set to @CM_DEFAULT_SUPATH@. .\" ---- .TP .B bootaction=BOOTACTION indicates what action, if any, should be taken for this target on system bootup. BOOTACTION can be one of "none", "mount", "swap" or "prepare", with the default being "none". .TP .B cipher=CIPHER sets the encryption algorithm used on the .BR DEVICE . The available algorithms are determined by the system kernel. This parameter is optional and defaults to "@CM_DEFAULT_CIPHER@". .\" ---- .TP .B keyformat=KEYMANAGER specifies the key management scheme used to interact with the .BR KEYFILE , as discussed in the .B CHOICE OF KEYMANAGER section below. The set of available key management schemes is determined when .B cryptmount is built, but may include "libgcrypt", "luks", and "openssl-compat", in addition to "builtin" and "raw". This parameter is optional: if absent, "builtin" will be used on first generating the key, with an automatic choice being made when reading a pre-existing key. .\" ---- .TP .B keyfile=KEYFILE\t(required) gives the name of an ordinary file that contains the key used by the .B CIPHER algorithm to decrypt the filesystem. This key is itself encrypted in a way specified by the .B KEYHASH and .B KEYCIPHER \. .TP .B ivoffset=IVOFFSET sets the offset added to the sector-number used in constructing the cipher algorithm's initialization vector. This parameter is optional, and defaults to 0. .\" ---- .TP .B keyhash=KEYHASH is the hashing algorithm used to turn the user's password into the decryption key used by the .B KEYCIPHER algorithm. The available hashing algorithms are determined by the chosen key-encryption engine specified by .BR KEYMANAGER . This parameter is optional and the default depends on the value of .BR KEYMANAGER . .\" ---- .TP .B keycipher=KEYCIPHER is the encryption algorithm used to secure the decryption key of the filesystem itself. The available key-encryption algorithms are determined by the chosen key-encryption engine specified by .BR KEYMANAGER . This parameter is optional and the default depends on the value of .BR KEYMANAGER . .\" ---- .TP .B keymaxlen=KEYMAXLEN is the maximum number of bytes of the decryption key that will be read from .BR KEYFILE . This parameter is optional, and defaults to 0, indicating that the full length of .B KEYFILE should be read. .\" ---- .TP .B passwdretries=NUMATTEMPTS is the number of password-entry attempts that can be made before cryptmount will exit with an error-code when trying to mount or configure the target. .\" -------------------------------- .SH CHOICE OF KEYMANAGER .B cryptmount supports a variety of different ways of protecting the access key associated with each encrypted filesystem. For most users, the default \*(lqbuiltin\*(rq keymanager will provide a good level of security and flexibility. Alternative keymanagers offer a wider choice of different password-hashing schemes and compatibility with other encryption tools. The strengths and weaknesses of the different keymanagers are discussed below. .Sh builtin This keymanager is supported by cryptmount-2.0 or later, and uses a separate key-file. A password-based key derivation function (PBKDF) using the SHA1 hashing algorithm, together with blowfish-cbc encryption is used to protect the filesystem key. That key-derivation function was changed in cryptmount-4.0 to improve the security of new keyfiles, while preserving compatibility with existing keyfiles. If you need to write keyfiles in the previous format, you can specify \*(lqkeyformat=builtin:0\*(rq. The KEYHASH and KEYCIPHER parameters are ignored. .Sh libgcrypt This keymanager is supported by cryptmount-1.1 or later, and uses a separate key-file. A password-based key derivation function (PBKDF) is used to protect the filesystem key, with any hashing or cipher algorithm supported by the installed version of the libgcrypt library being available. .Sh luks This keymanager is supported by cryptmount-3.1 or later, and provided compatibility with the Linux Unified Key Setup (LUKS) disk-format. Instead of a separate keyfile, LUKS uses a header within the encrypted filesystem itself. It is advisable to choose the same value for both the 'dev' and 'keyfile' parameters, or leave 'keyfile' unspecified. As with all cryptmount filesystems, the 'dev' parameter may point to either a raw disk partition or an ordinary file. However, because of the filesystem structure assumed by LUKS, it is strongly recommended that you do not use either the 'startsector' or 'numsector' parameters. .Sh openssl/openssl-compat This keymanager has been supported since the earliest release of cryptmount, and uses a separate keyfile which is compatible with the format used by the 'openssl' command-line encryption tool. Since cryptmount-3.0 this file-format has been provided via the libgcrypt library, and is preferably specified by \*(lqkeyformat=openssl-compat\*(rq. A password-based key derivation function (PBKDF) is used to protect the filesystem key, with a choice of hashing or cipher algorithms being available. Most algorithms supported by the 'openssl' command-line tool should be available, provided the underlying algorithms are available within libgcrypt. .Sh password This keymanager is supported by cryptmount\-4.0 or later, and does not require any separate keyfile, but instead derives the filesystem key directly from the user's password. This means that it is not possible to change the access password without re-encrypting the entire filesystem. The 'keyhash' and 'keycipher' parameters are ignored. .Sh raw This keymanager is supported by cryptmount\-1.1 or later, and uses a separate keyfile where the access key is stored directly and .IR "without any encryption" . This keymanager is most useful for managing encrypted swap partitions, where the keyfile can be chosen as /dev/random, and hence where the access key will be different every time it is read. If the keyfile is an ordinary file, it offers minimal security, and should preferably be stored separately from the disk containing the encrypted filesystem, e.g. on a USB flash disk. .\" -------------------------------- .SH SECURITY Because .B cryptmount needs to operate with setuid privileges, it is very important that its configuration file is kept secure. Ideally @CM_SYSCONF_DIR@/cmtab should be managed only by the system administrator, and all key-files should be readable only by their owner. .B cryptmount makes basic checks on the security of @CM_SYSCONF_DIR@/cmtab each time it runs, and will refuse to operate unless the following conditions are met: .br * cmtab must be owned by root .br * cmtab must be a regular file .br * cmtab must not be globally writable .br * the directory containing cmtab must be owned by root .br * the directory containing cmtab must not be globally writable .br In addition, for each target within @CM_SYSCONF_DIR@/cmtab, all paths must be absolute (i.e. starting with '/'). When using unencrypted keyfiles (i.e. when .B KEYMANAGER is "raw"), it is recommended that the .B KEYFILE is stored with access permissions no less restrictive than 0600, or on a removable device such as a USB flash-disk. (With recent versions of .B cryptmount the "builtin" key-format should be portable between different installations and vastly more secure than "raw" keyfiles.) It is very important that you do not lose or damage the .B KEYFILE as this file is essential to providing access to your encrypted filesystem. You are strongly advised to consider keeping a backup of your .B KEYFILE in some form. .\" -------------------------------- .SH ENCRYPTED SWAP PARTITIONS & AUTO-FORMATTING When the 'mkswap' option is selected for a particular target within @CM_SYSCONF_DIR@/cmtab, .B cryptmount will attempt to automatically format an encrypted swap partition whenever you run "cryptmount \-\-swapon ". This is often useful when there is no need to preserve swap data between reboots, such as when not using the kernel's hibernation features. Because reformatting will destroy any existing data on the chosen swap partition, .B cryptmount will do some basic checking on the first megabyte of the partition, based on the degree of randomness (entropy) in the current contents. If the partition looks like it contains pure noise, or has been zeroed, then the partition will be formatted automatically. If .B cryptmount determines that the partition may contain non-random data, then it will ask you to run 'mkswap' manually. As there is no fool-proof way of determining whether a partition (especially after encryption) contains valuable data, you should be very careful about the raw device chosen for any target on which you select the 'mkswap' option. .\" -------------------------------- .SH EXAMPLE FILE The following example of @CM_SYSCONF_DIR@/cmtab consists of five targets, using a variety of encryption algorithms and storing their filesystems in different ways, including a target representing an encrypted swap partition: .sp .nf # @CM_SYSCONF_DIR@/cmtab # example file \- please modify before use _DEFAULTS_ { passwdretries=3 # allow 3 password attempts by default } luks { # partition created by cryptsetup-luks dev=/dev/sdb63 dir=/mnt/luks-partition-$(USERNAME) keyformat=luks fstype=ext3 } basic { dev=/home/secretiveuser/crypt.fs dir=/home/secretiveuser/crypt # where to mount loop=auto # find free loop\-device fstype=ext3 mountoptions=default cipher=aes-cbc-plain # filesystem encryption keyfile=/home/secretiveuser/crypt.key # use default sha1/blowfish key-encryption: keyformat=builtin } partition { dev=/dev/sdb62 # use whole disk partition dir=/mnt/crypt62 fstype=ext3 mountoptions=nosuid,noexec cipher=serpent-cbc-plain # information about file used to store decryption key: keyfile=@CM_SYSCONF_DIR@/crypt_sdb62.key keyformat=openssl # use OpenSSL key-encryption keyhash=md5 keycipher=bf\-cbc # encryption of key file } subset { dev=/dev/sdb63 startsector=512 numsectors=16384 # use subset of partition dir=/mnt/encrypted\\ subset\\ of\\ sdb fstype=reiserfs mountoptions=defaults cipher=twofish-cbc-plain # filesystem encryption # information about file used to store decryption key: keyfile=@CM_SYSCONF_DIR@/crypt_sdb63.key keyformat=libgcrypt keyhash=md5 keycipher=blowfish\-cbc # encryption of key file } encswap { # encrypted swap partition bootaction=swap dev=/dev/disk/by-id/scsi-SATA_ST500_ABCDEFG-part37 startsector=16896 numsectors=1024 # use subset of partition fstype=swap flags=mkswap cipher=twofish-cbc-plain # read fresh 16-byte key from /dev/random whenever used: keyfile=/dev/random keymaxlen=16 keyformat=raw } # end of cmtab .fi The 'basic' target uses an ordinary file "/home/secretiveuser/crypt.fs" to store the encrypted filesystem, perhaps within a normal user's home directory. A loopback device will be automatically allocated (because of the "loop=auto") by .B cryptmount to turn this into a block-special device, before mounting. The decryption key for the filesystem is also stored in this user's home directory, making it easier for them to change the password protecting the key. The 'partition' target uses a whole disk partition to store the encrypted filesystem, with the decryption key stored in the main .B cryptmount configuration directory. The 'subset' target is similar to the 'partition' target except that it does not use a whole disk partition. This would allow other groups of blocks within that partition to be used for other filesystems managed via .B cryptmount or .B dmsetup. The 'encswap' target uses a subset of blocks within a disk partition to form an encrypted swap device. A new encryption key is read from the system random-number generator /dev/random every time the target is used. ___DELETE_CSWAP_1 Note that the current installation of .B cryptmount does not appear to have support for crypto-swap enabled. ___END_CSWAP_1 The 'luks' target provides access to an encrypted partition created by the 'cryptsetup-luks' utility. By using the environmental variable $(USERNAME), the filesystem's mount-point will vary depending on which user invokes .B cryptmount. For example, user 'joe' would find the filesystem mounted below /mnt/luks-partition-joe. .B cryptmount will be able to mount and unmount the partition, but various advanced LUKS features must be accessed through .B cryptsetup .\" -------------------------------- .SH FILES .I @CM_SYSCONF_DIR@/cmtab - main configuration file .SH "SEE ALSO" .BR cryptmount (8), .BR cryptmount-setup (8), .BR cryptsetup (8), .BR dmsetup (8), .BR openssl (1) .\" -------------------------------- .SH COPYRIGHT NOTICE .B cryptmount is Copyright 2005-2024, RW Penney .br and is supplied with NO WARRANTY. Licencing terms are as described in the file "COPYING" within the cryptmount source distribution. .\" vim: set ts=4 sw=4 et: cryptmount-6.3.0/man/cryptmount-setup.8.in000066400000000000000000000020551465135467200206160ustar00rootroot00000000000000.\" cryptmount-setup manual page .\" (C)Copyright 2007-2023 RW Penney .\" .TH CRYPTMOUNT-SETUP 8 "2023-01-07" "@PACKAGE_VERSION@" "User commands" .SH NAME cryptmount-setup \- setup a new encrypted filesystem .\" -------------------------------- .SH SYNOPSIS .BI "cryptmount-setup" .\" -------------------------------- .SH DESCRIPTION .B cryptmount-setup assists in the initial configuration of an encrypted filesystem, to be managed by .B cryptmount (8). If run by the superuser, .B cryptmount-setup will allow a basic LUKS-encrypted filesystem to be created within an ordinary file. The size, location, mount-point and ownership of the filesystem can be selected interactively. For more advanced options, please see the manual page for .B cryptmount (8) or .B cmtab (5) .SH "SEE ALSO" .BR cmtab (5) .BR cryptmount (8) .\" -------------------------------- .SH COPYRIGHT NOTICE .B cryptmount is Copyright 2005-2023, RW Penney .br and is supplied with NO WARRANTY. Licencing terms are as described in the file "COPYING" within the cryptmount source distribution. cryptmount-6.3.0/man/cryptmount.8.in000066400000000000000000000306351465135467200174650ustar00rootroot00000000000000.\" cryptmount manual page .\" (C)Copyright 2005-2024 RW Penney .\" .TH CRYPTMOUNT 8 "2024-07-21" "@PACKAGE_VERSION@" "User commands" .SH NAME cryptmount \- mount/unmount/configure an encrypted filesystem .\" -------------------------------- .SH SYNOPSIS .BI "cryptmount \fITARGET\fR [\fITARGET ...\fR]" .LP .BI "cryptmount \-\-unmount \fITARGET\fR [\fITARGET ...\fR]" .LP .BI "cryptmount \-\-change\-password \fITARGET\fR" .LP .BI "cryptmount \-\-generate\-key \fISIZE\fP \fITARGET\fR" ___DELETE_CSWAP_0 .LP .BI "cryptmount \-\-swapon \fITARGET\fR" .LP .BI "cryptmount \-\-swapoff \fITARGET\fR" ___END_CSWAP_0 .\" -------------------------------- .SH DESCRIPTION .B cryptmount allows an encrypted filesystem to be mounted or unmounted, without requiring superuser privileges, and assists the superuser in creating new encrypted filesystems. After initial configuration of the filesystem by the system administrator, the user needs only to provide the decryption password for that filing system in order for .B cryptmount to automatically configure device-mapper and loopback targets before mounting the filesystem. .B cryptmount was written in response to differences between the newer device-mapper infrastructure of the linux-2.6 kernel series, and the older cryptoloop infrastructure which allowed ordinary users access to encrypted filesystems directly through .B mount (8). .\" -------------------------------- .SH OPTIONS .TP .B \-a \-\-all act on all available targets, e.g. for mounting all targets. .TP .B \-m \-\-mount mount the specified target, configuring any required device-mapper or loopback devices. The user will be asked to supply a password to unlock the decryption key for the filesystem. .TP .B \-u \-\-unmount unmount the specified target, and deconfigure any underlying device-mapper or loopback devices. No password is required, although the operation will fail if the filesystem is in use, or if a non-root user tries to unmount a filesystem mounted by a different user. .TP .B \-S \-\-status provide information on whether the specified target is currently mounted or not .TP .B \-l \-\-list lists all available targets, including basic information about the filesystem and mount point of each. .TP .B \-c \-\-change\-password change the password protecting the decryption key for a given filesystem. .TP .B \-g \-\-generate\-key "\fIsize\fP" setup a decryption key for a new filesystem. .IR size\fP gives the length of the key in bytes. .TP .B \-e \-\-reuse\-key "\fIexisting-target\fP" setup a decryption key for a new filesystem, using an existing key from another filesystem, for example to translate between different file-formats for storing a single key. This option is only available to the superuser. .TP .B \-f \-\-config\-fd "\fInum\fP" read configuration information about targets from file-descriptor .IR num\fP instead of the default configuration file. This option is only available to the superuser. .TP .B \-w \-\-passwd\-fd "\fInum\fP" read passwords from file-descriptor .IR num\fP instead of from the terminal, e.g. for using cryptmount within scripts or GUI wrappers. Each password is read once only, in contrast to terminal-based operation where new passwords would be requested twice for verification. .TP .B \-p \-\-prepare prepare all the device-mapper and loopback devices needed to access a target, but do not mount. This is intended to allow the superuser to install a filesystem on an encrypted device. .TP .B \-r \-\-release releases all device-mapper and loopback devices associated with a particular target. This option is only available to the superuser. ___DELETE_CSWAP_0 .TP .B \-s \-\-swapon enable the specified target for paging and swapping. This option is only available to the superuser. .TP .B \-x \-\-swapoff disable the specified target for paging and swapping. This option is only available to the superuser. ___END_CSWAP_0 .TP .B \-k \-\-key-managers list all the available formats for protecting the filesystem access keys. .TP .B \-B \-\-system-boot setup all targets which have declared a "bootaction" parameter. This will typically be used to automatically mount encrypted filesystems, or setup encrypted swap partitions, on system startup. This option is only available to the superuser. .TP .B \-Q \-\-system-shutdown close-down all targets which have declared a "bootaction" parameter. This is essentially the opposite of the "\-\-system-boot" option. .TP .B \-n \-\-safetynet attempts to close-down any mounted targets that should normally have been shutdown with \-\-unmount or \-\-swapoff. This option is only available to the superuser, and intended .B exclusively for use during shutdown/reboot of the operating system. .TP .B \-v \-\-version show the version-number of the installed program. .\" -------------------------------- .SH RETURN CODES .B cryptmount returns zero on success. A non-zero value indicates a failure of some form, as follows: .TP .B 1 unrecognized command-line option; .TP .B 2 unrecognized filesystem target name; .TP .B 3 failed to execute helper program; .TP .B 100 insufficient privilege; .TP .B 101 security failure in installation. .\" -------------------------------- .SH EXAMPLE USAGE In order to create a new encrypted filesystem managed by cryptmount, you can use the supplied 'cryptmount-setup' program, which can be used by the superuser to interactively configure a basic setup. Alternatively, a manual setup allows more control of configuration settings. Before doing so, one should ensure that kernel support for /dev/loop and /dev/mapper is available, e.g. via .sp .nf modprobe \-a loop dm\-crypt .fi Now suppose that we wish to setup a new encrypted filesystem, that will have a target-name of "opaque". If we have a free disk partition available, say /dev/sdb63, then we can use this directly to store the encrypted filesystem. Alternatively, if we want to store the encrypted filesystem within an ordinary file, we need to create space using a recipe such as: .sp .nf dd if=/dev/zero of=/home/opaque.fs bs=1M count=512 .fi .sp and then replace all occurrences of '/dev/sdb63' in the following with '/home/opaque.fs'. (/dev/urandom can be used in place of /dev/zero, debatably for extra security, but is rather slower.) First, we need to add an entry in @CM_SYSCONF_DIR@/cmtab, which describes the encryption that will be used to protect the filesystem itself and the access key, as follows: .sp .nf opaque { dev=/dev/sdb63 dir=/home/crypt fstype=ext2 mountoptions=defaults cipher=twofish keyfile=@CM_SYSCONF_DIR@/opaque.key keyformat=builtin } .fi Here, we will be using the "twofish" algorithm to encrypt the filesystem itself, with the built-in key-manager being used to protect the decryption key (to be stored in @CM_SYSCONF_DIR@/opaque.key). In order to generate a secret decryption key (in @CM_SYSCONF_DIR@/opaque.key) that will be used to encrypt the filesystem itself, we can execute, as root: .sp .nf cryptmount \-\-generate\-key 32 opaque .fi This will generate a 32-byte (256-bit) key, which is known to be supported by the Twofish cipher algorithm, and store it in encrypted form after asking the system administrator for a password. If we now execute, as root: .sp .nf cryptmount \-\-prepare opaque .fi .sp we will then be asked for the password that we used when setting up @CM_SYSCONF_DIR@/opaque.key, which will enable .B cryptmount to setup a device-mapper target (/dev/disk/by-id/dm-name-opaque). (If you receive an error message of the form .B "device-mapper ioctl cmd 9 failed: Invalid argument", this may mean that you have chosen a key-size that isn't supported by your chosen cipher algorithm. You can get some information about suitable key-sizes by checking the output from "more /proc/crypto", and looking at the "min keysize" and "max keysize" fields.) We can now use standard tools to create the actual filesystem on /dev/disk/by-id/dm-name-opaque: .sp .nf mke2fs /dev/disk/by-id/dm-name-opaque .fi .sp (It may be advisable, after the filesystem is first mounted, to check that the permissions of the top-level directory created by mke2fs are appropriate for your needs.) After executing .sp .nf cryptmount \-\-release opaque mkdir /home/crypt .fi .sp the encrypted filesystem is ready for use. Ordinary users can mount it by typing .sp .nf cryptmount \-m opaque .fi .sp or .sp .nf cryptmount opaque .fi .sp and unmount it using .sp .nf cryptmount \-u opaque .fi .B cryptmount keeps a record of which user mounted each filesystem in order to provide a locking mechanism to ensure that only the same user (or root) can unmount it. .\" -------------------------------- .SH PASSWORD CHANGING After a filesystem has been in use for a while, one may want to change the access password. For an example target called "opaque", this can be performed by executing: .sp .nf cryptmount \-\-change\-password opaque .fi After successfully supplying the old password, one can then choose a new password which will be used to re-encrypt the access key for the filesystem. (The filesystem itself is not altered or re-encrypted.) .\" -------------------------------- .SH LUKS ENCRYPTED FILESYSTEMS .B cryptmount can be used to provide easy access to encrypted filesystems compatible with the Linux Unified Key Setup (LUKS) capabilities of the .B cryptsetup application. In order to access an existing LUKS partition, an entry needs to be created within @CM_SYSCONF_DIR@/cmtab. For example, if the hard-disk partition /dev/sdb62 is used to contain a LUKS encrypted ext3 filesystem, an entry of the form: .sp .nf LUKS { keyformat=luks dev=/dev/sdb62 keyfile=/dev/sdb62 dir=/home/luks-dir fstype=ext3 } .fi .sp would allow this to be mounted via .B cryptmount beneath /home/luks-dir by executing .sp .nf cryptmount LUKS .fi .B cryptmount will also allow any user that knows one of the access-passwords to change their password via .sp .nf cryptmount \-\-change-password LUKS .fi .B cryptmount also provides basic support for creating new LUKS encrypted filesystems, which can be placed within ordinary files as well as disk partitions, via the '\-\-generate-key' recipe shown above. However, to exploit the full range of functionality within LUKS, such as for adding multiple passwords, one needs to use .B cryptsetup It is strongly recommended that you do not attempt to use LUKS support in combination with cryptmount's features for storing .I multiple encrypted filesystems within a single disk partition or an ordinary file. This is because of assumptions within the cryptsetup-luks design that the LUKS key-material is always stored at the beginning of the disk partition. ___DELETE_FSCK_1 .\" -------------------------------- .SH FILESYSTEM MAINTENANCE For filesystems that are mounted on system-startup, it is normal for checks on their integrity to be performed automatically at regular intervals, typically every few dozen mounts. If .B cryptmount has not been compiled with the '\-\-enable\-fsck' option, such checks need to be performed manually for filesystems managed by .B cryptmount , which will require the involvement of both the system administrator and the users who know the relevant access passwords for the filesystems involved. Suppose that we wish to check the filesystem associated with .B cryptmount target 'opaque', we first need to prepare the decryption devices: .sp .nf cryptmount \-\-prepare opaque .fi .sp this will create a device-mapper target accessible via '/dev/disk/by-id/dm-name-opaque', on which we can then run standard checking utilities: .sp .nf fsck \-t auto /dev/disk/by-id/dm-name-opaque .fi After these tests have been completed, we can then release the devices: .sp .nf cryptmount \-\-release opaque .fi .sp and continue using the filesystem as before. ___END_FSCK_1 .\" -------------------------------- .SH FILES .I @CM_SYSCONF_DIR@/cmtab - main configuration file .LP .I @CM_SYSRUN_DIR@/cryptmount.status - record of mounted filesystems .SH "SEE ALSO" .BR cmtab (5), .BR cryptmount-setup (8), .BR cryptsetup (8), ___DELETE_FSCK_1 .BR fsck (8), ___END_FSCK_1 .BR mount (8) .\" -------------------------------- .SH BUGS The author would be grateful for any constructive suggestions and bug-reports, via https://github.com/rwpenney/cryptmount/issues .\" -------------------------------- .SH COPYRIGHT NOTICE .B cryptmount is Copyright 2005-2024, RW Penney .br and is supplied with NO WARRANTY. Licencing terms are as described in the file "COPYING" within the cryptmount source distribution. .\" vim: set ts=4 sw=4 et: cryptmount-6.3.0/man/fr/000077500000000000000000000000001465135467200151435ustar00rootroot00000000000000cryptmount-6.3.0/man/fr/Makefile.am000066400000000000000000000002511465135467200171750ustar00rootroot00000000000000mandir = @mandir@/fr man_MANS = cmtab.5 cryptmount.8 EXTRA_DIST = cmtab.5.in cryptmount.8.in include ${top_srcdir}/man/makeman.defs clean-local: -rm -f ${man_MANS} cryptmount-6.3.0/man/fr/cmtab.5.in000066400000000000000000000364351465135467200167370ustar00rootroot00000000000000.\" cmtab (French) manual page .\" Copyright (c) 2006-2024 RW Penney .\" .\" ---- macro definitions ---- .de Sh \" Subsection heading .br .ne 5 .PP \fB\\$1\fR .PP .. .TH CMTAB 5 "2018-01-18" "@PACKAGE_VERSION@" "Manuel de l'utilisateur Linux" .SH NOM cmtab \- informations statiques sur les syst\[`e]mes de fichiers dirig\['e]s par cryptmount .\" -------------------------------- .SH DESCRIPTION Les informations sur les syst\[`e]mes de fichiers chiffr\['e]s dirig\['e]s par .B cryptmount sont contenues dans le fichier @CM_SYSCONF_DIR@/cmtab. Chaque syst\[`e]me de fichiers est appell\['e] par un nom de cible qu'on peut utiliser comme param\[`e]tre de .B cryptmount et ce nom appara\[^i]t dans @CM_SYSCONF_DIR@/cmtab devant une liste des param\[`e]tres qui d\['e]crit o\[`u] le syst\[`e]me de fichiers est contenu, et comment il est chiffr\['e]. Le format du cmtab est souple, et la description de chaque cible est d\['e]limit\['e]e par des accolades, les param\[`e]tres sont sp\['e]cifi\['e]s par les paires CLEF=VALEUR, et on peut mettre autant de caract\[`e]re blanc d'espacement que l'on veut. Les annotations commencent avec un caract\[`e]re \(aq#', qui peut \[^e]tre utilis\['e] \[`a] n'importe quel endroit dans une ligne, et continuent jusqu'\[`a] la fin de cette ligne. Le caract\[`e]re \(aq\\' indique que si le caract\[`e]re suitvant a une signification sp\['e]ciale, celle-ci sera ignor\['e]e, comme par exemple si on veut incorporer un espace dans le nom d'un fichier. @CM_SYSCONF_DIR@/cmtab contient des inscriptions de la forme suivante: .EX NOM_CIBLE { dev=PERIPHERIQUE flags=DRAPEAU,DRAPEAU,... startsector=SECTEURDEBUT numsectors=NUMSECTEURS loop=PERIPH_LOOP dir=REP_MONT fstype=TYPE mountoptions=MOPT,MOPT,... fsckoptions=FOPT;FOPT;... supath=SUPATH cipher=CHIFFRE ivoffset=IVOFFSET keyformat=FORMAT_CLEF keyfile=FICHIER_CLEF keyhash=HASH_CLEF keycipher=CHIFFRE_CLEF keymaxlen=MAX_CLEF passwdretries=NUMESSAYES } .EE Ici, les param\[`e]tres \(aqflags', \(aqstartsector', \(aqnumsectors', \(aqloop', \(aqivoffset', \(aqkeyformat', \(aqkeymaxlen' et \(aqpasswdretries' sont optionnels. Les param\[`e]tres ont les sens suivants: .TP .BI NOM_CIBLE est le nom par lequel cryptmount se r\['e]f\[`e]re \[`a] un syst\[`e]me de fichiers particulier. Il est possible d'indiquer valeurs par d\['e]faut pour les cibles suivanteis en utilisant le nom sp\['e]cial "_DEFAULTS_". .\" ---- .TP .BI PERIPHERIQUE est le nom du vrai p\['e]riph\['e]rique (e.g. /dev/sdb63) ou du fichier ordinaire (e.g. /home/secretiveuser/private.fs) qui range le syst\[`e]me de fichiers chiffr\['e]. .\" ---- .TP .BI DRAPEAU est un bouton de configuration, comme par exemple .br * "user" (n'importe quel utilisateur peut monter), .br * "nouser" (seulement le super-utilisateur peut monter), .br * "fsck" (v\['e]rifier automatiquement le syst\[`e]me de fichiers avant de monter), .br * "nofsck" (ne v\['e]rifier pas le syst\[`e]me de fichiers avant de monter), .br * "mkswap" (formater la cible pour la pagination), .br * "nomkswap" (ne formater pas la cible), .br * "trim" (activer SSD TRIM/discard), .br * "notrim" (d\['e]sactiver SSD TRIM/discard). .br Ce param\[`e]tre est optionnel, et le d\['e]faut est "user,fsck,nomkswap,notrim". .\" ---- .TP .BI SECTEURDEBUT est le numero du secteur (de 512 octets) du .B PERIPHERIQUE o\[`u] le syst\[`e]me de fichiers va commencer. Ce param\[`e]tre est optionnel, et le d\['e]faut est z\['e]ro. .\" ---- .TP .BI NUMSECTEURS donne la taille totale du syst\[`e]me de fichiers, en secteurs (blocs de 512 octets). Ce param\[`e]tre est optionnel, et le d\['e]faut est \-1, ce qui signifie que tout le .B PERIPHERIQUE sera utilis\['e]e. .\" ---- .TP .BI PERIPH_LOOP peut \[^e]tre utilis\['e] pour specifier un p\['e]riph\['e]rique loop particulier (e.g. /dev/loop0) au cas o\[`u] .B PERIPHERIQUE est un fichier ordinaire. Ce param\[`e]tre est optionnel, et le d\['e]faut est "auto". .\" ---- .TP .BI REP_MONT est le r\['e]pertoire dans lequel le syst\[`e]me de fichiers chiffr\['e] sera mont\['e]. .\" ---- .TP .BI TYPE specifie le type du syst\[`e]me de fichiers (comme utilis\['e] par .B mount (8)). On doit specifier "swap" si la p\['e]riph\['e]rique va \[^e]tre utilis\['e]e pour la pagination chiffr\['e]e. .\" ---- .TP .BI MOPT est une option de montage, comme compris par .B mount (8). Typiquement, MOPT peut \[^e]tre "default", "noatime", "noexec", "nosuid", "ro", "sync" etc. .\" ---- .TP .BI FOPT est une option de v\['e]rification, comme compris par .B fsck (8). Typiquement, FOPT peut \[^e]tre "\-C", "\-V" etc. .\" ---- .TP .BI CHIFFRE est le type d'algorithme de chiffrage qui sera utilis\['e] sur .B PERIPHERIQUE. La liste des algorithmes possibles est d\['e]termine par le noyau. .\" ---- .TP .BI FORMAT_CLEF indique quel moteur de chiffrage on utilise pour diriger le .B FICHIER_CLEF. Les moteurs disponibles sont d\['e]termin\['e]s pendant l'installation de .B cryptmount mais peuvent comprendre "openssl" et "libgcrypt" en plus de "builtin" (int\['e]gr\['e]) et "raw" (brut). Ce param\[`e]tre est optionel, est s'il est absent, "builtin" sera utilis\['e] quand la clef est construit. .\" ---- .TP .BI FICHIER_CLEF est un fichier ordinaire qui contient la clef utilis\['e]e par l'algorithme .B CHIFFRE pour d\['e]chiffrer le syst\[`e]me de fichiers. Cette clef elle-m\[^e]me est chiffr\['e]e a partir de .B HASH_CLEF et .B CHIFFRE_CLEF \. .\" ---- .TP .BI IVOFFSET est l'offset qui est ajout\['e] au num\['e]ro du secteur pendant le calcul du vecteur d'initialisation de l'algorithme de chiffrage. Ce param\[`e]tre est optionnel, et le d\['e]faut est z\['e]ro. .\" ---- .TP .BI HASH_CLEF est l'algorithme (hash) utilis\['e] pour brouiller le mot de passe de l'utilisateur dans l'algorithme .B CHIFFRE_CLEF qui protege la clef du syst\[`e]me de fichiers chiffr\['e]. On peut choisir n'importe quel algorithme qui est fourni par le .B FORMAT_CLEF qu'on a choisi. .\" ---- .TP .BI CHIFFRE_CLEF est l'algorithme chiffre qui prot\[`e]ge la clef du syst\[`e]me de fichiers chiffr\['e] lui-m\[^e]me. Le menu d'algorithmes est d\['e]termin\['e] par la choix de .B FORMAT_CLEF .\" ---- .TP .BI MAX_CLEF est le nombre d'octets maximum qui sera lu du .B FICHIER_CLEF pour devenir la clef de d\['e]chiffrage. Ce param\[`e]tre est optionnel, et le d\['e]faut est z\['e]ro, ce qui indique que .B FICHIER_CLEF sera lu en entier. .\" ---- .TP .BI NUMESSAYES est le nombre de tentatives de mot de passe avant que cryptmount aille terminer quand on essaye de monter ou configurer une cible. .\" -------------------------------- .SH COMMENT CHOISIR LE FORMAT DE LA CLEF .B cryptmount offrit un s\['e]lection de fa\[,c]ons pour proteger la clef associ\['e]e avec chaque syst\[`e]me de fichiers chiffr\['e]. Pour le plupart des utilisateurs, la choix d\['e]faute "builtin" donne un bon niveau de securit\['e] et versatilit\['e]. Quelques autre moteurs de chiffrage sont disponible, et donnent plus de choix des algorithms pour brouiller le mot de passe, ou compatabilit\['e] avec quelques autre paquets. Le menu des moteurs sont le suivant. .Sh builtin Ce moteur est inclus dans cryptmount-2.0 et suivant, est utilise un fichier independent pour cacher la clef. .Sh libgcrypt Ce moteur est inclus dans cryptmount-1.1 et suivant, est utilise un fichier independent pour cacher la clef. .Sh luks Ce moteur est inclus dans cryptmount-3.1 et suivant, est peut diriger les syst\[`e]me de fichiers du format LUKS ("Linux Unified Key Setup"). Ce format cache la clef dans une region sp\['e]ciale du syst\[`e]me de fichiers lui-m\[^e]me. Il est recommand\['e] de ne pas utiliser les param\[`e]tres "startsector" ou "numsectors" parce que le format LUKS suppose qu'une partition enti\[`e]re est disponible pour le syst\[`e]me de fichiers. .Sh openssl/openssl-compat Ce moteur etait disponible depuis les premiers versions de cryptmount, et utilise un fichier independent pour cacher la clef. Le format de ce fichier est compatible aver le paquet "openssl". .Sh password Ce moteur est inclus dans cryptmount-4.0 et suivant, est n'a pas besoin d'un fichier pour cacher la clef. Plut\[^o]t, la clef est constui directment du mot de passe, et donc il n'est pas possible de changer le mot de passe sans rechiffrer le syst\[`e]me de fichiers en entiers. .Sh raw Ce moteur est inclus dans cryptmount-1.1 et suivant, est utilise un fichier independent pour contenir la clef, sans aucun chiffrage. Ce moteur est utile principalement pour les partitions de pagination. .\" -------------------------------- .SH SECURITE Etant donn\['e] que .B cryptmount est install\['e] avec des permissions setuid, il est tr\[`e]s imporant que son fichier de configuration soit solide. Id\['e]alement, @CM_SYSCONF_DIR@/cmtab devrait \[^e]tre dirig\['e] seulement par le super-utilisateur, et toutes les clefs devraient \[^e]tre seulement lisibles par leurs utilisateurs propres. .B cryptmount v\['e]rifie la s\['e]curit\['e] du @CM_SYSCONF_DIR@/cmtab chaque fois qu'il est execut\['e], et se terminera \[`a] moins que: .br * cmtab ne soit poss\['e]d\['e] par le super-utilisateur .br * cmtab ne soit un fichier r\['e]gulier .br * les permissions de cmtab ne contiennent pas d'\['e]criture universelle .br * le r\['e]pertoire, qui contient cmtab, ne soit poss\['e]d\['e] par le super-utilisateur .br * les permissions du r\['e]pertoire, qui contient cmtab, ne contiennent pas d'\['e]criture universelle. .br De plus, pour toutes les cibles dans @CM_SYSCONF_DIR@/cmtab, tous les fichiers doivent avoir des nom absolus (c'est\-\[`a]\-dire commencent avec '/'). En cas qu'on a choisi "raw" (brut) pour le .B FORMAT_CLEF c'est pr\['e]f\['e]rable si .B FICHIER_CLEF est rang\['e] avec des permissions d'acc\[`e]s non moins restrictives que 0600, ou bien est contenu sur un disque USB-flash, par exemple. .\" -------------------------------- .SH PAGINATION CHIFFREE ET MKSWAP AUTOMATIQUE Lorsque l'option `mkswap' est s\['e]lectionn\['e] pour une cible particuli\[`e]re dans @CM_SYSCONF_DIR@/cmtab, . B cryptmount tentera automatiquement de formater une partition swap chiffr\['e]e chaque fois que vous ex\['e]cutez "cryptmount \-\-swapon ". C'est souvent utile quand il n'est pas n\['e]cessaire de conserver les donn\['e]es de pagination entre les red\['e]marrages, comme lorsque vous n'utilisez pas les caract\['e]ristiques d'hibernation du noyau. Parce que le reformatage supprime toutes les donn\['e]es existantes sur la partition de pagination choisi, . B cryptmount se faire des v\['e]rifications de base sur le premier m\['e]gaoctet de la partition, bas\['e]e sur le degr\['e] d'al\['e]a (entropie) dans le contenu actuel. Si la partition semble contenir bruit pur, ou a \['e]t\['e] remis \[`a] z\['e]ro, la partition sera format\['e]e automatiquement. Si . B cryptmount d\['e]termine que la partition peut contenir des donn\['e]es non-al\['e]atoire, puis il vous demandera d'ex\['e]cuter "mkswap" manuellement. Comme il n'existe aucun moyen infaillible de d\['e]terminer si une partition (surtout chiffr\['e]e) contient des donn\['e]es importantes, vous devriez \[^e]tre tr\[`e]s prudent sur p\['e]riph\['e]rique brut choisi pour n'importe quelle cible sur lequel vous s\['e]lectionnez l'option "mkswap". .\" -------------------------------- .SH FICHIER EXEMPLE Le @CM_SYSCONF_DIR@/cmtab exemple suivant contient cinq cibles, qui utilisent un m\['e]lange d'algorithmes de chiffrage et qui rangent leurs syst\[`e]mes de fichiers de mani\[`e]res differentes. Il y en a aussi un cible qui represent une partition de pagination. .EX # @CM_SYSCONF_DIR@/cmtab # fichier exemplaire \- modifiez avant d'utiliser SVP _DEFAULTS_ { passwdretries=3 # permet 3 essayes de mot de passe par d\['e]faut } luks { # partition cre\['e] avec cryptsetup-luks dev=/dev/sdb63 dir=/mnt/partition-luks keyformat=luks keyfile=/dev/sdb63 fstype=ext3 } basic { dev=/home/secretiveuser/crypt.fs dir=/home/secretiveuser/crypt # o\[`u] on va monter loop=auto # trouver un p\['e]riph loop libre fstype=ext3 mountoptions=default cipher=aes-cbc-plain # chiffrage du syst\[`e]me de fichiers keyfile=/home/secretiveuser/crypt.key # utiliser le gestionnaire des clefs int\['e]gr\['e] keyformat=builtin } partition { dev=/dev/sdb62 # utiliser une partition enti\[`e]re dir=/mnt/crypt62 fstype=ext3 mountoptions=nosuid,noexec \ cipher=serpent-cbc-plain # info sur le fichier qui contient la clef de d\['e]chiffrage: keyfile=@CM_SYSCONF_DIR@/crypt_sdb62.key keyformat=openssl # utiliser OpenSSL pour chiffrage de la clef keyhash=md5 keycipher=bf\-cbc # chiffrage du fichier de la clef } subset { dev=/dev/sdb63 startsector=512 numsectors=16384 # utiliser une partie d'une partition dir=/mnt/encrypted\\ subset\\ of\\ sdb fstype=reiserfs mountoptions=defaults cipher=twofish-cbc-plain # chiffrage du syst\[`e]me de fichiers # info sur le fichier qui contient la clef de d\['e]chiffrage: keyfile=@CM_SYSCONF_DIR@/crypt_sdb63.key keyformat=libgcrypt keyhash=md5 keycipher=blowfish\-cbc # chiffrage de la clef d'acc\[`e]s } encswap { # pagination chiffr\['e]e dev=/dev/sdb63 startsector=16896 numsectors=1024 # utiliser une partie d'une partition fstype=swap flags=mkswap cipher=twofish-cbc-plain # lire une clef nouvelle de 16-octets de /dev/random chaque fois: keyfile=/dev/random keymaxlen=16 keyformat=raw } # fin de cmtab .EE La cible \(aqbasic' utilise le fichier ordinaire "/home/secretiveuser/crypt.fs" pour ranger le syst\[`e]me de fichiers chiffr\['e]. Un p\['e]riph\['e]rique loop sera configur\['e] automatiquement par .B cryptmount (\[`a] cause du "loop=auto"). La cible \(aqpartition' utilise une partition enti\[`e]re du disque dur pour ranger le syst\[`e]me de fichiers chiffr\['e]. La clef de d\['e]chiffrage est contenue dans le r\['e]pertoire principal de .B cryptmount. La cible \(aqsubset' est semblable \[`a] la cible \(aqpartition' sauf qu'elle n'utilise pas une partition enti\[`e]re. De cette mani\[`e]re, on peut utiliser des autres groupes de blocs de la partition pour des autres syst\[`e]mes de fichiers dirig\['e]s par .B cryptmount ou .B dmsetup. La cible \(aqencswap' utilise une partie d'une partition du disque dur pour proviser la pagination chiffr\['e]e. Une nouvelle clef de d\['e]chiffrage sera lu du /dev/random chaque fois la cible est utilis\['e]e. .\" -------------------------------- .SH FICHIERS .I @CM_SYSCONF_DIR@/cmtab - fichier principal du configuration .SH "VOIR AUSSI" .BR cryptmount (8), .BR cryptmount-setup (8), .BR dmsetup (8), .BR openssl (1) .\" -------------------------------- .SH COPYRIGHT NOTICE .B cryptmount est Copyright 2005-2024 RW Penney .br et il n'y a point de garantie. Les termes de sa licence sont d\['e]crits dans le fichier "COPYING" dans le paquet source de cryptmount. .\" -------------------------------- .SH TRADUCTION RW Penney, 2006-2024, avec beaucoup d'assistance de FP. .\" vim: set ts=4 sw=4 et: cryptmount-6.3.0/man/fr/cryptmount.8.in000066400000000000000000000227131465135467200200720ustar00rootroot00000000000000.\" cryptmount (French) manual page .\" Copyright (c) 2006-2024 RW Penney .\" .TH CRYPTMOUNT 8 "2024-07-21" "@PACKAGE_VERSION@" "Manuel de l'utilisateur Linux" .SH NOM cryptmount \- monter/d\['e]monter un syst\[`e]me de fichiers chiffr\['e] .\" -------------------------------- .SH SYNOPSIS .BI "cryptmount \fICIBLE\fR [\fICIBLE ...\fR]" .LP .BI "cryptmount \-\-unmount \fICIBLE\fR [\fICIBLE ...\fR]" .LP .BI "cryptmount \-\-change\-password \fICIBLE\fR" .LP .BI "cryptmount \-\-generate\-key \fIsize\fP \fICIBLE\fR" ___DELETE_CSWAP_0 .LP .BI "cryptmount \-\-swapon \fICIBLE\fR" .LP .BI "cryptmount \-\-swapoff \fICIBLE\fR" ___END_CSWAP_0 .\" -------------------------------- .SH DESCRIPTION .B cryptmount permet \[`a] un utilisateur ordinaire d'acc\['e]der \[`a] un syst\[`e]me de fichiers chiffr\['e] sans avoir besoin des privil\[`e]ges du super-utilisateur, et aussi aide le super-utilisateur \[`a] cr\['e]er des nouveaux syst\[`e]mes de fichiers chiffr\['e]s. Apr\[`e]s avoir \['e]t\['e] configur\['e] la premi\[`e]re fois par le super-utilisateur, l'utilisateur a seulement besoin de donner le mot de passe du syst\[`e]me de fichiers pour que .B cryptmount configure automatiquement des cibles du device-mapper et p\['e]riph\['e]rique loop avant de monter le syst\[`e]me de fichiers. .B cryptmount a \['e]t\['e] \['e]crit en r\['e]ponse aux diff\['e]rences entre le nouveau device-mapper du linux-2.6 serie des noyeaux et, le plus ag\['e], cryptoloop qui a permis \[`a] des utilisateurs ordinaires d'acc\['e]der aux syst\[`e]mes de fichiers chiffr\['e]s directement avec .B mount (8). .\" -------------------------------- .SH OPTIONS .TP .B \-a \-\-all op\['e]rer sur toutes les cibles dans @CM_SYSCONF_DIR@/cmtab, par exemple si on veut monter toutes les cibles. .TP .B \-m \-\-mount monter une cible particuli\[`e]re. On demandera \[`a] l'utilisateur de donner un mot de passe pour r\['e]v\['e]ler la clef qui d\['e]chiffre le syst\[`e]me de fichiers. .TP .B \-u \-\-unmount d\['e]monter une cible particuli\[`e]re. On n'a pas besoin de donner un mot de passe, mais si un utilisateur ordinaire qui n'a pas mont\['e] ce syst\[`e]me de fichiers essaye de le d\['e]monter, cela se soldera par un \['e]chec. .TP .B \-l \-\-list donner une liste de toutes les cibles. .TP .B \-c \-\-change\-password changer le mot de passe qui prot\[`e]ge un syst\[`e]me de fichers. .TP .B \-\-generate\-key "\fItaille\fP" cr\['e]er une clef de d\['e]chiffrage pour un nouveau syst\[`e]me de fichiers. .IR taille\fP donne la longeur de la clef en octets. .TP .B \-e \-\-reuse\-key "\fIcible-actuel\fP" cr\['e]er une clef de d\['e]chiffrage pour un nouveau syst\[`e]me de fichiers, utilisant une clef existante d'un autre syst\[`e]me de fichiers. .TP .B \-f \-\-config\-fd "\fInum\fP" lire les information des cibles d'un descripteur de fichier num\['e]ro .IR num\fP en place du fichier de configuration de defaut. Cette option est reserv\['e]e seulement pour le super-utilisateur. .TP .B \-w \-\-passwd\-fd "\fInum\fP" lire les mots de passe d'un descripteur de fichier num\['e]ro .IR num\fP en place du terminal. .TP .B \-p \-\-prepare pr\['e]parer toutes les cibles du device-mapper et p\['e]riph\['e]rique loop n\['e]cessaires pour acc\['e]der \[`a] une cible, mais sans la monter. Cette commande permet au super-utilisateur d'installer un syst\[`e]me de fichiers sur un p\['e]riph\['e]rique chiffr\['e]. .TP .B \-r \-\-release lib\['e]rer toutes les cibles du device-mapper et p\['e]riph\['e]rique loop associ\['e]es \[`a] une cible particuli\[`e]re. Cette option est reserv\['e]e seulement pour le super-utilisateur. ___DELETE_CSWAP_0 .TP .B \-s \-\-swapon activer une cible pour la pagination sur disque chiffr\['e]. Cette option est reserv\['e]e seulement pour le super-utilisateur. .TP .B \-x \-\-swapoff d\['e]sactiver une cible pour la pagination sur disque chiffr\['e]. Cette option est reserv\['e]e seulement pour le super-utilisateur. ___END_CSWAP_0 .TP .B \-k \-\-key-managers donne une list de tous les gestionnaires des fichier-clefs. .TP .B \-v \-\-version donner le num\['e]ro version de la programme install\['e]e. .\" -------------------------------- .SH CODES DE RETOUR .B cryptmount donne un z\['e]ro si l'action a r\['e]ussi. Une autre valeur indique qu'une erreur a \['e]t\['e] comise: .TP .B 1 un argument n'est pas reconnu; .TP .B 2 le nom d'une cible n'est pas reconnu; .TP .B 3 l'excecution d'une programme a \['e]chou\['e]; .TP .B 100 l'utilisateur n'a pas assez de privil\[`e]ge; .TP .B 101 il y a un \['e]chec de le securit\['e] dans l'installation. .\" -------------------------------- .SH EXEMPLES Si vous voulez construire un nouveau syst\[`e]me de fichiers chiffr\['e] dirig\['e] par cryptmount, vous pouvez utiliser le programme 'cryptmount-setup' compris avec ce paquet, qui permet au super-utilisateur d'\['e]tablir interactivement une cible basique. Autrement, imaginez que l'on veuille construire un nouveau syst\[`e]me de fichiers chiffr\['e], que l'on appellera \[Fo]opaque\[Fc]. Si on a une partition libre du disque dur, par exemple /dev/hdb63, on peut utiliser cette partition directement pour contenir le syst\[`e]me de fichiers. Sinon, on peut conserver le syst\[`e]me de fichiers chiffr\['e] dans un fichier ordinaire, si on reserve de l'espace-disque avec par exemple la commande suivante: .EX dd if=/dev/zero of=/home/opaque.fs bs=1M count=512 .EE et ensuite, on doit remplacer toutes les instances de \[Fo]/dev/hdb63\[Fc] dans ce qui suit par \[Fo]/home/opaque.fs\[Fc]. D'abord, on doit cr\['e]er un inscription dans @CM_SYSCONF_DIR@/cmtab, qui d\['e]crit le chiffrage qui sera utilis\['e] pour prot\[`e]ger le syst\[`e]me de fichiers, ainsi: .EX opaque { dev=/dev/hdb63 dir=/home/crypt fstype=ext2 mountoptions=defaults cipher=twofish keyfile=@CM_SYSCONF_DIR@/opaque.key keyformat=builtin } .EE Ici, on utilisera l'algorithme "twofish" pour chiffrer le syst\[`e]me de fichiers lui-m\[^e]me, et le gestionnaire int\['e]gr\['e] ("builtin") va conserver le securit\['e] de la clef de d\['e]chiffrage dans @CM_SYSCONF_DIR@/opaque.key. Pour g\['e]n\['e]rer une clef de d\['e]chiffrage secr\[`e]te (dans @CM_SYSCONF_DIR@/opaque.key), on peut ex\['e]cuter, en tant que super-utilisateur: .EX cryptmount \-\-generate\-key 32 opaque .EE Cette commande produit une clef de 32 octets (256 bits), et on sait que le chiffre Twofish accepte les clefs de 256 bits. Si on ex\['e]cute la commande suivante, en tant que super-utilisateur: .EX cryptmount \-\-prepare opaque .EE on doit produire le mot de passe qu'on a donn\['e] lors de l'\['e]criture du @CM_SYSCONF_DIR@/opaque.key. Ceci permet \[`a] .B cryptmount de pr\['e]parer une cible device-mapper (/dev/disk/by-id/dm-name-opaque). Maintenant, les outils standards sont disponibles pour mettre un syst\[`e]me de fichiers sur /dev/disk/by-id/dm-name-opaque: .EX mke2fs /dev/disk/by-id/dm-name-opaque .EE Apr\[`e]s avoir ex\['e]cut\['e] .EX cryptmount \-\-release opaque mkdir /home/crypt .EE le syst\[`e]me de fichiers chiffr\['e] est pr\[^e]t. Les utilisateurs ordinaires pouvent monter le syst\[`e]me de fichiers en tapant .EX cryptmount \-m opaque .EE ou .EX cryptmount opaque .EE et pouvent d\['e]monter avec .EX cryptmount \-u opaque .EE .B cryptmount maintenit un rapport sur lequel utilisateur a mont\['e] chaque cible de mani\[`e]re \[`a] interdir \[`a] tout autre utilisateur (sauf le super-utilisateur) de d\['e]monter ce syst\[`e]me de fichiers. .\" -------------------------------- .SH MODIFIER MOT DE PASSE Apr\[`e]s avoir utilis\['e] un syst\[`e]me de fichiers pendant un certain temps, on peut vouloir changer le mot de passe. Par exemple, si on a une cible appel\['e]e "opaque", on peut ex\['e]cuter: .EX cryptmount \-\-change\-password opaque .EE On doit donner l'ancien mot de passe, et ensuite choisir un nouveau mot de passe qui va chiffrer la clef d'acc\[`e]s pour le syst\[`e]me de fichiers. (Le syst\[`e]me de fichier lui-m\[^e]me n'est pas modifi\['e].) .\" -------------------------------- .SH SYSTEMES DE FICHIERS `LUKS' On peut utiliser .B cryptmount pour acc\[`e]der facilement les syst\[`e]mes de fichiers en format LUKS cr\['e]e avec le paquet .B cryptsetup. Si on a d\['e]j\[`a] construi un partition LUKS, on doit seulment mettre un autre cible dans @CM_SYSCONF_DIR@/cmtab. Par example, si le partition /dev/hdb62 sur le disque dur contient un syst\[`e]me de fichiers du type `ext3', chiffr\['e]e avec LUKS, on peut ecrire: .EX LUKS { keyformat=luks dev=/dev/hdb62 keyfile=/dev/hdb62 dir=/home/luks-dir fstype=ext3 } .EE Apr\[`e]s avoir faire \[,c]a, c'est possible de monter cette syst\[`e]me de fichiers sous /home/luks-dir avec .EX cryptmount LUKS .EE .\" -------------------------------- .SH FICHIERS .I @CM_SYSCONF_DIR@/cmtab - fichier de configuration .LP .I @CM_SYSRUN_DIR@/cryptmount.status - rapport sur les cibles mont\['e]es .SH "VOIR AUSSI" .BR cmtab (5), .BR cryptmount-setup (8), .BR cryptsetup (8), .BR mount (8), .\" -------------------------------- .SH BOGUES L'auteur accueille les suggestions .B constructives \[`a] https://github.com/rwpenney/cryptmount/issues .\" -------------------------------- .SH COPYRIGHT NOTICE .B cryptmount est Copyright 2005-2024 RW Penney .br et il n'y a point de garantie. Les termes de sa licence sont d\['e]crits dans le fichier "COPYING" dans le paquet source de cryptmount. .\" -------------------------------- .SH TRADUCTION RW Penney, 2006-2014, avec beaucoup d'assistance de mon \['e]pouse. .\" vim: set ts=4 sw=4 et: cryptmount-6.3.0/man/makeman.defs000066400000000000000000000020061465135467200170060ustar00rootroot00000000000000# cryptmount makefile-rules for man-pages # RW Penney, April 2006 # transform manpages in Makefile rather than configure, # because otherwise '${prefix}' may not be fully expanded: mantransform="s,@PACKAGE_VERSION\@,${PACKAGE_VERSION},g; \ s,@CM_SYSCONF_DIR\@,${CM_SYSCONF_DIR},g; \ s,@CM_SYSRUN_DIR\@,${CM_SYSRUN_DIR},g; \ s,@CM_DEFAULT_CIPHER\@,${CM_DEFAULT_CIPHER},g; \ s,@DFLT_KEYHASH\@,${DFLT_KEYHASH},g; \ s,@DFLT_KEYCIPHER\@,${DFLT_KEYCIPHER},g; \ s,@CM_DEFAULT_SUPATH\@,${CM_DEFAULT_SUPATH},g; \ /^___DELETE_CSWAP_${WITH_CSWAP}/,/^___END_CSWAP_${WTIH_CSWAP}/d; \ /^___DELETE_FSCK_${WITH_FSCK}/,/^___END_FSCK_${WTIH_FSCK}/d; \ /^___/d" cmtab.5: cmtab.5.in ${top_builddir}/config.status @echo "Preparing $@ from $<" @sed ${mantransform} $< > $@ cryptmount.8: cryptmount.8.in ${top_builddir}/config.status @echo "Preparing $@ from $<" @sed ${mantransform} $< > $@ cryptmount-setup.8: cryptmount-setup.8.in ${top_builddir}/config.status @echo "Preparing $@ from $<" @sed ${mantransform} $< > $@ cryptmount-6.3.0/mkinstalldirs000077500000000000000000000066721465135467200166020ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2020-07-26.22; # UTC # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' IFS=" "" $nl" errstatus=0 dirmode= usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit $? ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 $scriptversion" exit $? ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and # mkdir -p a/c at the same time, both will detect that a is missing, # one will create a, then the other will try to create a and die with # a "File exists" error. This is a problem when calling mkinstalldirs # from a parallel make. We use --version in the probe to restrict # ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the 'mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because '.' already # exists. test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi ;; *) if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "umask 22" umask 22 echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./--version "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac echo "umask 22" umask 22 for file do case $file in /*) pathcomp=/ ;; *) pathcomp= ;; esac oIFS=$IFS IFS=/ set fnord $file shift IFS=$oIFS for d do test "x$d" = x && continue pathcomp=$pathcomp$d case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp=$pathcomp/ done if test ! -z "$dirmode"; then echo "chmod $dirmode $file" chmod "$dirmode" "$file" || errstatus=$? fi done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: cryptmount-6.3.0/po/000077500000000000000000000000001465135467200143775ustar00rootroot00000000000000cryptmount-6.3.0/po/LINGUAS000066400000000000000000000000671465135467200154270ustar00rootroot00000000000000# languages available for cryptmount text output de fr cryptmount-6.3.0/po/Makefile.in.in000066400000000000000000000332211465135467200170520ustar00rootroot00000000000000# Makefile for PO directory in any package using GNU gettext. # Copyright (C) 1995-1997, 2000-2006 by Ulrich Drepper # # This file can be copied and used freely without restrictions. It can # be used in projects which are not available under the GNU General Public # License but which still want to provide support for the GNU gettext # functionality. # Please note that the actual code of GNU gettext is covered by the GNU # General Public License and is *not* in the public domain. # # Origin: gettext-0.16 PACKAGE = @PACKAGE@ VERSION = @VERSION@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ SHELL = /bin/sh @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ datadir = @datadir@ localedir = @localedir@ gettextsrcdir = $(datadir)/gettext/po INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ # We use $(mkdir_p). # In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as # "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, # @install_sh@ does not start with $(SHELL), so we add it. # In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined # either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake # versions, $(mkinstalldirs) and $(install_sh) are unused. mkinstalldirs = $(SHELL) @install_sh@ -d install_sh = $(SHELL) @install_sh@ MKDIR_P = @MKDIR_P@ mkdir_p = @mkdir_p@ GMSGFMT_ = @GMSGFMT@ GMSGFMT_no = @GMSGFMT@ GMSGFMT_yes = @GMSGFMT_015@ GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) MSGFMT_ = @MSGFMT@ MSGFMT_no = @MSGFMT@ MSGFMT_yes = @MSGFMT_015@ MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) XGETTEXT_ = @XGETTEXT@ XGETTEXT_no = @XGETTEXT@ XGETTEXT_yes = @XGETTEXT_015@ XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) MSGMERGE = msgmerge MSGMERGE_UPDATE = @MSGMERGE@ --update MSGINIT = msginit MSGCONV = msgconv MSGFILTER = msgfilter POFILES = @POFILES@ GMOFILES = @GMOFILES@ UPDATEPOFILES = @UPDATEPOFILES@ DUMMYPOFILES = @DUMMYPOFILES@ DISTFILES.common = Makefile.in.in remove-potcdate.sin \ $(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ $(POFILES) $(GMOFILES) \ $(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) POTFILES = \ CATALOGS = @CATALOGS@ # Makevars gets inserted here. (Don't remove this line!) .SUFFIXES: .SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update .po.mo: @echo "$(MSGFMT) -c -o $@ $<"; \ $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo .sin.sed: sed -e '/^#/d' $< > t-$@ mv t-$@ $@ all: all-@USE_NLS@ all-yes: stamp-po all-no: # $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no # internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because # we don't want to bother translators with empty POT files). We assume that # LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. # In this case, stamp-po is a nop (i.e. a phony target). # stamp-po is a timestamp denoting the last time at which the CATALOGS have # been loosely updated. Its purpose is that when a developer or translator # checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, # "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent # invocations of "make" will do nothing. This timestamp would not be necessary # if updating the $(CATALOGS) would always touch them; however, the rule for # $(POFILES) has been designed to not touch files that don't need to be # changed. stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @test ! -f $(srcdir)/$(DOMAIN).pot || { \ echo "touch stamp-po" && \ echo timestamp > stamp-poT && \ mv stamp-poT stamp-po; \ } # Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', # otherwise packages like GCC can not be built if only parts of the source # have been downloaded. # This target rebuilds $(DOMAIN).pot; it is an expensive operation. # Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ else \ msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ fi; \ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ --files-from=$(srcdir)/POTFILES.in \ --copyright-holder='$(COPYRIGHT_HOLDER)' \ --msgid-bugs-address="$$msgid_bugs_address" test ! -f $(DOMAIN).po || { \ if test -f $(srcdir)/$(DOMAIN).pot; then \ sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ else \ rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ fi; \ else \ mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ fi; \ } # This rule has no dependencies: we don't need to update $(DOMAIN).pot at # every "make" invocation, only create it when it is missing. # Only "make $(DOMAIN).pot-update" or "make dist" will force an update. $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update # This target rebuilds a PO file if $(DOMAIN).pot has changed. # Note that a PO file is not touched if it doesn't need to be changed. $(POFILES): $(srcdir)/$(DOMAIN).pot @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot; \ else \ $(MAKE) $${lang}.po-create; \ fi install: install-exec install-data install-exec: install-data: install-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ for file in $(DISTFILES.common) Makevars.template; do \ $(INSTALL_DATA) $(srcdir)/$$file \ $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ for file in Makevars; do \ rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ else \ : ; \ fi install-data-no: all install-data-yes: all $(mkdir_p) $(DESTDIR)$(datadir) @catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ dir=$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $(DESTDIR)$$dir; \ if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ if test -n "$$lc"; then \ if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ for file in *; do \ if test -f $$file; then \ ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ fi; \ done); \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ else \ if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ :; \ else \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ fi; \ fi; \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ fi; \ done; \ done install-strip: install installdirs: installdirs-exec installdirs-data installdirs-exec: installdirs-data: installdirs-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ else \ : ; \ fi installdirs-data-no: installdirs-data-yes: $(mkdir_p) $(DESTDIR)$(datadir) @catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ dir=$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $(DESTDIR)$$dir; \ for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ if test -n "$$lc"; then \ if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ for file in *; do \ if test -f $$file; then \ ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ fi; \ done); \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ else \ if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ :; \ else \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ fi; \ fi; \ fi; \ done; \ done # Define this as empty until I found a useful application. installcheck: uninstall: uninstall-exec uninstall-data uninstall-exec: uninstall-data: uninstall-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ for file in $(DISTFILES.common) Makevars.template; do \ rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ else \ : ; \ fi uninstall-data-no: uninstall-data-yes: catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ done; \ done check: all info dvi ps pdf html tags TAGS ctags CTAGS ID: mostlyclean: rm -f remove-potcdate.sed rm -f stamp-poT rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po rm -fr *.o clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES *.mo maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." rm -f stamp-po $(GMOFILES) distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) dist distdir: $(MAKE) update-po @$(MAKE) dist2 # This is a separate target because 'update-po' must be executed before. dist2: stamp-po $(DISTFILES) dists="$(DISTFILES)"; \ if test "$(PACKAGE)" = "gettext-tools"; then \ dists="$$dists Makevars.template"; \ fi; \ if test -f $(srcdir)/$(DOMAIN).pot; then \ dists="$$dists $(DOMAIN).pot stamp-po"; \ fi; \ if test -f $(srcdir)/ChangeLog; then \ dists="$$dists ChangeLog"; \ fi; \ for i in 0 1 2 3 4 5 6 7 8 9; do \ if test -f $(srcdir)/ChangeLog.$$i; then \ dists="$$dists ChangeLog.$$i"; \ fi; \ done; \ if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ for file in $$dists; do \ if test -f $$file; then \ cp -p $$file $(distdir) || exit 1; \ else \ cp -p $(srcdir)/$$file $(distdir) || exit 1; \ fi; \ done update-po: Makefile $(MAKE) $(DOMAIN).pot-update test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. .nop.po-create: @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 # General rule for updating PO files. .nop.po-update: @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ cd $(srcdir); \ if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "msgmerge for $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) @: Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ cd $(top_builddir) \ && $(SHELL) ./config.status $(subdir)/$@.in po-directories force: # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: cryptmount-6.3.0/po/Makevars000066400000000000000000000004171465135467200160750ustar00rootroot00000000000000# Makefile variables for PO directory in any package using GNU gettext. DOMAIN = $(PACKAGE) subdir = po top_builddir = .. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ COPYRIGHT_HOLDER = RW Penney MSGID_BUGS_ADDRESS = cryptmount@rwpenney.uk EXTRA_LOCALE_CATEGORIES = cryptmount-6.3.0/po/POTFILES.in000066400000000000000000000004271465135467200161570ustar00rootroot00000000000000# List of cryptmount source files containing translatable strings. # RW Penney, April 2006 # main sources: armour.c armour-builtin.c armour-gcry.c armour-luks.c blowfish.c cryptmount.c dmutils.c fsutils.c looputils.c tables.c utils.c # shell-scripts: sysinit/setupscript.sh.in cryptmount-6.3.0/po/Rules-quot000066400000000000000000000033761465135467200164130ustar00rootroot00000000000000# Special Makefile rules for English message catalogs with quotation marks. DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot .SUFFIXES: .insert-header .po-update-en en@quot.po-create: $(MAKE) en@quot.po-update en@boldquot.po-create: $(MAKE) en@boldquot.po-update en@quot.po-update: en@quot.po-update-en en@boldquot.po-update: en@boldquot.po-update-en .insert-header.po-update-en: @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ ll=`echo $$lang | sed -e 's/@.*//'`; \ LC_ALL=C; export LC_ALL; \ cd $(srcdir); \ if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "creation of $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi en@quot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header en@boldquot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header mostlyclean: mostlyclean-quot mostlyclean-quot: rm -f *.insert-header cryptmount-6.3.0/po/boldquot.sed000066400000000000000000000003311465135467200167220ustar00rootroot00000000000000s/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g s/“/“/g s/”/”/g s/‘/‘/g s/’/’/g cryptmount-6.3.0/po/cryptmount.pot000066400000000000000000000350741465135467200173600ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR RW Penney # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: cryptmount@rwpenney.uk\n" "POT-Creation-Date: 2024-07-20 14:24+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: armour.c:151 armour-builtin.c:300 armour-gcry.c:570 armour-gcry.c:726 #, c-format msgid "Key-extraction failed for \"%s\"\n" msgstr "" #: armour.c:173 #, c-format msgid "Key-writing failed for \"%s\"\n" msgstr "" #: armour.c:358 #, c-format msgid "Failed to open keyfile \"%s\" for target \"%s\"\n" msgstr "" #: armour.c:366 #, c-format msgid "Missing keyfile for target \"%s\"\n" msgstr "" #: armour.c:393 #, c-format msgid "Missing output keyfile for target \"%s\"\n" msgstr "" #: armour.c:786 #, c-format msgid "Specification for target \"%s\" contains non-absolute pathname\n" msgstr "" #: armour-builtin.c:282 armour-gcry.c:552 armour-gcry.c:707 #, c-format msgid "Password mismatch when extracting key\n" msgstr "" #: armour-builtin.c:398 armour-gcry.c:631 armour-gcry.c:785 #, c-format msgid "Failed to create new key file\n" msgstr "" #: armour-gcry.c:177 #, c-format msgid "Couldn't find libgcrypt cipher \"%s\"\n" msgstr "" #: armour-gcry.c:186 #, c-format msgid "Couldn't find libgcrypt cipher mode \"%s\" - using fallback\n" msgstr "" #: armour-gcry.c:192 #, c-format msgid "Couldn't find libgcrypt digest \"%s\"\n" msgstr "" #: armour-gcry.c:513 #, c-format msgid "Bad keyfile format (libgcrypt)\n" msgstr "" #: armour-gcry.c:556 #, c-format msgid "Checksum mismatch in keyfile (gcry, %x != %x)\n" msgstr "" #: armour-gcry.c:672 #, c-format msgid "Bad keyfile format (openssl-compat)\n" msgstr "" #: armour-gcry.c:711 #, c-format msgid "Checksum mismatch in keyfile (openssl-compat, ofs=%u,idx=%u)\n" msgstr "" #: armour-luks.c:217 #, c-format msgid "Failed to acquire privileges for LUKS container\n" msgstr "" #: armour-luks.c:310 armour-luks.c:394 #, c-format msgid "Failed to initialize device for LUKS keyfile\n" msgstr "" #: armour-luks.c:320 #, c-format msgid "Failed to extract LUKS key for \"%s\" (errno=%d)\n" msgstr "" #: armour-luks.c:381 #, c-format msgid "Formatting \"%s\", will probably destroy all existing data" msgstr "" #: armour-luks.c:410 #, c-format msgid "Failed to create LUKS header for \"%s\"\n" msgstr "" #: armour-luks.c:420 #, c-format msgid "Failed to create LUKS key for \"%s\"\n" msgstr "" #: armour-luks.c:433 #, c-format msgid "Setting password on LUKS keyslot-%u\n" msgstr "" #: cryptmount.c:126 msgid "" "usage: cryptmount [OPTION [target ...]]\n" "\n" " available options are as follows:\n" "\n" " -h | --help\n" " -a | --all\n" " -c | --change-password \n" " -k | --key-managers\n" " -l | --list\n" " -S | --status\n" " -m | --mount \n" " -u | --unmount \n" " --generate-key \n" " --reuse-key \n" " --prepare \n" " --release \n" " --config-fd \n" " --passwd-fd \n" " --swapon \n" " --swapoff \n" " --version\n" "\n" " please report bugs to \n" msgstr "" #. TRANSLATORS: this string is marked as 'no-c-format' because #. some localizations may require the mount-point and filesystem type #. to be printed in a different order, but the untranslated string needs #. to remain an ordinary string that can be printed without gettext. #: cryptmount.c:261 #, no-c-format msgid "%-16s [to mount on \"%s\" as \"%s\"]\n" msgstr "" #: cryptmount.c:393 #, c-format msgid "Failed to extract cipher key\n" msgstr "" #: cryptmount.c:402 #, c-format msgid "Cannot open device \"%s\" for target \"%s\"\n" msgstr "" #: cryptmount.c:410 #, c-format msgid "Failed to get size of \"%s\"\n" msgstr "" #: cryptmount.c:420 #, c-format msgid "Bad device-mapper start/length" msgstr "" #: cryptmount.c:447 #, c-format msgid "Device-mapper target-creation failed for \"%s\"\n" msgstr "" #: cryptmount.c:487 cryptmount.c:724 #, c-format msgid "Target \"%s\" does not appear to be configured\n" msgstr "" #: cryptmount.c:505 #, c-format msgid "Cannot stat \"%s\"\n" msgstr "" #: cryptmount.c:513 #, c-format msgid "Failed to remove device-mapper target \"%s\"\n" msgstr "" #: cryptmount.c:545 #, c-format msgid "Target \"%s\" is already mounted\n" msgstr "" #: cryptmount.c:604 #, c-format msgid "Target \"%s\" does not appear to be mounted\n" msgstr "" #: cryptmount.c:614 #, c-format msgid "Only \"%s\" can unmount \"%s\"\n" msgstr "" #. TRANSLATORS: the following expands to include #. the *numerical* user-identity in place of '%lu', #. e.g. giving 'only user-16 can unmount "target"': #: cryptmount.c:620 #, c-format msgid "Only user-%lu can unmount \"%s\"\n" msgstr "" #: cryptmount.c:665 #, c-format msgid "Target \"%s\" is already configured\n" msgstr "" #: cryptmount.c:689 cryptmount.c:744 #, c-format msgid "Crypto-swap is not supported by this installation of cryptmount\n" msgstr "" #: cryptmount.c:776 #, c-format msgid "Key-file for \"%s\" isn't password-protected\n" msgstr "" #: cryptmount.c:802 cryptmount.c:923 #, c-format msgid "Cannot open \"%s\" for writing\n" msgstr "" #: cryptmount.c:817 #, c-format msgid "Retiring old key (%s -> %s) failed\n" msgstr "" #: cryptmount.c:825 #, c-format msgid "Installing new key (%s -> %s) failed\n" msgstr "" #: cryptmount.c:832 #, c-format msgid "Backup of previous key is in \"%s\"\n" msgstr "" #: cryptmount.c:872 cryptmount.c:1548 #, c-format msgid "Target name \"%s\" is not recognized\n" msgstr "" #: cryptmount.c:878 #, c-format msgid "Bad key-length parameter" msgstr "" #: cryptmount.c:890 #, c-format msgid "Key-file \"%s\" already exists for target \"%s\"\n" msgstr "" #: cryptmount.c:900 #, c-format msgid "Generating random key; please be patient...\n" msgstr "" #: cryptmount.c:904 #, c-format msgid "Failed to generate new key\n" msgstr "" #: cryptmount.c:937 #, c-format msgid "Installation of new keyfile \"%s\" failed" msgstr "" #: cryptmount.c:1072 #, c-format msgid "Only root can use option \"%s\"\n" msgstr "" #: cryptmount.c:1085 #, c-format msgid "Only root can configure \"%s\"\n" msgstr "" #: cryptmount.c:1149 #, c-format msgid "Cannot find key-manager to match target \"%s\"\n" msgstr "" #: cryptmount.c:1416 #, c-format msgid "Multiple operating modes not supported\n" msgstr "" #: cryptmount.c:1471 #, c-format msgid "Memory-locking failed...\n" msgstr "" #: cryptmount.c:1499 #, c-format msgid "Bad file-descriptor (%d)\n" msgstr "" #: cryptmount.c:1509 #, c-format msgid "Security failure\n" msgstr "" #: cryptmount.c:1528 #, c-format msgid "Trailing command-line arguments given with '--all' option\n" msgstr "" #: cryptmount.c:1560 #, c-format msgid "Target security failure for \"%s\"\n" msgstr "" #: cryptmount.c:1569 #, c-format msgid "No targets specified\n" msgstr "" #: fsutils.c:267 #, c-format msgid "Unsuitable filesystem type \"%s\" for swapping\n" msgstr "" #: fsutils.c:297 #, c-format msgid "" "Device \"%s\" appears to contain data (entropy=%.3g,%.3g) - please run " "mkswap manually\n" msgstr "" #: looputils.c:228 #, c-format msgid "Failed to free device (%d,%d)\n" msgstr "" #: looputils.c:264 #, c-format msgid "No available loopback devices\n" msgstr "" #: looputils.c:278 #, c-format msgid "Bad device type (%x) for \"%s\" (need block/file)\n" msgstr "" #: tables.c:549 #, c-format msgid "" "cryptmount: please replace \"fsoptions\" with \"mountoptions\" in cmtab\n" msgstr "" #: tables.c:554 #, c-format msgid "cryptmount: unrecognized option \"%s\" in cmtab\n" msgstr "" #: tables.c:637 #, c-format msgid "Configuration error near %s:%d\n" msgstr "" #: utils.c:316 #, c-format msgid "Unable to allocate memory\n" msgstr "" #: utils.c:439 #, c-format msgid "Too few random-number sources found\n" msgstr "" #: utils.c:498 #, c-format msgid "Cannot read stdin" msgstr "" #: utils.c:510 #, c-format msgid "Failed to turn off keyboard echoing on terminal\n" msgstr "" #: utils.c:540 #, c-format msgid "Enter new password for target \"%s\": " msgstr "" #: utils.c:541 #, c-format msgid "Enter password for target \"%s\": " msgstr "" #: utils.c:550 #, c-format msgid "Confirm password: " msgstr "" #: utils.c:553 #, c-format msgid "Password mismatch\n" msgstr "" #: utils.c:592 sysinit/setupscript.sh.in:237 #, sh-format msgid "yes" msgstr "" #: utils.c:599 #, c-format msgid "Are you sure? (Type \"%s\" to proceed): " msgstr "" #: utils.c:602 #, c-format msgid "Cannot read stdin\n" msgstr "" #: sysinit/setupscript.sh.in:41 #, sh-format msgid "Abandoning $ProgName ..." msgstr "" #: sysinit/setupscript.sh.in:49 #, sh-format msgid "" "This script must be run with superuser privileges - please try again, e.g. " "using one of the following:" msgstr "" #: sysinit/setupscript.sh.in:64 #, sh-format msgid "No LUKS support available - using built-in key manager" msgstr "" #: sysinit/setupscript.sh.in:123 #, sh-format msgid "opaque" msgstr "" #: sysinit/setupscript.sh.in:124 #, sh-format msgid "" "Each cryptmount filesystem is identifed by a short name which is used when " "mounting or configuring that filesystem. This name should be a single word " "(without spaces), such as \"${DefaultTargetName}\"." msgstr "" #: sysinit/setupscript.sh.in:125 #, sh-format msgid "The following target names have already been used:" msgstr "" #: sysinit/setupscript.sh.in:132 #, sh-format msgid "Please enter a target name for your filesystem" msgstr "" #: sysinit/setupscript.sh.in:136 #, sh-format msgid "The target-name \"${TargetName}\" has already been used" msgstr "" #: sysinit/setupscript.sh.in:144 #, sh-format msgid "" "The ${TargetName} filesystem can be configured to be owned by a nominated " "user, who will be able to create top-level files & directories without " "needing to involve the superuser." msgstr "" #: sysinit/setupscript.sh.in:146 #, sh-format msgid "Which user should own the filesystem (leave blank for \"root\")" msgstr "" #: sysinit/setupscript.sh.in:152 #, sh-format msgid "" "In order to access the ${TargetName} filesystem, it must be mounted on top " "of an empty directory." msgstr "" #: sysinit/setupscript.sh.in:156 #, sh-format msgid "Please specify where \"${TargetName}\" should be mounted" msgstr "" #: sysinit/setupscript.sh.in:160 #, sh-format msgid "${mount_dir} is not a valid directory name" msgstr "" #: sysinit/setupscript.sh.in:168 #, sh-format msgid "" "The maximum available size of your filesystem needs to be chosen so that " "enough space can be reserved on your disk." msgstr "" #: sysinit/setupscript.sh.in:172 #, sh-format msgid "Enter the filesystem size (in MB)" msgstr "" #: sysinit/setupscript.sh.in:177 #, sh-format msgid "${fs_size} is not a valid number" msgstr "" #: sysinit/setupscript.sh.in:183 #, sh-format msgid "" "The actual encrypted filesystem will be stored in a special file, which " "needs to be large enough to contain your entire encrypted filesystem." msgstr "" #: sysinit/setupscript.sh.in:187 #, sh-format msgid "Enter a filename for your encrypted container" msgstr "" #: sysinit/setupscript.sh.in:191 #, sh-format msgid "WARNING: ${crypto_dev} already exists" msgstr "" #: sysinit/setupscript.sh.in:204 #, sh-format msgid "" "Access to your encrypted filesystem is protected by a key that is kept in a " "separate small file. The key is locked by a password that you must enter " "whenever you mount the filesystem." msgstr "" #: sysinit/setupscript.sh.in:208 #, sh-format msgid "Enter a location for the keyfile" msgstr "" #: sysinit/setupscript.sh.in:212 #, sh-format msgid "WARNING: ${key_file} already exists" msgstr "" #: sysinit/setupscript.sh.in:224 #, sh-format msgid "Your filing system is now ready to be built - this will involve:" msgstr "" #: sysinit/setupscript.sh.in:225 #, sh-format msgid " - Creating the directory \"${mount_dir}\"" msgstr "" #: sysinit/setupscript.sh.in:226 #, sh-format msgid " - Creating a ${fs_size}MB file, \"${crypto_dev}\"" msgstr "" #: sysinit/setupscript.sh.in:227 #, sh-format msgid " - Adding an extra entry (\"${TargetName}\") in ${CM_CFGDIR}/cmtab" msgstr "" #: sysinit/setupscript.sh.in:229 #, sh-format msgid " - Creating a key-file (\"${key_file}\")" msgstr "" #: sysinit/setupscript.sh.in:231 #, sh-format msgid " - Creating an ext4 filingsystem on \"${crypto_dev}\"" msgstr "" #: sysinit/setupscript.sh.in:234 #, sh-format msgid " - Overwriting the backup configuration-file \"${bckp_cmtab}\"" msgstr "" #: sysinit/setupscript.sh.in:236 #, sh-format msgid "If you do not wish to proceed, no changes will be made to your system." msgstr "" #: sysinit/setupscript.sh.in:238 #, sh-format msgid "no" msgstr "" #: sysinit/setupscript.sh.in:239 #, sh-format msgid "" "Please confirm that you want to proceed (enter \"${AffirmativeResponse}\")" msgstr "" #: sysinit/setupscript.sh.in:242 #, sh-format msgid "Installation abandoned" msgstr "" #: sysinit/setupscript.sh.in:246 #, sh-format msgid "done" msgstr "" #: sysinit/setupscript.sh.in:248 #, sh-format msgid "Making mount-point (${mount_dir})..." msgstr "" #: sysinit/setupscript.sh.in:251 #, sh-format msgid "Creating filesystem container (${crypto_dev})..." msgstr "" #: sysinit/setupscript.sh.in:256 #, sh-format msgid "Taking backup of cryptmount master config-file (${bckp_cmtab})..." msgstr "" #: sysinit/setupscript.sh.in:272 #, sh-format msgid "Generating filesystem access key..." msgstr "" #: sysinit/setupscript.sh.in:280 #, sh-format msgid "Formatting encrypted filesystem..." msgstr "" #: sysinit/setupscript.sh.in:309 #, sh-format msgid "cryptmount setup script" msgstr "" #: sysinit/setupscript.sh.in:311 #, sh-format msgid "" "This program will allow you to setup a secure filing-system that will be " "managed by \"cryptmount\". You will be able to select basic features such as " "the location and size of the filesystem - if you want more advanced " "features, you should consult the cryptmount manual page." msgstr "" #: sysinit/setupscript.sh.in:314 #, sh-format msgid "cryptmount comes with ABSOLUTELY NO WARRANTY." msgstr "" #: sysinit/setupscript.sh.in:315 #, sh-format msgid "" "This is free software, and you are welcome to redistribute it under certain " "conditions - see the file 'COPYING' in the source directory." msgstr "" #: sysinit/setupscript.sh.in:342 #, sh-format msgid "Your new encrypted filesystem is now ready for use - to access, try:" msgstr "" #: sysinit/setupscript.sh.in:345 #, sh-format msgid "After you have finished using the filesystem, try:" msgstr "" cryptmount-6.3.0/po/de.po000066400000000000000000000576361465135467200153500ustar00rootroot00000000000000# German translation of the cryptmount language file resulting in de.po # Copyright © 2008-2014 Kai Wasserbäch # 2020,2022 Helge Kreutzmann # This file is distributed under the same license as the cryptmount package. # msgid "" msgstr "" "Project-Id-Version: cryptmount 6.0-1\n" "Report-Msgid-Bugs-To: cryptmount@rwpenney.uk\n" "POT-Creation-Date: 2024-07-20 14:24+0100\n" "PO-Revision-Date: 2022-09-11 20:18+0200\n" "Last-Translator: Helge Kreutzmann \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: armour.c:151 armour-builtin.c:300 armour-gcry.c:570 armour-gcry.c:726 #, c-format msgid "Key-extraction failed for \"%s\"\n" msgstr "Auslesen des Schlüssels für »%s« schlug fehl.\n" #: armour.c:173 #, c-format msgid "Key-writing failed for \"%s\"\n" msgstr "Schreiben des Schlüssels für »%s« schlug fehl.\n" #: armour.c:358 #, c-format msgid "Failed to open keyfile \"%s\" for target \"%s\"\n" msgstr "Öffnen der Schlüsseldatei »%s« für Ziel »%s« schlug fehl.\n" #: armour.c:366 #, c-format msgid "Missing keyfile for target \"%s\"\n" msgstr "Schlüsseldatei für Ziel »%s« fehlt.\n" #: armour.c:393 #, c-format msgid "Missing output keyfile for target \"%s\"\n" msgstr "Schlüsselausgabedatei für Ziel »%s« fehlt.\n" #: armour.c:786 #, c-format msgid "Specification for target \"%s\" contains non-absolute pathname\n" msgstr "Die Zielangabe für »%s« enthält eine nicht-absolute Pfadangabe.\n" #: armour-builtin.c:282 armour-gcry.c:552 armour-gcry.c:707 #, c-format msgid "Password mismatch when extracting key\n" msgstr "Fehlerhaftes Passwort während des Auslesens des Schlüssels.\n" #: armour-builtin.c:398 armour-gcry.c:631 armour-gcry.c:785 #, c-format msgid "Failed to create new key file\n" msgstr "Erstellen einer neuen Schlüsseldatei schlug fehl.\n" #: armour-gcry.c:177 #, c-format msgid "Couldn't find libgcrypt cipher \"%s\"\n" msgstr "Konnte libgcrypt-Chiffre »%s« nicht finden.\n" #: armour-gcry.c:186 #, c-format msgid "Couldn't find libgcrypt cipher mode \"%s\" - using fallback\n" msgstr "" "Konnte libgcrypt-Chiffrenmodus »%s« nicht finden - Rückfalloption wird " "verwandt\n" #: armour-gcry.c:192 #, c-format msgid "Couldn't find libgcrypt digest \"%s\"\n" msgstr "Konnte libgcrypt-Hash »%s« nicht finden.\n" #: armour-gcry.c:513 #, c-format msgid "Bad keyfile format (libgcrypt)\n" msgstr "Falsches Schlüsseldateiformat (libgcrypt).\n" #: armour-gcry.c:556 #, c-format msgid "Checksum mismatch in keyfile (gcry, %x != %x)\n" msgstr "" "Nicht übereinstimmende Prüfsumme in der Schlüsseldatei (gcry, %x != %x).\n" #: armour-gcry.c:672 #, c-format msgid "Bad keyfile format (openssl-compat)\n" msgstr "Falsches Schlüsseldateiformat (openssl-compat).\n" #: armour-gcry.c:711 #, c-format msgid "Checksum mismatch in keyfile (openssl-compat, ofs=%u,idx=%u)\n" msgstr "" "Nicht übereinstimmende Prüfsumme in der Schlüsseldatei (openssl-compat, " "ofs=%u, idx=%u).\n" #: armour-luks.c:217 #, c-format msgid "Failed to acquire privileges for LUKS container\n" msgstr "Erlangen von Privilegien für LUKS-Container schlug fehl.\n" #: armour-luks.c:310 armour-luks.c:394 #, c-format msgid "Failed to initialize device for LUKS keyfile\n" msgstr "Initialisieren eines Gerätes für LUKS-Schlüsseldatei schlug fehl.\n" #: armour-luks.c:320 #, c-format msgid "Failed to extract LUKS key for \"%s\" (errno=%d)\n" msgstr "Auslesen des LUKS-Schlüssels für »%s« schlug fehl (errno=%d).\n" #: armour-luks.c:381 #, c-format msgid "Formatting \"%s\", will probably destroy all existing data" msgstr "" "Formatiere »%s«, dies wird wahrscheinlich alle bestehenden Daten zerstören." #: armour-luks.c:410 #, c-format msgid "Failed to create LUKS header for \"%s\"\n" msgstr "Erstellen eines neuen LUKS-Headers für »%s« schlug fehl.\n" #: armour-luks.c:420 #, c-format msgid "Failed to create LUKS key for \"%s\"\n" msgstr "Erstellen eines neuen LUKS-Schlüssels für »%s« schlug fehl.\n" #: armour-luks.c:433 #, c-format msgid "Setting password on LUKS keyslot-%u\n" msgstr "Setze Passwort für den LUKS-Schlüsselplatz »%u«\n" #: cryptmount.c:126 msgid "" "usage: cryptmount [OPTION [target ...]]\n" "\n" " available options are as follows:\n" "\n" " -h | --help\n" " -a | --all\n" " -c | --change-password \n" " -k | --key-managers\n" " -l | --list\n" " -S | --status\n" " -m | --mount \n" " -u | --unmount \n" " --generate-key \n" " --reuse-key \n" " --prepare \n" " --release \n" " --config-fd \n" " --passwd-fd \n" " --swapon \n" " --swapoff \n" " --version\n" "\n" " please report bugs to \n" msgstr "" "Aufruf: cryptmount [OPTION [Ziel …]]\n" "\n" " Die folgenden Optionen sind verfügbar:\n" "\n" " -h | --help\n" " -a | --all\n" " -c | --change-password \n" " -k | --key-managers\n" " -l | --list\n" " -S | --status\n" " -m | --mount \n" " -u | --unmount \n" " --generate-key \n" " --reuse-key \n" " --prepare \n" " --release \n" " --config-fd \n" " --passwd-fd \n" " --swapon \n" " --swapoff \n" " --version\n" "\n" " Bitte melden Sie Fehler (auf Englisch) an .\n" #. TRANSLATORS: this string is marked as 'no-c-format' because #. some localizations may require the mount-point and filesystem type #. to be printed in a different order, but the untranslated string needs #. to remain an ordinary string that can be printed without gettext. #: cryptmount.c:261 #, no-c-format msgid "%-16s [to mount on \"%s\" as \"%s\"]\n" msgstr "%-16s [um »%3$s« unter »%2$s« einzuhängen]\n" #: cryptmount.c:393 #, c-format msgid "Failed to extract cipher key\n" msgstr "Auslesen des Chiffreschlüssels schlug fehl.\n" #: cryptmount.c:402 #, c-format msgid "Cannot open device \"%s\" for target \"%s\"\n" msgstr "Kann Gerät »%s« für Ziel »%s« nicht öffnen.\n" #: cryptmount.c:410 #, c-format msgid "Failed to get size of \"%s\"\n" msgstr "Konnte Größe von »%s« nicht ermitteln.\n" #: cryptmount.c:420 #, c-format msgid "Bad device-mapper start/length" msgstr "Falsche(r) device-mapper-Beginn/Länge." #: cryptmount.c:447 #, c-format msgid "Device-mapper target-creation failed for \"%s\"\n" msgstr "Erstellen des device-mapper-Ziels für »%s« schlug fehl.\n" #: cryptmount.c:487 cryptmount.c:724 #, c-format msgid "Target \"%s\" does not appear to be configured\n" msgstr "Ziel »%s« scheint unkonfiguriert zu sein.\n" #: cryptmount.c:505 #, c-format msgid "Cannot stat \"%s\"\n" msgstr "Kann Status für »%s« nicht abfragen.\n" #: cryptmount.c:513 #, c-format msgid "Failed to remove device-mapper target \"%s\"\n" msgstr "Entfernen des device-mapper-Ziels »%s« schlug fehl.\n" #: cryptmount.c:545 #, c-format msgid "Target \"%s\" is already mounted\n" msgstr "Ziel »%s« ist bereits eingehängt.\n" #: cryptmount.c:604 #, c-format msgid "Target \"%s\" does not appear to be mounted\n" msgstr "Ziel »%s« scheint noch nicht eingehängt zu sein.\n" #: cryptmount.c:614 #, c-format msgid "Only \"%s\" can unmount \"%s\"\n" msgstr "Nur »%s« kann »%s« aushängen.\n" #. TRANSLATORS: the following expands to include #. the *numerical* user-identity in place of '%lu', #. e.g. giving 'only user-16 can unmount "target"': #: cryptmount.c:620 #, c-format msgid "Only user-%lu can unmount \"%s\"\n" msgstr "Nur der Benutzer mit der ID »%lu« kann »%s« aushängen.\n" #: cryptmount.c:665 #, c-format msgid "Target \"%s\" is already configured\n" msgstr "Ziel »%s« ist bereits konfiguriert.\n" #: cryptmount.c:689 cryptmount.c:744 #, c-format msgid "Crypto-swap is not supported by this installation of cryptmount\n" msgstr "" "Crypto-swap wird von dieser cryptmount-Installation nicht unterstützt.\n" #: cryptmount.c:776 #, c-format msgid "Key-file for \"%s\" isn't password-protected\n" msgstr "Schlüsseldatei für »%s« ist nicht passwortgeschützt.\n" #: cryptmount.c:802 cryptmount.c:923 #, c-format msgid "Cannot open \"%s\" for writing\n" msgstr "Kann »%s« nicht zum Schreiben öffnen.\n" #: cryptmount.c:817 #, c-format msgid "Retiring old key (%s -> %s) failed\n" msgstr "Ausmustern des alten Schlüssels (%s -> %s) schlug fehl.\n" #: cryptmount.c:825 #, c-format msgid "Installing new key (%s -> %s) failed\n" msgstr "Installation des neuen Schlüssels (%s -> %s) schlug fehl.\n" #: cryptmount.c:832 #, c-format msgid "Backup of previous key is in \"%s\"\n" msgstr "Eine Sicherheitskopie des vorherigen Schlüssels ist in »%s«.\n" #: cryptmount.c:872 cryptmount.c:1548 #, c-format msgid "Target name \"%s\" is not recognized\n" msgstr "Zielname »%s« wurde nicht erkannt.\n" #: cryptmount.c:878 #, c-format msgid "Bad key-length parameter" msgstr "Falscher Schlüssellängen-Parameter" #: cryptmount.c:890 #, c-format msgid "Key-file \"%s\" already exists for target \"%s\"\n" msgstr "Schlüsseldatei »%s« existiert für das Ziel »%s« bereits.\n" #: cryptmount.c:900 #, c-format msgid "Generating random key; please be patient...\n" msgstr "Erstelle zufälligen Schlüssel; bitte warten Sie …\n" #: cryptmount.c:904 #, c-format msgid "Failed to generate new key\n" msgstr "Generieren des neuen Schlüssels schlug fehl\n" #: cryptmount.c:937 #, c-format msgid "Installation of new keyfile \"%s\" failed" msgstr "Installation der neuen Schlüsseldatei »%s« schlug fehl." #: cryptmount.c:1072 #, c-format msgid "Only root can use option \"%s\"\n" msgstr "Nur root kann die Option »%s« verwenden.\n" #: cryptmount.c:1085 #, c-format msgid "Only root can configure \"%s\"\n" msgstr "Nur root kann »%s« konfigurieren.\n" #: cryptmount.c:1149 #, c-format msgid "Cannot find key-manager to match target \"%s\"\n" msgstr "Kann keinen für das Ziel »%s« passenden Schlüsselmanager finden.\n" #: cryptmount.c:1416 #, c-format msgid "Multiple operating modes not supported\n" msgstr "Mehrere Betriebsmodi werden nicht unterstützt\n" #: cryptmount.c:1471 #, c-format msgid "Memory-locking failed...\n" msgstr "Sperren des Arbeitsspeichers schlug fehl …\n" #: cryptmount.c:1499 #, c-format msgid "Bad file-descriptor (%d)\n" msgstr "Fehlerhafter Dateideskriptor (%d)\n" #: cryptmount.c:1509 #, c-format msgid "Security failure\n" msgstr "Sicherheitsfehler\n" #: cryptmount.c:1528 #, c-format msgid "Trailing command-line arguments given with '--all' option\n" msgstr "" "Abschließende Befehlszeilen-Argumente; wurden zusammen mit der Option »--" "all« angegeben.\n" #: cryptmount.c:1560 #, c-format msgid "Target security failure for \"%s\"\n" msgstr "Sicherheitsfehler für Ziel »%s«.\n" #: cryptmount.c:1569 #, c-format msgid "No targets specified\n" msgstr "Keine Ziele angegeben.\n" #: fsutils.c:267 #, c-format msgid "Unsuitable filesystem type \"%s\" for swapping\n" msgstr "Unpassender Dateisystemtyp »%s« zum Auslagern.\n" #: fsutils.c:297 #, c-format msgid "" "Device \"%s\" appears to contain data (entropy=%.3g,%.3g) - please run " "mkswap manually\n" msgstr "" "Das Gerät »%s« scheint Daten zu enthalten (Entropie=%.3g,%.3g) – bitte " "führen Sie mkswap manuell aus.\n" #: looputils.c:228 #, c-format msgid "Failed to free device (%d,%d)\n" msgstr "Konnte Gerät (%d,%d) nicht freigeben.\n" #: looputils.c:264 #, c-format msgid "No available loopback devices\n" msgstr "Keine verfügbaren Loopback-Geräte.\n" #: looputils.c:278 #, c-format msgid "Bad device type (%x) for \"%s\" (need block/file)\n" msgstr "Falscher Gerätetyp (%x) für »%s« (Block/Datei benötigt).\n" #: tables.c:549 #, c-format msgid "" "cryptmount: please replace \"fsoptions\" with \"mountoptions\" in cmtab\n" msgstr "" "cryptmount: Bitte ersetzen »fsoptions« mit »mountoptions« in der cmtab\n" #: tables.c:554 #, c-format msgid "cryptmount: unrecognized option \"%s\" in cmtab\n" msgstr "cryptmount: Nicht unterstützte Option »%s« in der cmtab.\n" #: tables.c:637 #, c-format msgid "Configuration error near %s:%d\n" msgstr "Konfigurationsfehler nahe %s:%d\n" #: utils.c:316 #, c-format msgid "Unable to allocate memory\n" msgstr "Konnte keinen Speicher reservieren.\n" #: utils.c:439 #, c-format msgid "Too few random-number sources found\n" msgstr "Zu wenige Zufallszahlenquellen gefunden.\n" #: utils.c:498 #, c-format msgid "Cannot read stdin" msgstr "Kann nicht von der Standardeingabe lesen." #: utils.c:510 #, c-format msgid "Failed to turn off keyboard echoing on terminal\n" msgstr "Konnte die Wiedergabe der Tastatureingabe nicht deaktivieren.\n" #: utils.c:540 #, c-format msgid "Enter new password for target \"%s\": " msgstr "Bitte geben Sie ein neues Passwort für das Ziel »%s« ein: " #: utils.c:541 #, c-format msgid "Enter password for target \"%s\": " msgstr "Bitte geben Sie das Passwort für das Ziel »%s« ein: " #: utils.c:550 #, c-format msgid "Confirm password: " msgstr "Passwort bestätigen: " #: utils.c:553 #, c-format msgid "Password mismatch\n" msgstr "Passworte stimmen nicht überein.\n" #: utils.c:592 sysinit/setupscript.sh.in:237 #, sh-format msgid "yes" msgstr "ja" #: utils.c:599 #, c-format msgid "Are you sure? (Type \"%s\" to proceed): " msgstr "Sind Sie sicher? (Geben Sie »%s« ein, um fortzufahren): " #: utils.c:602 #, c-format msgid "Cannot read stdin\n" msgstr "Kann nicht von der Standardeingabe lesen.\n" #: sysinit/setupscript.sh.in:41 #, sh-format msgid "Abandoning $ProgName ..." msgstr "Beende $ProgName …" #: sysinit/setupscript.sh.in:49 #, sh-format msgid "" "This script must be run with superuser privileges - please try again, e.g. " "using one of the following:" msgstr "" "Dieses Skript muss mit den Rechten von root (superuser) ausgeführt werden - " "bitte versuchen Sie es z.B. mit einem der folgenden Benutzernamen erneut:" #: sysinit/setupscript.sh.in:64 #, sh-format msgid "No LUKS support available - using built-in key manager" msgstr "" "Keine LUKS-Unterstützung verfügbar - eingebauter Schlüsselverwalter wird " "verwandt" #: sysinit/setupscript.sh.in:123 #, sh-format msgid "opaque" msgstr "undurchlässig" #: sysinit/setupscript.sh.in:124 #, sh-format msgid "" "Each cryptmount filesystem is identifed by a short name which is used when " "mounting or configuring that filesystem. This name should be a single word " "(without spaces), such as \"${DefaultTargetName}\"." msgstr "" "Jedes cryptmount-Dateisystem wird durch einen Kurznamen identifiziert, der " "verwandt wird, wenn das Dateisystem eingehängt oder konfiguriert wird. " "Dieser Name sollte ein einzelnes Wort (ohne Leerzeichen) wie beispielsweise " "»${DefaultTargetName}« sein." #: sysinit/setupscript.sh.in:125 #, sh-format msgid "The following target names have already been used:" msgstr "Die folgenden Zielnamen werden bereits verwandt:" #: sysinit/setupscript.sh.in:132 #, sh-format msgid "Please enter a target name for your filesystem" msgstr "Bitte geben Sie einen Zielnamen für Ihr Dateisystem ein." #: sysinit/setupscript.sh.in:136 #, sh-format msgid "The target-name \"${TargetName}\" has already been used" msgstr "Der Zielname »${TargetName}« wird bereits verwandt." #: sysinit/setupscript.sh.in:144 #, sh-format msgid "" "The ${TargetName} filesystem can be configured to be owned by a nominated " "user, who will be able to create top-level files & directories without " "needing to involve the superuser." msgstr "" "Das Dateisystem mit dem Namen »${TargetName}« kann so konfiguriert werden, " "dass es einem bestimmten Benutzer gehört, der dann ohne den Superuser im " "Wurzelverzeichnis des Dateisystems Dateien und Verzeichnisse erstellen kann." #: sysinit/setupscript.sh.in:146 #, sh-format msgid "Which user should own the filesystem (leave blank for \"root\")" msgstr "" "Welchem Benutzer soll das Dateisystem gehören (leer lassen für »root«)?" #: sysinit/setupscript.sh.in:152 #, sh-format msgid "" "In order to access the ${TargetName} filesystem, it must be mounted on top " "of an empty directory." msgstr "" "Um auf das Dateisystem »${TargetName}« zugreifen zu können, muss es in ein " "leeres Verzeichnis eingehängt werden." #: sysinit/setupscript.sh.in:156 #, sh-format msgid "Please specify where \"${TargetName}\" should be mounted" msgstr "Bitte geben Sie an, wo »${TargetName}« eingehängt werden soll." #: sysinit/setupscript.sh.in:160 #, sh-format msgid "${mount_dir} is not a valid directory name" msgstr "»${mount_dir}« ist kein gültiger Verzeichnisname." #: sysinit/setupscript.sh.in:168 #, sh-format msgid "" "The maximum available size of your filesystem needs to be chosen so that " "enough space can be reserved on your disk." msgstr "" "Die maximal verfügbare Größe des Dateisystems muss angegeben werden, damit " "auf der Festplatte ausreichend Speicherplatz reserviert werden kann." #: sysinit/setupscript.sh.in:172 #, sh-format msgid "Enter the filesystem size (in MB)" msgstr "Bitte geben Sie die Größe des Dateisystems ein (in MB)." #: sysinit/setupscript.sh.in:177 #, sh-format msgid "${fs_size} is not a valid number" msgstr "»${fs_size}« ist keine gültige Zahl" #: sysinit/setupscript.sh.in:183 #, sh-format msgid "" "The actual encrypted filesystem will be stored in a special file, which " "needs to be large enough to contain your entire encrypted filesystem." msgstr "" "Das eigentliche verschlüsselte Dateisystem wird in einer speziellen Datei " "abgelegt, die groß genug sein muss, um Ihr komplettes verschlüsseltes " "Dateisystem zu enthalten." #: sysinit/setupscript.sh.in:187 #, sh-format msgid "Enter a filename for your encrypted container" msgstr "Bitte geben Sie einen Dateinamen für den verschlüsselten Container an" #: sysinit/setupscript.sh.in:191 #, sh-format msgid "WARNING: ${crypto_dev} already exists" msgstr "WARNUNG: »${crypto_dev}« existiert bereits." #: sysinit/setupscript.sh.in:204 #, sh-format msgid "" "Access to your encrypted filesystem is protected by a key that is kept in a " "separate small file. The key is locked by a password that you must enter " "whenever you mount the filesystem." msgstr "" "Der Zugriff auf Ihr verschlüsseltes Dateisystem wird durch einen Schlüssel " "geschützt, der in einer kleinen, separaten Datei gespeichert wird. Der " "Schlüssel wird durch ein Passwort gesichert, welches Sie jedes Mal eingeben " "müssen, wenn Sie das Dateisystem einhängen wollen." #: sysinit/setupscript.sh.in:208 #, sh-format msgid "Enter a location for the keyfile" msgstr "Bitte geben Sie einen Speicherplatz für die Schlüsseldatei ein." #: sysinit/setupscript.sh.in:212 #, sh-format msgid "WARNING: ${key_file} already exists" msgstr "WARNUNG: »${key_file}« existiert bereits." #: sysinit/setupscript.sh.in:224 #, sh-format msgid "Your filing system is now ready to be built - this will involve:" msgstr "" "Ihr Dateisystem kann nun erstellt werden, dies umfasst die folgenden " "Schritte:" #: sysinit/setupscript.sh.in:225 #, sh-format msgid " - Creating the directory \"${mount_dir}\"" msgstr " - Erstellen des Verzeichnisses »${mount_dir}«" #: sysinit/setupscript.sh.in:226 #, sh-format msgid " - Creating a ${fs_size}MB file, \"${crypto_dev}\"" msgstr "" " - Erstellen einer ${fs_size} MB großen Datei mit dem Namen »${crypto_dev}«" #: sysinit/setupscript.sh.in:227 #, sh-format msgid " - Adding an extra entry (\"${TargetName}\") in ${CM_CFGDIR}/cmtab" msgstr "" " - Hinzufügen eines zusätzlichen Eintrags (»${TargetName}«) in ${CM_CFGDIR}/" "cmtab" #: sysinit/setupscript.sh.in:229 #, sh-format msgid " - Creating a key-file (\"${key_file}\")" msgstr " - Erstellen der Schlüsseldatei »${key_file}«" #: sysinit/setupscript.sh.in:231 #, sh-format msgid " - Creating an ext4 filingsystem on \"${crypto_dev}\"" msgstr " - Erstellen eines ext4-Dateisystems auf »${crypto_dev}«" #: sysinit/setupscript.sh.in:234 #, sh-format msgid " - Overwriting the backup configuration-file \"${bckp_cmtab}\"" msgstr "" " - Überschreiben der Sicherheitskopie der Konfigurationsdatei ${bckp_cmtab}" #: sysinit/setupscript.sh.in:236 #, sh-format msgid "If you do not wish to proceed, no changes will be made to your system." msgstr "" "Falls Sie nicht fortfahren möchten, werden keine Änderungen an Ihrem System " "vorgenommen." #: sysinit/setupscript.sh.in:238 #, sh-format msgid "no" msgstr "nein" #: sysinit/setupscript.sh.in:239 #, sh-format msgid "" "Please confirm that you want to proceed (enter \"${AffirmativeResponse}\")" msgstr "" "Bitte bestätigen Sie, dass Sie fortfahren möchten (geben Sie bitte " "»${AffirmativeResponse}« ein)" #: sysinit/setupscript.sh.in:242 #, sh-format msgid "Installation abandoned" msgstr "Installation abgebrochen" #: sysinit/setupscript.sh.in:246 #, sh-format msgid "done" msgstr "erledigt" #: sysinit/setupscript.sh.in:248 #, sh-format msgid "Making mount-point (${mount_dir})..." msgstr "Erstelle Einhängepunkt »${mount_dir}« …" #: sysinit/setupscript.sh.in:251 #, sh-format msgid "Creating filesystem container (${crypto_dev})..." msgstr "Erstelle Dateisystemcontainer »${crypto_dev}« …" #: sysinit/setupscript.sh.in:256 #, sh-format msgid "Taking backup of cryptmount master config-file (${bckp_cmtab})..." msgstr "" "Erstelle Sicherheitskopie der Haupt-Cryptmount-Konfigurationsdatei " "»${bckp_cmtab}« …" #: sysinit/setupscript.sh.in:272 #, sh-format msgid "Generating filesystem access key..." msgstr "Erstelle Zugriffsschlüssel für das Dateisystem …" #: sysinit/setupscript.sh.in:280 #, sh-format msgid "Formatting encrypted filesystem..." msgstr "Formatiere das verschlüsselte Dateisystem …" #: sysinit/setupscript.sh.in:309 #, sh-format msgid "cryptmount setup script" msgstr "cryptmount-Einrichtungsskript" #: sysinit/setupscript.sh.in:311 #, sh-format msgid "" "This program will allow you to setup a secure filing-system that will be " "managed by \"cryptmount\". You will be able to select basic features such as " "the location and size of the filesystem - if you want more advanced " "features, you should consult the cryptmount manual page." msgstr "" "Dieses Programm erlaubt es Ihnen, ein verschlüsseltes Dateisystem zu " "erstellen, welches von »cryptmount« verwaltet wird. Sie können grundlegende " "Eigenschaften wie Speicherort und Größe des Dateisystems einstellen. Wollen " "Sie weitere fortgeschrittenere Eigenschaften beeinflussen, sollten Sie die " "Handbuchseite von »cryptmount« lesen." #: sysinit/setupscript.sh.in:314 #, sh-format msgid "cryptmount comes with ABSOLUTELY NO WARRANTY." msgstr "cryptmount wird OHNE JEDWEDE GARANTIEN angeboten." #: sysinit/setupscript.sh.in:315 #, sh-format msgid "" "This is free software, and you are welcome to redistribute it under certain " "conditions - see the file 'COPYING' in the source directory." msgstr "" "Dies ist freie Software und Sie dürfen sie unter bestimmten Bedingungen " "weiterverbreiten - die Details finden Sie in der Datei »COPYING« im " "Quellcodeverzeichnis." #: sysinit/setupscript.sh.in:342 #, sh-format msgid "Your new encrypted filesystem is now ready for use - to access, try:" msgstr "" "Ihr neues, verschlüsseltes Dateisystem kann nun verwandt werden. Um darauf " "zuzugreifen, versuchen Sie Folgendes:" #: sysinit/setupscript.sh.in:345 #, sh-format msgid "After you have finished using the filesystem, try:" msgstr "Nach der Benutzung des Dateisystems, geben Sie bitte Folgendes ein:" #~ msgid "Failed to read LUKS header for \"%s\"\n" #~ msgstr "Konnte LUKS-Header von »%s« nicht lesen.\n" #~ msgid "" #~ "Writing LUKS keys is not possible unless cryptmount has been built with " #~ "the uuid-dev package installed\n" #~ msgstr "" #~ "Nur falls das »uuid-dev«-Paket beim kompilieren von cryptmount verfügbar " #~ "war, können LUKS-Schlüssel geschrieben werden.\n" #~ msgid "" #~ "cryptmount: using \"keycipher=none\" is deprecated - please use " #~ "\"keyformat=raw\" instead\n" #~ msgstr "" #~ "cryptmount: Die Verwendung von »keycipher=none« ist veraltet - bitte " #~ "verwenden Sie stattdessen »keyformat=raw«.\n" #~ msgid "Missing parameter\n" #~ msgstr "Fehlender Parameter\n" cryptmount-6.3.0/po/en@boldquot.header000066400000000000000000000024711465135467200200310ustar00rootroot00000000000000# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # # This catalog furthermore displays the text between the quotation marks in # bold face, assuming the VT100/XTerm escape sequences. # cryptmount-6.3.0/po/en@quot.header000066400000000000000000000022631465135467200171670ustar00rootroot00000000000000# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # cryptmount-6.3.0/po/fr.po000066400000000000000000000556711465135467200153640ustar00rootroot00000000000000# French translations for cryptmount package. # Copyright (C) 2006-2024 RW Penney # This file is distributed under the same license as the cryptmount package. # msgid "" msgstr "" "Project-Id-Version: cryptmount 4.0-1\n" "Report-Msgid-Bugs-To: cryptmount@rwpenney.uk\n" "POT-Creation-Date: 2024-07-20 14:24+0100\n" "PO-Revision-Date: 2006-04-21 07:51+0100\n" "Last-Translator: RW Penney \n" "Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: armour.c:151 armour-builtin.c:300 armour-gcry.c:570 armour-gcry.c:726 #, c-format msgid "Key-extraction failed for \"%s\"\n" msgstr "Extraction de la clef pour \"%s\" a echoue\n" #: armour.c:173 #, c-format msgid "Key-writing failed for \"%s\"\n" msgstr "Ecriture de la clef pour \"%s\" a echoue\n" #: armour.c:358 #, c-format msgid "Failed to open keyfile \"%s\" for target \"%s\"\n" msgstr "Ouverture du fichier \"%s\" pour la cible \"%s\" a echoue\n" #: armour.c:366 #, c-format msgid "Missing keyfile for target \"%s\"\n" msgstr "Pas de fichier-clef pour la cible \"%s\"\n" #: armour.c:393 #, c-format msgid "Missing output keyfile for target \"%s\"\n" msgstr "Pas de fichier-clef pour la cible \"%s\"\n" #: armour.c:786 #, c-format msgid "Specification for target \"%s\" contains non-absolute pathname\n" msgstr "" #: armour-builtin.c:282 armour-gcry.c:552 armour-gcry.c:707 #, c-format msgid "Password mismatch when extracting key\n" msgstr "Mot de passe n'est pas verifi\n" #: armour-builtin.c:398 armour-gcry.c:631 armour-gcry.c:785 #, c-format msgid "Failed to create new key file\n" msgstr "Gnration de nouvelle clef a echoue\n" #: armour-gcry.c:177 #, c-format msgid "Couldn't find libgcrypt cipher \"%s\"\n" msgstr "Chiffre \"%s\" n'est pas reconnu dans libgcrypt\n" #: armour-gcry.c:186 #, c-format msgid "Couldn't find libgcrypt cipher mode \"%s\" - using fallback\n" msgstr "Mode de chiffrage \"%s\" n'est pas reconnu dans libgcrypt\n" #: armour-gcry.c:192 #, c-format msgid "Couldn't find libgcrypt digest \"%s\"\n" msgstr "Hash \"%s\" n'est pas reconnu dans libgcrypt\n" #: armour-gcry.c:513 #, c-format msgid "Bad keyfile format (libgcrypt)\n" msgstr "Mauvais fichier-clef (libcrypt)\n" #: armour-gcry.c:556 #, c-format msgid "Checksum mismatch in keyfile (gcry, %x != %x)\n" msgstr "Mauvais fichier-clef (gcry, %x != %x)\n" #: armour-gcry.c:672 #, c-format msgid "Bad keyfile format (openssl-compat)\n" msgstr "Mauvais fichier-clef (openssl-compat)\n" #: armour-gcry.c:711 #, c-format msgid "Checksum mismatch in keyfile (openssl-compat, ofs=%u,idx=%u)\n" msgstr "Mauvais fichier-clef (openssl-compat, ofs=%u,idx=%u)\n" #: armour-luks.c:217 #, c-format msgid "Failed to acquire privileges for LUKS container\n" msgstr "chec de l'acquisition des privilges pour le fichier-clef LUKS\n" #: armour-luks.c:310 armour-luks.c:394 #, c-format msgid "Failed to initialize device for LUKS keyfile\n" msgstr "chec de l'initialisation des appareils pour le fichier-clef LUKS\n" #: armour-luks.c:320 #, c-format msgid "Failed to extract LUKS key for \"%s\" (errno=%d)\n" msgstr "Extraction de la clef LUKS a echoue pour la cible \"%s\" (errno=%d)\n" #: armour-luks.c:381 #, c-format msgid "Formatting \"%s\", will probably destroy all existing data" msgstr "Formatage de \"%s\" va detruire tous donns sur ce conteneur" #: armour-luks.c:410 #, c-format msgid "Failed to create LUKS header for \"%s\"\n" msgstr "Gnration d'en-tte LUKS pour \"%s\" a echoue\n" #: armour-luks.c:420 #, c-format msgid "Failed to create LUKS key for \"%s\"\n" msgstr "Gnration de clef LUKS pour \"%s\" a echoue\n" #: armour-luks.c:433 #, c-format msgid "Setting password on LUKS keyslot-%u\n" msgstr "" #: cryptmount.c:126 msgid "" "usage: cryptmount [OPTION [target ...]]\n" "\n" " available options are as follows:\n" "\n" " -h | --help\n" " -a | --all\n" " -c | --change-password \n" " -k | --key-managers\n" " -l | --list\n" " -S | --status\n" " -m | --mount \n" " -u | --unmount \n" " --generate-key \n" " --reuse-key \n" " --prepare \n" " --release \n" " --config-fd \n" " --passwd-fd \n" " --swapon \n" " --swapoff \n" " --version\n" "\n" " please report bugs to \n" msgstr "" "usage: cryptmount [OPTION [cible ...]]\n" "\n" " les options disponible sont les suivants:\n" "\n" " -h | --help\n" " -a | --all\n" " -c | --change-password \n" " -k | --key-managers\n" " -l | --list\n" " -S | --status\n" " -m | --mount \n" " -u | --unmount \n" " --generate-key \n" " --reuse-key \n" " --prepare \n" " --release \n" " --config-fd \n" " --passwd-fd \n" " --swapon \n" " --swapoff \n" " --version\n" "\n" " veuillez notifier les bogues \n" #. TRANSLATORS: this string is marked as 'no-c-format' because #. some localizations may require the mount-point and filesystem type #. to be printed in a different order, but the untranslated string needs #. to remain an ordinary string that can be printed without gettext. #: cryptmount.c:261 #, no-c-format msgid "%-16s [to mount on \"%s\" as \"%s\"]\n" msgstr "%-16s [pour monter sur \"%s\" comme \"%s\"]\n" #: cryptmount.c:393 #, c-format msgid "Failed to extract cipher key\n" msgstr "Extraction de la clef de dchiffrage a echoue\n" #: cryptmount.c:402 #, c-format msgid "Cannot open device \"%s\" for target \"%s\"\n" msgstr "Ne peut pas ouvrir le priphrique \"%s\" pour la cible \"%s\"\n" #: cryptmount.c:410 #, c-format msgid "Failed to get size of \"%s\"\n" msgstr "Mesurage de la taille du \"%s\" a echou\n" #: cryptmount.c:420 #, c-format msgid "Bad device-mapper start/length" msgstr "Mauvais debut/taille pour device-mapper" #: cryptmount.c:447 #, c-format msgid "Device-mapper target-creation failed for \"%s\"\n" msgstr "Cration de la cible device-mapper pour \"%s\" a echoue\n" #: cryptmount.c:487 cryptmount.c:724 #, c-format msgid "Target \"%s\" does not appear to be configured\n" msgstr "La cible \"%s\" n'a pas t configure\n" #: cryptmount.c:505 #, c-format msgid "Cannot stat \"%s\"\n" msgstr "Ne pas pouvoir stat \"%s\"\n" #: cryptmount.c:513 #, c-format msgid "Failed to remove device-mapper target \"%s\"\n" msgstr "Destruction de la cible device-mapper \"%s\" a echoue\n" #: cryptmount.c:545 #, c-format msgid "Target \"%s\" is already mounted\n" msgstr "La cible \"%s\" est dj monte\n" #: cryptmount.c:604 #, c-format msgid "Target \"%s\" does not appear to be mounted\n" msgstr "La cible \"%s\" n'est pas monte\n" #: cryptmount.c:614 #, c-format msgid "Only \"%s\" can unmount \"%s\"\n" msgstr "Seulement utilisateur \"%s\" peut dmonter \"%s\"\n" #. TRANSLATORS: the following expands to include #. the *numerical* user-identity in place of '%lu', #. e.g. giving 'only user-16 can unmount "target"': #: cryptmount.c:620 #, c-format msgid "Only user-%lu can unmount \"%s\"\n" msgstr "Seulement utilisateur-%lu peut dmonter \"%s\"\n" #: cryptmount.c:665 #, c-format msgid "Target \"%s\" is already configured\n" msgstr "La cible \"%s\" est dj configure\n" #: cryptmount.c:689 cryptmount.c:744 #, c-format msgid "Crypto-swap is not supported by this installation of cryptmount\n" msgstr "" "Pagination chiffre n'est pas possible avec cet installation de cryptmount\n" #: cryptmount.c:776 #, c-format msgid "Key-file for \"%s\" isn't password-protected\n" msgstr "Le fichier-clef pour \"%s\" n'est pas protger par mot de passe\n" #: cryptmount.c:802 cryptmount.c:923 #, c-format msgid "Cannot open \"%s\" for writing\n" msgstr "Ne pas pouvoir ecrire \"%s\"\n" #: cryptmount.c:817 #, c-format msgid "Retiring old key (%s -> %s) failed\n" msgstr "Retraitment de vielle fichier-clef (%s -> %s) a echoue\n" #: cryptmount.c:825 #, c-format msgid "Installing new key (%s -> %s) failed\n" msgstr "Installation de nouvelle fichier-clef (%s -> %s) a echoue\n" #: cryptmount.c:832 #, c-format msgid "Backup of previous key is in \"%s\"\n" msgstr "Une sauvegarde de l'ancienne clef est dans \"%s\"\n" #: cryptmount.c:872 cryptmount.c:1548 #, c-format msgid "Target name \"%s\" is not recognized\n" msgstr "Nom de cible \"%s\" n'est pas reconnu\n" #: cryptmount.c:878 #, c-format msgid "Bad key-length parameter" msgstr "Mauvaise paramtre pour la taille de la clef" #: cryptmount.c:890 #, c-format msgid "Key-file \"%s\" already exists for target \"%s\"\n" msgstr "Le fichier-clef \"%s\" existe dj pour la cible \"%s\"\n" #: cryptmount.c:900 #, c-format msgid "Generating random key; please be patient...\n" msgstr "Veuillez attendre pendant la cration d'une clef alatoire...\n" #: cryptmount.c:904 #, c-format msgid "Failed to generate new key\n" msgstr "Gnration de nouvelle clef a echoue\n" #: cryptmount.c:937 #, c-format msgid "Installation of new keyfile \"%s\" failed" msgstr "Installation de novelle fichier-clef \"%s\" a echoue" #: cryptmount.c:1072 #, c-format msgid "Only root can use option \"%s\"\n" msgstr "Seulement le super-utilisateur peut utiliser \"%s\"\n" #: cryptmount.c:1085 #, c-format msgid "Only root can configure \"%s\"\n" msgstr "Seulement le super-utilisateur peut configurer \"%s\"\n" #: cryptmount.c:1149 #, c-format msgid "Cannot find key-manager to match target \"%s\"\n" msgstr "Ne peut pas trouver un diriger-clef pour la cible \"%s\"\n" #: cryptmount.c:1416 #, c-format msgid "Multiple operating modes not supported\n" msgstr "" #: cryptmount.c:1471 #, c-format msgid "Memory-locking failed...\n" msgstr "Verrouillage de la memoire a echou...\n" #: cryptmount.c:1499 #, c-format msgid "Bad file-descriptor (%d)\n" msgstr "Maivais descripteur de fichier (%d)\n" #: cryptmount.c:1509 #, c-format msgid "Security failure\n" msgstr "Echec de securit\n" #: cryptmount.c:1528 #, c-format msgid "Trailing command-line arguments given with '--all' option\n" msgstr "Arguments donns aprs option '--all'\n" #: cryptmount.c:1560 #, c-format msgid "Target security failure for \"%s\"\n" msgstr "Echec de securit pour cible \"%s\"\n" #: cryptmount.c:1569 #, c-format msgid "No targets specified\n" msgstr "Pas de cible donne\n" #: fsutils.c:267 #, c-format msgid "Unsuitable filesystem type \"%s\" for swapping\n" msgstr "Mauvaise type de systme de fichiers \"%s\" pour la pagination\n" #: fsutils.c:297 #, c-format msgid "" "Device \"%s\" appears to contain data (entropy=%.3g,%.3g) - please run " "mkswap manually\n" msgstr "" "Priphrique \"%s\" semble contenir des donnes valable (entropy=%.3g,%.3g) " "- veuillez utiliser mkswap manuellement\n" #: looputils.c:228 #, c-format msgid "Failed to free device (%d,%d)\n" msgstr "Dgagement du priphrique (%d,%d) a echou\n" #: looputils.c:264 #, c-format msgid "No available loopback devices\n" msgstr "Il n'y a aucun priph-loop disponible\n" #: looputils.c:278 #, c-format msgid "Bad device type (%x) for \"%s\" (need block/file)\n" msgstr "" "Mauvais type (%x) du priphrique pour \"%s\" (on a besoin du block/file)\n" #: tables.c:549 #, c-format msgid "" "cryptmount: please replace \"fsoptions\" with \"mountoptions\" in cmtab\n" msgstr "" "cryptmount: veillez remplacer \"fsoptions\" avec \"mountoptions\" dans votre " "cmtab\n" #: tables.c:554 #, c-format msgid "cryptmount: unrecognized option \"%s\" in cmtab\n" msgstr "cryptmount: mauvaise option \"%s\" dans votre cmtab\n" #: tables.c:637 #, c-format msgid "Configuration error near %s:%d\n" msgstr "Echec de configuration prs de %s:%d\n" #: utils.c:316 #, c-format msgid "Unable to allocate memory\n" msgstr "" #: utils.c:439 #, c-format msgid "Too few random-number sources found\n" msgstr "" #: utils.c:498 #, c-format msgid "Cannot read stdin" msgstr "" #: utils.c:510 #, c-format msgid "Failed to turn off keyboard echoing on terminal\n" msgstr "" #: utils.c:540 #, c-format msgid "Enter new password for target \"%s\": " msgstr "Donnez nouveau mot de passe pour la cible \"%s\": " #: utils.c:541 #, c-format msgid "Enter password for target \"%s\": " msgstr "Donnez mot de passe pour la cible \"%s\": " #: utils.c:550 #, c-format msgid "Confirm password: " msgstr "Confirmez mot de passe: " #: utils.c:553 #, c-format msgid "Password mismatch\n" msgstr "Les deux mots de passe sont differents\n" #: utils.c:592 sysinit/setupscript.sh.in:237 #, sh-format msgid "yes" msgstr "oui" #: utils.c:599 #, c-format msgid "Are you sure? (Type \"%s\" to proceed): " msgstr "Etes vous sr? (Tappez \"%s\" pour continuer): " #: utils.c:602 #, c-format msgid "Cannot read stdin\n" msgstr "" #: sysinit/setupscript.sh.in:41 #, sh-format msgid "Abandoning $ProgName ..." msgstr "$ProgName va se terminer ..." #: sysinit/setupscript.sh.in:49 #, sh-format msgid "" "This script must be run with superuser privileges - please try again, e.g. " "using one of the following:" msgstr "" "Ce script est seulement pour le super-utilisateur - veuillez essayer avec " "par exemple:" #: sysinit/setupscript.sh.in:64 #, sh-format msgid "No LUKS support available - using built-in key manager" msgstr "" #: sysinit/setupscript.sh.in:123 #, sh-format msgid "opaque" msgstr "secret" #: sysinit/setupscript.sh.in:124 #, sh-format msgid "" "Each cryptmount filesystem is identifed by a short name which is used when " "mounting or configuring that filesystem. This name should be a single word " "(without spaces), such as \"${DefaultTargetName}\"." msgstr "" "Chaque systme de fichiers dirig par cryptmount est appel par un nom court " "qu'on utilise pendant le montage ou la configuration de cette systme de " "fichiers. Ce nom doit tre un seul mot (sans espaces), comme par exemple " "\"${DefaultTargetName}\"." #: sysinit/setupscript.sh.in:125 #, sh-format msgid "The following target names have already been used:" msgstr "Les noms de cible suivants sont dj pris:" #: sysinit/setupscript.sh.in:132 #, sh-format msgid "Please enter a target name for your filesystem" msgstr "Veuillez donnez un nom de cible pour votre systme de fichiers" #: sysinit/setupscript.sh.in:136 #, sh-format msgid "The target-name \"${TargetName}\" has already been used" msgstr "Le nom de cible \"${TargetName}\" est dj pris" #: sysinit/setupscript.sh.in:144 #, sh-format msgid "" "The ${TargetName} filesystem can be configured to be owned by a nominated " "user, who will be able to create top-level files & directories without " "needing to involve the superuser." msgstr "" "Il est possible de donner possession du ${TargetName} un utilisateur " "specifique pour que cet utilisateur puisse crer des fichiers et rpertoires " "sans besoin du super-utilisateur." #: sysinit/setupscript.sh.in:146 #, sh-format msgid "Which user should own the filesystem (leave blank for \"root\")" msgstr "" "Quel utilisateur doit posseder le systme de fichiers (laissez vide pour " "\"root\")" #: sysinit/setupscript.sh.in:152 #, sh-format msgid "" "In order to access the ${TargetName} filesystem, it must be mounted on top " "of an empty directory." msgstr "" "Pour acceder le systme de fichiers ${TargetName}, il doit tre mont sur un " "rpertoire vide." #: sysinit/setupscript.sh.in:156 #, sh-format msgid "Please specify where \"${TargetName}\" should be mounted" msgstr "Donner le nom d'un rpertoire sur lequel \"${TargetName}\" sera mont" #: sysinit/setupscript.sh.in:160 #, sh-format msgid "${mount_dir} is not a valid directory name" msgstr "Le nom ${mount_dir} n'est pas valide comme rpertoire" #: sysinit/setupscript.sh.in:168 #, sh-format msgid "" "The maximum available size of your filesystem needs to be chosen so that " "enough space can be reserved on your disk." msgstr "" "La taille maximale de votre systme de fichiers doit tre choisie pour " "qu'assez d'espace soit reserv sur votre disque dur." #: sysinit/setupscript.sh.in:172 #, sh-format msgid "Enter the filesystem size (in MB)" msgstr "Donnez la taille du systme de fichiers (en MO)" #: sysinit/setupscript.sh.in:177 #, sh-format msgid "${fs_size} is not a valid number" msgstr "${fs_size} n'est pas un numero valide" #: sysinit/setupscript.sh.in:183 #, sh-format msgid "" "The actual encrypted filesystem will be stored in a special file, which " "needs to be large enough to contain your entire encrypted filesystem." msgstr "" "Le systme de fichiers chiffr sera contenu dans un fichier special, qui " "doit tre d'une taille suffisament grande pour contenir votre systme de " "fichiers entier." #: sysinit/setupscript.sh.in:187 #, sh-format msgid "Enter a filename for your encrypted container" msgstr "Donnez un nom de fichier pour votre conteneur chiffr" #: sysinit/setupscript.sh.in:191 #, sh-format msgid "WARNING: ${crypto_dev} already exists" msgstr "ATTENTION: ${crypto_dev} existe dj" #: sysinit/setupscript.sh.in:204 #, sh-format msgid "" "Access to your encrypted filesystem is protected by a key that is kept in a " "separate small file. The key is locked by a password that you must enter " "whenever you mount the filesystem." msgstr "" "L'accs votre systme de fichiers chiffr est protg par une clef qui est " "contenue dans son mme petit fichier. Pour acceder cette clef, on doit " "donner un mot de passe chaque fois que l'on monte le systme de fichiers." #: sysinit/setupscript.sh.in:208 #, sh-format msgid "Enter a location for the keyfile" msgstr "Donnez un nom de fichier pour le fichier-clef" #: sysinit/setupscript.sh.in:212 #, sh-format msgid "WARNING: ${key_file} already exists" msgstr "ATTENTION: ${key_file} existe dj" #: sysinit/setupscript.sh.in:224 #, sh-format msgid "Your filing system is now ready to be built - this will involve:" msgstr "" "Maintenant, votre systme de fichiers est prt tre construit, selon les " "tapes suivantes:" #: sysinit/setupscript.sh.in:225 #, sh-format msgid " - Creating the directory \"${mount_dir}\"" msgstr " - Cration du rpertoire \"${mount_dir}\"" #: sysinit/setupscript.sh.in:226 #, sh-format msgid " - Creating a ${fs_size}MB file, \"${crypto_dev}\"" msgstr " - Cration d'un fichier \"${crypto_dev}\" de ${fs_size}MO" #: sysinit/setupscript.sh.in:227 #, sh-format msgid " - Adding an extra entry (\"${TargetName}\") in ${CM_CFGDIR}/cmtab" msgstr "" " - Ajout d'une cible supplmentaire (\"${TargetName}\") dans ${CM_CFGDIR}/" "cmtab" #: sysinit/setupscript.sh.in:229 #, sh-format msgid " - Creating a key-file (\"${key_file}\")" msgstr " - Cration d'un fichier-clef (\"${key_file}\")" #: sysinit/setupscript.sh.in:231 #, sh-format msgid " - Creating an ext4 filingsystem on \"${crypto_dev}\"" msgstr " - Construction d'un systme de fichiers ext4 sur \"${crypto_dev}\"" #: sysinit/setupscript.sh.in:234 #, sh-format msgid " - Overwriting the backup configuration-file \"${bckp_cmtab}\"" msgstr " - crasement le fichier de sauvegarde \"${bckp_cmtab}\"" #: sysinit/setupscript.sh.in:236 #, sh-format msgid "If you do not wish to proceed, no changes will be made to your system." msgstr "Si vous ne voulez pas continuer, votre systme ne changera pas." #: sysinit/setupscript.sh.in:238 #, sh-format msgid "no" msgstr "non" #: sysinit/setupscript.sh.in:239 #, sh-format msgid "" "Please confirm that you want to proceed (enter \"${AffirmativeResponse}\")" msgstr "" "Veuillez confirmer que vous voulez continuer (crivez " "\"${AffirmativeResponse}\")" #: sysinit/setupscript.sh.in:242 #, sh-format msgid "Installation abandoned" msgstr "Installation termine" #: sysinit/setupscript.sh.in:246 #, sh-format msgid "done" msgstr "termin(e)" #: sysinit/setupscript.sh.in:248 #, sh-format msgid "Making mount-point (${mount_dir})..." msgstr "Ralisation du point de montage (${mount_dir})..." #: sysinit/setupscript.sh.in:251 #, sh-format msgid "Creating filesystem container (${crypto_dev})..." msgstr "Cration du conteneur du systme de fichiers (${crypto_dev})..." #: sysinit/setupscript.sh.in:256 #, sh-format msgid "Taking backup of cryptmount master config-file (${bckp_cmtab})..." msgstr "Sauvegarde du fichier de configuration (${bckp_cmtab})..." #: sysinit/setupscript.sh.in:272 #, sh-format msgid "Generating filesystem access key..." msgstr "Construction du fichier-clef..." #: sysinit/setupscript.sh.in:280 #, sh-format msgid "Formatting encrypted filesystem..." msgstr "Formatage du systme de fichier chiffr..." #: sysinit/setupscript.sh.in:309 #, sh-format msgid "cryptmount setup script" msgstr "" #: sysinit/setupscript.sh.in:311 #, sh-format msgid "" "This program will allow you to setup a secure filing-system that will be " "managed by \"cryptmount\". You will be able to select basic features such as " "the location and size of the filesystem - if you want more advanced " "features, you should consult the cryptmount manual page." msgstr "" "Ce progamme vous permettra de construire un systme de fichiers chiffr qui " "sera dirig par cryptmount. Vous pourrez selectioner quelques options " "basiques, telle que la location et la taille du systme de fichiers. Si vous " "avez besoin de particularits plus avances, il faut lire la page manuel de " "cryptmount." #: sysinit/setupscript.sh.in:314 #, sh-format msgid "cryptmount comes with ABSOLUTELY NO WARRANTY." msgstr "cryptmount n'est fourni avec aucune garantie." #: sysinit/setupscript.sh.in:315 #, sh-format msgid "" "This is free software, and you are welcome to redistribute it under certain " "conditions - see the file 'COPYING' in the source directory." msgstr "" "Ce paquet est un logiciel libre - les termes de sa licence sont dcrits dans " "le fichier 'COPYING' dans le paquet source." #: sysinit/setupscript.sh.in:342 #, sh-format msgid "Your new encrypted filesystem is now ready for use - to access, try:" msgstr "" "Votre nouveau systme de fichiers chiffr est prt - pour l'utiliser, " "veuillez essayer:" #: sysinit/setupscript.sh.in:345 #, sh-format msgid "After you have finished using the filesystem, try:" msgstr "Lorsque vous avez termin d'utiliser le systme de fichiers, essayez:" #~ msgid "Failed to create loop device for LUKS keyfile\n" #~ msgstr "Cration du priphrique-loop pour le fichier-clef LUKS a echoue\n" #~ msgid "Failed to read LUKS header for \"%s\"\n" #~ msgstr "Lisant l'en-tte LUKS pour \"%s\" a echou\n" #~ msgid "" #~ "cryptmount: using \"keycipher=none\" is deprecated - please use " #~ "\"keyformat=raw\" instead\n" #~ msgstr "" #~ "cryptmount: usage de \"keycipher=none\" est dcourag - veuillez plutt " #~ "utiliser \"keyformat=raw\"\n" #~ msgid "Missing parameter\n" #~ msgstr "Paramtre perdue\n" #~ msgid "Unrecognized key format (%s) for target \"%s\"\n" #~ msgstr "Mauvaise type de fichier-clef (%s) pour la cible \"%s\"\n" #~ msgid "Missing output stream for target \"%s\"\n" #~ msgstr "Pas de flux de sorti pour la cible \"%s\"\n" #~ msgid "target name \"%s\" is not recognized\n" #~ msgstr "nom de cible \"%s\" n'est pas reconnu\n" #~ msgid "key-extraction failed for \"%s\"\n" #~ msgstr "extraction de la clef pour \"%s\" a echoue\n" #~ msgid "password mismatch when extracting key\n" #~ msgstr "mot de passe n'est pas verifi\n" #~ msgid "failed to create new key file\n" #~ msgstr "gnration de nouvelle clef a echoue\n" cryptmount-6.3.0/po/insert-header.sin000066400000000000000000000012401465135467200176410ustar00rootroot00000000000000# Sed script that inserts the file called HEADER before the header entry. # # At each occurrence of a line starting with "msgid ", we execute the following # commands. At the first occurrence, insert the file. At the following # occurrences, do nothing. The distinction between the first and the following # occurrences is achieved by looking at the hold space. /^msgid /{ x # Test if the hold space is empty. s/m/m/ ta # Yes it was empty. First occurrence. Read the file. r HEADER # Output the file's contents by reading the next line. But don't lose the # current line while doing this. g N bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } cryptmount-6.3.0/po/quot.sed000066400000000000000000000002311465135467200160600ustar00rootroot00000000000000s/"\([^"]*\)"/“\1”/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“”/""/g cryptmount-6.3.0/po/remove-potcdate.sin000066400000000000000000000006601465135467200202120ustar00rootroot00000000000000# Sed script that remove the POT-Creation-Date line in the header entry # from a POT file. # # The distinction between the first and the following occurrences of the # pattern is achieved by looking at the hold space. /^"POT-Creation-Date: .*"$/{ x # Test if the hold space is empty. s/P/P/ ta # Yes it was empty. First occurrence. Remove the line. g d bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } cryptmount-6.3.0/sysinit/000077500000000000000000000000001465135467200154635ustar00rootroot00000000000000cryptmount-6.3.0/sysinit/Makefile.am000066400000000000000000000033571465135467200175270ustar00rootroot00000000000000# automake script for cryptmount system-startup mechanisms # RW Penney, April 2013 EXTRA_DIST = cryptmount.service.in modules-load.conf \ setupscript.sh.in initscript.in scripttransform='s,@EXENAME@,$(bindir)/cryptmount$(EXEEXT),g; \ s,@SYSCONF_DIR@,$(CM_SYSCONF_DIR),g; \ s,@PKG_NAME@,$(PACKAGE_NAME),g; \ s,@PKG_VERSION@,$(VERSION),g; \ s,@LCL_DIR@,$(localedir),g' initscript: initscript.in sed ${scripttransform} $< > $@ cryptmount.service: cryptmount.service.in sed ${scripttransform} $< > $@ setupscript: setupscript.sh.in sed ${scripttransform} $< > $@ install-exec-hook: install-inits install-setup install-inits: cryptmount.service initscript if USE_SYSTEMD test -d "${DESTDIR}${CM_SYSD_UNITDIR}" || ${mkdir_p} "${DESTDIR}${CM_SYSD_UNITDIR}" endif # USE_SYSTEMD if test -d "${DESTDIR}${CM_SYSD_UNITDIR}" ; then \ ${INSTALL_PROGRAM_ENV} ${INSTALL_DATA} cryptmount.service "${DESTDIR}${CM_SYSD_UNITDIR}"; \ fi test -d "${DESTDIR}/etc/modules-load.d" || ${mkdir_p} "${DESTDIR}/etc/modules-load.d" ${INSTALL_PROGRAM_ENV} ${INSTALL_DATA} modules-load.conf "${DESTDIR}/etc/modules-load.d/cryptmount.conf"; if !USE_SYSTEMD test -d "${DESTDIR}/etc/init.d" -o -d "${DESTDIR}/etc/rc.d/init.d" || ${mkdir_p} "${DESTDIR}/etc/init.d" for initdir in /etc/init.d /etc/rc.d/init.d; do \ if test -d "${DESTDIR}$${initdir}" ; then \ ${INSTALL_PROGRAM_ENV} ${INSTALL_SCRIPT} initscript "${DESTDIR}$${initdir}/cryptmount" ; \ break; \ fi; \ done endif # !USE_SYSTEMD install-setup: setupscript test -d "${DESTDIR}${sbindir}" || ${mkdir_p} "${DESTDIR}${sbindir}" ${INSTALL_PROGRAM_ENV} ${INSTALL_SCRIPT} setupscript "${DESTDIR}${sbindir}/cryptmount-setup" clean-local: -rm -f cryptmount.service initscript setupscript cryptmount-6.3.0/sysinit/cryptmount.service.in000066400000000000000000000005411465135467200216760ustar00rootroot00000000000000# systemd definition for 'cryptmount' [Unit] Description=cryptmount startup Documentation=man:cryptmount https://github.com/rwpenney/cryptmount/ After=local-fs.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=@EXENAME@ --system-boot ExecStop=@EXENAME@ --system-shutdown ExecStopPost=@EXENAME@ --safetynet [Install] WantedBy=sysinit.target cryptmount-6.3.0/sysinit/initscript.in000066400000000000000000000070521465135467200202070ustar00rootroot00000000000000#!/bin/sh # boot-time init script for cryptmount # RW Penney, August 2006 # Basic support for Linux Standard Base: ### BEGIN INIT INFO # Provides: cryptmount # Required-Start: $remote_fs # Required-Stop: $remote_fs # Should-Start: $syslog # Should-Stop: $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: setup encrypted filesystems/swap at boot # Description: configure device-mapper targets for encrypted # filesystems and swap-partitions managed by cryptmount ### END INIT INFO CM_EXE=@EXENAME@ DISK_ID_PATH=/dev/disk/by-id/ CM_BOOTDV="" CM_BOOTSW="" CM_BOOTFS="" # Check whether cryptmount executable is usable: test -x "${CM_EXE}" || exit 5 # Read user-specified lists of filesystems to initialize: if [ -f /etc/default/cryptmount ]; then . /etc/default/cryptmount fi configured() { # Check if any of the targets needed at boot has been configured: for target in ${CM_BOOTDV} ${CM_BOOTFS} ${CM_BOOTSW}; do if [ -b "${DISK_ID_PATH}/dm-name-${target}" ]; then true return fi done false } dodevices() { case "$1" in start) test -z "${CM_BOOTDV}" || ${CM_EXE} --prepare ${CM_BOOTDV} ;; stop) test -z "${CM_BOOTDV}" || ${CM_EXE} --release ${CM_BOOTDV} ;; esac } doswaps() { case "$1" in start) test -z "${CM_BOOTSW}" || ${CM_EXE} --swapon ${CM_BOOTSW} ;; stop) test -z "${CM_BOOTSW}" || ${CM_EXE} --swapoff ${CM_BOOTSW} ;; esac } dofilesys() { case "$1" in start) test -z "${CM_BOOTFS}" || ${CM_EXE} --mount ${CM_BOOTFS} ;; stop) test -z "${CM_BOOTFS}" || ${CM_EXE} --unmount ${CM_BOOTFS} ;; esac } doALL() { if test -n "${CM_BOOTDV}" -o -n "${CM_BOOTSW}" \ -o -n "${CM_BOOTFS}" -o -n "${CM_EARLYDV}"; then echo "Using /etc/default/cryptmount is DEPRECATED - please use 'bootaction={mount|swap|prepare}' flags within @SYSCONF_DIR@/cmtab" fi case "$1" in start) dodevices start doswaps start dofilesys start ;; stop) dofilesys stop doswaps stop dodevices stop ;; esac } case "$1" in start) # Make sure that kernel device-mapper is available: modprobe -q -a dm-mod dm-crypt || true ${CM_EXE} --system-boot if configured; then echo "cryptmount ${STAGE}auto-filesystems seem to be already configured" else echo "Starting cryptmount ${STAGE}targets (hit shift/ctrl if short of entropy):" doALL start fi ;; stop) ${CM_EXE} --system-shutdown if configured; then echo "Stopping cryptmount ${STAGE}targets:" doALL stop fi ${CM_EXE} --safetynet || true ;; restart) ${CM_EXE} --system-shutdown if configured; then doALL stop fi ${CM_EXE} --system-boot doALL start ;; force-reload|reload) # nothing to do ;; status) if configured; then echo "cryptmount ${STAGE}auto-filesystems are in use" else echo "cryptmount ${STAGE}auto-filesystems do not appear to be in use" exit 3 fi ;; *) echo "Usage: $0 " \ " {start|stop|restart|reload|force-reload|status}" >&2 exit 1 ;; esac exit 0 cryptmount-6.3.0/sysinit/modules-load.conf000066400000000000000000000000641465135467200207170ustar00rootroot00000000000000# Kernel modules needed by cryptmount dm-crypt loop cryptmount-6.3.0/sysinit/setupscript.sh.in000077500000000000000000000262601465135467200210220ustar00rootroot00000000000000#!/bin/sh # simple setup script for cryptmount # RW Penney, May 2007 # This file is part of 'cryptmount' and is therefore # supplied with NO WARRANTY of any form. # Please see the file 'COPYING' in the main cryptmount source directory # for further information. CM_BINEXE="@EXENAME@" CM_CFGDIR="@SYSCONF_DIR@" # prepare gettext internationalization: TEXTDOMAIN="@PKG_NAME@" export TEXTDOMAIN TEXTDOMAINDIR="@LCL_DIR@" export TEXTDOMAINDIR if which gettext.sh > /dev/null 2>&1; then . gettext.sh else eval_gettext() { eval "echo \"$1\""; } fi FoldLines() { # wrap text-output to fit into 70-columns, breaking on whitespace fold -s -w 70 } ToLowerCase() { # translate upper-case letters to lower-case tr '[:upper:]' '[:lower:]' } TrapCleanup() { # try to mitigate any damage if terminated prematurely ProgName="$0" eval_gettext "Abandoning \$ProgName ..."; echo exit 2 } CheckPrivileges() { if [ "`whoami`" != "root" ]; then echo "" eval_gettext "This script must be run with superuser privileges - please try again, e.g. using one of the following:" | FoldLines; echo echo " sudo $0" echo " su -c $0" echo "" exit 1 fi } CheckLuksSupport() { if `${CM_BINEXE} --key-managers | egrep -q '\'`; then has_luks_keymgr="yes" else has_luks_keymgr="no" echo "" eval_gettext "No LUKS support available - using built-in key manager"; echo fi } SectionBreak() { echo "" case "$1" in minor) ;; major) echo "------------------------------" ;; *) echo "" ;; esac } GetResponse() { # Issue prompt string & await response from user # syntax: GetResponse echo "" echo " $1" echo -n " [$2]: " read resp if [ -z "${resp}" ]; then resp="$2" fi eval "$3=\"${resp}\"" } GuessHome() { # Try to guess user's home-directory, even after su/sudo guessed_home="${HOME}" if [ "${user_owner}" != "" ]; then eval "guessed_home=~${user_owner}" fi for tgt in "${guessed_home}" "${HOME}" "`pwd`" "/home"; do hm="`echo ${tgt}/ | sed -n -e 's%^\(/.*home/[^/]*\).*$%\1%p'`" if [ "${hm}" != "" -a -d "${hm}" ]; then guessed_home="`echo ${hm} | sed 's%/$%%'`" break fi done } CanonVars() { # Canonicalize string variables for var in $@; do eval "val=\"\$${var}\"" eval "$var=\"`echo \"${val}\" | sed 's, ,\\\\ ,g'`\"" done } GetTargetName() { DefaultTargetName=`eval_gettext "opaque"` eval_gettext "Each cryptmount filesystem is identifed by a short name which is used when mounting or configuring that filesystem. This name should be a single word (without spaces), such as \"\${DefaultTargetName}\"." | FoldLines; echo eval_gettext "The following target names have already been used:" echo -n " " tgts=`${CM_BINEXE} --list | awk '{printf"%s ", $1}'` if [ ! -z "${tgts}" ]; then echo "${tgts}"; else echo "(NONE)"; fi TargetName="" while [ -z "${TargetName}" ]; do prompt=`eval_gettext "Please enter a target name for your filesystem"` GetResponse "${prompt}" "${DefaultTargetName}" "TargetName" if ${CM_BINEXE} --list "${TargetName}" >/dev/null 2>&1; then eval_gettext "The target-name \"\${TargetName}\" has already been used" TargetName="" fi done } GetUser() { eval_gettext "The \${TargetName} filesystem can be configured to be owned by a nominated user, who will be able to create top-level files & directories without needing to involve the superuser." | FoldLines; echo prompt=`eval_gettext "Which user should own the filesystem (leave blank for \"root\")"` GetResponse "${prompt}" "" "user_owner" } GetMountPoint() { eval_gettext "In order to access the \${TargetName} filesystem, it must be mounted on top of an empty directory." | FoldLines; echo mount_dir="" while [ -z "${mount_dir}" ]; do prompt=`eval_gettext "Please specify where \"\\\${TargetName}\" should be mounted"` GetResponse "${prompt}" "${guessed_home}/crypt" "mount_dir" if [ -e "${mount_dir}" -a ! -d "${mount_dir}" ]; then eval_gettext "\${mount_dir} is not a valid directory name"; echo mount_dir="" fi done } GetContainerInfo() { eval_gettext "The maximum available size of your filesystem needs to be chosen so that enough space can be reserved on your disk." | FoldLines; echo fs_size="" while [ -z "${fs_size}" ]; do prompt=`eval_gettext "Enter the filesystem size (in MB)"` GetResponse "${prompt}" "64" "fs_size" if [ "${fs_size}" -gt 0 ] 2>/dev/null; then true else eval_gettext "\${fs_size} is not a valid number"; echo fs_size="" fi done SectionBreak eval_gettext "The actual encrypted filesystem will be stored in a special file, which needs to be large enough to contain your entire encrypted filesystem." | FoldLines; echo crypto_dev="" while [ -z "${crypto_dev}" ]; do prompt=`eval_gettext "Enter a filename for your encrypted container"` GetResponse "${prompt}" "${guessed_home}/crypto.fs" "crypto_dev" if [ -e "${crypto_dev}" ]; then eval_gettext "WARNING: \${crypto_dev} already exists"; echo crypto_dev="" fi done } GetKeyInfo() { if [ "${has_luks_keymgr}" = "yes" ]; then cmtab_keyspec="keyformat=luks" return fi eval_gettext "Access to your encrypted filesystem is protected by a key that is kept in a separate small file. The key is locked by a password that you must enter whenever you mount the filesystem." | FoldLines; echo key_file="" while [ -z "${key_file}" ]; do prompt=`eval_gettext "Enter a location for the keyfile"` GetResponse "${prompt}" "${CM_CFGDIR}/${TargetName}.key" "key_file" if [ -e "${key_file}" ]; then eval_gettext "WARNING: \${key_file} already exists"; echo key_file="" fi done cmtab_keyspec="keyformat=builtin keyfile=`echo "${key_file}" | sed 's, ,\\\\ ,g'`" } BuildFS() { bckp_cmtab="${CM_CFGDIR}/cmtab.bckp-setup" SectionBreak major eval_gettext "Your filing system is now ready to be built - this will involve:" | FoldLines; echo "" eval_gettext " - Creating the directory \"\${mount_dir}\""; echo eval_gettext " - Creating a \${fs_size}MB file, \"\${crypto_dev}\""; echo eval_gettext " - Adding an extra entry (\"\${TargetName}\") in \${CM_CFGDIR}/cmtab"; echo if [ -n "${key_file}" ]; then eval_gettext " - Creating a key-file (\"\${key_file}\")"; echo fi eval_gettext " - Creating an ext4 filingsystem on \"\${crypto_dev}\""; echo if [ -f "${bckp_cmtab}" ]; then eval_gettext " - Overwriting the backup configuration-file \"\${bckp_cmtab}\""; echo fi eval_gettext "If you do not wish to proceed, no changes will be made to your system."; echo AffirmativeResponse=`eval_gettext "yes" | ToLowerCase` NegativeResponse=`eval_gettext "no"` prompt=`eval_gettext "Please confirm that you want to proceed (enter \"\\\${AffirmativeResponse}\")"` GetResponse "${prompt}" "${NegativeResponse}" "confirm" if [ "`echo ${confirm} | ToLowerCase`" != "${AffirmativeResponse}" ]; then eval_gettext "Installation abandoned"; echo exit 1 fi Completed=`eval_gettext "done"` set -e eval_gettext "Making mount-point (\${mount_dir})..." mkdir -p "${mount_dir}" echo " ${Completed}" eval_gettext "Creating filesystem container (\${crypto_dev})..." pfx=`dirname "${crypto_dev}"` test -d "${pfx}" || mkdir -p "${pfx}" dd if=/dev/zero of="${crypto_dev}" bs=1M count="${fs_size}" >/dev/null 2>&1 echo " ${Completed}" eval_gettext "Taking backup of cryptmount master config-file (\${bckp_cmtab})..." mv "${CM_CFGDIR}/cmtab" "${bckp_cmtab}" echo " ${Completed}" cat "${bckp_cmtab}" > "${CM_CFGDIR}/cmtab" cat <> "${CM_CFGDIR}/cmtab" # Entry automatically generated by setup-script: `echo "${TargetName}" | sed 's, ,\\\\ ,g'` { dev=`echo "${crypto_dev}" | sed 's, ,\\\\ ,g'` dir=`echo "${mount_dir}" | sed 's, ,\\\\ ,g'` fstype=ext4 mountoptions=defaults cipher=aes ${cmtab_keyspec} } EOF eval_gettext "Generating filesystem access key..."; echo until ${CM_BINEXE} --generate-key 32 "${TargetName}"; do cmerrno=$? if [ ${cmerrno} -ne 33 ]; then eval_gettext "Key-generation failure (status=${cmerrno})" exit 3 fi done eval_gettext "Formatting encrypted filesystem..."; echo until ${CM_BINEXE} --prepare "${TargetName}"; do cmerrno=$? if [ ${cmerrno} -ne 21 ]; then eval_gettext "Cannot prepare device (status=${cmerrno})" exit 4 fi done mke2fs -t ext4 "/dev/disk/by-id/dm-name-${TargetName}" >/dev/null 2>&1 if [ "${user_owner}" != "" ]; then chown "${user_owner}" "${mount_dir}" "${crypto_dev}" chmod 0500 "${mount_dir}" chmod 0600 "${crypto_dev}" mount "/dev/disk/by-id/dm-name-${TargetName}" "${mount_dir}" chown "${user_owner}" "${mount_dir}" chmod 0700 "${mount_dir}" umount "${mount_dir}" fi (udevadm settle || udevsettle || sleep 5) 2>/dev/null ${CM_BINEXE} --release "${TargetName}" } # # Main program # SectionBreak major eval_gettext "cryptmount setup script"; echo; echo eval_gettext "This program will allow you to setup a secure filing-system that will be managed by \"cryptmount\". You will be able to select basic features such as the location and size of the filesystem - if you want more advanced features, you should consult the cryptmount manual page." | FoldLines; echo; echo echo "cryptmount version @PKG_VERSION@, (C)Copyright 2007-2024, RW Penney" eval_gettext "cryptmount comes with ABSOLUTELY NO WARRANTY."; echo eval_gettext "This is free software, and you are welcome to redistribute it under certain conditions - see the file 'COPYING' in the source directory." | FoldLines; echo CheckPrivileges CheckLuksSupport modprobe -q -a loop dm-mod dm-crypt || true trap TrapCleanup INT QUIT HUP # Interactively gather configuration information from user: SectionBreak major GetTargetName SectionBreak GetUser GuessHome SectionBreak GetMountPoint SectionBreak GetContainerInfo SectionBreak GetKeyInfo # Build filesystem: BuildFS SectionBreak major eval_gettext "Your new encrypted filesystem is now ready for use - to access, try:" | FoldLines; echo echo " cryptmount ${TargetName}" echo " cd ${mount_dir}" eval_gettext "After you have finished using the filesystem, try:" | FoldLines; echo echo " cd" echo " cryptmount --unmount ${TargetName}" echo if [ -n "${key_file}" ]; then eval_gettext "Please take great care NOT to delete or damage your keyfile (\"${key_file}\"). Without that file, and the associated password, it will be virtually impossible to access your encrypted filesystem. You may want to keep a separate backup copy of the keyfile." | FoldLines; echo fi exit 0 # vim: set ts=4 sw=4 et: cryptmount-6.3.0/tables.c000066400000000000000000000671201465135467200154050ustar00rootroot00000000000000/* * Config-table and mount-table utilities for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "armour.h" #include "cryptmount.h" #include "delegates.h" #include "tables.h" #include "utils.h" #ifdef TESTING # include "cmtesting.h" #endif const char *cm_status_filename = "cryptmount.status"; enum /* config-file tokens */ { T_IDENT, T_LBRACE, T_OPT, T_RBRACE, T_ERROR }; /** * Description of an open target-status file. * * Internally, the status-file has the following structure: \verbatim # [TITLE] - one-line text header 0 - integer file-format version number n,[TARGET],uid - target-name length, target-name, uid of mounter ... - further target records \endverbatim */ struct statfile /* information about status file */ { int version; /* file format version */ FILE *fp; /* file handle */ }; /** * Representation of an option flag within the configuration file, * associated with a bit field within a target definition. */ typedef struct { const char *name; unsigned andmask; unsigned ormask; } tgt_option_t; static tgt_option_t /** Menu of options within 'flags' field of target definition */ setup_options[] = { { "defaults", 0U, FLG_DEFAULTS }, { "user", ~0U, FLG_USER }, { "nouser", ~0U ^ FLG_USER, 0U }, { "fsck", ~0U, FLG_FSCK }, { "nofsck", ~0U ^ FLG_FSCK, 0U }, { "mkswap", ~0U, FLG_MKSWAP }, { "nomkswap", ~0U ^ FLG_MKSWAP, 0U }, { "trim", ~0U, FLG_TRIM }, { "notrim", ~0U ^ FLG_TRIM, 0U }, { NULL, ~0U, 0U } }, /** Menu of options within 'bootaction' field of target definition */ boot_options[] = { { "none", ~0U ^ FLG_BOOT_MASK, 0 }, { "mount", ~0U ^ FLG_BOOT_MASK, FLG_BOOT_MOUNT }, { "swap", ~0U ^ FLG_BOOT_MASK, FLG_BOOT_SWAP }, { "prepare", ~0U ^ FLG_BOOT_MASK, FLG_BOOT_PREP }, { NULL, ~0U, 0U } }; struct vardefn /** Description of a quasi-environmental variable */ { char *varname; char *value; struct vardefn *next; }; static struct vardefn *vardefns = NULL; static tgtdefn_t *parse_stream(FILE *fp, const char *cfgname); void set_variable(const char *varname, const char *value) /** Set the value of an environmental variable */ { struct vardefn *newvar; newvar = (struct vardefn*)malloc(sizeof(struct vardefn)); newvar->next = vardefns; newvar->varname = cm_strdup(varname); newvar->value = cm_strdup(value); vardefns = newvar; } const char *query_variable(char *varname) /** Get the current value of an environmental variable */ { struct vardefn *var; for (var=vardefns; var!=NULL; var=var->next) { if (strcmp(varname, var->varname) == 0) return var->value; } return NULL; } void init_env_dictionary() /** Initialize internal dictionary of quasi-environmental variables */ { char buff[512]; const uid_t uid = getuid(); const gid_t gid = getgid(); struct passwd *pwent = NULL; struct group *grent = NULL; if (vardefns != NULL) return; sprintf(buff, "%d", (int)uid); set_variable("UID", buff); pwent = getpwuid(uid); if (pwent != NULL) { set_variable("USERNAME", pwent->pw_name); set_variable("HOME", pwent->pw_dir); } sprintf(buff, "%d", (int)gid); set_variable("GID", buff); grent = getgrgid(gid); if (grent != NULL) set_variable("GROUPNAME", grent->gr_name); } void clear_env_dictionary() { struct vardefn *vd; while (vardefns != NULL) { vd = vardefns; if (vd->varname != NULL) free((void*)vd->varname); if (vd->value != NULL) free((void*)vd->value); vardefns = vd->next; free((void*)vd); } } tgtdefn_t *alloc_tgtdefn(const tgtdefn_t *prototype) /** Allocate storage for a target-structure */ { tgtdefn_t *tgt; #define DFLT_OR_PROTO(dflt, proto) \ (prototype == NULL ? (dflt) : (proto)) tgt = (tgtdefn_t*)malloc(sizeof(tgtdefn_t)); tgt->ident = NULL; tgt->flags = DFLT_OR_PROTO(FLG_DEFAULTS, prototype->flags); tgt->dev = NULL; tgt->start = 0; tgt->length = -1; tgt->dir = NULL; tgt->fstype = DFLT_OR_PROTO(NULL, cm_strdup(prototype->fstype)); tgt->mountoptions = DFLT_OR_PROTO(NULL, cm_strdup(prototype->mountoptions)); tgt->fsckoptions = DFLT_OR_PROTO(NULL, cm_strdup(prototype->fsckoptions)); tgt->loopdev = NULL; tgt->supath = DFLT_OR_PROTO(NULL, cm_strdup(prototype->supath)); tgt->cipher = DFLT_OR_PROTO(cm_strdup(CM_DEFAULT_CIPHER), cm_strdup(prototype->cipher)); tgt->ivoffset = 0; tgt->key.format = DFLT_OR_PROTO(NULL, cm_strdup(prototype->key.format)); tgt->key.filename = NULL; tgt->key.digestalg = DFLT_OR_PROTO(NULL, cm_strdup(prototype->key.digestalg)); tgt->key.cipheralg = DFLT_OR_PROTO(NULL, cm_strdup(prototype->key.cipheralg)); tgt->key.maxlen = DFLT_OR_PROTO(-1L, prototype->key.maxlen); tgt->key.retries = DFLT_OR_PROTO(1U, prototype->key.retries); tgt->nx = NULL; #undef DFLT_OR_PROTO return tgt; } const tgtdefn_t *get_tgtdefn(const tgtdefn_t *head, const char *ident) /** Find info-structure for target of given name */ { const tgtdefn_t *itr,*ent=NULL; for (itr=head; itr!=NULL && ent==NULL; itr=itr->nx) { if (strcmp(ident, itr->ident) == 0) { ent = itr; } } return ent; } tgtdefn_t *clone_tgtdefn(const tgtdefn_t *orig) /** Create (deep) copy of target-definition */ { tgtdefn_t *clone; if (orig == NULL) return NULL; clone = (tgtdefn_t*)malloc(sizeof(tgtdefn_t)); clone->ident = cm_strdup(orig->ident); clone->flags = orig->flags; clone->dev = cm_strdup(orig->dev); clone->start = orig->start; clone->length = orig->length; clone->dir = cm_strdup(orig->dir); clone->fstype = cm_strdup(orig->fstype); clone->mountoptions = cm_strdup(orig->mountoptions); clone->fsckoptions = cm_strdup(orig->fsckoptions); clone->loopdev = cm_strdup(orig->loopdev); clone->supath = cm_strdup(orig->supath); clone->cipher = cm_strdup(orig->cipher); clone->ivoffset = orig->ivoffset; clone->key.format = cm_strdup(orig->key.format); clone->key.filename = cm_strdup(orig->key.filename); clone->key.digestalg = cm_strdup(orig->key.digestalg); clone->key.cipheralg = cm_strdup(orig->key.cipheralg); clone->key.maxlen = orig->key.maxlen; clone->key.retries = orig->key.retries; clone->nx = NULL; return clone; } void free_tgtdefn(tgtdefn_t *tgt) /** Relinquish storage for a target-structure */ { free((void*)tgt->ident); free((void*)tgt->dev); free((void*)tgt->dir); free((void*)tgt->fstype); free((void*)tgt->mountoptions); free((void*)tgt->fsckoptions); free((void*)tgt->loopdev); free((void*)tgt->supath); free((void*)tgt->cipher); free((void*)tgt->key.format); free((void*)tgt->key.filename); free((void*)tgt->key.digestalg); free((void*)tgt->key.cipheralg); free((void*)tgt); } static void append(char c, char **buff, unsigned *pos, unsigned *bufflen) /** Append character to string, reallocating memory as necessary */ { unsigned newlen; if (*pos >= *bufflen) { newlen = (*bufflen) * 2 + 64; *buff = (char*)realloc(*buff, (size_t)newlen); *bufflen = newlen; } (*buff)[*pos] = c; ++(*pos); } void expand_variables(char **buff, const char *src) /** Expand $(VAR) patterns within a string */ { const size_t srclen = strlen(src); enum { S_PLAIN, S_VAR }; const char *curs = src; char *varname, *varp = NULL; int literal = 0; unsigned state; cm_string_t *result; result = cm_str_alloc(64); state = S_PLAIN; varname = (char*)malloc(srclen * 2); for (curs=src; *curs!='\0'; ++curs) { if (!literal && *curs == '\\') { literal = 1; continue; } switch (state) { case S_PLAIN: if (!literal && curs[0] == '$' && curs[1] == '(') { /* Mark start of variable term */ state = S_VAR; varp = varname; ++curs; } else { /* Copy character unchanged into output */ cm_str_append_char(result, *curs); } break; case S_VAR: if (!literal && *curs == ')') { /* Extract value from dictionary */ *varp = '\0'; cm_str_append_str(result, query_variable(varname)); state = S_PLAIN; } else { /* accumulate characters of variable name */ *varp = *curs; ++varp; } break; default: break; } literal = 0; } free((void*)varname); if (*buff != NULL) free((void*)(*buff)); *buff = cm_str_strip(result); } #ifdef TESTING /*! \addtogroup unit_tests * @{ */ int tb_test_expand() /** Check variable expansion in configuration-file parser */ { char answer[1024], *buff = NULL; CM_TEST_START("Variable expansion"); expand_variables(&buff, "nothing here"); CM_ASSERT_STR_EQUAL("nothing here", buff); expand_variables(&buff, "nothing\\ here"); CM_ASSERT_STR_EQUAL("nothing here", buff); expand_variables(&buff, "nothing-$(UID) here"); sprintf(answer, "nothing-%d here", getuid()); CM_ASSERT_STR_EQUAL(answer, buff); if (buff != NULL) free((void*)buff); CM_TEST_OK(); } /** @} */ #endif /* TESTING */ static int proc_string(void *ptr, const char *src, const void *config) /** Process var=val entry in config-table for "string" type */ { char **addr = (char**)ptr; expand_variables(addr, src); return (*addr == NULL); } #define PROC_VARVAL(FN_NAME, TYPE, FMT) \ static int FN_NAME(void *ptr, const char *src, const void *x) \ /** Process var=val entry in config-table for "TYPE" */ \ { TYPE qv, *addr=(TYPE*)ptr; \ if (sscanf(src, FMT, &qv) == 1) { \ *addr = qv; return 0; \ } \ return 1; \ } PROC_VARVAL(proc_unsigned, unsigned, "%u") PROC_VARVAL(proc_long, long, "%ld") PROC_VARVAL(proc_int64, int64_t, "%" SCNi64) #undef PROC_VARVAL /** * Convert string of comma-separated configuration-switches * within \a selection into binary flags. A pointer to the (unsigned) flags, * is supplied via \a flagptr, and the set of available switches * is in the form of an array of tgt_option_t, passed via \a menuptr. */ int proc_flags(void *flagptr, const char *selection, const void *menuptr) { unsigned *flags = (unsigned*)flagptr; const tgt_option_t *menu = (const tgt_option_t*)menuptr; unsigned idx, len; if (selection == NULL) return 0; for (;;) { for (len=0; selection[len]!='\0' && selection[len]!=','; ++len); for (idx=0; menu[idx].name!=NULL; ++idx) { if (strncmp(selection, menu[idx].name, (size_t)len) == 0) { *flags = (*flags & menu[idx].andmask) | menu[idx].ormask; break; } } if (menu[idx].name == NULL) { fprintf(stderr, "bad option \"%s\"\n", selection); return 1; } if (selection[len] == '\0') break; selection += len + 1; } return 0; } static void read_token(char *buff, unsigned *t_state, tgtdefn_t *tgt) /** Process token (word) from configuration-file while parsing */ { struct tokinfo_t { const char *name; int varoffset; int (*proc)(void *var, const char *val, const void *config); const void *config; } *tok; #define OFFSET(x) (int)((char*)&((tgtdefn_t*)NULL)->x - (char*)NULL) struct tokinfo_t toktable[] = { { "flags", OFFSET(flags), proc_flags, setup_options }, { "bootaction", OFFSET(flags), proc_flags, boot_options }, { "dev", OFFSET(dev), proc_string, NULL }, { "dir", OFFSET(dir), proc_string, NULL }, { "startsector", OFFSET(start), proc_int64, NULL }, { "numsectors", OFFSET(length), proc_int64, NULL }, { "fstype", OFFSET(fstype), proc_string, NULL }, { "mountoptions", OFFSET(mountoptions), proc_string, NULL }, /* FIXME - "fsoptions" was deprecated in version 4.1 - remove by Jan2016 */ { "fsoptions", OFFSET(mountoptions), proc_string, NULL }, { "fsckoptions", OFFSET(fsckoptions), proc_string, NULL }, { "loop", OFFSET(loopdev), proc_string, NULL }, { "supath", OFFSET(supath), proc_string, NULL }, { "cipher", OFFSET(cipher), proc_string, NULL }, { "ivoffset", OFFSET(ivoffset), proc_int64, NULL }, { "keyformat", OFFSET(key.format), proc_string, NULL }, { "keyfile", OFFSET(key.filename), proc_string, NULL }, { "keyhash", OFFSET(key.digestalg), proc_string, NULL }, { "keycipher", OFFSET(key.cipheralg), proc_string, NULL }, { "keymaxlen", OFFSET(key.maxlen), proc_long, NULL }, { "passwdretries", OFFSET(key.retries), proc_unsigned, NULL }, { NULL, 0, NULL } }; #undef OFFSET char *eq; switch (*t_state) { case T_IDENT: (void)proc_string((void*)&tgt->ident, buff, NULL); *t_state = T_LBRACE; break; case T_LBRACE: *t_state = (strcmp(buff, "{") == 0 ? T_OPT : T_ERROR); break; case T_OPT: if (strcmp(buff, "}") == 0) { *t_state = T_RBRACE; break; } if ((eq = strchr(buff,'=')) == NULL) { *t_state = T_ERROR; break; } *eq = '\0'; ++eq; /* Delegate processing to specific token-processor from table: */ for (tok=toktable; tok->name!=NULL; ++tok) { if (strcmp(tok->name, buff) == 0) { (*tok->proc)((void*)((char*)tgt + tok->varoffset), eq, tok->config); break; } } if (strcmp(buff, "fsoptions") == 0) { fprintf(stderr, _("cryptmount: please replace \"fsoptions\" with \"mountoptions\" in cmtab\n")); *t_state = T_ERROR; } if (tok->name == NULL) { fprintf(stderr, _("cryptmount: unrecognized option \"%s\" in cmtab\n"), buff); *t_state = T_ERROR; } break; default: break; } } tgtdefn_t *parse_stream(FILE *fp, const char *cfgname) /** Convert config-file information into linked-list of target-structures */ { enum { C_SPACE, C_WORD, C_COMMENT }; int ch, lineno = 1, literal = 0; unsigned pos = 0, bufflen = 0; unsigned c_state, t_state; char *buff = NULL; tgtdefn_t *head = NULL, **cmp = &head, *tgt = NULL, *prototype = NULL; c_state = C_SPACE; t_state = T_IDENT; tgt = alloc_tgtdefn(prototype); while (!feof(fp) && t_state != T_ERROR) { ch = fgetc(fp); if (ch == (int)'\n') ++lineno; if (literal && ch == (int)'\n') { /* Ignore escaped end-of-line */ literal = 0; continue; } if (!literal && ch == (int)'#') c_state = C_COMMENT; if (!literal && ch == (int)'\\') { /* Treat next character literally */ literal = 1; continue; } switch (c_state) { case C_SPACE: if (literal || !isspace(ch)) { pos = 0; append((char)ch, &buff, &pos, &bufflen); c_state = C_WORD; } break; case C_WORD: if (literal || !isspace(ch)) { append((char)ch, &buff, &pos, &bufflen); } else { append('\0', &buff, &pos, &bufflen); read_token(buff, &t_state, tgt); c_state = C_SPACE; } break; case C_COMMENT: if (!literal && ch == '\n') c_state = C_SPACE; break; default: break; } literal = 0; if (t_state == T_RBRACE) { /* Parsing has reached end of target definition */ if (strcmp(tgt->ident, "_DEFAULTS_") == 0) { /* New target definition is set of default values */ if (prototype != NULL) free_tgtdefn(prototype); prototype = tgt; } else { /* New target definition is genuine target */ *cmp = tgt; cmp = &tgt->nx; } tgt = alloc_tgtdefn(prototype); t_state = T_IDENT; } } if (t_state == T_ERROR) { fprintf(stderr, _("Configuration error near %s:%d\n"), cfgname, lineno); } if (prototype != NULL) free_tgtdefn(prototype); if (tgt != NULL) free_tgtdefn(tgt); if (buff != NULL) free((void*)buff); return head; } tgtdefn_t *parse_config(const char *cfgname) /** Convert config-file into linked-list of target-structures */ { FILE *fp; tgtdefn_t *head = NULL; fp = fopen(cfgname, "r"); if (fp == NULL) { fprintf(stderr, "failed to open \"%s\"\n", cfgname); return NULL; } head = parse_stream(fp, cfgname); fclose(fp); return head; } tgtdefn_t *parse_config_fd(int fd) /** Convert input-stream config-data into target-structures */ { FILE *fp = NULL; tgtdefn_t *head = NULL; char label[64]; fp = fdopen(fd, "r"); if (fp == NULL) { fprintf(stderr, "failed to read input-stream %d\n", fd); return NULL; } snprintf(label, sizeof(label), "stream-%d", fd); head = parse_stream(fp, label); return head; } void free_config(tgtdefn_t **head) /** Free all entries in target-config list */ { tgtdefn_t *cmx; if (head == NULL) return; while ((cmx = *head) != NULL) { *head = cmx->nx; free_tgtdefn(cmx); } } tgtstat_t *alloc_tgtstatus(const tgtdefn_t *tgt) /** Create new status record for given target */ { tgtstat_t *ts; ts = (tgtstat_t*)malloc(sizeof(tgtstat_t)); ts->ident = NULL; ts->uid = 0; ts->nx = NULL; if (tgt != NULL) ts->ident = cm_strdup(tgt->ident); return ts; } void free_tgtstatus(tgtstat_t *ts) /** Free storage of target-status record (or list thereof) */ { tgtstat_t *tx = NULL; while ((tx = ts) != NULL) { ts = tx->nx; if (tx->ident != NULL) free((void*)tx->ident); free((void*)tx); } } /** * Prepare status-file for reading/writing. * * This will perform basic validation on the header * of the status file (typically /var/run/cmstatus). * If the file appears to be corrupted, this function * will return NULL. */ struct statfile *statfile_open(const char *fname, const char *mode) { struct statfile *sf = NULL; char buff[256]; FILE *fp; if ((fp = fopen(fname, mode)) != NULL) { sf = (struct statfile*)malloc(sizeof(struct statfile)); sf->fp = fp; if (mode[0] == 'w') { sf->version = 0; /* Format-version for new files */ fprintf(fp,"# auto-generated by cryptmount - do not edit\n"); fprintf(fp, "%d\n", sf->version); } else { if (fgets(buff, (int)sizeof(buff), fp) == NULL || fscanf(fp, "%d", &sf->version) != 1) { fclose(sf->fp); free((void*)sf); sf = NULL; } } } return sf; } /** * Read information about next target from the status-file. * * This will typically only be called after acquiring * a lock via cm_mutex_lock(). */ tgtstat_t *statfile_read(struct statfile *sf) { tgtstat_t *ts = NULL; char *ident = NULL; int len; unsigned long uid; if (sf == NULL) goto bail_out; if (fscanf(sf->fp, "%d,", &len) != 1) goto bail_out; ident = (char*)malloc((size_t)(len + 1)); if (cm_fread((void*)ident, (size_t)(len + 1), sf->fp) != 0) { goto bail_out; } ident[len] = '\0'; if (fscanf(sf->fp, "%lu", &uid) != 1) goto bail_out; if (feof(sf->fp)) goto bail_out; ts = alloc_tgtstatus(NULL); ts->ident = ident; ts->uid = uid; ident = NULL; bail_out: if (ident != NULL) free((void*)ident); return ts; } /** * Write mount-status information about the given target * into the status-file. * * This will typically only be called after acquiring * a lock via cm_mutex_lock(). */ void statfile_write(struct statfile *sf, const tgtstat_t *stat) { fprintf(sf->fp, "%u,", (unsigned)strlen(stat->ident)); fprintf(sf->fp, "%s,", stat->ident); fprintf(sf->fp, "%lu\n", stat->uid); } void statfile_close(struct statfile *sf) { #if HAVE_SYNCFS syncfs(fileno(sf->fp)); #endif fclose(sf->fp); free((void*)sf); } /*! @brief Find mount/owner status of given target * * Read an entry from persistent storage within /run/cryptmount.status * to identify whether the given target is currently mounted * or used as an active swap partition. * * Note that any unmount/swapoff operations applied by tools * other than cryptmount are likely to make this metadata unreliable. * * \see put_tgtstatus(). */ tgtstat_t *get_tgtstatus(const tgtdefn_t *tgt) { char *fname = NULL; tgtstat_t *ts = NULL; struct statfile *sf; int badlock; (void)cm_path(&fname, CM_SYSRUN_PFX, cm_status_filename); badlock = cm_mutex_lock(); sf = statfile_open(fname, "r"); if (sf == NULL) goto bail_out; while ((ts = statfile_read(sf)) != NULL) { if (strcmp(tgt->ident, ts->ident) == 0) break; else free_tgtstatus(ts); } statfile_close(sf); bail_out: if (!badlock) cm_mutex_unlock(); if (fname != NULL) free((void*)fname); return ts; } /*! @brief Find list of mount/owner status for all mounted targets. * * \see get_tgtstatus(), statfile_read(). */ tgtstat_t *get_all_tgtstatus() { char *fname = NULL; tgtstat_t *ts = NULL, *head = NULL, **sfp = &head; struct statfile *sf; int badlock; (void)cm_path(&fname, CM_SYSRUN_PFX, cm_status_filename); badlock = cm_mutex_lock(); sf = statfile_open(fname, "r"); if (sf == NULL) goto bail_out; while ((ts = statfile_read(sf)) != NULL) { *sfp = ts; sfp = &ts->nx; } statfile_close(sf); bail_out: if (!badlock) cm_mutex_unlock(); if (fname != NULL) free((void*)fname); return head; } /*! @brief Update mount/owner status of given target * * Insert or update an entry from persistent storage * within /run/cryptmount.status to mark the given target * as currently being mounted or used as an active swap partition. * * \see get_tgtstatus(). */ int put_tgtstatus(const tgtdefn_t *tgt, const tgtstat_t *newstat) { char *newfname = NULL, *oldfname = NULL; struct statfile *sfin, *sfout; tgtstat_t *ts = NULL; struct stat sbuff; int badlock, eflag = 0; (void)cm_path(&oldfname, CM_SYSRUN_PFX, cm_status_filename); (void)cm_path(&newfname, CM_SYSRUN_PFX, "cmstatus-temp"); badlock = cm_mutex_lock(); sfout = statfile_open(newfname, "w"); if (sfout == NULL) { eflag = 1; goto bail_out; } if (stat(oldfname, &sbuff) == 0) { sfin = statfile_open(oldfname, "r"); if (sfin == NULL) { statfile_close(sfout); unlink(newfname); eflag = 1; goto bail_out; } /* Copy most entries from existing status-file: */ while ((ts = statfile_read(sfin)) != NULL) { if (strcmp(tgt->ident, ts->ident) != 0) { statfile_write(sfout, ts); } free_tgtstatus(ts); } statfile_close(sfin); } /* Add new entry onto end of new status-file: */ if (newstat != NULL) { statfile_write(sfout, newstat); } statfile_close(sfout); /* Overwrite old status-file: */ if (rename(newfname, oldfname) != 0 || chown(oldfname, (uid_t)0, (gid_t)0) != 0 || chmod(oldfname, S_IWUSR|S_IRUSR | S_IRGRP | S_IROTH) != 0) { eflag = 1; goto bail_out; } bail_out: if (!badlock) cm_mutex_unlock(); if (newfname != NULL) free((void*)newfname); if (oldfname != NULL) free((void*)oldfname); return eflag; } /** * Perform basic validation on the contents of the target-status file * (typically /var/run/cmstatus). * * @return zero if the file is known to be damaged. */ int is_cmstatus_intact() { char *fname = NULL; struct stat sbuff; struct statfile *sf; int intact = 1, badlock; (void)cm_path(&fname, CM_SYSRUN_PFX, cm_status_filename); badlock = cm_mutex_lock(); if (stat(fname, &sbuff) != 0) { /* A missing file is considered to be valid */ goto bail_out; } sf = statfile_open(fname, "r"); if (sf == NULL) { intact = 0; goto bail_out; } /* Read each status line, performing basic syntax checking */ while (intact) { unsigned long uid = 0; int len = 0, err; err = fscanf(sf->fp, "%d,", &len); if (err == EOF) break; if (err != 1) intact = 0; if (len > 1024 || fseek(sf->fp, len, SEEK_CUR) < 0) intact = 0; if (fgetc(sf->fp) != ',') intact = 0; if (fscanf(sf->fp, "%lu", &uid) != 1) intact = 0; } statfile_close(sf); bail_out: if (!badlock) cm_mutex_unlock(); if (fname != NULL) free((void*)fname); return intact; } /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/tables.h000066400000000000000000000044501465135467200154070ustar00rootroot00000000000000/* * Declarations for config-table & mount-table utilities for cryptmount * (C)Copyright 2005-2024, RW Penney */ /* This file is part of cryptmount cryptmount is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. cryptmount is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _TABLES_H #define _TABLES_H /*! \addtogroup cmtab_utils * @{ */ extern const char *cm_status_filename; struct tgtdefn; /*! * Record for persistent storage of target status. * * This is used to populate entries in /run/cryptmount.status * where each target that is either mounted or active as a swap device * is listed together with the user-id of its owner. */ typedef struct tgtstat { char *ident; /*!< Unique identifying name of target */ unsigned long uid; /*!< User-ID responsible for mounting filesystem */ struct tgtstat *nx; /*!< Form into linked list */ } tgtstat_t; void init_env_dictionary(); void clear_env_dictionary(); struct tgtdefn *alloc_tgtdefn(const struct tgtdefn *prototype); const struct tgtdefn *get_tgtdefn(const struct tgtdefn *head, const char *ident); struct tgtdefn *clone_tgtdefn(const struct tgtdefn *orig); void free_tgtdefn(struct tgtdefn *tgt); struct tgtdefn *parse_config(const char *cfgname); struct tgtdefn *parse_config_fd(int fd); void free_config(struct tgtdefn **head); tgtstat_t *alloc_tgtstatus(const struct tgtdefn *tgt); tgtstat_t *get_tgtstatus(const struct tgtdefn *tgt); tgtstat_t *get_all_tgtstatus(); int put_tgtstatus(const struct tgtdefn *tgt, const tgtstat_t *tstat); void free_tgtstatus(tgtstat_t *tstat); int is_cmstatus_intact(); /** @} */ #endif /* _TABLES_H */ /* * (C)Copyright 2005-2024, RW Penney */ cryptmount-6.3.0/testing/000077500000000000000000000000001465135467200154365ustar00rootroot00000000000000cryptmount-6.3.0/testing/Makefile.am000066400000000000000000000011371465135467200174740ustar00rootroot00000000000000# automake script for cryptmount testing suite # RW Penney, March 2014 EXTRA_DIST = mudslinger.in passwd.fs KEYHEADERS = $(shell ls keys/*.hdr) AUTOKEYS = $(KEYHEADERS:%.hdr=%) clean-local: -rm -f mudslinger-*-*.log -rm -f ${AUTOKEYS} dist-hook: mkdir ${distdir}/keys; cp -p ${srcdir}/keys/[0-9]* ${distdir}/keys/ mudslinger: mudslinger.in sed -e 's,@PKG_VERSION@,$(PACKAGE_VERSION),g' $< > $@ chmod +x mudslinger autokeys: ${AUTOKEYS} ${AUTOKEYS}: ${KEYHEADERS} for k in ${AUTOKEYS}; do \ cp $${k}.hdr $${k}; \ dd if=/dev/zero of=$${k} bs=32k count=64 \ conv=notrunc oflag=append; done cryptmount-6.3.0/testing/keys/000077500000000000000000000000001465135467200164115ustar00rootroot00000000000000cryptmount-6.3.0/testing/keys/1.1.2_libgcrypt_md5_blowfish_0000066400000000000000000000000601465135467200237270ustar00rootroot00000000000000cm-gcrye +8XǙ;-*kaR\].cryptmount-6.3.0/testing/keys/1.1.2_libgcrypt_sha512_cast5_0000066400000000000000000000000601465135467200234470ustar00rootroot00000000000000cm-gcryGA(2"IRXɮA# K]z@RPZpMJZcryptmount-6.3.0/testing/keys/2.0.1_libgcrypt_ripemd160_twofish_0000066400000000000000000000000701465135467200246170ustar00rootroot00000000000000cm-gcryS&Ĥ $ٟ,eX*$o&s2L"jE?&b+cryptmount-6.3.0/testing/keys/2.0.1_openssl_md4_aes-192-cbc_0000066400000000000000000000000601465135467200234020ustar00rootroot00000000000000Salted__|q)$0 2xRyr,j&8?21Tcryptmount-6.3.0/testing/keys/2.0.1_openssl_md5_bf-cbc_0000066400000000000000000000000501465135467200227100ustar00rootroot00000000000000Salted__ >c z$Mj ]ᴢJ^ȚB:fZcryptmount-6.3.0/testing/keys/2.0.1_raw_none_none_0000066400000000000000000000000201465135467200221100ustar00rootroot00000000000000cryptmount012345cryptmount-6.3.0/testing/keys/3.0.2_builtin_sha1_blowfish-cbc_0000066400000000000000000000000541465135467200242760ustar00rootroot00000000000000cm-bltiNA6m\Lf70Q AMqcryptmount-6.3.0/testing/keys/3.0.2_libgcrypt_md5_blowfish_0000066400000000000000000000000601465135467200237300ustar00rootroot00000000000000cm-gcryW5W%k|cU @V^&]m ˸cryptmount-6.3.0/testing/keys/3.0.2_openssl-compat_md5_blowfish_0000066400000000000000000000000501465135467200246740ustar00rootroot00000000000000Salted__vm%Xpo_L)6V8N]Hcryptmount-6.3.0/testing/keys/3.0.2_raw_none_none_0000066400000000000000000000000201465135467200221120ustar00rootroot00000000000000cryptmount012345cryptmount-6.3.0/testing/keys/3.1.2_builtin_sha1_blowfish-cbc_0000066400000000000000000000000541465135467200242770ustar00rootroot00000000000000cm-bltiW<1{4Dyccç*o奏2SL5wFcryptmount-6.3.0/testing/keys/3.1.2_libgcrypt_md5_blowfish_0000066400000000000000000000000601465135467200237310ustar00rootroot00000000000000cm-gcryX'uQ%˗2_j4g[kUcryptmount-6.3.0/testing/keys/3.1.2_luks_md5_blowfish_0.hdr000066400000000000000000002050001465135467200234650ustar00rootroot00000000000000LUKSaescbc-plainsha1FF574ll5ɖo`ZfS<2|a 4u 4de25fc3-9034-4f21-8505-d5c0b36e4c95q BR8V7}z ޭޭޭޭޭޭޭmƷ2,y.0}-5)Ǯ6=R_L?MrF'U/“h7pN90\G'I[k^`p8CĞ(97m=tY$p #[(jM)55]+6)kf4| "Ȥ ז舃C֨A'ӌĢNo(i˕5oF!l\uu4*[Ĩb/_qe(+NtkJ2e 0XRJ^=5/' Lj_J wm~H,I; ~_..Ŷ@P/iΆܕ+ȴpݤD5~ֳ6@Qƹ.FwYf$ܻTݨ.dbSRn~D/|e&~KL8(y_A26B 6!vW eIB$ n =5^n?C9落KWoY\\42S-2Ed# yUuJE7L(ɦ8S`GH2*j}[UR/ +A!UnJ:`:($EvVRBu̼1M?+n@MسbXn܏km_*ƞzr͡gU?+8NIe]ƨfZcb9UX K>Уg,،Y۞4&ԣUf|æea"dÆ-/[ƯvNle fpAzm5Eaj@D5-䂵`aޚGG_\i(sWV˶;{U@N.^uQ[ !.?aFZmHc`~xG]9w>yVv᫩6w288~Ex# P:?M {}0G +Oyns9W P7,[j!w9~4 F1C_JavimDgc{IicXurњ:0٠ta2l`b4,Ps{HnV0;td/l>d+0>F|L̪9':f[q ӹ9ZuU8veoZV@#>N3B vhj8з:f0f_2׃҇f&1A,Q뭦geeߣ$1{ۅ[Ղ-򿱥%+>>Ӌ4(jH%JEnedhx ) `0Wލ^XG-znؤll˙ʐ2B\ ]I][]PKC$Q[4Ϗg@{ѻ;\j!9co?/KK` ,DfT'v-, G; zR=4c>`sg?{(]W4)-F*oV==3wt'±j}pI ߛJj=8Q#}MV7 M.ڱe`D萘2ɺ5 H\mE)WɄFaJalL.O BYK<ڦ>cHsbgmU1,?zJ٧ qMe?HqO?xc)L\j/@>#P~BK8>J{*=taժf0q9ueٹi;%jY-_Z7LDl\:LNӕSiRB ,QZ*hgO_E*"Y8>W >; ov7&)ZKޑj=cNH<x.xPhpHq0U6pUJD{HhT&i03C,b*QSÅKX)-S'v.!|h8xzlO֛&[+ve8mX !_2ŝoͫqpzi&!TWerP:Ov1oL>f)Zl@0P /XT;Nƍ:Q 'EOT lH ?9 QMiiGԕ3 uljIpхI[0i6|6dV%F0_m)zGV*ӷ?vmXS ^|2_,И3KD1J6uSO0QGqӷ憁ޏ~Ωv82<` 8r$X%kxvKϻrE缁6y:c9N(ePuF,i=-?CUё@n}KY_dŢTßt /,1ZT=`yE9*/ODs@_buL09iC]m᧜C E)v8q5y&`GX;:$0gi0m=L$ k$zc_CJpZq u"5^@lѩ<Ǖ<Ǜ#tur/^i(4lՈ[٭҅@Q7T?e"О eDhl&-bԡi*17-k qH1& \[S kYOC }]é.LAGEHne鮁 cffWv@,q6mpv+)q9/aIP-Zo.Xh>(c eхB%2{cCjGH}gzc!uƘ7JMK6w i/'I F8jes~ fS x M}d@@.Gl;Xz o/Vvⓧw>(rX;^Akj*9X~('8+tlbRYo&<bnJJ$3M;_C!;g§Uc^n{UUr8; vHmAކa]c=JT]20u|vB6*t> 6N)'.?LMv; w+ookiIἂ1CxPBͨ`j$ |څ1v,°kzo^f9 ԉkz#HrD~P]S^ (t-߲-#2nݴA>g}5$HYHĵși, /{gԽy)tr/#V(Ʒ];jٜh< Zr+Ρ7kݢ|1ѢXPDڏp,$ Ǭ`F_Ecfo:yx,gXqA,>ضA}JScz'aqj}A".ن [ 6^}ab.eBzqN.5 Zbv`H3syFxlfu+`VfJNOy'pPܹYoTYerf">ޗT0juY:sFڴM,-}VK:bEP5OPoW2+ǬS(Yihz-b.&e<+6%}\65d&HwܐmK"ief(?Qz,"/iسh;;|8G%&k`čRS/);^x:!Ɍ3Zv`QӎZ?3w5PHGjo;nD_lh߿9̸x5+<NmO6]=ɵ(%e?ǁ ǫ{ʩc_kq` 㿑;aei Om| Pk4H!yi(‹opsP$| ?WnԬ-1uԇDQXfM[q1GjyRZi)DPH%c+֔i`+e : hF ʿXie [S WQ0zaS~.hϴךVw]n3Ѱs+{d !ŧWapP $cEOUh󝟄^XulI-{9-e\ރt^/΋ջ|owhۨHĊU;YߴGb^s mZo`Fx4+i sI5:QWҁZ^p88ywV +B?:}|Bb :bUzZ_ 81.X8;~KVHca]D18SR n37=P0;3O];=s2ϼ|L?I}y 8C̊)!(8(7n ^BpS/ (8F= ޮf.3'u?{ 5h,L^ ,_'?IE{'e'^ ?PхHgIP׬b!&U?ޚQ~\ u)>iv)%+ߴߓ mUKn ֌#eyj[;^ˢ!h*a+0ܷA. oP߳kvG &ICv#&1 wG "D5`!o6kw/PMHPV~:mwp~Jx/7pi zg6C!Y#YlYAPw}+o؀ 7<Di;@Xw l 7 @ 9l/\"fP@0=K)A_@=vBCh _UT z[;qYi`*cbb#!@lb+8[+InZa1 ztTpLXY8,(Rl]n¿7L&L fgrMg*oΙ0qFWKMӝg:*Z \8h4O A,=I*H*QPNhq!I`"'Dws- 2l%Dp ?>v>nzevƇxȏ.mAE|`JK!lBK?5NKF=>Lh?\)7cej)~MDgiË︱7~P+lΑiTwT >w*aszt5Y{` -,h22* 87FxDKXٴZ2qʼnZԵPX`RN#l`7KKi:[d\%DǢ e קNijD`;gn 0?&U=,ix:]*RdNc8UUP@ &DHaVvLAV yU5ΗV3ZMQY_}TFҘ_u]}: pWr^"A=j1a!G\%&݋ &~8ê##r6x plo 48N@A3 10.YPLqH1/)H\۶i\@җ3E0Yckl/!JgȌ*v<,,F*]0zpqOaЬs ;s M-?rfJx+̰Kd$wG9q jMhԙ!ZXYWf>zM1AgRgl-c_'1*jȾ[j.W"98-YJPsxӃSOW`MoîsEm ~K;"5{᡺'I~jX3/Gu?!ϱ.c7ZZpg|`~g4`SoHqn?ke9dSC|ob2Ac{+ T#auh i\ k#%-K;s<? n2g nTº|)[+bp^X$k  wQehP9a @ą03AUja<'n-7#TڮI4?Ӿ+4Ɂr̴dDܚNgj=Vs&%@iO -0g8f$[ЬEd|# | NU`4 ~nFdVǰ1mY&հ3[}(@BOon]#YK#GԬqC 44#)oσG[M^K3u rTᙟ> gDp-<-ᜢB #Sm;"F()kCYyC Ӟw;%8,C>s$/4 KClp{&(SV2jAmJ. [fL"~V+m e޲zNh%Bx5Ъ8fUH=p_KV]/$xyDG y0"[0w@nYՖ\eN[/{կή1ƫp8SG!h~GugD&$4 N?!EH?^hc1c)X䣈뢖$)ày oP8/6d p)(:귛f̕I m6 qN.>7=xs{ όxF0{-!w)@>c=6w9? G=iCFperCoy^)W.0|UKb1+r>C zY]/wwȾE$[6̇DI(M{nIBfqެvPw"&~^htƟ f)we 'HS&P*?}ٻSRx Btr07ٖrn^kl,+6TM 9uk@ք:KN)㫙t'O~lz zCsЉ" 5n5r3^bM2eƋ þt8Låk8?w*Q̠a Wʀ?s<||3ΉtL׍ol՟_SQODή #f(LAu~Hο'{in=\F"'a̋<] YyK1|Szsp Ds \F`k*sE4kKw xq31Ju^ʧ|)*IVO"2! vȖ}sߌ0w>b 2vbą&qQۮ09c0,Rqby7M󬼔%%}8mӽ^H"[I*+_b{w|?5҉**~8́!GcBj~]p5NϖEo&܁gvx@WPboc'Odx[8Uv|0]Rڧ$IB4r&?Wz0qM}ge|PkH*;Ža9-d.H$;_I713ӸG23J4"gS`EMCO@W8/YeH0("^!KŐl qX">bqr/"3>Ki`9f|;Av kiIVxg8@! qSDR+wg6!}'%ߐP٠m@m5i WcjIGuLa/A O|EO#&嬊` 5h '`5닭Yoz5 4 #+^J롾k|h!gT/K<^Gbv ϳO+x/TfQ&%@Y77d0wt+cR#:}W z,ǙZenȻ.Va9KZ8N$B14A螪4)LTX5 %A݌lm52~y9N"e{(:x~F T^(Bݘcd!# gEXl>_U9/ȿO ͩs#,Kcup7>N3$ӊ(M ?_zWHS0 \oiLsiiz3`*-Q^EUz-U6khTcRm'cD&Z-譫nCD/]Act wN+JsEImwLAƦ#zzuW\XxsPbNk۪ 1Rlݔp 幪AEW6n %2MvkZUyc|lZ ' @n(˳'S^] hAi%O1eɭI\x<3,A<\Q~+vOD`q~CrzV侼N/zIҟּLE~`ƝXtoъmKpa÷|]!)ʩ|r0̉,:1ҡŕ]C9ŔhVd[4\N)khmuts|m}VSD"/DCғ~ⲟJ|7/Ĺxq'9d ƚV+Z=g 'Tϼ"\%y3`'>`.=bEXdSi<ExZ]~RwLҚTM6aLjL# (%ޅF_JONr>HT8F}=2"H:Δ¨B{¸R0LN6ne׹6K>XBXzsCMnSoWN(h+>+Gvp D_gI6> 65n"uԍnEDOxw+I!I@=^a_krJol&i!ۓd:)r;ZO2mx֠6{U>֐CݾM`30ۋ+b.聋"so6 L}XWZcNLe2:YAUNLOQQڻ5g:i |p^LD!СaPbW6YT1+ZG2,}es3FdߋFI{Q/&4h=Lr3ѽUt婙.4hU8*gCLNg( !$f N|~dfd0Z"÷I ̻ %A  ۪Uic# ANydIOq˯2_1m6USq>G|~@瓉kbS̊ޜQ]OxeۢM8.ɓ6QI]J?p\ ~E1R8K"Sp<Ɓ&,ZBխ k8ŏS 16Y琅YHzʍ!.MalM&] [eF]iMIhPz ^`[70q4cKItYBZ^bU`,'mnCUMy (/:'.*7SS~|S5O.pGrUȹ.t "c8 苬R[)6mqL6Flo0fAS`-?pEt )ía+K0ND;H;ek[ { s\ Jg5dX}9cria,F5duNu-z=E[$قLKqo_o|rC wޑ V[l<˥ۿd4G7"ʟ7gO&f~+qIhǛL5C׍tu?"@'xZ)#c HiБ+醴j±7 =^|hn|` (I@-c7=*HUGPN70Pi;Z:S?ͭWRXҸX. QZ`~79peɿj f>x46#e5=kںɦ{\Yʸ=*qx>fZľ'xK4JwA>Nq?85!a z.wZ݅8d*A|)s^^Wr閸"蠯Tk_|Fo!W*nMT'|GohbA+5'5+[XcfnDG"vFK4,wF:v׾s De~؏ QCE"0=7uE)0DY V9Xbev)xSO4$m`<<`ߚy"7l:M\D+܃d)w;GfgKxz+XDOknP+̗mxr"r6_?32} GϽH%5Qb9ѽ-~ Q֪@16"+,+L&8ڕUMx(޶C^UGn3^}=a*{7kí+#GW(Qa4(] bWSKoOb&\8.OlW8ZO"sF#)u,wv4sW|efj`A*TE{}NQk#l"S6Т KÊh-.{Xd%SL#{$;&6PС{Y:֢=lU<詥BoA˾*$Њrnμm>C:A,3+=sj1PՉ},Uc.G}α]8&'lCSUZP# h J2݉&9g~IV9Ajs_r*BI$H_YŌf:Qa)] .+üQ`ۍ[\?qOS!vQg'HJN0 vP,[RhCp,&$G0ҙcie\(fiJ:´GS*kx 1z41c;ƑIVx'Su5O&КBhԠW+UO @-?FSBv3PE)|CAkv@å2OZ|dуҗ)OOz:ORWTί!Ÿ|B|y;Q-%"S5 c lB؂3a\*GZEJUNNoOصg9)&EkVG >?N]@o2ICگ'=YX+s_jA'_]3}0''9 }6!6;jwie0rz݆HlKЛd@6ǚ ÷ϫm|a ܥ NWK͉HtDcG$;oq|@*.ԝ @7ն Z`IWJRW_`,WFpPд^E,|GdڮƧեԴa-Őѵ{<9l_~L*2Лz.=UskbuR ijYa1sfZX0@п \2^[Ύs_#RחnMAD )mx0= 9ZE5)Nv}m,Qg&DQ*FFɦb_ io S_8Wgߒ?E,vrDzQh;K Y րGYG`o%̈8J;02=Y(%rPV0fI5t]jv:|m_`=tIGh0t:hH0JjF#L%r]kAGgnIgy S&ο2s՝.knפV9pLcx^vPrG|pi*G\ }MM4of e>%&Fa׮;?6ʓ- TU)~=<^12 NR1S  -9[l+t4CzԖPο)(E )nl, lޗ>(E|ǂ]"W^,FAi$Ie'6XNV%CjJ6 _.I$*iՅH~y(t rS{qӄF:@G&|%!2j4 nYyVI+=sJqx55OvDRdv0U! \M+C/prƅȯl=4O341b %(MuY|7k,njB(M7~!Oh%R?$J_uogS"Z怤"䟦 p&kI^@CWDQ~I&|bU*oC Y"̟ EC׷di5hJT M.o[EW!% [Ґ^CŘCgx._)1A#s+M1m4C#`f7Rń+t I={%dSgcz֘[cVqqTu[R{ǚ|_ @/&\ᅺYRa̓}/z=ax׉%43es¿1恒ޕIN"'G'8=Ջ>d@몖}*PH~C#KDm@WB'@Wy ̨5E3DV0AWhN JLɋ=,3nY)!#-U65|%kM쐣1˞ }d^Tm cx w_wu{F3:;A(]_۔ @0g׺[D/ #9F}7(ik5 3 %;pp^myoSbݟ~Cd܆Ş,Dt5\먺yγn #K@Vy؆hH;_f|kmAqJk^C@'S y_'cpLJ'0̞7o/{6 @X} "(fL27{IH.q0ԓ.,eHses.dSd33thKDo{bԥ \/*ϝS:wnt[ t W`NpG_|dæ0d/dXi#,.HbKprr$[5sgpPb ʉupc]ɗa5Vv.0HE#Y5< Դ?*)CXmp*PiBS~^>&\arE/mw/^.{xZ[Ğa|򗺄}Tr'Y togp=KOn}G@u1FKŪg/6)GjѻA/K#O|WzΖB EvAI?mVR RT(`5|٢cMFk!^`jٮ K0MpNh/XY+fbH*K4+bB~FH fe&cZ9+[GŶle ^=1NaAUuu]F@'t6}Н(辔.溳ʣP;ZUy8Ιz553ma|똈<}%rg\ÃKnTYFQ!!'U{g?Lb^MA`nh| ["!fB#p~g+l"ƉLw}x܍=X;vW}#?ɎzC(e6¿}[ƲTմx*j ϤqJ:g+4L7 Q^ XK/tSdŬEd-ajѴbk1d~ؓD8S/!omvj !$'I XQѬ{qL]~U)QlN$rM3uTV7}Lv 7Q^0U=OݢBReV*s d#`:0IN&BR7?~Cqϭcñ(V5f\l[ o8ӌ7''O_SVM5G \'>.? ( {?0P&;ԥI%@_MzbRdFJ6v%WGy?}`Ҋm`qx8*tƕg%4ԍޟDҀ%m*'<;]-Z [UslK¿xڎhP<;am<%&|H(+eɃ^XpAr8P/|-ѨaD%!iPtVoZ?%妻S+w.0<pt,o҃5 !jfV&qmS.ӕNfGSոcm O)<1UŅw?/]݅ C )dp+T6V;;"e 36 ~`F{|Žq|Av^Lk?<hlИGy>db:Pt硒A9ȝVwD[LsS(,2p;_[F<,77~A9]2MtY#(&9V}6WW1Md7<N\>=ߟ$ z* nWt[_QJd?DSGz$k2:Unnh!q"*f#sM={%):4dvWfuaHÁը^籠D ;\6ܛh }%<=~.Ai"i|T'a,#@_zf W~끐D:!fvI(4Gx؂cK9Xc[vV%[~?iU.dmLdfbZժnCL)-Mn6(U>sA;|&PLVp>]3DxbIaMΌ9G FTo&KZ{iszcUKn?DDkތB(uN NKςwDg T<>O?S@no9f4aqt\"C@{C7"nx[OvD(ۚT+L(_+LONSo*y+TO;Y<<Y~g[` O w"2d#Ÿ8 VcdI|ufĄwXoǠn@׌ėl( CeEZ @I$m N%ksC$[4#OAuWpQ_} ;:lb6ii+ȕRӮH aFV=9=1!{|鲓 *Q*,7kJ[G߹N8W?sՌ [uE(OBG|"瓭ZT_hJ KG?|Cu!*>r9e1%^vϴrG~Y0n!œ?a&Úkx 'b4zR RLଷR'z#O 8dƽ (ӟyѼsک8a/ZhĜ<tQhŌdR l r⡷,]=a/F kR (RF4=iQo^Blwa/ӀFAH%f jW2ϵ#mDyӢpW )w_7/uJ|pN;=$m49!< EɶđnGQ0c$KUBxieM \>&zuEd*b*a?{ZEnۈN[q!$SnB=cl"tQ22V^GkH9X&Wĵm"9x+\Ls:`ob5ʌVEt gjnsD)! %oٵ$)r 9贒ӁxuOi vGPI~Ki$p?—=qeQxIٞV^97@JW IWvzrF#V=/~SShV5|d?>lb5ۜQqρR"F.L6$~dRq<ݦAªqubd{(- S" OlĴ"5W"@kAW1ۙ ?i^YR Qo`&DEߔԫ'j<7F-Wf޵\Js"]zB(#vg.MzD $E,iSWp's20j+'{`As#`Y83a>r_'l%V#{ ]Js?,1tJ KR5"D 7)DR]Iصj{EF"8TuI ?7( |{æ#r{1Sn\US76@ V>hq#WdJ+qY;Qs/X<=Ͻ~%%-=M#K2gZYO]!VHZ^9AXzeZaKtYSߕM܃HuFD/.&G )U"X5ELz0RASpht˖*2h©Лd=̋u2 IeqkTu[4tnڗMGTv9* Euea ЌFLx,TKDlN6QD'DqɚVUhgܟk4<~\Btji+Y (ͯ뉫>!$xVz(ŏCB{5i*rTHO.<߹PoU'$] 넓./ `\+MQk/P+\~uJ' pvl˱AettN~x b8"S4>LJU\)m+ؾh 9:O{okԚ-;!0]0m]"_@KL:skXQ?Ϳ;F-V}cep5UVnA3¯AYv9aF&V;AKy!1+"WI&]/[\j^_u\i(772AS3躅sFkS_/J|b' 9M{DS ZxJet?!(j{gj(VeID܆Iм'ĒRDIU]%5y ̛s`T'zŚS Ce? Bdr]D?M)ZyCp˚ kdvHbCs5K_=JV!3v>rW5qE4^ćNɯsf6Iv /1{%BhZ1(6y~fQc } C ѠsOl,e"qo13,3Z2]g !bsVBswJyDi`ؖd||)ؚgf#oGF7Pׇ.r6MG-*X %o*YhQu}Hq8R (jTIOArMnE2o靹 ƹ8xAh;>)QwepG/6hlcyC g#% LLE>N[et$xGwVĈfV- 8WLeMd"O%MNaD$j8%zKe$N$LxdQɑNyIiw#VzOpDcCҌǍcn c@,9{ v z܄HMνos.f䗍ul}Pr3x,Vj f1$!ts=I);; _:Szha^{]b` =_LOS;|Uj6f΀Bm OK>M2_bIEuԣl&yC^_pY.HRZ:t*4ޝ>ȏJo]g3XZW8>lU%svȠDzyaۭT=~Į=?1#׵zjҫ,Wnh@{T'AH>,H :; ]=Z5H|w@:Y9߰Ea0B/DlȜsC[j1dQ160yLc~G/+fdhGAJwFy}2wr˲,ܣZ)ٹh Awf=7]6 CZPTߩNTT $Q=Te3JK=~whPXH($<+߀O[@# qIuX5@pcKKHX[H`dux,A0F{I#@C5tTXt8C<TtYixV'#lpjN8YXͯ nm!KwE5̀߫+:! YFcB# {dG$us&hoS8r$PLjN ?s#eF,d!Ev֥=NUwR/~G(wA[`GC)GϩuEo!)329LI(͈@Mk6}貢/xK0C1c vWZ&j[8zgBTR?D` \g, u5(SCFbS_kjca|~C@S;:Ob–7V▯IDsKτgX xId8L2^R@`P=Cj9MR 1 _U"E~񍀔;TYgfy箶mc@* J4'qGv'VVM:r?O(XCmSAtcZ?DvՌ_q~F4CS_;_иv4RuryCWr3-/G)N _5%zHRgYlq ؂m% ,8bK5R[;LrB%4Lo7J[N\?Xbd|% w?tY>In1Qrlr.I;z]}MFlDdT4i_]=|(=g)\@UotP\{ݺj{Y!jo 7B}6#w FOO'y+h7E="RmcN㴖'!FɇD Bmi#W&4{TEG:º/&)Ȅ,L\=~^y\ߎ~b "*O &@Yg"NA{7{>5"JZcF@՝ 29sUHIW\j;hs$)*G[qdy1[~8O"+<>'-̳*o5GK+}%*n¢J?fl~KLiS<:Ê:$*tM.gڙǏ; (IHq,g0oFZN@0s)zʅUc,C0p$hg Qi"΅TYtl&[]B-0_ϡ+RVrsvИ~*o*R_%e04WQAqM}K*%_2@m ejh(XnIɂ`I:P!) ZLI$a!. ku |@4C!;]_6-KI9qԟt7 |ίbN1=2X =&hhG[oX!P,ZD+FЗ1)RNruY՝N"}8~h.H-1 PK+uz*[Wqx$:*լ\%D+'f8RMɡRwH0EŚ5Zp]&xHZG)la>l!M! Qs{5$/* /rJ_o P0^eGX.SQH`oUҥn 7ڣ6D+P%|I2P  o9=E#(x(J{,&}œ176&dƚ3!쇤۴ǐs(pE@WVttlU42i4c6a{j$Zr^{]ˆ yOr cQ<쾤brtrLsG|YX[j6=HrXY;"cA"c/(a7T.B/(ܙMåuu ;Sÿp87 3PˊP>'.e Ϲ,hMvM ҇phwPTq}MIi \;]BnT'Eكp/>Ά 1aK!pB!Y%%[_~ \;p«5[bg֗V :t^v"e@?_O3v$5@9XZۦ%;J+ܾ\}m[/(VfPV^aI#dm6 N4g+ γG38YZUģ>䌃m0؞ H}1Fa vI#eh_ y|(0nS*?:q?^V5FRo2֋9.ҡq8R*CYN}PjNRwsS w k(&VƅCj1~,1ֵdy#W+" | # GJ}-Dhv<`ZoVL,5=hΎ 5[yy}+![zNdoH {ʗ'[68 @։yG{EC2N;%w& =堑@-r&m. D{j\>ʓp J)ͨ7&0x' *s|!E/m~P )0?y1N;MT<($N[}}?~[ÕϕKblEOOȂwS #k  jo@`<@ d,{P^wUöv zP$)r[/O|Ey G}^T'9Wr ſ,O:QrӟƻK?>e1=z3VdFb-A8gf%gG"T#:|Ǣ'"@6gII}UAê*Z0e\@M.)stI)/\ΡV <ۉ0f%^ waDiV:AaϵnMH2\a $,pb^E퍕с{a;/Ǥ"OkHNx$usPOPK@Q=r̯Rpz0͍Ol lz~XDi HtG獜F` *:,)Iӆ0׷1˩"Q8ia0=JR7tK4V(iZe^tXxwժ.J3#|(;4up;u (ÛӖ ˠsg$O:x\ULቮ ;+{\FU)Sys xzyt^u3]!d:N@`y&}lu▰c~4*e{\g奫g|/L׉GB e霱 z ;,1񳿡7}X?ƿ+ɤhAsD64![!xn^gl:̷ͰiqBpK{P'hjҭBsQ%5V`BK#n5v]9,60Z*n}|¹Zp+: O/#4*XE66|= Bu A#6%u @[ׂ1>JbHnw+ڴ+ 8EQ+ ewKPI7m䪑tD4;EB+r*f *7ۜ:(Ĝ9Nceдre [aT0sڮRgyXPlS_@I—V[J3[ 0q-6/Kr_w^/~QݭϷ4xJXb0 BLc#DL:Q n+a;jHtydMw_}gMIm{ZmxLx.Fd!uWV7Z_E\eg;nW1V8=릸(ӗq>4iT92.o.oJ:X+`[455b~b)MX%5<Ͼb'qPtH.CUO[L] ,\3K,Y Ed>*`㺃hv"UwK: #Zw,1 ?7v Nltr Ql$7}ʠdX{ETKQ5 Tu3MD5L_~muYT/-'ާ"PuD:w3΢DѾhlW 7mvāfՍ:27oBQaQugtŏ&:CORW,!Wi0^OtK:gb'ԛ;+tcT5k5֪_XY,?Y_M9 7ЇfPu[1h .?(:/Z<8Y_ pU,pDdEF#g&M,6Aesk9CkΙwmA4˪.%dev ɺB44*3״a+yeJ mmkajVSI汏 9|-/!0Bgȭİ@Z bp2N?Ąmn!|?>!]+x 94B6r旚> \,sxyŏBg n}}=R磅zdADB8/$Ł ~S6pOJоQq)*3:z FZ2ZBV f;x"t Db'T:6 9Uk{8C-YF4? SzpT@FjKZ4KIeW#|PqeFD^2y-Ɂ?Ké6c@zg+C)DDw m*~~s?݀$llE @<4 B9;2,HtigەƬj?#MH;c,MF" G@1\yIMc$fdIVqI 6a6,..ypid5TR|׮I&hhBޕFm4tuFx& Q^QAmWKr//śxMmf7S)}$f2r_cٰSBYTLNlHmrO0ȿͷSg0{ 6aQty D 4Dʶꫩx) l'.ª'&[>jx=_&ryt?OQafR3X"= |sEq\'d`<\ B"sUNeqR@kHiFEw#$juprxs"uaOgV?[=M*i=^t~e},?>c mv#&O}plrfcL_ϸ Up]{m)$û= F p$K&$㈪{$:1>ži:0|k{T֠Boc Ȧ$ghgDeܜ<] -&ȇq|*z`c Ch7b8M4?3).l%;cKZ滴o(v|zx&CgÄ#r7-d(E(`$Zt@A܇(9̩Bpe5f$݁@^iM"N\u!7/HVn5M9lq⍞qת_MI^JuĮٷ,`YEb[a)*!I֛%TVɥȕ|E &'Z OEMdX?"g&f );{ 0律p-Ze("m=$A `׎k2y_ar 0C%&EHGd.Vx +7"WImY2ZjR`Iź]Dw0{h񡉃c;~La ngYDL[B{2 #6n]Qs(j9 o҉-mwf߬S; "ɌY Z(Xhi]9#^ ^rЍ3lG&үW;!KDzh-ʭ464O,v>qAd)_ڣ |j&%hVswVp- )hCMyNA}V!=''3A3; Ӧ?)=4oީ>I>Y*WS;mՅ%o\Pj gXp UT@x3NjO6V}yxoŌr5DHmM 22аx-,*Xf\Ѥ^59zt*y%K@.ꈬ䛘"0+9w:4Kn}* ,Sm -\6:]E+28)F;.&B-Fq_HlP!=d-%e7 ٟei.,O#PMv#J➹btefcN<vVo sVƢL;Z>7鉫dTEpWvnTGdo5𚚃S5%ف:Uԫt#0O5HvE] e~$>ZXƖn=O/g3%f QF%( 8Ea$!IH|*?bvZ|K|Pn%xңfF%Ί% ; < (bql8([)oH7m c>-EC1Oxԣ0կLnnP3?o0nVμcHg!QMLE$ꫬaڟo ݈0Óo H7=s{nx0U.K^l(@G[@5kuC6abG!8bb<`Mco0w;6#AVXs/Q3YԘtA @Ў Li4#$YĽ-Hk&\ L6YKY[ur䫳CW)~b=np2x#,*Peخ͈嵺Ƚ_OF% }:: Ldk;R{]g V`cƸ=q>!r!`Rb=9T(NvS-ZQ|3 0'G])eOFSiěuQ>)%iI`ui7/yr-R|i\⪛Acx$ַGx;]b0SS`Xwb;yˀĽ)GĦ#Å)D%e_\>tTNs.yt:PJBQcdf JUAAiXz ـ2k$ 30ϒ(bh9#Z=ɥ!hvb6(\r6_T]-6jk# &\^4``xTi$V?hDbZN.4zsC6 _c[.*}M7RFīf A^}+HXL̹`c , 1/=9!D"g'x/|obwJ%<|˹;3GDPɓ;j cUN&zWY CsnY>@w [@%9 8@>nUS{h'>$|9I~ 4)(LCbFm5/p%~}ZK7CWuКd7)FIUy'^n$Щ- 1_wh'yɳ|k sɇ&rofO>dbUWE-!9q!4F5<^5dQ=&=p*^]ˍ6ì/< -*IAC4v'F)Qz06x;Nw,FJk +UY덫B6?OAB0˝fr 'b~;?[hU ~$=sseF, DOSW[W)'[49쥝K"R7G"uRgD'C }iGt{s߻pe 1 hROb>t5*S Ms#Ah[=&b8[[r@hjmbslg#: M wk2%T!w`ڪ I=Bp}: Yv+. )?ruS }^̒6OC4uL!,9"D"B4a7Vc5A:k ]1ߌ R7ئJ8^cˀQ9Yq뒅S_zeoJR '1|"9/[COANJX>I5"L3J{d4/O lcw|:w.[#OԳIGPڇʰk.$LTgzR⢹XFH*"Yp&vQVF4e"`}ș$ &T)s fV89X>(= mr}yDkrXoz&$זe\Pf_6"TΛ޽w߂ pٸ5ŭ #9 Cns{k'&rYx/nƗS|bg1%6ngkBW^z9/B;-/*۴''{ |; dҘǢU)WY z$e]8*P֍LM 0>;ϭ>V!a݃ :i 4Ze?>}8@Gq6c7;q*NmCy;d6W2kYY#aK=]=T?e1`AA=(E}uޛ#"0\AjO}!v-CqBnF~Pƍ..mgrƵOmaփQ]oCX t"MS[>o%`eY, ib xjsj4Mm΁*PX<rNIѩLGkU^ I5Xd1ݦ#r0AJ:L9_L"fV2,iTTr^צ7K$7FltMÁA34^cxEd / B-+#<~ٌ^p 28f5ɸf5‘2OȞuyadm-r-Xi-ZG^`p1 "C/DO OwJz͠or#іr`JԶCxwBA? "2 )H.QK ;wS<@wW렴כ;|D?.j醖1qg9+׌Ig(2)Ok 9UC?~> fхQT iѓ$UBAmS|$D}3f˽=YY]?Ŏ݂M͞=/B$KTd(55%krJ98}M703/&sW`Ok- % %+&9Ȥ3x5QbQgr#Xۆ+bNtOJQˑ bc4GJOi9r /v/uz 5*N` dT ;ü3)vwC;0n8n!W^OS9pʻC)ߟ3fX(d?7fU-@6dpE6?=]0k 5{X38Z5Qiyr-8Ҙ'>XUJ +FtQ:,\#ZIS硹 + Z䖽 +1Q ( Oo ܠWʸUptkP9k%*~/ޯ õB 2H_Zk|1(MHn[ ɨ=@{Y: QU'Nө(\CQ[H%BfNh` 43*%P7̏l_9͎ݍgd{*LHy`8tK1#T-c&tP jA&^%6ϐW[Y%/2f՜TE&릈ڟiڢKNbG#= =G$znMC57_$g9)'?[zÆqH,b=~ ^`^&J}V^jWfoeT t[dz˰ޙ$oוR҉*ގr}wn-_T&tbƯg@= /%ePGN^9c8{ᑍ6mQI\3uWpc(D6R}خG I0s*IU'prxHjѩ D?|bnIK/mG;Yy1JmS_¥gPOf0rہS1Mm ME%ǫSͦkR:m$!Akp1ë.~LXdwI+|UomK'L؛[&G2WGnqPsΌZ^%⁼?nr"&nFfƪQe(j!zuL\Q}J~KSګe)shJgxtj{~p?{<81bSޔjDiyU,8tjŵ.ncG%573pJYdEpB9;2u|8+葛yfLfL'@Dec1@RjWY WgH%ALFRć9"`$ _KO+_<ܞrDY?>&T=LW6A S/ #9dڄhSi5nT7;M'B&Z0[Őe>Z g?š~.9 @DChcN1fU3Z^j,k>ZښEֆ:4hM E(zG+U7/c%_.u{&0A0 彩VnF`G̃3H1 D\ĐЯǕNvͲx8!^`Ar#=(<\ ,ӧ[ݙ ɩw˺Ya,2|TjA.tm)mbr(0׆˾Nf% },GBZos(-CU4,42},Hj>18P9"ν `)TP8Dsx GW]'G>vR?Q+o(2(2DMBu6yT %&*Y.),| Dm:w27)4nѯ8ʃRW ]g3OwKE^3Q%OY ~ u ,m^ -q6u.,XJ`XlQ%{S:GDl4 %t}뽊R J;WzfWc0alH\H5Í_mأ!,CF̹xg`gOĮdWm͋4A@ &[D)5:qcue$س֚d076KM#\ ed.5 BzDuaVo@/s*/>$մBn;,_ik$}܊P{!,: :-;/dh 2%i:jQq!K˶&m7(|Ԃi܎l9ԈɗhBK"G`M[?A:ٍ( "0U@jpPN6Mpժ#6Z#pgLa%2M+Cm)3FK?:ؖ̄ep"ԧor#mOpc6Wh,V;i9dȕ0 2T%]7|W\:8""X#E#m⍉mj=)+"mxÝ߽܅͗Ә(лv"n_=h"Gy߹w$gPE|B3P%}m+%Q@~$_%l&=ӮmvOB nFyـD4e婫!yeIių;5:~<WK캑8g:=zPX·sB# CfAռ?]C'nKšnVJkZ/\R:K/)H=م:|Ŏ4Zs{HZF]::>3hRp)E_4"NǑ'H*Xk'4YepE5ԱJgByNۋ5EXHQoi HV;-x+DJ0h9ϫdm5kC)cJg{8=*RZEz-PD 7;P PLW 鑴vSKsq;!%kܑm| ~[Ks18-r޼-AF/C|D9ryR+;N+~<VG2[P⬪#2Xwm/FGߛـk0qmUIhML")AdG W<8( e TxKµP0(9@3_ӯVx9yZLEk$ON3IKa{-?0 yѲ½?`әS.B+5S{:Н^t/S;2𴡈v۹]DpX!-CBP>pJޘ `l Du ~"3NsGfݽ紤Q")( 5| S7e9@VrI Iv$]m{]w O$ J-[ ȫ2#-nT-(%QD}" S$"":OVh,婝Z cV W[L1#nQT(~w!Su_Q2",u:V9[18޽ye5陳D"vn@2ˮB`k\GP&&T(~2opÎ!I.~Cދm5843oX+nv<'b4Qxf3|g!&njzĹ\Z{-s Mx=B+U9x /Eq0cIZ,OxVo (D4vȇ}ɶX 9zS~D M4l!3Grw;q7g|Bw9vI4;IH hG!ȡa+^i^KYoknɁ<( *DwǞ-}*[a 2˻:+0p7qz_݁, p /P"mHrwgb4mǚw rH]U.2oi&;u)Hao!) Nм8p ~q3޶as>.˽ɏQeWfڼq?  8s`\[Jf|Az<0ɫc&I!=T}tZooBQ5?> D'Efgu2GMi7~ a*eê觩 ٌ7Iu433XLˬ2x Uq{~o;z fRAPuD1 ~NCs%+MFׄ6Pֳ7"=@P>nĀ| k\/5շ1Ū)tix'z"A!7YjψPS>h-ww/~ 1ޣOx<J|)^I҆1iX"8 zYm-gz#`X ;#Zn1 E e XlŒ8‹BPݹT4:n&f%1@ M^DJFEΖxT†3dol;VhY ()IT!%d I!S6țȔC17|XN' KV6:lvNrkE(bly*2T4qR3hjo цϚ]!%Б~I?08VB?Dz|@I7E9uyn筺b3E&17> ɩ7qNў*l؈}TjW8[m1MLddW)Z&[k*5R9iW1ʊgY?6Dk@|$z_2;'$$&T7s=nDxV1SXդ*\߲>]Ūd',$/Jx1qǩP ᓴ%֒:I FN6`.$zwJvфMKDg#ڢesqEl"(TzcbY%\lb l'H%|(2o]Y:bc'h|{#t f+;$ ;wR,:d W)m$RHILR<7ձkpF{r 1x!M$ԭۙ"#Q2K }Y_W/K$B5^0+vp}g?V4p|=p-F6rIZ`;\g130LIA"bj-/10/ϭ6n `-v_h#ze/6!6?`6W"F UB`nhdkFj;}?RawZ=q* 㒣33@24湋D=l#Q̥_ ?5lta<4>J?>.ClP>(;ր*l-}jߣu e*:TJ&qEgV4i,]Fu\0V8z r!F }l Eej1s J/=Ⱥ&`?5NWwzOK? W~B6t+'ނ؜1|B+ H1¿MbXF*c'ɏ?SNx$K CrqY4OD@lO Lzla,>p4e\]Dp9PmL(KO+u;RP_m ܄FxUx];wbc|BA]Q1Tuʹ%yx ۺOмHVxm^J/vYc:kfqPJq8 a)׷wqH4B):by%&v׫3r)|Y0 #7~h._˧/ ~yw6REw{Mz%X.{Qٟ?5r! rz=̅z/"B ZSyF"^4UPbm'28DjQTcYM9f3q [G-]Euy İ$iPٻYc×mڞ6`ՌI% S0\S-׉B:I" gm|IrRd9(3wr]A.S}@mC4Sz+a5{ɫRO,\`aI=eubu# ; v_oAu:,x) P61-,!.)QZKpQç輳$!aiJh.F)8tD(#G[hcY=}6]{ HrI*HUDŽ4K܍}vĻo0+ze`zU0pϯOڰ Hb0I"1,yqQ!W"= HtaD~I.щQ}@h98N} 8P/K)05Ed.$-JO`>|M&u̮bvr**GNΎ}ո Զ? G A?`'`ywl>ljS# afLG y錚Ҙ%t9~yrE27{#"=/;ւ_.Ů2}ԔKޒi2w)S$ 9^+H5ĉ]v&K_!dPGT1K +xTs iŷmStW+Jj?XVӇ`($A+ lp;02o{WrN=C)0(<$p%aw=-4!ySRSiVy؉ _/mnC 嵛s?oR`#T=t9MbYW脚ҁ0g;Ye%|P+֓ Z9ˠ6XsHU"/DUƺbE+p[tT*z,.:RUna;"+>!u<]|JFFjtO(J2W֦׀[OW4U sb53&^|]%-(ԛ޼$Q͘A hמ Xzx JwVL<颁~kP & m1,-@XXHPRp!a@ӞҰ_eƌsY;. !-LVʱuPv,]0S1 % h `1VZ(x-0ك<0gDjn./XwkWL}e~9W.f2? r}Vh?-hz}q}(&Q0:Yěz[KAw!nfBїed"!TWhil(^Pkټf{qgզ-(Ku;ah${DVJƢz PЃkBhh3w ,sɏP7WP  s\WƵF†f߁=1#[v4 Wlފf3*CXw/D[M%>`)ft9(:>q* Hw0UGSqY">ox t}p5ZJmPs}S}>Xkr"^; JMUt gm^ ߉;ʬP5)`LlF!WEf,H_ћd֞`0F`2fN1~zT4<;-SINBpԨͷ[ iBx.(^[)js潼dX&tae*l_ ؁K~8mP8)ֱO)SNJ%mc8 Q@ N!|%|pgx"AoT,a*0S6&Ϭ ݆n)i0q@hF:i>ZFFZW/{iSSpLF*Έ:D> Ҥzx3xIMHJ[ kf!G{΃5o3WK^8ëqyzA{,HCKUݰˆ-#Oԕl'gP5nI[<%JxH΄>EwFf/ǰCNKGP[g]{Q}ϔvlZѭD!uDjC?ޞ2N3?R=kp5=yZѪg]t*~=VK #Vׅ +{TEk_+CCvYDdUIŤ5 ouW@EXd׸,*Il{x \rp ]B-=B$+'uG^=)ZT?؝۳88͎e\ ^l57h>t{QIy]<j0*<+Uo,I2"K;DS3jv[w*tQ tʹRL^V=C׭2n#< }ɤ~O{mWZ>"dhw3to⊄0cL!eۖ:qW[b?Ɠ gn1Unk+,rX<hB+Jc;ۈ[ 疞t :R\5gX9ħ4bU\wX5)-DDjte˃>-$"X|q+zdELCf-AgWu͍c c Pr3C>46y=4wWEǔNv6x+wb-q׳BOXb\RF(=̝ڵiGV%N1"'o5tѩa=;d*/F`{TC|9][8d#_Wk~^g>֐@n͞/[pI;xn$pnk 26C`mtlE_]%͞ d늭p&U]AK${Kh#+ zgM]p!+G~r>4-N># rzufj2w0 WM J|;WÒ$y[J,n?fPMls2Җ/p21ӂJz\c.B:(4F`BsCk=#6 ɴ@($K&֗{iCtkw[n_UTt鏷e+'ssy<ޡo&FU?P0e,KXr޶(I w$EwQZJ}AbU}/!YxO|aa2kVx[cyzJ/<d b=V#%G%YP 9Hށ喎2c9"M[`MԓgcՀF&qC&\=iډD >IUktX>0Uօ\Dj-oK;hhvp &$~/;[V/Ѐ[BO k`&ˀɟ Cs).nJQ#^>rJF${]#ݳ̟-JF׻uBfUn"aJW2''O_^-[/ڰ͓['Jd3 ۝aUoy!A2|P9Fم(a(ˤ1bsfΦsх䖄 ω0MNGiV2])Yf3rT+ߺ-n_=Ru& e q/G`[_j\91y석!%+~=^Z~ 1JOTDfJKhMEdrq:~˓m_z%R}V~M >0͢Mc24DmX k#{OO/QFO`"m0s@ qruXI, Wd[e\ IfT;D.#S4}Qu? ]?O/y۲6+.O ~=d)MsGcfȇ)L&bc*5k"{;6'5(6,'whV "}, \ZGZ 4LutEwY;t9L6Ⱥ6BtX~.I;+ kՂ/SĶ\`WjL;~DfpϕUyItA7`l9@> Ov_<}.0H%oN?1ul>7Pˤ#@WTԤSؾm+E6A+ -M l}G,kg5u|w)Rjp']ei ݇W"t) 3<۪:{k90dʷr˟2j +E}q™)!=1X% 0n;zd׵-SdWo,CAFC^8u-h| 2Vm{:hѺGʢ'ؽnD4 hNY/g?2 ZӢ:D21|xq..Q hM*3PZ+t{-`"u% |U&l/uy۽[M4c(I$`%*)43>\[g恽CT,YRBUYȅ$?(Y푞ி-|<}6lJ:L7GOGq6S^5FpՀ)9Ғ! dI|m xBLqts)((Lxj&1y~\RML_`p]Zox`#i@4OfV0Ĭh!L'{_ X]H܏3K`ƧcpNJT%P~)Ix%T]RL~5_+..q7C/ -`~T SL)|6wt& T,%""pV;1eL]wUKݎw|h0eIrclkh/9JZ.Zy E(exk\M,fnjbABpnWg8wykI >;%Kap&߰`e)Y -?ۂؘ>c].Ij@:nw^?2 zOE12KZ:ܾx5a1$_f򓺶i@$ta^YBv,B^%t8iǖuDdw4 [C˺W!ŵýs8u+VE)KWce/pHr@ߨozOjlH˘9>0۸zm8Kp1#Mwr >Vj4^sf49Q"q&Km-*[?\[Pۡg2\q,$~Mrf]>*TYz̗,X" 8)&`@  ԻØzB6WrNFr ?|o0b@=/erKS! G} ,,:k&9AW/TN_U`pځ̋7K ر压['=b"Lr5YX@]D;n37زVx낵΃nq#BXXq0Ue])1z)cMdAMQacl<7 \li.3عȔWRF7O_oӿۓTMH5>z ŅO"DqUmm1![A~#F WbZ(ܦ6A4+p  w>d9}LаtadܮR9k&q$]⯹!LSΤٍ|0<]F_Ր6 f]NCwvxHǮ+#H.UiPr3X0'q(XߚB&ʛ1c 'Th0~_(ICH`1xO#.N)5^Wwi `+1dwB%n=/J3^FcxDA}AVf:r~HV9 G0'Taz¾#R%m(5nhln:aFmvJ'𖑻\ϝa fWmǝV Mn}\I yh#f=dÑe/3z?(,` }5#2Q*CKŦ~aPV}3lnpl~AA=:2vɦT3x+aoywO{ɱ2a=#Pt O7sA c@ʃ-2kk 0[bNΕxD$pN,ce𺈴 7(a-aM2?j{=zuH:v4Į.wUH,cT֮G*1UR"s3EjG@؋F zGg)m`n[؞9 G~˛\B7^Ta_ tj>nOxGɥ[rK4߉U9e3W*@jP" C2ޥ ^YXUf?- 1:\ ^K9Kp@hi?Fj7%MVNaC'IS{57OS=_INҡFU+V@ﺑ:dH;OESNR eP$YQT.p+R΢䄄t~2h8G̾g L!8$'378=/!Lo*mB>]' 'ލ͘8o|ZU_]vT<`͖S d tE6}OtK [=㊱)<*=9ZS/U(O yONmG͖# Hd͝g.kqng eF"ȼ Qt\M-XܴQ[ bKHTRau_jNf\1<䟎@P< i ^?[jwfCF ] jyx xsh@aV+VJyȤX+iD,;=[zg5Rѧ ZaHkF{HP ?PF|mŐ?P%B.cm)ىbo"(]Xw"ҚT yZLZ.ٷιEc#Í4TX= 5P*qxPܪ/sI"o }@wlvK)$2 Q uwͱtʅ~vhDvӪHm/vM`,'Ya]\uMB-Ԕ~ {c-s^50Ӷɡ \t= މ3zwSz;d- {;hQcdW& sOdR?XS Fڅ<\)v0XnE+wyk ;ô',(4kEkqiEl FؑfmqH.rO=qt~zdA+T)e2Mvt[%;-All?,GPa'Oe~H-هJT}sr$)R:wƏͨ 9FCZȰ[̋ 7sMC!T4y:0-y:|S$(T@BE*g]Wz@V_VdF!"xP_LBtŊGV5ۍ#ف_͗lUwAv 'sGm3YlY:b9|d0y߁+g:'V; ntͬ)T 8ւs (݄(Drf.HN tmOel+㖾J Pk]%d5WY҇Bjd4Im$7'@xJ,F;ҩ&3䍬EK3f&1kPMoau@p>D`><@ZMiō1h7w\x v)xk]=.Z 02n4U;sď$Vp}r@N3؎"vO`jV㍏ZҀ:/_GE.аGO.X{_3XpZWph ^-;~>{}ۉe`Oe{e]kZ~ $p:\E)| 4P"E|bn~~@Qa?\c UgBM7"/V F88(׾=Wd) 5g/_X{%0h#b8U RS \7o Ze[ 2ci.?ء*|FT7g"udGbrh`''PA $ڍ׋գ{@0~FI6_nfSBxmQPI駗zc!# gXz)$f !IW$ZJYs30 !W5d69BģԖ9HINpSP c`{/[ׂAT% ės`Q_)wZV*)f$ۓL~&a8l2t  ~63ATV"i8=;'nDZmvY}]X9Iٜ NKʫ4tPFS׮EG^sQH_4W%rcl~KSJ4_S'\> y04Nȓv.N!~齬}Á㺡g*+.v k@LׂV|/6"7[~".7@4F+@qRkOH 1:{{H`dĮ f3X!~^ nΫ7bcYh_`L/S5cv䔓 F<{J[H"v܃%Q.{ AV yvCesHG4 }JތmBp6 ot#b%^"w ԤQy՗7Gջ9椏<'*rD( a-QF}/ 0κd3Hm> ZY3U34 {ԃ*-Y7+A0]kZ 7fcfzB>I|OUq&ީ t䁢t5@d& $vM)x]8] ܒb,#x_|UAGzCܯacryptmount-6.3.0/testing/keys/4.0_openssl-compat_md4_cast_0000066400000000000000000000000501465135467200236510ustar00rootroot00000000000000Salted__6rs4oʰgޯJwv+-[͟cryptmount-6.3.0/testing/keys/4.1_luks_ripemd160_twofish_0.hdr000066400000000000000000004100001465135467200242140ustar00rootroot00000000000000LUKStwofishcbc-plainripemd160%Î˪)8hh߲ڶ'2R !&Ia^?P5~KF[O410278cf-3c15-492b-89ef-7524db7e403eq <]5jt&zO>Wq ]bVHcp) .铗%#ޭޭޭޭޭޭDZy*>b̭ep8_ PōX+=crvMʭQd s, .h;/ѻ]PtqWJܝ m0/AmjJ CJћry昨k)40F6ʧ˭姸bqRܲA9`/Ѵ'΁V,ޭ&EW1L2 ./!GVu_;#0t=eXqtæOw6M}w"ء[~V$~(XޥnV+#s {ri;J5m:}û02/\XjvG %8FϑU ;J9 ⑱g!БdIsFxUD9T i42͵&@>Js !P_emCy7ʛu34񒥋ZeIHccg7nu6OUTOLGLb|28`R3ʡAIuۍ U͎iG'1ux ff,xWrbEȵ|jPD=QB,&Pl4.F˝O:I(7;@?y/&TXY kf\4ў&hɳN8\cymKQarGxbNܢ,iZt-M"ya},c!^TdFHs%G}t *v^j=!x0n`ϴSn%$'wE _5FaB_NyQ!̷cdiHiF* Nح{Oa!A]ي GDoKzԷP5;O6{d0HTZV?m3U!_Y]6} =."eqc䑨P*Bg8déoVMG;/0~$5SG-N{N؜щ$"vu 6ُ $!xDxQ=]-ҙrohQCL[.w{ABښ<o/Zϲ"nD llUZQT$[C M7;M&ejhd^LXWTG&D_3jЕs?fD@l^ Z4QARqڙO@s,Ð8ˈ)J%iuв;c6hi7Ci pn2 l.m6Yԑ`X7=>buԓ:hλs gYg(EJ^`U^EYewB`B [΢bYl!13W=~mT;.O< ֨kwM]D 2ї~ KT&=~wU?_*zcLrSEj@43vZff]8.%*6 ~/pxZp 1f~<+c!EtH$B{ *T2#!p1s6hC0q +L6)a[C\-Di>9dR&Ё@\h@ǎW8ɰ͋9=h^aLs؞:$=*׷~D],vivHy`g͟?(rX!ԍ;0 `4Vm9(!1&"1*,挷~]Rr[UQ]wSR+^j_W-\; n 7s޻bޭ" 0%2b ߱Bin9xm1'< #CxBlIo0*Nsjyo|NK[]|:f#@2#_V 5kSL\\I*AP~dv|vD1IehV\]D<9A$]FE~M'0̛23.6V"(,Lqrdx[(1 FaVPqeJ6ٲ!Ę$7į+ @ %" pFO+hT[q57ל4Augt Y9)|;E0z̺@~Vv܏vA_ǻ!!`&+h02j䜳ɥd]XDZCqHutyΰb; jyiGJM`WE)d[,|C  :OGuv}kQ&;FH&gWsÎDF7PL$7k eΈg]D 񞋯## K0EiWLEt|H;?ZJ90v4Yߘs\!Ң|F8L+6ryͻi.%ea4X/~Rf,uk-uh~^ =|z UqWQ9E_Sh>5`FJ1F? ;b]KyaH.v?=BóQOZEd1ʁ$ð37 ~Pm@HPkz2QS4 fx1#9WŘ""OgIl}c Q ,ikmP4~׬1\lSzq%0&ܾu< ew3ayuDPdqr8@Wa{E>[|c.u4& A[4tEʾj/ O&ʦ֝Gu9<ϒYҥT`8g)NSWgD@M#Zf Vebwxdz2}!&yf?ʭ{dsLR.  a#D=G%$h?D }3-^EOF?afSǴ6+[BHٜtrJp귇^f;ᅫ٬v#М2\5TԎ#j{OX5sKb0r^HGa yJA,-Omd,?DR2nv@,^s& VʢwysHS.:ɿ7 3xP/!(Z= 22wwUAZZly;w-k> (P_+:(Dn$:,VG0rL'Jkı2GMDžF.r$LgħK-"@;fnBbԹN^ A8uZv!50wӘG < c3^`Sg:־Ң2VJ)ٿDq¦)<#k|e쮩v(m{Icz8TkZ")ƒLht<ѡ[6:"{f6ձ%՝iu< + 8@;$1&>jqI$dJEq@l{GfjVʼjcƫ$0pjQ0F tZ|`  k.vT;t,ìFX_^isgC:uɪ}qb3dóg-pWp'pď$wK?=n?_U39VV>v7QP`FVBR`w1Vz`Ё";(aV(Z[`!xںl# %MR)Dc%,"<3Kb}NO0K怉1`N97e03CL "/˖[OF5S .dѷ@n/I94׿'u/Wu%x/֏Ys,Ibω:5ANw\/jYO[8%%nDqښ+ؾ{qgq#@jIrNj t"[/CRkqj1Jч&e~v`Nj-/Z-.kTQs}-.Vrs}5xN_zppLRT㓅!s8;LM%;a-NdO3KR*uAЙRTDy/(ʠ̈ܝ}zZc>Q,{W좨-!uK@n4i\1#}T'@Zq8TtÅ#1 A3jEս&cTm7s%O+s2 B4Hb/56ᮗ_R:a0gpl1˼F,I{{-B+`*c( frU<D<4,3Qe4!Է@FFHi"{xWAh]?J &nM@,yQMᇩ_9ݜ!Pd¼t_nOq;w$k#|pn_ZQIG,GxA:q`u > r wC/gN sTW%z/s4Qӝ1Qgϳ.ӵE_Γ0O1?AIоcoW@Kh9:y}:ZH_RnϛU@5rpzmqO  #og<|9D2(C I{;EH5/%Iu#Rޅ%N["YX`ӗSFs~9@N|pu&g&ؗς ß+|,RG6Ds9x\z8[& U4_Li.0_uTRF(uAD7}@ WBGa0OhݥOxv% n3]Z9C5O<^O>%F1A>C`xЋSyV8jRxDZk?NeZ)GHImkJ6xr*J(]v#uFw`0W.3|P[O}l7%_"9gr Z*U !&u!9 ,ESKdBbv53`i`LX{!@P_ķ3]o卂6[ObQZX9[sΰaUغHQ@܂X֓4_]؆ձ]Eß =T~eS[B*1FUi8x88gc{kuW%d0#qwK1J2ߨbhGx 5<Xǭ1| ?!mȵ-X\gk'Qyfp$"6`0Y2T¸)?αRWd{B֔sh%XK'7Kĝl)0!zl3zJCqRAəҹm$97ܶKK&I5`X;{3e=JǗ#JD;TY~GPn6Az$Lٟ 1L$2R'%oZo|p0\pY{$'@LM\~oʎA>@&="͖`MqNRܧlv;()䆹l =T<7sr+XB%e7#}QR?.EFζY~2v|Y aBŊT iv+y'qfqǗn_yZ4rd=^xZhp&D3]dȐLS?QzsK;?a_2PK'&f }C S@p*5*:*f7K^4}Jnm8GlM2VvlM46Z:EO&IIPck&$3!+Ϻ>v;D?EqTHcƙG-c ,~ǘ h,:e0z-;$vטqRh܃G ?b(sDkZ 7EŦ,Ful͉pe*( dϲyå%wĮc}.LB( CQ^'ʰdAL?}Q6 '@'S6S&4W)cNyp4Gfkæ # -g1-?j K[}ކRqMy{^I#6ь;,?ٮO? <5'k^<>LwyoT8Wt$ ۓHq}a@]@\ՁFL^ \RYЙ]u BS x0Ho5B.U톳!o98JumӀƜaڰmnˊs+8fd0:CT*5iX.R@|+*Lk~),k=(?ʻ-X2l]0\cF<dԋåqo:+pΧVc곶iatc]L ݍ{rLK>\?4m\">8AfiWȖڸEwqmq]p!DVtFWh5 ѭbl ?#scmau2A얚tGyvNo?$ (~@o^\==:krH[^aէ|cqosEZ%o;B=7i| f{pZX3k_ߤ!R"l `֒>?L\f)Id~@m=xڥno1WNΤ|>>Md ?e7>J=ɴ R;:.1$ǒV_p[\Z፲EZ#XbY A) HXz8iSnnD"+xCR\\YO^~JE_% L|˧{QCԥEwUrujϫL6a76fa?= bO·9kR#5{v2t`fL#Z ^*1AdphIL `W!.ķ3,wajNXm)~ɵi5kY0v '}~rrKs5g3.-tLɃH]3h'.@dp%u:Ap"k-FCDteW"=Ef#i.%݃Θ$+t.ИD".@*w8ƞ8((c\ S)3@-BnjTȿE ~{H>)6K7ϯ,'$HnHsEm3k2b >LJm@>[rj"jڑ Hs~Jyzwۮ; &{d/A4%HE^;4t#6AYazezw@M?q2s܆I`$ic "5BLJg7l-"ԇ Vh^!RY 0v J2ⰨB㧡2iX ucps"tD3(o=-r‹yyȋ񛋑}T.ɑw𠉌gT٫χ<`a֑.f׻ptVovH=VzW∷?y?@*Б6i/AFjec5y o|xz$~=)掲|4Y,2[ԝ"1g ~$Pn6L[*KT` ,V"Tfq|,R]eN+s=_`." Ľg(WZs]Н16£ Hul΃Cmb!!T{ }khxf,.6v)U89_0j}óx"q9[g/bf]][c ?J@&snMafk=<nȪ\ƒm_#zpkBrq5sFfPE Qmtkfl-y(*6}᧌htv(gxĞ.thdYL %b"EHZaq4F7Ѿt۠Ξ{ŋ9s5]t4>9p#amځTZ{{^IB4>!9&);{]:3.6䎿|cǣ_vD 1iD<$A"_o dzR޵|ueONϔ V=.fIuҀJ;Xpn',#mԚ!ngFxe9ЫyQYa ͤ + {pƆFp/р g*lؾ%H6ЫIB(Sfmb"+$I*^Mo",E£ApıniHjW''iꎨe+<+&oq?ڢSA:'gHO, 4EtL mrIr}5Z*nbߙ5m_4.AZ'~j"xgM:G`Dv9 Ÿ]kef"r(NTy:u NLٳ;xNAO<дnիdNJ]v%nǓEzGTEJx`Q<7Fy ȸ Mǯ6'̊Q$ף0_Ir{:26M s~6#}ȥkt{sĨA+/]ŜyeRՃ !f>fw l>%V}^ՌJvv%NtװOh5ycm̳ Q*{U:agzRx\ض$Z_&)[EAY&=%Q:Jj|>=0ձsYK+}WiO$z׹Sz1- i쨒cZXf E;wdU#V3xu%=S}ML8d?5ep(8,~2.9xc}4aAJX7+͝)7 l;8; )WM!$r)9ko5O|ņZŒ8$,JrlY_CinHt0@nnLe]*қnoŸFAp숫 h B-1770^(܀(b i|F٦o' B^%1MJ<È\D2V_1'/[Oq9ջmπW;H)LGࢤ0\YyuUxEǡNk52t#V/8tFG#FnBw~"6؇,B_u#*.MPCC]7*e\jͫx[Ͳ5ypNTU.e0qםZuF?ʑ]#nzprxPpN< L7};3; DƤ7WRHŠWMu|̈́ גиvI+89 [3NNo/uF aA&x&bvzSYl x!'CQR[5!t"P/A8.\=Έz~ y\}~KX$,m,R0u_n=3#B:Pŝ޼Afo+[%XIf;q/9י@`'*u+۵[!HZ4Kvaf =|gǘuXyڦݯ]|t WжYPpF-t8u,g#{,gMlZ {kv/ 3@A+q g٦Rw0]Gl+;"'o\-DIoJϹkX"3q\s8gV|Q.vD!?WوŁɞ㩬KB2o~Ĝm1ձÁFG zu+ MY5g=#RڌK ^B㯮ҿ1%V Ph3u2w:\8s7&j*?l$d}N>qxj:Ioy$j&.#Q  toa9LָdH l ̊k9溳ƍnjtC "Wf* =>ښRg!% WA@ }r-RG`f3(C$ r( J3xU:=)F P 86BYO nܔ`NS4p[{ 0Wg ups\lS&ܱjal)t( ]+:z05Ǫ."@4Zh{פ 'Y.ڪ&5[Y7Zh bO 0C $Wyۛ&B""*1e:bDeTEu\ Gz⛡ɎR֝ϬkQŌkksCX(xL7Yˬ i֊/ ^JMtK(pMF,`{> .텹X䥋Wzk"/FN{c!ZTVE4͛6'B#IW&l&6W !IDHӀIǃ"nuѐ.{г!M4;䫛Z}>Q[~5m kYR${Y$n\ͦH}6? *b-DCD#gC: *ds։cc.Q(^\ֶTއݬ+͐y'М:nXbjdk ` 7l12k@mԆ|zWJW(Il .t]rV>ڟ\6,٣ }r7if .=ߜn2B GAfҔiM\:;7Ds^ ytAO_@*$o0Wq [oqS#{^P$nc)p-ٮ^H(VڂlI8si Bc  ՙbI-C1WbUoÆgբ+BIjb 1mgnІ{#ry8SjGEmպwCd[Iˆg>Fzpv'*f(UPK?^":RFM)Bd;FO9{ oP5zQHʁj=Y>R#r>,-Ķ&K(\vGP<3j6fu$f m{Cf(@4`o2(e6)b> %b("\12 HlP$ZDvYtr`.+]J[!wWH:ㅖgp23]:ߴ-WdBϦe3yG c]K 6Iɘv8 [It\Z5Ժ3m'I|bg{A]0kFeNVuGܙ!/er;3ZtLV'N ]F[vy[UJgy۞0O?0Ӑ8w][(3X#gIuע5#~-knN^7ys`3:Fr:.B5j/?+T`L>S0 ÏC">'[ƺF?'P6<,%|Ɇ?k8B ?jS~o1D29AH'D!|WdnΦ~ogK`F(pu\]\ۗyNe8qss; hIHT@YsU86+Q-fX &$q3~{_Js g5eeqIi) (#^s?[W3 Amo[vq5$M膕~\QJ8҂wWX{;ˣf}gW+쁔/5t3ǦrΑmiZS΁''=(v! c FVjr. p:EՏuPW|;7+pHfbsL;T#t8p4mC f뉋_+kBq /1rbc`r{2U&.c%73CP88JPbW=Ňe_聍x Qn V=I?~_ 0oFCPfQh %Bf} ~jȎҍ9  5kD]ul_k|"A/40u>}ϸԷ 6kcyߏ^4D kWг3gfXm1}(c3?oЙ* =gd@B%z XՌAy jT3*b RgXQ)1An.;eΝF:xыQ>@(f󋷮E¥J::ɍ0'Aظ+N0yL*DM" H* d8Ϭһ8`{sܭѥwTZu* LŘpF($녕" x7]'Fl{ېu вly<4W)4;9k, B ,%wWEI\KlI. [8ua'o;pwBIk 6 Y:ɶm) Tl^EꚸRP2pbw`,;BMr43! jnb̡d6ZhbUb`%/# Y5VDs(~I+$Ġ 9iLbP¾Ur:Ίu{dL*mB7 xֹ"D9kMznC_9iA_Lz]kӂb4U\-t?w^}Qs @PH4 &>MhMwu$O'K+%&gc2e, Z\V,Lsv lE],p 7EV<]0 KωxsּJ%R),r}rXPw>")-MX3yߛUXE~IJC(HZ*RxaJMdJO;JVy>#IRj..qp'0-FC1y+ʩa_ K85 (u;% LgP !/-{ 05E9_"p>ͿE)#;J!6l ժPҧkG36D1P+n;Դ"GC{)`r F <}kO-E#0Lؼ%j-m+/.#N'` l{Ί%zFԩ՞'zQqoVٴ]ejV{lMن570ΡҪ61-7XR:~'+!(_C eݽ_K+lݤCz`d7ʍ*#8qQx,wΪ]D1DcωRDxn%‚pj6^g!Tx"e.@KN: wxk}$.CRϼe8 C2PSKb&zf3z40ƘQ+=lBdiN>tg6>]1WRN:rt$j\&XT9Bޔ'0HMny Iܴf_ 7Ee02>IP MA^X]j@53C/Z_DKgS7ιR. VT^ģ0= CB7VsE8> S%;x@8B֮0YBt."hsqmo!/R:yXscs@.K'0 BJX~@$ eLl*=S&J!kX]ջ|uc@ѮU8\my8O0Pk3:/pBy6o#|N WV/B4W5"kn'e u'KrAI|6fL;6RLͭ&; pIZY-+aPj;;+mn;'3\@2k^SsTMXՖ(QҎ?loR?!Cb(3+YK؇G|Rz,y/!s"YJd3mN5OK_T`?`|QL4WissqCcCB;^~R[>׆n6=З5ى9{$uU~`+J+ε6K(բ'_Gxf"hMEN4)T+큿Ȋ䧷%ݫ)봄v|Kl kõ6aܴ4aG zӘ@egcqvoV4mscp2w!ozy1*ܾsXrnM6ce`9ȩl: 0kwphl6ei.z#JTejIヤ?0M;]`D3Ojmn(B rKE8Zk3gK~7SV7(dlt0`f[Jp?л`HpL#'Z70ꄱ)h!,PUkeT&ؕh*|U韩iǼ ^H UQ9EIq yϢpU!Xk:Ibq$'4o"V#Tzf왗-\/Ԧ!R 2^)TLěvE>Y] fp3ðOFҷ|*qOS)s|`̐wOCeE|/dm)8}Eif*{:~®"~`5LQF \`r$ Ȫt#6eYlTao>ق[pEnf jx+2p|+Idű: {}IC հJ4= fu]ax3ĵ~ dl*o\j]( e5 +7T 9+pEkOCD3x*"*+ AoDlEsl>g`ù,Ӳ!/n_ *?C.l8"R'#S9cNLۀqa#MKiU ̵kߠl-QeTP!vI:n=d@ꈑi>jn&t47b0iFUIU*E}7,2X{D'_XMF;3CůJkg)ٷc?>y'Z:t1T 3bԝ<3R L,rFEù.ծa'c>Oto7[;. 2`o/dX9Zcl2'.I3_{yfi+Ͽk Gت&aI9z_ҲQrZh@^piG<Xj0ÁhC'bT¦NE*_lj5]c JRnYPFDoLӟQ88!'btVr_\vZ;_ѳqєil;}q"MP۪ `rJt8ůC+!A-68u&xeݥ[VnzBA0fy}~lwHѽWlm(sHÃלk^^>ǔ x/EFMH'(~78*-2ӺNÃ#hTXN,;)3lv Ep06$11+P3JYğ 6V '1)멁SJP^D }#ZAҚѝg崷O@QJiW@pT*d D#q&E&*{nFD0'jnx0{VYt/lj 0w5N%[9D`VS8I41a4#  Mu>Tȫم'8F=J2R8%(èrYb;w"+ʶVua<&TzS gz6&4 B'ZS eW<;^Im-a*IѯGT wD}8w[2Ib4qm8 EŻx pwX7K띲m Uw@KeJ?Ge[S"-ej;[Xޓ*R^u+Ƕm - nۛ8ҢKۑNcymijg"H h;6DSYһ+ܱpar@5ܝijc)LDTJl[Uq;3 GYsWant Q7ЀU&Q~v%МcK e*cIJ3pIK 2]Hf"tA䊧e,J&),Y{=ȕp8DEץy )G~OP= \pxKxpF;f3['g+L:Bu3~bwf.Vk' L.Gʡ:ڏBtő1r҇{9_]uUi+bz¡Tow?D >dԉK$!X{*ת<ݪi5XZk>K]fQ6L淢#y:rB#00n~G=H|KR,]@FXqj P-:[X?TX}epe:W`zV^GƞESNw85B)EAPw /"V1G#V=tl-D~~ukEY`` + ,2Sz*MY)o<p#'d=^r=ï5 )H`PKb:y`׮PA(H)CcC3ms$ RI`t= =ba]BH_BU c?Mo|s,he'IP25z܂D3Ui 7(JnHnKqŠ/5aj/2(jAR ?&mQ؉rei>n:9Pm9Wc>D>V[zᎺy8 h\n H<><+M=+ UxBJ+p5U<՜5se SƘ6ʗmtVj2p*)nMAO{rۅ1mF7Sa]xoMDjl0'Q>PPL}N!x^ M~g_-/'y;v8L:xxj7]F7F RWoг^s=5:jt;Eʒ1 E ՋLm-fjfmqR/pN.K,H P %ӇDyi͙~/UB1i0-"c  vЙT?\uͮ@ |B`,N Eu|hyZ=Ԙ)h\E2I|T6-N g[ _T]]mXgy{s4nM*uWW3m"q'gϑK0Y_\/gLI7"uS!9SqCh~XULaC MZZWt ru2̌Tm~2KNOyୃjTHgo9g ִv^`ċ/ꅈ.|fw­ e%#iH$L 6rc(k.gqI>^)^`FDcS:Sо$c [t QY;L0< yUߺ]OFVo4,Hӕ$\t!v1 t$e\Zl=]vCe ҲDX[̞ٸW%H<BڶɐNDjڨ6W}HP8|{Wrc(ڄ;ox-8S9!θ"Z3|ʻͨXW`ya`? ߛں#jք^{Q濺Bsۂ] tr/lU6vXdV*8ѣM&T ߆ :$%}Sxk0kf&.6>xtyt2l0-䣥5ZJt$@1 !nj~z,̜~ɌBe(%ey=>`N= Hr$18˺=/fRvf2a'wCYhoWד M %SLM*1aL/l RHBz0!! c CwDilO-1eST1/ xk/2%Ki0( ZKT?|k<\ͣFffSHoϚOcI@f%:'b۶ԗ;~v6U<4"LYY -i$۫Xƛ603$Wg%/3mŊH0nbFBM!Rw奷ϒhu,=3a- t8仭:`G29pˍo&;|?zAJ,+I}wNM OR ]C+ HvVV rQ)^?Ij@Mq̔;gS*AoYȘVF6<"л!*ng{KrDMYQ305!4x4' s}!}w/zԄ㛇̮]*kr6wrm\ђ,Z9~ѹƔ:1%Kӫ54b CKڮ -@pmKM@ؚSJ玦o&vK> Irqυ>FE5e^uR+D s1gx$u'q ԇNhOV!Wuwlݡ~T*}W6Sl1jR68y[PTG^ZsY*U v6D<4|mV8[FDP@MÏK |,Qoۘ׃[bE[`vXK'&E_i@x6WB}!T xPJݸ+hϳIqK '㋾p)4)ݡCԻyhKY7_6'yմK6 ?ZML6caD -{7 /c#|/JMX*xHEh#M|;,zBSSNaARɾVd}ށ)nڟNV>bG@vjM[l)n=6;BrG/RZT"Y !^H\eW,Ϭxk&yUngk26I IU=X5hhl]X:k)EiiS> w#RN*{`R4Eۦ!-][ % a0pf?$[Yt Scfv%yw`ܫ<7n / &c׿_4Bz‘sM\=niRKhhőjcqH_ŀ[T(zD2ZмCr^2 /z/6^+b|cC(@w]uS6ht&mYA VaNڇA f5.5 yX} &O(DwUTmXM,>2##a#p}[ʱ~#xz^.R L"T` /h9wk):NBI.Ӂ?,S'm[<&/~o|MA{T!%`eԊ9ݱЈ޶&6%4@!DZ3kڪ˿â 'O@͈e[^i}7P;kb:n*{֥iK ,C!~"$ ;Ɯ ?-:Z6mL& boW/@#'"ǶIye3"Do݂ę_S&1le os; u@&[8hZ#f^H`/ּ/=jg^tӅCT48["9Vwj GwÊA4'%^x4%R=S< y5ENy ,`nߑ>u#$ Y̤&zK<䉂@. 4WbJaaI(Y֔$|{f)ۺy4K 6lXچ8 c\;*O Sz,Nݏc٦ J8L辢AY|02:]Svg+WLΊ)LaYMM< |ܵ7ބ}9K2V=EZNJ yh#Ĭk3uM1]/u ƶRmC;/~f6uRW2Q 3-nepsm|.TsύXQGK4Ҹc]P$ }#C9}K^q 2Evq`k b|yA{4e&-ןT T*Td6k|w& K\*e07 Ρog䤛ʚ"bJSX)ľ˂g1oKu:7H8ꏾ6[ ANo.Ƚ|CZ#õ5WR~'9GݴoNqkH^V0* ֯nUPцl }aP ?uZo>Giv?)1ȫMˉؓZ=b EMNE)յ] \ T0`SNsqzLYh0fMjasz (AJ8HQJ:Cl5Y[PX_ݫb TJ7e43ͅ.Õd/["hTȽ!ɍjΖ.0~ 7(g*Z$ -:Wi &ZJO*{"Y`#&{`X6c32ez3W4W񯤒BԎ`@85KC5gԙ6{ w/(Bnaz}#*@/җ- 8 )a}!KKrxshbPɨ"&~21V΄8I񽇿'7VC 98z jׯP*T%u[ DLAՓNP%kYrHSR*,d[^ Oq]PVښbQja4 G#cCBdP% QպJs*x=c1^SNEx*kAA<+Jž5[oG\oԸvs{ll ]& y$2 6ʐ!j1Oh鲩z>,Q V, 1\MnlG() e!'^I[% s]!rZG<_w`#-tSTLαpA1'zvdYlA[dB jgkM"cgAj7FN?34`5|!lIbK#[ULtaZn6K_^9=lLR ՄƘx}l8Ǿl>MSjN:!Nc[0K=xw0V#2#( .-9GoHatuo}3"R d|f S!sX y=zY0rǨ屁9@j٠XmNް+6FMqqvlF~{ى>VO{v7JS̶!S6[RN[4[/x&khw$|)X=8'=t/uRԓ]mlR}ﰢ:[†෰t8N-Eq;Ua#P] 5O%}PK1"v*1-~P!fj lWzH*R]!+ <#Į\y DTU{?P@ ER/^GkHdeNq9%LĞŸq?xi?|?DRrU}fVF XJuf=%k&ROI0NcJsjpV7 Ѫƥ?`&='( m2o0~9ﶮMciJ t@Dz9IVջqA`_gه6V*Bݙ*̡ oBcfgt̑fD V؅#c6}6Bʄ5?@OgPS<5u0uJ%Ci}FDؖ_X8:g|7@6/p`oRQRݼ $F*fnz.Ih-dɖ[ fCx=\0y-pP>XzBpA  fPχ`C'$c{).M:TG=TcTRH.9i|}ׁ441 @sPTE%Ec]|0Nc.(8AJ%ى:*7×Qݤ{eE>z4ʪtБz1C16:w͇OLL<8twH_.7= S!):ckQRP^"ŧ}Gd61ba1^Sb-utn[-P2Ӵ\}Ti'ĬԥoNMZo%qpR>&ߏae6|꣸uTMAk"؊x̧,Mi97Sbhf^EnϙWxһ#vkRٱ 6IŎɕoA"t^& JQz+mR_Pb2݈RH]G<|f5&`@c <Q6s^ÀPr4oHjC4>y8q\q8;\i7 .\!6̵I=#/nʈr٢\s.7 LL΄X≍OqueԉX#0^W۶]KÅD,ۧ;+[d* !x#s)SޟD$6ee/Z`I$#kSƠi E&ՋU)c 5t$SxmQ5:bJZ넍CŔ}mb!S$t[Jsk!jB[CU,g7_O29U M5| X{$T}3{SUC3yT@g Yh>>!T `AOB@_Oe!7 z]/O3uj(;ԦhYA-6aרܖ4p)F,5p# Vƿ^+DdD򻍪c|Qv# Eed ƂC/LD'Ȣo2~{zzvEpֱ6+ݑjy3 =16ot ,wy!UC]`nb8V9TYd [S ^b$%lXgi2ku:4/ܮЊNrC k@3u! !rBļ'x5O~)sJzXe•mGvG~0`V8(0lTud[冪A:BĢT"dD Dg~؜6TONSzc:"&G,Z -X 1;(vC~bIטtNL;@~ B#- |bXzi]hi;[Pdryb8F 'k&f`}*2*5/{Zuн[X]nVT!_U^L%= R0YtΨ>1hSZ28Hs˸.00]_;-U$Mcf8bzA0aOj^%x\3+Hӄ@r5~+.%!*rGeɇ`1rNhslA`s $싮jC6nTeyc#?:`6Q>r @^ROa~oh(5zf0::Ԣjc҆˳ی9%^1CQ:!4cg@p#Q>hbUA"# jK Q}E-ufzQ=qvjA.fTH?Vز§p-$泠|[|IۦojN$Z!8x!0|qOžysTʨ ׄ #`Tōzc({~T˼G0o!yuP65GL:da6 GtLYq;p TE}:+ x[^i=H!߶l`HmO+GkЖgs:%47hd% l,nZq aݖc:yzW|A\xʝJ}B, :\,PZeQ3UrՁtYxSR;Rs#WO߱K57cTqd![x8&xסUѐfOVhay^U]6=OWByQ4Mh֍4lx2\vɵ${T`A#, i\`]xmz U_Ll;]nB6u7ߨkG WhoS X,!)o R#c0jbg9HSҘr}޾c5\xV4NknClGɳLH9D6>؍ a0وW.{wU Ӵ3PO]i*7SN5pc@L4Iȵd%D=٢aEV |o dEwSPfHRVhZ!GA?1K|݉'%Ysβ  b(Q9@ҫ x]'5 MEyZݭ?UmB73l( ,2ہHPw)SI'Z2&VhyWkV@wtE R?0x05i7_%֫yg: Ήq\'+.Ѓ/rw ({$ܵoelhRf"U `鎄61o㴞V?!lAu .ͯ`g=&sR*=LyԳrmil`d0Va*,RdцX/q#*hnz\>$MCblKةEX+ ~\,a -jP q)=亃'&w}KMp t ^h416;jX>/>E#n mK䦅op4`kESrޥ]oFe^>iԂ[s3FBrяdk5W\.eǔRw/eh6[6>"UQ؆#JC6hqn'G[G~ i9Rfzj% ]G/GN@T6ĢƨkY`鼑 el/g_ ]mTQ+9>"z8;v6ĹZ[m/C;%NO78OOb؂ND|$͚jN!`Uݷ3wb){Jd c[kjaXh:.vvO5A9ы J49R$ QZ1u)rx]+1dCYx7z@L} oȓo.8UpCn܍W,bR)cnO]Coxͧdg9O"t8Zᝋ а5ոg>8udZ|Q^!n&W_i \!i@yƒda]IE`i>}wjf,=U`?7pH0_-mek]h',8?oT9<պ_06# L7rSY+CKf=Psw+Lދ!ح(Tא$K2|vybbitM858Π,O4x 8PݨfP`ό2  H%R{pS^|4% 1pWhsګ|lj۵!d8$q2S\Mqv~z<|w;EDH4?كSuPq/ !A$g](0^~[oe m8sB#Rz ּ9]w=1.TGo"P&\ǟ=8@ 2^8e\w]K"(X{v1~Od|Iv cN`ƚőr#+ #G 3ARuGX^W(e?ڀ I[v\Z.Ϝ}`n`+]%O 08jFeauY 1q`š|͸|PgC*7綦J͙ jkWNbLpC cZʅ.lgx_Q:Pt.hL bhVoў~KM{@ؙ޹/{G剭9A17-ZD }Y&SplY2NxcBU8-Jrdyqg=SX%)W! ~vq~[C}T*f_vz@C) #8>kS,|K} - )Οɶ üvsbR'l E]"RsҢ–^׿s|#X~\Kμ]ZФaVӅ>QG-s 忯I1tf sj8S hۥ%RC|Ca;3C"?h ?eawE۷ 2D$Q^Ym ؏\5t83#lny)gѐSu!F04-E+ zDpc΀|ۨMcA`2WqT3~12ME걓"Hk,P r1d瘸Fx(#{ֳg:Hhv OPOz|\8xæ(Tzu F^xkәQF=Mu?ңS#b=nMМ7l2$sͣz*I8 c/S{aIfg\ǑC6=!yTaET+˭r{t$@<;' 2cH\NT;ɶ H 끔/4Xo:4]],0IwQ@">:ݬroaoDe6 ĕ]BQ ֩p )aZW>[{:(H|>5Gp (bHh:`3CRqFܥJY _0gH -P <)&iq{9>Jg)9,rMnݶZ]`\xL5a 7YO},Q"PT}]>,Omoʷ( VYp[^$`8asхYB1%cj+9 3pR̉^<Џ-F rqWCmbJo~y!ȤM BH9ɿ-`eKשJβckQ&[N:~L hJ֓i6: h f8[G\lfgrܝ EftZ&v8E_I[Re,'c36t*}zvjhU-g~ٽlx0#Jc6)=4.oHW'L65o"mHqͫ~CDmzoBc? >Tgv3И()I,ڕEgݏ$5cUdCtVmXd+XE}zWx<G(VuPv:hB뚫^iӵf+zY!ē9Ft0!g҈ƿv Ԓz)%.ޤ#X1OxQ=S\o:xDhE䉧/&.ql%O2v5V*wש갷i =y=5yy䛑R=$ 2Y*N :3!5|09~E^K:2LFmI^uPo{{!6Lǻ7nȮed>5IqJ,QS(Q!G^{3^N 9K_~13]]tg-}C%lWeu0Gx>t+ϡI409T 3J=5i቎m%N W >8݆I) Sʵ{,% j{ `sk.J#gTTUٌ {_w៓=Lr.FرB*Eh0zyTLB{In^$h6: ~-`C0Ǧd0W g ܟξ2F*-ҏAckٻeRPQ~x&/޿0Y/AF %`p05umKݴ-;{Hkrv>j W|hVnE9o=>ʊye/}iZoy1;ŋi l/ Rw?E$.uH?t AXR;v1 HGc #|߳cm6xßmTB[eRi`|hĄbEZ!V&! O-qCOWUٻ.;h+lYԂW%614;φD!.ъX/3?Q-^lI>*bϲ]\tM!7Ho'~'t<ơ> p2k L:dbbS]%oHADI { ,]p(@~薯-EPEpI5Kp tq2 PYT;3D =1儩YuCtFߞKuztw,kσ Acs:HҺnƓg(Za"iLD 7y\袩 )gd-!U𤦃G*/SbIcg';Ӭ d?P+<]qSp2zusSe265b^z#M L#++Asmqw,?Jdn%Pl㩞ݗ ]tۂn}.7'%Yx`,ÐOPٛ T>Ob[ڥ8=++Š: )rb2Ö[ owYHaD!y$G=1: nA2-.<ے3S]ⳣ=4{'^"pMkv}2&f΋Fjx16wɳ@3hc'6iWÂka>j"GE)v72Û_US$U&WL |_MVтJC^ܓް)\3C!CHY,4+&J.df;ntb?י ⣱N <iRjsJQ3y f"9X8=& 4L/rJQ-S!lY,@eRՐƆ34dU"8X-!0k֩n1*AX 㺑DmxW*(\'nX |)W0N=v.PjNҠ:?ubV @} b%,( tU,+Vdl7;@Az PRZ1@tA=f-?9Eey+0,xr*n/hn`юݫ7']ZmѲ,crMr\11'4# ڷ^cgYfk7NZ }a8'O*"o1~Sh3CFG̺7%@vُI9bP$/\ J8R=L1~t6vD\U{%?U WYP2t1ŘMOBHIހݜ8.`VԆ +*0  Ww*vO:tHC梒9(ٞ8jq75Җ8m3T3 }ـ*Rʈ_KW4iEh0IȤUa $s?"AKnBeӺ`ۮ~wg!e7`&Oی].P4tu< ᶵ)'↼vG4GD+!6# \zlQ^&hd4Z4lo'_,1H?KR&)fF-KHoT-QVl~sf|_H|w׈_Zq{92'wBTvɈ°~&nTpUN*Gm9J..$S=d-,KU$G-,Si ,of7.0'JOLRm5>z-$sty૶I ,uۢM#h +#\aj &j'"ɬGpo~M:w4#3o9hSG"p<,R P֑sɅ79Up}ԷzۨSY&lG8X=bp^!QkuO2B bZ0Kgq"*3+^yZT.uRuEzi [eA0r"l0?!R'U=`B/14xXK1S'DWVÞ|ΚhkXX[SMꖣ='#exfݟn 'Ǜq tWB9. xzbҥ_d`Zq#ʠp#tPRQ[87xr^x=q]@iZ/ [|;g2bx3R;WZVyQ0>_젣VV4P,.:vĬ4\ljSmpn l{^=]u" KY㚆TWSUF&<%ӿ(=VobPu"2y_"^/si)%)Cଆfnde5i|ZČ#^#Kud 64dl*. &KKB.DzXi|ju&RM hnI/yqG-0{[LXV3[+d*NYЏ͠g}uūbԋ^m0$c |&rJHE\J U٭MĦ]KE (N܏Hk4k2,$NKG VZTd6K(-%K @Ҍ 1X1j-gc|cD33pu2^3ͣ.;?9@J߹Ah>B\*x#k,*czXTE)0:5KbZ*t Q BPVY/zay?(Pk0&X(T*t,X_DJyY"P($ t{Qُe{\ "i/&Ml~zfҢ]=$6#U+!_pdBIo*5/Fmͦ#KuϹU~vܱs/eUp'M8A Y?{ d*/Sflp~6tt8n CaOhhSjԕVwɘVe{4Ubc@Ɍ1zOF CMs0qj;H@Gq[syƞ>ܬ3/.{z=֜|TFL7$ɾfnLERoCgg)I+g7~̎-H^C>oͣƚ8$+1^C/R D=\\nb~]g~a3菊1dl1  Rڐ_xKtn egwBDV'Kϭ)ӹ VۈsjRQHOآ//yƀZ{u?}P@:8>2/8ĚPZy^+'L‡=N 4KªB PmCjxjǰgq(fɒizF?sfk x,b*Aj Мdao܋f1!fao_=;F]EΔ^y׷/wXwݤ9ʔ:>OKaޝcsʉ9_$Gedc+jY'eR:mouȅcd#qtdd8 hhO0L!D9CYW}"I^uc.'a޾yŨin^p G;oYݽOoBL2'=ő#]щ7v"B䶦ZF~LD?'Nrxv#ٴӌ03qj/[[=i/.؁4~ȉH嘃csa8$o /"R8o~ YCYfF #,<$EGI/N`벼?pL%l)T^soچ߅qyWc,]%C/&t =}Nqqc䑯@ENLJ9H*ocE:2V|m 쬕e\,mұ ]DATJ/d:nu#&F'<Kog;p"G> R),cb`T ]{2'|րΊG07][SSzs5& > T2gJGl\x+;SB`f>!yJtgi.5ȟB07kG\&Fϲ ͒Gx9Qplt[)k^XS5y3/vcZJ,[HP@BDz0Ļ6!^ [3>ɺV"^kWj[yCW55ʢ}EJ[lXõ [c\yg>3;,m "wfzmm4(` tiW2dalWî9n_3yÞp< nJb|ɺ:"T'LFR.|7rE5g .`@QA{ӥqeAj(4#dԏ~D"+8AI.s͔##5Ϩ. G'IF @O}(Sm8?TH uU9">ՠ tdR0DF컕v$~rB T~p@$jg:k8S0b#d%E1b¼SA.x{r)#HA;%'ޚ5e&y:d"kh!?~ωIZiC՗!l ȿF ݖR &敩Ur_U6 H^(Ÿ`Rn(aN\nճaw0el1!h٪H/Tއ8>ntt,3 }@1o#\l=u2S r>1$wʵeV.mEčZbݠ~ FtUS{&!|th'J[ho$r^N𲀠-G.go'#udc}n_Io)>jOamy՘ o5d"[nRjw @ ȶjs3j8:KQ 7 $wHazlyinoZ2|'_z ׎ $_\7l -KV k1Dx!!i׵ jmd ^9fmv[*|pH:ˣoݭa L:rakޠ;ڶ4G+ƹUS,s?^2wb:#DvG!dݾ@ӡ_|G,g<{y#u1ݷ#^ ]ɽm@ivcF/0/Ĭm,HOb2y]*wdq]M:^DM?8NuW7MfPBȬ(ķ+ rJ_ -@:n4.5Q5.|GkG$  Cw)G ?o^-Ə\]J+7/- 7=˔@lp#?r ɖr m3~F(lGU€$5?*Dz?Ȏ7-mWP>ç[#8ƿsqz ~u-{pq[.Q sc,,G3Ry7J4Q OCE eV폙PףWUGF HqJvB~#ԙmA[M]"*C\sQ-Ðŗm3`1,4'{w'ؓg͛W]dB~F}O b9C!*$3&b>pN>nԣa~p8L($+Ӣv=~J*;Vx|G d?ɫ+d`evXMY& h|㧛6xY9K ǂIuc7"4 }-Atg8_\t>+abF4BM:B't,4 ?Ҟ\]*EUx lyD5s]= ^bkX=2";.0s鱼0˾ޫA\ly=. 9a;ҳ&3LD*CI2tu8,B v<5[-uǫnr3&b&jWjHNMs74i4U(@Jf mߜLوg#Q^KIB{RVc^ tM@)@݁KOX Z{.18dҰ|T)Y1MDQT|wk7wNRiư~8U)T$Q8pbx%jU: *IsL 0t,ΎՌl)l`j|/Pڱ3H b][Sϟ:,Uв4>EtTeϔ5u{{ʐsYh\DfF+e. T~RzfR|!\=\w_fax>!=F{XB~cPksPbj-7􃍻Bnj.AضPmDG邇$D+)ҜKq?i7b<,Yx0xdabe|W1Œkhѻܼ4"i6+QOmpe/'X7vI:I˝ O{0KfGT.{Q["@W<[{"zj<ˑa1DT3V݇)='x^$ pNL"U-‘c[Y[NzbRay a1}Cr:¡:RM:]]Ǽw=7]KE_j~1G9dvU5iՍҭFGlFDRꅝ:5Cw*@81a`Z ^A IKh YYAGk09rxWJce \;~?%-rp_ fcV@Ra5Q-eGdC}<'5|5_%ObyQs!e7MjF(Vt [d91lWtB$nvL9+ОLO &}-M!yٜuImJ"QY =6P<OYFB H >l2vfM|>H09rPd{CF8٩1z?xǝ%Ǜ]DrIPpHP>~҇?+hi;]*" II^7 _rDW:;4MX1=ޭ ~""q-ZN ?12GV.I/:?2Nݜ~CYFQ:bӘ3YST(Z_a#ιz<[wu hv }j,+}NMOU;x4P`1gUrP,ZUnTk$~, 4gI?]@=|MmzUf3Aj8"hZiW(*SPWTa =rq#., MyPoJ^u׶6[~iبoj}1,XĊ?v!"vʈsӛBbrgDQDŽX*"T;/6*-ebJEp+лq񙲄j<oXJ~ 8ů`e4**i$ CPr;gp+$& q!ISM] tse^Embr_^ 嶟d~ 3f$,({+A]pI:L`?=yޜ49HMRANE}4_ ӹtR.];a= ѵ!< G>Ф%F3GeT6) &nu>c+C ̇ރJ@oĜNj؍N9=͢YXKvm4cT*Pt';a*]>(JSFZ%`{.*6cC)scv'@+7hZ} +ycKpZLeW?.I{mnɋ/Sr˖{r`q!mH9H2K/YwEfb',:xRvנa@ O^&!Hb=ߌY.$vX "8j\MRS`z aZΑcW<ΰ7 )'^M_._hP{!}oP%naL\@紌+92_ KL#8E׋)JJ RbErpcvs|]S"æ@zfd#љE^CB;f.8w'ymyvD $j О`9 Rm)!MfL(4T_#IgbgXIIrBC@R~t%L)c]N\"qo yrniʠgHṆJ̆)4}S+aRy2?1ݧ8پ >+lƲ7KG Ŗ߸J RcApARd`]9N\n=KMS.j?5Bm fIʭ!| ƚ@32j42*4! )(0v/*Yi&Ms­U%G2MB$Xi8TZ^:(yZ˸&wr}_Ϊgx׽aJB^y=wC@*ZE)cG뇤F zQY_rU俗+3 2AȧζT }ˌpgR[5ڈ ͘m@c`G;kI(lOn.65ʋ\GCu=9kGRq0cwP֥\!p"&t :x4G?2G{D"؁9zt K, xu%dEs=dI;IR 0 L0[r[ Qf71V2k[& Ey2N+P-7C=DJP,Ay4…N1;DsHUfٶ1)qP$ɝ f:Pƺq;7i&5oHV:1{щ(HԏܚX+<ÐԘE*)oaAUa '|١`Rrja[{2KM;d4g6Ld͠$ cL,60y`0òR6z/.h`Ҵb7:i: ÏMF`|Yxԩo~jt/m[$H\\Mes(ԒLAF9.laVˑ 2?`Liy&苀;cbdji;۶ qp{3?X*mܶt g6LiΌZ"ظbLi ZXRN 2GT@}h*-fbppkƃC-qՔAz1UNo>| (r  a!u/߆)w'Ph\ޜx8>݆b|Ւg,X"w*UZ۹MBͩ(,(G3 <_KK~W}:Ez8y_͓j.g@> 547>Vc~bxEc}*u\kezrQdY%]C*i^ͷ16٫/L-–'0]~[T$M?UUlA4zxO"e(cQcZJ P݊b{6TʈYLݲ'%ںIXzo <}KekK,sm3׽~c7C16 Uo.51sC o[  f@{*9k3h´$ǰ7l2|ԥT'i0lřa e@KN Ԋ~]e s?V-jzCY8{cZ1y[K2-c!H5pH'#_U êE/@xdxpGD ֩eT~_h;CjE+^ae./Iً!`.D0EDAEG5sDZԊ:ZEvB 51?Z,tϒ#ޯ'حcjPVzg13v)`j0\_n{)y'"!ġt/Jq)6Bl?m0,[ɑSx*}-XIxЕzn~+^gP^Ōup8^M,Dh=MuuJ,PJ:܅btnϞPPGVoҫZkMaXehY72Ffi;'"9t \EȂㄤo_|p%"B45fRT<.p C96Ͽ&;>?t2p ?͔ }IaVy pRQc֮nԈϖԨhc- 3T~Am>yMhx؈C88Ę]VC2ضnT\ Bn \-bcQu1eG L4~U7|t֒훾0ʜJ}!;Dx<,Ǹ5%$G'(tB,?vz3sf3à:NnzF  j2cKr6m"R&!x'ct0[2 Z8aella)pG.:tƫw N Io.k}/FeW!i{I30Nْ" NfX^y -w}j-"( _`Pą2OHN9'0K7xs;^^qDp/~mf碄y߀yVltԆYB #fM}lgf5}ë<Ä"DDZGl=x9f"^/$dCy0nР|ER3,qJe1YgThlz{ lą Q)"i\I_JN+aɁ;{;wb#I*x.VdO_&Rʆp7b;=='Ǻfb*H5QqVjuB1g +r98X> 0td;&ʽY^ h95=[ Z^9㱻縞5M`1K."DV/XψIky^U9#D\öؕЯ1ҷjacBKXR̮- ࡽpǓM‘p)vaQ:AoO 1*?y,y:_?UgP/T>'s!pN%&m;J qlĻZO|D"62f0$ņE_2KxIA@ twOdRh\ uXL4(7$1j0.?|3-iămuM t.~!ˆV|tS{_連_ft}YN&TEE(c.!)_/'uQveUy"_RP1|ˏ9ĢnQIPV0.St6ű]7@DX%qoZh/P**uн-CA@7 Vjz:17$0^YRƙmތwƔvxjlR8㺩")Y InA&;G,7%]_i7 V~S{xZЮa$SWeP+.euDhFa7>`VLȭqN`y"Z(lW(/Gqzo$/EJDT@r(Rb;o*J8Q3ψW&^9 j֢Fx]^ː'a%rhwȻ?w-lAYTu.(7(iM#Jk/ Hd F-I'ώA"=ޖh^J)FnyV 7+[?αTtH6O ƒV"0.K)vKr~;߻nRk?a]0CߝGQ: wjޤG^);{9T o\}xZG%7}W;Vs$NQXS׸(1N/^IZcq))/wc 9bvhrC(UG#glY~9\'Cg/r*s<",t*ӖPj(T)hY V ek0-y!EQ`G!b~0IS1sT(vNQ~ײ髖V %+Oœ\ ~W?eIX>X􄸠k C(Ok{r9S[Ja`Ζ_ZW߿&fwu\ET@ Wv[Y6CnNA\Nr׀h~hp!n{ߑAe\`R*gebwdwuXEԇ|oF?y=9+NR|=fǾRe#DC2pk0'MRдIR0\CZ^QI,OR@lv3ġ0rs6`PwrFv:>d8(jtÇ}}Pr]Ȥ-+2QPWW uoxͦZbyj纖}ϱP ôa #8j+p1oԝVL-P Y ǟBeLTb?O-AkU "$$`-כE0лI<#m%%Q}}+l/ЪIo:2b'h?@쟮N[?"?rѐ;\] 1,y31JV9I}tY%q6\{E>=*}LlyEU0q, -< O S{ű!wM.WǢ 1xN9B ܻEN|_w$+e*p42GOu\ny9z20V8]E=@j |ؚ汋5@L֥v7  n ǀԿֻTUS]P ë'M_)qAAZt*@90݄vB9Uy4RTE)oԑWW!HZO>nk^xi$IQ "f#XC ^*AkfVh#G/JG!n*G}6oCةp)yO|4rm!Xm2&ʪ*vp(7uY7_j|q~jzbѤ=>1[Z6Hku K矱HT.U^k'{iNM#bDjDVC|b+M)Y)ݕH12ٓY B1vF0lģ} &`/TbaO<Û7{*'wr;n 2Nw68\o$oRMX]dQnysQ @/րLwg"~#DorNJ )܌2 tAv@i!O"f#2Y3; wt"{xm2E'}Y@+Y jv@/EJ)d۸]*zz, "6Cqᩴ/~Y೵5o/chI};+]bu*i"5 :xOzsc o4%:jSpf c{ S7Ƣ6@G̏O.o!U2'|2_q tNߺ@4ˀBN_GH^4GC/d{<ӌܦ)ݎ>#> 1 Ը buIuamX{]Ȑ[@\ &Ueo2־sUyeFz?=P.._niܻ~en 6= %?u֓ Y$ $)_黜8^vW'sQl0} FMXKKBgQ8輅H$,Ԗ ф<~VJG}#BXQUI~6PZwc=]GL /0\w]-'D'm/`*0dh_>!!2֮,Ktm+h3*Fij9DV^<~3{|wR{VŜUUA_ghT&|]h%P4άزen u'1@zꌎ-. D~.&=m>\D2`& 9E&lwR~ UC3YD2Pk[WeoUՐX᝽n<+ޅXf8!D9l WnR_ 2ԄArJ?qf.E_RWWf; &\$&6q 8L/Oǜ}wkNM24qPme+LB^NlSaP F,鉢ƨxsBx+gJ|@˖FL]5QS3;<{q^g}ڔC*A;5ںE@0&59DVx7!-O\#pZD+/ZH7+U;|D2j-QwYࡑL@tnؘi(v$ %V|v6|&9e;Iqj# k}ȇ MD>ɑ&, R Rg{m,qt@đԝUq16jI%*Ye)a\p:xY,K&,bNbV Îh3P)a^S*. ztOt.d~ ,D=rO)^XDg8]!?zI`FFi2S^h&BA#jƖ:(Z9E Y g̘~w\LD _`@B3w͡81#t;G)D']]="G|q᭎ʔsDQc 5?^h1Z.1yO _A. Vk ڋm?CS| \%J0EW<5^meJa F4F]9f?l: *—*Ar?!6}24;( }oYKFV'f`/1b5bhan7{C-]lv ݰșSǫ{DOD';KJV4F#QYY¦Sޕ9LP/pZe}dqy(YLGb-PG&&pj\?SR\Btfƅ4vD`H-fݻe8]}"x<;ZƟEҧT@.IcyG/C א7o#dWc/#CUKB 2ԥt$u10\)YWhGMshHa„ehf+yFlR>m`V1iw_ ,+\Tu cصY\,pm0:h f#+woa \ mβ~ Pg(k]Qz!O Vp^~3^Pu-CYD3QUy?@JVB1'h֟\z S FNKVBl+6Ə~G@6s/ӬF5ȲqK^/LAү 9E ڮu#-G@x@QnS3~k nshw>Ih{q;-Sx/-qȑ_2cjwoF]bxiƂ{"0"{V9!ʐmBxZ,yg8 ]% aF,=n z urE)s%lXJPZC5 thkx H$لׯMMv*#AÝEI! }U%,RQA][Z,RL؅Ħ6m}_tD>Ym7x\/G5_ dTȜTp-Y,}W*(MX>U(_bB:k[('|HZKq8mp>@~D&i(V&J#i]x`MB06C.݇']µ;NY[Ay` @4/>+ 5G!!"WKok\N[FGwT2,KXU Lg5n8GzϏ6O]GR#G;d uQF7T}8uP=+rtITby6 /$oᏋTTu#_A:#/\&a0,A;#P<;;&\pER]A+wi{:0(y>`f*΁kG&!01!T:wIUT&B #@H_U0avBIWШvH iփӾA?8˯H*7ɪlnǨT7c(mxӗs6:nDHO9p}. x9d2Ab ~ SBkat<ө%Qm7V1+Qm WJY fR[h晴RnM)?48[&nqG[*,Keߠ(ziFz_}jJfQ 3(S0% ldc5 wtġ2T5K8˫I/< '9LA8aay! P~<䄏z,Ta]DݝO>4A03̞ITݖe8P2..Rʟ+!* ˜* 1!2|AÑ~&*vl.9A? O jw;Irq; D(I4&dB~"kɸ]%$vΖ'E'k~65r.FְNdk}hs\Y5O֜Gq+9@&+1tr;6DLwAk8pP“IgWP1cZDEmɺ1#LdUp&ngp/c^髪O7|J Q f^QͪG^L?<_ 9Nqߟ7BsԁCK/$+RQu ?o%%h2>i,,UVff~~慗hFc*Ȏ"]G?H;UEbR}[H e搲S=ʢ8ʒ˧ɴKs.0%dk`boɈh4'1KM0A´7D Ks+;Buȭ&(>.N\t2Ln3Q<$MnF%M5&}gpŝUŠa­`<JX+9vz ;sح`H<4;% D-yTP ccP\W&楣L6/THEH *n ~hr#IVɻO̙Xkٺ3;mЮoGaݙFƙݍUnʣ8县/yԏO❎߈B л>Vpg5%ڌRz\jBt]Lťr+B(;_թ]W}Ȏo-wE;@¨F=}6Y01^QAnMϡ{jH#-fgc^V(dAAe3& ʩP ,d?Sf:@'th0w2#7ؖ,EM'ҩ14rV !k{c/f]';ONQDPz W JV4ZnJvQ'Vp"V`GRbL\rp$A@^Rs\fָ@]ݨKpzXF&{"c5Ŗ|7SS^ZF$?M-IcԌ*c_21C**Lƹg?r\q;nJntq?W2-ȿZa T>6 6'YjЂ2. p#3y`0"MI;ꁁl Ҧ95x1P2!*4gz{z`Ϻf-B[+K+A6{aGJ7е\;܃D&kK1𕰑vgvÐ3_kB i̷n*uqv1QTG=DE줅Fm{CLA^`gR{żVոmDQ%D@JCS_V̲#a섙{!,IW'>v4g`B$7]8`ӪfwCqBo]j-|- &PJ z3F|"Ѭd["WAreA3ÐFYG;7 30 3BG#x8( $ \S/*cirR2; b0liK3Bwj3Qv:Y?X{#:3綼2C0P 4alYh;X0IKW:ig5q۸ *p-z8 } =-m>=fUkMn#UeMȡROt>wHvwpgְj}wr^=f1Ew݃ҷ$9XĂ4ٝl  k8 7I7=tSqovl(uΦ&Ɵ؇c`RwNV" .y*?vZiq"'Fl ia|5bxUk@fRVgi{ˌݫ[ 7rTۤtvCD^I880 &Ыјl%ީx5M[$lv͊v:'A;hz!_ IOS'u Z=}+w0ȦH, lsܘh.K=ZnČhEmV| uPM<#c-'MsҚWO]ٛO$cIPootk}Θ`\è4TLbqMO]h\9=XIfl։/Ib"c|l\0%LTZ) ?IQ=tGl :s#ߏ9&YҲRF1?H_0τhtL@B?5w)!<,b c$SAB5Gz{!J:3`8g缟0Nn!KL_X`E^k@ȜK&gɯ1[ GqԈeՂ;H'=6<;0Y7]֙"n6Rk%IPҹ SÉ'c-jgKLumD5(uy<"R?8Vq^h< T 'Kd! %ШB_570 tH2s_SA,@@UPd)33,zܓ!KZ3Nh7hww؞qCQ0J ! ~#|;s%Ebr.֤| gG3Qesw07s0ɤӅodzxG)S]ʶt}E8%\'J`1GͪONGޮ6rff;I)In~PYצVMA茫7h pLG. /s`0I+#`m:cD42e0knrQ1Դz?SPCz!! /z`/Z=&Xd\8.dV݈SScQu~+("үalûύK.ፘ"D\h%2~{6pM `H%dZ)ƤT!>|$X`*%''1Ez1TgC;Jw M&b: g)6Odx7<9?F>(vv74%mkqd4|af'XziRHBFG}xگ0-4+o̊2U9Rec.>Ip /1_J@sLNW/[t}mn* (go905}W]Ʋ~]٤ka>_wV:0pU+@Vi1ٓ q@"h:o[VDz'oX)^ܩ?f.9Fql/6}p=I SKޞw%SNe~z%DKV׻G՟# =4ctQJ:BjR[x[e7ԾxctycZ~-)^ǫv]yF{LY Н(Fx`%"k3q\PB)y hVYg~;K.\G3],ڀPwSMlR erdp[ uC@@ao,)Z >?.gbgdH 5n~Pp>1kb_9ITa.R{i,/6T>KPx0w?M-P9 hB RQfIR@s\h kuPzoAn0Ю5+\'''ha)s,j%5;7){XaXV~! 5JhQ Θ(->(el;Ԓ } ZQ&3!V&e[hkx]oK[ *!6PJ:feVXʼFX?.`;n"R\-]hu#ܡS}8N&N `zySݐf^V<.rӹ"=&[i50$Uba(x M@CۨƢ d҉0 Gcyb|WdҜ4t+C d+Uxٰ$"R|dy䮢MnO9)qkx^a$3` | MrX`u1^2"dYɛl)CFݡDa :54[}SJ`li ӑ|d H(aƵ7b>4t[1 xLN :]peC<.ŒtWL#EJ4,hw'|ń0 :^|]Y밌?#2= Ԙ < R7М_w_ҌE#ۜK>sCON4C?Oݭsu(6JZH'n2ZW!JY ͔ZvM?D2Ό)4,0Na*nJvLBW3>pR~E&3>WC\GzlAoӸшf ;o9 [fmAxeJ¾w˅X((K,DiH72i9j*ѕri. 63p@w?&q6]Ud:xk6Eȃmhdg-DX0: ?|#q:Tpۿ=)-p>:9eKv:R'r|]%DHIyX89{ծ\\V RR`" QAxd=G5IYtdYZk{c[j]*(AɮFmK2z, c4 И}QσP~iI1w.z QVYQ^_n^+}9뺚D-I|-;կOiD|옑n7 G4G~=KWR=f.dS'ڂP`t :xppGT3,OS ?@:S:klV>喆nG5EsNyd2b KB o"Ϊq#1+L]@CE"6sSQ\uR?~ q}M ɖ0 pN&2pu=(6|#TqGPt sɂ>0N<sϫexywz[1κC,>f%HJ-!?D*+uƈ\D67=)K(< |3by8 m2ͽ] 3AT`$@LJK@Hq.a?4+#B7 U,T_Ȟ 2)HM&({)]҇6{i R;1RVIea ?k,gy7/:r t0VntwͤR5˪"b2E 0EQ*ǭ.;,G gZKkZd AWSB3IRMKҘ4 .CP[粏#ڱ*{?tf, ldITf66 2t'd_oAhh$s');bwW\6t.j/ p U/`?Y{4g?I-ec7i^uq7.Y)gLNw ae0{_tVr'@ ƍ`EazV8`H˽FٴW .L;,f,Ql:* }UUL,S^_9KkE|fMyMF 'zIj<Mn͈9E-JB7x@ =vqb%=[s>u_w{TcVElKS &ŃJ[gϑFsqB,6QӡoDGzzM} yǿ9bx iڧ.^|Gʯ䠋N[oy0iIwK#P_ŀmN2Fno4pTxQ=  MHHDfaowa%dvOo&[[;scAs6lI)1k̿/GW+԰:)-p4)VP ]U侷=ҸIKq1<W\ S1lX>ް./!Ad&6;b>NrpXN&3jq_"UxO RܭK,J4#褐z|2GjMZt=rK2”*`)I(J_= ^*붮ISnӏ*_OS<M$-X6qvonF0*|`W gI#o&FgƲa[@Nuʮ{ѹ”?0QOxgxmԲ}"%+l [쳻4rRЋp]Gq)i((bn5.̤N#<xDJ^NJ Zp6 .j;xx;z1U˭`%.#\ .hnv3X³‡A#qk-]Eɑ^ 8It i7)@]WU#z*jPbJb 'z(/=鵛Iζ6PMqLABtxxWO 륮lUݡsh.~!ކ]עʹ+yv8Vc\ux~*$oQ.6xlIӷX13%Ȼ6̮۳Dּ.߷{>Z4SLkg0Y (˪a3bKK +P|u9ɐZOaY +"2I{hR<6}x1KF?0gUwUoT/x>EWKzJﺉ`:‚ڜ 峨?~I=z A69VC's&~//w X4yS4#W?Yk{7sI;Ƀ^pzS'Y' _/D#E9 t<-vZd¤;9 ܨklAamU>i}%9nn&=\1 iPx2"JMmuu+Z l `f;NԤ IPqrzUyc;vs$6n //Oy#U3jeSYb> lL.fI9?Ǹߏ5If1jf6S5r[! u]wY[xl)_-8#UqG'j%*ȅ+[Şo "ֱsfTԎ Wԝ ;\CGlưPo=;w3HM92c&XGѪP'*t]N)ᥨҟ2zGeMmAIk^xbxjU^Q^t4<']T8 lA} 9)/QpV:߇-vE0y{%E 7\>y׷nN"@|gC T*@cnC4nat%1Qb{4>i2j /xTA#$w=(n]dJ@Mk- 9g0,'~a)I}[⟏.hI;50!1wK)α .pXxQlXl\u0"5lگU MD];7Ku;<^*-)u&%y*}ȉGWGxW5Oݍ95[CU.*=sԽr𤉹#*{*\NCddoq<*;9 F_+Ag5Q4ǣ? L oñd Ew`xϜyP(m,c] 3Rdd?ޟ-ܿٹȱ}EAՌCzsFdF9 77أFӒ r: S3mJmcίd,|#PkUZ~bp$H^R?wNK0 u@Ŝa``>SEEMHD-a4PD`c1d &qT2.El~&eת' &{=pб}n߽ZL:V盶8=;TVA]7gj ʎh Q{֥4׹Lܽ΃t0&R¡97m~b7:ߴ ~;mxC{g+9jg,FܵmPS_vR72K#,Yw翈4595GO\O$we0S+t4 2-;srOQtGz(Xm_|Up~fΜ9fg¹y({$nsAu+iL=#XjZ܄ޛ'j1c=xl M ÀCmڟ'%d[<*7Zmy(rr>$w%)|dȡlCVcCKnѱ{ɸuKq)w J_*犫^i[| u)*$'&Mt2'xI' $X%NC:A*=oǴ}푔@FjRW,bK8Z' @hKY-O7R9B*BʫH/MZ w Qi;ɡ:@R tG&DA2tqLɅIʤaoӣ q+}mB0L3}]T0G$M(qYBJB)h蘳w(dԴ7iy-N+0gxh=LyIS6WR6ca?-be>zjn`eCf׏K-cKWwcShlOg+ yHaߺp]F8@OcPD_;+BL U" la^kߡi9TD9,0"'8[z[,4Bj+FA>D}9-ٙ+ G$o:ԪbYxr^^{fR#)g)/S~wvTP.pp|GUKKH;$dPߜm4J@$%ɩAOdAu~U׏fuT!\쐥n㹑& ֲNk o3e=?Y|};X8ڌ) s'C*}u-,߶eȦ>A#SԿe1Րϩ"\ aZSZS%XKl{DM>&VӜF<տ54D=XEVNu5pغu@r v~C"Fd!OuGy3ӊ *b=Q0E" : q+%^lnUg<'f!zG~vR@Rޢk1#,3qo6͞>T Q`l[`HmEb;!R˴1|UT'7vLگ94|ze܉ąpgUˢr8PlP8TޝiGbˌfimL傭A+[ O݅Xb@MǛ䢜11-?r{'- &PiKd MlH bCQ% el q&wner< -h)/PH^X~Ne )/>*"ePE':ފl X;MOoQP4ECO674(@~A[ɲl/Ts%GxlWdU6:!HTMҐsq?=zG}38ϮckЭ|KeUP\2VL?y%=y7>~|v-d*[HigI]2u {&BJK#: 1pJŤ{I |?âa w!iIaY)4ûh$ h~%5+q?'Ćc ̮@p^>9t> G@j|0e˜1f^5AEԑyl{]QymicNx\Isof(e̛ب0b7+4s>HsIXgW{cGM8_#ClPM =bS4$xPPXRt*9ą H`v"3!xR5 +1X@A"e (1qS8Dm@tmՋ-K1 V YD˧ڕ&_`6hS(U d?soР.K-嚚pM`[p@9[!go~R |L?KNv(/Ǜt{n^(ߊ75]s1lt>>l4 T)Gl?ȡS:‰ਃzw-erT:k3R /$WsSUfgUmx1kMB&ޑrG],p 3^[rV:(j3x[ ܠ@> 6Hl:@M`iMv@~nl^: `*2ԏ1Vnj;ztЦGKoG9҉:P45TptsJ8)Rm<[4YCS A(B1Z%3Igܹ?Z*6ͦ'dᚨ LI7[/%=j])J N=sUwX*^|O~R1乍IznLJd/)Ǻ AU~p~q^=xc'pmN_-,56 eP6 Xg`+q,_&bڻkZ3^cI7JBHWU2!M9V]੐bZaI-*Ѻ>1Rљʗ^'a-:jqa qaZ2HjT5"MaFd_^_夘"ZVCQgiP^1Oٽ9E,qaqe>&r0~'?BFIt5]SbkY֚o^yK89L|el`g+Sdt6.?Hd),//Ϥ3WXاR$e:F 4X&CeDlދ[7"}\goŪrHV`^2iӾ =zveAqϽ#5z4C}f4. ^Rֈ"ٻEߑX,JdyQk65fvaޤmA2kk6.D#/0Yʍ@x3<ܖ!N$6HׅtoϝdcD~Xjo\?0 Rd,!Ն8G$Ie-'9>Λyގe"S\3 [K@re ODLߊ+cRx-ԢC;gz j"ܾr[8MַUz:,eƷIJ|N݇ &mpj2bK .YnkfGS}hi F['IKkuz) `oJGV[ub7 J tT,>|bn鞱I(NPl;ـz5s\ WÀib[,"٭Ǫ$F}Wj=VZj;*/fNTy!WYdjѢi:ʗq?RiWU?&/qzq/hTf2[ W*9?Ð,QuF킏rR6EUFW⅓dC,q%IhK>ݬgڃSk%(ؙnWߪHxkg.fՂ6%#Gs#2ȝ D.[I(g)͑ & A\/JJN#sV[s %.jCl 2EᅌuG160f\ ڋ(.4-_٣ a4T/Wdܨ1PF" -KD&ffXkOVن/k瞷Wm2ڊeHM;z%]$PNEI˟$ ԍTaS֭rsNl"mȫُ(0͢6ֆ[2D_ܢJ̊KKl.wzgR3pb{gQFɪ8u%n (<ĎD7z'KzuB+ufp%(rCW3^iw"VT?^5 b勧 !dKsvr\3DH~ZP;)gR5R"%=jcCԩwn]e'l)rHLQ6"W#.[Dtv<7mNjj՛MRC>h#š|VpkzSVpyf#60!r JY`~ݓ$P,J^wqi#A`Eǚq 2W\)fOn=vݟd~PXiyj.@"X%-h)Ȃ)j~^lS$>a@#Bِ$Bnڶ޷yFVq0$V q˗qjbԇfHe **AIeLLYZ_߂|-~0d3ޞSxOTUϑڒ$6`lI#1t!՗xi@xm,@I7kB td|0E͓~[7+)/Ks<س)kxW01/:9;4vQ| FBp6ؒȼg `zrSps~0vlo9660onT*ؑ=/ӍK֬xp{wPxN {zv[%7)UoewrXJYء`k<]ɘ*9 )C2 u>+=e↩Kq5*dX1@ o|lFd%QLDܿIrw5MW`imޝezNdeS3jhJP{N+S A6GQk.?+ml4ۖ"JĤ@/~+?J\ٵjzkVvYr- | ݯhJb 6*}c0=7Cufh>溗H.$˒Y^fޅ`pV*~<粇M(i:A,FlV^2q1@c+Zh~C9h5{yxmEځu %@]:[OC(ZPXzI[~7:l]qE\,÷y+zJڠ2ɤDADrirNM\4 aL&+G|Kkx%)SWVwbWlUC?,N9Mk wO>1,S<a~?k*٭vBhxCkPt([mnΤڿ@ aWh'~#: Jh`10 E270ƺ3^p]L~ 2? c/hj5h{-hqzTw ^/xhk>aX:;f7L`~L.h5{u?FQ7PCl=Xvzz5夋cȢ |yhQӒ4\GN.2#'[ILl5gW\KpfX?O ;n[5KVoWL'H&zw̫-_d&9QV+.4wut$k+p@^w&3zGZ0m|/2 k4pQ&[ O0-x~2fXlmݺȂ&Zwqx߅=:=WꗧzoHIMnmRA.T]FS{W/UK].zaR<8`b"%4ڀ${D8{+#yဋQwGܻnc,l!o ϗ,g= ꮟ.?¦ uP(e6݁{2 ֖b志RL2"t,qR"Jh+ʹEH8GlH١& 1RsX9k˶;۲DAK~`>ˍux<ۮ61-Wmv?.BfZ>)_KS:㍫]bIWeՈoEn,Z}ꪪQ6#{ \$ߛM1G@6TȆ6r%'Jᘠ#z/B]X"t~~Bc ]egܪ7)C7RW )Z:;╟u޻,X:іۋV3-W9l@_| *B5-<4ؿwJA*xZHFh& =͎>"Tl:Yhٷ&)+o;NEajM]GޓC~iC-u ̨w0f~?x(Lɪ# qSG>FiL%vrZCVzHQHkU1[K!8m{fBqhcL!#؏=Ɠхj }) Ho>/D3Hz٘fm<ܪ,u2|>?+J_\XK8WYZEjfqDDq*IdMn" ﺴr 跭qָTA>72»m6~m?%Oc:R-/(imbcvkQ+\ ٫b&Z(#a/ L*lD.xkRb8 )X3:kD$>cjҿG>IHƉ*┕Tl̩?3UP1tlƫG@+~$`]{G )/GFm݆zVOHwԄb6z3X%e-fEf>TPe?ˍƀpZ .RZ AvʺVw[ ⶉzq63w!Eq ]XF)@5=$`G RSA Sf4N 8mb2r7ix#*,4=daus"oaM6bsCU]X0bKbd{ho cmL;>0g2#13/;V7"'Mw NPM(ot9{o_xBDGjѤwai6-oa<^L C ~}Ŕ2 8(E6-D}{yzƴvnf c9b:)svn5AhCZTneePp!\s 5 j_s>G4<OT C{;\itݍWtUd =cj Hp1'mXJU?Q׳Hmatb4UtIJX/j'5?')[$.q^:߁OA"Xy.64q$2c"lk,VwFǣഄΐ_ o+YjG̓tG\X.PK&jFD>5!ըץC_)€$MXh35:ٌ=v u "94..?+lΎ]2a_vO8*Ĵv4p !am]>hz* 5bVF7͒0Q~ *w3t\F :^ԗ>\t˂՗xwa? bhV LJY Z`U{."Ӧu·5t\e(C CLA57:G7ga{f- g|ZJQޖ̼iY`>DYWpZ:pJ4pU ͙/K + !,AM>wgpF'Rd*ˊ1ю * 8{)zVSǞ\ǎ#az?OD,$4NrqQR.\6" ]FmU %p23QKb]{FE:!:V2wU:FAK@ԙe h94 b9c3ɨgK =լ r3 hS<L 𻸅^OP ̸̏kWH|!OZ~]dXa4CVjuq&00Cݲ\a%ɬ;5[TG# #:{BhN[ 弐\RXK4Rz{aS,Zs-'}s[ϕ},N!B*RguJIvNK,76 :Ω<{xzjBB^m;H"LV*mno7'mKR]G9pGe6 6QUpf3DM9+Txq_Dz!B7-RQؓNFdȠmvΑI~guPSbH].Q|笿t7) `aW2),ʌ…v a#zL%4uv.*x8u^KhSꭨ"€s= VIBfdk(=#ڼbʶV-u\38wO@(Q#$ǥ@i@5<'M?Dװ8,52^_AVLg nn1 *_2blx;[H@WW7mp~Yr(ԁ:I(G]3s5#)}ꔝomޅ'g+AS/穾̚%+o*2d(씆紉> in+)7Zynܦ,)VCW5凨lz+0DHvqZ,]:TNfDLrL+bi2LH:hroݾ[7N|P$1˙ ş9T4\DsU$ uV0CP-HÌ[Į}JxG̪ 6&-`_グC"ŸrJEe;1&șbkQQf^u$78;g Y{i!Nm-{8SLǧS* |-Wj W4;o]:?8V%vT5S_B]iޗ<ͥ($U1pt~ u() +]l ȓࣥ2e6Ν""gRT4VDrAB;c6Ȟs pW}M5gw Q5% ,N&Y96ӟt4VQgz8*:@аr*%.&X1 ȪIζLjG.)FjpThL#EæW ?bY-XqR{ʉq1BʗLKPliCbP-;b.Q  .5:>6mկޙelQQCP:lΠh>a̡S}ܠ Lp6Ar߉EȣƯ4:0 вWߊT/sS$xc"ek}}Up%fm2J6u2i92VX./8$L$r ;Xރ_o=NCG^5{4MlDf!N m+rb?@Q*ւ {՜ 6Z\`Ɖ>t0'YPַnAQe=nwxFq^Z{}އ3ʈ)̅Nޝd?_P*wl4twڐi6j4/W0-߼ͥUw99bjȽ ςll:ͳۓ1HF{o77 ]xAZLK(P Dkm1;Uoݛ句ông75Ȕ# A`ۍ]T&w8+EȕNC\-ط;YJ7شLT|+󶌑sO 9y*Wn+$(C>r :Mˆ,;yu "zd1*lNL#mם\)Κ'⤂RlqTwSӪ]I|rFHhc9*u!e:;\Sf0gw%۞RlPql% .GhkƖW DI>%p$ ']i12?#,sAV iG@zuK+: /xWN WD'XVv }X h[nIaVz~{|n0;"QMv@5[UPB{qJی}W4xbyq|9!.t=#]O 2dK` 0^nkX tD@ '.-89Ϙ+ɷ#[RL赊>^Du&A3yJMoXV*5vT zr5z-.pN ZܒZiZLl=zOu5]Q?^4>o;Px Ͽ Ms?#LHuWGI~A99ď%v[\8P{_35-uooof| _ǨdQ%T;D SYFl附j(gvȥc!;yb[xp!;K.\ql;w׶<1ڕO@܎dUs{kA%QT*i:켎)٢Dmxt|ANn .fArod3x!trЩI_F$)d2˽Iu[Z{z'RX,XΖmP_(I%5e"hcwqN.XAו*y=xdH"ݓFNT(/8Ϥ\Y?/[X04ޅu>L<%L1(=6A:K|Y gpue1$sAp5ajp󾁈.EbL=,&{kDZAN܇/N\4<;<Y_eV$77K_*&y NV;p$ޠUTshz[tHM}u~*p^v؞8Q.Z*ʛm JJ}29-X;P(+y A[gj?!d! O!$ʚZ<'uإ 9/pUfQ0Gc1t4a ]cd}pIRb>ٿoUe]3gUʖD|"}Q:̙."7!=Kj6^4jسYlG_)1=Dƹ>8b_\cx'pQ2mxMG`Q¾у6xpݳur0N.t^(⧪ `߭;{s oTY^c Oc<1 zvk !jVTv .XED]>USҀFoE$)pGqUY?.e0/|@jzHBy-GfԺ-)>-RS;;8x6KFo>X4.QR4b.5: {t|?Tǚrԁj8szϏc@jqFe3yXupj"QDi)ІӂUkUǖ04ZH]sj\l«-Η|za}3:Aߪ{AZ5.#&GŪ$1,s\hI]$1XbS3/nG K`LV<p*=V'v U~GTfjsjri߰iн("xBB0|S:(K`C}l/8bWzw13w/!ih>?ѕ)-UsFA4d\GVX!u[~Ay}ćCMzӮ$z#譕%A h˩dC:*rIY7!!kA{۸ W.@'-jsM.r17¯.@@(>hFWY`1J}îjJT֦bhKpuR?ix.Gۓn 9v k OODG0J?hN͞0d,Xa|:GkykT挶=\`S{RFǡ/6-CFI) h2pxv޶вhŠ\3P$ߦx1/Wm `~105 dA0y۵MCTat5c hN"BZmi< Ảr-䋎B$^_^N³0{汏YłإdTD+=- .ghs3Ԯ(3Ӯ%4E3FE-@2a=Io-Sư$zw<$"> BZ-0ĤGO&QH O|DcirL&3q=Z.|P./}B$/OCx.y37, TpqNhm.9aFS(|y4M< qЕb)85b0;Qj0U\`M򛵼ACtQwf?v- G"jK㘍4T_HQld,́Nȃ։]%f|$$/D=,Ad%ǽu5lf@Da d)T:EuE,@ÃGCˤmOm:z1wsaJ ^$t ݬU1m(UUY i"Q*\K:JRٜGpNg 56~1.)TN /j1@?rǑC;a]. ^\E#M^W`wUjGUC2b{8P#(CLErlL~>.eWZ W5_d8P1H8Gxi9RU|5h4fbdW(IHTiI4&SRt7g,.|q{(wjr|^^3Lb^m&sR+:`nM@X*` @?4%HP뼁X&FR~V^si2_.xCkҫ_/Usb0ᶸeqvzK ߢ0p vlZ@_0%&kG2ئ188 \l 坟HHbZ/JRDNBNU caAJ1`cDCe7Kjh^cD9͵ja}mF4Z̼6Hwfy8!?a/cT@vЅ$-YOZu&#L^5ִĠϾ(!`fۀ #ȝޝ25\K?e\fpscZEh}ա_F9iwG '}%˃fE`7%EY[{s!ehZ`٨ 5ƑDX%~ '%'AYapS~s+=5Btƅi0FO(N|Dd_sgd>j|nPI(he臄Wu_i8A.+掙Iկx^ȭ.ちUpGzQd]d { $zѯ)I=eFOo'8z~]|e73eט e? ,}"gV,CߎD`wQ+W1 a]N] Im %ߜY+~v&SLk#%=|J?󒀮9~r&JCf%-<?T#jǛ}$y:ZcJzy\bP+@לI1LY:<&}ɕN+}{$fhʦ4uؤJ" .  $_)1 GЭy3;0Z a^KZǣg#ل jB-04\E0cQH>m _&Kpq Ɯ Ьv"F:\3GFH$hYU2֋Nb6P+eA;U8F0+ŋ@ 6Iu%moB!daA^Q}(0-}"A<\܀`7#~vRzoxXܧV$G %dTXNAv(߱_( QcR(\:3Fpw17pu*+澇Ͷ/ͤ` $˱_Ek E"PAs5` ʦ[`b8k0i,2-#OA~֧,s˥26 ,O΋n Dp' FA* bP_ɧلNgz!qI6٭0to)o6ͨ Jãl8g:m[)w9_>ٛ K> 8SSvk6 )A2  &3;W" 2O";vͿ\;z]/Ҵa/> ӧ]hf24Fm@\܎:=,Xl;N7Kl$]Vl&rϚ;G S4Ha3l_Rd A㒀ܜq &+/8-s%%&56FM;p<8YcB4>6ͯ:tG*c\\JW=Dq_}eYti7̂ zMU6V=Q 0Fy]+2ѽc]kk1iC;w @=^VI%!3k%!v\\k(1f$cLr΅kPd(_H膏uk,"D N#"8G%)tׯTO8Y[ɻ\3F$1pӎIZ?Ǔ112C}µRkX* A7x$F:.^jvS4L~T[UpJ(Cg04|יm֬%iN &GYE Vt~A> F;<Z1t|8imECpCvJb;mhhs?)i]d@DR=D];Qg9\ȼGy$O&$5NԞ"Њ%!i5X㭫1.n9Ϣ8A'~IkEBZNP2Z%?g%P2$%ͩUQva.,9SDV'1QDpdi@#C#k!Y^¯,f/XMfm!_f%K/% G6k* zMH%#!u (XS'nr!ؗ0p9H&\GKwߔ44/O7OU;TP̀@rt?bx/Ʃ0G˗CSUY"tX6 w2K8T)w6߁g&*;>t UV|#^bE1@zf}3IC8|Ж}R㵍(8)wY]˽:<9/ȝ@/ [{l4RaKdZ~\F$V t yN#NjF].R𠪥ިY(Q`бa1)F`x!QfFlFDp_y:m 0:ξ'ꛪɡK/YІ w5[ĎyH,q٨M 0uӓ#`7c!޵n&&ŏnk@hێܮM~Y9pf6b˱(X="[tEQ?}VlG03>Mw㋌|/Pzӭcl׉~H)=sw*b訚(n`|W>ۢ@+`MPE&^mwqG|7!m J" t\CMwFuSΥgI6U[īCiM3)P:hkݱL'պ|[Xl$nIs Qxy'.TN7[>cCNkvZ#X^؜pSI^VŸ4gTq(dl;z^ln),EiH]|>R~N lBr?,+/ "b?׏sv4oĽ*6pu\XLc}o(5ʁ!tX;⾚褼a t.zp_s=x:YL4s|G Jj9 v[ə'rfg&=?%O% 7"hz:M;(ya2ۄ5Svcq ci)3?a=@Ȁ/i³Ta$(dbVxjcRѨi[DpFNĺQ$/sj}Q>ݍ,K+Ցfdb~ )ʙ?г,oְ/'5 wFxrPiO%cԔS<=:Ǧ Yg2 $PCT՞8GfP̹h tT%'ͫ(@r [Wu؝=,4SO$k@zc/>g+wCϵ%ƚ϶taCަIq=ĺWV\|%C)Dx@!t!8e=upz&. Q(Bn0)?I%BpGDe/$!3U"D[^j1mFP^g=uzֱ&n10Y-btiI _tT+rJ )Sbg"eq_K(_Qt4q5} |QtCq[6Ib701P0T#[cBxaH~9~wtn3Z GB "&j놬x./vAH=$b. FG\Kѭ%'D26: բ@ Rff ݅3(z=Ѭr6Xðj=l~$EsF}w3)-&'pŘ$t+ẃ#V·z⦙+.L>|G[p~oѦ}GV Qyǐ^RفE#?k{b2[Q WzGF$2~oI' !mg=A-hCpjII|*\(t_O$} iʰI4N~,W3:༖͵^c-\!r. I 8bU$8Ԡ1" SXC@;ȤM?2O9gm X?vԀyɡtic?}`e)}Ϻm򉥵abp S&gPB 4Yql};AW%N_ςQ!p .5rc6:ZC7l&qႼ)XLF-H<sdbEX2j;Jѻ7cqg_ lwV:7 Q(mr^^"E- $4C[rk>yx-N!_kݯ*L  E& s Z}蟀_Mo5?o vĔ-OEmWc>~=D67_v^ƕyZq v}1l_Ƶ 2. h(V/F1 #gb̒./Oȯ8s@4n%6x$ͣRIֺϯ Rr/12@aݕ I`CqIH w(saROG|XA\uf%&b3an ˔P}e~7λAKhRRTNA0^pw2BYQ.gDŭKfi}'ת zl젱wdo:/1O!^ٕ֬BIFZL);@l4 + dp4B϶M^y´'I Uж#2׳f=׊-ZΪ}OQ oMkWʄ ŽFD(vk.յ^_#cx+A,;`EPPDKw~ZQ,!{~m/]\dS/+)!״nP ]6&B!;4CVaC7C 7Gxscý7gMbЉ:*uCx@JXN;rn}(IP >'F9(zPFa V!Eb%R%:6([8ՙ%Vm ő͉>4`LuW rFYtW?gs[/$2mJo@ZX7gm=,iZC}Qr(j>_Qu0A2I":xEMuF:1Ļno[6G>즚:IXwtyz/&srqb|7`4OXbD:$!*Pq:Odz1޼ {NxKI<TKݴ؀0wV 57~]D:*,2јGDݟ }emdv C $gJ|K8 gNf.ÀKZ[ѹȋD_|s`a4 [`8Hf:e4}2,pJmÕ2l@Q) rVXhQǕOl*("V&1uQratRFWDl>B'&  @, ^a '|yu/-#Vj28FU;vjw& ZܶnU3pEe /Ϲ|jNq'd4zhLIȰ@O0Zu+{MLX&Z,K[bM| ߾S96AKkqDžGOx|ƌ^f PX$2h Y))|=bƕYâXn`GK@W(w@AaitݨAiƔ= 9NF>gĄ:J5=ZX(J֮cM0{87xK){rA\j\ wؾ){2S#, ч+ј&mYd2Y3!1Ye~ȨVmΚ< f^B]azUAC7$7[:w\U^g%UfaQiAH A }U?M Da a^ |ǃLszح10X^CgpQDZ#-IAk5L; Ķ BZ^ 8iXȻg+D;E-rثol ϑ$< ܟo OYE0ƜoLc }gr4PFpVDx-rs.7cmgY̓P[RLXp0~ |}*ZQ/LBX o58saGt)Rt[ Y&2L6yK=T_,2w?UL= 6͒_<WHQYa&h7fFgw-9TLćQRX7H9N̊қ哻I$V%ziЇp{ einv9इR6D7?{v )/R"Zl-2ȼB2so&Cwn뽾% эr)}0ց}k5rGv-'JwnO5_+=0/pG ^Geb2 b []ͥp;nB}oyyƶt)vO<;R~ajNߋ{m-A'0=޵i'N,5kd$$7Hh#^M~dxkP\%IJ*n/ȜQ<$>nT]A@xz>PӖtR}rjk%r; |{́4M.Z])UR6d>kNu'@Qu4&[v~[U7T#9;5 %Z%A>>GY#yTϡʣ:c gZe_T9Ś4fO1_)H2_ޜ {0Ug3CDlN)jTj~,Po3oҐ>T:Ww]-V Pж1Bc*s0]N(ZyOkMPީnf QJQ!*)(FPqz.vw٠閴/FVժ$i ʛ/v+uZXy@)+@{p2#'q-a {bQ` *0Dxtc~P/wi|}hHfDڃ# aǰ9j:&^hb!rs%WaEk DvJO֘zl? {@;ux / :ybA9'aoTR]>!\+@Ѡ1:?Hi*5-G3Z~xGGAjblJ1%kBaP<+ !2k}?&&>6ZL^aR;=C<8f6,a5M `uD g/z/C428c+v}::,R<Ȍuo5]c.o+HnCuZ_㗹2+r$T6쬚pPDGSq{|-6#S&x,M W[PXɶǼ(1sϽ7Ŋ:VF'kӝ{CykAqZzɽ s7[nKlA`4~RY96tޗ݋}??6U,%r w`!D$z0Cʴnt8p(t kdOݓʲT%hOQ܆ϣ`ώDZc@ߚN$k>$̯]fxJa,RIgko&d3Feɪ^D_W;Fv{wWTU/{fxauj5 )>!;ت_~mK("ϚrL;PYyB!tCOg !yHErZĆ*+%=SIwɉI]ny8t `*4T;)i||PAOתӝ;V ӕ-Mb0P.iA'xUpos|QCd+2jWLJq?ZAꧾi@|$*4!Vg3P]|uqQ  ׏ߣnH'-""*YF",Qyx̴Ŝ0w o*ԧ,ؗG%ة'e}AGyH[dR *Z]ݟO{.yl#ʅs'n&gDR;5= b8OU\S)2 3^ Nswe8Wn!]k}ҨOo\t)&LHqK ;. ? 4]c4cae)",DZGN)Y dAn(lӄ1S0AB";H7o ,CO]iZ{QONqurx ]0Qz2:H'lӐ:u(Hb-[&%(߬G!з]iG"c*'؄lY7[d@##6`>|#[\x6 flK]rSP'T-6Ltb%z:f(]'A0;ԯS :$yp6P}bbmcނR[B]e r\]ƝLTn#V`DM![7\c o4^`Î` }5U[ќ[H!%#AgE9*f$Wk6{o] AMD "|cZER+D/|~zUhSUFzj~=Xc5{bnL~Ǯj0ts*d M Wˆ5LY|v^`}>:ߞ-& U"0EbwR㧸T/ڝ '3L5dnNܿNْ0бN*$HHX!e󳒅<P67=$0GL]mdր`t'/:>:5zKBؑuF&?8.'ϑ|! M,*  P)(l!;Jkz@Ww߸ބځ$b0ê_Qyj5 C߀b[KX1!Pr O@?&\]ںHI,: >vDNoC2 2#H40 |dVO\-2CSG97S`m۬._COb(,l[c7|NPZe)t mYctl3gG$5\ 37Jd|Ɉ\zТ{c^B82 (Z"G "x2 _ALˆZELXO7U!|-! +4"AF䢵,txf0r .aſd ,Zm^h[:)I *iPӶ9&:0וE|*Z]W[}ԕjNG1Z{C !í: kȴvpU3{^jqSL$ZK{W66xbY"^@Ъ](jȫG/mҥ/]{Dt^1FGTZlDn5]/zX'H͈j&VtT~~}wA#xK 'ҌIhǴ1<{mn'8w/ jк̧v돕njefql^#&p7 G_[xBpXN#Ex*5AS V`z#uy"z@g Y^W{bkӚqDg,ȇÚ37aZNPZto&UuY7%7] Z9'A}=-!F+yZner2>Sbo 2^;"_;Td%RQگn\PeqzOQ93qD)h2:qKfձuT#(f.q =94Hq>vͧu tff"ab E=/Yq; a7cNB>C?Ud940Q:9xjv/(Uo Q%mӵo4b:nvy.Z? XVSPBDO_#ogOBmb~%D4oV $WmǕ(:IxɆ^W/Kk:`P_+#?1oYt 8"#&ajzCn75y qz=^[UtSKu 1A;& ʰ]YtZ&Fi /0 NͪI#Hd)=}jl/z? ~* hAXLH7GTrX}o1p`׾IX_YZK? \öY mm|og.>|Ȧ# щQӼT<JeSL@tMR5=Ybp exh^ޑ流~\NVbT)~M90Pb͐z2볟zVev:M!OgFo(S8߈aZ}5y=Fm9"ʢR(Rn[fu"x9MB A~rY cGo")iy_M)p0*ٻ<k UjLl힧r18P gk NLk9*N|&=hR. B5Ѡ("Pc'\ܮ)kk*p#oUΟCHpQ+uttCcV (8tH[ l=j 6yt~+īŚW ]mF,,> lPlj' 6qT>b.Mu24qqhІk腖U䅉Q^4d +ϥ=H%/e n~VQWt>論QKm:҇OFO/ZÓV>iS X?g_BxxՕW/GqW`;[[0K)P"L؂6c2|b9)~N_#vV bEq8\l/n:̜ &En0 e\}1Ϊ-=ĉ$G]F!^]s@I5t1B.l2uHH?gyEEgVl;brIB!ǗBkbZ܍h0 dtgL'8dң fuNz$R#|H SH(;Bn\4{ 0MGA#O+b~e-LrQ6h-,Q 2s~rO 'O%,ȿV[ `֒x#%3m*uj/-Zd}o a. Yt(_}ZäO1,~1Y=\XԠBfjP$qc>xXaf^OZ؀ Qgq xBB<̊62!xqar͉D0WUəea8B<"7z@4Ur'tv%tm!M?@dD2`.s3O?2s T~@ cFJ=0M"7RPcTᏡq`WMha'qlKHP$9Up$Pv/ q $f'%w%€HS>vK%^8EҾRJ lu>COt>%?űXt2bzr^CgjCAPR{_W<M2U3~Y-n\0_P R6 L*Ѐ #J=wxoRXW3bU٨c<0:{鯏-x )ث+!|2\}jA*}YzCZ{0\I=|7(..rb󵌡t T#׋ |%>,<{-B:Fz{%,7 ZyruUg=GW]);f6lݨ̛%߈bkc>2ի5[anV]!t7IcAbЌ<V݋wmTLed#{ov鵺 tA2+2J L ˅;0 #Ƶ8&n Ln[ʹ>Ib5y ~% 2]ؒ.ZJG(?stAN[$mxk Ş̄jۣQ"& G0آPae 8 ~K P &)cP'3ñEzE`Y|5L벍Cl\.+QYJ~6ӹèCDž}3uŊmy uQf)ac;&(D@',_u\T^R9.ֱV$SR\clj9\71ڹ B&MunWP8< qkn , ȜBv-҄v\ c\)&l׀,ET:,9z1/i2!7)JԹg)(M(J(sohYV׀3QH;5 A˘"Sm]jCnV<͏$A'p~qz2>`n>Jd-?ȊUG兿z?*LlJD{ibE"F ;ԩr gGMɶɶp93bjo Up:}(8Jj`?azZwK0rJUo=DY:e,^mk;`/QbCخMQ(,W3$p[YAa7On-MWUb9@۝5Hg5)xD6%JbIM0okE 0& Tti@;fx-z{[YqG톐3#Ynףߴ↫B:GF}*9xd7[KP;"SHS3Y:H<Zl#ް%J1T3YK3wIUi?6p\H1a= |S bp>L8 ؆&KB9h\z>ASPE:SV<.)Je(&%ˢ Cf//L&vǯKV fETh赽zba;8+ D85" P1Q5P9?18^ ^(z0Dwx"V+I+mrw'2[$rZZc(88τӐ_Y;xlo-#rߑLɂTeg}lWea3\ 10@FgԽM}(OnM{sM\B\ jGs彩ϭÕ0T&0Y%]_0.9,jYSAJ6fQ'k~k$H+ji$ c[1>9B4BvuJ5.yBJO@"ٛLwhE̮q\[ -ɚW0J"NWM[i6ZTjzWd}1}(Z?/zsX[B px?HTI?Qd@~¿qgYEl[pqۡ`_ eP$a]I'ZsO%h%_X6Z[- Zm0,Di0 A{mA·%(5k*&Zeషdhog GRЧ*zgad~?tduvsYfŌ6kC&}9o!DNs)s1O?Ic'::jЊb7PNORtrDgIZ`ିƴ .c,z'ˍ*VuŹ6\WCg"/pEN;vѡfEkV0"8<$Ѱe,}.`iߒX-}FE~gingMKpC,̅#٭(˸esjq<;ia"/-;|.򤘸$5C\-_>S+$Ы Rx׊o/ck^<+1Kv-wH _A H&&)1K Z.zyUJ>J&p:74цsc]@Ae^ߚҫԣ;젘vb3N&XWZ4cY[I)A%äCI~Yّ%nf(|䐟#R?wtT\Aּ*y#[*bGy*\`L5rmt,kS9/2%zSUV!j1XқKwd 58چ7g3~^0n"['HQY՝=Wo^Di'JvOW_d53S3'{z'`lm=_`vJZ²Hk?};`8}Dt BC(b%Sѳ[aEy@Z<]s R9o}FD)4BNHa%NCN} r>'nyXl *)K`o*B OC`&fgBq,Sh`?SJ)Tvt5_m  iρ?F>6qW[ѧ9^C(khf장,Np6K }A eA^8wy*:QX'ȑ-WP,.Kؓk}8&I7jnB/[tY~T߮:#~pFF3d(l^C;Ι{-!+Q ɷ:,#*?)M<$"J>hm)#= 2+6﷣r9P0 ҋ/w%S-[fmoQ+cEۉC9wJ-7}/qca}db@2rY8r-=P _֧pˋ$4tgb2jX0v=ikHBG!7.v4 oT뵟| r[6Zt*=tހbGuK[l Y b3^m9Fvn@/ WyET^zQofXm92pC1EFםd3z5Xxl 6y*ý#]A!*o%3DHz;mYKvQ9{#ѹUu?kRZT KT9q ¥Xq2ԺbBA{ʦokK4K鵢UUaKTLjqABBzϳv4*}2UmI[Ku<ُEiA_^ϸ]_ʼ?ڬ%JBVN|%7 xWeB^UƜѝOX#Kq8\4!7sO̖Gk' Y *)Zbǜ \E_ S ř,N>=Pa51yGbU3OŕۭpswU#']HK Er.'aJllOE ]xvJF,= ~'.'#ZHFT_n`Mӈ#=x95rV\dhJrrɟQ8x@ց!LO֐R{-6)l+S@-TgBQoA_AC8$x |1h(gl@W/dJx6)e*AD;š%%mڽ '%Ւ g ;9^4<%/6fv#t8Á4x.v8ͩT.T#̤SMk(Wy _鍍 EtTl@nW"A}>f/U{Yu$l >hRMpdžԁ13U͚]HNb"nf d:;irs9ty# RA眱f{T5 qr<>l>&)l #<-DD/C/1hchX`*x+vPz=iE=f\żwihڀ"foA`zȫ>PO\] +"^0^{Fa }V`أ ?Q>a^<6&_֎NapJfm&Grho6uwݚ!4xY=,9% 286$y'LꙨ ;y1FP; CBWɠ3.,M}Gro}u.Do"\{KFl`3aS7,񱃢|) Kp:lsʽ?͘8 2Fu#}d*Uqd.+rA{@Ϋ|Rr#\u? 1{Nԕ og k 0.[;{C3sW9XBFlr4O)#0Z#lm`}{g Hz=@fO@{o ,E0M(ɔ]QM}g/y(b%E;v5|'Xؚ +pݺC*4"K*W~loP. #|π S6'C& 'DnB~R>Ac'h?I RSkþ3DK"44%,ppM.H ̇ՈkY~.a-YRIA0ؕV|؎Y=+F՚OCmI6i ׫m[Q7>ۥ "0DtM{y2-Gʊ/{kE̛0ضi1(G?vwyc&g/ɫ39w9n*JfTf}!@^c\gHNL[fD05 jKNc]`{yK}ϼz`:LЏ+>5."#Iv}͝-/y/SC :)/@(ѩ2r+rIcFz+_ )4=pܿۻbG H9XʜWB7PٽDI HDmׅ2u]6ǖmϣ K .gwC Y]0ܴm|3ձsXuScڗAٔaxIه'lq? t6bjߥ|3jl?Ot=&R8"D[r$1u+Rs9I${#hZ+ "Bk>+T{E P=ek_MMjcf⡱`g3>EU)|4X*Cɱ]xS3+"S 1cg,ӨBi>M{V\?!@ 3,Y$)/TD+DZQX8=vi> )򭡤Bl hikC;k=6Ƅ|)oȕl=TM.@RIEviݎ(s 0AXCNԬnMs0*tpb | Q,*1^P/"W,IM)lB7qrR(ZTཿL)O>/>!*9un.(R$ܤ e"X~'^vνtk)>3A/Fi\Ki"J+ƬM0!)X(f vf:`i+Fqn mptS2:]:!`qk։VDfyYKϬ{ƟxvsAa|Imj/^Q)Ӌka2v84f&:jĿdQ}N'c!uo%wwy1EjV![wEf j~+$ghN<,_ceDb|De?.L=)NNqٌ t3B2{6DGGiYY/7oEa(tzu-Kv1~=7V: {[L68J*\f y?dhk/:q9RRmΌؖ0챖{ ^~C>z+}ZZ&/S>.q{ZB[ض_K.Sj)l xqVۀ36̐L{8FNhl3WГvY4h6"n"ZCdr e3@`++L#"}eegj&޺rBKо1[qֳM]PTIҖ˗:CΑN"AιLcL{"{;#2s~hz!<쮮ga .WjY7 SȜ>U6˒㩒N%}AfD@h؏8XZMrƐkAe<dµf;o qbO~1uHG nc|Z% pZqՀ[CK=q˅\8٠{9I3w9eڢd*7Ս1LnfC1|8~}Y4VIXΝ=|G5+S( A\;2ީ3`5ت( `F i_Q-}j[MXWZzjh4.#ˮ:g4 _~*eZәnP|ZT"lt4PhnBz?7|p]m=s  `Z`f}6rHäTK'8 ?ʟ.^!JTE0!ħ;.`!ꛞ\B{Ʒ*P$)18s~b Xa;;mòǿxiS;؀ϥQx*; ףD6fRG;_xc +4,ctŋs\sw?$[xd-JqT[M)C0 =H BYPdj {x_VnQCU?dᆄH|Z\/[{h85@=\:ɩ=(H\+2V:wӕ5}u99"›:&;2c j2PmƊj3a)tK>wL)Pi} Up-Œ$zFq|qa]%HgZ0U^_Ky1:Aׂ#0P'V$Q17 _{=OW#Ԟ d|:nbuϋ)ϴ PZ1Q)nc];Iµkn?6u|\ YÙzNE3,<2ZhuBZ[QdzjKz]a޺OrKQ4xЬ71S71xDA˱:^7(9g dMl+h^$,.žuNs|-ɡEC92`IPV69vwY8P ?V )<>7a්dxTR:(D z .Lr+v f+V@(_zuFCS|b"e5ؼvBa@u_}%ۏ1+my@J 4^A}|=r nu|ƠX%%'Pp!UF/֑s>I bkkVT)YgCDh3ŚcroA uxp)ěl 8[G. msez^Y_;h ,bs󡏔CyBI2&vf,q{F't&3|(= HO*:qǨ HujVD4fHd^G . ʻ@pDyؼqF@CtJܖ-#cSd6v=dYFG;P_Ԓ)UhLV/JEp4'cK>BDS 2AXk uOvIŖ*.${y׌ͲBo{"g8&=ypIS/+qhS8ifs=` BT\xV%7.YW.݈f3d'ޭV=q,[U%F&QHYΣ6CFazA@1 m!xi+Vƴ(fb@"Ī6KԑҖ Du1dEdi{W؏ .7IAO <>_uVdsqݰJkoع1vp*dI/LL.pl-s!w'9k9yn|Aja^ڷ6+euaFofC8\#ˆpJ,zw*ږm^DZ_؆Pi w?H5+ɲo?5hk}?aK잩45Sѻ3ӬCYHgKS !{iH}ܡқƵ*`?WCz:NC[6! $\}|S;5e/Q!^8C|aT}D#3#7gBً[pT' ć OPg]KjlmێdCTwZAj?.=OV޿EI.sBW hKagB-hVHt4M-dh-m*xJB߃%dF d3XJ B|18}2D;pgVcrQ}Pk.(8eΣ.Zs$cryptmount-6.3.0/testing/mudslinger.in000077500000000000000000002002461465135467200201460ustar00rootroot00000000000000#!/bin/bash # Testing script for cryptmount (compiled with -DTESTING) # RW Penney, December 2005 DD=/bin/dd LOSETUP=/sbin/losetup SU_p="/bin/su -p" TMPDIR=/tmp/cm-$$ CM=../cryptmount PASSWD="3normouslyComplexPassw0rd,maybe?" # Pair of users, with valid login-shells: USER1=bin USER2=nobody LOOPDEV=/dev/null LOOPDEV2=/dev/null DATEFMT="+%d%b%y-%H:%M:%S" function listLoopDevs() { # Find free loopback devices least likely to be selected by 'losetup -f' # Make sure device driver has at least two slots available: dummy_lf="${TMPDIR}/dummy_loop" ${DD} if=/dev/zero of="${dummy_lf}" bs=1M count=1 2>/dev/null for i in 0 1; do ${LOSETUP} -f "${dummy_lf}" done for lp in `${LOSETUP} -j "${dummy_lf}" -O NAME | sed '1d'`; do ${LOSETUP} -d ${lp} done rm -f "${dummy_lf}" ${LOSETUP} -l -O NAME | \ sed '1d' > ${TMPDIR}/usedLoops ls /dev/loop[0-9]* | \ grep -v -x -f ${TMPDIR}/usedLoops | \ sort -r > ${TMPDIR}/availableLoops }; function dm_target_path() { if [ -b "/dev/disk/by-id/dm-name-$1" ]; then echo "/dev/disk/by-id/dm-name-$1" else echo "/dev/mapper/$1" fi }; function dd_sync() { ${DD} $@ sync }; function blank_mke2fs() { # Preceed mke2fs with device-prefix zeroing to avoid valid-data tests # BEWARE - this assumes we are certain we can safely reformat the given device dev_arg="${@: -1}" if [ -b "${dev_arg}" ]; then ${DD} if=/dev/zero of="${dev_arg}" bs=1M count=1 2>/dev/null mke2fs "$@" 2>&3 else echo "${dev_arg} is not a block device" false fi }; # # Testing infrastructure # NTESTS_RUN=0 NTESTS_FAILED=0 NTESTS_PASSED=0 NTESTS_ABORTED=0 if test -t 1 && which tput >/dev/null 2>&1; then ts_norm=$(tput sgr0) ts_bold=$(tput bold) ts_good=$(tput setaf 2) ts_warn=$(tput setaf 5) ts_fail=${ts_bold}$(tput setaf 1) fi function test_start() { # Syntax: test_start echo -n "Testing $1..." echo -e "\n\n---- Test \"$1\" ---- ("`date ${DATEFMT}`")\n" 1>&3 if [ ${NTESTS_ABORTED} -gt 0 ]; then test_abort false return else NTESTS_RUN=`expr ${NTESTS_RUN} + 1` true return fi }; function test_fail() { echo " ${ts_fail}FAILED!${ts_norm} [$1]" echo "!!! TEST FAILED [$1] ("`date ${DATEFMT}`") !!!" 1>&3 NTESTS_FAILED=`expr ${NTESTS_FAILED} + 1` # Execute optional clean-up command if [ ! -z "$2" ]; then echo " (attempting clean-up with \"$2\")" 1>&3 eval "$2" 1>&3 fi }; function test_pass() { echo " ${ts_good}passed${ts_norm}" echo "(test passed @ "`date ${DATEFMT}`")" 1>&3 NTESTS_PASSED=`expr ${NTESTS_PASSED} + 1` }; function test_abort() { echo " ${ts_warn}aborted${ts_norm}" echo "(test aborted)" 1>&3 NTESTS_ABORTED=`expr ${NTESTS_ABORTED} + 1` }; function test_summary() { echo -e "\n========" echo "${NTESTS_RUN} tests run" echo " ${NTESTS_FAILED} tests failed" echo " ${NTESTS_PASSED} tests passed" echo -e "\n\n${NTESTS_RUN}/${NTESTS_FAILED}/${NTESTS_PASSED} tests run/failed/passed" 1>&3 }; # # Utility routines # function tupelize() { # Assign comma-separated fields to set of scalars # Syntax: tupelize [var0 [var1]...] local tupstring=`echo $1 | sed 's/,/ /g'` shift for field in ${tupstring}; do local var="$1" eval "${var}=\"${field}\"" shift done } function wait_udev() { # Wait for udev events to settle sleep 0.25 udevadm settle 2>/dev/null \ || udevsettle 2>/dev/null \ || sleep 2.75 }; function mk_ssl_keyfile() { # Syntax: mk_ssl_keyfile dd_sync if=/dev/urandom bs=${1}c count=1 2>/dev/null | \ openssl enc -e -pass pass:"${PASSWD}" -md $2 -${3} 2>&3 }; function mkrandshort() { # Create random 4-digit hex number od -An -N2 -t x2 /dev/urandom | sed 's% *%%g' }; function mkbingrep() { # Create simple binary-grep for block-offset test cat < "${1}.c" #include #include #define BLKLEN 32 int main(int argc, char*argv[]) { int i, notzeros, state=0; long fpos=0; char buff[BLKLEN]; while (read(STDIN_FILENO,(void*)buff,(size_t)BLKLEN) == (ssize_t)BLKLEN && state < 2) { for (notzeros=0,i=0; !notzeros && i ${TMPDIR}/dm-list1 for tgt in `awk '{printf"%s\n",$1}' ${TMPDIR}/dm-list1` do if grep -q "${tgt}" ${TMPDIR}/dm-list0; then true; else echo "removing ${tgt}" umount "$(dm_target_path ${tgt})" 2>&3 || true dmsetup remove ${tgt} 2>&3 fi done rm "${TMPDIR}/dm-list1" } # # Specific test-cases # function test_version() { # Check that cryptmount has been compiled properly for further tests if test_start "version"; then true; else return; fi echo "#nothing here!" > ${TMPDIR}/cmtab if ${CM} --config-dir ${TMPDIR} --version 2>&3; then test_pass else test_abort echo "*** Please ensure cryptmount has been compiled with -DTESTING" echo "*** or rebuild using 'make clean cmtest'" fi }; function test_binary() { # Run built-in unit-tests if test_start "binary self-test"; then true; else return; fi if ${CM} --self-test 2>&3; then test_pass else test_abort fi }; function test_keygen() { # Test automatic key generation if test_start "key generation"; then true; else return; fi mgrlist=`${CM} --key-managers 2>/dev/null | sed -e 's/,/ /g' -e 's/\//' -e 's/\//'` for mgr in $mgrlist; do for len in 4 16 64; do echo "${mgr}: len=${len}" 1>&3 idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults cipher=twofish keyformat=${mgr} keyfile=${TMPDIR}/keyfile } EOF rm -f ${TMPDIR}/keyfile if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx}" 2>&3; then test_fail "privilege violation"; return; fi if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key ${len} target${idx} 2>&3; then true; else test_fail make-key; return; fi if [ ! -f ${TMPDIR}/keyfile ]; then test_fail missing-key; return; fi fllen=`wc -c ${TMPDIR}/keyfile | awk '{printf"%d", $1}'` if [ "${fllen}" -lt "${len}" ]; then test_fail "keyfile size"; return; fi if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then test_fail key-overwrite; return; fi done done test_pass }; function test_setup_dev() { # Basic test of prepare/release on raw device if test_start "basic setup (device)"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults cipher=twofish keyformat=builtin keyfile=${TMPDIR}/keyfile } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then true; else test_fail "key-generation"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi if blank_mke2fs -q $(dm_target_path target${idx}); then true; else test_fail "mke2fs (${idx})"; find /dev -name \*target${idx}\* -ls 1>&3; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release"; find /dev -name \*target${idx}\* -ls 1>&3; return; fi test_pass }; function test_setup_loop() { # Basic test of prepare/release via loopback device if test_start "basic setup (loopback)"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${TMPDIR}/loopfile loop=auto dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults cipher=twofish keyformat=raw keyfile=${TMPDIR}/keyfile } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then true; else test_fail "key-generation"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi if blank_mke2fs -q $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi test_pass }; function test_setup_roloop() { # Test prepare/release of loopback on read-only device if test_start "read-only loopback"; then true; else return; fi idx=`mkrandshort` mkdir ${TMPDIR}/romnt dd_sync if=/dev/zero of=${TMPDIR}/roloopfile bs=1M count=32 2>/dev/null ${LOSETUP} "${LOOPDEV2}" ${TMPDIR}/roloopfile blank_mke2fs -q "${LOOPDEV2}" mount -t ext2 "${LOOPDEV2}" ${TMPDIR}/romnt dd_sync if=/dev/zero of=${TMPDIR}/romnt/lpfl bs=1M count=16 2>/dev/null cat < ${TMPDIR}/cmtab target${idx} { dev=${TMPDIR}/romnt/lpfl flags=nofsck loop=auto dir=${TMPDIR}/mnt fstype=ext2 mountoptions=ro cipher=twofish keyformat=builtin keyfile=${TMPDIR}/keyfile keyhash=sha1 keycipher=blowfish-cbc } EOF cleanup="umount ${TMPDIR}/romnt; ${LOSETUP} -d "${LOOPDEV2}"; rm ${TMPDIR}/roloopfile; rmdir ${TMPDIR}/romnt" rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then true; else test_fail "key-generation" "${cleanup}"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail "prepare" "${cleanup}" ; return; fi if blank_mke2fs -q $(dm_target_path target${idx}); then true; else test_fail "mke2fs" "${cleanup}"; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release" "${cleanup}"; return; fi mount -o remount,ro ${TMPDIR}/romnt if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount target${idx} 2>&3; then true; else test_fail "mount-ro" "${cleanup}" ; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --unmount target${idx} 2>&3; then true; else test_fail "unmount-ro" "${cleanup}" ; return; fi # ideally we should try rw-mounting the filesystem, # and checking that the operation fails, but libdevmapper-1.01 apparently # does not deal well with read-only loopback devices eval "${cleanup}" test_pass }; function test_null() { # Test robustness to null cmtab targets if test_start "null targets"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { } EOF if ${CM} --config-dir ${TMPDIR} --list 1>&3 2>&3 ; then true; else test_fail list; return; fi if ${CM} --config-dir ${TMPDIR} --list target${idx} 1>&3 2>&3; then true; else test_fail list; return; fi test_pass }; function test_passchange() { # Test password-changing if test_start "password changing"; then true; else return; fi mgrlist=`${CM} --key-managers 2>/dev/null | sed -e 's/,/ /g' -e 's/\//' -e 's/\//' -e 's/\//'` for mgr in ${mgrlist}; do echo "${mgr}" 1>&3 if [ -f ${TMPDIR}/keyfile ]; then rm ${TMPDIR}/keyfile; fi idx=`mkrandshort` NEWPASSWD="${PASSWD}-new${idx}" if [ "${mgr}" != "luks" ]; then keyline="keyformat=$mgr keyfile=${TMPDIR}/keyfile" else keyline="keyformat=$mgr" fi cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults cipher=blowfish ${keyline} } EOF if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 1>&3 2>&3; then true; else test_fail "make-key"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail "prepare"; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release"; return; fi rm -f ${TMPDIR}/keyfile-old if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --newpassword "${NEWPASSWD}" --change-password target${idx} 1>&3 2>&3; then true; else test_fail "changing password"; return; fi if [ "${mgr}" != "luks" ]; then if [ -f ${TMPDIR}/keyfile-old ]; then rm ${TMPDIR}/keyfile-old; else test_fail "missing backup key"; return; fi fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then test_fail "old password"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${NEWPASSWD}" --prepare target${idx} 2>&3; then true; else test_fail "prepare-new"; return; fi if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release-new"; return; fi wait_udev done test_pass }; function test_mtab() { # Test of updates to mtab if test_start "mtab updates"; then true; else return; fi fstype=ext3 rm -f ${TMPDIR}/keyfile ln -s ./mnt ${TMPDIR}/mnt-link0 ln -s mnt ${TMPDIR}/mnt-link1 cleanup="true" # Slackware-12 doesn't like variant="/.//./", for unknown reasons for variant in "" "/" "//" "/./" "/.//./" "-link0" "-link1" do idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=user,fsck dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt${variant} fstype=${fstype} mountoptions=ro,noexec cipher=cast5 fsckoptions=-N;-T;-V keyformat=builtin keyfile=${TMPDIR}/keyfile } EOF cleanup="rm ${TMPDIR}/mnt-link0 ${TMPDIR}/mnt-link1" echo "variant=\"${variant}\"" >&3 test -f ${TMPDIR}/keyfile || ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail "prepare" "${cleanup}" ; return; fi if mkfs -t ${fstype} $(dm_target_path target${idx}) 1>&3 2>&3; then true; else ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; test_fail "mkfs.${fstype}" "${cleanup}"; return fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release" "${cleanup}" ; return; fi if [ `df -k | grep -c $(dm_target_path target${idx})` -ne 0 ]; then test_fail "pre-existing" "${cleanup}" ; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount target${idx}" 1>&3 2>&3; then true; else test_fail "mount" "${cleanup}" ; return; fi if [ `df -k | grep -c "target${idx}"` -ne 1 ]; then test_fail "unregistered" "${cleanup}" ; return; fi wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail "unmount" "${cleanup}" ; return; fi if [ `df -k | grep -c $(dm_target_path target${idx})` -ne 0 ]; then test_fail "remnant" "${cleanup}" ; return; fi done eval "${cleanup}" test_pass }; function test_listing() { # Test listing of cmtab targets if test_start "listing targets"; then true; else return; fi cat < /dev/null > ${TMPDIR}/cmtab tlist="" for tgt in 0 1 2 3 4 5 6 7 do idx=`mkrandshort` idx2=`mkrandshort` cat <> ${TMPDIR}/cmtab target${idx} { dev=${TMPDIR}/loopfile dir=/mnt/point-${idx2} fstype=brokenfs mountoptions=nosuid,noatime,sync cipher=blowfish keyfile=${TMPDIR}/keyfile keyhash=md5 keycipher=aes } EOF tlist="${tlist} target${idx},/mnt/point-${idx2}" done if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --list" > ${TMPDIR}/tlist 2>&3; then true; else test_fail listing; return; fi for marker in ${tlist} do tupelize $marker tgt dir dirq=`awk "/^${tgt}/{ printf\"%s\",\\$5 }" ${TMPDIR}/tlist` if [ "${dirq}" = "" ]; then test_fail "absent"; return; fi if [ "${dirq}" != "\"${dir}\"" ]; then test_fail "mismatched: ${dirq} != ${dir}"; return; fi done rm ${TMPDIR}/tlist test_pass }; function test_defaults() { # Test _DEFAULTS_ pseudo-targets if test_start "defaults pseudo-targets"; then true; else return; fi cat < /dev/null > ${TMPDIR}/cmtab tlist="" for tgt in 0 1 2 3 4 5 6 7 do idx=`mkrandshort` idx2=`mkrandshort` idx3=`mkrandshort` cat <> ${TMPDIR}/cmtab _DEFAULTS_ { fstype=fs-${idx3} cipher=random keyhash=md-${idx} } target${idx} { dev=${TMPDIR}/loopfile dir=/mnt/point-${idx2} mountoptions=sync cipher=blowfish keyfile=${TMPDIR}/keyfile } EOF tlist="${tlist} target${idx},/mnt/point-${idx2},fs-${idx3}" done if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --list" > ${TMPDIR}/tlist 2>&3; then true; else test_fail listing; return; fi if [ "`echo ${tlist} | wc -w`" -ne "`wc -l < ${TMPDIR}/tlist`" ]; then test_fail "wrong number of targets"; return fi for marker in ${tlist} do tupelize $marker tgt dir fs echo $tgt __ $dir __ $fs 1>&3 dirq=`awk "/^${tgt}/{ printf\"%s\",\\$5 }" ${TMPDIR}/tlist` fsq=`awk "/^${tgt}/{ printf\"%s\",\\$7 }" ${TMPDIR}/tlist` if [ "${dirq}" != "\"${dir}\"" ]; then test_fail "mismatched mount-point (${dirq} != ${dir})"; return; fi if [ "${fsq}" != "\"${fs}\"]" ]; then test_fail "mismatched fstype (${fsq} != ${fs})"; return; fi done rm ${TMPDIR}/tlist test_pass }; function test_bad_passwd() { # Test of password mismatch if test_start "basic password mismatch"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults cipher=twofish keyformat=builtin keyfile=${TMPDIR}/keyfile keyhash=sha1 keycipher=blowfish-cbc } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then true; else test_fail "key-generation"; return; fi if ${CM} --config-dir ${TMPDIR} --password "NOT${PASSWD}" --prepare target${idx} 2>&3; then ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3 test_fail prepare else test_pass; fi }; function test_fdpasswd() { # Check reading of password via file-descriptor if test_start "command-line passwords"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt keyfile=${TMPDIR}/keyfile } EOF rm -f ${TMPDIR}/keyfile echo PASS1 > ${TMPDIR}/cmstrm COMMAND="${CM} --config-dir ${TMPDIR} --passwd-fd 5 --generate-key 16 target${idx}" if ${COMMAND} 5< ${TMPDIR}/cmstrm 2>&3; then true; else test_fail "key-generation (priv)"; return; fi if ${CM} --config-dir ${TMPDIR} --password PASS1 --prepare target${idx} 2>&3; then true; else test_fail "prepare"; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release"; fi echo PASS2 >> ${TMPDIR}/cmstrm if ${CM} --config-dir ${TMPDIR} --change-password --passwd-fd 6 target${idx} 6< ${TMPDIR}/cmstrm 2>&3; then true; else test_fail "password change"; fi echo PASS2 > ${TMPDIR}/cmstrm COMMAND="${CM} --config-dir ${TMPDIR} --passwd-fd 7 --prepare target${idx}" if ${COMMAND} 5< ${TMPDIR}/cmstrm 7< /dev/null 2>&3; then test_fail "prepare (bad-fd)"; return; fi if ${COMMAND} 7< ${TMPDIR}/cmstrm 2>&3; then true; else test_fail "prepare (2,priv)"; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release (2)"; fi rm ${TMPDIR}/cmstrm ${TMPDIR}/keyfile-old test_pass }; function test_bad_keyfmt() { # Test of unavailable key-manager if test_start "unavailable key-format"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults cipher=twofish keyfile=${TMPDIR}/keyfile keyformat=BAD } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then test_fail "key-generation"; return; fi dd_sync if=/dev/urandom of=${TMPDIR}/keyfile bs=16c count=1 2>/dev/null if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3 test_fail prepare else test_pass; fi }; function test_bad_keyhash() { # Test of unavailable keyhash algorithm if test_start "unavailable key-hashing"; then true; else return; fi mgrlist=`${CM} --key-managers 2>/dev/null | sed -e 's/,/ /g' -e 's/\//' -e 's/\//' -e 's/\//'` for mgr in $mgrlist; do for alg in md15 sha19.2 rypemd; do echo "key-manager=${mgr} keyhash=${alg}" 1>&3 idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults cipher=twofish keyformat=${mgr} keyfile=${TMPDIR}/keyfile keyhash=${alg} } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then test_fail "key-generation"; return; fi done done test_pass; }; function test_envvars() { # Test targets involving environmental variables if test_start "environmental variables"; then true; else return; fi idx=`mkrandshort` rm -f ${TMPDIR}/keyfile* cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} flags=nofsck dir=${TMPDIR}/mnt-\$(GROUPNAME) fstype=ext2 mountoptions=defaults cipher=twofish keyformat=builtin keyfile=${TMPDIR}/keyfile-\$(USERNAME) } EOF if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then true; else test_fail "make-key"; return; fi if [ ! -f ${TMPDIR}/keyfile-root ]; then test_fail "missing key"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail "prepare"; return; fi if blank_mke2fs -q $(dm_target_path target${idx}); then true; else test_fail "mke2fs"; return; fi if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release"; return; fi for user in ${USER1} ${USER2}; do group=`su -s /bin/sh -c "id -ng" ${user}` echo "user=${user}.${group}" >&3 cp ${TMPDIR}/keyfile-root ${TMPDIR}/keyfile-${user} if ${SU_p} ${user} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --newpassword "${PASSWD}"-${user} --change-password target${idx}" 2>&3; then true; else test_fail "changing password"; return; fi wait_udev mkdir ${TMPDIR}/mnt-${group} if ${SU_p} ${user} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}-${user}" --mount target${idx}" 2>&3; then true; else test_fail "mount-${user}"; return; fi if [ ! -d ${TMPDIR}/mnt-${group}/lost+found ]; then test_fail "lost+found ${user}.${group}"; return; fi if ${SU_p} ${user} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail "mount-${user}"; return; fi done rm -f ${TMPDIR}/keyfile-* rmdir ${TMPDIR}/mnt-* test_pass; }; function test_frenzy() { # Test multiple targets being (un)mounted in parallel if test_start "frenetic activity"; then true; else return; fi rm -f ${TMPDIR}/keyfile tgtlist="" pos=0 fsz=2048 cat /dev/null > ${TMPDIR}/cmtab for cnt in $(seq 0 7); do if [ ! -d ${TMPDIR}/mnt${cnt} ]; then mkdir ${TMPDIR}/mnt${cnt}; fi idx=`mkrandshort` while ( echo ${tgtlist} | grep -q target${idx} ); do idx=`mkrandshort` done tgtlist="$tgtlist target${idx}" cat <> ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} startsector=${pos} numsectors=${fsz} dir=${TMPDIR}/mnt${cnt} flags=user,nofsck fstype=ext2 mountoptions=defaults cipher=blowfish keyformat=builtin keyfile=${TMPDIR}/keyfile } EOF test -f ${TMPDIR}/keyfile || ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3 pos=`expr ${pos} + ${fsz}` done cleanup="${CM} --config-dir ${TMPDIR} --release --all" if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare --all 2>&3; then true; else test_fail "prepare" "${cleanup}"; return; fi for tgt in ${tgtlist}; do dd_sync if=/dev/zero of=$(dm_target_path ${tgt}) bs=1M count=1 2>/dev/null if blank_mke2fs -q $(dm_target_path ${tgt}); then true; else test_fail mke2fs; return; fi done wait_udev for tgt in ${tgtlist}; do if ${CM} --config-dir ${TMPDIR} --release ${tgt} 2>&3; then true; else test_fail release; fi done srtlist=`echo ${tgtlist} | awk '{for (i=1; i<=NF; ++i) printf"%s\n",\$i}' | sort` for tgt in ${srtlist}; do ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount ${tgt}" 2>&3 & done wait cat ${TMPDIR}/cryptmount.status 1>&3 cleanup="${CM} --config-dir ${TMPDIR} --unmount --all" if [ "`wc -l ${TMPDIR}/cryptmount.status | awk '{printf"%d",$1}'`" -ne 10 ]; then test_fail "cmstatus" "${cleanup}"; return; fi if [ `df -k | grep -c "${TMPDIR}/mnt"` -lt 8 ]; then df 1>&3; test_fail "df" "${cleanup}"; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount ${tgtlist}" 2>&3; then true; else test_fail unmount; return; fi test_pass }; function test_cipher_algs() { # Test usability of different encryption algorithms if test_start "cipher algorithm availability"; then true; else return; fi for CipherLen in aes,32 blowfish,48 twofish,32 serpent,12 do tupelize $CipherLen cipher len echo "cipher=${CipherLen}" 1>&3 idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=user,fsck dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt fstype=ext3 mountoptions=noatime,sync cipher=${cipher} fsckoptions=-N;-V keyfile=${TMPDIR}/keyfile keyformat=builtin } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then true; else test_fail "key-generation"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi if blank_mke2fs -q -j $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount target${idx}" 1>&3 2>&3; then true; else test_fail "mount"; return; fi wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail "unmount"; return; fi done test_pass }; function test_purepw() { # Test pure-password key-manager if test_start "pure-password key-manager"; then true; else return; fi # Check against reference encrypted filesystem: idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { keyformat=password cipher=aes dev=`pwd`/passwd.fs } EOF cleanup="${CM} --config-dir ${TMPDIR} --release --all" if ${CM} --config-dir ${TMPDIR} --password "pure" --prepare target${idx} 2>&3; then true; else test_fail "prepare passwd.fs"; return; fi wait_udev if [ "`head -n 1 $(dm_target_path target${idx})`" = "PurePassword" ]; then true; else test_fail "bad decrypt" "${cleanup}"; return; fi if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release passwd.fs" "${cleanup}"; return; fi # Check creation & access of new filesystems: for CipherLen in aes,16 twofish,24 serpent,18 do tupelize $CipherLen cipher len echo "cipher=${CipherLen}" 1>&3 idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { keyformat=password dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt flags=user,nofsck fstype=ext2 cipher=${cipher} } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi dd_sync if=/dev/zero of=$(dm_target_path target${idx}) bs=1M count=1 2>/dev/null if blank_mke2fs -q $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "not-${PASSWD}" --mount target${idx}" 2>&3; then test_fail "bad-password"; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount target${idx}" 2>&3; then true; else test_fail "mount"; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail "unmount"; return; fi wait_udev done test_pass }; function test_ssl_algs() { # Test usability of OpenSSL key & hashing algorithms if test_start "OpenSSL algorithm availability"; then true; else return; fi if ${CM} --key-managers 2>/dev/null | grep -q openssl; then true; else test_fail "No OpenSSL support"; return; fi for keycipher in aes-128-ecb aes-256-cbc camellia-128-cbc; do # Beware cfb*, ofb modes seem incompatible for unknown reasons for keyhash in md5 sha1 sha256; do echo "keycipher=${keycipher} keyhash=${keyhash}" 1>&3 mk_ssl_keyfile 16 ${keyhash} ${keycipher} > ${TMPDIR}/keyfile idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=user,nofsck dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt fstype=ext3 mountoptions=noatime,sync cipher=aes-ecb keyformat=openssl keyfile=${TMPDIR}/keyfile keyhash=${keyhash} keycipher=${keycipher} } EOF if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi dd_sync if=/dev/zero of=$(dm_target_path target${idx}) bs=1M count=1 2>/dev/null if blank_mke2fs -q -j $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount target${idx}" 2>&3; then true; else test_fail mount; return; fi wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail unmount; return; fi wait_udev done done test_pass }; function test_gcry_algs() { # Test usability of libgcrypt key & hashing algorithms if test_start "libgcrypt algorithm availability"; then true; else return; fi if ${CM} --key-managers 2>/dev/null | grep -q -w libgcrypt; then true; else test_fail "No libgcrypt support"; return; fi for keycipher in aes192 blowfish cast5-ecb camellia-256-xts do for keyhash in ripemd160 tiger192 sha512 do echo "keycipher=${keycipher} keyhash=${keyhash}" 1>&3 idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=user,nofsck dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt fstype=ext3 mountoptions=noatime,sync cipher=twofish keyformat=libgcrypt keyfile=${TMPDIR}/keyfile keyhash=${keyhash} keycipher=${keycipher} } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then true; else test_fail "key-generation"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi dd_sync if=/dev/zero of=$(dm_target_path target${idx}) bs=1M count=1 2>/dev/null if blank_mke2fs -q -j $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount target${idx}" 2>&3; then true; else test_fail mount; return; fi wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail "unmount"; return; fi wait_udev done done test_pass }; function test_gcryossl() { # Test usability of libgcrypt OpenSSL-compatibility layer if test_start "libgcrypt OpenSSL emulator"; then true; else return; fi if ${CM} --key-managers 2>/dev/null | grep -q -w openssl-compat; then true; else test_fail "No openssl-compat support"; return; fi configs="aes-128-cbc:md5:aes-cbc:md5 \ aes-192-ecb:sha224:aes192-ecb:sha224 \ aes-256-cbc:md5:aes256-cbc:md5 \ camellia-256-cbc:sha1:camellia256-cbc:sha1 \ des3:sha384:3des-cbc:sha384" for config in ${configs} do echo "config=${config}" 1>&3 Ocipher=`echo $config | awk 'BEGIN{FS=":"}{printf"%s",$1}'` Ohash=`echo $config | awk 'BEGIN{FS=":"}{printf"%s",$2}'` Gcipher=`echo $config | awk 'BEGIN{FS=":"}{printf"%s",$3}'` Ghash=`echo $config | awk 'BEGIN{FS=":"}{printf"%s",$4}'` # Generate key-file with openssl program: mk_ssl_keyfile 16 ${Ohash} ${Ocipher} > ${TMPDIR}/keyfile idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=user,nofsck dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt fstype=ext3 mountoptions=noatime,sync cipher=aes-ecb keyformat=openssl-compat keyfile=${TMPDIR}/keyfile keyhash=${Ghash} keycipher=${Gcipher} } EOF # Configure filesystem with libgcrypt-openssl compatibility layer: if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi dd_sync if=/dev/zero of=$(dm_target_path target${idx}) bs=1M count=1 2>/dev/null if blank_mke2fs -q -j $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi # change to openssl-keymanager, if available: if ${CM} --key-managers 2>/dev/null | grep -q -w openssl; then ed -s ${TMPDIR}/cmtab <&3; then true; else test_fail mount; return; fi wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail unmount; return; fi wait_udev done test_pass }; function test_mountlock() { # Test of mounting & user-locking if test_start "mounting & user-locking"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=user,nofsck dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt fstype=ext3 mountoptions=nosuid,noexec cipher=twofish keyfile=${TMPDIR}/keyfile } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --generate-key 32 --newpassword "${PASSWD}" target${idx} 2>&3; then true; else test_fail make-key; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi if blank_mke2fs -q -j $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount target${idx}" 2>&3; then true; else test_fail mount; return; fi if ${SU_p} ${USER2} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then test_fail bad-unmount; return; fi if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail unmount; return; fi test_pass }; function test_userflags() { # Test of mounting with user/nouser flags if test_start "mounting & user-flags"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=nouser,nofsck dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt fstype=ext3 mountoptions=nosuid,noexec cipher=twofish keyfile=${TMPDIR}/keyfile } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --generate-key 16 --newpassword "${PASSWD}" target${idx} 2>&3; then true; else test_fail make-key; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi if blank_mke2fs -q -j $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi for cfg in user,${USER1},pass user,root,pass nouser,${USER1},fail nouser,root,pass do tupelize $cfg flgs usr exp ed -s ${TMPDIR}/cmtab </dev/null 1>&2 /flags=/ c flags=${flgs},nofsck . w q EOF echo "config: ${cfg}" 1>&3 ${SU_p} ${usr} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --mount target${idx}" 1>&3 2>&3 stat=$? if [ \( "$stat" -eq 0 -a "$exp" != "pass" \) -o \( "$stat" -ne 0 -a "$exp" != "fail" \) ]; then test_fail bad-mount return fi wait_udev ${SU_p} ${usr} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --unmount target${idx}" 2>&3 stat=$? if [ \( "$stat" -eq 0 -a "$exp" != "pass" \) -o \( "$stat" -ne 0 -a "$exp" != "fail" \) ]; then test_fail bad-unmount return fi done test_pass }; function test_mountsynonyms() { # Test for synonyms of (un)mount if test_start "mount synonyms"; then true; else return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=user,nofsck dev=${TMPDIR}/devfile dir=${TMPDIR}/mnt fstype=ext3 mountoptions=,,,noatime cipher=blowfish keyfile=${TMPDIR}/keyfile keyformat=raw } EOF rm -f ${TMPDIR}/keyfile if ${CM} --config-dir ${TMPDIR} --generate-key 12 --newpassword "${PASSWD}" target${idx} 2>&3; then true; else test_fail make-key; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi if blank_mke2fs -q -j $(dm_target_path target${idx}); then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail release; return; fi for mntopt in "" "-m" "--mount" do for unmopt in "-u" "--unmount" do echo "mount[${mntopt}] unmount[${unmopt}]" 1>&3 if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" ${mntopt} target${idx}" 2>&3; then true; else test_fail mount; return; fi wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} ${unmopt} target${idx}" 2>&3; then true; else test_fail unmount; return; fi done done test_pass }; function test_offsets() { # check if startsector/numsectors parameters operate correctly if test_start "block offsets"; then true; else return; fi rm -f ${TMPDIR}/keyfile for offset in 0 16 256 do for length in 128 512 2048 do idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { flags=user,nofsck dev=${TMPDIR}/devfile startsector=${offset} numsectors=${length} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults cipher=aes ivoffset=61 keyfile=${TMPDIR}/keyfile } EOF test -f ${TMPDIR}/keyfile || ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3 dd_sync if=/dev/zero of=${LOOPDEV} bs=1M count=32 2>/dev/null sync if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then cleanup="${CM} --config-dir ${TMPDIR} --release target${idx}" dd_sync if=/dev/zero of=$(dm_target_path target${idx}) bs=1b count=`expr ${length} + 16` 2>&3 wait_udev ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3 wait_udev sync locs=`${TMPDIR}/bingrep < ${LOOPDEV}` first=`echo $locs | awk '{printf"%d",($1 / 512)}'` extent=`echo $locs | awk '{printf"%d", ($2 - $1) / 512}'` echo "offset=${offset} length=${length} vs first=${first} extent=${extent}" 1>&3 if [ "${first}" -ne "${offset}" -o "${extent}" -ne "${length}" ]; then test_fail "offset/length mismatch (${first}/${extent} != ${offset}/${length})" "${cleanup}" return fi else test_fail prepare return fi done done test_pass }; function test_swap() { # Basic test of swapon/swapoff on raw device if test_start "swapon (device)"; then true; else return; fi for cfg in ext2,rand,mkswap,fail swap,rand,mkswap,pass \ swap,rand,nomkswap,fail swap,zero,mkswap,pass \ swap,blank,mkswap,fail swap,data,mkswap,fail do tupelize $cfg fstype format flg exp idx=`mkrandshort` prio=`od -An -N1 -t u1 /dev/urandom | sed 's% *%%g'` cat < ${TMPDIR}/cmtab swap${idx} { dev=${LOOPDEV} mountoptions=pri=${prio} fstype=${fstype} flags=${flg} cipher=twofish-cbc-plain keyformat=raw keyfile=/dev/urandom keymaxlen=32 } EOF echo "config: $cfg - prio=${prio}" 1>&3 case $format in zero) dd_sync if=/dev/zero of=${LOOPDEV} bs=1M count=4 2>/dev/null ;; blank) blank_mke2fs -q ${LOOPDEV} ;; rand) dd_sync if=/dev/urandom of=${LOOPDEV} bs=1M count=4 2>/dev/null ;; data) dd_sync if=$0 of=${LOOPDEV} bs=1M count=4 2>/dev/null ;; esac wait_udev; sync if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --swapon swap${idx}" 2>&3; then test_fail privilege; return; fi if grep -q swap${idx} /proc/swaps; then test_fail pre-existing; return; fi ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --swapon swap${idx} 2>&3; stat=$? echo "stat: $stat" 1>&3 if [ \( "$stat" -eq 0 -a "$exp" != "pass" \) -o \( "$stat" -ne 0 -a "$exp" != "fail" \) ]; then test_fail "swapon" return fi wait_udev if [ "$stat" -eq 0 ]; then cat /proc/swaps >&3 if grep -q "\<${prio}\>" /proc/swaps; then true; else test_fail "proc+swaps"; return; fi # Beware that udev may rename our swap device within /proc/swaps! fi ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --swapoff swap${idx} 2>&3; if [ \( "$stat" -eq 0 -a "$exp" != "pass" \) -o \( "$stat" -ne 0 -a "$exp" != "fail" \) ]; then test_fail swapoff return fi if [ "$stat" -eq 0 ]; then if grep -q swap${idx} /proc/swaps; then test_fail proc-swaps; return; fi fi wait_udev done test_pass }; function test_fdconfig() { # Test usage of configuration via file-descriptor if test_start "command-line config-file"; then true; else return; fi if [ -f ${TMPDIR}/keyfile ]; then rm ${TMPDIR}/keyfile; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext2 flags=defaults cipher=twofish keyfile=${TMPDIR}/keyfile } EOF COMMAND="${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx}" if ${COMMAND} 2>&3; then true; else test_fail "key-generation (priv)"; return; fi cp ${TMPDIR}/cmtab ${TMPDIR}/cmstrm cat /dev/null > ${TMPDIR}/cmtab COMMAND="${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --config-fd 5 --prepare target${idx}" if ${SU_p} ${USER1} -c "${COMMAND}" 5< ${TMPDIR}/cmstrm 2>&3; then test_fail "config-fd"; return; fi if ${COMMAND} 5< ${TMPDIR}/cmstrm 2>&3; then true; else test_fail "config-fd (priv)"; return; fi wait_udev COMMAND="${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --config-fd 7 --release target${idx}" if ${SU_p} ${USER1} -c "${COMMAND}" 7< ${TMPDIR}/cmstrm 2>&3; then test_fail "config-fd"; return; fi if ${COMMAND} 7< ${TMPDIR}/cmstrm 2>&3; then true; else test_fail "config-fd (priv)"; return; fi rm ${TMPDIR}/cmstrm test_pass }; function test_privblock() { # Test blockage of privileged actions if test_start "privilege checks"; then true; else return; fi if [ -f ${TMPDIR}/keyfile ]; then rm ${TMPDIR}/keyfile; fi if [ -f ${TMPDIR}/keyfile_ ]; then rm ${TMPDIR}/keyfile_; fi dd_sync if=/dev/zero of=${LOOPDEV} bs=1M count=4 2>/dev/null; sync idx=`mkrandshort` NEWPASSWD="${PASSWD}-new${idx}" cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=swap flags=mkswap cipher=twofish keyfile=${TMPDIR}/keyfile keyhash=sha1 keycipher=aes-192-cbc } target${idx}_ { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=swap flags=mkswap cipher=twofish keyfile=${TMPDIR}/keyfile_ keyhash=sha1 keycipher=aes-192-cbc } EOF COMMAND="${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx}" if ${SU_p} ${USER1} -c "${COMMAND}" 2>&3; then test_fail "key-generation"; return; fi if ${COMMAND} 2>&3; then true; else test_fail "key-generation (priv)"; return; fi COMMAND="${CM} --config-dir ${TMPDIR} --password ${PASSWD} --newpassword ${NEWPASSWD} --reuse-key target${idx} target${idx}_" if ${SU_p} ${USER1} -c "${COMMAND}" 2>&3; then test_fail "key-reuse"; return; fi if ${COMMAND} 2>&3; then true; else test_fail "key-reuse (priv)"; return; fi wait_udev for action in --prepare --release --swapon --swapoff --safetynet do COMMAND="${CM} --config-dir ${TMPDIR} --password "${PASSWD}" ${action} target${idx}" if ${SU_p} ${USER1} -c "${COMMAND}" 2>&3; then test_fail "${action}"; return; fi if ${COMMAND} 2>&3; then true; else test_fail "${action} (priv)"; return; fi wait_udev done rm ${TMPDIR}/keyfile_ test_pass }; function test_voverride() { # Test file-format overrides if test_start "version overrides"; then true; else return; fi for config in 0,pass 1,pass 2,fail; do echo "config=${config}" >&3 tupelize ${config} fversion exp idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=defaults keyformat=builtin:${fversion} keyfile=${TMPDIR}/keyfile } EOF rm -f ${TMPDIR}/keyfile ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 1>&3 2>&3 stat=$? if [ "$stat" -eq 0 -a "${exp}" == "pass" ]; then obsv=`od -j 7 -N 1 -t d1 ${TMPDIR}/keyfile | sed -n '1s/^[0-9]* *//p'` if [ "$obsv" -ne "$fversion" ]; then test_fail "Version mismatch (${obsv} vs ${fversion})"; return; fi elif [ "${exp}" != "fail" ]; then test_fail "Bad version" return fi done test_pass }; function test_cryptsetup_compat() { # Check compatibility with (plain old) cryptsetup if test_start "cryptsetup compatibility"; then true; else return; fi if which cryptsetup 1>&3; then true; else test_fail "cryptsetup not available"; return; fi if ${CM} --key-managers 2>/dev/null | grep -q openssl; then true; else test_fail "No OpenSSL support"; return; fi mk_ssl_keyfile 32 md5 aes192 > ${TMPDIR}/keyfile openssl enc -d -aes192 -md md5 -in ${TMPDIR}/keyfile -pass pass:"${PASSWD}" -out ${TMPDIR}/keymat 2>/dev/null for cipher in blowfish serpent; do for length in 16384 32768; do for startsec in 0 32; do for ivoffset in 0 172 932; do idx=`mkrandshort` echo "${cipher},${length},${startsec},${ivoffset}" 1>&3 cryptsetup --key-file ${TMPDIR}/keymat -c ${cipher} -b ${length} -o ${startsec} -p ${ivoffset} create cstarget${idx} ${LOOPDEV} 2>&3 if [ -b $(dm_target_path cstarget${idx}) ]; then cs_size=`blockdev --getsize $(dm_target_path cstarget${idx})` dd_sync if=/dev/zero of=$(dm_target_path cstarget${idx}) \ bs=16k count=16 2>/dev/null blank_mke2fs -q -j $(dm_target_path cstarget${idx}) wait_udev cryptsetup remove cstarget${idx} 2>&3 wait_udev else test_fail "cryptsetup creation"; return fi if [ "${cs_size}" -ne "${length}" ]; then # Beware non-functioning '--size' option in cryptsetup-1.2 test_fail "cryptsetup incorrect sizing ($cs_size vs $length)"; return; fi cat < ${TMPDIR}/cmtab target${idx} { flags=user,nofsck dev=${LOOPDEV} startsector=${startsec} numsectors=${length} dir=${TMPDIR}/mnt fstype=ext3 mountoptions=defaults cipher=${cipher} ivoffset=${ivoffset} keyformat=openssl keyfile=${TMPDIR}/keyfile keyhash=md5 keycipher=aes192 } EOF if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" target${idx} 2>&3; then true; else test_fail "mount"; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --unmount target${idx} 2>&3; then true; else test_fail "unmount"; return; fi done done done done rm ${TMPDIR}/keymat test_pass }; function test_luks_loopdev() { # Check operation of LUKS container via loopback device if test_start "LUKS loopback"; then true; else return; fi if ${CM} --key-managers 2>/dev/null | grep -q luks; then true; else test_fail "No LUKS support"; return; fi idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { keyformat=luks loop=auto dev=${TMPDIR}/loopfile dir=${TMPDIR}/mnt fstype=ext3 flags=nofsck } EOF if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 32 target${idx} 2>&3; then true; else test_fail "key-generation"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi if blank_mke2fs -t ext3 -q "/dev/disk/by-id/dm-name-target${idx}"; then true; else test_fail mke2fs; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release"; find /dev -name \*target${idx}\* -ls 1>&3; return; fi wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" target${idx}" 2>&3; then true; else test_fail "mount"; return; fi wait_udev; sleep 1 if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail "unmount"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --newpassword ${NEWPASSWD} --change-password target${idx} 1>&3 2>&3; then true; else test_fail "changing password"; return; fi test_pass }; function test_luks_compat() { # Check compatibility with cryptsetup-luks, importing into cryptmount if test_start "LUKS compatibility"; then true; else return; fi if which cryptsetup 1>&3; then true; else test_fail "cryptsetup not available"; return; fi if ${CM} --key-managers 2>/dev/null | grep -q luks; then true; else test_fail "No LUKS support"; return; fi echo -n "keyslot0-password" > ${TMPDIR}/keymat0 echo -n "${PASSWD}" > ${TMPDIR}/keymat for CipherLen in aes,128 twofish-xts-plain64,256 serpent-cbc-essiv:sha256,96 do tupelize $CipherLen cipher len echo "config: $CipherLen" 1>&3 # Setup partition with cryptsetup-luks: TMPTGT="mudslinger-`mkrandshort`" if dd_sync if=/dev/zero of=${LOOPDEV} bs=1M count=1 conv=notrunc 2>/dev/null; then true; else test_fail "purging"; return; fi cryptsetup --batch-mode --cipher ${cipher} --key-size ${len} luksFormat "${LOOPDEV}" ${TMPDIR}/keymat0 1>&3 2>&3 sync cryptsetup --key-file ${TMPDIR}/keymat0 --cipher ${cipher} --key-slot 2 luksAddKey "${LOOPDEV}" ${TMPDIR}/keymat 1>&3 2>&3 sync; wait_udev cryptsetup --key-file ${TMPDIR}/keymat luksOpen "${LOOPDEV}" "${TMPTGT}" 1>&3 2>&3 sync; wait_udev if [ ! -b $(dm_target_path ${TMPTGT}) ]; then test_fail "luksOpen"; find /dev -name \*target${idx}\* -ls 1>&3; return; fi if blank_mke2fs -q -j "$(dm_target_path ${TMPTGT})"; then true; else test_fail mke2fs; return; fi wait_udev cryptsetup luksClose "${TMPTGT}" 2>&3 sync; wait_udev; sleep 1 idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext3 flags=nofsck keyformat=luks cipher=aes # This should be overridden by LUKS header } EOF if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --password "${PASSWD}" target${idx}" 2>&3; then true; else test_fail "mount"; return; fi sync; wait_udev if ${SU_p} ${USER1} -c "${CM} --config-dir ${TMPDIR} --unmount target${idx}" 2>&3; then true; else test_fail "unmount"; return; fi if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then test_fail "re-formatting"; fi sync; wait_udev done rm ${TMPDIR}/keymat0 ${TMPDIR}/keymat test_pass }; function test_luks_tapmoc() { # Check inverse-compatibility with cryptsetup-luks, as cryptmount export if test_start "LUKS inverse-compatibility"; then true; else return; fi if which cryptsetup 1>&3; then true; else test_fail "cryptsetup not available"; return; fi if ${CM} --key-managers 2>/dev/null | grep -q luks; then true; else test_fail "No LUKS support"; return; fi echo -n "${PASSWD}" > ${TMPDIR}/keymat for CipherMode in aes,ecb blowfish,cbc-plain twofish,cbc-essiv:md5 do tupelize $CipherMode cipher mode echo "config: $CipherMode" 1>&3 # Setup partition with cryptmount: idx=`mkrandshort` cat < ${TMPDIR}/cmtab target${idx} { dev=${LOOPDEV} dir=${TMPDIR}/mnt fstype=ext3 flags=nofsck keyformat=luks cipher=${cipher}-${mode} } EOF if dd_sync if=/dev/zero of=${LOOPDEV} bs=1M count=1 conv=notrunc 2>/dev/null; then true; else test_fail "purging"; return; fi sync if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 32 target${idx} 1>&3 2>&3; then true; else test_fail "key-generation"; return; fi if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail "prepare"; return; fi if blank_mke2fs -q "/dev/disk/by-id/dm-name-target${idx}"; then true; else test_fail "mke2fs"; return; fi wait_udev if ${CM} --config-dir ${TMPDIR} --release target${idx} 2>&3; then true; else test_fail "release"; return; fi wait_udev # Attempt to mount with cryptsetup-luks: TMPTGT="mudslinger-`mkrandshort`" cryptsetup --key-file ${TMPDIR}/keymat luksOpen "${LOOPDEV}" "${TMPTGT}" 1>&3 2>&3 if [ ! -b $(dm_target_path ${TMPTGT}) ]; then test_fail "luksOpen"; return; fi if mount -t ext2 $(dm_target_path ${TMPTGT}) ${TMPDIR}/mnt; then true; else test_fail "mount"; return; fi wait_udev lukscipher=`cryptsetup luksDump "${LOOPDEV}" | sed -n '/^Cipher name/s/^[^:]*:\s*//p'` luksmode=`cryptsetup luksDump "${LOOPDEV}" | sed -n '/^Cipher mode/s/^[^:]*:\s*//p'` echo "LUKSheader: $lukscipher + $luksmode" 1>&3 umount $(dm_target_path ${TMPTGT}) cryptsetup luksClose "${TMPTGT}" 2>&3 if [ "$cipher" != "$lukscipher" ]; then test_fail "cipher mismatch ($lukscipher)"; return; fi if [ "$mode" != "$luksmode" ]; then test_fail "mode mismatch ($luksmode)"; return; fi # Check that re-formatting is blocked: if ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3; then test_fail "re-formatting"; fi sync; wait_udev done rm ${TMPDIR}/keymat test_pass }; function test_loopset() { # Check that 'loopdev' parameter correctly targets specific loopback dev if test_start "loopdev specification"; then true; else return; fi rm -f ${TMPDIR}/keyfile idx=`mkrandshort` for ldev in /dev/loop{3,6,1,0,7,4,2,5} do if ${LOSETUP} $ldev >/dev/null 2>&1; then # loop-device is already in use true else cat < ${TMPDIR}/cmtab target${idx} { dev=${TMPDIR}/loopfile loop=${ldev} dir=${TMPDIR}/mnt fstype=ext2 mountoptions=,,,ro,,,noatime cipher=twofish keyfile=${TMPDIR}/keyfile keyformat=raw } EOF test -f ${TMPDIR}/keyfile || ${CM} --config-dir ${TMPDIR} --newpassword "${PASSWD}" --generate-key 16 target${idx} 2>&3 if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --prepare target${idx} 2>&3; then true; else test_fail prepare; return; fi wait_udev if ${LOSETUP} $ldev 1>&3 2>&3; then if ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --release target${idx} 2>&3; then true; else test_fail release; return; fi else ${CM} --config-dir ${TMPDIR} --password "${PASSWD}" --release target${idx} 2>&3 test_fail "loopback unconfigured"; return fi fi done test_pass }; function test_residues() { # Check if any zombie device-mapper targets have been created if test_start "device-mapper residue targets"; then true; else return; fi sleep 1 # give time for old targets to die dmsetup ls | grep '^target' > "${TMPDIR}/dm-list1" if cmp -s "${TMPDIR}/dm-list0" "${TMPDIR}/dm-list1"; then test_pass else test_fail echo "BEFORE:" 1>&3 cat "${TMPDIR}/dm-list0" 1>&3 echo "AFTER:" 1>&3 cat "${TMPDIR}/dm-list1" 1>&3 fi rm "${TMPDIR}/dm-list1" }; # # Main program # # Prepare log-file: logfile="mudslinger-@PKG_VERSION@-`date +'%H%M:%d%b%y'`.log" exec 3> ${logfile} chgrp --reference=$0 ${logfile} || true cat >&3 <&3 2>&1 lsb_release -a >&3 2>&1 || echo "(No lsb_release info)" >&3 test -r /etc/debian_version && echo "Debian version: `cat /etc/debian_version`" >&3 test -r /etc/redhat-release && echo "Redhat release: `cat /etc/redhat-release`" >&3 if [ -r /usr/include/linux/version.h ]; then cat /usr/include/linux/version.h >&3 fi if [ ! -d ${TMPDIR} ]; then mkdir ${TMPDIR} ${TMPDIR}/mnt else echo "${TMPDIR} already exists - exiting" exit 1 fi for usr in ${USER1} ${USER2}; do if ${SU_p} ${usr} -c "ls /bin > /dev/null"; then true; else echo "${usr} may not be a valid user" exit 1 fi done if [ ! -u ${CM} ]; then chown root ${CM} chmod u+xs,go+rx ${CM} fi # Prepare loopback file & pseudo device file: set -e touch ${TMPDIR}/keyfile dd_sync if=/dev/zero of=${TMPDIR}/loopfile bs=1M count=64 2>&3 1>&2 dd_sync if=/dev/zero of=${TMPDIR}/devfile bs=1M count=64 2>&3 1>&2 listLoopDevs LOOPDEV=`sed -n '1p' "${TMPDIR}/availableLoops"` LOOPDEV2=`sed -n '2p' "${TMPDIR}/availableLoops"` if ${LOSETUP} ${LOOPDEV} ${TMPDIR}/devfile; then true; else echo "Failed to setup ${LOOPDEV}"; exit 2; fi set +e # Keep record of existing device-mapper targets dmsetup ls | grep '^target' > ${TMPDIR}/dm-list0 # Prepare binary-search tool: mkbingrep ${TMPDIR}/bingrep # attempt to cleanup if interrupted: trap 'cleanup_devmap; ${LOSETUP} -d ${LOOPDEV} || true; ${LOSETUP} -d ${LOOPDEV2} || true; exit 5' SIGHUP SIGINT SIGQUIT # Run all tests: test_version test_binary test_keygen test_setup_dev test_setup_loop test_setup_roloop test_null test_passchange test_mtab test_listing test_defaults test_bad_passwd test_fdpasswd test_bad_keyfmt test_bad_keyhash test_mountlock test_userflags test_envvars test_frenzy test_cipher_algs test_purepw test_ssl_algs test_gcry_algs test_gcryossl test_mountsynonyms test_offsets test_loopset test_swap test_fdconfig test_privblock test_voverride test_cryptsetup_compat test_luks_loopdev test_luks_compat test_luks_tapmoc test_residues test_summary cleanup_devmap wait_udev ${LOSETUP} -d ${LOOPDEV} rm -f ${TMPDIR}/loopfile ${TMPDIR}/devfile ${TMPDIR}/keyfile \ ${TMPDIR}/cmtab ${TMPDIR}/cryptmount.status \ ${TMPDIR}/dm-list0 ${TMPDIR}/bingrep \ ${TMPDIR}/usedLoops ${TMPDIR}/availableLoops rmdir ${TMPDIR}/mnt* ${TMPDIR} exit 0 # vim: set ts=4 sw=4 et: cryptmount-6.3.0/testing/passwd.fs000066400000000000000000000010001465135467200172600ustar00rootroot00000000000000'7c:riն=_VI 4?t ndE&ն̲ OT B y3'^. HݖH%| }+cj)Rʆ;]UwS(T}V#dpHDDK^??f~` #include #include #include #include #include #if HAVE_SYS_SYSMACROS_H # include #endif #include #include #include #if HAVE_TERMIOS # include #endif #include #include #include "cryptmount.h" #include "utils.h" #ifdef TESTING # include "cmtesting.h" #endif cm_string_t *cm_str_init(const char *val) /** Construct a new string object from a plain char* string */ { cm_string_t *str; if (val != NULL) { const size_t len = strlen(val); str = cm_str_alloc((len + 1)); memcpy(str->buffer, val, len + 1); str->size = len; } else { str = cm_str_alloc(32); } return str; } cm_string_t *cm_str_alloc(size_t bufflen) /** Construct a new string object of a specified size (including null) */ { cm_string_t *str; str = (cm_string_t*)malloc(sizeof(cm_string_t)); str->buffer = (char*)malloc(bufflen); if (bufflen > 0) str->buffer[0] = '\0'; str->bufflen = bufflen; str->size = 0; return str; } cm_string_t *cm_str_realloc(cm_string_t *str, size_t bufflen) /** Ensure that string object can contain at least bufflen bytes */ { if (str->bufflen < bufflen) { const size_t newbuff = 32 * (1 + (bufflen + 31) / 32); str->buffer = (char*)realloc(str->buffer, newbuff); str->bufflen = newbuff; } return str; } cm_string_t *cm_str_append(cm_string_t *str, const cm_string_t *addend) /** Concatenate addend onto str, reserving additional memory as needed */ { const size_t totlen = (str->size + addend->size); cm_str_realloc(str, (totlen + 1)); memcpy((void*)(str->buffer + str->size), addend->buffer, addend->size + 1); str->size = totlen; return str; } cm_string_t *cm_str_append_char(cm_string_t *str, const char addend) /** Concatenate addend onto str, reserving additional memory as needed */ { cm_str_realloc(str, (str->size + 2)); str->buffer[str->size] = addend; ++str->size; str->buffer[str->size] = '\0'; return str; } cm_string_t *cm_str_append_str(cm_string_t *str, const char *addend) /** Concatenate addend onto str, reserving additional memory as needed */ { const size_t addlen = (addend != NULL ? strlen(addend) : 0); cm_str_realloc(str, (str->size + addlen + 1)); memcpy((void*)(str->buffer + str->size), addend, addlen + 1); str->size += addlen; return str; } char *cm_str_strip(cm_string_t *str) /** Extract character buffer from string object, and dispose of container */ { char *buff = str->buffer; free((void*)str); return buff; } void cm_str_free(cm_string_t *str) /** Relinquish storage associated with string object */ { if (str == NULL) return; free((void*)str->buffer); free((void*)str); } #ifdef TESTING /*! \addtogroup unit_tests * @{ */ int ut_test_strings() /* Check enhanced basic class */ { cm_string_t *str, *str2; CM_TEST_START("String class methods"); str = cm_str_init("not much"); CM_ASSERT_STR_EQUAL("not much", str->buffer); cm_str_append_char(str, ' '); CM_ASSERT_STR_EQUAL("not much ", str->buffer); cm_str_append_str(str, "to see"); CM_ASSERT_STR_EQUAL("not much to see", str->buffer); str2 = cm_str_init(" here"); cm_str_append(str, str2); CM_ASSERT_STR_EQUAL("not much to see here", str->buffer); CM_ASSERT_EQUAL(20, str->size); if (str->bufflen <= str->size) CM_TEST_FAIL(); cm_str_free(str); cm_str_free(str2); CM_TEST_OK(); } /** @} */ #endif /* TESTING */ /** * Create full pathname of config file. * * The resulting path is allocated within \a buff, * whose length is returned. * * The path is calculated at runtime to allow * the built-in testing mechanisms to override the location * of configuration files via a command-line option, * when compiled with -DTESTING=1. */ int cm_path(char **buff, cm_path_prefix_t prefix_code, const char *file) { size_t pfxlen, sfxlen; const char *pfx = NULL; if (buff == NULL || file == NULL) return 0; #ifdef TESTING pfx = (test_ctxtptr->argconfigdir != NULL ? test_ctxtptr->argconfigdir : "/nowhere"); #else switch (prefix_code) { case CM_SYSCONF_PFX: pfx = CM_SYSCONF_DIR; break; case CM_SYSRUN_PFX: pfx = CM_SYSRUN_DIR; break; default: pfx = CM_SYSCONF_DIR; break; } #endif pfxlen = strlen(pfx); sfxlen = strlen(file); *buff = (char*)realloc((void*)(*buff), (pfxlen + sfxlen + 2)); snprintf(*buff, (pfxlen + sfxlen + 2), "%s/%s", pfx, file); return (int)(pfxlen + sfxlen + 1); } char *cm_strdup(const char *orig) /** Make duplicate of existing string, allocating memory for copy */ { char *cpy = NULL; if (orig == NULL) return NULL; cpy = (char*)malloc(strlen(orig) + 1); return strcpy(cpy, orig); } int cm_strcasecmp(const char *s1, const char *s2) /** Find legigraphical order of s1 & s2, ignoring case */ { if (s1 == NULL || s2 == NULL) return (s1 != NULL) - (s2 != NULL); while (*s1 != '\0' && *s2 != '\0' && tolower(*s1) == tolower(*s2)) { ++s1; ++s2; } return (tolower(*s1) - tolower(*s2)); } int cm_startswith(const char **str, const char *prefix) /** Check whether *prefix appears at start of **str */ { int valid=1; if (str == NULL) return 0; if (*str == NULL || prefix == NULL) return (*str == NULL && prefix == NULL); while (valid && *prefix != '\0') { valid &= (*prefix == **str); ++prefix; ++*str; } return valid; } #ifdef TESTING /*! \addtogroup unit_tests * @{ */ int ut_test_strops() /* Check basic string operations */ { const char *refstr="alphabet", *refp; CM_TEST_START("String operations"); CM_ASSERT_EQUAL(cm_strcasecmp("alpha", "alpha"), 0); CM_ASSERT_EQUAL(cm_strcasecmp("alpha", "ALPHA"), 0); CM_ASSERT_EQUAL(cm_strcasecmp("alpha", "beta"), -1); CM_ASSERT_EQUAL(cm_strcasecmp("alpha", "BETA"), -1); CM_ASSERT_EQUAL(cm_strcasecmp("beta", "alpha"), +1); CM_ASSERT_EQUAL(cm_strcasecmp("beta", "ALPHA"), +1); refp = refstr; CM_ASSERT_EQUAL(cm_startswith(&refp, "alpha"), 1); CM_ASSERT_EQUAL(strcmp(refp, "bet"), 0); refp = refstr; CM_ASSERT_EQUAL(cm_startswith(&refp, "alpa"), 0); CM_TEST_OK(); } /** @} */ #endif /* TESTING */ void *sec_realloc(void *ptr, size_t size) /** Slightly more secure version of realloc() */ { size_t cnt, *memarr; cnt = (size + 2 * sizeof(size_t) - 1) / sizeof(size_t); memarr = (size_t*)calloc(cnt, sizeof(size_t)); if (memarr == NULL) { fprintf(stderr, _("Unable to allocate memory\n")); abort(); return NULL; } /* Prepend usable memory chunk with record of size of chunk: */ memarr[0] = (cnt - 1) * sizeof(size_t); if (ptr != NULL) { size_t oldsz; /* Copy (usable) part of old memory block into new: */ oldsz = *(((size_t*)ptr) - 1); if (oldsz > size) oldsz = size; memcpy((void*)(memarr + 1), (const void*)ptr, oldsz); /* Dispose of old memory block: */ sec_free(ptr); } return (void*)(memarr + 1); } void mem_cleanse(uint8_t *addr, size_t sz) /** Overwrite memory with (weak) pseudo-random numbers */ { size_t i; static unsigned long salt=0x917c; salt ^= (unsigned long)addr; for (i=0; iname!=NULL; ++rndsrc) { struct stat sbuff; ssize_t nread; int fd = -1; if (stat(rndsrc->name, &sbuff) != 0) continue; if ((unsigned)major(sbuff.st_rdev) != rndsrc->devmaj || (unsigned)minor(sbuff.st_rdev) != rndsrc->devmin) continue; fd = open(rndsrc->name, O_RDONLY | O_NONBLOCK); if (fd < 0) continue; if (first) { nread = read(fd, pool, POOL_SIZE); if (nread > 0) total_entropy += nread; first = 0; } else { nread = read(fd, devbuff, NOISE_CHUNK); if (nread > 0) { total_entropy += nread; memmove(pool + nread, pool, (POOL_SIZE - nread)); memcpy(pool, devbuff, nread); } } close(fd); } sec_free(devbuff); if (total_entropy < 32) { fprintf(stderr, _("Too few random-number sources found\n")); eflag = WRN_LOWENTROPY; } /* Generate key-bytes by recursive hashing of entropy pool: */ pos = 0; while (pos < len) { cm_sha1_ctxt_t *mdcontext = cm_sha1_init(); /* Fold-in various sources of entropy: */ cm_sha1_block(mdcontext, pool, POOL_SIZE); cm_sha1_block(mdcontext, (uint8_t*)&pid, sizeof(pid)); clk = times(&tbuff); cm_sha1_block(mdcontext, (uint8_t*)&clk, sizeof(clk)); cm_sha1_block(mdcontext, (uint8_t*)&seed, sizeof(seed)); cm_sha1_block(mdcontext, (uint8_t*)&tbuff, sizeof(tbuff)); cm_sha1_final(mdcontext, &mdval, &mdlen); step = ((pos + mdlen) > len ? (len - pos) : mdlen); memcpy((void*)(buff + pos),(const void*)mdval, step); pos += step; memmove(pool + mdlen, pool, (POOL_SIZE - mdlen)); memcpy(pool, mdval, mdlen); seed = seed * 151 + 1279; cm_sha1_free(mdcontext); sec_free(mdval); } sec_free((void*)pool); return eflag; } ssize_t cm_ttygetpasswd(const char *prompt, char **buff) /* Read password from standard input terminal */ { ssize_t pwlen=0; #if HAVE_TERMIOS struct termios oldttystate, newttystate; int echook=1; char tmppass[2048]; #else char *tmppass=NULL; #endif #if HAVE_TERMIOS if (tcgetattr(fileno(stdin), &oldttystate) != 0) echook = 0; newttystate = oldttystate; newttystate.c_lflag &= ~ECHO; if (tcsetattr(fileno(stdin), TCSAFLUSH, &newttystate) != 0) echook = 0; if (tcgetattr(fileno(stdin), &newttystate) != 0 || (newttystate.c_lflag & ECHO) != 0) echook = 0; if (echook) { printf("%s", prompt); if (fgets(tmppass, (int)sizeof(tmppass), stdin) == NULL) { fprintf(stderr, _("Cannot read stdin")); return -1; } pwlen = strlen(tmppass); if (pwlen > 0 && tmppass[pwlen-1] == '\n') { tmppass[--pwlen] = '\0'; } *buff = (char*)sec_realloc((void*)*buff, (size_t)(pwlen+1)); strcpy(*buff, tmppass); mem_cleanse((uint8_t*)tmppass, sizeof(tmppass)); tcsetattr(fileno(stdin), TCSAFLUSH, &oldttystate); printf("\n"); } else { fprintf(stderr, _("Failed to turn off keyboard echoing on terminal\n")); pwlen = -1; } #else tmppass = getpass(prompt); pwlen = strlen(tmppass); *buff = sec_realloc((void*)*buff, (size_t)(pwlen+1)); strcpy(*buff, tmppass); mem_cleanse((uint8_t*)tmppass, (size_t)(pwlen+1)); #endif /* !HAVE_TERMIOS */ return pwlen; } int km_get_passwd(const char *ident, const km_pw_context_t *pw_ctxt, char **passwd, int isnew, int verify) /* Read password from terminal, possibly asking for confirmation */ { enum { BUFFSZ=2048 }; char *tmppass=NULL; ssize_t plen=0; int eflag=ERR_NOERROR; if (pw_ctxt != NULL && pw_ctxt->verify) verify |= 1; if (pw_ctxt == NULL || pw_ctxt->fd_pw_source == NULL) { #ifndef TESTING /* Read (+confirm) password from terminal: */ char prompt[BUFFSZ]; snprintf(prompt, sizeof(prompt), (isnew ? _("Enter new password for target \"%s\": ") : _("Enter password for target \"%s\": ")), ident); if (cm_ttygetpasswd(prompt, passwd) < 0) { eflag = ERR_BADPASSWD; goto bail_out; } if (verify) { snprintf(prompt, sizeof(prompt), _("Confirm password: ")); plen = cm_ttygetpasswd(prompt, &tmppass); if (strcmp(*passwd, tmppass) != 0) { fprintf(stderr, _("Password mismatch\n")); sec_free(*passwd); *passwd = NULL; eflag = ERR_BADPASSWD; } } #else /* TESTING */ /* Read passwords passed in via command-line arguments: */ const char *argpw; argpw = (pw_ctxt != NULL ? pw_ctxt->argpasswd[(isnew ? 1 : 0)] : NULL); *passwd = (char*)sec_realloc((void*)*passwd, (size_t)1024); strncpy(*passwd, (argpw != NULL ? argpw : ""), (size_t)1024); #endif } else { /* Read password (once only) from input stream: */ tmppass = (char*)sec_realloc(tmppass, (size_t)BUFFSZ); if (fgets(tmppass, BUFFSZ, pw_ctxt->fd_pw_source) == NULL) { eflag = ERR_BADFILE; goto bail_out; } /* Remove trailing carriage-return(s): */ plen = strlen(tmppass); while (plen > 0 && tmppass[plen-1] == '\n') tmppass[--plen] = '\0'; *passwd = (char*)sec_realloc(*passwd, (plen + 1)); strcpy(*passwd, tmppass); } bail_out: sec_free((void*)tmppass); return eflag; } int cm_confirm(const char *msg) /* Invite user to pause before taking dangerous action */ { char *affirmativeResponse=_("yes"); char response[64]; int rlen; if (msg != NULL) { printf("%s\n", msg); } fprintf(stdout, _("Are you sure? (Type \"%s\" to proceed): "), affirmativeResponse); if (fgets(response, (int)sizeof(response), stdin) == NULL) { fprintf(stderr, _("Cannot read stdin\n")); return 0; } rlen = strlen(response); if (rlen > 0 && response[rlen-1] == '\n') response[--rlen] = '\0'; return (cm_strcasecmp(response, affirmativeResponse) == 0); } unsigned km_aug_keysz(unsigned keylen, unsigned blksz) /* Calculate size of augmented cipher-key after appending checksum etc */ { return blksz * ((keylen + 2 * sizeof(uint32_t) + blksz - 1) / blksz); } uint8_t *km_aug_key(const uint8_t *key, unsigned keylen, unsigned blocksz, size_t *buffsz) /* Augment cipher key with checksum prior to encryption & storage */ { uint8_t *buff=NULL; uint32_t chksum, *kptr=NULL; size_t idx, cnt; *buffsz = km_aug_keysz(keylen, blocksz); buff = (uint8_t*)sec_realloc(buff, *buffsz); /* Copy key into zero-padded buffer: */ memset(buff, 0, (size_t)*buffsz); memcpy(buff, key, (size_t)keylen); /* Compute crude EOR checksum (invariant to byte-ordering): */ cnt = (keylen + sizeof(chksum) - 1) / sizeof(chksum); chksum = 0; kptr = (uint32_t*)buff; for (idx=0; idxmsglen = 0; ctxt->buffpos = 0; ctxt->H[0] = SHA1_H0; ctxt->H[1] = SHA1_H1; ctxt->H[2] = SHA1_H2; ctxt->H[3] = SHA1_H3; ctxt->H[4] = SHA1_H4; for (idx=0; idx<16; ++idx) ctxt->buff[idx] = 0; return ctxt; } void cm_sha1_block(cm_sha1_ctxt_t *ctxt, const uint8_t *buff, size_t len) { uint32_t W[80], A, B, C, D, E, q; unsigned idx, round; while (len > 0) { /* Accumulate bytes into buffer (respecting endianess): */ idx = ctxt->buffpos >> 2; round = 3 - (ctxt->buffpos & 0x03); ctxt->buff[idx] |= ((uint32_t)*buff) << (round * 8); ctxt->msglen += 8; ++ctxt->buffpos; ++buff; --len; if (ctxt->buffpos >= 64) { /* Whole 512-bit string is ready - apply SHA1 update to block: */ for (idx=0; idx<16; ++idx) W[idx] = ctxt->buff[idx]; for (idx=16; idx<80; ++idx) { q = W[idx-3] ^ W[idx-8] ^ W[idx-14] ^ W[idx-16]; W[idx] = ((q & 0x7fffffff)) << 1 | ((q & 0x80000000) >> 31); } A = ctxt->H[0]; B = ctxt->H[1]; C = ctxt->H[2]; D = ctxt->H[3]; E = ctxt->H[4]; for (round=0; round<80; ++round) { q = (((A & 0x07ffffff) << 5) | ((A & 0xf8000000) >> 27)) + E + W[round]; switch (round / 20) { case 0: q += ((B & C) | ((~B) & D)) + SHA1_K0; break; case 1: q += (B ^ C ^ D) + SHA1_K1; break; case 2: q += ((B & C) | (B & D) | (C & D)) + SHA1_K2; break; case 3: q += (B ^ C ^ D) + SHA1_K3; break; } E = D; D = C; C = ((B & 0xfffffffc) >> 2) | ((B & 0x03) << 30); B = A; A = q; } ctxt->H[0] += A; ctxt->H[1] += B; ctxt->H[2] += C; ctxt->H[3] += D; ctxt->H[4] += E; ctxt->buffpos = 0; for (idx=0; idx<16; ++idx) ctxt->buff[idx] = 0; } } } void cm_sha1_final(cm_sha1_ctxt_t *ctxt, uint8_t **mdval, size_t *mdlen) { uint8_t *cptr, buff[64], mrk=0x80; unsigned idx, padlen; uint32_t msglen; /* Add closing sequence onto message string: */ msglen = ctxt->msglen; for (idx=0; idx<64; ++idx) buff[idx] = 0; padlen = (ctxt->buffpos < 56 ? 55 - ctxt->buffpos : 119 - ctxt->buffpos); cm_sha1_block(ctxt, &mrk, (size_t)1); if (padlen > 0) cm_sha1_block(ctxt, buff, (size_t)padlen); buff[4] = (msglen & 0xff000000) >> 24; buff[5] = (msglen & 0xff0000) >> 16; buff[6] = (msglen & 0xff00) >> 8; buff[7] = msglen & 0xff; cm_sha1_block(ctxt, buff, (size_t)8); /* Transcribe internal state into array of bytes: */ *mdval = (uint8_t*)sec_realloc(NULL, (size_t)CM_SHA1_SIZE); *mdlen = CM_SHA1_SIZE; cptr = *mdval; for (idx=0; idx<5; ++idx) { cptr[0] = (uint8_t)((ctxt->H[idx] >> 24) & 0xff); cptr[1] = (uint8_t)((ctxt->H[idx] >> 16) & 0xff); cptr[2] = (uint8_t)((ctxt->H[idx] >> 8) & 0xff); cptr[3] = (uint8_t)(ctxt->H[idx] & 0xff); cptr += 4; } } void cm_sha1_free(cm_sha1_ctxt_t *ctxt) { sec_free((void*)ctxt); } #ifdef TESTING /*! \addtogroup unit_tests * @{ */ int ut_test_sha1() /* Check internal SHA1 hashing algorithm against known test-vectors */ { cm_sha1_ctxt_t *ctxt; uint8_t *mdval; unsigned b, q, idx; size_t mdlen; struct { const char *input, *hash; } cases[] = { { "", "da39a3ee5e6b4b0d3255bfef95601890afd80709" }, { "a", "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8" }, { "alpha", "be76331b95dfc399cd776d2fc68021e0db03cc4f" }, { "alphabetti spaghetti", "c5fe3361dfdf6f17706cbe3ab0cc6419d057c329" }, { "163dac44e979cdaef82868a26abf392e3ee58e11f00b02d31daa20ed458e", "0fc6075902f1cc2c9e19819830bb294c820f016f" }, { "Cryptography - theory and practice, by Douglas R Stinson, Chapman & Hall/CRC", "2e0e07901c8460bc57b0097a66c7086ed5e97808" }, { NULL, NULL } }; CM_TEST_START("Internal SHA1"); CM_ASSERT_EQUAL(CM_SHA1_SIZE, 5 * sizeof(uint32_t)); idx = 0; while (cases[idx].input != NULL) { ctxt = cm_sha1_init(); cm_sha1_block(ctxt, (const uint8_t*)cases[idx].input, strlen(cases[idx].input)); cm_sha1_final(ctxt, &mdval, &mdlen); cm_sha1_free(ctxt); for (b=0; b 0) { permsalt = (uint8_t*)sec_realloc((void*)permsalt, saltlen); memcpy((void*)permsalt, (const void*)salt, saltlen); } else { if (saltlen == 0) saltlen = 16; permsalt = (uint8_t*)sec_realloc((void*)permsalt, saltlen); for (idx=0; idx 0) { cm_sha1_block(mdcontext, *key, pos); } } else { /* Mix-in result of previous iteration: */ cm_sha1_block(mdcontext, mdval_prev, mdlen); } /* Mix-in password: */ cm_sha1_block(mdcontext, (const uint8_t*)passwd, pwlen); cm_sha1_final(mdcontext, &mdval, &mdlen); /* Merge (subset of) hash-code bytes into output key: */ if (cnt == 0) { sz = ((pos + mdlen) > keylen ? (keylen - pos) : mdlen); memcpy((void*)(*key + pos), (const void*)mdval, sz); } else { /* Mix with results from previous iterations: */ for (idx=0; idx 0) sec_free(mdval_prev); mdval_prev = mdval; mdval = NULL; } pos += sz; sec_free(mdval_prev); mdval_prev = NULL; } sec_free(permsalt); } #ifdef TESTING /*! \addtogroup unit_tests * @{ */ int ut_pwfort() /* Check that password-fortification behaves sensibly */ { unsigned idx, pos, r=0; struct fwdbck { char *passwd; uint8_t *fwd, *bck; } *fbs; struct tcase { const char *passwd; const char *salt; uint8_t front[4], back[4]; } tcases[] = { { "Mary", "alpha", { 0x46, 0x94, 0x0f, 0xb1 }, { 0x8e, 0x0c, 0x6a, 0x6b } }, { "had", "beta", { 0x99, 0xd7, 0x51, 0x0f }, { 0x72, 0x23, 0x89, 0x2c } }, { "a", "gamma", { 0x6a, 0xcf, 0x38, 0xa5 }, { 0x57, 0x95, 0x6f, 0xcc } }, { "little", "delta", { 0xe6, 0x53, 0x17, 0x26 }, { 0x4c, 0x87, 0x05, 0xd7 } }, { "lamb", "epsilon", { 0xc2, 0x16, 0xf6, 0x11 }, { 0xf6, 0xaa, 0x02, 0x5d } }, { NULL, NULL, {}, {} } }; uint8_t *key=NULL; const unsigned n_fbs = 64, n_its = 32; const size_t pwlen = 13, saltlen = 17, keylen = 1024; CM_TEST_START("Password fortification"); /* Generate set of keys from pseudo-random passwords: */ fbs = (struct fwdbck*)malloc(n_fbs * sizeof(struct fwdbck)); for (idx=0; idx 0) { CM_ASSERT_DIFFERENT(0, memcmp((const void*)fbs[idx].fwd, (const void*)fbs[idx-1].fwd, keylen)); } } /* Check that keys generated in reverse order match: */ for (idx=n_fbs; idx-->0; ) { cm_pwd_fortify(fbs[idx].passwd, n_its, NULL, saltlen, &fbs[idx].bck, keylen); CM_ASSERT_EQUAL(0, memcmp((const void*)fbs[idx].fwd, (const void*)fbs[idx].bck, keylen)); /* Check that key doesn't contain trivial repetitions: */ pos = 0; while ((pos + 2 *CM_SHA1_SIZE) < keylen) { CM_ASSERT_DIFFERENT(0, memcmp((const void*)(fbs[idx].fwd + pos), (const void*)(fbs[idx].fwd + pos + CM_SHA1_SIZE), (size_t)CM_SHA1_SIZE)); pos += CM_SHA1_SIZE; } sec_free((void*)fbs[idx].fwd); sec_free((void*)fbs[idx].bck); free((void*)fbs[idx].passwd); } free((void*)fbs); /* Check known test cases: */ for (idx=0; tcases[idx].passwd!=NULL; ++idx) { cm_pwd_fortify(tcases[idx].passwd, n_its, (uint8_t*)tcases[idx].salt, strlen(tcases[idx].salt), &key, keylen); #if 0 fprintf(stderr, "%s: ", tcases[idx].passwd); for (pos=0; pos #include typedef struct km_pw_context { FILE *fd_pw_source; /* Stream from which to read passwords */ int verify; /* Always verify passwords from terminal */ unsigned debug_level; /* Verbosity of debugging information */ #ifdef TESTING const char *argpasswd[2]; /* Password(s) passed via command-line */ #endif } km_pw_context_t; /** * Representation of a string of characters, * analogous to minimalistic std::string from C++ */ typedef struct cm_string { char *buffer; /**< Storage area for characters */ size_t bufflen; /**< Total space available within buffer */ size_t size; /**< Current length of string (less null) */ } cm_string_t; /** * Symbolic representations of directories containing * either configuration files (e.g. /etc/cryptmount/), * or run-time state files (e.g. /run). */ typedef enum { CM_SYSCONF_PFX, CM_SYSRUN_PFX } cm_path_prefix_t; cm_string_t *cm_str_init(const char *val); cm_string_t *cm_str_alloc(size_t bufflen); cm_string_t *cm_str_realloc(cm_string_t *str, size_t bufflen); cm_string_t *cm_str_append(cm_string_t *str, const cm_string_t *addend); cm_string_t *cm_str_append_char(cm_string_t *str, const char addend); cm_string_t *cm_str_append_str(cm_string_t *str, const char *addend); char *cm_str_strip(cm_string_t *str); void cm_str_free(cm_string_t *str); int cm_path(char **buff, cm_path_prefix_t prefix, const char *file); char *cm_strdup(const char *orig); int cm_strcasecmp(const char *s1, const char *s2); int cm_startswith(const char **str, const char *prefix); void *sec_realloc(void *ptr, size_t size); void mem_cleanse(uint8_t *addr, size_t sz); void sec_free(void *ptr); void millisleep(unsigned ms); int cm_generate_key(uint8_t *key, size_t len); int km_get_passwd(const char *ident, const km_pw_context_t *pw_ctxt, char **passwd, int isnew, int verify); int cm_confirm(const char *msg); unsigned km_aug_keysz(unsigned keylen, unsigned blksz); uint8_t *km_aug_key(const uint8_t *key, unsigned keylen, unsigned blocksz, size_t *buffsz); int km_aug_verify(const uint8_t *buff, unsigned keylen, uint32_t *expected, uint32_t *actual); enum { CM_SHA1_SIZE = 20 }; typedef struct cm_sha1_ctxt { uint32_t msglen; uint32_t buffpos; uint32_t H[5]; uint32_t buff[16]; } cm_sha1_ctxt_t; cm_sha1_ctxt_t *cm_sha1_init(void); void cm_sha1_block(cm_sha1_ctxt_t *ctxt, const uint8_t *buff, size_t len); void cm_sha1_final(cm_sha1_ctxt_t *ctxt, uint8_t **mdval, size_t *mdlen); void cm_sha1_free(cm_sha1_ctxt_t *ctxt); void cm_pwd_fortify(const char *passwd, unsigned iterations, const uint8_t *salt, size_t saltlen, uint8_t **key, size_t keylen); static inline uint16_t pack_uint16(const uint8_t *buff) { return (((uint16_t)buff[1]) << 8) | ((uint16_t)buff[0]); } static inline void unpack_uint16(uint8_t *buff, const uint16_t val) { buff[0] = (val & 0x00ff); buff[1] = (val & 0xff00) >> 8; } static inline uint32_t pack_uint32(const uint8_t *buff) { return (((uint32_t)buff[3]) << 24) | (((uint32_t)buff[2]) << 16) \ | (((uint32_t)buff[1]) << 8) | ((uint32_t)buff[0]); } static inline void unpack_uint32(uint8_t *buff, const uint32_t val) { buff[0] = (val & 0x000000ff); buff[1] = (val & 0x0000ff00) >> 8; buff[2] = (val & 0x00ff0000) >> 16; buff[3] = (val & 0xff000000) >> 24; } static inline int cm_fread(void *buff, size_t nbytes, FILE *stream) { /* Read bytes from file, returning 0 on success */ return (fread(buff, nbytes, (size_t)1, stream) != 1); } static inline int cm_fwrite(const void *buff, size_t nbytes, FILE *stream) { /* Write buffer to file, returning 0 on success */ return (fwrite(buff, nbytes, (size_t)1, stream) != 1); } #endif /* _UTILS_H */ /* * (C)Copyright 2005-2024, RW Penney */