pax_global_header00006660000000000000000000000064134214217440014514gustar00rootroot0000000000000052 comment=c526858186db8ba67e7ea9c836d3a6f0c59e041b sbsigntool-0.9.2/000077500000000000000000000000001342142174400137075ustar00rootroot00000000000000sbsigntool-0.9.2/AUTHORS000066400000000000000000000003001342142174400147500ustar00rootroot00000000000000Authors of sbsigntool: Adam Conrad Ard Biesheuvel Ben Hutchings Guy Lunardi Ivan Hu James Bottomley Jeremy Kerr Linn Crosetto Mathieu Trudel-Lapierre Maxim Kammerer Steve Langasek sbsigntool-0.9.2/COPYING000066400000000000000000000030321342142174400147400ustar00rootroot00000000000000sbsigntool - utilities for signing UEFI binaries for use with secure boot. (c) 2012 by Jeremy Kerr, Canonical Ltd. 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but is provided AS IS, WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and NON-INFRINGEMENT. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. sbsigntool-0.9.2/ChangeLog000066400000000000000000000431011342142174400154600ustar00rootroot000000000000002019-01-09 6082c13 James Bottomley * Version 0.9.2 2019-01-09 f770423 James Bottomley * src/image.c: remove alignment of regions 2019-01-09 7d0af72 James Bottomley * sbvarsign: use SignedData instead of PKCS7 for authenticated updates 2018-02-20 bfa0e2a Guy Lunardi * Fix Fedora Build 2017-10-28 7c5ae40 James Bottomley * Version 0.9.1 2017-10-28 dd0cdb0 James Bottomley * sbsign, sbvarsign: support engine based private keys 2017-10-19 5dbccc0 James Bottomley * Version 0.9 2017-10-19 ecb0bb9 James Bottomley * Fix Debian 8 and Leap_42.1 builds 2017-10-19 da9e173 James Bottomley * tests: Fix up to work on arbitrary architectures 2017-10-18 e755471 James Bottomley * tests/detach-remove.sh: fix for i386 pecoff size problems 2017-10-18 a982caf James Bottomley * tests: fix up the generation of the test pecoff binary for gcc-7.2 2017-10-18 9695384 James Bottomley * tests: fix signature resign/reattach test problems 2016-06-26 a674a7e Ben Hutchings * Update OpenSSL API usage to support OpenSSL 1.1 2017-10-18 be46e95 James Bottomley * make check: fix test environment problem 2016-11-16 51cd64b James Bottomley * Add OPENSSL_config(NULL) to each binary to load openssl.cnf 2016-02-14 81a96b3 James Bottomley * Version: 0.8 2016-02-12 69d05ff James Bottomley * sbkeysync: don't include efi.h 2016-02-12 38575ff James Bottomley * configure: build on arm 2016-01-27 cf9a310 Mathieu Trudel-Lapierre * sbverify: Clear out content for the signature we're building 2015-10-27 b213bf3 Linn Crosetto * Handle odd buffer lengths in checksum 2015-07-15 ce3550b Steve Langasek * Support openssl 1.0.2b and above 2016-01-27 29639fd Ard Biesheuvel * sbsigntool: add support for ARM and Aarch64 PE/COFF images 2016-01-27 59edca1 Ard Biesheuvel * sbsigntool: fix handling of zero sized sections 2016-01-27 f5825a2 Ard Biesheuvel * sbsigntool: remove doubly defined IMAGE_FILE_MACHINE_AMD64 2016-01-27 0a7024f James Bottomley * sbverify: add extra expiry errors to ignore 2016-01-27 2090a6c Steve Langasek * Update the PE checksum field using the somewhat-underdocumented algorithm, so that we match the Microsoft implementation in our signature generation. 2015-01-06 67e3771 James Bottomley * OBS add correcting definition of EFI_ARCH 2014-12-19 af00687 James Bottomley * Version 0.7 2014-12-19 39333a3 James Bottomley * sbsign, sbattach, sbverify: add multiple signature support 2014-12-19 a5be9e5 James Bottomley * sbverify: fix verification 2014-12-19 c6caf1b James Bottomley * Clear ssl errors after loading everyting 2013-09-30 a482ebd James Bottomley * Fix for multi-sign 2013-04-11 00271cd James Bottomley * image.c: clear image variable 2012-11-13 130b244 Jeremy Kerr * sbkeysync: add corrected efivars magic 2012-10-11 ce3498a Jeremy Kerr * Version 0.6 2012-10-10 7c4465c Jeremy Kerr * sbverify: explicitly trust all certificates given in --cert arguments 2012-10-10 2038c41 Jeremy Kerr * sbverify: Add --verbose option 2012-10-10 86219ed Jeremy Kerr * Version 0.5 2012-10-08 aa60392 Jeremy Kerr * sbkeysync: change default efivarfs mountpoint to /sys/.../efivars/ 2012-10-02 53d38e7 Jeremy Kerr * Version 0.4 2012-10-02 e8a2989 Jeremy Kerr * image: improve handling of unaligned section tables 2012-10-02 c6996fc Jeremy Kerr * image: use data_size in cert table header 2012-09-28 01d2aa4 Jeremy Kerr * image: improve section table parsing 2012-09-28 22fa5ba Jeremy Kerr * image: Allow variable sized data directories 2012-09-05 027bde0 Jeremy Kerr * sbvarsign: fix incorrect pointer in add_auth_descriptor 2012-09-05 8a9366d Jeremy Kerr * sbvarsign: auth descriptor hash does not cover the \0 in the varname 2012-08-24 6a56400 Jeremy Kerr * sbkeysync: fix siglist iteration 2012-08-24 6e4e566 Jeremy Kerr * sbvarsign: Improve default GUID choice 2012-08-24 1b6eaee Jeremy Kerr * skkeysync: Add PK-handing code 2012-08-24 c80b5a2 Jeremy Kerr * sbkeysync: Refactor signature database data structures 2012-08-23 81bb4e3 Jeremy Kerr * sbkeysync: fix invalid free in keystore_read_entry 2012-08-23 a870a28 Jeremy Kerr * sbkeysync: Improve error handling in read_firmware_key_database 2012-08-23 b53ad57 Jeremy Kerr * sbkeysync: insert new keys 2012-08-23 fbedc4b Jeremy Kerr * sbkeysync: print keystore before key databases 2012-08-23 603e4f9 Jeremy Kerr * sbkeysync: Find keys missing from firmware key databases 2012-08-23 7e7fae0 Jeremy Kerr * sbkeysync: Rename struct keystore_entry->list to keystore_list 2012-08-22 2a87e12 Jeremy Kerr * sbkeysync: Generate and print key descriptions 2012-08-22 a5f7a63 Jeremy Kerr * sbkeysync: add comment to sigdb_iterate 2012-08-22 8c3bd4f Jeremy Kerr * sbkeysync: Change key_id to key_parse 2012-08-22 ac5d82d Jeremy Kerr * sbkeysync: Print filesystem key databases 2012-08-21 0c6ca3f Jeremy Kerr * sbkeysync: read keystore into kdb->filesystem_keys 2012-08-21 6576207 Jeremy Kerr * sbkeysync: Unify key_database 2012-08-21 d48d2a5 Jeremy Kerr * sbkeysync: Add key_database->filesystem_keys 2012-08-21 4c7eff0 Jeremy Kerr * sbkeysync: keystore -> fs_keystore 2012-08-21 ed3059d Jeremy Kerr * sbkeysync: pass data buffer (instead of EFI_SIGNATURE_DATA) to key_id 2012-08-21 3f10faa Jeremy Kerr * sbkeysync: add keystore_entry->root 2012-08-21 2d58004 Jeremy Kerr * sbkeysync: Add --keystore and --no-default-keystores options 2012-08-21 3729176 Jeremy Kerr * sbkeysync: Add --verbose option and conditionally print debug output 2012-08-20 651d158 Jeremy Kerr * sbkeysync: Add keystore parsing functions 2012-08-20 c0f22ed Jeremy Kerr * sbkeysync: Add --efivars-dir option to specific different locations for var files 2012-08-20 2625af1 Jeremy Kerr * sbkeysync: Add X509 key parsing 2012-08-20 7c4b36d Jeremy Kerr * sbkeysync: Add key ID data to print_key_database() 2012-08-20 d45de48 Jeremy Kerr * sbkeysync: read & print signature databases 2012-08-20 63b21b9 Jeremy Kerr * Move EFI_CERT types to efivars.h 2012-08-24 7fca8bd Jeremy Kerr * fileio: Add fileio_read_file_noerror() 2012-08-23 0ba703a Jeremy Kerr * sbvarsign: Start with a default set of variable attributes 2012-08-23 922bcc9 Jeremy Kerr * efivars: Move EFI_VARIABLE_* attributes to efivars.h 2012-08-22 fa42e39 Jeremy Kerr * sbsiglist: fix signature size check 2012-08-22 ef7f262 Jeremy Kerr * sbvarsign: WIN_CERTIFICATE.dwLength should include the header size 2012-08-22 887f5a1 Jeremy Kerr * sbvarsign: Fix invalid sizeof() for zeroing timestamp data 2012-08-21 378ecab Jeremy Kerr * sbsiglist: check for owner and type arguments 2012-08-14 2e7d96b Jeremy Kerr * sbsiglist: Fix SignatureSize 2012-08-13 98dc757 Jeremy Kerr * image: use fileio_write_file 2012-08-13 3e2bd9b Jeremy Kerr * Remove unused gen-keyfiles source 2012-08-13 ac3f03f Jeremy Kerr * docs: Create man pages for sbvarsign & sbsiglist 2012-08-13 101b703 Jeremy Kerr * Move sources to src/ subdirectory 2012-08-13 9464dcf Jeremy Kerr * image: Use size of image data when writing images 2012-08-13 b164b13 Jeremy Kerr * image: always parse image regions 2012-08-13 c9481ba Jeremy Kerr * Include efivars.h in automake infrastructure 2012-08-13 2a38dec Jeremy Kerr * tests: run tests for each arch 2012-08-10 dfc59be Jeremy Kerr * image: Allow manipulation of i386 PE/COFF files 2012-08-10 96d5769 Jeremy Kerr * Remove arch-specific coff headers 2012-08-04 58d2ad4 Maxim Kammerer * image: Prevent an uninitialized variable warning 2012-08-10 1a6fe60 Jeremy Kerr * sbsiglist: Add utility for creating EFI_SIGNATURE_LISTs 2012-08-10 7b95aee Jeremy Kerr * fileio: Add fileio_write_file 2012-08-10 5b15c0a Jeremy Kerr * efivars: rename efi variable header 2012-08-03 f574194 Jeremy Kerr * fileio: Unify whole-file reads 2012-08-03 d05cd38 Jeremy Kerr * fileio: Unify key & cert loading 2012-08-03 ab77d55 Jeremy Kerr * image: add functions to add and remove signatures 2012-08-02 d73dd55 Jeremy Kerr * sbattach: fix --detach 2012-08-02 7aad206 Jeremy Kerr * sbattach: fix missing openssl/evp.h header 2012-07-31 bc755fa Jeremy Kerr * sbvarsign: First cut of a variable-signing tool 2012-06-28 b537e74 Jeremy Kerr * Version 0.3 2012-06-28 34f45aa Jeremy Kerr * license: Add OpenSSL exception to GPLv3 terms 2012-06-28 90ac52e Jeremy Kerr * COPYING: remove non-license text 2012-06-27 3a17b39 James Bottomley * image: fix signature calculation when there's junk at the end of the efi binary 2012-06-28 99f2a9a Jeremy Kerr * tests: Add test for PE/COFF cert table header validity 2012-06-25 8d417f2 James Bottomley * image: fix incorrect assumption about signature header 2012-06-28 585915b Jeremy Kerr * sbsign: handle errors from PKCS7_sign_add_signer() 2012-06-26 183ce60 James Bottomley * sbsign: fix failure to sign when key is password protected 2012-06-20 c07dfb9 Ivan Hu * configure: Add check for bfh.h 2012-06-19 5e07c4e Ivan Hu * tests: Add a test to check invalid PKCS7 signature attaching 2012-06-19 bfb778e Ivan Hu * sbattach: Check that attached signatures are valid PKCS7 data 2012-06-14 bf6df84 Jeremy Kerr * sbverify: Use a variable for image filename 2012-06-13 9b7f7fb Jeremy Kerr * image: Unconditionally parse PE/COFF data 2012-06-13 128f1c1 Jeremy Kerr * sbverify: Check for failed image load 2012-06-13 b48e256 Jeremy Kerr * tests: Add tests for missing image, cert & key files 2012-06-13 0af5e01 Jeremy Kerr * tests: Execute tests in a clean (temporary) directory 2012-06-13 8716e88 Jeremy Kerr * tests: Use COMPILE.S for assembing test object 2012-06-13 807f0e6 Jeremy Kerr * Version 0.2 2012-06-13 7c2d8bb Jeremy Kerr * docs: Add simple manpage for sbattach 2012-06-13 deb9211 Jeremy Kerr * automake: Clean generated man files 2012-06-13 3cde1e4 Jeremy Kerr * tests: Add a few simple tests 2012-06-13 cc881c2 Jeremy Kerr * Remove unused test.c file 2012-06-12 4c79e3a Jeremy Kerr * sbattach: Add too to manage detached signatures 2012-06-12 564f5bc Jeremy Kerr * image: Add facility to write unsigned images 2012-06-11 a07b8d2 Jeremy Kerr * sbsign,sbverify: Update getopt_long optstrings 2012-06-11 5836038 Jeremy Kerr * sbverify: Add support for detached signatures 2012-06-11 b8a7d51 Jeremy Kerr * sbverify: Split image signature table reading to separate function 2012-06-11 e9f438c Jeremy Kerr * Fix warnings from added -W flags 2012-06-11 f19e8bb Jeremy Kerr * automake: Add -Wall -Wextra CFLAGS 2012-06-11 af4f088 Jeremy Kerr * sbsign: Add --detached option to create detached PKCS7 signatures 2012-06-11 0c9fbd2 Jeremy Kerr * sbsign: fix flag for verbose operation 2012-06-11 3673db1 Jeremy Kerr * docs: Fix manpage creation 2012-05-29 9b2f3a7 Adam Conrad * autogen.sh: Fix ccan_module assignment 2012-05-28 3fb0f00 Jeremy Kerr * image: use read_write_all from ccan 2012-05-28 f1112b4 Jeremy Kerr * image: Fix format specifier for 32-bit builds 2012-05-24 d5e634c Jeremy Kerr * autoconfiscate 2012-05-23 82f8c30 Jeremy Kerr * docs: Add initial manpages 2012-05-23 c14efcb Jeremy Kerr * sbsign,sbverify: help2man-ize usage output 2012-05-23 98a4f10 Jeremy Kerr * Makefile: Add dist targets 2012-05-22 1b2b5c6 Jeremy Kerr * ccan: Add ccan import logic 2012-05-15 6ff68e5 Jeremy Kerr * Move ccan submodule 2012-05-15 9a08e25 Jeremy Kerr * Remove unused header 2012-05-14 bc618c5 Jeremy Kerr * Remove pkcs7-simple test file 2012-05-14 9ac930e Jeremy Kerr * Makefile: add install target 2012-05-14 a1b270f Jeremy Kerr * Makefile: Comment components 2012-05-14 c67b82a Jeremy Kerr * sbverify: clean up openssl init 2012-05-14 c499763 Jeremy Kerr * sbverify: add check for invalid PKCS7 data 2012-05-14 74eb766 Jeremy Kerr * sbverify: Add certificate chain verification 2012-05-12 e111127 Jeremy Kerr * verify: move idc-related parsing to idc.c 2012-05-12 46cf6a6 Jeremy Kerr * sbsign: fix incorrect check for certificate load 2012-05-12 57d9f0c Jeremy Kerr * image: reformat gap warnings 2012-05-12 ab05bec Jeremy Kerr * image: add cert table to image size 2012-05-12 e1fec08 Jeremy Kerr * sbverify: Add check for image hash 2012-05-12 fefe97c Jeremy Kerr * sbverify: check for presence of signature table 2012-05-12 b73f723 Jeremy Kerr * Makefile: add $(tools) var 2012-05-12 55b1940 Jeremy Kerr * sbsigntool -> sbsign 2012-05-12 a183de9 Jeremy Kerr * image: open output file with O_TRUNC 2012-04-24 04b70fc Jeremy Kerr * sbsigntooL: expand usage info 2012-04-24 9826a43 Jeremy Kerr * Add GPLv3 text in COPYING 2012-04-24 906654e Jeremy Kerr * coff: remove unneeded coff includes 2012-04-23 9d3c8b5 Jeremy Kerr * Add copyright comments 2012-04-23 e019eec Jeremy Kerr * image: warn about potential checksum differences 2012-04-23 01e33cd Jeremy Kerr * idc: allocate using the image context 2012-04-23 acd8c0a Jeremy Kerr * Initial commit sbsigntool-0.9.2/LICENSE.GPLv3000066400000000000000000000773301342142174400156200ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS sbsigntool-0.9.2/Makefile.am000066400000000000000000000000431342142174400157400ustar00rootroot00000000000000 SUBDIRS = lib/ccan src docs tests sbsigntool-0.9.2/NEWS000066400000000000000000000006161342142174400144110ustar00rootroot00000000000000v0.5: sbkeysync's default efivars mountpoint has been moved to /sys/firmware/efi/efivars/. This is to match the proposed Linux kernel patch for efivarfs, which provides this sysfs node for the purpose of mounting efivarfs, and leaving the older ../vars/ interface for legacy applications. This default can be overridden using the --efivars-path option to sbkeysync. v0.1: Initial version sbsigntool-0.9.2/README000066400000000000000000000007631342142174400145750ustar00rootroot00000000000000sbsigntool - Signing utility for UEFI secure boot Copyright (C) 2102 Jeremy Kerr Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. See file ./INSTALL for building and installation instructions. Main git repository: git://kernel.ubuntu.com/jk/sbsigntool.git sbsigntool is free software. See the file COPYING for copying conditions. sbsigntool-0.9.2/aclocal.m4000066400000000000000000001472461342142174400155650ustar00rootroot00000000000000# generated automatically by aclocal 1.16.1 -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # 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. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- dnl serial 11 (pkg-config-0.29) dnl dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR # Copyright (C) 2002-2018 Free Software Foundation, Inc. # # 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. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # Figure out how to run the assembler. -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # 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. # AM_PROG_AS # ---------- AC_DEFUN([AM_PROG_AS], [# By default we simply use the C compiler to build assembly code. AC_REQUIRE([AC_PROG_CC]) test "${CCAS+set}" = set || CCAS=$CC test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)]) AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)]) _AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl ]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2018 Free Software Foundation, Inc. # # 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. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2018 Free Software Foundation, Inc. # # 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. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2018 Free Software Foundation, Inc. # # 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. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. Try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # # 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. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2018 Free Software Foundation, Inc. # # 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. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # 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. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2018 Free Software Foundation, Inc. # # 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. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # 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. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2018 Free Software Foundation, Inc. # # 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. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # 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. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # # 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. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2018 Free Software Foundation, Inc. # # 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. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # 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. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2018 Free Software Foundation, Inc. # # 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. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2018 Free Software Foundation, Inc. # # 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. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR sbsigntool-0.9.2/config.h.in000066400000000000000000000031151342142174400157320ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Big-endian system */ #undef HAVE_BIG_ENDIAN /* Define to 1 if you have the header file. */ #undef HAVE_EFI_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Little-endian system */ #undef HAVE_LITTLE_ENDIAN /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_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 header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_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 you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION sbsigntool-0.9.2/configure.ac000066400000000000000000000047411342142174400162030ustar00rootroot00000000000000AC_INIT([sbsigntool], [0.9.2], [James.Bottomley@HansenPartnership.com]) AM_INIT_AUTOMAKE() AC_PREREQ(2.60) AC_CONFIG_HEADERS(config.h) AC_CONFIG_SRCDIR(src/sbsign.c) AM_PROG_AS AC_PROG_CC AM_PROG_CC_C_O AC_PROG_CPP AC_PROG_RANLIB AC_PROG_MKDIR_P AC_CHECK_TOOL(OBJCOPY, [objcopy]) AC_CHECK_TOOL(STRIP, [strip]) AC_CHECK_HEADER([bfd.h], [], AC_MSG_ERROR([bfd.h not found.] [bfd.h is usually distributed in a binutils development package.])) if test $cross_compiling = no; then AM_MISSING_PROG(HELP2MAN, help2man) else HELP2MAN=: fi AC_MSG_CHECKING([build system endianness]) AC_PREPROC_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[#if __BYTE_ORDER != __LITTLE_ENDIAN]] [[#error]] [[#endif]])], endian=little little_endian=1 big_endian=0) AC_PREPROC_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[#if __BYTE_ORDER != __BIG_ENDIAN]] [[#error]] [[#endif]])], endian=big little_endian=0 big_endian=1) if test x"$endian" != "xbig" -a x"$endian" != "xlittle"; then AC_MSG_ERROR([Can't determine endianness; is endian.h present?]) fi AC_MSG_RESULT($endian) AC_DEFINE_UNQUOTED(HAVE_LITTLE_ENDIAN, $little_endian, [Little-endian system]) AC_DEFINE_UNQUOTED(HAVE_BIG_ENDIAN, $big_endian, [Big-endian system]) PKG_PROG_PKG_CONFIG() PKG_CHECK_MODULES(libcrypto, libcrypto, [], AC_MSG_ERROR([libcrypto (from the OpenSSL package) is required])) PKG_CHECK_MODULES(uuid, uuid, [], AC_MSG_ERROR([libuuid (from the uuid package) is required])) dnl gnu-efi headers require extra include dirs EFI_ARCH=$(uname -m | sed 's/i.86/ia32/;s/arm.*/arm/') AM_CONDITIONAL(TEST_BINARY_FORMAT, [ test "$EFI_ARCH" = "arm" -o "$EFI_ARCH" = "aarch64" ]) ## # no consistent view of where gnu-efi should dump the efi stuff, so find it ## for path in /lib /lib64 /usr/lib /usr/lib64 /usr/lib32 /lib/efi /lib64/efi /usr/lib/efi /usr/lib64/efi /usr/lib/gnuefi /usr/lib64/gnuefi ; do if test -e $path/crt0-efi-$EFI_ARCH.o; then CRTPATH=$path fi done if test -z "$CRTPATH"; then AC_MSG_ERROR([cannot find the gnu-efi crt path]) fi EFI_CPPFLAGS="-I/usr/include/efi -I/usr/include/efi/$EFI_ARCH \ -DEFI_FUNCTION_WRAPPER" CPPFLAGS_save="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $EFI_CPPFLAGS" AC_CHECK_HEADERS([efi.h], [], [], $EFI_INCLUDES) CPPFLAGS="$CPPFLAGS_save" AC_SUBST(EFI_CPPFLAGS, $EFI_CPPFLAGS) AC_SUBST(EFI_ARCH, $EFI_ARCH) AC_SUBST(CRTPATH, $CRTPATH) AC_CONFIG_FILES([Makefile src/Makefile lib/ccan/Makefile] [docs/Makefile tests/Makefile]) AC_OUTPUT sbsigntool-0.9.2/docs/000077500000000000000000000000001342142174400146375ustar00rootroot00000000000000sbsigntool-0.9.2/docs/Makefile.am000066400000000000000000000004741342142174400167000ustar00rootroot00000000000000 man1_MANS = sbsign.1 sbverify.1 sbattach.1 sbvarsign.1 sbsiglist.1 EXTRA_DIST = sbsign.1.in sbverify.1.in sbattach.1.in \ sbvarsign.1.in sbsiglist.1.in CLEANFILES = $(man1_MANS) $(builddir)/%.1: $(srcdir)/%.1.in $(top_builddir)/src/% $(MKDIR_P) $(@D) $(HELP2MAN) --no-info -i $< -o $@ $(top_builddir)/src/$* sbsigntool-0.9.2/docs/sbattach.1.in000066400000000000000000000000731342142174400171170ustar00rootroot00000000000000[name] sbattach - UEFI secure boot detached signature tool sbsigntool-0.9.2/docs/sbsiglist.1.in000066400000000000000000000001011342142174400173210ustar00rootroot00000000000000[name] sbsiglist - Create EFI_SIGNATURE_LIST signature databases sbsigntool-0.9.2/docs/sbsign.1.in000066400000000000000000000000561342142174400166140ustar00rootroot00000000000000[name] sbsign - UEFI secure boot signing tool sbsigntool-0.9.2/docs/sbvarsign.1.in000066400000000000000000000000741342142174400173250ustar00rootroot00000000000000[name] sbvarsign - UEFI authenticated variable signing tool sbsigntool-0.9.2/docs/sbverify.1.in000066400000000000000000000000651342142174400171600ustar00rootroot00000000000000[name] sbverify - UEFI secure boot verification tool sbsigntool-0.9.2/lib/000077500000000000000000000000001342142174400144555ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/000077500000000000000000000000001342142174400153615ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/Makefile.am000066400000000000000000000015561342142174400174240ustar00rootroot00000000000000noinst_LIBRARIES = libccan.a libccan_a_SOURCES = \ ccan/read_write_all/read_write_all.c \ ccan/read_write_all/read_write_all.h \ ccan/typesafe_cb/typesafe_cb.h \ ccan/array_size/array_size.h \ ccan/tlist/tlist.h \ ccan/time/time.h \ ccan/time/time.c \ ccan/list/list.c \ ccan/list/list.h \ ccan/compiler/compiler.h \ ccan/str/debug.c \ ccan/str/str.c \ ccan/str/str.h \ ccan/str/str_debug.h \ ccan/failtest/failtest_proto.h \ ccan/failtest/failtest.h \ ccan/failtest/failtest_override.h \ ccan/failtest/failtest_undo.h \ ccan/failtest/failtest.c \ ccan/tcon/tcon.h \ ccan/build_assert/build_assert.h \ ccan/check_type/check_type.h \ ccan/htable/htable.c \ ccan/htable/htable.h \ ccan/htable/htable_type.h \ ccan/talloc/talloc.c \ ccan/talloc/talloc.h \ ccan/hash/hash.h \ ccan/hash/hash.c \ ccan/endian/endian.h \ ccan/container_of/container_of.h sbsigntool-0.9.2/lib/ccan/ccan/000077500000000000000000000000001342142174400162655ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/array_size/000077500000000000000000000000001342142174400204355ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/array_size/array_size.h000066400000000000000000000015001342142174400227520ustar00rootroot00000000000000#ifndef CCAN_ARRAY_SIZE_H #define CCAN_ARRAY_SIZE_H #include "config.h" #include /** * ARRAY_SIZE - get the number of elements in a visible array * @arr: the array whose size you want. * * This does not work on pointers, or arrays declared as [], or * function parameters. With correct compiler support, such usage * will cause a build error (see build_assert). */ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + _array_size_chk(arr)) #if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF /* Two gcc extensions. * &a[0] degrades to a pointer: a different type from an array */ #define _array_size_chk(arr) \ BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \ typeof(&(arr)[0]))) #else #define _array_size_chk(arr) 0 #endif #endif /* CCAN_ALIGNOF_H */ sbsigntool-0.9.2/lib/ccan/ccan/build_assert/000077500000000000000000000000001342142174400207455ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/build_assert/build_assert.h000066400000000000000000000022231342142174400235750ustar00rootroot00000000000000#ifndef CCAN_BUILD_ASSERT_H #define CCAN_BUILD_ASSERT_H /** * BUILD_ASSERT - assert a build-time dependency. * @cond: the compile-time condition which must be true. * * Your compile will fail if the condition isn't true, or can't be evaluated * by the compiler. This can only be used within a function. * * Example: * #include * ... * static char *foo_to_char(struct foo *foo) * { * // This code needs string to be at start of foo. * BUILD_ASSERT(offsetof(struct foo, string) == 0); * return (char *)foo; * } */ #define BUILD_ASSERT(cond) \ do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) /** * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. * @cond: the compile-time condition which must be true. * * Your compile will fail if the condition isn't true, or can't be evaluated * by the compiler. This can be used in an expression: its value is "0". * * Example: * #define foo_to_char(foo) \ * ((char *)(foo) \ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) */ #define BUILD_ASSERT_OR_ZERO(cond) \ (sizeof(char [1 - 2*!(cond)]) - 1) #endif /* CCAN_BUILD_ASSERT_H */ sbsigntool-0.9.2/lib/ccan/ccan/check_type/000077500000000000000000000000001342142174400204035ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/check_type/check_type.h000066400000000000000000000044151342142174400226760ustar00rootroot00000000000000#ifndef CCAN_CHECK_TYPE_H #define CCAN_CHECK_TYPE_H #include "config.h" /** * check_type - issue a warning or build failure if type is not correct. * @expr: the expression whose type we should check (not evaluated). * @type: the exact type we expect the expression to be. * * This macro is usually used within other macros to try to ensure that a macro * argument is of the expected type. No type promotion of the expression is * done: an unsigned int is not the same as an int! * * check_type() always evaluates to 0. * * If your compiler does not support typeof, then the best we can do is fail * to compile if the sizes of the types are unequal (a less complete check). * * Example: * // They should always pass a 64-bit value to _set_some_value! * #define set_some_value(expr) \ * _set_some_value((check_type((expr), uint64_t), (expr))) */ /** * check_types_match - issue a warning or build failure if types are not same. * @expr1: the first expression (not evaluated). * @expr2: the second expression (not evaluated). * * This macro is usually used within other macros to try to ensure that * arguments are of identical types. No type promotion of the expressions is * done: an unsigned int is not the same as an int! * * check_types_match() always evaluates to 0. * * If your compiler does not support typeof, then the best we can do is fail * to compile if the sizes of the types are unequal (a less complete check). * * Example: * // Do subtraction to get to enclosing type, but make sure that * // pointer is of correct type for that member. * #define container_of(mbr_ptr, encl_type, mbr) \ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ * ((encl_type *) \ * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr)))) */ #if HAVE_TYPEOF #define check_type(expr, type) \ ((typeof(expr) *)0 != (type *)0) #define check_types_match(expr1, expr2) \ ((typeof(expr1) *)0 != (typeof(expr2) *)0) #else #include /* Without typeof, we can only test the sizes. */ #define check_type(expr, type) \ BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type)) #define check_types_match(expr1, expr2) \ BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2)) #endif /* HAVE_TYPEOF */ #endif /* CCAN_CHECK_TYPE_H */ sbsigntool-0.9.2/lib/ccan/ccan/compiler/000077500000000000000000000000001342142174400200775ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/compiler/compiler.h000066400000000000000000000126351342142174400220710ustar00rootroot00000000000000#ifndef CCAN_COMPILER_H #define CCAN_COMPILER_H #include "config.h" #ifndef COLD #if HAVE_ATTRIBUTE_COLD /** * COLD - a function is unlikely to be called. * * Used to mark an unlikely code path and optimize appropriately. * It is usually used on logging or error routines. * * Example: * static void COLD moan(const char *reason) * { * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); * } */ #define COLD __attribute__((cold)) #else #define COLD #endif #endif #ifndef NORETURN #if HAVE_ATTRIBUTE_NORETURN /** * NORETURN - a function does not return * * Used to mark a function which exits; useful for suppressing warnings. * * Example: * static void NORETURN fail(const char *reason) * { * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); * exit(1); * } */ #define NORETURN __attribute__((noreturn)) #else #define NORETURN #endif #endif #ifndef PRINTF_FMT #if HAVE_ATTRIBUTE_PRINTF /** * PRINTF_FMT - a function takes printf-style arguments * @nfmt: the 1-based number of the function's format argument. * @narg: the 1-based number of the function's first variable argument. * * This allows the compiler to check your parameters as it does for printf(). * * Example: * void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...); */ #define PRINTF_FMT(nfmt, narg) \ __attribute__((format(__printf__, nfmt, narg))) #else #define PRINTF_FMT(nfmt, narg) #endif #endif #ifndef CONST_FUNCTION #if HAVE_ATTRIBUTE_CONST /** * CONST_FUNCTION - a function's return depends only on its argument * * This allows the compiler to assume that the function will return the exact * same value for the exact same arguments. This implies that the function * must not use global variables, or dereference pointer arguments. */ #define CONST_FUNCTION __attribute__((const)) #else #define CONST_FUNCTION #endif #endif #if HAVE_ATTRIBUTE_UNUSED #ifndef UNNEEDED /** * UNNEEDED - a variable/function may not be needed * * This suppresses warnings about unused variables or functions, but tells * the compiler that if it is unused it need not emit it into the source code. * * Example: * // With some preprocessor options, this is unnecessary. * static UNNEEDED int counter; * * // With some preprocessor options, this is unnecessary. * static UNNEEDED void add_to_counter(int add) * { * counter += add; * } */ #define UNNEEDED __attribute__((unused)) #endif #ifndef NEEDED #if HAVE_ATTRIBUTE_USED /** * NEEDED - a variable/function is needed * * This suppresses warnings about unused variables or functions, but tells * the compiler that it must exist even if it (seems) unused. * * Example: * // Even if this is unused, these are vital for debugging. * static NEEDED int counter; * static NEEDED void dump_counter(void) * { * printf("Counter is %i\n", counter); * } */ #define NEEDED __attribute__((used)) #else /* Before used, unused functions and vars were always emitted. */ #define NEEDED __attribute__((unused)) #endif #endif #ifndef UNUSED /** * UNUSED - a parameter is unused * * Some compilers (eg. gcc with -W or -Wunused) warn about unused * function parameters. This suppresses such warnings and indicates * to the reader that it's deliberate. * * Example: * // This is used as a callback, so needs to have this prototype. * static int some_callback(void *unused UNUSED) * { * return 0; * } */ #define UNUSED __attribute__((unused)) #endif #else #ifndef UNNEEDED #define UNNEEDED #endif #ifndef NEEDED #define NEEDED #endif #ifndef UNUSED #define UNUSED #endif #endif #ifndef IS_COMPILE_CONSTANT #if HAVE_BUILTIN_CONSTANT_P /** * IS_COMPILE_CONSTANT - does the compiler know the value of this expression? * @expr: the expression to evaluate * * When an expression manipulation is complicated, it is usually better to * implement it in a function. However, if the expression being manipulated is * known at compile time, it is better to have the compiler see the entire * expression so it can simply substitute the result. * * This can be done using the IS_COMPILE_CONSTANT() macro. * * Example: * enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON }; * * // Out-of-line version. * const char *greek_name(enum greek greek); * * // Inline version. * static inline const char *_greek_name(enum greek greek) * { * switch (greek) { * case ALPHA: return "alpha"; * case BETA: return "beta"; * case GAMMA: return "gamma"; * case DELTA: return "delta"; * case EPSILON: return "epsilon"; * default: return "**INVALID**"; * } * } * * // Use inline if compiler knows answer. Otherwise call function * // to avoid copies of the same code everywhere. * #define greek_name(g) \ * (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g)) */ #define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr) #else /* If we don't know, assume it's not. */ #define IS_COMPILE_CONSTANT(expr) 0 #endif #endif #ifndef WARN_UNUSED_RESULT #if HAVE_WARN_UNUSED_RESULT /** * WARN_UNUSED_RESULT - warn if a function return value is unused. * * Used to mark a function where it is extremely unlikely that the caller * can ignore the result, eg realloc(). * * Example: * // buf param may be freed by this; need return value! * static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size) * { * return realloc(buf, (*size) *= 2); * } */ #define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define WARN_UNUSED_RESULT #endif #endif #endif /* CCAN_COMPILER_H */ sbsigntool-0.9.2/lib/ccan/ccan/container_of/000077500000000000000000000000001342142174400207335ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/container_of/container_of.h000066400000000000000000000060271342142174400235570ustar00rootroot00000000000000#ifndef CCAN_CONTAINER_OF_H #define CCAN_CONTAINER_OF_H #include #include "config.h" #include /** * container_of - get pointer to enclosing structure * @member_ptr: pointer to the structure member * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info(struct foo *foo) * { * return container_of(foo, struct info, my_foo); * } */ #define container_of(member_ptr, containing_type, member) \ ((containing_type *) \ ((char *)(member_ptr) \ - container_off(containing_type, member)) \ + check_types_match(*(member_ptr), ((containing_type *)0)->member)) /** * container_off - get offset to enclosing structure * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does * typechecking and figures out the offset to the enclosing type. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info(struct foo *foo) * { * size_t off = container_off(struct info, my_foo); * return (void *)((char *)foo - off); * } */ #define container_off(containing_type, member) \ offsetof(containing_type, member) /** * container_of_var - get pointer to enclosing structure using a variable * @member_ptr: pointer to the structure member * @container_var: a pointer of same type as this member's container * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type. * * Example: * static struct info *foo_to_i(struct foo *foo) * { * struct info *i = container_of_var(foo, i, my_foo); * return i; * } */ #if HAVE_TYPEOF #define container_of_var(member_ptr, container_var, member) \ container_of(member_ptr, typeof(*container_var), member) #else #define container_of_var(member_ptr, container_var, member) \ ((void *)((char *)(member_ptr) - \ container_off_var(container_var, member))) #endif /** * container_off_var - get offset of a field in enclosing structure * @container_var: a pointer to a container structure * @member: the name of a member within the structure. * * Given (any) pointer to a structure and a its member name, this * macro does pointer subtraction to return offset of member in a * structure memory layout. * */ #if HAVE_TYPEOF #define container_off_var(var, member) \ container_off(typeof(*var), member) #else #define container_off_var(var, member) \ ((char *)&(var)->member - (char *)(var)) #endif #endif /* CCAN_CONTAINER_OF_H */ sbsigntool-0.9.2/lib/ccan/ccan/endian/000077500000000000000000000000001342142174400175235ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/endian/LICENSE000077700000000000000000000000001342142174400237352../../licenses/LGPL-2.1ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/endian/endian.h000066400000000000000000000114471342142174400211410ustar00rootroot00000000000000/* Licensed under LGPLv2.1+ - see LICENSE file for details */ #ifndef CCAN_ENDIAN_H #define CCAN_ENDIAN_H #include #include "config.h" #if HAVE_BYTESWAP_H #include #else /** * bswap_16 - reverse bytes in a uint16_t value. * @val: value whose bytes to swap. * * Example: * // Output contains "1024 is 4 as two bytes reversed" * printf("1024 is %u as two bytes reversed\n", bswap_16(1024)); */ static inline uint16_t bswap_16(uint16_t val) { return ((val & (uint16_t)0x00ffU) << 8) | ((val & (uint16_t)0xff00U) >> 8); } /** * bswap_32 - reverse bytes in a uint32_t value. * @val: value whose bytes to swap. * * Example: * // Output contains "1024 is 262144 as four bytes reversed" * printf("1024 is %u as four bytes reversed\n", bswap_32(1024)); */ static inline uint32_t bswap_32(uint32_t val) { return ((val & (uint32_t)0x000000ffUL) << 24) | ((val & (uint32_t)0x0000ff00UL) << 8) | ((val & (uint32_t)0x00ff0000UL) >> 8) | ((val & (uint32_t)0xff000000UL) >> 24); } #endif /* !HAVE_BYTESWAP_H */ #if !HAVE_BSWAP_64 /** * bswap_64 - reverse bytes in a uint64_t value. * @val: value whose bytes to swap. * * Example: * // Output contains "1024 is 1125899906842624 as eight bytes reversed" * printf("1024 is %llu as eight bytes reversed\n", * (unsigned long long)bswap_64(1024)); */ static inline uint64_t bswap_64(uint64_t val) { return ((val & (uint64_t)0x00000000000000ffULL) << 56) | ((val & (uint64_t)0x000000000000ff00ULL) << 40) | ((val & (uint64_t)0x0000000000ff0000ULL) << 24) | ((val & (uint64_t)0x00000000ff000000ULL) << 8) | ((val & (uint64_t)0x000000ff00000000ULL) >> 8) | ((val & (uint64_t)0x0000ff0000000000ULL) >> 24) | ((val & (uint64_t)0x00ff000000000000ULL) >> 40) | ((val & (uint64_t)0xff00000000000000ULL) >> 56); } #endif /* Sanity check the defines. We don't handle weird endianness. */ #if !HAVE_LITTLE_ENDIAN && !HAVE_BIG_ENDIAN #error "Unknown endian" #elif HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN #error "Can't compile for both big and little endian." #endif /** * cpu_to_le64 - convert a uint64_t value to little-endian * @native: value to convert */ static inline uint64_t cpu_to_le64(uint64_t native) { #if HAVE_LITTLE_ENDIAN return native; #else return bswap_64(native); #endif } /** * cpu_to_le32 - convert a uint32_t value to little-endian * @native: value to convert */ static inline uint32_t cpu_to_le32(uint32_t native) { #if HAVE_LITTLE_ENDIAN return native; #else return bswap_32(native); #endif } /** * cpu_to_le16 - convert a uint16_t value to little-endian * @native: value to convert */ static inline uint16_t cpu_to_le16(uint16_t native) { #if HAVE_LITTLE_ENDIAN return native; #else return bswap_16(native); #endif } /** * le64_to_cpu - convert a little-endian uint64_t value * @le_val: little-endian value to convert */ static inline uint64_t le64_to_cpu(uint64_t le_val) { #if HAVE_LITTLE_ENDIAN return le_val; #else return bswap_64(le_val); #endif } /** * le32_to_cpu - convert a little-endian uint32_t value * @le_val: little-endian value to convert */ static inline uint32_t le32_to_cpu(uint32_t le_val) { #if HAVE_LITTLE_ENDIAN return le_val; #else return bswap_32(le_val); #endif } /** * le16_to_cpu - convert a little-endian uint16_t value * @le_val: little-endian value to convert */ static inline uint16_t le16_to_cpu(uint16_t le_val) { #if HAVE_LITTLE_ENDIAN return le_val; #else return bswap_16(le_val); #endif } /** * cpu_to_be64 - convert a uint64_t value to big endian. * @native: value to convert */ static inline uint64_t cpu_to_be64(uint64_t native) { #if HAVE_LITTLE_ENDIAN return bswap_64(native); #else return native; #endif } /** * cpu_to_be32 - convert a uint32_t value to big endian. * @native: value to convert */ static inline uint32_t cpu_to_be32(uint32_t native) { #if HAVE_LITTLE_ENDIAN return bswap_32(native); #else return native; #endif } /** * cpu_to_be16 - convert a uint16_t value to big endian. * @native: value to convert */ static inline uint16_t cpu_to_be16(uint16_t native) { #if HAVE_LITTLE_ENDIAN return bswap_16(native); #else return native; #endif } /** * be64_to_cpu - convert a big-endian uint64_t value * @be_val: big-endian value to convert */ static inline uint64_t be64_to_cpu(uint64_t be_val) { #if HAVE_LITTLE_ENDIAN return bswap_64(be_val); #else return be_val; #endif } /** * be32_to_cpu - convert a big-endian uint32_t value * @be_val: big-endian value to convert */ static inline uint32_t be32_to_cpu(uint32_t be_val) { #if HAVE_LITTLE_ENDIAN return bswap_32(be_val); #else return be_val; #endif } /** * be16_to_cpu - convert a big-endian uint16_t value * @be_val: big-endian value to convert */ static inline uint16_t be16_to_cpu(uint16_t be_val) { #if HAVE_LITTLE_ENDIAN return bswap_16(be_val); #else return be_val; #endif } #endif /* CCAN_ENDIAN_H */ sbsigntool-0.9.2/lib/ccan/ccan/failtest/000077500000000000000000000000001342142174400201005ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/failtest/LICENSE000077700000000000000000000000001342142174400241542../../licenses/LGPL-3ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/failtest/failtest.c000066400000000000000000001246111342142174400220640ustar00rootroot00000000000000/* Licensed under LGPL - see LICENSE file for details */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum failtest_result (*failtest_hook)(struct tlist_calls *); static FILE *tracef = NULL, *warnf; static int traceindent = 0; unsigned int failtest_timeout_ms = 20000; const char *failpath; const char *debugpath; enum info_type { WRITE, RELEASE_LOCKS, FAILURE, SUCCESS, UNEXPECTED }; struct lock_info { int fd; /* end is inclusive: you can't have a 0-byte lock. */ off_t start, end; int type; }; /* We hash the call location together with its backtrace. */ static size_t hash_call(const struct failtest_call *call) { return hash(call->file, strlen(call->file), hash(&call->line, 1, hash(call->backtrace, call->backtrace_num, call->type))); } static bool call_eq(const struct failtest_call *call1, const struct failtest_call *call2) { unsigned int i; if (strcmp(call1->file, call2->file) != 0 || call1->line != call2->line || call1->type != call2->type || call1->backtrace_num != call2->backtrace_num) return false; for (i = 0; i < call1->backtrace_num; i++) if (call1->backtrace[i] != call2->backtrace[i]) return false; return true; } /* Defines struct failtable. */ HTABLE_DEFINE_TYPE(struct failtest_call, (struct failtest_call *), hash_call, call_eq, failtable); bool (*failtest_exit_check)(struct tlist_calls *history); /* The entire history of all calls. */ static struct tlist_calls history = TLIST_INIT(history); /* If we're a child, the fd two write control info to the parent. */ static int control_fd = -1; /* If we're a child, this is the first call we did ourselves. */ static struct failtest_call *our_history_start = NULL; /* For printing runtime with --trace. */ static struct timeval start; /* Set when failtest_hook returns FAIL_PROBE */ static bool probing = false; /* Table to track duplicates. */ static struct failtable failtable; /* Array of writes which our child did. We report them on failure. */ static struct write_call *child_writes = NULL; static unsigned int child_writes_num = 0; /* fcntl locking info. */ static pid_t lock_owner; static struct lock_info *locks = NULL; static unsigned int lock_num = 0; /* Our original pid, which we return to anyone who asks. */ static pid_t orig_pid; /* Mapping from failtest_type to char. */ static const char info_to_arg[] = "mceoxprwfal"; /* Dummy call used for failtest_undo wrappers. */ static struct failtest_call unrecorded_call; struct contents_saved { size_t count; off_t off; off_t old_len; char contents[1]; }; /* File contents, saved in this child only. */ struct saved_mmapped_file { struct saved_mmapped_file *next; struct failtest_call *opener; struct contents_saved *s; }; static struct saved_mmapped_file *saved_mmapped_files; #if HAVE_BACKTRACE #include static void **get_backtrace(unsigned int *num) { static unsigned int max_back = 100; void **ret; again: ret = malloc(max_back * sizeof(void *)); *num = backtrace(ret, max_back); if (*num == max_back) { free(ret); max_back *= 2; goto again; } return ret; } #else /* This will test slightly less, since will consider all of the same * calls as identical. But, it's slightly faster! */ static void **get_backtrace(unsigned int *num) { *num = 0; return NULL; } #endif /* HAVE_BACKTRACE */ static struct failtest_call *add_history_(enum failtest_call_type type, bool can_leak, const char *file, unsigned int line, const void *elem, size_t elem_size) { struct failtest_call *call; /* NULL file is how we suppress failure. */ if (!file) return &unrecorded_call; call = malloc(sizeof *call); call->type = type; call->can_leak = can_leak; call->file = file; call->line = line; call->cleanup = NULL; call->backtrace = get_backtrace(&call->backtrace_num); memcpy(&call->u, elem, elem_size); tlist_add_tail(&history, call, list); return call; } #define add_history(type, can_leak, file, line, elem) \ add_history_((type), (can_leak), (file), (line), (elem), sizeof(*(elem))) /* We do a fake call inside a sizeof(), to check types. */ #define set_cleanup(call, clean, type) \ (call)->cleanup = (void *)((void)sizeof(clean((type *)NULL, false),1), (clean)) /* Dup the fd to a high value (out of the way I hope!), and close the old fd. */ static int move_fd_to_high(int fd) { int i; struct rlimit lim; int max; if (getrlimit(RLIMIT_NOFILE, &lim) == 0) { max = lim.rlim_cur; printf("Max is %i\n", max); } else max = FD_SETSIZE; for (i = max - 1; i > fd; i--) { if (fcntl(i, F_GETFL) == -1 && errno == EBADF) { if (dup2(fd, i) == -1) { warn("Failed to dup fd %i to %i", fd, i); continue; } close(fd); return i; } } /* Nothing? Really? Er... ok? */ return fd; } static bool read_write_info(int fd) { struct write_call *w; char *buf; /* We don't need all of this, but it's simple. */ child_writes = realloc(child_writes, (child_writes_num+1) * sizeof(child_writes[0])); w = &child_writes[child_writes_num]; if (!read_all(fd, w, sizeof(*w))) return false; w->buf = buf = malloc(w->count); if (!read_all(fd, buf, w->count)) return false; child_writes_num++; return true; } static char *failpath_string(void) { struct failtest_call *i; char *ret = strdup(""); unsigned len = 0; /* Inefficient, but who cares? */ tlist_for_each(&history, i, list) { ret = realloc(ret, len + 2); ret[len] = info_to_arg[i->type]; if (i->fail) ret[len] = toupper(ret[len]); ret[++len] = '\0'; } return ret; } static void do_warn(int e, const char *fmt, va_list ap) { char *p = failpath_string(); vfprintf(warnf, fmt, ap); if (e != -1) fprintf(warnf, ": %s", strerror(e)); fprintf(warnf, " [%s]\n", p); free(p); } static void fwarn(const char *fmt, ...) { va_list ap; int e = errno; va_start(ap, fmt); do_warn(e, fmt, ap); va_end(ap); } static void fwarnx(const char *fmt, ...) { va_list ap; va_start(ap, fmt); do_warn(-1, fmt, ap); va_end(ap); } static void tell_parent(enum info_type type) { if (control_fd != -1) write_all(control_fd, &type, sizeof(type)); } static void child_fail(const char *out, size_t outlen, const char *fmt, ...) { va_list ap; char *path = failpath_string(); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "%.*s", (int)outlen, out); printf("To reproduce: --failpath=%s\n", path); free(path); tell_parent(FAILURE); exit(1); } static void PRINTF_FMT(1, 2) trace(const char *fmt, ...) { va_list ap; unsigned int i; char *p; static int idx; if (!tracef) return; for (i = 0; i < traceindent; i++) fprintf(tracef, " "); p = failpath_string(); fprintf(tracef, "%i: %u: %s ", idx++, getpid(), p); va_start(ap, fmt); vfprintf(tracef, fmt, ap); va_end(ap); free(p); } static pid_t child; static void hand_down(int signum) { kill(child, signum); } static void release_locks(void) { /* Locks were never acquired/reacquired? */ if (lock_owner == 0) return; /* We own them? Release them all. */ if (lock_owner == getpid()) { unsigned int i; struct flock fl; fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; trace("Releasing %u locks\n", lock_num); for (i = 0; i < lock_num; i++) fcntl(locks[i].fd, F_SETLK, &fl); } else { /* Our parent must have them; pass request up. */ enum info_type type = RELEASE_LOCKS; assert(control_fd != -1); write_all(control_fd, &type, sizeof(type)); } lock_owner = 0; } /* off_t is a signed type. Getting its max is non-trivial. */ static off_t off_max(void) { BUILD_ASSERT(sizeof(off_t) == 4 || sizeof(off_t) == 8); if (sizeof(off_t) == 4) return (off_t)0x7FFFFFF; else return (off_t)0x7FFFFFFFFFFFFFFULL; } static void get_locks(void) { unsigned int i; struct flock fl; if (lock_owner == getpid()) return; if (lock_owner != 0) { enum info_type type = RELEASE_LOCKS; assert(control_fd != -1); trace("Asking parent to release locks\n"); write_all(control_fd, &type, sizeof(type)); } fl.l_whence = SEEK_SET; for (i = 0; i < lock_num; i++) { fl.l_type = locks[i].type; fl.l_start = locks[i].start; if (locks[i].end == off_max()) fl.l_len = 0; else fl.l_len = locks[i].end - locks[i].start + 1; if (fcntl(locks[i].fd, F_SETLKW, &fl) != 0) abort(); } trace("Acquired %u locks\n", lock_num); lock_owner = getpid(); } static struct contents_saved *save_contents(const char *filename, int fd, size_t count, off_t off, const char *why) { struct contents_saved *s = malloc(sizeof(*s) + count); ssize_t ret; s->off = off; ret = pread(fd, s->contents, count, off); if (ret < 0) { fwarn("failtest_write: failed to save old contents!"); s->count = 0; } else s->count = ret; /* Use lseek to get the size of file, but we have to restore * file offset */ off = lseek(fd, 0, SEEK_CUR); s->old_len = lseek(fd, 0, SEEK_END); lseek(fd, off, SEEK_SET); trace("Saving %p %s %zu@%llu after %s (filelength %llu) via fd %i\n", s, filename, s->count, (long long)s->off, why, (long long)s->old_len, fd); return s; } static void restore_contents(struct failtest_call *opener, struct contents_saved *s, bool restore_offset, const char *caller) { int fd; /* The top parent doesn't need to restore. */ if (control_fd == -1) return; /* Has the fd been closed? */ if (opener->u.open.closed) { /* Reopen, replace fd, close silently as we clean up. */ fd = open(opener->u.open.pathname, O_RDWR); if (fd < 0) { fwarn("failtest: could not reopen %s to clean up %s!", opener->u.open.pathname, caller); return; } /* Make it clearly distinguisable from a "normal" fd. */ fd = move_fd_to_high(fd); trace("Reopening %s to restore it (was fd %i, now %i)\n", opener->u.open.pathname, opener->u.open.ret, fd); opener->u.open.ret = fd; opener->u.open.closed = false; } fd = opener->u.open.ret; trace("Restoring %p %s %zu@%llu after %s (filelength %llu) via fd %i\n", s, opener->u.open.pathname, s->count, (long long)s->off, caller, (long long)s->old_len, fd); if (pwrite(fd, s->contents, s->count, s->off) != s->count) { fwarn("failtest: write failed cleaning up %s for %s!", opener->u.open.pathname, caller); } if (ftruncate(fd, s->old_len) != 0) { fwarn("failtest_write: truncate failed cleaning up %s for %s!", opener->u.open.pathname, caller); } if (restore_offset) { trace("Restoring offset of fd %i to %llu\n", fd, (long long)s->off); lseek(fd, s->off, SEEK_SET); } } /* We save/restore most things on demand, but always do mmaped files. */ static void save_mmapped_files(void) { struct failtest_call *i; trace("Saving mmapped files in child\n"); tlist_for_each_rev(&history, i, list) { struct mmap_call *m = &i->u.mmap; struct saved_mmapped_file *s; if (i->type != FAILTEST_MMAP) continue; /* FIXME: We only handle mmapped files where fd is still open. */ if (m->opener->u.open.closed) continue; s = malloc(sizeof *s); s->s = save_contents(m->opener->u.open.pathname, m->fd, m->length, m->offset, "mmapped file before fork"); s->opener = m->opener; s->next = saved_mmapped_files; saved_mmapped_files = s; } } static void free_mmapped_files(bool restore) { trace("%s mmapped files in child\n", restore ? "Restoring" : "Discarding"); while (saved_mmapped_files) { struct saved_mmapped_file *next = saved_mmapped_files->next; if (restore) restore_contents(saved_mmapped_files->opener, saved_mmapped_files->s, false, "saved mmap"); free(saved_mmapped_files->s); free(saved_mmapped_files); saved_mmapped_files = next; } } /* Returns a FAILTEST_OPEN, FAILTEST_PIPE or NULL. */ static struct failtest_call *opener_of(int fd) { struct failtest_call *i; /* Don't get confused and match genuinely failed opens. */ if (fd < 0) return NULL; /* Figure out the set of live fds. */ tlist_for_each_rev(&history, i, list) { if (i->fail) continue; switch (i->type) { case FAILTEST_CLOSE: if (i->u.close.fd == fd) { return NULL; } break; case FAILTEST_OPEN: if (i->u.open.ret == fd) { if (i->u.open.closed) return NULL; return i; } break; case FAILTEST_PIPE: if (i->u.pipe.fds[0] == fd || i->u.pipe.fds[1] == fd) { return i; } break; default: break; } } /* FIXME: socket, dup, etc are untracked! */ return NULL; } static void free_call(struct failtest_call *call) { /* We don't do this in cleanup: needed even for failed opens. */ if (call->type == FAILTEST_OPEN) free((char *)call->u.open.pathname); free(call->backtrace); tlist_del_from(&history, call, list); free(call); } /* Free up memory, so valgrind doesn't report leaks. */ static void free_everything(void) { struct failtest_call *i; while ((i = tlist_top(&history, list)) != NULL) free_call(i); failtable_clear(&failtable); } static NORETURN void failtest_cleanup(bool forced_cleanup, int status) { struct failtest_call *i; bool restore = true; /* For children, we don't care if they "failed" the testing. */ if (control_fd != -1) status = 0; else /* We don't restore contents for original parent. */ restore = false; /* Cleanup everything, in reverse order. */ tlist_for_each_rev(&history, i, list) { /* Don't restore things our parent did. */ if (i == our_history_start) restore = false; if (i->fail) continue; if (i->cleanup) i->cleanup(&i->u, restore); /* But their program shouldn't leak, even on failure. */ if (!forced_cleanup && i->can_leak) { printf("Leak at %s:%u: --failpath=%s\n", i->file, i->line, failpath_string()); status = 1; } } /* Put back mmaped files the way our parent (if any) expects. */ free_mmapped_files(true); free_everything(); if (status == 0) tell_parent(SUCCESS); else tell_parent(FAILURE); exit(status); } static bool following_path(void) { if (!failpath) return false; /* + means continue after end, like normal. */ if (*failpath == '+') { failpath = NULL; return false; } return true; } static bool follow_path(struct failtest_call *call) { if (*failpath == '\0') { /* Continue, but don't inject errors. */ return call->fail = false; } if (tolower((unsigned char)*failpath) != info_to_arg[call->type]) errx(1, "Failpath expected '%s' got '%c'\n", failpath, info_to_arg[call->type]); call->fail = cisupper(*(failpath++)); if (call->fail) call->can_leak = false; return call->fail; } static bool should_fail(struct failtest_call *call) { int status; int control[2], output[2]; enum info_type type = UNEXPECTED; char *out = NULL; size_t outlen = 0; struct failtest_call *dup; if (call == &unrecorded_call) return false; if (following_path()) return follow_path(call); /* Attach debugger if they asked for it. */ if (debugpath) { char *path; /* Pretend this last call matches whatever path wanted: * keeps valgrind happy. */ call->fail = cisupper(debugpath[strlen(debugpath)-1]); path = failpath_string(); if (streq(path, debugpath)) { char str[80]; /* Don't timeout. */ signal(SIGUSR1, SIG_IGN); sprintf(str, "xterm -e gdb /proc/%d/exe %d &", getpid(), getpid()); if (system(str) == 0) sleep(5); } else { /* Ignore last character: could be upper or lower. */ path[strlen(path)-1] = '\0'; if (!strstarts(debugpath, path)) { fprintf(stderr, "--debugpath not followed: %s\n", path); debugpath = NULL; } } free(path); } /* Are we probing? If so, we never fail twice. */ if (probing) { trace("Not failing %c due to FAIL_PROBE return\n", info_to_arg[call->type]); return call->fail = false; } /* Don't fail more than once in the same place. */ dup = failtable_get(&failtable, call); if (dup) { trace("Not failing %c due to duplicate\n", info_to_arg[call->type]); return call->fail = false; } if (failtest_hook) { switch (failtest_hook(&history)) { case FAIL_OK: break; case FAIL_PROBE: probing = true; break; case FAIL_DONT_FAIL: trace("Not failing %c due to failhook return\n", info_to_arg[call->type]); call->fail = false; return false; default: abort(); } } /* Add it to our table of calls. */ failtable_add(&failtable, call); /* We're going to fail in the child. */ call->fail = true; if (pipe(control) != 0 || pipe(output) != 0) err(1, "opening pipe"); /* Move out the way, to high fds. */ control[0] = move_fd_to_high(control[0]); control[1] = move_fd_to_high(control[1]); output[0] = move_fd_to_high(output[0]); output[1] = move_fd_to_high(output[1]); /* Prevent double-printing (in child and parent) */ fflush(stdout); fflush(warnf); if (tracef) fflush(tracef); child = fork(); if (child == -1) err(1, "forking failed"); if (child == 0) { traceindent++; if (tracef) { struct timeval diff; const char *p; char *failpath; struct failtest_call *c; c = tlist_tail(&history, list); diff = time_sub(time_now(), start); failpath = failpath_string(); p = strrchr(c->file, '/'); if (p) p++; else p = c->file; trace("%u->%u (%u.%02u): %s (%s:%u)\n", getppid(), getpid(), (int)diff.tv_sec, (int)diff.tv_usec / 10000, failpath, p, c->line); free(failpath); } /* From here on, we have to clean up! */ our_history_start = tlist_tail(&history, list); close(control[0]); close(output[0]); /* Don't swallow stderr if we're tracing. */ if (!tracef) { dup2(output[1], STDOUT_FILENO); dup2(output[1], STDERR_FILENO); if (output[1] != STDOUT_FILENO && output[1] != STDERR_FILENO) close(output[1]); } control_fd = move_fd_to_high(control[1]); /* Forget any of our parent's saved files. */ free_mmapped_files(false); /* Now, save any files we need to. */ save_mmapped_files(); /* Failed calls can't leak. */ call->can_leak = false; return true; } signal(SIGUSR1, hand_down); close(control[1]); close(output[1]); /* We grab output so we can display it; we grab writes so we * can compare. */ do { struct pollfd pfd[2]; int ret; pfd[0].fd = output[0]; pfd[0].events = POLLIN|POLLHUP; pfd[1].fd = control[0]; pfd[1].events = POLLIN|POLLHUP; if (type == SUCCESS) ret = poll(pfd, 1, failtest_timeout_ms); else ret = poll(pfd, 2, failtest_timeout_ms); if (ret == 0) hand_down(SIGUSR1); if (ret < 0) { if (errno == EINTR) continue; err(1, "Poll returned %i", ret); } if (pfd[0].revents & POLLIN) { ssize_t len; out = realloc(out, outlen + 8192); len = read(output[0], out + outlen, 8192); outlen += len; } else if (type != SUCCESS && (pfd[1].revents & POLLIN)) { if (read_all(control[0], &type, sizeof(type))) { if (type == WRITE) { if (!read_write_info(control[0])) break; } else if (type == RELEASE_LOCKS) { release_locks(); /* FIXME: Tell them we're done... */ } } } else if (pfd[0].revents & POLLHUP) { break; } } while (type != FAILURE); close(output[0]); close(control[0]); waitpid(child, &status, 0); if (!WIFEXITED(status)) { if (WTERMSIG(status) == SIGUSR1) child_fail(out, outlen, "Timed out"); else child_fail(out, outlen, "Killed by signal %u: ", WTERMSIG(status)); } /* Child printed failure already, just pass up exit code. */ if (type == FAILURE) { fprintf(stderr, "%.*s", (int)outlen, out); tell_parent(type); exit(WEXITSTATUS(status) ? WEXITSTATUS(status) : 1); } if (WEXITSTATUS(status) != 0) child_fail(out, outlen, "Exited with status %i: ", WEXITSTATUS(status)); free(out); signal(SIGUSR1, SIG_DFL); /* Only child does probe. */ probing = false; /* We continue onwards without failing. */ call->fail = false; return false; } static void cleanup_calloc(struct calloc_call *call, bool restore) { trace("undoing calloc %p\n", call->ret); free(call->ret); } void *failtest_calloc(size_t nmemb, size_t size, const char *file, unsigned line) { struct failtest_call *p; struct calloc_call call; call.nmemb = nmemb; call.size = size; p = add_history(FAILTEST_CALLOC, true, file, line, &call); if (should_fail(p)) { p->u.calloc.ret = NULL; p->error = ENOMEM; } else { p->u.calloc.ret = calloc(nmemb, size); set_cleanup(p, cleanup_calloc, struct calloc_call); } trace("calloc %zu x %zu %s:%u -> %p\n", nmemb, size, file, line, p->u.calloc.ret); errno = p->error; return p->u.calloc.ret; } static void cleanup_malloc(struct malloc_call *call, bool restore) { trace("undoing malloc %p\n", call->ret); free(call->ret); } void *failtest_malloc(size_t size, const char *file, unsigned line) { struct failtest_call *p; struct malloc_call call; call.size = size; p = add_history(FAILTEST_MALLOC, true, file, line, &call); if (should_fail(p)) { p->u.malloc.ret = NULL; p->error = ENOMEM; } else { p->u.malloc.ret = malloc(size); set_cleanup(p, cleanup_malloc, struct malloc_call); } trace("malloc %zu %s:%u -> %p\n", size, file, line, p->u.malloc.ret); errno = p->error; return p->u.malloc.ret; } static void cleanup_realloc(struct realloc_call *call, bool restore) { trace("undoing realloc %p\n", call->ret); free(call->ret); } /* Walk back and find out if we got this ptr from a previous routine. */ static void fixup_ptr_history(void *ptr, const char *why) { struct failtest_call *i; /* Start at end of history, work back. */ tlist_for_each_rev(&history, i, list) { switch (i->type) { case FAILTEST_REALLOC: if (i->u.realloc.ret == ptr) { trace("found realloc %p %s:%u matching %s\n", ptr, i->file, i->line, why); i->cleanup = NULL; i->can_leak = false; return; } break; case FAILTEST_MALLOC: if (i->u.malloc.ret == ptr) { trace("found malloc %p %s:%u matching %s\n", ptr, i->file, i->line, why); i->cleanup = NULL; i->can_leak = false; return; } break; case FAILTEST_CALLOC: if (i->u.calloc.ret == ptr) { trace("found calloc %p %s:%u matching %s\n", ptr, i->file, i->line, why); i->cleanup = NULL; i->can_leak = false; return; } break; default: break; } } trace("Did not find %p matching %s\n", ptr, why); } void *failtest_realloc(void *ptr, size_t size, const char *file, unsigned line) { struct failtest_call *p; struct realloc_call call; call.size = size; p = add_history(FAILTEST_REALLOC, true, file, line, &call); /* FIXME: Try one child moving allocation, one not. */ if (should_fail(p)) { p->u.realloc.ret = NULL; p->error = ENOMEM; } else { /* Don't catch this one in the history fixup... */ p->u.realloc.ret = NULL; fixup_ptr_history(ptr, "realloc"); p->u.realloc.ret = realloc(ptr, size); set_cleanup(p, cleanup_realloc, struct realloc_call); } trace("realloc %p %s:%u -> %p\n", ptr, file, line, p->u.realloc.ret); errno = p->error; return p->u.realloc.ret; } /* FIXME: Record free, so we can terminate fixup_ptr_history correctly. * If there's an alloc we don't see, it could get confusing if it matches * a previous allocation we did see. */ void failtest_free(void *ptr) { fixup_ptr_history(ptr, "free"); trace("free %p\n", ptr); free(ptr); } static struct contents_saved *save_file(const char *pathname) { int fd; struct contents_saved *s; fd = open(pathname, O_RDONLY); if (fd < 0) return NULL; s = save_contents(pathname, fd, lseek(fd, 0, SEEK_END), 0, "open with O_TRUNC"); close(fd); return s; } /* Optimization: don't create a child for an open which *we know* * would fail anyway. */ static bool open_would_fail(const char *pathname, int flags) { if ((flags & O_ACCMODE) == O_RDONLY) return access(pathname, R_OK) != 0; if (!(flags & O_CREAT)) { if ((flags & O_ACCMODE) == O_WRONLY) return access(pathname, W_OK) != 0; if ((flags & O_ACCMODE) == O_RDWR) return access(pathname, W_OK) != 0 || access(pathname, R_OK) != 0; } /* FIXME: We could check if it exists, for O_CREAT|O_EXCL */ return false; } static void cleanup_open(struct open_call *call, bool restore) { if (restore && call->saved) restore_contents(container_of(call, struct failtest_call, u.open), call->saved, false, "open with O_TRUNC"); if (!call->closed) { trace("Cleaning up open %s by closing fd %i\n", call->pathname, call->ret); close(call->ret); call->closed = true; } free(call->saved); } int failtest_open(const char *pathname, const char *file, unsigned line, ...) { struct failtest_call *p; struct open_call call; va_list ap; call.pathname = strdup(pathname); va_start(ap, line); call.flags = va_arg(ap, int); call.always_save = false; call.closed = false; if (call.flags & O_CREAT) { call.mode = va_arg(ap, int); va_end(ap); } p = add_history(FAILTEST_OPEN, true, file, line, &call); /* Avoid memory leak! */ if (p == &unrecorded_call) free((char *)call.pathname); if (should_fail(p)) { /* Don't bother inserting failures that would happen anyway. */ if (open_would_fail(pathname, call.flags)) { trace("Open would have failed anyway: stopping\n"); failtest_cleanup(true, 0); } p->u.open.ret = -1; /* FIXME: Play with error codes? */ p->error = EACCES; } else { /* Save the old version if they're truncating it. */ if (call.flags & O_TRUNC) p->u.open.saved = save_file(pathname); else p->u.open.saved = NULL; p->u.open.ret = open(pathname, call.flags, call.mode); if (p->u.open.ret == -1) { p->u.open.closed = true; p->can_leak = false; } else { set_cleanup(p, cleanup_open, struct open_call); } } trace("open %s %s:%u -> %i (opener %p)\n", pathname, file, line, p->u.open.ret, &p->u.open); errno = p->error; return p->u.open.ret; } static void cleanup_mmap(struct mmap_call *mmap, bool restore) { trace("cleaning up mmap @%p (opener %p)\n", mmap->ret, mmap->opener); if (restore) restore_contents(mmap->opener, mmap->saved, false, "mmap"); free(mmap->saved); } void *failtest_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset, const char *file, unsigned line) { struct failtest_call *p; struct mmap_call call; call.addr = addr; call.length = length; call.prot = prot; call.flags = flags; call.offset = offset; call.fd = fd; call.opener = opener_of(fd); /* If we don't know what file it was, don't fail. */ if (!call.opener) { if (fd != -1) { fwarnx("failtest_mmap: couldn't figure out source for" " fd %i at %s:%u", fd, file, line); } addr = mmap(addr, length, prot, flags, fd, offset); trace("mmap of fd %i -> %p (opener = NULL)\n", fd, addr); return addr; } p = add_history(FAILTEST_MMAP, false, file, line, &call); if (should_fail(p)) { p->u.mmap.ret = MAP_FAILED; p->error = ENOMEM; } else { p->u.mmap.ret = mmap(addr, length, prot, flags, fd, offset); /* Save contents if we're writing to a normal file */ if (p->u.mmap.ret != MAP_FAILED && (prot & PROT_WRITE) && call.opener->type == FAILTEST_OPEN) { const char *fname = call.opener->u.open.pathname; p->u.mmap.saved = save_contents(fname, fd, length, offset, "being mmapped"); set_cleanup(p, cleanup_mmap, struct mmap_call); } } trace("mmap of fd %i %s:%u -> %p (opener = %p)\n", fd, file, line, addr, call.opener); errno = p->error; return p->u.mmap.ret; } /* Since OpenBSD can't handle adding args, we use this file and line. * This will make all mmaps look the same, reducing coverage. */ void *failtest_mmap_noloc(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { return failtest_mmap(addr, length, prot, flags, fd, offset, __FILE__, __LINE__); } static void cleanup_pipe(struct pipe_call *call, bool restore) { trace("cleaning up pipe fd=%i%s,%i%s\n", call->fds[0], call->closed[0] ? "(already closed)" : "", call->fds[1], call->closed[1] ? "(already closed)" : ""); if (!call->closed[0]) close(call->fds[0]); if (!call->closed[1]) close(call->fds[1]); } int failtest_pipe(int pipefd[2], const char *file, unsigned line) { struct failtest_call *p; struct pipe_call call; p = add_history(FAILTEST_PIPE, true, file, line, &call); if (should_fail(p)) { p->u.open.ret = -1; /* FIXME: Play with error codes? */ p->error = EMFILE; } else { p->u.pipe.ret = pipe(p->u.pipe.fds); p->u.pipe.closed[0] = p->u.pipe.closed[1] = false; set_cleanup(p, cleanup_pipe, struct pipe_call); } trace("pipe %s:%u -> %i,%i\n", file, line, p->u.pipe.ret ? -1 : p->u.pipe.fds[0], p->u.pipe.ret ? -1 : p->u.pipe.fds[1]); /* This causes valgrind to notice if they use pipefd[] after failure */ memcpy(pipefd, p->u.pipe.fds, sizeof(p->u.pipe.fds)); errno = p->error; return p->u.pipe.ret; } static void cleanup_read(struct read_call *call, bool restore) { if (restore) { trace("cleaning up read on fd %i: seeking to %llu\n", call->fd, (long long)call->off); /* Read (not readv!) moves file offset! */ if (lseek(call->fd, call->off, SEEK_SET) != call->off) { fwarn("Restoring lseek pointer failed (read)"); } } } static ssize_t failtest_add_read(int fd, void *buf, size_t count, off_t off, bool is_pread, const char *file, unsigned line) { struct failtest_call *p; struct read_call call; call.fd = fd; call.buf = buf; call.count = count; call.off = off; p = add_history(FAILTEST_READ, false, file, line, &call); /* FIXME: Try partial read returns. */ if (should_fail(p)) { p->u.read.ret = -1; p->error = EIO; } else { if (is_pread) p->u.read.ret = pread(fd, buf, count, off); else { p->u.read.ret = read(fd, buf, count); if (p->u.read.ret != -1) set_cleanup(p, cleanup_read, struct read_call); } } trace("%sread %s:%u fd %i %zu@%llu -> %i\n", is_pread ? "p" : "", file, line, fd, count, (long long)off, p->u.read.ret); errno = p->error; return p->u.read.ret; } static void cleanup_write(struct write_call *write, bool restore) { trace("cleaning up write on %s\n", write->opener->u.open.pathname); if (restore) restore_contents(write->opener, write->saved, !write->is_pwrite, "write"); free(write->saved); } static ssize_t failtest_add_write(int fd, const void *buf, size_t count, off_t off, bool is_pwrite, const char *file, unsigned line) { struct failtest_call *p; struct write_call call; call.fd = fd; call.buf = buf; call.count = count; call.off = off; call.is_pwrite = is_pwrite; call.opener = opener_of(fd); p = add_history(FAILTEST_WRITE, false, file, line, &call); /* If we're a child, we need to make sure we write the same thing * to non-files as the parent does, so tell it. */ if (control_fd != -1 && off == (off_t)-1) { enum info_type type = WRITE; write_all(control_fd, &type, sizeof(type)); write_all(control_fd, &p->u.write, sizeof(p->u.write)); write_all(control_fd, buf, count); } /* FIXME: Try partial write returns. */ if (should_fail(p)) { p->u.write.ret = -1; p->error = EIO; } else { bool is_file; assert(call.opener == p->u.write.opener); if (p->u.write.opener) { is_file = (p->u.write.opener->type == FAILTEST_OPEN); } else { /* We can't unwind it, so at least check same * in parent and child. */ is_file = false; } /* FIXME: We assume same write order in parent and child */ if (!is_file && child_writes_num != 0) { if (child_writes[0].fd != fd) errx(1, "Child wrote to fd %u, not %u?", child_writes[0].fd, fd); if (child_writes[0].off != p->u.write.off) errx(1, "Child wrote to offset %zu, not %zu?", (size_t)child_writes[0].off, (size_t)p->u.write.off); if (child_writes[0].count != count) errx(1, "Child wrote length %zu, not %zu?", child_writes[0].count, count); if (memcmp(child_writes[0].buf, buf, count)) { child_fail(NULL, 0, "Child wrote differently to" " fd %u than we did!\n", fd); } free((char *)child_writes[0].buf); child_writes_num--; memmove(&child_writes[0], &child_writes[1], sizeof(child_writes[0]) * child_writes_num); /* Child wrote it already. */ trace("write %s:%i on fd %i already done by child\n", file, line, fd); p->u.write.ret = count; errno = p->error; return p->u.write.ret; } if (is_file) { p->u.write.saved = save_contents(call.opener->u.open.pathname, fd, count, off, "being overwritten"); set_cleanup(p, cleanup_write, struct write_call); } /* Though off is current seek ptr for write case, we need to * move it. write() does that for us. */ if (p->u.write.is_pwrite) p->u.write.ret = pwrite(fd, buf, count, off); else p->u.write.ret = write(fd, buf, count); } trace("%swrite %s:%i %zu@%llu on fd %i -> %i\n", p->u.write.is_pwrite ? "p" : "", file, line, count, (long long)off, fd, p->u.write.ret); errno = p->error; return p->u.write.ret; } ssize_t failtest_pwrite(int fd, const void *buf, size_t count, off_t offset, const char *file, unsigned line) { return failtest_add_write(fd, buf, count, offset, true, file, line); } ssize_t failtest_write(int fd, const void *buf, size_t count, const char *file, unsigned line) { return failtest_add_write(fd, buf, count, lseek(fd, 0, SEEK_CUR), false, file, line); } ssize_t failtest_pread(int fd, void *buf, size_t count, off_t off, const char *file, unsigned line) { return failtest_add_read(fd, buf, count, off, true, file, line); } ssize_t failtest_read(int fd, void *buf, size_t count, const char *file, unsigned line) { return failtest_add_read(fd, buf, count, lseek(fd, 0, SEEK_CUR), false, file, line); } static struct lock_info *WARN_UNUSED_RESULT add_lock(struct lock_info *locks, int fd, off_t start, off_t end, int type) { unsigned int i; struct lock_info *l; for (i = 0; i < lock_num; i++) { l = &locks[i]; if (l->fd != fd) continue; /* Four cases we care about: * Start overlap: * l = | | * new = | | * Mid overlap: * l = | | * new = | | * End overlap: * l = | | * new = | | * Total overlap: * l = | | * new = | | */ if (start > l->start && end < l->end) { /* Mid overlap: trim entry, add new one. */ off_t new_start, new_end; new_start = end + 1; new_end = l->end; trace("splitting lock on fd %i from %llu-%llu" " to %llu-%llu\n", fd, (long long)l->start, (long long)l->end, (long long)l->start, (long long)start - 1); l->end = start - 1; locks = add_lock(locks, fd, new_start, new_end, l->type); l = &locks[i]; } else if (start <= l->start && end >= l->end) { /* Total overlap: eliminate entry. */ trace("erasing lock on fd %i %llu-%llu\n", fd, (long long)l->start, (long long)l->end); l->end = 0; l->start = 1; } else if (end >= l->start && end < l->end) { trace("trimming lock on fd %i from %llu-%llu" " to %llu-%llu\n", fd, (long long)l->start, (long long)l->end, (long long)end + 1, (long long)l->end); /* Start overlap: trim entry. */ l->start = end + 1; } else if (start > l->start && start <= l->end) { trace("trimming lock on fd %i from %llu-%llu" " to %llu-%llu\n", fd, (long long)l->start, (long long)l->end, (long long)l->start, (long long)start - 1); /* End overlap: trim entry. */ l->end = start-1; } /* Nothing left? Remove it. */ if (l->end < l->start) { trace("forgetting lock on fd %i\n", fd); memmove(l, l + 1, (--lock_num - i) * sizeof(l[0])); i--; } } if (type != F_UNLCK) { locks = realloc(locks, (lock_num + 1) * sizeof(*locks)); l = &locks[lock_num++]; l->fd = fd; l->start = start; l->end = end; l->type = type; trace("new lock on fd %i %llu-%llu\n", fd, (long long)l->start, (long long)l->end); } return locks; } /* We trap this so we can record it: we don't fail it. */ int failtest_close(int fd, const char *file, unsigned line) { struct close_call call; struct failtest_call *p, *opener; /* Do this before we add ourselves to history! */ opener = opener_of(fd); call.fd = fd; p = add_history(FAILTEST_CLOSE, false, file, line, &call); p->fail = false; /* Consume close from failpath (shouldn't tell us to fail). */ if (following_path()) { if (follow_path(p)) abort(); } trace("close on fd %i\n", fd); if (fd < 0) return close(fd); /* Mark opener as not leaking, remove its cleanup function. */ if (opener) { trace("close on fd %i found opener %p\n", fd, opener); if (opener->type == FAILTEST_PIPE) { /* From a pipe? */ if (opener->u.pipe.fds[0] == fd) { assert(!opener->u.pipe.closed[0]); opener->u.pipe.closed[0] = true; } else if (opener->u.pipe.fds[1] == fd) { assert(!opener->u.pipe.closed[1]); opener->u.pipe.closed[1] = true; } else abort(); opener->can_leak = (!opener->u.pipe.closed[0] || !opener->u.pipe.closed[1]); } else if (opener->type == FAILTEST_OPEN) { opener->u.open.closed = true; opener->can_leak = false; } else abort(); } /* Restore offset now, in case parent shared (can't do after close!). */ if (control_fd != -1) { struct failtest_call *i; tlist_for_each_rev(&history, i, list) { if (i == our_history_start) break; if (i == opener) break; if (i->type == FAILTEST_LSEEK && i->u.lseek.fd == fd) { trace("close on fd %i undoes lseek\n", fd); /* This seeks back. */ i->cleanup(&i->u, true); i->cleanup = NULL; } else if (i->type == FAILTEST_WRITE && i->u.write.fd == fd && !i->u.write.is_pwrite) { trace("close on fd %i undoes write" " offset change\n", fd); /* Write (not pwrite!) moves file offset! */ if (lseek(fd, i->u.write.off, SEEK_SET) != i->u.write.off) { fwarn("Restoring lseek pointer failed (write)"); } } else if (i->type == FAILTEST_READ && i->u.read.fd == fd) { /* preads don't *have* cleanups */ if (i->cleanup) { trace("close on fd %i undoes read" " offset change\n", fd); /* This seeks back. */ i->cleanup(&i->u, true); i->cleanup = NULL; } } } } /* Close unlocks everything. */ locks = add_lock(locks, fd, 0, off_max(), F_UNLCK); return close(fd); } /* Zero length means "to end of file" */ static off_t end_of(off_t start, off_t len) { if (len == 0) return off_max(); return start + len - 1; } /* FIXME: This only handles locks, really. */ int failtest_fcntl(int fd, const char *file, unsigned line, int cmd, ...) { struct failtest_call *p; struct fcntl_call call; va_list ap; call.fd = fd; call.cmd = cmd; /* Argument extraction. */ switch (cmd) { case F_SETFL: case F_SETFD: va_start(ap, cmd); call.arg.l = va_arg(ap, long); va_end(ap); trace("fcntl on fd %i F_SETFL/F_SETFD\n", fd); return fcntl(fd, cmd, call.arg.l); case F_GETFD: case F_GETFL: trace("fcntl on fd %i F_GETFL/F_GETFD\n", fd); return fcntl(fd, cmd); case F_GETLK: trace("fcntl on fd %i F_GETLK\n", fd); get_locks(); va_start(ap, cmd); call.arg.fl = *va_arg(ap, struct flock *); va_end(ap); return fcntl(fd, cmd, &call.arg.fl); case F_SETLK: case F_SETLKW: trace("fcntl on fd %i F_SETLK%s\n", fd, cmd == F_SETLKW ? "W" : ""); va_start(ap, cmd); call.arg.fl = *va_arg(ap, struct flock *); va_end(ap); break; default: /* This means you need to implement it here. */ err(1, "failtest: unknown fcntl %u", cmd); } p = add_history(FAILTEST_FCNTL, false, file, line, &call); if (should_fail(p)) { p->u.fcntl.ret = -1; if (p->u.fcntl.cmd == F_SETLK) p->error = EAGAIN; else p->error = EDEADLK; } else { get_locks(); p->u.fcntl.ret = fcntl(p->u.fcntl.fd, p->u.fcntl.cmd, &p->u.fcntl.arg.fl); if (p->u.fcntl.ret == -1) p->error = errno; else { /* We don't handle anything else yet. */ assert(p->u.fcntl.arg.fl.l_whence == SEEK_SET); locks = add_lock(locks, p->u.fcntl.fd, p->u.fcntl.arg.fl.l_start, end_of(p->u.fcntl.arg.fl.l_start, p->u.fcntl.arg.fl.l_len), p->u.fcntl.arg.fl.l_type); } } trace("fcntl on fd %i -> %i\n", fd, p->u.fcntl.ret); errno = p->error; return p->u.fcntl.ret; } static void cleanup_lseek(struct lseek_call *call, bool restore) { if (restore) { trace("cleaning up lseek on fd %i -> %llu\n", call->fd, (long long)call->old_off); if (lseek(call->fd, call->old_off, SEEK_SET) != call->old_off) fwarn("Restoring lseek pointer failed"); } } /* We trap this so we can undo it: we don't fail it. */ off_t failtest_lseek(int fd, off_t offset, int whence, const char *file, unsigned int line) { struct failtest_call *p; struct lseek_call call; call.fd = fd; call.offset = offset; call.whence = whence; call.old_off = lseek(fd, 0, SEEK_CUR); p = add_history(FAILTEST_LSEEK, false, file, line, &call); p->fail = false; /* Consume lseek from failpath. */ if (failpath) if (should_fail(p)) abort(); p->u.lseek.ret = lseek(fd, offset, whence); if (p->u.lseek.ret != (off_t)-1) set_cleanup(p, cleanup_lseek, struct lseek_call); trace("lseek %s:%u on fd %i from %llu to %llu%s\n", file, line, fd, (long long)call.old_off, (long long)offset, whence == SEEK_CUR ? " (from current off)" : whence == SEEK_END ? " (from end)" : whence == SEEK_SET ? "" : " (invalid whence)"); return p->u.lseek.ret; } pid_t failtest_getpid(const char *file, unsigned line) { /* You must call failtest_init first! */ assert(orig_pid); return orig_pid; } void failtest_init(int argc, char *argv[]) { unsigned int i; orig_pid = getpid(); warnf = fdopen(move_fd_to_high(dup(STDERR_FILENO)), "w"); for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "--failpath=", strlen("--failpath="))) { failpath = argv[i] + strlen("--failpath="); } else if (strcmp(argv[i], "--trace") == 0) { tracef = warnf; failtest_timeout_ms = -1; } else if (!strncmp(argv[i], "--debugpath=", strlen("--debugpath="))) { debugpath = argv[i] + strlen("--debugpath="); } } failtable_init(&failtable); start = time_now(); } bool failtest_has_failed(void) { return control_fd != -1; } void failtest_exit(int status) { trace("failtest_exit with status %i\n", status); if (failtest_exit_check) { if (!failtest_exit_check(&history)) child_fail(NULL, 0, "failtest_exit_check failed\n"); } failtest_cleanup(false, status); } sbsigntool-0.9.2/lib/ccan/ccan/failtest/failtest.h000066400000000000000000000133301342142174400220640ustar00rootroot00000000000000/* Licensed under LGPL - see LICENSE file for details */ #ifndef CCAN_FAILTEST_H #define CCAN_FAILTEST_H #include "config.h" #if HAVE_FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 #endif #include #include #include #include #include /** * failtest_init - initialize the failtest module * @argc: the number of commandline arguments * @argv: the commandline argument array * * This initializes the module, and in particular if argv[1] is "--failpath=" * then it ensures that failures follow that pattern. This allows easy * debugging of complex failure paths. */ void failtest_init(int argc, char *argv[]); /** * failtest_exit - clean up and exit the test * @status: the status (usually exit_status() from ccan/tap). * * This cleans up and changes to files made in this child, and exits the test. * It also calls your failtest_default_hook, if any. * * A child which does not exit via failtest_exit() will cause the overall test * to fail. */ void NORETURN failtest_exit(int status); /** * enum failtest_call_type - discriminator for failtest_call.u */ enum failtest_call_type { FAILTEST_MALLOC, FAILTEST_CALLOC, FAILTEST_REALLOC, FAILTEST_OPEN, FAILTEST_CLOSE, FAILTEST_PIPE, FAILTEST_READ, FAILTEST_WRITE, FAILTEST_FCNTL, FAILTEST_MMAP, FAILTEST_LSEEK }; struct calloc_call { void *ret; size_t nmemb; size_t size; }; struct malloc_call { void *ret; size_t size; }; struct realloc_call { void *ret; void *ptr; size_t size; }; struct open_call { int ret; const char *pathname; int flags; mode_t mode; bool always_save; bool closed; /* This is used for O_TRUNC opens on existing files. */ struct contents_saved *saved; }; struct close_call { int fd; }; struct pipe_call { int ret; int fds[2]; bool closed[2]; }; struct read_call { ssize_t ret; off_t off; int fd; void *buf; size_t count; }; struct write_call { ssize_t ret; int fd; const void *buf; size_t count; off_t off; bool is_pwrite; struct failtest_call *opener; struct contents_saved *saved; }; struct fcntl_call { int ret; int fd; int cmd; union { struct flock fl; long l; int i; } arg; }; struct mmap_call { void *ret; void *addr; size_t length; int prot; int flags; int fd; off_t offset; struct failtest_call *opener; struct contents_saved *saved; }; struct lseek_call { ssize_t ret; int fd; off_t offset; int whence; off_t old_off; }; /** * struct failtest_call - description of a call redirected to failtest module * @type: the call type * @file: the filename of the caller * @line: the line number of the caller * @fail: did this call fail * @error: the errno (if any) * @u: the union of call data * * This structure is used to represent the ordered history of calls. * * See Also: * failtest_hook, failtest_exit_check */ struct failtest_call { /* We're in the history list. */ struct list_node list; enum failtest_call_type type; /* Where we were called from. */ const char *file; unsigned int line; /* Did we fail? */ bool fail; /* What we set errno to. */ int error; /* How do we clean this up? */ void (*cleanup)(void *u, bool restore); /* Should their program have cleaned up? */ bool can_leak; /* Backtrace of call chain. */ void **backtrace; unsigned int backtrace_num; /* The actual call data. */ union { struct calloc_call calloc; struct malloc_call malloc; struct realloc_call realloc; struct open_call open; struct close_call close; struct pipe_call pipe; struct read_call read; struct write_call write; struct fcntl_call fcntl; struct mmap_call mmap; struct lseek_call lseek; } u; }; /* This defines struct tlist_calls. */ TLIST_TYPE(calls, struct failtest_call); enum failtest_result { /* Yes try failing this call. */ FAIL_OK, /* No, don't try failing this call. */ FAIL_DONT_FAIL, /* Try failing this call but don't go too far down that path. */ FAIL_PROBE, }; /** * failtest_hook - whether a certain call should fail or not. * @history: the ordered history of all failtest calls. * * The default value of this hook is failtest_default_hook(), which returns * FAIL_OK (ie. yes, fail the call). * * You can override it, and avoid failing certain calls. The parameters * of the call (but not the return value(s)) will be filled in for the last * call. * * Example: * static enum failtest_result dont_fail_alloc(struct tlist_calls *history) * { * struct failtest_call *call; * call = tlist_tail(history, list); * if (call->type == FAILTEST_MALLOC * || call->type == FAILTEST_CALLOC * || call->type == FAILTEST_REALLOC) * return FAIL_DONT_FAIL; * return FAIL_OK; * } * ... * failtest_hook = dont_fail_alloc; */ extern enum failtest_result (*failtest_hook)(struct tlist_calls *history); /** * failtest_exit_check - hook for additional checks on a failed child. * @history: the ordered history of all failtest calls. * * Your program might have additional checks to do on failure, such as * check that a file is not corrupted, or than an error message has been * logged. * * If this returns false, the path to this failure will be printed and the * overall test will fail. */ extern bool (*failtest_exit_check)(struct tlist_calls *history); /** * failtest_has_failed - determine if a failure has occurred. * * Sometimes you want to exit immediately if you've experienced an * injected failure. This is useful when you have four separate tests * in your test suite, and you don't want to do the next one if you've * had a failure in a previous one. */ extern bool failtest_has_failed(void); /** * failtest_timeout_ms - how long to wait before killing child. * * Default is 20,000 (20 seconds). */ extern unsigned int failtest_timeout_ms; #endif /* CCAN_FAILTEST_H */ sbsigntool-0.9.2/lib/ccan/ccan/failtest/failtest_override.h000066400000000000000000000044231342142174400237660ustar00rootroot00000000000000/* Licensed under LGPL - see LICENSE file for details */ #ifndef CCAN_FAILTEST_OVERRIDE_H #define CCAN_FAILTEST_OVERRIDE_H /* This file is included before the source file to test. */ #include "config.h" #if HAVE_FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 #endif /* Replacement of allocators. */ #include #undef calloc #define calloc(nmemb, size) \ failtest_calloc((nmemb), (size), __FILE__, __LINE__) #undef malloc #define malloc(size) \ failtest_malloc((size), __FILE__, __LINE__) #undef realloc #define realloc(ptr, size) \ failtest_realloc((ptr), (size), __FILE__, __LINE__) #undef free #define free(ptr) \ failtest_free(ptr) /* Replacement of I/O. */ #include #include #include #include #include #undef open #define open(pathname, ...) \ failtest_open((pathname), __FILE__, __LINE__, __VA_ARGS__) #undef pipe #define pipe(pipefd) \ failtest_pipe((pipefd), __FILE__, __LINE__) #undef read #define read(fd, buf, count) \ failtest_read((fd), (buf), (count), __FILE__, __LINE__) #undef write #define write(fd, buf, count) \ failtest_write((fd), (buf), (count), __FILE__, __LINE__) #undef pread #define pread(fd, buf, count, off) \ failtest_pread((fd), (buf), (count), (off), __FILE__, __LINE__) #undef pwrite #define pwrite(fd, buf, count, off) \ failtest_pwrite((fd), (buf), (count), (off), __FILE__, __LINE__) #undef close #define close(fd) failtest_close(fd, __FILE__, __LINE__) #undef fcntl #define fcntl(fd, ...) failtest_fcntl((fd), __FILE__, __LINE__, __VA_ARGS__) #undef mmap /* OpenBSD doesn't idempotent-protect sys/mman.h, so we can't add args. */ #ifdef __OpenBSD__ #define mmap(addr, length, prot, flags, fd, offset) \ failtest_mmap_noloc((addr), (length), (prot), (flags), (fd), (offset)) #else #define mmap(addr, length, prot, flags, fd, offset) \ failtest_mmap((addr), (length), (prot), (flags), (fd), (offset), \ __FILE__, __LINE__) #endif /* !__OpenBSD__ */ #undef lseek #define lseek(fd, offset, whence) \ failtest_lseek((fd), (offset), (whence), __FILE__, __LINE__) /* Replacement of getpid (since failtest will fork). */ #undef getpid #define getpid() failtest_getpid(__FILE__, __LINE__) #include #endif /* CCAN_FAILTEST_OVERRIDE_H */ sbsigntool-0.9.2/lib/ccan/ccan/failtest/failtest_proto.h000066400000000000000000000031301342142174400233040ustar00rootroot00000000000000/* Licensed under LGPL - see LICENSE file for details */ #ifndef CCAN_FAILTEST_PROTO_H #define CCAN_FAILTEST_PROTO_H #include /* Potentially-failing versions of routines; #defined in failtest.h */ void *failtest_calloc(size_t nmemb, size_t size, const char *file, unsigned line); void *failtest_malloc(size_t size, const char *file, unsigned line); void *failtest_realloc(void *ptr, size_t size, const char *file, unsigned line); void failtest_free(void *ptr); int failtest_open(const char *pathname, const char *file, unsigned line, ...); int failtest_pipe(int pipefd[2], const char *file, unsigned line); ssize_t failtest_read(int fd, void *buf, size_t count, const char *file, unsigned line); ssize_t failtest_write(int fd, const void *buf, size_t count, const char *file, unsigned line); ssize_t failtest_pread(int fd, void *buf, size_t count, off_t offset, const char *file, unsigned line); ssize_t failtest_pwrite(int fd, const void *buf, size_t count, off_t offset, const char *file, unsigned line); void *failtest_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset, const char *file, unsigned line); void *failtest_mmap_noloc(void *addr, size_t length, int prot, int flags, int fd, off_t offset); off_t failtest_lseek(int fd, off_t offset, int whence, const char *file, unsigned line); int failtest_close(int fd, const char *file, unsigned line); int failtest_fcntl(int fd, const char *file, unsigned line, int cmd, ...); pid_t failtest_getpid(const char *file, unsigned line); #endif /* CCAN_FAILTEST_PROTO_H */ sbsigntool-0.9.2/lib/ccan/ccan/failtest/failtest_undo.h000066400000000000000000000022401342142174400231070ustar00rootroot00000000000000/* Licensed under LGPL - see LICENSE file for details */ #ifndef CCAN_FAILTEST_RESTORE_H #define CCAN_FAILTEST_RESTORE_H /* This file undoes the effect of failtest_override.h. */ #undef calloc #define calloc(nmemb, size) \ failtest_calloc((nmemb), (size), NULL, 0) #undef malloc #define malloc(size) \ failtest_malloc((size), NULL, 0) #undef realloc #define realloc(ptr, size) \ failtest_realloc((ptr), (size), NULL, 0) #undef open #define open(pathname, ...) \ failtest_open((pathname), NULL, 0, __VA_ARGS__) #undef pipe #define pipe(pipefd) \ failtest_pipe((pipefd), NULL, 0) #undef read #define read(fd, buf, count) \ failtest_read((fd), (buf), (count), NULL, 0) #undef write #define write(fd, buf, count) \ failtest_write((fd), (buf), (count), NULL, 0) #undef mmap #define mmap(addr, length, prot, flags, fd, offset) \ failtest_mmap((addr), (length), (prot), (flags), (fd), (offset), NULL, 0) #undef lseek #define lseek(fd, off, whence) \ failtest_lseek((fd), (off), (whence), NULL, 0) #undef close #define close(fd) failtest_close(fd) #undef fcntl #define fcntl(fd, ...) \ failtest_fcntl((fd), NULL, 0, __VA_ARGS__) #endif /* CCAN_FAILTEST_RESTORE_H */ sbsigntool-0.9.2/lib/ccan/ccan/hash/000077500000000000000000000000001342142174400172105ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/hash/hash.c000066400000000000000000000730511342142174400203050ustar00rootroot00000000000000/* ------------------------------------------------------------------------------- lookup3.c, by Bob Jenkins, May 2006, Public Domain. These are functions for producing 32-bit hashes for hash table lookup. hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() are externally useful functions. Routines to test the hash are included if SELF_TEST is defined. You can use this free for any purpose. It's in the public domain. It has no warranty. You probably want to use hashlittle(). hashlittle() and hashbig() hash byte arrays. hashlittle() is is faster than hashbig() on little-endian machines. Intel and AMD are little-endian machines. On second thought, you probably want hashlittle2(), which is identical to hashlittle() except it returns two 32-bit hashes for the price of one. You could implement hashbig2() if you wanted but I haven't bothered here. If you want to find a hash of, say, exactly 7 integers, do a = i1; b = i2; c = i3; mix(a,b,c); a += i4; b += i5; c += i6; mix(a,b,c); a += i7; final(a,b,c); then use c as the hash value. If you have a variable length array of 4-byte integers to hash, use hash_word(). If you have a byte array (like a character string), use hashlittle(). If you have several byte arrays, or a mix of things, see the comments above hashlittle(). Why is this so big? I read 12 bytes at a time into 3 4-byte integers, then mix those integers. This is fast (you can do a lot more thorough mixing with 12*3 instructions on 3 integers than you can with 3 instructions on 1 byte), but shoehorning those bytes into integers efficiently is messy. ------------------------------------------------------------------------------- */ //#define SELF_TEST 1 #if 0 #include /* defines printf for tests */ #include /* defines time_t for timings in the test */ #include /* defines uint32_t etc */ #include /* attempt to define endianness */ #ifdef linux # include /* attempt to define endianness */ #endif /* * My best guess at if you are big-endian or little-endian. This may * need adjustment. */ #if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ __BYTE_ORDER == __LITTLE_ENDIAN) || \ (defined(i386) || defined(__i386__) || defined(__i486__) || \ defined(__i586__) || defined(__i686__) || defined(__x86_64) || \ defined(vax) || defined(MIPSEL)) # define HASH_LITTLE_ENDIAN 1 # define HASH_BIG_ENDIAN 0 #elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ __BYTE_ORDER == __BIG_ENDIAN) || \ (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) # define HASH_LITTLE_ENDIAN 0 # define HASH_BIG_ENDIAN 1 #else # error Unknown endian #endif #endif /* old hash.c headers. */ #include "hash.h" #if HAVE_LITTLE_ENDIAN #define HASH_LITTLE_ENDIAN 1 #define HASH_BIG_ENDIAN 0 #elif HAVE_BIG_ENDIAN #define HASH_LITTLE_ENDIAN 0 #define HASH_BIG_ENDIAN 1 #else #error Unknown endian #endif #define hashsize(n) ((uint32_t)1<<(n)) #define hashmask(n) (hashsize(n)-1) #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) /* ------------------------------------------------------------------------------- mix -- mix 3 32-bit values reversibly. This is reversible, so any information in (a,b,c) before mix() is still in (a,b,c) after mix(). If four pairs of (a,b,c) inputs are run through mix(), or through mix() in reverse, there are at least 32 bits of the output that are sometimes the same for one pair and different for another pair. This was tested for: * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that satisfy this are 4 6 8 16 19 4 9 15 3 18 27 15 14 9 3 7 17 3 Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" defined as + with a one-bit base and a two-bit delta. I used http://burtleburtle.net/bob/hash/avalanche.html to choose the operations, constants, and arrangements of the variables. This does not achieve avalanche. There are input bits of (a,b,c) that fail to affect some output bits of (a,b,c), especially of a. The most thoroughly mixed value is c, but it doesn't really even achieve avalanche in c. This allows some parallelism. Read-after-writes are good at doubling the number of bits affected, so the goal of mixing pulls in the opposite direction as the goal of parallelism. I did what I could. Rotates seem to cost as much as shifts on every machine I could lay my hands on, and rotates are much kinder to the top and bottom bits, so I used rotates. ------------------------------------------------------------------------------- */ #define mix(a,b,c) \ { \ a -= c; a ^= rot(c, 4); c += b; \ b -= a; b ^= rot(a, 6); a += c; \ c -= b; c ^= rot(b, 8); b += a; \ a -= c; a ^= rot(c,16); c += b; \ b -= a; b ^= rot(a,19); a += c; \ c -= b; c ^= rot(b, 4); b += a; \ } /* ------------------------------------------------------------------------------- final -- final mixing of 3 32-bit values (a,b,c) into c Pairs of (a,b,c) values differing in only a few bits will usually produce values of c that look totally different. This was tested for * pairs that differed by one bit, by two bits, in any combination of top bits of (a,b,c), or in any combination of bottom bits of (a,b,c). * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly produced by subtraction) look like a single 1-bit difference. * the base values were pseudorandom, all zero but one bit set, or all zero plus a counter that starts at zero. These constants passed: 14 11 25 16 4 14 24 12 14 25 16 4 14 24 and these came close: 4 8 15 26 3 22 24 10 8 15 26 3 22 24 11 8 15 26 3 22 24 ------------------------------------------------------------------------------- */ #define final(a,b,c) \ { \ c ^= b; c -= rot(b,14); \ a ^= c; a -= rot(c,11); \ b ^= a; b -= rot(a,25); \ c ^= b; c -= rot(b,16); \ a ^= c; a -= rot(c,4); \ b ^= a; b -= rot(a,14); \ c ^= b; c -= rot(b,24); \ } /* -------------------------------------------------------------------- This works on all machines. To be useful, it requires -- that the key be an array of uint32_t's, and -- that the length be the number of uint32_t's in the key The function hash_word() is identical to hashlittle() on little-endian machines, and identical to hashbig() on big-endian machines, except that the length has to be measured in uint32_ts rather than in bytes. hashlittle() is more complicated than hash_word() only because hashlittle() has to dance around fitting the key bytes into registers. -------------------------------------------------------------------- */ uint32_t hash_u32( const uint32_t *k, /* the key, an array of uint32_t values */ size_t length, /* the length of the key, in uint32_ts */ uint32_t initval) /* the previous hash, or an arbitrary value */ { uint32_t a,b,c; /* Set up the internal state */ a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval; /*------------------------------------------------- handle most of the key */ while (length > 3) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 3; k += 3; } /*------------------------------------------- handle the last 3 uint32_t's */ switch(length) /* all the case statements fall through */ { case 3 : c+=k[2]; case 2 : b+=k[1]; case 1 : a+=k[0]; final(a,b,c); case 0: /* case 0: nothing left to add */ break; } /*------------------------------------------------------ report the result */ return c; } /* ------------------------------------------------------------------------------- hashlittle() -- hash a variable-length key into a 32-bit value k : the key (the unaligned variable-length array of bytes) length : the length of the key, counting by bytes val2 : IN: can be any 4-byte value OUT: second 32 bit hash. Returns a 32-bit value. Every bit of the key affects every bit of the return value. Two keys differing by one or two bits will have totally different hash values. Note that the return value is better mixed than val2, so use that first. The best hash table sizes are powers of 2. There is no need to do mod a prime (mod is sooo slow!). If you need less than 32 bits, use a bitmask. For example, if you need only 10 bits, do h = (h & hashmask(10)); In which case, the hash table should have hashsize(10) elements. If you are hashing n strings (uint8_t **)k, do it like this: for (i=0, h=0; i 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]&0xffffff" actually reads beyond the end of the string, but * then masks off the part it's not allowed to read. Because the * string is aligned, the masked-off tail is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). * * Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR. */ #if 0 switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff; a+=k[0]; break; case 6 : b+=k[1]&0xffff; a+=k[0]; break; case 5 : b+=k[1]&0xff; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff; break; case 2 : a+=k[0]&0xffff; break; case 1 : a+=k[0]&0xff; break; case 0 : return c; /* zero length strings require no mixing */ } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ case 1 : a+=k8[0]; break; case 0 : return c; } #endif /* !valgrind */ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ const uint8_t *k8; /*--------------- all but last block: aligned reads and different mixing */ while (length > 12) { a += k[0] + (((uint32_t)k[1])<<16); b += k[2] + (((uint32_t)k[3])<<16); c += k[4] + (((uint32_t)k[5])<<16); mix(a,b,c); length -= 12; k += 6; } /*----------------------------- handle the last (probably partial) block */ k8 = (const uint8_t *)k; switch(length) { case 12: c+=k[4]+(((uint32_t)k[5])<<16); b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ case 10: c+=k[4]; b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 9 : c+=k8[8]; /* fall through */ case 8 : b+=k[2]+(((uint32_t)k[3])<<16); a+=k[0]+(((uint32_t)k[1])<<16); break; case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ case 6 : b+=k[2]; a+=k[0]+(((uint32_t)k[1])<<16); break; case 5 : b+=k8[4]; /* fall through */ case 4 : a+=k[0]+(((uint32_t)k[1])<<16); break; case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ case 2 : a+=k[0]; break; case 1 : a+=k8[0]; break; case 0 : return c; /* zero length requires no mixing */ } } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; a += ((uint32_t)k[1])<<8; a += ((uint32_t)k[2])<<16; a += ((uint32_t)k[3])<<24; b += k[4]; b += ((uint32_t)k[5])<<8; b += ((uint32_t)k[6])<<16; b += ((uint32_t)k[7])<<24; c += k[8]; c += ((uint32_t)k[9])<<8; c += ((uint32_t)k[10])<<16; c += ((uint32_t)k[11])<<24; mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=((uint32_t)k[11])<<24; case 11: c+=((uint32_t)k[10])<<16; case 10: c+=((uint32_t)k[9])<<8; case 9 : c+=k[8]; case 8 : b+=((uint32_t)k[7])<<24; case 7 : b+=((uint32_t)k[6])<<16; case 6 : b+=((uint32_t)k[5])<<8; case 5 : b+=k[4]; case 4 : a+=((uint32_t)k[3])<<24; case 3 : a+=((uint32_t)k[2])<<16; case 2 : a+=((uint32_t)k[1])<<8; case 1 : a+=k[0]; break; case 0 : return c; } } final(a,b,c); *val2 = b; return c; } /* * hashbig(): * This is the same as hash_word() on big-endian machines. It is different * from hashlittle() on all machines. hashbig() takes advantage of * big-endian byte ordering. */ static uint32_t hashbig( const void *key, size_t length, uint32_t *val2) { uint32_t a,b,c; union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ /* Set up the internal state */ a = b = c = 0xdeadbeef + ((uint32_t)length) + *val2; u.ptr = key; if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ const uint8_t *k8; /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ while (length > 12) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); length -= 12; k += 3; } /*----------------------------- handle the last (probably partial) block */ /* * "k[2]<<8" actually reads beyond the end of the string, but * then shifts out the part it's not allowed to read. Because the * string is aligned, the illegal read is in the same word as the * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). * * Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR. */ #if 0 switch(length) { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; case 5 : b+=k[1]&0xff000000; a+=k[0]; break; case 4 : a+=k[0]; break; case 3 : a+=k[0]&0xffffff00; break; case 2 : a+=k[0]&0xffff0000; break; case 1 : a+=k[0]&0xff000000; break; case 0 : return c; /* zero length strings require no mixing */ } #else /* make valgrind happy */ k8 = (const uint8_t *)k; switch(length) /* all the case statements fall through */ { case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ case 8 : b+=k[1]; a+=k[0]; break; case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ case 4 : a+=k[0]; break; case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ case 1 : a+=((uint32_t)k8[0])<<24; break; case 0 : return c; } #endif /* !VALGRIND */ } else { /* need to read the key one byte at a time */ const uint8_t *k = (const uint8_t *)key; /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ while (length > 12) { a += ((uint32_t)k[0])<<24; a += ((uint32_t)k[1])<<16; a += ((uint32_t)k[2])<<8; a += ((uint32_t)k[3]); b += ((uint32_t)k[4])<<24; b += ((uint32_t)k[5])<<16; b += ((uint32_t)k[6])<<8; b += ((uint32_t)k[7]); c += ((uint32_t)k[8])<<24; c += ((uint32_t)k[9])<<16; c += ((uint32_t)k[10])<<8; c += ((uint32_t)k[11]); mix(a,b,c); length -= 12; k += 12; } /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { case 12: c+=k[11]; case 11: c+=((uint32_t)k[10])<<8; case 10: c+=((uint32_t)k[9])<<16; case 9 : c+=((uint32_t)k[8])<<24; case 8 : b+=k[7]; case 7 : b+=((uint32_t)k[6])<<8; case 6 : b+=((uint32_t)k[5])<<16; case 5 : b+=((uint32_t)k[4])<<24; case 4 : a+=k[3]; case 3 : a+=((uint32_t)k[2])<<8; case 2 : a+=((uint32_t)k[1])<<16; case 1 : a+=((uint32_t)k[0])<<24; break; case 0 : return c; } } final(a,b,c); *val2 = b; return c; } /* I basically use hashlittle here, but use native endian within each * element. This delivers least-surprise: hash such as "int arr[] = { * 1, 2 }; hash_stable(arr, 2, 0);" will be the same on big and little * endian machines, even though a bytewise hash wouldn't be. */ uint64_t hash64_stable_64(const void *key, size_t n, uint64_t base) { const uint64_t *k = key; uint32_t a,b,c; /* Set up the internal state */ a = b = c = 0xdeadbeef + ((uint32_t)n*8) + (base >> 32) + base; while (n > 3) { a += (uint32_t)k[0]; b += (uint32_t)(k[0] >> 32); c += (uint32_t)k[1]; mix(a,b,c); a += (uint32_t)(k[1] >> 32); b += (uint32_t)k[2]; c += (uint32_t)(k[2] >> 32); mix(a,b,c); n -= 3; k += 3; } switch (n) { case 2: a += (uint32_t)k[0]; b += (uint32_t)(k[0] >> 32); c += (uint32_t)k[1]; mix(a,b,c); a += (uint32_t)(k[1] >> 32); break; case 1: a += (uint32_t)k[0]; b += (uint32_t)(k[0] >> 32); break; case 0: return c; } final(a,b,c); return ((uint64_t)b << 32) | c; } uint64_t hash64_stable_32(const void *key, size_t n, uint64_t base) { const uint32_t *k = key; uint32_t a,b,c; /* Set up the internal state */ a = b = c = 0xdeadbeef + ((uint32_t)n*4) + (base >> 32) + base; while (n > 3) { a += k[0]; b += k[1]; c += k[2]; mix(a,b,c); n -= 3; k += 3; } switch (n) { case 2: b += (uint32_t)k[1]; case 1: a += (uint32_t)k[0]; break; case 0: return c; } final(a,b,c); return ((uint64_t)b << 32) | c; } uint64_t hash64_stable_16(const void *key, size_t n, uint64_t base) { const uint16_t *k = key; uint32_t a,b,c; /* Set up the internal state */ a = b = c = 0xdeadbeef + ((uint32_t)n*2) + (base >> 32) + base; while (n > 6) { a += (uint32_t)k[0] + ((uint32_t)k[1] << 16); b += (uint32_t)k[2] + ((uint32_t)k[3] << 16); c += (uint32_t)k[4] + ((uint32_t)k[5] << 16); mix(a,b,c); n -= 6; k += 6; } switch (n) { case 5: c += (uint32_t)k[4]; case 4: b += ((uint32_t)k[3] << 16); case 3: b += (uint32_t)k[2]; case 2: a += ((uint32_t)k[1] << 16); case 1: a += (uint32_t)k[0]; break; case 0: return c; } final(a,b,c); return ((uint64_t)b << 32) | c; } uint64_t hash64_stable_8(const void *key, size_t n, uint64_t base) { uint32_t b32 = base + (base >> 32); uint32_t lower = hashlittle(key, n, &b32); return ((uint64_t)b32 << 32) | lower; } uint32_t hash_any(const void *key, size_t length, uint32_t base) { if (HASH_BIG_ENDIAN) return hashbig(key, length, &base); else return hashlittle(key, length, &base); } uint32_t hash_stable_64(const void *key, size_t n, uint32_t base) { return hash64_stable_64(key, n, base); } uint32_t hash_stable_32(const void *key, size_t n, uint32_t base) { return hash64_stable_32(key, n, base); } uint32_t hash_stable_16(const void *key, size_t n, uint32_t base) { return hash64_stable_16(key, n, base); } uint32_t hash_stable_8(const void *key, size_t n, uint32_t base) { return hashlittle(key, n, &base); } /* Jenkins' lookup8 is a 64 bit hash, but he says it's obsolete. Use * the plain one and recombine into 64 bits. */ uint64_t hash64_any(const void *key, size_t length, uint64_t base) { uint32_t b32 = base + (base >> 32); uint32_t lower; if (HASH_BIG_ENDIAN) lower = hashbig(key, length, &b32); else lower = hashlittle(key, length, &b32); return ((uint64_t)b32 << 32) | lower; } #ifdef SELF_TEST /* used for timings */ void driver1() { uint8_t buf[256]; uint32_t i; uint32_t h=0; time_t a,z; time(&a); for (i=0; i<256; ++i) buf[i] = 'x'; for (i=0; i<1; ++i) { h = hashlittle(&buf[0],1,h); } time(&z); if (z-a > 0) printf("time %d %.8x\n", z-a, h); } /* check that every input bit changes every output bit half the time */ #define HASHSTATE 1 #define HASHLEN 1 #define MAXPAIR 60 #define MAXLEN 70 void driver2() { uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; uint32_t x[HASHSTATE],y[HASHSTATE]; uint32_t hlen; printf("No more than %d trials should ever be needed \n",MAXPAIR/2); for (hlen=0; hlen < MAXLEN; ++hlen) { z=0; for (i=0; i>(8-j)); c[0] = hashlittle(a, hlen, m); b[i] ^= ((k+1)<>(8-j)); d[0] = hashlittle(b, hlen, m); /* check every bit is 1, 0, set, and not set at least once */ for (l=0; lz) z=k; if (k==MAXPAIR) { printf("Some bit didn't change: "); printf("%.8x %.8x %.8x %.8x %.8x %.8x ", e[0],f[0],g[0],h[0],x[0],y[0]); printf("i %d j %d m %d len %d\n", i, j, m, hlen); } if (z==MAXPAIR) goto done; } } } done: if (z < MAXPAIR) { printf("Mix success %2d bytes %2d initvals ",i,m); printf("required %d trials\n", z/2); } } printf("\n"); } /* Check for reading beyond the end of the buffer and alignment problems */ void driver3() { uint8_t buf[MAXLEN+20], *b; uint32_t len; uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; uint32_t h; uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; uint32_t i; uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; uint32_t j; uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; uint32_t ref,x,y; uint8_t *p; printf("Endianness. These lines should all be the same (for values filled in):\n"); printf("%.8x %.8x %.8x\n", hash_word((const uint32_t *)q, (sizeof(q)-1)/4, 13), hash_word((const uint32_t *)q, (sizeof(q)-5)/4, 13), hash_word((const uint32_t *)q, (sizeof(q)-9)/4, 13)); p = q; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qq[1]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qqq[2]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); p = &qqqq[3]; printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); printf("\n"); /* check that hashlittle2 and hashlittle produce the same results */ i=47; j=0; hashlittle2(q, sizeof(q), &i, &j); if (hashlittle(q, sizeof(q), 47) != i) printf("hashlittle2 and hashlittle mismatch\n"); /* check that hash_word2 and hash_word produce the same results */ len = 0xdeadbeef; i=47, j=0; hash_word2(&len, 1, &i, &j); if (hash_word(&len, 1, 47) != i) printf("hash_word2 and hash_word mismatch %x %x\n", i, hash_word(&len, 1, 47)); /* check hashlittle doesn't read before or after the ends of the string */ for (h=0, b=buf+1; h<8; ++h, ++b) { for (i=0; i #include #include /* Stolen mostly from: lookup3.c, by Bob Jenkins, May 2006, Public Domain. * * http://burtleburtle.net/bob/c/lookup3.c */ /** * hash - fast hash of an array for internal use * @p: the array or pointer to first element * @num: the number of elements to hash * @base: the base number to roll into the hash (usually 0) * * The memory region pointed to by p is combined with the base to form * a 32-bit hash. * * This hash will have different results on different machines, so is * only useful for internal hashes (ie. not hashes sent across the * network or saved to disk). * * It may also change with future versions: it could even detect at runtime * what the fastest hash to use is. * * See also: hash64, hash_stable. * * Example: * #include * #include * #include * #include * * // Simple demonstration: idential strings will have the same hash, but * // two different strings will probably not. * int main(int argc, char *argv[]) * { * uint32_t hash1, hash2; * * if (argc != 3) * err(1, "Usage: %s ", argv[0]); * * hash1 = hash(argv[1], strlen(argv[1]), 0); * hash2 = hash(argv[2], strlen(argv[2]), 0); * printf("Hash is %s\n", hash1 == hash2 ? "same" : "different"); * return 0; * } */ #define hash(p, num, base) hash_any((p), (num)*sizeof(*(p)), (base)) /** * hash_stable - hash of an array for external use * @p: the array or pointer to first element * @num: the number of elements to hash * @base: the base number to roll into the hash (usually 0) * * The array of simple integer types pointed to by p is combined with * the base to form a 32-bit hash. * * This hash will have the same results on different machines, so can * be used for external hashes (ie. hashes sent across the network or * saved to disk). The results will not change in future versions of * this module. * * Note that it is only legal to hand an array of simple integer types * to this hash (ie. char, uint16_t, int64_t, etc). In these cases, * the same values will have the same hash result, even though the * memory representations of integers depend on the machine * endianness. * * See also: * hash64_stable * * Example: * #include * #include * #include * #include * * int main(int argc, char *argv[]) * { * if (argc != 2) * err(1, "Usage: %s ", argv[0]); * * printf("Hash stable result is %u\n", * hash_stable(argv[1], strlen(argv[1]), 0)); * return 0; * } */ #define hash_stable(p, num, base) \ (BUILD_ASSERT_OR_ZERO(sizeof(*(p)) == 8 || sizeof(*(p)) == 4 \ || sizeof(*(p)) == 2 || sizeof(*(p)) == 1) + \ sizeof(*(p)) == 8 ? hash_stable_64((p), (num), (base)) \ : sizeof(*(p)) == 4 ? hash_stable_32((p), (num), (base)) \ : sizeof(*(p)) == 2 ? hash_stable_16((p), (num), (base)) \ : hash_stable_8((p), (num), (base))) /** * hash_u32 - fast hash an array of 32-bit values for internal use * @key: the array of uint32_t * @num: the number of elements to hash * @base: the base number to roll into the hash (usually 0) * * The array of uint32_t pointed to by @key is combined with the base * to form a 32-bit hash. This is 2-3 times faster than hash() on small * arrays, but the advantage vanishes over large hashes. * * This hash will have different results on different machines, so is * only useful for internal hashes (ie. not hashes sent across the * network or saved to disk). */ uint32_t hash_u32(const uint32_t *key, size_t num, uint32_t base); /** * hash_string - very fast hash of an ascii string * @str: the nul-terminated string * * The string is hashed, using a hash function optimized for ASCII and * similar strings. It's weaker than the other hash functions. * * This hash may have different results on different machines, so is * only useful for internal hashes (ie. not hashes sent across the * network or saved to disk). The results will be different from the * other hash functions in this module, too. */ static inline uint32_t hash_string(const char *string) { /* This is Karl Nelson 's X31 hash. * It's a little faster than the (much better) lookup3 hash(): 56ns vs * 84ns on my 2GHz Intel Core Duo 2 laptop for a 10 char string. */ uint32_t ret; for (ret = 0; *string; string++) ret = (ret << 5) - ret + *string; return ret; } /** * hash64 - fast 64-bit hash of an array for internal use * @p: the array or pointer to first element * @num: the number of elements to hash * @base: the 64-bit base number to roll into the hash (usually 0) * * The memory region pointed to by p is combined with the base to form * a 64-bit hash. * * This hash will have different results on different machines, so is * only useful for internal hashes (ie. not hashes sent across the * network or saved to disk). * * It may also change with future versions: it could even detect at runtime * what the fastest hash to use is. * * See also: hash. * * Example: * #include * #include * #include * #include * * // Simple demonstration: idential strings will have the same hash, but * // two different strings will probably not. * int main(int argc, char *argv[]) * { * uint64_t hash1, hash2; * * if (argc != 3) * err(1, "Usage: %s ", argv[0]); * * hash1 = hash64(argv[1], strlen(argv[1]), 0); * hash2 = hash64(argv[2], strlen(argv[2]), 0); * printf("Hash is %s\n", hash1 == hash2 ? "same" : "different"); * return 0; * } */ #define hash64(p, num, base) hash64_any((p), (num)*sizeof(*(p)), (base)) /** * hash64_stable - 64 bit hash of an array for external use * @p: the array or pointer to first element * @num: the number of elements to hash * @base: the base number to roll into the hash (usually 0) * * The array of simple integer types pointed to by p is combined with * the base to form a 64-bit hash. * * This hash will have the same results on different machines, so can * be used for external hashes (ie. hashes sent across the network or * saved to disk). The results will not change in future versions of * this module. * * Note that it is only legal to hand an array of simple integer types * to this hash (ie. char, uint16_t, int64_t, etc). In these cases, * the same values will have the same hash result, even though the * memory representations of integers depend on the machine * endianness. * * See also: * hash_stable * * Example: * #include * #include * #include * #include * * int main(int argc, char *argv[]) * { * if (argc != 2) * err(1, "Usage: %s ", argv[0]); * * printf("Hash stable result is %llu\n", * (long long)hash64_stable(argv[1], strlen(argv[1]), 0)); * return 0; * } */ #define hash64_stable(p, num, base) \ (BUILD_ASSERT_OR_ZERO(sizeof(*(p)) == 8 || sizeof(*(p)) == 4 \ || sizeof(*(p)) == 2 || sizeof(*(p)) == 1) + \ sizeof(*(p)) == 8 ? hash64_stable_64((p), (num), (base)) \ : sizeof(*(p)) == 4 ? hash64_stable_32((p), (num), (base)) \ : sizeof(*(p)) == 2 ? hash64_stable_16((p), (num), (base)) \ : hash64_stable_8((p), (num), (base))) /** * hashl - fast 32/64-bit hash of an array for internal use * @p: the array or pointer to first element * @num: the number of elements to hash * @base: the base number to roll into the hash (usually 0) * * This is either hash() or hash64(), on 32/64 bit long machines. */ #define hashl(p, num, base) \ (BUILD_ASSERT_OR_ZERO(sizeof(long) == sizeof(uint32_t) \ || sizeof(long) == sizeof(uint64_t)) + \ (sizeof(long) == sizeof(uint64_t) \ ? hash64((p), (num), (base)) : hash((p), (num), (base)))) /* Our underlying operations. */ uint32_t hash_any(const void *key, size_t length, uint32_t base); uint32_t hash_stable_64(const void *key, size_t n, uint32_t base); uint32_t hash_stable_32(const void *key, size_t n, uint32_t base); uint32_t hash_stable_16(const void *key, size_t n, uint32_t base); uint32_t hash_stable_8(const void *key, size_t n, uint32_t base); uint64_t hash64_any(const void *key, size_t length, uint64_t base); uint64_t hash64_stable_64(const void *key, size_t n, uint64_t base); uint64_t hash64_stable_32(const void *key, size_t n, uint64_t base); uint64_t hash64_stable_16(const void *key, size_t n, uint64_t base); uint64_t hash64_stable_8(const void *key, size_t n, uint64_t base); /** * hash_pointer - hash a pointer for internal use * @p: the pointer value to hash * @base: the base number to roll into the hash (usually 0) * * The pointer p (not what p points to!) is combined with the base to form * a 32-bit hash. * * This hash will have different results on different machines, so is * only useful for internal hashes (ie. not hashes sent across the * network or saved to disk). * * Example: * #include * * // Code to keep track of memory regions. * struct region { * struct region *chain; * void *start; * unsigned int size; * }; * // We keep a simple hash table. * static struct region *region_hash[128]; * * static void add_region(struct region *r) * { * unsigned int h = hash_pointer(r->start, 0); * * r->chain = region_hash[h]; * region_hash[h] = r->chain; * } * * static struct region *find_region(const void *start) * { * struct region *r; * * for (r = region_hash[hash_pointer(start, 0)]; r; r = r->chain) * if (r->start == start) * return r; * return NULL; * } */ static inline uint32_t hash_pointer(const void *p, uint32_t base) { if (sizeof(p) % sizeof(uint32_t) == 0) { /* This convoluted union is the right way of aliasing. */ union { uint32_t u32[sizeof(p) / sizeof(uint32_t)]; const void *p; } u; u.p = p; return hash_u32(u.u32, sizeof(p) / sizeof(uint32_t), base); } else return hash(&p, 1, base); } #endif /* HASH_H */ sbsigntool-0.9.2/lib/ccan/ccan/htable/000077500000000000000000000000001342142174400175245ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/htable/LICENSE000077700000000000000000000000001342142174400237362../../licenses/LGPL-2.1ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/htable/htable.c000066400000000000000000000152421342142174400211330ustar00rootroot00000000000000/* Licensed under LGPLv2+ - see LICENSE file for details */ #include #include #include #include #include #include /* We use 0x1 as deleted marker. */ #define HTABLE_DELETED (0x1) /* We clear out the bits which are always the same, and put metadata there. */ static inline uintptr_t get_extra_ptr_bits(const struct htable *ht, uintptr_t e) { return e & ht->common_mask; } static inline void *get_raw_ptr(const struct htable *ht, uintptr_t e) { return (void *)((e & ~ht->common_mask) | ht->common_bits); } static inline uintptr_t make_hval(const struct htable *ht, const void *p, uintptr_t bits) { return ((uintptr_t)p & ~ht->common_mask) | bits; } static inline bool entry_is_valid(uintptr_t e) { return e > HTABLE_DELETED; } static inline uintptr_t get_hash_ptr_bits(const struct htable *ht, size_t hash) { /* Shuffling the extra bits (as specified in mask) down the * end is quite expensive. But the lower bits are redundant, so * we fold the value first. */ return (hash ^ (hash >> ht->bits)) & ht->common_mask & ~ht->perfect_bit; } void htable_init(struct htable *ht, size_t (*rehash)(const void *elem, void *priv), void *priv) { struct htable empty = HTABLE_INITIALIZER(empty, NULL, NULL); *ht = empty; ht->rehash = rehash; ht->priv = priv; ht->table = &ht->perfect_bit; } void htable_clear(struct htable *ht) { if (ht->table != &ht->perfect_bit) free((void *)ht->table); htable_init(ht, ht->rehash, ht->priv); } static size_t hash_bucket(const struct htable *ht, size_t h) { return h & ((1 << ht->bits)-1); } static void *htable_val(const struct htable *ht, struct htable_iter *i, size_t hash, uintptr_t perfect) { uintptr_t h2 = get_hash_ptr_bits(ht, hash) | perfect; while (ht->table[i->off]) { if (ht->table[i->off] != HTABLE_DELETED) { if (get_extra_ptr_bits(ht, ht->table[i->off]) == h2) return get_raw_ptr(ht, ht->table[i->off]); } i->off = (i->off + 1) & ((1 << ht->bits)-1); h2 &= ~perfect; } return NULL; } void *htable_firstval(const struct htable *ht, struct htable_iter *i, size_t hash) { i->off = hash_bucket(ht, hash); return htable_val(ht, i, hash, ht->perfect_bit); } void *htable_nextval(const struct htable *ht, struct htable_iter *i, size_t hash) { i->off = (i->off + 1) & ((1 << ht->bits)-1); return htable_val(ht, i, hash, 0); } void *htable_first(const struct htable *ht, struct htable_iter *i) { for (i->off = 0; i->off < (size_t)1 << ht->bits; i->off++) { if (entry_is_valid(ht->table[i->off])) return get_raw_ptr(ht, ht->table[i->off]); } return NULL; } void *htable_next(const struct htable *ht, struct htable_iter *i) { for (i->off++; i->off < (size_t)1 << ht->bits; i->off++) { if (entry_is_valid(ht->table[i->off])) return get_raw_ptr(ht, ht->table[i->off]); } return NULL; } /* This does not expand the hash table, that's up to caller. */ static void ht_add(struct htable *ht, const void *new, size_t h) { size_t i; uintptr_t perfect = ht->perfect_bit; i = hash_bucket(ht, h); while (entry_is_valid(ht->table[i])) { perfect = 0; i = (i + 1) & ((1 << ht->bits)-1); } ht->table[i] = make_hval(ht, new, get_hash_ptr_bits(ht, h)|perfect); } static COLD bool double_table(struct htable *ht) { unsigned int i; size_t oldnum = (size_t)1 << ht->bits; uintptr_t *oldtable, e; oldtable = ht->table; ht->table = calloc(1 << (ht->bits+1), sizeof(size_t)); if (!ht->table) { ht->table = oldtable; return false; } ht->bits++; ht->max = ((size_t)3 << ht->bits) / 4; ht->max_with_deleted = ((size_t)9 << ht->bits) / 10; /* If we lost our "perfect bit", get it back now. */ if (!ht->perfect_bit && ht->common_mask) { for (i = 0; i < sizeof(ht->common_mask) * CHAR_BIT; i++) { if (ht->common_mask & ((size_t)1 << i)) { ht->perfect_bit = (size_t)1 << i; break; } } } if (oldtable != &ht->perfect_bit) { for (i = 0; i < oldnum; i++) { if (entry_is_valid(e = oldtable[i])) { void *p = get_raw_ptr(ht, e); ht_add(ht, p, ht->rehash(p, ht->priv)); } } free(oldtable); } ht->deleted = 0; return true; } static COLD void rehash_table(struct htable *ht) { size_t start, i; uintptr_t e; /* Beware wrap cases: we need to start from first empty bucket. */ for (start = 0; ht->table[start]; start++); for (i = 0; i < (size_t)1 << ht->bits; i++) { size_t h = (i + start) & ((1 << ht->bits)-1); e = ht->table[h]; if (!e) continue; if (e == HTABLE_DELETED) ht->table[h] = 0; else if (!(e & ht->perfect_bit)) { void *p = get_raw_ptr(ht, e); ht->table[h] = 0; ht_add(ht, p, ht->rehash(p, ht->priv)); } } ht->deleted = 0; } /* We stole some bits, now we need to put them back... */ static COLD void update_common(struct htable *ht, const void *p) { unsigned int i; uintptr_t maskdiff, bitsdiff; if (ht->elems == 0) { /* Always reveal one bit of the pointer in the bucket, * so it's not zero or HTABLE_DELETED (1), even if * hash happens to be 0. Assumes (void *)1 is not a * valid pointer. */ for (i = sizeof(uintptr_t)*CHAR_BIT - 1; i > 0; i--) { if ((uintptr_t)p & ((uintptr_t)1 << i)) break; } ht->common_mask = ~((uintptr_t)1 << i); ht->common_bits = ((uintptr_t)p & ht->common_mask); ht->perfect_bit = 1; return; } /* Find bits which are unequal to old common set. */ maskdiff = ht->common_bits ^ ((uintptr_t)p & ht->common_mask); /* These are the bits which go there in existing entries. */ bitsdiff = ht->common_bits & maskdiff; for (i = 0; i < (size_t)1 << ht->bits; i++) { if (!entry_is_valid(ht->table[i])) continue; /* Clear the bits no longer in the mask, set them as * expected. */ ht->table[i] &= ~maskdiff; ht->table[i] |= bitsdiff; } /* Take away those bits from our mask, bits and perfect bit. */ ht->common_mask &= ~maskdiff; ht->common_bits &= ~maskdiff; ht->perfect_bit &= ~maskdiff; } bool htable_add(struct htable *ht, size_t hash, const void *p) { if (ht->elems+1 > ht->max && !double_table(ht)) return false; if (ht->elems+1 + ht->deleted > ht->max_with_deleted) rehash_table(ht); assert(p); if (((uintptr_t)p & ht->common_mask) != ht->common_bits) update_common(ht, p); ht_add(ht, p, hash); ht->elems++; return true; } bool htable_del(struct htable *ht, size_t h, const void *p) { struct htable_iter i; void *c; for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) { if (c == p) { htable_delval(ht, &i); return true; } } return false; } void htable_delval(struct htable *ht, struct htable_iter *i) { assert(i->off < (size_t)1 << ht->bits); assert(entry_is_valid(ht->table[i->off])); ht->elems--; ht->table[i->off] = HTABLE_DELETED; ht->deleted++; } sbsigntool-0.9.2/lib/ccan/ccan/htable/htable.h000066400000000000000000000112761342142174400211430ustar00rootroot00000000000000/* Licensed under LGPLv2+ - see LICENSE file for details */ #ifndef CCAN_HTABLE_H #define CCAN_HTABLE_H #include "config.h" #include #include #include /** * struct htable - private definition of a htable. * * It's exposed here so you can put it in your structures and so we can * supply inline functions. */ struct htable { size_t (*rehash)(const void *elem, void *priv); void *priv; unsigned int bits; size_t elems, deleted, max, max_with_deleted; /* These are the bits which are the same in all pointers. */ uintptr_t common_mask, common_bits; uintptr_t perfect_bit; uintptr_t *table; }; /** * HTABLE_INITIALIZER - static initialization for a hash table. * @name: name of this htable. * @rehash: hash function to use for rehashing. * @priv: private argument to @rehash function. * * This is useful for setting up static and global hash tables. * * Example: * // For simplicity's sake, say hash value is contents of elem. * static size_t rehash(const void *elem, void *unused) * { * return *(size_t *)elem; * } * static struct htable ht = HTABLE_INITIALIZER(ht, rehash, NULL); */ #define HTABLE_INITIALIZER(name, rehash, priv) \ { rehash, priv, 0, 0, 0, 0, 0, -1, 0, 0, &name.perfect_bit } /** * htable_init - initialize an empty hash table. * @ht: the hash table to initialize * @rehash: hash function to use for rehashing. * @priv: private argument to @rehash function. */ void htable_init(struct htable *ht, size_t (*rehash)(const void *elem, void *priv), void *priv); /** * htable_clear - empty a hash table. * @ht: the hash table to clear * * This doesn't do anything to any pointers left in it. */ void htable_clear(struct htable *ht); /** * htable_rehash - use a hashtree's rehash function * @elem: the argument to rehash() * */ size_t htable_rehash(const void *elem); /** * htable_add - add a pointer into a hash table. * @ht: the htable * @hash: the hash value of the object * @p: the non-NULL pointer * * Also note that this can only fail due to allocation failure. Otherwise, it * returns true. */ bool htable_add(struct htable *ht, size_t hash, const void *p); /** * htable_del - remove a pointer from a hash table * @ht: the htable * @hash: the hash value of the object * @p: the pointer * * Returns true if the pointer was found (and deleted). */ bool htable_del(struct htable *ht, size_t hash, const void *p); /** * struct htable_iter - iterator or htable_first or htable_firstval etc. * * This refers to a location inside the hashtable. */ struct htable_iter { size_t off; }; /** * htable_firstval - find a candidate for a given hash value * @htable: the hashtable * @i: the struct htable_iter to initialize * @hash: the hash value * * You'll need to check the value is what you want; returns NULL if none. * See Also: * htable_delval() */ void *htable_firstval(const struct htable *htable, struct htable_iter *i, size_t hash); /** * htable_nextval - find another candidate for a given hash value * @htable: the hashtable * @i: the struct htable_iter to initialize * @hash: the hash value * * You'll need to check the value is what you want; returns NULL if no more. */ void *htable_nextval(const struct htable *htable, struct htable_iter *i, size_t hash); /** * htable_get - find an entry in the hash table * @ht: the hashtable * @h: the hash value of the entry * @cmp: the comparison function * @ptr: the pointer to hand to the comparison function. * * Convenient inline wrapper for htable_firstval/htable_nextval loop. */ static inline void *htable_get(const struct htable *ht, size_t h, bool (*cmp)(const void *candidate, void *ptr), const void *ptr) { struct htable_iter i; void *c; for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) { if (cmp(c, (void *)ptr)) return c; } return NULL; } /** * htable_first - find an entry in the hash table * @ht: the hashtable * @i: the struct htable_iter to initialize * * Get an entry in the hashtable; NULL if empty. */ void *htable_first(const struct htable *htable, struct htable_iter *i); /** * htable_next - find another entry in the hash table * @ht: the hashtable * @i: the struct htable_iter to use * * Get another entry in the hashtable; NULL if all done. * This is usually used after htable_first or prior non-NULL htable_next. */ void *htable_next(const struct htable *htable, struct htable_iter *i); /** * htable_delval - remove an iterated pointer from a hash table * @ht: the htable * @i: the htable_iter * * Usually used to delete a hash entry after it has been found with * htable_firstval etc. */ void htable_delval(struct htable *ht, struct htable_iter *i); #endif /* CCAN_HTABLE_H */ sbsigntool-0.9.2/lib/ccan/ccan/htable/htable_type.h000066400000000000000000000071061342142174400222010ustar00rootroot00000000000000/* Licensed under LGPLv2+ - see LICENSE file for details */ #ifndef CCAN_HTABLE_TYPE_H #define CCAN_HTABLE_TYPE_H #include #include "config.h" /** * HTABLE_DEFINE_TYPE - create a set of htable ops for a type * @type: a type whose pointers will be values in the hash. * @keyof: a function/macro to extract a key: @keyof(const type *elem) * @hashfn: a hash function for a @key: size_t @hashfn(const *) * @eqfn: an equality function keys: bool @eqfn(const type *, const *) * @prefix: a prefix for all the functions to define (of form _*) * * NULL values may not be placed into the hash table. * * This defines the type hashtable type and an iterator type: * struct ; * struct _iter; * * It also defines initialization and freeing functions: * void _init(struct *); * void _clear(struct *); * * Add function only fails if we run out of memory: * bool _add(struct *ht, const *e); * * Delete and delete-by key return true if it was in the set: * bool _del(struct *ht, const *e); * bool _delkey(struct *ht, const *k); * * Find function return the matching element, or NULL: * type *_get(const struct @name *ht, const *k); * * Iteration over hashtable is also supported: * type *_first(const struct *ht, struct _iter *i); * type *_next(const struct *ht, struct _iter *i); * * It's currently safe to iterate over a changing hashtable, but you might * miss an element. Iteration isn't very efficient, either. * * You can use HTABLE_INITIALIZER like so: * struct ht = { HTABLE_INITIALIZER(ht.raw, _hash, NULL) }; */ #define HTABLE_DEFINE_TYPE(type, keyof, hashfn, eqfn, name) \ struct name { struct htable raw; }; \ struct name##_iter { struct htable_iter i; }; \ static inline size_t name##_hash(const void *elem, void *priv) \ { \ return hashfn(keyof((const type *)elem)); \ } \ static inline void name##_init(struct name *ht) \ { \ htable_init(&ht->raw, name##_hash, NULL); \ } \ static inline void name##_clear(struct name *ht) \ { \ htable_clear(&ht->raw); \ } \ static inline bool name##_add(struct name *ht, const type *elem) \ { \ return htable_add(&ht->raw, hashfn(keyof(elem)), elem); \ } \ static inline bool name##_del(struct name *ht, const type *elem) \ { \ return htable_del(&ht->raw, hashfn(keyof(elem)), elem); \ } \ static inline type *name##_get(const struct name *ht, \ const HTABLE_KTYPE(keyof) k) \ { \ /* Typecheck for eqfn */ \ (void)sizeof(eqfn((const type *)NULL, \ keyof((const type *)NULL))); \ return htable_get(&ht->raw, \ hashfn(k), \ (bool (*)(const void *, void *))(eqfn), \ k); \ } \ static inline bool name##_delkey(struct name *ht, \ const HTABLE_KTYPE(keyof) k) \ { \ type *elem = name##_get(ht, k); \ if (elem) \ return name##_del(ht, elem); \ return false; \ } \ static inline type *name##_first(const struct name *ht, \ struct name##_iter *iter) \ { \ return htable_first(&ht->raw, &iter->i); \ } \ static inline type *name##_next(const struct name *ht, \ struct name##_iter *iter) \ { \ return htable_next(&ht->raw, &iter->i); \ } #if HAVE_TYPEOF #define HTABLE_KTYPE(keyof) typeof(keyof(NULL)) #else #define HTABLE_KTYPE(keyof) void * #endif #endif /* CCAN_HTABLE_TYPE_H */ sbsigntool-0.9.2/lib/ccan/ccan/list/000077500000000000000000000000001342142174400172405ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/list/LICENSE000077700000000000000000000000001342142174400234522../../licenses/LGPL-2.1ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/list/list.c000066400000000000000000000017521342142174400203640ustar00rootroot00000000000000/* Licensed under LGPLv2.1+ - see LICENSE file for details */ #include #include #include "list.h" static void *corrupt(const char *abortstr, const struct list_node *head, const struct list_node *node, unsigned int count) { if (abortstr) { fprintf(stderr, "%s: prev corrupt in node %p (%u) of %p\n", abortstr, node, count, head); abort(); } return NULL; } struct list_node *list_check_node(const struct list_node *node, const char *abortstr) { const struct list_node *p, *n; int count = 0; for (p = node, n = node->next; n != node; p = n, n = n->next) { count++; if (n->prev != p) return corrupt(abortstr, node, n, count); } /* Check prev on head node. */ if (node->prev != p) return corrupt(abortstr, node, node, 0); return (struct list_node *)node; } struct list_head *list_check(const struct list_head *h, const char *abortstr) { if (!list_check_node(&h->n, abortstr)) return NULL; return (struct list_head *)h; } sbsigntool-0.9.2/lib/ccan/ccan/list/list.h000066400000000000000000000326151342142174400203730ustar00rootroot00000000000000/* Licensed under LGPLv2.1+ - see LICENSE file for details */ #ifndef CCAN_LIST_H #define CCAN_LIST_H #include #include #include #include /** * struct list_node - an entry in a doubly-linked list * @next: next entry (self if empty) * @prev: previous entry (self if empty) * * This is used as an entry in a linked list. * Example: * struct child { * const char *name; * // Linked list of all us children. * struct list_node list; * }; */ struct list_node { struct list_node *next, *prev; }; /** * struct list_head - the head of a doubly-linked list * @h: the list_head (containing next and prev pointers) * * This is used as the head of a linked list. * Example: * struct parent { * const char *name; * struct list_head children; * unsigned int num_children; * }; */ struct list_head { struct list_node n; }; /** * list_check - check head of a list for consistency * @h: the list_head * @abortstr: the location to print on aborting, or NULL. * * Because list_nodes have redundant information, consistency checking between * the back and forward links can be done. This is useful as a debugging check. * If @abortstr is non-NULL, that will be printed in a diagnostic if the list * is inconsistent, and the function will abort. * * Returns the list head if the list is consistent, NULL if not (it * can never return NULL if @abortstr is set). * * See also: list_check_node() * * Example: * static void dump_parent(struct parent *p) * { * struct child *c; * * printf("%s (%u children):\n", p->name, p->num_children); * list_check(&p->children, "bad child list"); * list_for_each(&p->children, c, list) * printf(" -> %s\n", c->name); * } */ struct list_head *list_check(const struct list_head *h, const char *abortstr); /** * list_check_node - check node of a list for consistency * @n: the list_node * @abortstr: the location to print on aborting, or NULL. * * Check consistency of the list node is in (it must be in one). * * See also: list_check() * * Example: * static void dump_child(const struct child *c) * { * list_check_node(&c->list, "bad child list"); * printf("%s\n", c->name); * } */ struct list_node *list_check_node(const struct list_node *n, const char *abortstr); #ifdef CCAN_LIST_DEBUG #define list_debug(h) list_check((h), __func__) #define list_debug_node(n) list_check_node((n), __func__) #else #define list_debug(h) (h) #define list_debug_node(n) (n) #endif /** * LIST_HEAD_INIT - initializer for an empty list_head * @name: the name of the list. * * Explicit initializer for an empty list. * * See also: * LIST_HEAD, list_head_init() * * Example: * static struct list_head my_list = LIST_HEAD_INIT(my_list); */ #define LIST_HEAD_INIT(name) { { &name.n, &name.n } } /** * LIST_HEAD - define and initialize an empty list_head * @name: the name of the list. * * The LIST_HEAD macro defines a list_head and initializes it to an empty * list. It can be prepended by "static" to define a static list_head. * * See also: * LIST_HEAD_INIT, list_head_init() * * Example: * static LIST_HEAD(my_global_list); */ #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) /** * list_head_init - initialize a list_head * @h: the list_head to set to the empty list * * Example: * ... * struct parent *parent = malloc(sizeof(*parent)); * * list_head_init(&parent->children); * parent->num_children = 0; */ static inline void list_head_init(struct list_head *h) { h->n.next = h->n.prev = &h->n; } /** * list_add - add an entry at the start of a linked list. * @h: the list_head to add the node to * @n: the list_node to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * struct child *child = malloc(sizeof(*child)); * * child->name = "marvin"; * list_add(&parent->children, &child->list); * parent->num_children++; */ static inline void list_add(struct list_head *h, struct list_node *n) { n->next = h->n.next; n->prev = &h->n; h->n.next->prev = n; h->n.next = n; (void)list_debug(h); } /** * list_add_tail - add an entry at the end of a linked list. * @h: the list_head to add the node to * @n: the list_node to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * list_add_tail(&parent->children, &child->list); * parent->num_children++; */ static inline void list_add_tail(struct list_head *h, struct list_node *n) { n->next = &h->n; n->prev = h->n.prev; h->n.prev->next = n; h->n.prev = n; (void)list_debug(h); } /** * list_empty - is a list empty? * @h: the list_head * * If the list is empty, returns true. * * Example: * assert(list_empty(&parent->children) == (parent->num_children == 0)); */ static inline bool list_empty(const struct list_head *h) { (void)list_debug(h); return h->n.next == &h->n; } /** * list_del - delete an entry from an (unknown) linked list. * @n: the list_node to delete from the list. * * Note that this leaves @n in an undefined state; it can be added to * another list, but not deleted again. * * See also: * list_del_from() * * Example: * list_del(&child->list); * parent->num_children--; */ static inline void list_del(struct list_node *n) { (void)list_debug_node(n); n->next->prev = n->prev; n->prev->next = n->next; #ifdef CCAN_LIST_DEBUG /* Catch use-after-del. */ n->next = n->prev = NULL; #endif } /** * list_del_from - delete an entry from a known linked list. * @h: the list_head the node is in. * @n: the list_node to delete from the list. * * This explicitly indicates which list a node is expected to be in, * which is better documentation and can catch more bugs. * * See also: list_del() * * Example: * list_del_from(&parent->children, &child->list); * parent->num_children--; */ static inline void list_del_from(struct list_head *h, struct list_node *n) { #ifdef CCAN_LIST_DEBUG { /* Thorough check: make sure it was in list! */ struct list_node *i; for (i = h->n.next; i != n; i = i->next) assert(i != &h->n); } #endif /* CCAN_LIST_DEBUG */ /* Quick test that catches a surprising number of bugs. */ assert(!list_empty(h)); list_del(n); } /** * list_entry - convert a list_node back into the structure containing it. * @n: the list_node * @type: the type of the entry * @member: the list_node member of the type * * Example: * // First list entry is children.next; convert back to child. * child = list_entry(parent->children.n.next, struct child, list); * * See Also: * list_top(), list_for_each() */ #define list_entry(n, type, member) container_of(n, type, member) /** * list_top - get the first entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *first; * first = list_top(&parent->children, struct child, list); */ #define list_top(h, type, member) \ ((type *)list_top_((h), list_off_(type, member))) static inline const void *list_top_(const struct list_head *h, size_t off) { if (list_empty(h)) return NULL; return (const char *)h->n.next - off; } /** * list_tail - get the last entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *last; * last = list_tail(&parent->children, struct child, list); */ #define list_tail(h, type, member) \ ((type *)list_tail_((h), list_off_(type, member))) static inline const void *list_tail_(const struct list_head *h, size_t off) { if (list_empty(h)) return NULL; return (const char *)h->n.prev - off; } /** * list_for_each - iterate through a list. * @h: the list_head (warning: evaluated multiple times!) * @i: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * list_for_each(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define list_for_each(h, i, member) \ list_for_each_off(h, i, list_off_var_(i, member)) /** * list_for_each_rev - iterate through a list backwards. * @h: the list_head * @i: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * list_for_each_rev(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define list_for_each_rev(h, i, member) \ for (i = container_of_var(list_debug(h)->n.prev, i, member); \ &i->member != &(h)->n; \ i = container_of_var(i->member.prev, i, member)) /** * list_for_each_safe - iterate through a list, maybe during deletion * @h: the list_head * @i: the structure containing the list_node * @nxt: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. The extra variable * @nxt is used to hold the next element, so you can delete @i from the list. * * Example: * struct child *next; * list_for_each_safe(&parent->children, child, next, list) { * list_del(&child->list); * parent->num_children--; * } */ #define list_for_each_safe(h, i, nxt, member) \ list_for_each_safe_off(h, i, nxt, list_off_var_(i, member)) /** * list_for_each_off - iterate through a list of memory regions. * @h: the list_head * @i: the pointer to a memory region wich contains list node data. * @off: offset(relative to @i) at which list node data resides. * * This is a low-level wrapper to iterate @i over the entire list, used to * implement all oher, more high-level, for-each constructs. It's a for loop, * so you can break and continue as normal. * * WARNING! Being the low-level macro that it is, this wrapper doesn't know * nor care about the type of @i. The only assumtion made is that @i points * to a chunk of memory that at some @offset, relative to @i, contains a * properly filled `struct node_list' which in turn contains pointers to * memory chunks and it's turtles all the way down. Whith all that in mind * remember that given the wrong pointer/offset couple this macro will * happilly churn all you memory untill SEGFAULT stops it, in other words * caveat emptor. * * It is worth mentioning that one of legitimate use-cases for that wrapper * is operation on opaque types with known offset for `struct list_node' * member(preferably 0), because it allows you not to disclose the type of * @i. * * Example: * list_for_each_off(&parent->children, child, * offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_off(h, i, off) \ for (i = list_node_to_off_(list_debug(h)->n.next, (off)); \ list_node_from_off_((void *)i, (off)) != &(h)->n; \ i = list_node_to_off_(list_node_from_off_((void *)i, (off))->next, \ (off))) /** * list_for_each_safe_off - iterate through a list of memory regions, maybe * during deletion * @h: the list_head * @i: the pointer to a memory region wich contains list node data. * @nxt: the structure containing the list_node * @off: offset(relative to @i) at which list node data resides. * * For details see `list_for_each_off' and `list_for_each_safe' * descriptions. * * Example: * list_for_each_safe_off(&parent->children, child, * next, offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_safe_off(h, i, nxt, off) \ for (i = list_node_to_off_(list_debug(h)->n.next, (off)), \ nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \ (off)); \ list_node_from_off_(i, (off)) != &(h)->n; \ i = nxt, \ nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \ (off))) /* Other -off variants. */ #define list_entry_off(n, type, off) \ ((type *)list_node_from_off_((n), (off))) #define list_head_off(h, type, off) \ ((type *)list_head_off((h), (off))) #define list_tail_off(h, type, off) \ ((type *)list_tail_((h), (off))) #define list_add_off(h, n, off) \ list_add((h), list_node_from_off_((n), (off))) #define list_del_off(n, off) \ list_del(list_node_from_off_((n), (off))) #define list_del_from_off(h, n, off) \ list_del_from(h, list_node_from_off_((n), (off))) /* Offset helper functions so we only single-evaluate. */ static inline void *list_node_to_off_(struct list_node *node, size_t off) { return (void *)((char *)node - off); } static inline struct list_node *list_node_from_off_(void *ptr, size_t off) { return (struct list_node *)((char *)ptr + off); } /* Get the offset of the member, but make sure it's a list_node. */ #define list_off_(type, member) \ (container_off(type, member) + \ check_type(((type *)0)->member, struct list_node)) #define list_off_var_(var, member) \ (container_off_var(var, member) + \ check_type(var->member, struct list_node)) #endif /* CCAN_LIST_H */ sbsigntool-0.9.2/lib/ccan/ccan/read_write_all/000077500000000000000000000000001342142174400212425ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/read_write_all/LICENSE000077700000000000000000000000001342142174400254542../../licenses/LGPL-2.1ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/read_write_all/read_write_all.c000066400000000000000000000012301342142174400243570ustar00rootroot00000000000000/* Licensed under LGPLv2+ - see LICENSE file for details */ #include "read_write_all.h" #include #include bool write_all(int fd, const void *data, size_t size) { while (size) { ssize_t done; done = write(fd, data, size); if (done < 0 && errno == EINTR) continue; if (done <= 0) return false; data = (const char *)data + done; size -= done; } return true; } bool read_all(int fd, void *data, size_t size) { while (size) { ssize_t done; done = read(fd, data, size); if (done < 0 && errno == EINTR) continue; if (done <= 0) return false; data = (char *)data + done; size -= done; } return true; } sbsigntool-0.9.2/lib/ccan/ccan/read_write_all/read_write_all.h000066400000000000000000000004441342142174400243720ustar00rootroot00000000000000/* Licensed under LGPLv2+ - see LICENSE file for details */ #ifndef _CCAN_READ_WRITE_H #define _CCAN_READ_WRITE_H #include #include bool write_all(int fd, const void *data, size_t size); bool read_all(int fd, void *data, size_t size); #endif /* _CCAN_READ_WRITE_H */ sbsigntool-0.9.2/lib/ccan/ccan/str/000077500000000000000000000000001342142174400170755ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/str/debug.c000066400000000000000000000030111342142174400203220ustar00rootroot00000000000000#include "config.h" #include #include #include #include #ifdef CCAN_STR_DEBUG /* Because we mug the real ones with macros, we need our own wrappers. */ int str_isalnum(int i) { assert(i >= -1 && i < 256); return isalnum(i); } int str_isalpha(int i) { assert(i >= -1 && i < 256); return isalpha(i); } int str_isascii(int i) { assert(i >= -1 && i < 256); return isascii(i); } #if HAVE_ISBLANK int str_isblank(int i) { assert(i >= -1 && i < 256); return isblank(i); } #endif int str_iscntrl(int i) { assert(i >= -1 && i < 256); return iscntrl(i); } int str_isdigit(int i) { assert(i >= -1 && i < 256); return isdigit(i); } int str_isgraph(int i) { assert(i >= -1 && i < 256); return isgraph(i); } int str_islower(int i) { assert(i >= -1 && i < 256); return islower(i); } int str_isprint(int i) { assert(i >= -1 && i < 256); return isprint(i); } int str_ispunct(int i) { assert(i >= -1 && i < 256); return ispunct(i); } int str_isspace(int i) { assert(i >= -1 && i < 256); return isspace(i); } int str_isupper(int i) { assert(i >= -1 && i < 256); return isupper(i); } int str_isxdigit(int i) { assert(i >= -1 && i < 256); return isxdigit(i); } #undef strstr #undef strchr #undef strrchr char *str_strstr(const char *haystack, const char *needle) { return strstr(haystack, needle); } char *str_strchr(const char *haystack, int c) { return strchr(haystack, c); } char *str_strrchr(const char *haystack, int c) { return strrchr(haystack, c); } #endif sbsigntool-0.9.2/lib/ccan/ccan/str/str.c000066400000000000000000000003421342142174400200500ustar00rootroot00000000000000#include size_t strcount(const char *haystack, const char *needle) { size_t i = 0, nlen = strlen(needle); while ((haystack = strstr(haystack, needle)) != NULL) { i++; haystack += nlen; } return i; } sbsigntool-0.9.2/lib/ccan/ccan/str/str.h000066400000000000000000000117411342142174400200620ustar00rootroot00000000000000/* Placed into the public domain. */ #ifndef CCAN_STR_H #define CCAN_STR_H #include "config.h" #include #include #include /** * streq - Are two strings equal? * @a: first string * @b: first string * * This macro is arguably more readable than "!strcmp(a, b)". * * Example: * if (streq(somestring, "")) * printf("String is empty!\n"); */ #define streq(a,b) (strcmp((a),(b)) == 0) /** * strstarts - Does this string start with this prefix? * @str: string to test * @prefix: prefix to look for at start of str * * Example: * if (strstarts(somestring, "foo")) * printf("String %s begins with 'foo'!\n", somestring); */ #define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0) /** * strends - Does this string end with this postfix? * @str: string to test * @postfix: postfix to look for at end of str * * Example: * if (strends(somestring, "foo")) * printf("String %s end with 'foo'!\n", somestring); */ static inline bool strends(const char *str, const char *postfix) { if (strlen(str) < strlen(postfix)) return false; return streq(str + strlen(str) - strlen(postfix), postfix); } /** * stringify - Turn expression into a string literal * @expr: any C expression * * Example: * #define PRINT_COND_IF_FALSE(cond) \ * ((cond) || printf("%s is false!", stringify(cond))) */ #define stringify(expr) stringify_1(expr) /* Double-indirection required to stringify expansions */ #define stringify_1(expr) #expr /** * strcount - Count number of (non-overlapping) occurrences of a substring. * @haystack: a C string * @needle: a substring * * Example: * int i; * i = strcount("aaa aaa", "a"); // i = 6; * i = strcount("aaa aaa", "ab"); // i = 0; * i = strcount("aaa aaa", "aa"); // i = 2; */ size_t strcount(const char *haystack, const char *needle); /** * cisalnum - isalnum() which takes a char (and doesn't accept EOF) * @c: a character * * Surprisingly, the standard ctype.h isalnum() takes an int, which * must have the value of EOF (-1) or an unsigned char. This variant * takes a real char, and doesn't accept EOF. */ static inline bool cisalnum(char c) { return isalnum((unsigned char)c); } static inline bool cisalpha(char c) { return isalpha((unsigned char)c); } static inline bool cisascii(char c) { return isascii((unsigned char)c); } #if HAVE_ISBLANK static inline bool cisblank(char c) { return isblank((unsigned char)c); } #endif static inline bool ciscntrl(char c) { return iscntrl((unsigned char)c); } static inline bool cisdigit(char c) { return isdigit((unsigned char)c); } static inline bool cisgraph(char c) { return isgraph((unsigned char)c); } static inline bool cislower(char c) { return islower((unsigned char)c); } static inline bool cisprint(char c) { return isprint((unsigned char)c); } static inline bool cispunct(char c) { return ispunct((unsigned char)c); } static inline bool cisspace(char c) { return isspace((unsigned char)c); } static inline bool cisupper(char c) { return isupper((unsigned char)c); } static inline bool cisxdigit(char c) { return isxdigit((unsigned char)c); } #include /* These checks force things out of line, hence they are under DEBUG. */ #ifdef CCAN_STR_DEBUG #include /* These are commonly misused: they take -1 or an *unsigned* char value. */ #undef isalnum #undef isalpha #undef isascii #undef isblank #undef iscntrl #undef isdigit #undef isgraph #undef islower #undef isprint #undef ispunct #undef isspace #undef isupper #undef isxdigit /* You can use a char if char is unsigned. */ #if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF #define str_check_arg_(i) \ ((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \ char) \ || (char)255 > 0)) #else #define str_check_arg_(i) (i) #endif #define isalnum(i) str_isalnum(str_check_arg_(i)) #define isalpha(i) str_isalpha(str_check_arg_(i)) #define isascii(i) str_isascii(str_check_arg_(i)) #if HAVE_ISBLANK #define isblank(i) str_isblank(str_check_arg_(i)) #endif #define iscntrl(i) str_iscntrl(str_check_arg_(i)) #define isdigit(i) str_isdigit(str_check_arg_(i)) #define isgraph(i) str_isgraph(str_check_arg_(i)) #define islower(i) str_islower(str_check_arg_(i)) #define isprint(i) str_isprint(str_check_arg_(i)) #define ispunct(i) str_ispunct(str_check_arg_(i)) #define isspace(i) str_isspace(str_check_arg_(i)) #define isupper(i) str_isupper(str_check_arg_(i)) #define isxdigit(i) str_isxdigit(str_check_arg_(i)) #if HAVE_TYPEOF /* With GNU magic, we can make const-respecting standard string functions. */ #undef strstr #undef strchr #undef strrchr /* + 0 is needed to decay array into pointer. */ #define strstr(haystack, needle) \ ((typeof((haystack) + 0))str_strstr((haystack), (needle))) #define strchr(haystack, c) \ ((typeof((haystack) + 0))str_strchr((haystack), (c))) #define strrchr(haystack, c) \ ((typeof((haystack) + 0))str_strrchr((haystack), (c))) #endif #endif /* CCAN_STR_DEBUG */ #endif /* CCAN_STR_H */ sbsigntool-0.9.2/lib/ccan/ccan/str/str_debug.h000066400000000000000000000013151342142174400212240ustar00rootroot00000000000000#ifndef CCAN_STR_DEBUG_H #define CCAN_STR_DEBUG_H /* #define CCAN_STR_DEBUG 1 */ #ifdef CCAN_STR_DEBUG /* Because we mug the real ones with macros, we need our own wrappers. */ int str_isalnum(int i); int str_isalpha(int i); int str_isascii(int i); #if HAVE_ISBLANK int str_isblank(int i); #endif int str_iscntrl(int i); int str_isdigit(int i); int str_isgraph(int i); int str_islower(int i); int str_isprint(int i); int str_ispunct(int i); int str_isspace(int i); int str_isupper(int i); int str_isxdigit(int i); char *str_strstr(const char *haystack, const char *needle); char *str_strchr(const char *s, int c); char *str_strrchr(const char *s, int c); #endif /* CCAN_STR_DEBUG */ #endif /* CCAN_STR_DEBUG_H */ sbsigntool-0.9.2/lib/ccan/ccan/talloc/000077500000000000000000000000001342142174400175435ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/talloc/LICENSE000077700000000000000000000000001342142174400237552../../licenses/LGPL-2.1ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/talloc/talloc.c000066400000000000000000001063651342142174400212000ustar00rootroot00000000000000/* Samba Unix SMB/CIFS implementation. Samba trivial allocation library - new interface NOTE: Please read talloc_guide.txt for full documentation Copyright (C) Andrew Tridgell 2004 Copyright (C) Stefan Metzmacher 2006 ** NOTE! The following LGPL license applies to the talloc ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* inspired by http://swapped.cc/halloc/ */ #include "talloc.h" #include #include #include #include #include /* use this to force every realloc to change the pointer, to stress test code that might not cope */ #define ALWAYS_REALLOC 0 #define MAX_TALLOC_SIZE 0x7FFFFFFF #define TALLOC_MAGIC 0xe814ec70 #define TALLOC_FLAG_FREE 0x01 #define TALLOC_FLAG_LOOP 0x02 #define TALLOC_FLAG_EXT_ALLOC 0x04 #define TALLOC_MAGIC_REFERENCE ((const char *)1) /* by default we abort when given a bad pointer (such as when talloc_free() is called on a pointer that came from malloc() */ #ifndef TALLOC_ABORT #define TALLOC_ABORT(reason) abort() #endif #ifndef discard_const_p #if defined(INTPTR_MIN) # define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) #else # define discard_const_p(type, ptr) ((type *)(ptr)) #endif #endif /* these macros gain us a few percent of speed on gcc */ #if HAVE_BUILTIN_EXPECT /* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 as its first argument */ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #else #define likely(x) x #define unlikely(x) x #endif /* this null_context is only used if talloc_enable_leak_report() or talloc_enable_leak_report_full() is called, otherwise it remains NULL */ static void *null_context; static pid_t *autofree_context; static void *(*tc_malloc)(size_t size) = malloc; static void (*tc_free)(void *ptr) = free; static void *(*tc_realloc)(void *ptr, size_t size) = realloc; static void *(*tc_external_realloc)(const void *parent, void *ptr, size_t size); static void (*tc_lock)(const void *ctx); static void (*tc_unlock)(void); struct talloc_reference_handle { struct talloc_reference_handle *next, *prev; void *ptr; }; typedef int (*talloc_destructor_t)(void *); struct talloc_chunk { struct talloc_chunk *next, *prev; struct talloc_chunk *parent, *child; struct talloc_reference_handle *refs; talloc_destructor_t destructor; const char *name; size_t size; unsigned flags; }; /* 16 byte alignment seems to keep everyone happy */ #define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15) #define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc)) /* panic if we get a bad magic value */ static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) { const char *pp = (const char *)ptr; struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { if (tc->flags & TALLOC_FLAG_FREE) { TALLOC_ABORT("Bad talloc magic value - double free"); } else { TALLOC_ABORT("Bad talloc magic value - unknown value"); } } return tc; } /* hook into the front of the list */ #define _TLIST_ADD(list, p) \ do { \ if (!(list)) { \ (list) = (p); \ (p)->next = (p)->prev = NULL; \ } else { \ (list)->prev = (p); \ (p)->next = (list); \ (p)->prev = NULL; \ (list) = (p); \ }\ } while (0) /* remove an element from a list - element doesn't have to be in list. */ #define _TLIST_REMOVE(list, p) \ do { \ if ((p) == (list)) { \ (list) = (p)->next; \ if (list) (list)->prev = NULL; \ } else { \ if ((p)->prev) (p)->prev->next = (p)->next; \ if ((p)->next) (p)->next->prev = (p)->prev; \ } \ if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \ } while (0) static int locked; static inline void lock(const void *p) { if (tc_lock && p) { struct talloc_chunk *tc = talloc_chunk_from_ptr(p); if (tc->flags & TALLOC_FLAG_EXT_ALLOC) { if (locked) TALLOC_ABORT("nested locking"); tc_lock(tc); locked = 1; } } } static inline void unlock(void) { if (locked) { tc_unlock(); locked = 0; } } /* return the parent chunk of a pointer */ static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr) { struct talloc_chunk *tc; if (unlikely(ptr == NULL)) { return NULL; } tc = talloc_chunk_from_ptr(ptr); while (tc->prev) tc=tc->prev; return tc->parent; } /* This version doesn't do locking, so you must already have it. */ static void *talloc_parent_nolock(const void *ptr) { struct talloc_chunk *tc; tc = talloc_parent_chunk(ptr); return tc ? TC_PTR_FROM_CHUNK(tc) : NULL; } void *talloc_parent(const void *ptr) { void *parent; lock(ptr); parent = talloc_parent_nolock(ptr); unlock(); return parent; } /* find parents name */ const char *talloc_parent_name(const void *ptr) { struct talloc_chunk *tc; lock(ptr); tc = talloc_parent_chunk(ptr); unlock(); return tc? tc->name : NULL; } static void *init_talloc(struct talloc_chunk *parent, struct talloc_chunk *tc, size_t size, int external) { if (unlikely(tc == NULL)) return NULL; tc->size = size; tc->flags = TALLOC_MAGIC; if (external) tc->flags |= TALLOC_FLAG_EXT_ALLOC; tc->destructor = NULL; tc->child = NULL; tc->name = NULL; tc->refs = NULL; if (likely(parent)) { if (parent->child) { parent->child->parent = NULL; tc->next = parent->child; tc->next->prev = tc; } else { tc->next = NULL; } tc->parent = parent; tc->prev = NULL; parent->child = tc; } else { tc->next = tc->prev = tc->parent = NULL; } return TC_PTR_FROM_CHUNK(tc); } /* Allocate a bit of memory as a child of an existing pointer */ static inline void *__talloc(const void *context, size_t size) { struct talloc_chunk *tc; struct talloc_chunk *parent = NULL; int external = 0; if (unlikely(context == NULL)) { context = null_context; } if (unlikely(size >= MAX_TALLOC_SIZE)) { return NULL; } if (likely(context)) { parent = talloc_chunk_from_ptr(context); if (unlikely(parent->flags & TALLOC_FLAG_EXT_ALLOC)) { tc = tc_external_realloc(context, NULL, TC_HDR_SIZE+size); external = 1; goto alloc_done; } } tc = (struct talloc_chunk *)tc_malloc(TC_HDR_SIZE+size); alloc_done: return init_talloc(parent, tc, size, external); } /* setup a destructor to be called on free of a pointer the destructor should return 0 on success, or -1 on failure. if the destructor fails then the free is failed, and the memory can be continued to be used */ void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->destructor = destructor; } /* increase the reference count on a piece of memory. */ int talloc_increase_ref_count(const void *ptr) { if (unlikely(!talloc_reference(null_context, ptr))) { return -1; } return 0; } /* helper for talloc_reference() this is referenced by a function pointer and should not be inline */ static int talloc_reference_destructor(struct talloc_reference_handle *handle) { struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr); _TLIST_REMOVE(ptr_tc->refs, handle); return 0; } /* more efficient way to add a name to a pointer - the name must point to a true string constant */ static inline void _talloc_set_name_const(const void *ptr, const char *name) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->name = name; } /* internal talloc_named_const() */ static inline void *_talloc_named_const(const void *context, size_t size, const char *name) { void *ptr; ptr = __talloc(context, size); if (unlikely(ptr == NULL)) { return NULL; } _talloc_set_name_const(ptr, name); return ptr; } /* make a secondary reference to a pointer, hanging off the given context. the pointer remains valid until both the original caller and this given context are freed. the major use for this is when two different structures need to reference the same underlying data, and you want to be able to free the two instances separately, and in either order */ void *_talloc_reference(const void *context, const void *ptr) { struct talloc_chunk *tc; struct talloc_reference_handle *handle; if (unlikely(ptr == NULL)) return NULL; lock(context); tc = talloc_chunk_from_ptr(ptr); handle = (struct talloc_reference_handle *)_talloc_named_const(context, sizeof(struct talloc_reference_handle), TALLOC_MAGIC_REFERENCE); if (unlikely(handle == NULL)) { unlock(); return NULL; } /* note that we hang the destructor off the handle, not the main context as that allows the caller to still setup their own destructor on the context if they want to */ talloc_set_destructor(handle, talloc_reference_destructor); handle->ptr = discard_const_p(void, ptr); _TLIST_ADD(tc->refs, handle); unlock(); return handle->ptr; } /* return 1 if ptr is a parent of context */ static int _talloc_is_parent(const void *context, const void *ptr) { struct talloc_chunk *tc; if (context == NULL) { return 0; } tc = talloc_chunk_from_ptr(context); while (tc) { if (TC_PTR_FROM_CHUNK(tc) == ptr) { return 1; } while (tc && tc->prev) tc = tc->prev; if (tc) { tc = tc->parent; } } return 0; } /* move a lump of memory from one talloc context to another return the ptr on success, or NULL if it could not be transferred. passing NULL as ptr will always return NULL with no side effects. */ static void *__talloc_steal(const void *new_ctx, const void *ptr) { struct talloc_chunk *tc, *new_tc; if (unlikely(!ptr)) { return NULL; } if (unlikely(new_ctx == NULL)) { new_ctx = null_context; } tc = talloc_chunk_from_ptr(ptr); if (unlikely(new_ctx == NULL)) { if (tc->parent) { _TLIST_REMOVE(tc->parent->child, tc); if (tc->parent->child) { tc->parent->child->parent = tc->parent; } } else { if (tc->prev) tc->prev->next = tc->next; if (tc->next) tc->next->prev = tc->prev; } tc->parent = tc->next = tc->prev = NULL; return discard_const_p(void, ptr); } new_tc = talloc_chunk_from_ptr(new_ctx); if (unlikely(tc == new_tc || tc->parent == new_tc)) { return discard_const_p(void, ptr); } if (tc->parent) { _TLIST_REMOVE(tc->parent->child, tc); if (tc->parent->child) { tc->parent->child->parent = tc->parent; } } else { if (tc->prev) tc->prev->next = tc->next; if (tc->next) tc->next->prev = tc->prev; } tc->parent = new_tc; if (new_tc->child) new_tc->child->parent = NULL; _TLIST_ADD(new_tc->child, tc); return discard_const_p(void, ptr); } /* internal talloc_free call */ static inline int _talloc_free(const void *ptr) { struct talloc_chunk *tc; void *oldparent = NULL; if (unlikely(ptr == NULL)) { return -1; } tc = talloc_chunk_from_ptr(ptr); if (unlikely(tc->refs)) { int is_child; /* check this is a reference from a child or grantchild * back to it's parent or grantparent * * in that case we need to remove the reference and * call another instance of talloc_free() on the current * pointer. */ is_child = _talloc_is_parent(tc->refs, ptr); _talloc_free(tc->refs); if (is_child) { return _talloc_free(ptr); } return -1; } if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) { /* we have a free loop - stop looping */ return 0; } if (unlikely(tc->destructor)) { talloc_destructor_t d = tc->destructor; if (d == (talloc_destructor_t)-1) { return -1; } tc->destructor = (talloc_destructor_t)-1; if (d(discard_const_p(void, ptr)) == -1) { tc->destructor = d; return -1; } tc->destructor = NULL; } if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) oldparent = talloc_parent_nolock(ptr); if (tc->parent) { _TLIST_REMOVE(tc->parent->child, tc); if (tc->parent->child) { tc->parent->child->parent = tc->parent; } } else { if (tc->prev) tc->prev->next = tc->next; if (tc->next) tc->next->prev = tc->prev; } tc->flags |= TALLOC_FLAG_LOOP; while (tc->child) { /* we need to work out who will own an abandoned child if it cannot be freed. In priority order, the first choice is owner of any remaining reference to this pointer, the second choice is our parent, and the final choice is the null context. */ void *child = TC_PTR_FROM_CHUNK(tc->child); const void *new_parent = null_context; struct talloc_chunk *old_parent = NULL; if (unlikely(tc->child->refs)) { struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); if (p) new_parent = TC_PTR_FROM_CHUNK(p); } /* finding the parent here is potentially quite expensive, but the alternative, which is to change talloc to always have a valid tc->parent pointer, makes realloc more expensive where there are a large number of children. The reason we need the parent pointer here is that if _talloc_free_internal() fails due to references or a failing destructor we need to re-parent, but the free call can invalidate the prev pointer. */ if (new_parent == null_context && (tc->child->refs || tc->child->destructor)) { old_parent = talloc_parent_chunk(ptr); } if (unlikely(_talloc_free(child) == -1)) { if (new_parent == null_context) { struct talloc_chunk *p = old_parent; if (p) new_parent = TC_PTR_FROM_CHUNK(p); } __talloc_steal(new_parent, child); } } tc->flags |= TALLOC_FLAG_FREE; if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) tc_external_realloc(oldparent, tc, 0); else tc_free(tc); return 0; } void *_talloc_steal(const void *new_ctx, const void *ptr) { void *p; lock(new_ctx); p = __talloc_steal(new_ctx, ptr); unlock(); return p; } /* remove a secondary reference to a pointer. This undo's what talloc_reference() has done. The context and pointer arguments must match those given to a talloc_reference() */ static inline int talloc_unreference(const void *context, const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); struct talloc_reference_handle *h; if (unlikely(context == NULL)) { context = null_context; } for (h=tc->refs;h;h=h->next) { struct talloc_chunk *p = talloc_parent_chunk(h); if (p == NULL) { if (context == NULL) break; } else if (TC_PTR_FROM_CHUNK(p) == context) { break; } } if (h == NULL) { return -1; } return _talloc_free(h); } /* remove a specific parent context from a pointer. This is a more controlled varient of talloc_free() */ int talloc_unlink(const void *context, void *ptr) { struct talloc_chunk *tc_p, *new_p; void *new_parent; if (ptr == NULL) { return -1; } if (context == NULL) { context = null_context; } lock(context); if (talloc_unreference(context, ptr) == 0) { unlock(); return 0; } if (context == NULL) { if (talloc_parent_chunk(ptr) != NULL) { unlock(); return -1; } } else { if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) { unlock(); return -1; } } tc_p = talloc_chunk_from_ptr(ptr); if (tc_p->refs == NULL) { int ret = _talloc_free(ptr); unlock(); return ret; } new_p = talloc_parent_chunk(tc_p->refs); if (new_p) { new_parent = TC_PTR_FROM_CHUNK(new_p); } else { new_parent = NULL; } if (talloc_unreference(new_parent, ptr) != 0) { unlock(); return -1; } __talloc_steal(new_parent, ptr); unlock(); return 0; } /* add a name to an existing pointer - va_list version */ static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_FMT(2,0); static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->name = talloc_vasprintf(ptr, fmt, ap); if (likely(tc->name)) { _talloc_set_name_const(tc->name, ".name"); } return tc->name; } /* add a name to an existing pointer */ const char *talloc_set_name(const void *ptr, const char *fmt, ...) { const char *name; va_list ap; va_start(ap, fmt); name = talloc_set_name_v(ptr, fmt, ap); va_end(ap); return name; } /* create a named talloc pointer. Any talloc pointer can be named, and talloc_named() operates just like talloc() except that it allows you to name the pointer. */ void *talloc_named(const void *context, size_t size, const char *fmt, ...) { va_list ap; void *ptr; const char *name; lock(context); ptr = __talloc(context, size); unlock(); if (unlikely(ptr == NULL)) return NULL; va_start(ap, fmt); name = talloc_set_name_v(ptr, fmt, ap); va_end(ap); if (unlikely(name == NULL)) { talloc_free(ptr); return NULL; } return ptr; } /* return the name of a talloc ptr, or "UNNAMED" */ const char *talloc_get_name(const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) { return ".reference"; } if (likely(tc->name)) { return tc->name; } return "UNNAMED"; } /* check if a pointer has the given name. If it does, return the pointer, otherwise return NULL */ void *talloc_check_name(const void *ptr, const char *name) { const char *pname; if (unlikely(ptr == NULL)) return NULL; pname = talloc_get_name(ptr); if (likely(pname == name || strcmp(pname, name) == 0)) { return discard_const_p(void, ptr); } return NULL; } /* this is for compatibility with older versions of talloc */ void *talloc_init(const char *fmt, ...) { va_list ap; void *ptr; const char *name; /* * samba3 expects talloc_report_depth_cb(NULL, ...) * reports all talloc'ed memory, so we need to enable * null_tracking */ talloc_enable_null_tracking(); ptr = __talloc(NULL, 0); if (unlikely(ptr == NULL)) return NULL; va_start(ap, fmt); name = talloc_set_name_v(ptr, fmt, ap); va_end(ap); if (unlikely(name == NULL)) { talloc_free(ptr); return NULL; } return ptr; } /* Allocate a bit of memory as a child of an existing pointer */ void *_talloc(const void *context, size_t size) { return __talloc(context, size); } static int talloc_destroy_pointer(void ***pptr) { if ((uintptr_t)**pptr < getpagesize()) TALLOC_ABORT("Double free or invalid talloc_set?"); /* Invalidate pointer so it can't be used again. */ **pptr = (void *)1; return 0; } void _talloc_set(void *ptr, const void *ctx, size_t size, const char *name) { void ***child; void *p; p = talloc_named_const(ctx, size, name); if (unlikely(!p)) goto set_ptr; child = talloc(p, void **); if (unlikely(!child)) { talloc_free(p); p = NULL; goto set_ptr; } *child = ptr; talloc_set_name_const(child, "talloc_set destructor"); talloc_set_destructor(child, talloc_destroy_pointer); set_ptr: /* memcpy rather than cast avoids aliasing problems. */ memcpy(ptr, &p, sizeof(p)); } /* externally callable talloc_set_name_const() */ void talloc_set_name_const(const void *ptr, const char *name) { _talloc_set_name_const(ptr, name); } /* create a named talloc pointer. Any talloc pointer can be named, and talloc_named() operates just like talloc() except that it allows you to name the pointer. */ void *talloc_named_const(const void *context, size_t size, const char *name) { void *p; lock(context); p = _talloc_named_const(context, size, name); unlock(); return p; } /* free a talloc pointer. This also frees all child pointers of this pointer recursively return 0 if the memory is actually freed, otherwise -1. The memory will not be freed if the ref_count is > 1 or the destructor (if any) returns non-zero */ int talloc_free(const void *ptr) { int saved_errno = errno, ret; lock(ptr); ret = _talloc_free(discard_const_p(void, ptr)); unlock(); if (ret == 0) errno = saved_errno; return ret; } /* A talloc version of realloc. The context argument is only used if ptr is NULL */ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name) { struct talloc_chunk *tc; void *new_ptr; /* size zero is equivalent to free() */ if (unlikely(size == 0)) { talloc_free(ptr); return NULL; } if (unlikely(size >= MAX_TALLOC_SIZE)) { return NULL; } /* realloc(NULL) is equivalent to malloc() */ if (ptr == NULL) { return talloc_named_const(context, size, name); } tc = talloc_chunk_from_ptr(ptr); /* don't allow realloc on referenced pointers */ if (unlikely(tc->refs)) { return NULL; } lock(ptr); if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) { /* need to get parent before setting free flag. */ void *parent = talloc_parent_nolock(ptr); tc->flags |= TALLOC_FLAG_FREE; new_ptr = tc_external_realloc(parent, tc, size + TC_HDR_SIZE); } else { /* by resetting magic we catch users of the old memory */ tc->flags |= TALLOC_FLAG_FREE; #if ALWAYS_REALLOC new_ptr = tc_malloc(size + TC_HDR_SIZE); if (new_ptr) { memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE); tc_free(tc); } #else new_ptr = tc_realloc(tc, size + TC_HDR_SIZE); #endif } if (unlikely(!new_ptr)) { tc->flags &= ~TALLOC_FLAG_FREE; unlock(); return NULL; } tc = (struct talloc_chunk *)new_ptr; tc->flags &= ~TALLOC_FLAG_FREE; if (tc->parent) { tc->parent->child = tc; } if (tc->child) { tc->child->parent = tc; } if (tc->prev) { tc->prev->next = tc; } if (tc->next) { tc->next->prev = tc; } tc->size = size; _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); unlock(); return TC_PTR_FROM_CHUNK(tc); } /* a wrapper around talloc_steal() for situations where you are moving a pointer between two structures, and want the old pointer to be set to NULL */ void *_talloc_move(const void *new_ctx, const void *_pptr) { const void **pptr = discard_const_p(const void *,_pptr); void *ret = _talloc_steal(new_ctx, *pptr); (*pptr) = NULL; return ret; } /* return the total size of a talloc pool (subtree) */ static size_t _talloc_total_size(const void *ptr) { size_t total = 0; struct talloc_chunk *c, *tc; tc = talloc_chunk_from_ptr(ptr); if (tc->flags & TALLOC_FLAG_LOOP) { return 0; } tc->flags |= TALLOC_FLAG_LOOP; total = tc->size; for (c=tc->child;c;c=c->next) { total += _talloc_total_size(TC_PTR_FROM_CHUNK(c)); } tc->flags &= ~TALLOC_FLAG_LOOP; return total; } size_t talloc_total_size(const void *ptr) { size_t total; if (ptr == NULL) { ptr = null_context; } if (ptr == NULL) { return 0; } lock(ptr); total = _talloc_total_size(ptr); unlock(); return total; } /* return the total number of blocks in a talloc pool (subtree) */ static size_t _talloc_total_blocks(const void *ptr) { size_t total = 0; struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); if (tc->flags & TALLOC_FLAG_LOOP) { return 0; } tc->flags |= TALLOC_FLAG_LOOP; total++; for (c=tc->child;c;c=c->next) { total += _talloc_total_blocks(TC_PTR_FROM_CHUNK(c)); } tc->flags &= ~TALLOC_FLAG_LOOP; return total; } size_t talloc_total_blocks(const void *ptr) { size_t total; lock(ptr); total = _talloc_total_blocks(ptr); unlock(); return total; } static size_t _talloc_reference_count(const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); struct talloc_reference_handle *h; size_t ret = 0; for (h=tc->refs;h;h=h->next) { ret++; } return ret; } /* return the number of external references to a pointer */ size_t talloc_reference_count(const void *ptr) { size_t ret; lock(talloc_chunk_from_ptr(ptr)); ret = _talloc_reference_count(ptr); unlock(); return ret; } /* report on memory usage by all children of a pointer, giving a full tree view */ static void _talloc_report_depth_cb(const void *ptr, int depth, int max_depth, void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *private_data), void *private_data) { struct talloc_chunk *c, *tc; tc = talloc_chunk_from_ptr(ptr); if (tc->flags & TALLOC_FLAG_LOOP) { return; } callback(ptr, depth, max_depth, 0, private_data); if (max_depth >= 0 && depth >= max_depth) { return; } tc->flags |= TALLOC_FLAG_LOOP; for (c=tc->child;c;c=c->next) { if (c->name == TALLOC_MAGIC_REFERENCE) { struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c); callback(h->ptr, depth + 1, max_depth, 1, private_data); } else { _talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data); } } tc->flags &= ~TALLOC_FLAG_LOOP; } void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *private_data), void *private_data) { if (ptr == NULL) { ptr = null_context; } if (ptr == NULL) return; lock(ptr); _talloc_report_depth_cb(ptr, depth, max_depth, callback, private_data); unlock(); } static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f) { const char *name = talloc_get_name(ptr); FILE *f = (FILE *)_f; if (is_ref) { fprintf(f, "%*sreference to: %s\n", depth*4, "", name); return; } if (depth == 0) { fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", (max_depth < 0 ? "full " :""), name, (unsigned long)_talloc_total_size(ptr), (unsigned long)_talloc_total_blocks(ptr)); return; } fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", depth*4, "", name, (unsigned long)_talloc_total_size(ptr), (unsigned long)_talloc_total_blocks(ptr), (int)_talloc_reference_count(ptr), ptr); #if 0 fprintf(f, "content: "); if (talloc_total_size(ptr)) { int tot = talloc_total_size(ptr); int i; for (i = 0; i < tot; i++) { if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) { fprintf(f, "%c", ((char *)ptr)[i]); } else { fprintf(f, "~%02x", ((char *)ptr)[i]); } } } fprintf(f, "\n"); #endif } /* report on memory usage by all children of a pointer, giving a full tree view */ void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f) { talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f); fflush(f); } /* report on memory usage by all children of a pointer, giving a full tree view */ void talloc_report_full(const void *ptr, FILE *f) { talloc_report_depth_file(ptr, 0, -1, f); } /* report on memory usage by all children of a pointer */ void talloc_report(const void *ptr, FILE *f) { talloc_report_depth_file(ptr, 0, 1, f); } /* report on any memory hanging off the null context */ static void talloc_report_null(void) { if (talloc_total_size(null_context) != 0) { talloc_report(null_context, stderr); } } /* report on any memory hanging off the null context */ static void talloc_report_null_full(void) { if (talloc_total_size(null_context) != 0) { talloc_report_full(null_context, stderr); } } /* enable tracking of the NULL context */ void talloc_enable_null_tracking(void) { if (null_context == NULL) { null_context = _talloc_named_const(NULL, 0, "null_context"); } } /* disable tracking of the NULL context */ void talloc_disable_null_tracking(void) { _talloc_free(null_context); null_context = NULL; } /* enable leak reporting on exit */ void talloc_enable_leak_report(void) { talloc_enable_null_tracking(); atexit(talloc_report_null); } /* enable full leak reporting on exit */ void talloc_enable_leak_report_full(void) { talloc_enable_null_tracking(); atexit(talloc_report_null_full); } /* talloc and zero memory. */ void *_talloc_zero(const void *ctx, size_t size, const char *name) { void *p; lock(ctx); p = _talloc_named_const(ctx, size, name); unlock(); if (p) { memset(p, '\0', size); } return p; } /* memdup with a talloc. */ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) { void *newp; lock(t); newp = _talloc_named_const(t, size, name); unlock(); if (likely(newp)) { memcpy(newp, p, size); } return newp; } /* strdup with a talloc */ char *talloc_strdup(const void *t, const char *p) { char *ret; if (!p) { return NULL; } ret = (char *)talloc_memdup(t, p, strlen(p) + 1); if (likely(ret)) { _talloc_set_name_const(ret, ret); } return ret; } /* append to a talloced string */ char *talloc_append_string(char *orig, const char *append) { char *ret; size_t olen = strlen(orig); size_t alenz; if (!append) return orig; alenz = strlen(append) + 1; ret = talloc_realloc(NULL, orig, char, olen + alenz); if (!ret) return NULL; /* append the string with the trailing \0 */ memcpy(&ret[olen], append, alenz); _talloc_set_name_const(ret, ret); return ret; } /* strndup with a talloc */ char *talloc_strndup(const void *t, const char *p, size_t n) { size_t len; char *ret; for (len=0; lensize - 1; va_copy(ap2, ap); len = vsnprintf(&c, 1, fmt, ap2); va_end(ap2); if (len <= 0) { /* Either the vsnprintf failed or the format resulted in * no characters being formatted. In the former case, we * ought to return NULL, in the latter we ought to return * the original string. Most current callers of this * function expect it to never return NULL. */ return s; } s = talloc_realloc(NULL, s, char, s_len + len+1); if (!s) return NULL; va_copy(ap2, ap); vsnprintf(s+s_len, len+1, fmt, ap2); va_end(ap2); _talloc_set_name_const(s, s); return s; } /* Realloc @p s to append the formatted result of @p fmt and return @p s, which may have moved. Good for gradually accumulating output into a string buffer. */ char *talloc_asprintf_append(char *s, const char *fmt, ...) { va_list ap; va_start(ap, fmt); s = talloc_vasprintf_append(s, fmt, ap); va_end(ap); return s; } /* alloc an array, checking for integer overflow in the array size */ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name) { void *p; if (count >= MAX_TALLOC_SIZE/el_size) { return NULL; } lock(ctx); p = _talloc_named_const(ctx, el_size * count, name); unlock(); return p; } /* alloc an zero array, checking for integer overflow in the array size */ void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name) { void *p; if (count >= MAX_TALLOC_SIZE/el_size) { return NULL; } p = _talloc_zero(ctx, el_size * count, name); return p; } /* realloc an array, checking for integer overflow in the array size */ void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name) { if (count >= MAX_TALLOC_SIZE/el_size) { return NULL; } return _talloc_realloc(ctx, ptr, el_size * count, name); } /* a function version of talloc_realloc(), so it can be passed as a function pointer to libraries that want a realloc function (a realloc function encapsulates all the basic capabilities of an allocation library, which is why this is useful) */ void *talloc_realloc_fn(const void *context, void *ptr, size_t size) { return _talloc_realloc(context, ptr, size, NULL); } static int talloc_autofree_destructor(void *ptr) { autofree_context = NULL; return 0; } static void talloc_autofree(void) { if (autofree_context && *autofree_context == getpid()) talloc_free(autofree_context); } /* return a context which will be auto-freed on exit this is useful for reducing the noise in leak reports */ void *talloc_autofree_context(void) { if (autofree_context == NULL || *autofree_context != getpid()) { autofree_context = talloc(NULL, pid_t); *autofree_context = getpid(); talloc_set_name_const(autofree_context, "autofree_context"); talloc_set_destructor(autofree_context, talloc_autofree_destructor); atexit(talloc_autofree); } return autofree_context; } size_t talloc_get_size(const void *context) { struct talloc_chunk *tc; if (context == NULL) return 0; tc = talloc_chunk_from_ptr(context); return tc->size; } /* find a parent of this context that has the given name, if any */ void *talloc_find_parent_byname(const void *context, const char *name) { struct talloc_chunk *tc; if (context == NULL) { return NULL; } lock(context); tc = talloc_chunk_from_ptr(context); while (tc) { if (tc->name && strcmp(tc->name, name) == 0) { unlock(); return TC_PTR_FROM_CHUNK(tc); } while (tc && tc->prev) tc = tc->prev; if (tc) { tc = tc->parent; } } unlock(); return NULL; } /* show the parentage of a context */ void talloc_show_parents(const void *context, FILE *file) { struct talloc_chunk *tc; if (context == NULL) { fprintf(file, "talloc no parents for NULL\n"); return; } lock(context); tc = talloc_chunk_from_ptr(context); fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context)); while (tc) { fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc))); while (tc && tc->prev) tc = tc->prev; if (tc) { tc = tc->parent; } } unlock(); fflush(file); } int talloc_is_parent(const void *context, const void *ptr) { int ret; lock(context); ret = _talloc_is_parent(context, ptr); unlock(); return ret; } void talloc_set_allocator(void *(*malloc)(size_t size), void (*free)(void *ptr), void *(*realloc)(void *ptr, size_t size)) { tc_malloc = malloc; tc_free = free; tc_realloc = realloc; } void *talloc_add_external(const void *ctx, void *(*realloc)(const void *, void *, size_t), void (*lock)(const void *p), void (*unlock)(void)) { struct talloc_chunk *tc, *parent; void *p; if (tc_external_realloc && tc_external_realloc != realloc) TALLOC_ABORT("talloc_add_external realloc replaced"); tc_external_realloc = realloc; if (unlikely(ctx == NULL)) { ctx = null_context; parent = NULL; } else parent = talloc_chunk_from_ptr(ctx); tc = tc_external_realloc(ctx, NULL, TC_HDR_SIZE); p = init_talloc(parent, tc, 0, 1); tc_lock = lock; tc_unlock = unlock; return p; } sbsigntool-0.9.2/lib/ccan/ccan/talloc/talloc.h000066400000000000000000001105411342142174400211740ustar00rootroot00000000000000#ifndef CCAN_TALLOC_H #define CCAN_TALLOC_H /* Copyright (C) Andrew Tridgell 2004-2005 Copyright (C) Stefan Metzmacher 2006 ** NOTE! The following LGPL license applies to the talloc ** library. This does NOT imply that all of Samba is released ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "config.h" /* this uses a little trick to allow __LINE__ to be stringified */ #ifndef __location__ #define __TALLOC_STRING_LINE1__(s) #s #define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s) #define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__) #define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__ #endif /* try to make talloc_set_destructor() and talloc_steal() type safe, if we have a recent gcc */ #if HAVE_TYPEOF #define _TALLOC_TYPEOF(ptr) __typeof__(ptr) #else #define _TALLOC_TYPEOF(ptr) void * #endif #define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr)) /** * talloc - allocate dynamic memory for a type * @ctx: context to be parent of this allocation, or NULL. * @type: the type to be allocated. * * The talloc() macro is the core of the talloc library. It takes a memory * context and a type, and returns a pointer to a new area of memory of the * given type. * * The returned pointer is itself a talloc context, so you can use it as the * context argument to more calls to talloc if you wish. * * The returned pointer is a "child" of @ctx. This means that if you * talloc_free() @ctx then the new child disappears as well. Alternatively you * can free just the child. * * @ctx can be NULL, in which case a new top level context is created. * * Example: * unsigned int *a, *b; * a = talloc(NULL, unsigned int); * b = talloc(a, unsigned int); * * See Also: * talloc_zero, talloc_array, talloc_steal, talloc_free. */ #define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type) /** * TALLOC_CTX - indicate that a pointer is used as a talloc parent. * * As talloc is a hierarchial memory allocator, every talloc chunk is a * potential parent to other talloc chunks. So defining a separate type for a * talloc chunk is not strictly necessary. TALLOC_CTX is defined nevertheless, * as it provides an indicator for function arguments. * * Example: * struct foo { * int val; * }; * * static struct foo *foo_new(TALLOC_CTX *mem_ctx) * { * struct foo *foo = talloc(mem_ctx, struct foo); * if (foo) * foo->val = 0; * return foo; * } */ typedef void TALLOC_CTX; /** * talloc_set - allocate dynamic memory for a type, into a pointer * @ptr: pointer to the pointer to assign. * @ctx: context to be parent of this allocation, or NULL. * * talloc_set() does a talloc, but also adds a destructor which will make the * pointer invalid when it is freed. This can find many use-after-free bugs. * * Note that the destructor is chained off a zero-length allocation, and so * is not affected by talloc_set_destructor(). * * Example: * unsigned int *b, *a; * a = talloc(NULL, unsigned int); * talloc_set(&b, a); * talloc_free(a); * *b = 1; // This will crash! * * See Also: * talloc. */ #define talloc_set(pptr, ctx) \ _talloc_set((pptr), (ctx), sizeof(&**(pptr)), __location__) /** * talloc_free - free talloc'ed memory and its children * @ptr: the talloced pointer to free * * The talloc_free() function frees a piece of talloc memory, and all its * children. You can call talloc_free() on any pointer returned by talloc(). * * The return value of talloc_free() indicates success or failure, with 0 * returned for success and -1 for failure. The only possible failure condition * is if the pointer had a destructor attached to it and the destructor * returned -1. See talloc_set_destructor() for details on destructors. * errno will be preserved unless the talloc_free fails. * * If this pointer has an additional parent when talloc_free() is called then * the memory is not actually released, but instead the most recently * established parent is destroyed. See talloc_reference() for details on * establishing additional parents. * * For more control on which parent is removed, see talloc_unlink(). * * talloc_free() operates recursively on its children. * * Example: * unsigned int *a, *b; * a = talloc(NULL, unsigned int); * b = talloc(a, unsigned int); * // Frees a and b * talloc_free(a); * * See Also: * talloc_set_destructor, talloc_unlink */ int talloc_free(const void *ptr); /** * talloc_set_destructor - set a destructor for when this pointer is freed * @ptr: the talloc pointer to set the destructor on * @destructor: the function to be called * * The function talloc_set_destructor() sets the "destructor" for the pointer * @ptr. A destructor is a function that is called when the memory used by a * pointer is about to be released. The destructor receives the pointer as an * argument, and should return 0 for success and -1 for failure. * * The destructor can do anything it wants to, including freeing other pieces * of memory. A common use for destructors is to clean up operating system * resources (such as open file descriptors) contained in the structure the * destructor is placed on. * * You can only place one destructor on a pointer. If you need more than one * destructor then you can create a zero-length child of the pointer and place * an additional destructor on that. * * To remove a destructor call talloc_set_destructor() with NULL for the * destructor. * * If your destructor attempts to talloc_free() the pointer that it is the * destructor for then talloc_free() will return -1 and the free will be * ignored. This would be a pointless operation anyway, as the destructor is * only called when the memory is just about to go away. * * Example: * static int destroy_fd(int *fd) * { * close(*fd); * return 0; * } * * static int *open_file(const char *filename) * { * int *fd = talloc(NULL, int); * *fd = open(filename, O_RDONLY); * if (*fd < 0) { * talloc_free(fd); * return NULL; * } * // Whenever they free this, we close the file. * talloc_set_destructor(fd, destroy_fd); * return fd; * } * * See Also: * talloc, talloc_free */ #define talloc_set_destructor(ptr, function) \ _talloc_set_destructor((ptr), typesafe_cb(int, void *, (function), (ptr))) /** * talloc_zero - allocate zeroed dynamic memory for a type * @ctx: context to be parent of this allocation, or NULL. * @type: the type to be allocated. * * The talloc_zero() macro is equivalent to: * * ptr = talloc(ctx, type); * if (ptr) memset(ptr, 0, sizeof(type)); * * Example: * unsigned int *a, *b; * a = talloc_zero(NULL, unsigned int); * b = talloc_zero(a, unsigned int); * * See Also: * talloc, talloc_zero_size, talloc_zero_array */ #define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type) /** * talloc_array - allocate dynamic memory for an array of a given type * @ctx: context to be parent of this allocation, or NULL. * @type: the type to be allocated. * @count: the number of elements to be allocated. * * The talloc_array() macro is a safe way of allocating an array. It is * equivalent to: * * (type *)talloc_size(ctx, sizeof(type) * count); * * except that it provides integer overflow protection for the multiply, * returning NULL if the multiply overflows. * * Example: * unsigned int *a, *b; * a = talloc_zero(NULL, unsigned int); * b = talloc_array(a, unsigned int, 100); * * See Also: * talloc, talloc_zero_array, talloc_array_length */ #define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type) /** * talloc_size - allocate a particular size of memory * @ctx: context to be parent of this allocation, or NULL. * @size: the number of bytes to allocate * * The function talloc_size() should be used when you don't have a convenient * type to pass to talloc(). Unlike talloc(), it is not type safe (as it * returns a void *), so you are on your own for type checking. * * Best to use talloc() or talloc_array() instead. * * Example: * void *mem = talloc_size(NULL, 100); * memset(mem, 0xFF, 100); * * See Also: * talloc, talloc_array, talloc_zero_size */ #define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__) #if HAVE_TYPEOF /** * talloc_steal - change/set the parent context of a talloc pointer * @ctx: the new parent * @ptr: the talloc pointer to reparent * * The talloc_steal() function changes the parent context of a talloc * pointer. It is typically used when the context that the pointer is currently * a child of is going to be freed and you wish to keep the memory for a longer * time. * * The talloc_steal() function returns the pointer that you pass it. It does * not have any failure modes. * * NOTE: It is possible to produce loops in the parent/child relationship if * you are not careful with talloc_steal(). No guarantees are provided as to * your sanity or the safety of your data if you do this. * * talloc_steal (new_ctx, NULL) will return NULL with no sideeffects. * * Example: * unsigned int *a, *b; * a = talloc(NULL, unsigned int); * b = talloc(NULL, unsigned int); * // Reparent b to a as if we'd done 'b = talloc(a, unsigned int)'. * talloc_steal(a, b); * * See Also: * talloc_reference */ #define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) _talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); _talloc_steal_ret; }) /* this extremely strange macro is to avoid some braindamaged warning stupidity in gcc 4.1.x */ #else #define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)) #endif /* HAVE_TYPEOF */ /** * talloc_report_full - report all the memory used by a pointer and children. * @ptr: the context to report on * @f: the file to report to * * Recursively print the entire tree of memory referenced by the * pointer. References in the tree are shown by giving the name of the pointer * that is referenced. * * You can pass NULL for the pointer, in which case a report is printed for the * top level memory context, but only if talloc_enable_null_tracking() has been * called. * * Example: * unsigned int *a, *b; * a = talloc(NULL, unsigned int); * b = talloc(a, unsigned int); * fprintf(stderr, "Dumping memory tree for a:\n"); * talloc_report_full(a, stderr); * * See Also: * talloc_report */ void talloc_report_full(const void *ptr, FILE *f); /** * talloc_reference - add an additional parent to a context * @ctx: the additional parent * @ptr: the talloc pointer * * The talloc_reference() function makes @ctx an additional parent of @ptr. * * The return value of talloc_reference() is always the original pointer @ptr, * unless talloc ran out of memory in creating the reference in which case it * will return NULL (each additional reference consumes around 48 bytes of * memory on intel x86 platforms). * * If @ptr is NULL, then the function is a no-op, and simply returns NULL. * * After creating a reference you can free it in one of the following ways: * * - you can talloc_free() any parent of the original pointer. That will * reduce the number of parents of this pointer by 1, and will cause this * pointer to be freed if it runs out of parents. * * - you can talloc_free() the pointer itself. That will destroy the most * recently established parent to the pointer and leave the pointer as a * child of its current parent. * * For more control on which parent to remove, see talloc_unlink(). * Example: * unsigned int *a, *b, *c; * a = talloc(NULL, unsigned int); * b = talloc(NULL, unsigned int); * c = talloc(a, unsigned int); * // b also serves as a parent of c (don't care about errors) * (void)talloc_reference(b, c); */ #define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr)) /** * talloc_unlink - remove a specific parent from a talloc pointer. * @context: the parent to remove * @ptr: the talloc pointer * * The talloc_unlink() function removes a specific parent from @ptr. The * context passed must either be a context used in talloc_reference() with this * pointer, or must be a direct parent of @ptr. * * Note that if the parent has already been removed using talloc_free() then * this function will fail and will return -1. Likewise, if @ptr is NULL, * then the function will make no modifications and return -1. * * Usually you can just use talloc_free() instead of talloc_unlink(), but * sometimes it is useful to have the additional control on which parent is * removed. * * Example: * unsigned int *a, *b, *c; * a = talloc(NULL, unsigned int); * b = talloc(NULL, unsigned int); * c = talloc(a, unsigned int); * // b also serves as a parent of c. * (void)talloc_reference(b, c); * talloc_unlink(b, c); */ int talloc_unlink(const void *context, void *ptr); /** * talloc_report - print a summary of memory used by a pointer * * The talloc_report() function prints a summary report of all memory * used by @ptr. One line of report is printed for each immediate child of * @ptr, showing the total memory and number of blocks used by that child. * * You can pass NULL for the pointer, in which case a report is printed for the * top level memory context, but only if talloc_enable_null_tracking() has been * called. * * Example: * unsigned int *a, *b; * a = talloc(NULL, unsigned int); * b = talloc(a, unsigned int); * fprintf(stderr, "Summary of memory tree for a:\n"); * talloc_report(a, stderr); * * See Also: * talloc_report_full */ void talloc_report(const void *ptr, FILE *f); /** * talloc_ptrtype - allocate a size of memory suitable for this pointer * @ctx: context to be parent of this allocation, or NULL. * @ptr: the pointer whose type we are to allocate * * The talloc_ptrtype() macro should be used when you have a pointer and * want to allocate memory to point at with this pointer. When compiling * with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size() * and talloc_get_name() will return the current location in the source file. * and not the type. * * Example: * unsigned int *a = talloc_ptrtype(NULL, a); */ #define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr))) /** * talloc_new - create a new context * @ctx: the context to use as a parent. * * This is a utility macro that creates a new memory context hanging off an * exiting context, automatically naming it "talloc_new: __location__" where * __location__ is the source line it is called from. It is particularly useful * for creating a new temporary working context. */ #define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__) /** * talloc_zero_size - allocate a particular size of zeroed memory * * The talloc_zero_size() function is useful when you don't have a known type. */ #define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__) /** * talloc_zero_array - allocate an array of zeroed types * @ctx: context to be parent of this allocation, or NULL. * @type: the type to be allocated. * @count: the number of elements to be allocated. * * Just like talloc_array, but zeroes the memory. */ #define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type) /** * talloc_array_size - allocate an array of elements of the given size * @ctx: context to be parent of this allocation, or NULL. * @size: the size of each element * @count: the number of elements to be allocated. * * Typeless form of talloc_array. */ #define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__) /** * talloc_array_ptrtype - allocate an array of memory suitable for this pointer * @ctx: context to be parent of this allocation, or NULL. * @ptr: the pointer whose type we are to allocate * @count: the number of elements for the array * * Like talloc_ptrtype(), except it allocates an array. */ #define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count) /** * talloc_realloc - resize a talloc array * @ctx: the parent to assign (if p is NULL) * @p: the memory to reallocate * @type: the type of the object to allocate * @count: the number of objects to reallocate * * The talloc_realloc() macro changes the size of a talloc pointer. The "count" * argument is the number of elements of type "type" that you want the * resulting pointer to hold. * * talloc_realloc() has the following equivalences: * * talloc_realloc(context, NULL, type, 1) ==> talloc(context, type); * talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N); * talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr); * * The "context" argument is only used if "ptr" is NULL, otherwise it is * ignored. * * talloc_realloc() returns the new pointer, or NULL on failure. The call will * fail either due to a lack of memory, or because the pointer has more than * one parent (see talloc_reference()). */ #define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type) /** * talloc_realloc_size - resize talloc memory * @ctx: the parent to assign (if p is NULL) * @ptr: the memory to reallocate * @size: the new size of memory. * * The talloc_realloc_size() function is useful when the type is not known so * the typesafe talloc_realloc() cannot be used. */ #define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__) /** * talloc_strdup - duplicate a string * @ctx: the talloc context for the new string * @p: the string to copy * * The talloc_strdup() function is equivalent to: * * ptr = talloc_size(ctx, strlen(p)+1); * if (ptr) memcpy(ptr, p, strlen(p)+1); * * This functions sets the name of the new pointer to the passed string. This * is equivalent to: * * talloc_set_name_const(ptr, ptr) */ char *talloc_strdup(const void *t, const char *p); /** * talloc_strndup - duplicate a limited length of a string * @ctx: the talloc context for the new string * @p: the string to copy * @n: the maximum length of the returned string. * * The talloc_strndup() function is the talloc equivalent of the C library * function strndup(): the result will be truncated to @n characters before * the nul terminator. * * This functions sets the name of the new pointer to the passed string. This * is equivalent to: * * talloc_set_name_const(ptr, ptr) */ char *talloc_strndup(const void *t, const char *p, size_t n); /** * talloc_memdup - duplicate some talloc memory * * The talloc_memdup() function is equivalent to: * * ptr = talloc_size(ctx, size); * if (ptr) memcpy(ptr, p, size); */ #define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__) /** * talloc_asprintf - sprintf into a talloc buffer. * @t: The context to allocate the buffer from * @fmt: printf-style format for the buffer. * * The talloc_asprintf() function is the talloc equivalent of the C library * function asprintf(). * * This functions sets the name of the new pointer to the new string. This is * equivalent to: * * talloc_set_name_const(ptr, ptr) */ char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_FMT(2,3); /** * talloc_append_string - concatenate onto a tallocated string * @orig: the tallocated string to append to * @append: the string to add, or NULL to add nothing. * * The talloc_append_string() function appends the given formatted string to * the given string. * * This function sets the name of the new pointer to the new string. This is * equivalent to: * * talloc_set_name_const(ptr, ptr) */ char *WARN_UNUSED_RESULT talloc_append_string(char *orig, const char *append); /** * talloc_asprintf_append - sprintf onto the end of a talloc buffer. * @s: The tallocated string buffer * @fmt: printf-style format to append to the buffer. * * The talloc_asprintf_append() function appends the given formatted string to * the given string. * * This functions sets the name of the new pointer to the new string. This is * equivalent to: * talloc_set_name_const(ptr, ptr) */ char *WARN_UNUSED_RESULT talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_FMT(2,3); /** * talloc_vasprintf - vsprintf into a talloc buffer. * @t: The context to allocate the buffer from * @fmt: printf-style format for the buffer * @ap: va_list arguments * * The talloc_vasprintf() function is the talloc equivalent of the C library * function vasprintf() * * This functions sets the name of the new pointer to the new string. This is * equivalent to: * * talloc_set_name_const(ptr, ptr) */ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_FMT(2,0); /** * talloc_vasprintf_append - sprintf onto the end of a talloc buffer. * @t: The context to allocate the buffer from * @fmt: printf-style format for the buffer * @ap: va_list arguments * * The talloc_vasprintf_append() function is equivalent to * talloc_asprintf_append(), except it takes a va_list. */ char *WARN_UNUSED_RESULT talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_FMT(2,0); /** * talloc_set_type - force the name of a pointer to a particular type * @ptr: the talloc pointer * @type: the type whose name to set the ptr name to. * * This macro allows you to force the name of a pointer to be a particular * type. This can be used in conjunction with talloc_get_type() to do type * checking on void* pointers. * * It is equivalent to this: * talloc_set_name_const(ptr, #type) */ #define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type) /** * talloc_get_type - convert a talloced pointer with typechecking * @ptr: the talloc pointer * @type: the type which we expect the talloced pointer to be. * * This macro allows you to do type checking on talloc pointers. It is * particularly useful for void* private pointers. It is equivalent to this: * * (type *)talloc_check_name(ptr, #type) */ #define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type) /** * talloc_find_parent_byname - find a talloc parent by type * @ptr: the talloc pointer * @type: the type we're looking for * * Find a parent memory context of the current context that has the given * name. This can be very useful in complex programs where it may be difficult * to pass all information down to the level you need, but you know the * structure you want is a parent of another context. */ #define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type) /** * talloc_increase_ref_count - hold a reference to a talloc pointer * @ptr: the talloc pointer * * The talloc_increase_ref_count(ptr) function is exactly equivalent to: * * talloc_reference(NULL, ptr); * * You can use either syntax, depending on which you think is clearer in your * code. * * It returns 0 on success and -1 on failure. */ int talloc_increase_ref_count(const void *ptr); /** * talloc_set_name - set the name for a talloc pointer * @ptr: the talloc pointer * @fmt: the printf-style format string for the name * * Each talloc pointer has a "name". The name is used principally for debugging * purposes, although it is also possible to set and get the name on a pointer * in as a way of "marking" pointers in your code. * * The main use for names on pointer is for "talloc reports". See * talloc_report() and talloc_report_full() for details. Also see * talloc_enable_leak_report() and talloc_enable_leak_report_full(). * * The talloc_set_name() function allocates memory as a child of the * pointer. It is logically equivalent to: * talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...)); * * Note that multiple calls to talloc_set_name() will allocate more memory * without releasing the name. All of the memory is released when the ptr is * freed using talloc_free(). */ const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_FMT(2,3); /** * talloc_set_name_const - set a talloc pointer name to a string constant * @ptr: the talloc pointer to name * @name: the strucng constant. * * The function talloc_set_name_const() is just like talloc_set_name(), but it * takes a string constant, and is much faster. It is extensively used by the * "auto naming" macros, such as talloc(). * * This function does not allocate any memory. It just copies the supplied * pointer into the internal representation of the talloc ptr. This means you * must not pass a name pointer to memory that will disappear before the ptr is * freed with talloc_free(). */ void talloc_set_name_const(const void *ptr, const char *name); /** * talloc_named - create a specifically-named talloc pointer * @context: the parent context for the allocation * @size: the size to allocate * @fmt: the printf-style format for the name * * The talloc_named() function creates a named talloc pointer. It is equivalent * to: * * ptr = talloc_size(context, size); * talloc_set_name(ptr, fmt, ....); */ void *talloc_named(const void *context, size_t size, const char *fmt, ...) PRINTF_FMT(3,4); /** * talloc_named_const - create a specifically-named talloc pointer * @context: the parent context for the allocation * @size: the size to allocate * @name: the string constant to use as the name * * This is equivalent to: * * ptr = talloc_size(context, size); * talloc_set_name_const(ptr, name); */ void *talloc_named_const(const void *context, size_t size, const char *name); /** * talloc_get_name - get the name of a talloc pointer * @ptr: the talloc pointer * * This returns the current name for the given talloc pointer. See * talloc_set_name() for details. */ const char *talloc_get_name(const void *ptr); /** * talloc_check_name - check if a pointer has the specified name * @ptr: the talloc pointer * @name: the name to compare with the pointer's name * * This function checks if a pointer has the specified name. If it does then * the pointer is returned. It it doesn't then NULL is returned. */ void *talloc_check_name(const void *ptr, const char *name); /** * talloc_init - create a top-level context of particular name * @fmt: the printf-style format of the name * * This function creates a zero length named talloc context as a top level * context. It is equivalent to: * * talloc_named(NULL, 0, fmt, ...); */ void *talloc_init(const char *fmt, ...) PRINTF_FMT(1,2); /** * talloc_total_size - get the bytes used by the pointer and its children * @ptr: the talloc pointer * * The talloc_total_size() function returns the total size in bytes used by * this pointer and all child pointers. Mostly useful for debugging. * * Passing NULL is allowed, but it will only give a meaningful result if * talloc_enable_leak_report() or talloc_enable_leak_report_full() has been * called. */ size_t talloc_total_size(const void *ptr); /** * talloc_total_blocks - get the number of allocations for the pointer * @ptr: the talloc pointer * * The talloc_total_blocks() function returns the total allocations used by * this pointer and all child pointers. Mostly useful for debugging. For * example, a pointer with no children will return "1". * * Passing NULL is allowed, but it will only give a meaningful result if * talloc_enable_leak_report() or talloc_enable_leak_report_full() has been * called. */ size_t talloc_total_blocks(const void *ptr); /** * talloc_report_depth_cb - walk the entire talloc tree under a talloc pointer * @ptr: the talloc pointer to recurse under * @depth: the current depth of traversal * @max_depth: maximum depth to traverse, or -1 for no maximum * @callback: the function to call on each pointer * @private_data: pointer to hand to @callback. * * This provides a more flexible reports than talloc_report(). It will * recursively call the callback for the entire tree of memory referenced by * the pointer. References in the tree are passed with is_ref = 1 and the * pointer that is referenced. * * You can pass NULL for the pointer, in which case a report is printed for the * top level memory context, but only if talloc_enable_leak_report() or * talloc_enable_leak_report_full() has been called. * * The recursion is stopped when depth >= max_depth. max_depth = -1 means only * stop at leaf nodes. */ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *private_data), void *private_data); /** * talloc_report_depth_file - report talloc usage to a maximum depth * @ptr: the talloc pointer to recurse under * @depth: the current depth of traversal * @max_depth: maximum depth to traverse, or -1 for no maximum * @f: the file to report to * * This provides a more flexible reports than talloc_report(). It will let you * specify the depth and max_depth. */ void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f); /** * talloc_enable_null_tracking - enable tracking of top-level tallocs * * This enables tracking of the NULL memory context without enabling leak * reporting on exit. Useful for when you want to do your own leak reporting * call via talloc_report_null_full(); */ void talloc_enable_null_tracking(void); /** * talloc_disable_null_tracking - enable tracking of top-level tallocs * * This disables tracking of the NULL memory context. */ void talloc_disable_null_tracking(void); /** * talloc_enable_leak_report - call talloc_report on program exit * * This enables calling of talloc_report(NULL, stderr) when the program * exits. In Samba4 this is enabled by using the --leak-report command line * option. * * For it to be useful, this function must be called before any other talloc * function as it establishes a "null context" that acts as the top of the * tree. If you don't call this function first then passing NULL to * talloc_report() or talloc_report_full() won't give you the full tree * printout. * * Here is a typical talloc report: * * talloc report on 'null_context' (total 267 bytes in 15 blocks) * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks * iconv(UTF8,CP850) contains 42 bytes in 2 blocks * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks * iconv(CP850,UTF8) contains 42 bytes in 2 blocks * iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks * iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks */ void talloc_enable_leak_report(void); /** * talloc_enable_leak_report - call talloc_report_full on program exit * * This enables calling of talloc_report_full(NULL, stderr) when the program * exits. In Samba4 this is enabled by using the --leak-report-full command * line option. * * For it to be useful, this function must be called before any other talloc * function as it establishes a "null context" that acts as the top of the * tree. If you don't call this function first then passing NULL to * talloc_report() or talloc_report_full() won't give you the full tree * printout. * * Here is a typical full report: * * full talloc report on 'root' (total 18 bytes in 8 blocks) * p1 contains 18 bytes in 7 blocks (ref 0) * r1 contains 13 bytes in 2 blocks (ref 0) * reference to: p2 * p2 contains 1 bytes in 1 blocks (ref 1) * x3 contains 1 bytes in 1 blocks (ref 0) * x2 contains 1 bytes in 1 blocks (ref 0) * x1 contains 1 bytes in 1 blocks (ref 0) */ void talloc_enable_leak_report_full(void); /** * talloc_autofree_context - a context which will be freed at exit * * This is a handy utility function that returns a talloc context which will be * automatically freed on program exit. This can be used to reduce the noise in * memory leak reports. */ void *talloc_autofree_context(void); /** * talloc_array_length - get the number of elements in a talloc array * @p: the talloc pointer whose allocation to measure. * * This assumes that @p has been allocated as the same type. NULL returns 0. * * See Also: * talloc_get_size */ #define talloc_array_length(p) (talloc_get_size(p) / sizeof((*p))) /** * talloc_get_size - get the requested size of an allocation * @ctx: the talloc pointer whose allocation to measure. * * This function lets you know the amount of memory alloced so far by this * context. It does NOT account for subcontext memory. * * See Also: * talloc_array_length */ size_t talloc_get_size(const void *ctx); /** * talloc_find_parent_byname - find a parent of this context with this name * @ctx: the context whose ancestors to search * @name: the name to look for * * Find a parent memory context of @ctx that has the given name. This can be * very useful in complex programs where it may be difficult to pass all * information down to the level you need, but you know the structure you want * is a parent of another context. */ void *talloc_find_parent_byname(const void *ctx, const char *name); /** * talloc_set_allocator - set the allocations function(s) for talloc. * @malloc: the malloc function * @free: the free function * @realloc: the realloc function * * Instead of using the standard malloc, free and realloc, talloc will use * these replacements. @realloc will never be called with size 0 or ptr NULL. */ void talloc_set_allocator(void *(*malloc)(size_t size), void (*free)(void *ptr), void *(*realloc)(void *ptr, size_t size)); /** * talloc_add_external - create an externally allocated node * @ctx: the parent * @realloc: the realloc() equivalent * @lock: the call to lock before manipulation of external nodes * @unlock: the call to unlock after manipulation of external nodes * * talloc_add_external() creates a node which uses a separate allocator. All * children allocated from that node will also use that allocator. * * Note: Currently there is only one external allocator, not per-node, * and it is set with this function. * * @lock is handed a pointer which was previous returned from your realloc * function; you should use that to figure out which lock to get if you have * multiple external pools. * * The parent pointers in realloc is the talloc pointer of the parent, if any. */ void *talloc_add_external(const void *ctx, void *(*realloc)(const void *parent, void *ptr, size_t), void (*lock)(const void *p), void (*unlock)(void)); /* The following definitions come from talloc.c */ void *_talloc(const void *context, size_t size); void _talloc_set(void *ptr, const void *ctx, size_t size, const char *name); void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)); size_t talloc_reference_count(const void *ptr); void *_talloc_reference(const void *context, const void *ptr); void *WARN_UNUSED_RESULT _talloc_realloc(const void *context, void *ptr, size_t size, const char *name); void *talloc_parent(const void *ptr); const char *talloc_parent_name(const void *ptr); void *_talloc_steal(const void *new_ctx, const void *ptr); void *_talloc_move(const void *new_ctx, const void *pptr); void *_talloc_zero(const void *ctx, size_t size, const char *name); void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name); void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name); void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name); void *WARN_UNUSED_RESULT _talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name); void *talloc_realloc_fn(const void *context, void *ptr, size_t size); void talloc_show_parents(const void *context, FILE *file); int talloc_is_parent(const void *context, const void *ptr); #endif /* CCAN_TALLOC_H */ sbsigntool-0.9.2/lib/ccan/ccan/tcon/000077500000000000000000000000001342142174400172305ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/tcon/tcon.h000066400000000000000000000066651342142174400203610ustar00rootroot00000000000000/* Placed into the public domain */ #ifndef CCAN_TCON_H #define CCAN_TCON_H #include "config.h" /** * TCON - declare a _tcon type containing canary variables. * @decls: the semi-colon separated list of type canaries. * * This declares a _tcon member for a structure. It should be the * last element in your structure; with sufficient compiler support it * will not use any actual storage. tcon_check() will compare * expressions with one of these "type canaries" to cause warnings if * the container is misused. * * A type of "void *" will allow tcon_check() to pass on any (pointer) type. * * Example: * // Simply typesafe linked list. * struct list_head { * struct list_head *prev, *next; * }; * * struct string_list { * struct list_head raw; * TCON(char *canary); * }; * * // More complex: mapping from one type to another. * struct map { * void *contents; * }; * * struct int_to_string_map { * struct map raw; * TCON(char *charp_canary; int int_canary); * }; */ #if HAVE_FLEXIBLE_ARRAY_MEMBER #define TCON(decls) struct { decls; } _tcon[] #else #define TCON(decls) struct { decls; } _tcon[1] #endif /** * tcon_check - typecheck a typed container * @x: the structure containing the TCON. * @canary: which canary to check against. * @expr: the expression whose type must match the TCON (not evaluated) * * This macro is used to check that the expression is the type * expected for this structure (note the "useless" sizeof() argument * which contains this comparison with the type canary). * * It evaluates to @x so you can chain it. * * Example: * #define tlist_add(h, n, member) \ * list_add(&tcon_check((h), canary, (n))->raw, &(n)->member) */ #define tcon_check(x, canary, expr) \ (sizeof((x)->_tcon[0].canary == (expr)) ? (x) : (x)) /** * tcon_check_ptr - typecheck a typed container * @x: the structure containing the TCON. * @canary: which canary to check against. * @expr: the expression whose type must match &TCON (not evaluated) * * This macro is used to check that the expression is a pointer to the type * expected for this structure (note the "useless" sizeof() argument * which contains this comparison with the type canary), or NULL. * * It evaluates to @x so you can chain it. */ #define tcon_check_ptr(x, canary, expr) \ (sizeof(&(x)->_tcon[0].canary == (expr)) ? (x) : (x)) /** * tcon_type - the type within a container (or void *) * @x: the structure containing the TCON. * @canary: which canary to check against. */ #if HAVE_TYPEOF #define tcon_type(x, canary) __typeof__((x)->_tcon[0].canary) #else #define tcon_type(x, canary) void * #endif /** * tcon_ptr_type - pointer to the type within a container (or void *) * @x: the structure containing the TCON. * @canary: which canary to check against. */ #if HAVE_TYPEOF #define tcon_ptr_type(x, canary) __typeof__(&(x)->_tcon[0].canary) #else #define tcon_ptr_type(x, canary) void * #endif /** * tcon_cast - cast to a canary type for this container (or void *) * @x: a structure containing the TCON. * @canary: which canary to cast to. * @expr: the value to cast * * This is used to cast to the correct type for this container. If the * platform doesn't HAVE_TYPEOF, then it casts to void * (which will * cause a warning if the user doesn't expect a pointer type). */ #define tcon_cast(x, canary, expr) ((tcon_type((x), canary))(expr)) #define tcon_cast_ptr(x, canary, expr) ((tcon_ptr_type((x), canary))(expr)) #endif /* CCAN_TCON_H */ sbsigntool-0.9.2/lib/ccan/ccan/time/000077500000000000000000000000001342142174400172235ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/time/LICENSE000077700000000000000000000000001342142174400234402../../licenses/BSD-MITustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/time/time.c000066400000000000000000000040101342142174400203200ustar00rootroot00000000000000/* Licensed under BSD-MIT - see LICENSE file for details */ #include #include #include struct timeval time_now(void) { struct timeval now; gettimeofday(&now, NULL); return now; } bool time_greater(struct timeval a, struct timeval b) { if (a.tv_sec > b.tv_sec) return true; else if (a.tv_sec < b.tv_sec) return false; return a.tv_usec > b.tv_usec; } bool time_less(struct timeval a, struct timeval b) { if (a.tv_sec < b.tv_sec) return true; else if (a.tv_sec > b.tv_sec) return false; return a.tv_usec < b.tv_usec; } bool time_eq(struct timeval a, struct timeval b) { return a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec; } struct timeval time_sub(struct timeval recent, struct timeval old) { struct timeval diff; diff.tv_sec = recent.tv_sec - old.tv_sec; if (old.tv_usec > recent.tv_usec) { diff.tv_sec--; diff.tv_usec = 1000000 + recent.tv_usec - old.tv_usec; } else diff.tv_usec = recent.tv_usec - old.tv_usec; assert(diff.tv_sec >= 0); return diff; } struct timeval time_add(struct timeval a, struct timeval b) { struct timeval sum; sum.tv_sec = a.tv_sec + b.tv_sec; sum.tv_usec = a.tv_usec + b.tv_usec; if (sum.tv_usec > 1000000) { sum.tv_sec++; sum.tv_usec -= 1000000; } return sum; } struct timeval time_divide(struct timeval t, unsigned long div) { return time_from_usec(time_to_usec(t) / div); } struct timeval time_multiply(struct timeval t, unsigned long mult) { return time_from_usec(time_to_usec(t) * mult); } uint64_t time_to_msec(struct timeval t) { uint64_t msec; msec = t.tv_usec / 1000 + (uint64_t)t.tv_sec * 1000; return msec; } uint64_t time_to_usec(struct timeval t) { uint64_t usec; usec = t.tv_usec + (uint64_t)t.tv_sec * 1000000; return usec; } struct timeval time_from_msec(uint64_t msec) { struct timeval t; t.tv_usec = (msec % 1000) * 1000; t.tv_sec = msec / 1000; return t; } struct timeval time_from_usec(uint64_t usec) { struct timeval t; t.tv_usec = usec % 1000000; t.tv_sec = usec / 1000000; return t; } sbsigntool-0.9.2/lib/ccan/ccan/time/time.h000066400000000000000000000101601342142174400203300ustar00rootroot00000000000000/* Licensed under BSD-MIT - see LICENSE file for details */ #ifndef CCAN_TIME_H #define CCAN_TIME_H #include "config.h" #include #include #include /** * time_now - return the current time * * Example: * printf("Now is %lu seconds since epoch\n", (long)time_now().tv_sec); */ struct timeval time_now(void); /** * time_greater - is a after b? * @a: one time. * @b: another time. * * Example: * static bool timed_out(const struct timeval *start) * { * #define TIMEOUT time_from_msec(1000) * return time_greater(time_now(), time_add(*start, TIMEOUT)); * } */ bool time_greater(struct timeval a, struct timeval b); /** * time_less - is a before b? * @a: one time. * @b: another time. * * Example: * static bool still_valid(const struct timeval *start) * { * #define TIMEOUT time_from_msec(1000) * return time_less(time_now(), time_add(*start, TIMEOUT)); * } */ bool time_less(struct timeval a, struct timeval b); /** * time_eq - is a equal to b? * @a: one time. * @b: another time. * * Example: * #include * #include * * // Can we fork in under a microsecond? * static bool fast_fork(void) * { * struct timeval start = time_now(); * if (fork() != 0) { * exit(0); * } * wait(NULL); * return time_eq(start, time_now()); * } */ bool time_eq(struct timeval a, struct timeval b); /** * time_sub - subtract two times * @recent: the larger (more recent) time. * @old: the smaller (less recent) time. * * This returns a well formed struct timeval. * * Example: * static bool was_recent(const struct timeval *start) * { * return time_sub(time_now(), *start).tv_sec < 1; * } */ struct timeval time_sub(struct timeval recent, struct timeval old); /** * time_add - add two times * @a: one time. * @b: another time. * * The times must not overflow, or the results are undefined. * * Example: * // We do one every second. * static struct timeval next_time(void) * { * return time_add(time_now(), time_from_msec(1000)); * } */ struct timeval time_add(struct timeval a, struct timeval b); /** * time_divide - divide a time by a value. * @t: a time. * @div: number to divide it by. * * Example: * // How long does it take to do a fork? * static struct timeval forking_time(void) * { * struct timeval start = time_now(); * unsigned int i; * * for (i = 0; i < 1000; i++) { * if (fork() != 0) { * exit(0); * } * wait(NULL); * } * return time_divide(time_sub(time_now(), start), i); * } */ struct timeval time_divide(struct timeval t, unsigned long div); /** * time_multiply - multiply a time by a value. * @t: a time. * @mult: number to multiply it by. * * Example: * ... * printf("Time to do 100000 forks would be %u sec\n", * (unsigned)time_multiply(forking_time(), 1000000).tv_sec); */ struct timeval time_multiply(struct timeval t, unsigned long mult); /** * time_to_msec - return number of milliseconds * @t: a time * * It's often more convenient to deal with time values as * milliseconds. Note that this will fit into a 32-bit variable if * it's a time difference of less than ~7 weeks. * * Example: * ... * printf("Forking time is %u msec\n", * (unsigned)time_to_msec(forking_time())); */ uint64_t time_to_msec(struct timeval t); /** * time_to_usec - return number of microseconds * @t: a time * * It's often more convenient to deal with time values as * microseconds. Note that this will fit into a 32-bit variable if * it's a time difference of less than ~1 hour. * * Example: * ... * printf("Forking time is %u usec\n", * (unsigned)time_to_usec(forking_time())); * */ uint64_t time_to_usec(struct timeval t); /** * time_from_msec - convert milliseconds to a timeval * @msec: time in milliseconds * * Example: * // 1/2 second timeout * #define TIMEOUT time_from_msec(500) */ struct timeval time_from_msec(uint64_t msec); /** * time_from_usec - convert microseconds to a timeval * @usec: time in microseconds * * Example: * // 1/2 second timeout * #define TIMEOUT time_from_usec(500000) */ struct timeval time_from_usec(uint64_t usec); #endif /* CCAN_TIME_H */ sbsigntool-0.9.2/lib/ccan/ccan/tlist/000077500000000000000000000000001342142174400174245ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/tlist/LICENSE000077700000000000000000000000001342142174400235002../../licenses/LGPL-3ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/tlist/tlist.h000066400000000000000000000166141342142174400207440ustar00rootroot00000000000000/* Licensed under LGPL - see LICENSE file for details */ #ifndef CCAN_TLIST_H #define CCAN_TLIST_H #include #include /** * TLIST_TYPE - declare a typed list type (struct tlist) * @suffix: the name to use (struct tlist_@suffix) * @type: the type the list will contain (void for any type) * * This declares a structure "struct tlist_@suffix" to use for * lists containing this type. The actual list can be accessed using * ".raw" or tlist_raw(). * * Example: * // Defines struct tlist_children * TLIST_TYPE(children, struct child); * struct parent { * const char *name; * struct tlist_children children; * unsigned int num_children; * }; * * struct child { * const char *name; * struct list_node list; * }; */ #define TLIST_TYPE(suffix, type) \ struct tlist_##suffix { \ struct list_head raw; \ TCON(type *canary); \ } /** * TLIST_INIT - initalizer for an empty tlist * @name: the name of the list. * * Explicit initializer for an empty list. * * See also: * tlist_init() * * Example: * static struct tlist_children my_list = TLIST_INIT(my_list); */ #define TLIST_INIT(name) { LIST_HEAD_INIT(name.raw) } /** * tlist_check - check head of a list for consistency * @h: the tlist_head * @abortstr: the location to print on aborting, or NULL. * * Because list_nodes have redundant information, consistency checking between * the back and forward links can be done. This is useful as a debugging check. * If @abortstr is non-NULL, that will be printed in a diagnostic if the list * is inconsistent, and the function will abort. * * Returns non-NULL if the list is consistent, NULL otherwise (it * can never return NULL if @abortstr is set). * * See also: list_check() * * Example: * static void dump_parent(struct parent *p) * { * struct child *c; * * printf("%s (%u children):\n", p->name, p->num_children); * tlist_check(&p->children, "bad child list"); * tlist_for_each(&p->children, c, list) * printf(" -> %s\n", c->name); * } */ #define tlist_check(h, abortstr) \ list_check(&(h)->raw, (abortstr)) /** * tlist_init - initialize a tlist * @h: the tlist to set to the empty list * * Example: * ... * struct parent *parent = malloc(sizeof(*parent)); * * tlist_init(&parent->children); * parent->num_children = 0; */ #define tlist_init(h) list_head_init(&(h)->raw) /** * tlist_raw - unwrap the typed list and check the type * @h: the tlist * @expr: the expression to check the type against (not evaluated) * * This macro usually causes the compiler to emit a warning if the * variable is of an unexpected type. It is used internally where we * need to access the raw underlying list. */ #define tlist_raw(h, expr) (&tcon_check((h), canary, (expr))->raw) /** * tlist_add - add an entry at the start of a linked list. * @h: the tlist to add the node to * @n: the entry to add to the list. * @member: the member of n to add to the list. * * The entry's list_node does not need to be initialized; it will be * overwritten. * Example: * struct child *child = malloc(sizeof(*child)); * * child->name = "marvin"; * tlist_add(&parent->children, child, list); * parent->num_children++; */ #define tlist_add(h, n, member) list_add(tlist_raw((h), (n)), &(n)->member) /** * tlist_add_tail - add an entry at the end of a linked list. * @h: the tlist to add the node to * @n: the entry to add to the list. * @member: the member of n to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * tlist_add_tail(&parent->children, child, list); * parent->num_children++; */ #define tlist_add_tail(h, n, member) \ list_add_tail(tlist_raw((h), (n)), &(n)->member) /** * tlist_del_from - delete an entry from a linked list. * @h: the tlist @n is in * @n: the entry to delete * @member: the member of n to remove from the list. * * This explicitly indicates which list a node is expected to be in, * which is better documentation and can catch more bugs. * * Note that this leaves @n->@member in an undefined state; it * can be added to another list, but not deleted again. * * See also: tlist_del() * * Example: * tlist_del_from(&parent->children, child, list); * parent->num_children--; */ #define tlist_del_from(h, n, member) \ list_del_from(tlist_raw((h), (n)), &(n)->member) /** * tlist_del - delete an entry from an unknown linked list. * @n: the entry to delete from the list. * @member: the member of @n which is in the list. * * Example: * tlist_del(child, list); * parent->num_children--; */ #define tlist_del(n, member) \ list_del(&(n)->member) /** * tlist_empty - is a list empty? * @h: the tlist * * If the list is empty, returns true. * * Example: * assert(tlist_empty(&parent->children) == (parent->num_children == 0)); */ #define tlist_empty(h) list_empty(&(h)->raw) /** * tlist_top - get the first entry in a list * @h: the tlist * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *first; * first = tlist_top(&parent->children, list); */ #define tlist_top(h, member) \ ((tcon_type((h), canary)) \ list_top_(&(h)->raw, \ (char *)(&(h)->_tcon[0].canary->member) - \ (char *)((h)->_tcon[0].canary))) /** * tlist_tail - get the last entry in a list * @h: the tlist * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *last; * last = tlist_tail(&parent->children, list); */ #define tlist_tail(h, member) \ ((tcon_type((h), canary)) \ list_tail_(&(h)->raw, \ (char *)(&(h)->_tcon[0].canary->member) - \ (char *)((h)->_tcon[0].canary))) /** * tlist_for_each - iterate through a list. * @h: the tlist * @i: an iterator of suitable type for this list. * @member: the list_node member of @i * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * tlist_for_each(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define tlist_for_each(h, i, member) \ list_for_each(tlist_raw((h), (i)), (i), member) /** * tlist_for_each - iterate through a list backwards. * @h: the tlist * @i: an iterator of suitable type for this list. * @member: the list_node member of @i * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * tlist_for_each_rev(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define tlist_for_each_rev(h, i, member) \ list_for_each_rev(tlist_raw((h), (i)), (i), member) /** * tlist_for_each_safe - iterate through a list, maybe during deletion * @h: the tlist * @i: an iterator of suitable type for this list. * @nxt: another iterator to store the next entry. * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. The extra variable * @nxt is used to hold the next element, so you can delete @i from the list. * * Example: * struct child *next; * tlist_for_each_safe(&parent->children, child, next, list) { * tlist_del(child, list); * parent->num_children--; * } */ #define tlist_for_each_safe(h, i, nxt, member) \ list_for_each_safe(tlist_raw((h), (i)), (i), (nxt), member) #endif /* CCAN_TLIST_H */ sbsigntool-0.9.2/lib/ccan/ccan/typesafe_cb/000077500000000000000000000000001342142174400205515ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/typesafe_cb/LICENSE000077700000000000000000000000001342142174400247632../../licenses/LGPL-2.1ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/ccan/typesafe_cb/typesafe_cb.h000066400000000000000000000116401342142174400232100ustar00rootroot00000000000000/* Licensed under LGPLv2.1+ - see LICENSE file for details */ #ifndef CCAN_TYPESAFE_CB_H #define CCAN_TYPESAFE_CB_H #include "config.h" #if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P /** * typesafe_cb_cast - only cast an expression if it matches a given type * @desttype: the type to cast to * @oktype: the type we allow * @expr: the expression to cast * * This macro is used to create functions which allow multiple types. * The result of this macro is used somewhere that a @desttype type is * expected: if @expr is exactly of type @oktype, then it will be * cast to @desttype type, otherwise left alone. * * This macro can be used in static initializers. * * This is merely useful for warnings: if the compiler does not * support the primitives required for typesafe_cb_cast(), it becomes an * unconditional cast, and the @oktype argument is not used. In * particular, this means that @oktype can be a type which uses the * "typeof": it will not be evaluated if typeof is not supported. * * Example: * // We can take either an unsigned long or a void *. * void _set_some_value(void *val); * #define set_some_value(e) \ * _set_some_value(typesafe_cb_cast(void *, (e), unsigned long)) */ #define typesafe_cb_cast(desttype, oktype, expr) \ __builtin_choose_expr( \ __builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \ oktype), \ (desttype)(expr), (expr)) #else #define typesafe_cb_cast(desttype, oktype, expr) ((desttype)(expr)) #endif /** * typesafe_cb_cast3 - only cast an expression if it matches given types * @desttype: the type to cast to * @ok1: the first type we allow * @ok2: the second type we allow * @ok3: the third type we allow * @expr: the expression to cast * * This is a convenient wrapper for multiple typesafe_cb_cast() calls. * You can chain them inside each other (ie. use typesafe_cb_cast() * for expr) if you need more than 3 arguments. * * Example: * // We can take either a long, unsigned long, void * or a const void *. * void _set_some_value(void *val); * #define set_some_value(expr) \ * _set_some_value(typesafe_cb_cast3(void *,, \ * long, unsigned long, const void *,\ * (expr))) */ #define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr) \ typesafe_cb_cast(desttype, ok1, \ typesafe_cb_cast(desttype, ok2, \ typesafe_cb_cast(desttype, ok3, \ (expr)))) /** * typesafe_cb - cast a callback function if it matches the arg * @rtype: the return type of the callback function * @atype: the (pointer) type which the callback function expects. * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * * If a callback function takes a single argument, this macro does * appropriate casts to a function which takes a single atype argument if the * callback provided matches the @arg. * * It is assumed that @arg is of pointer type: usually @arg is passed * or assigned to a void * elsewhere anyway. * * Example: * void _register_callback(void (*fn)(void *arg), void *arg); * #define register_callback(fn, arg) \ * _register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg)) */ #define typesafe_cb(rtype, atype, fn, arg) \ typesafe_cb_cast(rtype (*)(atype), \ rtype (*)(__typeof__(arg)), \ (fn)) /** * typesafe_cb_preargs - cast a callback function if it matches the arg * @rtype: the return type of the callback function * @atype: the (pointer) type which the callback function expects. * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * * This is a version of typesafe_cb() for callbacks that take other arguments * before the @arg. * * Example: * void _register_callback(void (*fn)(int, void *arg), void *arg); * #define register_callback(fn, arg) \ * _register_callback(typesafe_cb_preargs(void, void *, \ * (fn), (arg), int), \ * (arg)) */ #define typesafe_cb_preargs(rtype, atype, fn, arg, ...) \ typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype), \ rtype (*)(__VA_ARGS__, __typeof__(arg)), \ (fn)) /** * typesafe_cb_postargs - cast a callback function if it matches the arg * @rtype: the return type of the callback function * @atype: the (pointer) type which the callback function expects. * @fn: the callback function to cast * @arg: the (pointer) argument to hand to the callback function. * * This is a version of typesafe_cb() for callbacks that take other arguments * after the @arg. * * Example: * void _register_callback(void (*fn)(void *arg, int), void *arg); * #define register_callback(fn, arg) \ * _register_callback(typesafe_cb_postargs(void, (fn), void *, \ * (arg), int), \ * (arg)) */ #define typesafe_cb_postargs(rtype, atype, fn, arg, ...) \ typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__), \ rtype (*)(__typeof__(arg), __VA_ARGS__), \ (fn)) #endif /* CCAN_CAST_IF_TYPE_H */ sbsigntool-0.9.2/lib/ccan/licenses/000077500000000000000000000000001342142174400171665ustar00rootroot00000000000000sbsigntool-0.9.2/lib/ccan/licenses/BSD-MIT000066400000000000000000000017771342142174400201640ustar00rootroot00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sbsigntool-0.9.2/lib/ccan/licenses/LGPL-2.1000066400000000000000000000636371342142174400201640ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! sbsigntool-0.9.2/lib/ccan/licenses/LGPL-3000066400000000000000000000167271342142174400200240ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser 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 Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. sbsigntool-0.9.2/src/000077500000000000000000000000001342142174400144765ustar00rootroot00000000000000sbsigntool-0.9.2/src/Makefile.am000066400000000000000000000024121342142174400165310ustar00rootroot00000000000000 bin_PROGRAMS = sbsign sbverify sbattach sbvarsign sbsiglist sbkeysync coff_headers = coff/external.h coff/pe.h AM_CFLAGS = -Wall -Wextra --std=gnu99 common_SOURCES = idc.c idc.h image.c image.h fileio.c fileio.h \ efivars.h $(coff_headers) common_LDADD = ../lib/ccan/libccan.a $(libcrypto_LIBS) common_CFLAGS = -I$(top_srcdir)/lib/ccan/ sbsign_SOURCES = sbsign.c $(common_SOURCES) sbsign_LDADD = $(common_LDADD) sbsign_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) sbverify_SOURCES = sbverify.c $(common_SOURCES) sbverify_LDADD = $(common_LDADD) sbverify_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) sbattach_SOURCES = sbattach.c $(common_SOURCES) sbattach_LDADD = $(common_LDADD) sbattach_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) sbvarsign_SOURCES = sbvarsign.c $(common_SOURCES) sbvarsign_LDADD = $(common_LDADD) $(uuid_LIBS) sbvarsign_CPPFLAGS = $(EFI_CPPFLAGS) sbvarsign_CFLAGS = $(AM_CFLAGS) $(uuid_CFLAGS) $(common_CFLAGS) sbsiglist_SOURCES = sbsiglist.c $(common_SOURCES) sbsiglist_LDADD = $(common_LDADD) $(uuid_LIBS) sbsiglist_CPPFLAGS = $(EFI_CPPFLAGS) sbsiglist_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) sbkeysync_SOURCES = sbkeysync.c $(common_SOURCES) sbkeysync_LDADD = $(common_LDADD) $(uuid_LIBS) sbkeysync_CPPFLAGS = $(EFI_CPPFLAGS) sbkeysync_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) sbsigntool-0.9.2/src/coff/000077500000000000000000000000001342142174400154135ustar00rootroot00000000000000sbsigntool-0.9.2/src/coff/external.h000066400000000000000000000154261342142174400174160ustar00rootroot00000000000000/* external.h -- External COFF structures Copyright 2001, 2006, 2010 Free Software Foundation, Inc. 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 3 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. */ #ifndef COFF_EXTERNAL_H #define COFF_EXTERNAL_H #ifndef DO_NOT_DEFINE_FILHDR /********************** FILE HEADER **********************/ struct external_filehdr { char f_magic[2]; /* magic number */ char f_nscns[2]; /* number of sections */ char f_timdat[4]; /* time & date stamp */ char f_symptr[4]; /* file pointer to symtab */ char f_nsyms[4]; /* number of symtab entries */ char f_opthdr[2]; /* sizeof(optional hdr) */ char f_flags[2]; /* flags */ }; #define FILHDR struct external_filehdr #define FILHSZ 20 #endif #ifndef DO_NOT_DEFINE_AOUTHDR /********************** AOUT "OPTIONAL HEADER" **********************/ typedef struct external_aouthdr { char magic[2]; /* type of file */ char vstamp[2]; /* version stamp */ char tsize[4]; /* text size in bytes, padded to FW bdry*/ char dsize[4]; /* initialized data " " */ char bsize[4]; /* uninitialized data " " */ char entry[4]; /* entry pt. */ char text_start[4]; /* base of text used for this file */ char data_start[4]; /* base of data used for this file */ } ATTRIBUTE_PACKED AOUTHDR; #define AOUTHDRSZ 28 #define AOUTSZ 28 typedef struct external_aouthdr64 { char magic[2]; /* Type of file. */ char vstamp[2]; /* Version stamp. */ char tsize[4]; /* Text size in bytes, padded to FW bdry*/ char dsize[4]; /* Initialized data " ". */ char bsize[4]; /* Uninitialized data " ". */ char entry[4]; /* Entry pt. */ char text_start[4]; /* Base of text used for this file. */ } AOUTHDR64; #define AOUTHDRSZ64 24 #endif /* not DO_NOT_DEFINE_AOUTHDR */ #ifndef DO_NOT_DEFINE_SCNHDR /********************** SECTION HEADER **********************/ struct external_scnhdr { char s_name[8]; /* section name */ char s_paddr[4]; /* physical address, aliased s_nlib */ char s_vaddr[4]; /* virtual address */ char s_size[4]; /* section size */ char s_scnptr[4]; /* file ptr to raw data for section */ char s_relptr[4]; /* file ptr to relocation */ char s_lnnoptr[4]; /* file ptr to line numbers */ char s_nreloc[2]; /* number of relocation entries */ char s_nlnno[2]; /* number of line number entries */ char s_flags[4]; /* flags */ }; #define SCNHDR struct external_scnhdr #define SCNHSZ 40 /* Names of "special" sections. */ #define _TEXT ".text" #define _DATA ".data" #define _BSS ".bss" #define _COMMENT ".comment" #define _LIB ".lib" #endif /* not DO_NOT_DEFINE_SCNHDR */ #ifndef DO_NOT_DEFINE_LINENO /********************** LINE NUMBERS **********************/ #ifndef L_LNNO_SIZE #error L_LNNO_SIZE needs to be defined #endif /* 1 line number entry for every "breakpointable" source line in a section. Line numbers are grouped on a per function basis; first entry in a function grouping will have l_lnno = 0 and in place of physical address will be the symbol table index of the function name. */ struct external_lineno { union { char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ char l_paddr[4]; /* (physical) address of line number */ } l_addr; char l_lnno[L_LNNO_SIZE]; /* line number */ }; #define LINENO struct external_lineno #define LINESZ (4 + L_LNNO_SIZE) #if L_LNNO_SIZE == 4 #define GET_LINENO_LNNO(abfd, ext) H_GET_32 (abfd, (ext->l_lnno)) #define PUT_LINENO_LNNO(abfd, val, ext) H_PUT_32 (abfd, val, (ext->l_lnno)) #endif #if L_LNNO_SIZE == 2 #define GET_LINENO_LNNO(abfd, ext) H_GET_16 (abfd, (ext->l_lnno)) #define PUT_LINENO_LNNO(abfd, val, ext) H_PUT_16 (abfd, val, (ext->l_lnno)) #endif #endif /* not DO_NOT_DEFINE_LINENO */ #ifndef DO_NOT_DEFINE_SYMENT /********************** SYMBOLS **********************/ #define E_SYMNMLEN 8 /* # characters in a symbol name */ #ifndef E_FILNMLEN #define E_FILNMLEN 14 #endif #define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ struct external_syment { union { char e_name[E_SYMNMLEN]; struct { char e_zeroes[4]; char e_offset[4]; } e; } e; char e_value[4]; char e_scnum[2]; char e_type[2]; char e_sclass[1]; char e_numaux[1]; } ATTRIBUTE_PACKED ; #define SYMENT struct external_syment #define SYMESZ 18 #ifndef N_BTMASK #define N_BTMASK 0xf #endif #ifndef N_TMASK #define N_TMASK 0x30 #endif #ifndef N_BTSHFT #define N_BTSHFT 4 #endif #ifndef N_TSHIFT #define N_TSHIFT 2 #endif #endif /* not DO_NOT_DEFINE_SYMENT */ #ifndef DO_NOT_DEFINE_AUXENT union external_auxent { struct { char x_tagndx[4]; /* str, un, or enum tag indx */ union { struct { char x_lnno[2]; /* declaration line number */ char x_size[2]; /* str/union/array size */ } x_lnsz; char x_fsize[4]; /* size of function */ } x_misc; union { struct /* if ISFCN, tag, or .bb */ { char x_lnnoptr[4]; /* ptr to fcn line # */ char x_endndx[4]; /* entry ndx past block end */ } x_fcn; struct /* if ISARY, up to 4 dimen. */ { char x_dimen[E_DIMNUM][2]; } x_ary; } x_fcnary; char x_tvndx[2]; /* tv index */ } x_sym; union { char x_fname[E_FILNMLEN]; struct { char x_zeroes[4]; char x_offset[4]; } x_n; } x_file; struct { char x_scnlen[4]; /* section length */ char x_nreloc[2]; /* # relocation entries */ char x_nlinno[2]; /* # line numbers */ #ifdef INCLUDE_COMDAT_FIELDS_IN_AUXENT char x_checksum[4]; /* section COMDAT checksum */ char x_associated[2]; /* COMDAT associated section index */ char x_comdat[1]; /* COMDAT selection number */ #endif } x_scn; struct { char x_tvfill[4]; /* tv fill value */ char x_tvlen[2]; /* length of .tv */ char x_tvran[2][2]; /* tv range */ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ } ATTRIBUTE_PACKED ; #define AUXENT union external_auxent #define AUXESZ 18 #define _ETEXT "etext" #endif /* not DO_NOT_DEFINE_AUXENT */ #endif /* COFF_EXTERNAL_H */ sbsigntool-0.9.2/src/coff/pe.h000066400000000000000000000457531342142174400162060ustar00rootroot00000000000000/* pe.h - PE COFF header information Copyright 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. 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 3 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. */ #ifndef _PE_H #define _PE_H /* NT specific file attributes. */ #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 #define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010 #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 #define IMAGE_FILE_16BIT_MACHINE 0x0040 #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 #define IMAGE_FILE_32BIT_MACHINE 0x0100 #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 #define IMAGE_FILE_SYSTEM 0x1000 #define IMAGE_FILE_DLL 0x2000 #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 /* DllCharacteristics flag bits. The inconsistent naming may seem odd, but that is how they are defined in the PE specification. */ #define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040 #define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080 #define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100 #define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 #define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 /* Additional flags to be set for section headers to allow the NT loader to read and write to the section data (to replace the addresses of data in dlls for one thing); also to execute the section in .text's case. */ #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 #define IMAGE_SCN_MEM_EXECUTE 0x20000000 #define IMAGE_SCN_MEM_READ 0x40000000 #define IMAGE_SCN_MEM_WRITE 0x80000000 /* Section characteristics added for ppc-nt. */ #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */ #define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */ #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */ #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */ #define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */ #define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */ #define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */ #define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */ #define IMAGE_SCN_MEM_FARDATA 0x00008000 #define IMAGE_SCN_MEM_PURGEABLE 0x00020000 #define IMAGE_SCN_MEM_16BIT 0x00020000 #define IMAGE_SCN_MEM_LOCKED 0x00040000 #define IMAGE_SCN_MEM_PRELOAD 0x00080000 /* Bit position in the s_flags field where the alignment values start. */ #define IMAGE_SCN_ALIGN_POWER_BIT_POS 20 #define IMAGE_SCN_ALIGN_POWER_BIT_MASK 0x00f00000 #define IMAGE_SCN_ALIGN_POWER_NUM(val) \ (((val) >> IMAGE_SCN_ALIGN_POWER_BIT_POS) - 1) #define IMAGE_SCN_ALIGN_POWER_CONST(val) \ (((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS) #define IMAGE_SCN_ALIGN_1BYTES IMAGE_SCN_ALIGN_POWER_CONST (0) #define IMAGE_SCN_ALIGN_2BYTES IMAGE_SCN_ALIGN_POWER_CONST (1) #define IMAGE_SCN_ALIGN_4BYTES IMAGE_SCN_ALIGN_POWER_CONST (2) #define IMAGE_SCN_ALIGN_8BYTES IMAGE_SCN_ALIGN_POWER_CONST (3) /* Default alignment if no others are specified. */ #define IMAGE_SCN_ALIGN_16BYTES IMAGE_SCN_ALIGN_POWER_CONST (4) #define IMAGE_SCN_ALIGN_32BYTES IMAGE_SCN_ALIGN_POWER_CONST (5) #define IMAGE_SCN_ALIGN_64BYTES IMAGE_SCN_ALIGN_POWER_CONST (6) #define IMAGE_SCN_ALIGN_128BYTES IMAGE_SCN_ALIGN_POWER_CONST (7) #define IMAGE_SCN_ALIGN_256BYTES IMAGE_SCN_ALIGN_POWER_CONST (8) #define IMAGE_SCN_ALIGN_512BYTES IMAGE_SCN_ALIGN_POWER_CONST (9) #define IMAGE_SCN_ALIGN_1024BYTES IMAGE_SCN_ALIGN_POWER_CONST (10) #define IMAGE_SCN_ALIGN_2048BYTES IMAGE_SCN_ALIGN_POWER_CONST (11) #define IMAGE_SCN_ALIGN_4096BYTES IMAGE_SCN_ALIGN_POWER_CONST (12) #define IMAGE_SCN_ALIGN_8192BYTES IMAGE_SCN_ALIGN_POWER_CONST (13) /* Encode alignment power into IMAGE_SCN_ALIGN bits of s_flags */ #define COFF_ENCODE_ALIGNMENT(SECTION, ALIGNMENT_POWER) \ ((SECTION).s_flags |= IMAGE_SCN_ALIGN_POWER_CONST ((ALIGNMENT_POWER))) #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */ #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */ #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */ #define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */ /* COMDAT selection codes. */ #define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */ #define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */ #define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */ #define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */ #define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */ /* Machine numbers. */ #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 #define IMAGE_FILE_MACHINE_ALPHA 0x0184 #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 #define IMAGE_FILE_MACHINE_AM33 0x01d3 #define IMAGE_FILE_MACHINE_AMD64 0x8664 #define IMAGE_FILE_MACHINE_ARM 0x01c0 #define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 #define IMAGE_FILE_MACHINE_CEE 0xc0ee #define IMAGE_FILE_MACHINE_CEF 0x0cef #define IMAGE_FILE_MACHINE_EBC 0x0ebc #define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_MACHINE_IA64 0x0200 #define IMAGE_FILE_MACHINE_M32R 0x9041 #define IMAGE_FILE_MACHINE_M68K 0x0268 #define IMAGE_FILE_MACHINE_MIPS16 0x0266 #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 #define IMAGE_FILE_MACHINE_R10000 0x0168 #define IMAGE_FILE_MACHINE_R3000 0x0162 #define IMAGE_FILE_MACHINE_R4000 0x0166 #define IMAGE_FILE_MACHINE_SH3 0x01a2 #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 #define IMAGE_FILE_MACHINE_SH3E 0x01a4 #define IMAGE_FILE_MACHINE_SH4 0x01a6 #define IMAGE_FILE_MACHINE_SH5 0x01a8 #define IMAGE_FILE_MACHINE_THUMB 0x01c2 #define IMAGE_FILE_MACHINE_TRICORE 0x0520 #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 #define IMAGE_FILE_MACHINE_AARCH64 0xaa64 #define IMAGE_SUBSYSTEM_UNKNOWN 0 #define IMAGE_SUBSYSTEM_NATIVE 1 #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 #define IMAGE_SUBSYSTEM_POSIX_CUI 7 #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 #define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 #define IMAGE_SUBSYSTEM_XBOX 14 /* Magic values that are true for all dos/nt implementations. */ #define DOSMAGIC 0x5a4d #define NT_SIGNATURE 0x00004550 /* NT allows long filenames, we want to accommodate this. This may break some of the bfd functions. */ #undef FILNMLEN #define FILNMLEN 18 /* # characters in a file name. */ struct external_PEI_DOS_hdr { /* DOS header fields - always at offset zero in the EXE file. */ char e_magic[2]; /* Magic number, 0x5a4d. */ char e_cblp[2]; /* Bytes on last page of file, 0x90. */ char e_cp[2]; /* Pages in file, 0x3. */ char e_crlc[2]; /* Relocations, 0x0. */ char e_cparhdr[2]; /* Size of header in paragraphs, 0x4. */ char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0. */ char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF. */ char e_ss[2]; /* Initial (relative) SS value, 0x0. */ char e_sp[2]; /* Initial SP value, 0xb8. */ char e_csum[2]; /* Checksum, 0x0. */ char e_ip[2]; /* Initial IP value, 0x0. */ char e_cs[2]; /* Initial (relative) CS value, 0x0. */ char e_lfarlc[2]; /* File address of relocation table, 0x40. */ char e_ovno[2]; /* Overlay number, 0x0. */ char e_res[4][2]; /* Reserved words, all 0x0. */ char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0. */ char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0. */ char e_res2[10][2]; /* Reserved words, all 0x0. */ char e_lfanew[4]; /* File address of new exe header, usually 0x80. */ char dos_message[16][4]; /* Other stuff, always follow DOS header. */ }; struct external_PEI_IMAGE_hdr { char nt_signature[4]; /* required NT signature, 0x4550. */ /* From standard header. */ char f_magic[2]; /* Magic number. */ char f_nscns[2]; /* Number of sections. */ char f_timdat[4]; /* Time & date stamp. */ char f_symptr[4]; /* File pointer to symtab. */ char f_nsyms[4]; /* Number of symtab entries. */ char f_opthdr[2]; /* Sizeof(optional hdr). */ char f_flags[2]; /* Flags. */ }; struct external_PEI_filehdr { /* DOS header fields - always at offset zero in the EXE file. */ char e_magic[2]; /* Magic number, 0x5a4d. */ char e_cblp[2]; /* Bytes on last page of file, 0x90. */ char e_cp[2]; /* Pages in file, 0x3. */ char e_crlc[2]; /* Relocations, 0x0. */ char e_cparhdr[2]; /* Size of header in paragraphs, 0x4. */ char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0. */ char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF. */ char e_ss[2]; /* Initial (relative) SS value, 0x0. */ char e_sp[2]; /* Initial SP value, 0xb8. */ char e_csum[2]; /* Checksum, 0x0. */ char e_ip[2]; /* Initial IP value, 0x0. */ char e_cs[2]; /* Initial (relative) CS value, 0x0. */ char e_lfarlc[2]; /* File address of relocation table, 0x40. */ char e_ovno[2]; /* Overlay number, 0x0. */ char e_res[4][2]; /* Reserved words, all 0x0. */ char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0. */ char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0. */ char e_res2[10][2]; /* Reserved words, all 0x0. */ char e_lfanew[4]; /* File address of new exe header, usually 0x80. */ char dos_message[16][4]; /* Other stuff, always follow DOS header. */ /* Note: additional bytes may be inserted before the signature. Use the e_lfanew field to find the actual location of the NT signature. */ char nt_signature[4]; /* required NT signature, 0x4550. */ /* From standard header. */ char f_magic[2]; /* Magic number. */ char f_nscns[2]; /* Number of sections. */ char f_timdat[4]; /* Time & date stamp. */ char f_symptr[4]; /* File pointer to symtab. */ char f_nsyms[4]; /* Number of symtab entries. */ char f_opthdr[2]; /* Sizeof(optional hdr). */ char f_flags[2]; /* Flags. */ }; #ifdef COFF_IMAGE_WITH_PE /* The filehdr is only weird in images. */ #undef FILHDR #define FILHDR struct external_PEI_filehdr #undef FILHSZ #define FILHSZ 152 #endif /* COFF_IMAGE_WITH_PE */ /* 32-bit PE a.out header: */ typedef struct { AOUTHDR standard; /* NT extra fields; see internal.h for descriptions. */ char ImageBase[4]; char SectionAlignment[4]; char FileAlignment[4]; char MajorOperatingSystemVersion[2]; char MinorOperatingSystemVersion[2]; char MajorImageVersion[2]; char MinorImageVersion[2]; char MajorSubsystemVersion[2]; char MinorSubsystemVersion[2]; char Reserved1[4]; char SizeOfImage[4]; char SizeOfHeaders[4]; char CheckSum[4]; char Subsystem[2]; char DllCharacteristics[2]; char SizeOfStackReserve[4]; char SizeOfStackCommit[4]; char SizeOfHeapReserve[4]; char SizeOfHeapCommit[4]; char LoaderFlags[4]; char NumberOfRvaAndSizes[4]; /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */ } PEAOUTHDR; #undef AOUTSZ #define AOUTSZ (AOUTHDRSZ + 196) /* Like PEAOUTHDR, except that the "standard" member has no BaseOfData (aka data_start) member and that some of the members are 8 instead of just 4 bytes long. */ typedef struct { #ifdef AOUTHDRSZ64 AOUTHDR64 standard; #else AOUTHDR standard; #endif /* NT extra fields; see internal.h for descriptions. */ char ImageBase[8]; char SectionAlignment[4]; char FileAlignment[4]; char MajorOperatingSystemVersion[2]; char MinorOperatingSystemVersion[2]; char MajorImageVersion[2]; char MinorImageVersion[2]; char MajorSubsystemVersion[2]; char MinorSubsystemVersion[2]; char Reserved1[4]; char SizeOfImage[4]; char SizeOfHeaders[4]; char CheckSum[4]; char Subsystem[2]; char DllCharacteristics[2]; char SizeOfStackReserve[8]; char SizeOfStackCommit[8]; char SizeOfHeapReserve[8]; char SizeOfHeapCommit[8]; char LoaderFlags[4]; char NumberOfRvaAndSizes[4]; /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */ } PEPAOUTHDR; #ifdef AOUTHDRSZ64 #define PEPAOUTSZ (AOUTHDRSZ64 + 196 + 5 * 4) /* = 240 */ #else #define PEPAOUTSZ 240 #endif #undef E_FILNMLEN #define E_FILNMLEN 18 /* # characters in a file name. */ /* Import Tyoes fot ILF format object files.. */ #define IMPORT_CODE 0 #define IMPORT_DATA 1 #define IMPORT_CONST 2 /* Import Name Tyoes for ILF format object files. */ #define IMPORT_ORDINAL 0 #define IMPORT_NAME 1 #define IMPORT_NAME_NOPREFIX 2 #define IMPORT_NAME_UNDECORATE 3 /* Weak external characteristics. */ #define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 #define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 #define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 /* .pdata/.xdata defines and structures for x64 PE+ for exception handling. */ /* .pdata in exception directory. */ struct pex64_runtime_function { bfd_vma rva_BeginAddress; bfd_vma rva_EndAddress; bfd_vma rva_UnwindData; unsigned int isChained : 1; }; struct external_pex64_runtime_function { bfd_byte rva_BeginAddress[4]; bfd_byte rva_EndAddress[4]; bfd_byte rva_UnwindData[4]; }; /* If the lowest significant bit is set for rva_UnwindData RVA, it means that the unified RVA points to another pex64_runtime_function that this entry shares the unwind_info block with. */ #define PEX64_IS_RUNTIME_FUNCTION_CHAINED(PTR_RTF) \ (((PTR_RTF)->rva_UnwindData & 1) != 0) #define PEX64_GET_UNWINDDATA_UNIFIED_RVA(PTR_RTF) \ ((PTR_RTF)->rva_UnwindData & ~1) /* The unwind codes. */ #define UWOP_PUSH_NONVOL 0 #define UWOP_ALLOC_LARGE 1 #define UWOP_ALLOC_SMALL 2 #define UWOP_SET_FPREG 3 #define UWOP_SAVE_NONVOL 4 #define UWOP_SAVE_NONVOL_FAR 5 #define UWOP_SAVE_XMM 6 #define UWOP_SAVE_XMM_FAR 7 #define UWOP_SAVE_XMM128 8 #define UWOP_SAVE_XMM128_FAR 9 #define UWOP_PUSH_MACHFRAME 10 struct pex64_unwind_code { bfd_vma prologue_offset; /* Contains Frame offset, or frame allocation size. */ bfd_vma frame_addr; unsigned int uwop_code : 4; /* xmm, mm, or standard register from 0 - 15. */ unsigned int reg : 4; /* Used for UWOP_PUSH_MACHFRAME to indicate optional errorcode stack argument. */ unsigned int has_errorcode : 1; }; struct external_pex64_unwind_code { bfd_byte dta[2]; }; #define PEX64_UNWCODE_CODE(VAL) ((VAL) & 0xf) #define PEX64_UNWCODE_INFO(VAL) (((VAL) >> 4) & 0xf) /* The unwind info. */ #define UNW_FLAG_NHANDLER 0 #define UNW_FLAG_EHANDLER 1 #define UNW_FLAG_UHANDLER 2 #define UNW_FLAG_FHANDLER 3 #define UNW_FLAG_CHAININFO 4 #define UNW_FLAG_MASK 0x1f struct pex64_unwind_info { bfd_vma SizeOfBlock; bfd_byte Version; /* Values from 0 up to 7 are possible. */ bfd_byte Flags; /* Values from 0 up to 31 are possible. */ bfd_vma SizeOfPrologue; bfd_vma CountOfCodes; /* Amount of pex64_unwind_code elements. */ /* 0 = CFA, 1..15 are index of integer registers. */ unsigned int FrameRegister : 4; bfd_vma FrameOffset; bfd_vma sizeofUnwindCodes; bfd_byte *rawUnwindCodes; /* Valid for UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER. */ bfd_vma CountOfScopes; bfd_byte *rawScopeEntries; bfd_vma rva_ExceptionHandler; /* UNW_EHANDLER. */ bfd_vma rva_TerminationHandler; /* UNW_FLAG_UHANDLER. */ bfd_vma rva_FrameHandler; /* UNW_FLAG_FHANDLER. */ bfd_vma FrameHandlerArgument; /* UNW_FLAG_FHANDLER. */ bfd_vma rva_FunctionEntry; /* UNW_FLAG_CHAININFO. */ }; struct external_pex64_unwind_info { bfd_byte Version_Flags; bfd_byte SizeOfPrologue; bfd_byte CountOfCodes; bfd_byte FrameRegisterOffset; /* external_pex64_unwind_code array. */ /* bfd_byte handler[4]; */ /* Optional language specific data. */ }; struct external_pex64_scope { bfd_vma Count; }; struct pex64_scope { bfd_byte Count[4]; }; struct pex64_scope_entry { bfd_vma rva_BeginAddress; bfd_vma rva_EndAddress; bfd_vma rva_HandlerAddress; bfd_vma rva_JumpAddress; }; #define PEX64_SCOPE_ENTRY_SIZE 16 struct external_pex64_scope_entry { bfd_byte rva_BeginAddress[4]; bfd_byte rva_EndAddress[4]; bfd_byte rva_HandlerAddress[4]; bfd_byte rva_JumpAddress[4]; }; #define PEX64_UWI_VERSION(VAL) ((VAL) & 7) #define PEX64_UWI_FLAGS(VAL) (((VAL) >> 3) & 0x1f) #define PEX64_UWI_FRAMEREG(VAL) ((VAL) & 0xf) #define PEX64_UWI_FRAMEOFF(VAL) (((VAL) >> 4) & 0xf) #define PEX64_UWI_SIZEOF_UWCODE_ARRAY(VAL) \ ((((VAL) + 1) & ~1) * 2) #define PEX64_OFFSET_TO_UNWIND_CODE 0x4 #define PEX64_OFFSET_TO_HANDLER_RVA (COUNTOFUNWINDCODES) \ (PEX64_OFFSET_TO_UNWIND_CODE + \ PEX64_UWI_SIZEOF_UWCODE_ARRAY(COUNTOFUNWINDCODES)) #define PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) \ (PEX64_OFFSET_TO_HANDLER_RVA(COUNTOFUNWINDCODES) + 4) #define PEX64_SCOPE_ENTRY(COUNTOFUNWINDCODES, IDX) \ (PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \ PEX64_SCOPE_ENTRY_SIZE * (IDX)) #endif /* _PE_H */ sbsigntool-0.9.2/src/efivars.h000066400000000000000000000062201342142174400163060ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #ifndef EFI_VARAUTH_H #define EFI_VARAUTH_H #include #define EFI_CERT_TYPE_PKCS7_GUID \ { 0x4aafd29d, 0x68df, 0x49ee, \ { 0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7 } } #define EFI_CERT_X509_GUID \ { 0xa5c059a1, 0x94e4, 0x4aa7, \ { 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 } } #define EFI_CERT_SHA256_GUID \ { 0xc1c41626, 0x504c, 0x4092, \ { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } } #define EFI_IMAGE_SECURITY_DATABASE_GUID \ { 0xd719b2cb, 0x3d3a, 0x4596, \ { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f } } #ifndef EFI_VARIABLE_NON_VOLATILE #define EFI_VARIABLE_NON_VOLATILE 0x00000001 #endif #ifndef EFI_VARIABLE_BOOTSERVICE_ACCESS #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 #endif #ifndef EFI_VARIABLE_RUNTIME_ACCESS #define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 #endif #ifndef EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 #endif #ifndef EFI_VARIABLE_APPEND_WRITE #define EFI_VARIABLE_APPEND_WRITE 0x00000040 #endif typedef struct { UINT32 dwLength; UINT16 wRevision; UINT16 wCertificateType; UINT8 bCertificate[]; } WIN_CERTIFICATE; typedef struct { WIN_CERTIFICATE Hdr; EFI_GUID CertType; UINT8 CertData[]; } WIN_CERTIFICATE_UEFI_GUID; typedef struct { EFI_TIME TimeStamp; WIN_CERTIFICATE_UEFI_GUID AuthInfo; } EFI_VARIABLE_AUTHENTICATION_2; typedef struct { EFI_GUID SignatureOwner; UINT8 SignatureData[]; } EFI_SIGNATURE_DATA; typedef struct { EFI_GUID SignatureType; UINT32 SignatureListSize; UINT32 SignatureHeaderSize; UINT32 SignatureSize; } EFI_SIGNATURE_LIST; #endif /* EFI_VARAUTH_H */ sbsigntool-0.9.2/src/fileio.c000066400000000000000000000114471342142174400161200ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #include #include #include #include #include #include #include #include #include #include #include #include "fileio.h" #define FLAG_NOERROR (1<<0) static int ui_read(UI *ui, UI_STRING *uis) { char password[128]; if (UI_get_string_type(uis) != UIT_PROMPT) return 0; EVP_read_pw_string(password, sizeof(password), "Enter engine key pass phrase:", 0); UI_set_result(ui, uis, password); return 1; } EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename) { UI_METHOD *ui; ENGINE *e; EVP_PKEY *pkey = NULL; ENGINE_load_builtin_engines(); e = ENGINE_by_id(engine); if (!e) { fprintf(stderr, "Failed to load engine: %s\n", engine); ERR_print_errors_fp(stderr); return NULL; } ui = UI_create_method("sbsigntools"); if (!ui) { fprintf(stderr, "Failed to create UI method\n"); ERR_print_errors_fp(stderr); goto out_free; } UI_method_set_reader(ui, ui_read); if (!ENGINE_init(e)) { fprintf(stderr, "Failed to initialize engine %s\n", engine); ERR_print_errors_fp(stderr); goto out_free; } pkey = ENGINE_load_private_key(e, filename, ui, NULL); ENGINE_finish(e); out_free: ENGINE_free(e); return pkey; } EVP_PKEY *fileio_read_pkey(const char *filename) { EVP_PKEY *key = NULL; BIO *bio; bio = BIO_new_file(filename, "r"); if (!bio) goto out; key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); out: BIO_free_all(bio); if (!key) { fprintf(stderr, "Can't load key from file '%s'\n", filename); ERR_print_errors_fp(stderr); } return key; } X509 *fileio_read_cert(const char *filename) { X509 *cert = NULL; BIO *bio; bio = BIO_new_file(filename, "r"); if (!bio) goto out; cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); out: BIO_free_all(bio); if (!cert) { fprintf(stderr, "Can't load certificate from file '%s'\n", filename); ERR_print_errors_fp(stderr); } return cert; } static int __fileio_read_file(void *ctx, const char *filename, uint8_t **out_buf, size_t *out_len, int flags) { struct stat statbuf; uint8_t *buf; size_t len; int fd, rc; rc = -1; fd = open(filename, O_RDONLY); if (fd < 0) goto out; rc = fstat(fd, &statbuf); if (rc) goto out; len = statbuf.st_size; buf = talloc_array(ctx, uint8_t, len); if (!buf) goto out; if (!read_all(fd, buf, len)) goto out; rc = 0; out: if (fd >= 0) close(fd); if (rc) { if (!(flags & FLAG_NOERROR)) fprintf(stderr, "Error reading file %s: %s\n", filename, strerror(errno)); } else { *out_buf = buf; *out_len = len; } return rc; } int fileio_read_file(void *ctx, const char *filename, uint8_t **out_buf, size_t *out_len) { return __fileio_read_file(ctx, filename, out_buf, out_len, 0); } int fileio_read_file_noerror(void *ctx, const char *filename, uint8_t **out_buf, size_t *out_len) { return __fileio_read_file(ctx, filename, out_buf, out_len, FLAG_NOERROR); } int fileio_write_file(const char *filename, uint8_t *buf, size_t len) { int fd; fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror("open"); return -1; } if (!write_all(fd, buf, len)) { perror("write_all"); close(fd); return -1; } close(fd); return 0; } sbsigntool-0.9.2/src/fileio.h000066400000000000000000000040661342142174400161240ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #ifndef FILEIO_H #define FILEIO_H #include #include #include EVP_PKEY *fileio_read_pkey(const char *filename); EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename); X509 *fileio_read_cert(const char *filename); int fileio_read_file(void *ctx, const char *filename, uint8_t **out_buf, size_t *out_len); int fileio_read_file_noerror(void *ctx, const char *filename, uint8_t **out_buf, size_t *out_len); int fileio_write_file(const char *filename, uint8_t *buf, size_t len); #endif /* FILEIO_H */ sbsigntool-0.9.2/src/idc.c000066400000000000000000000202171342142174400154030ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #include #include #include #include #include #include #include #include #include "idc.h" typedef struct idc_type_value { ASN1_OBJECT *type; ASN1_TYPE *value; } IDC_TYPE_VALUE; ASN1_SEQUENCE(IDC_TYPE_VALUE) = { ASN1_SIMPLE(IDC_TYPE_VALUE, type, ASN1_OBJECT), ASN1_OPT(IDC_TYPE_VALUE, value, ASN1_ANY), } ASN1_SEQUENCE_END(IDC_TYPE_VALUE); IMPLEMENT_ASN1_FUNCTIONS(IDC_TYPE_VALUE); typedef struct idc_string { int type; union { ASN1_BMPSTRING *unicode; ASN1_IA5STRING *ascii; } value; } IDC_STRING; ASN1_CHOICE(IDC_STRING) = { ASN1_IMP(IDC_STRING, value.unicode, ASN1_BMPSTRING, 0), ASN1_IMP(IDC_STRING, value.ascii, ASN1_IA5STRING, 1), } ASN1_CHOICE_END(IDC_STRING); IMPLEMENT_ASN1_FUNCTIONS(IDC_STRING); typedef struct idc_link { int type; union { ASN1_NULL *url; ASN1_NULL *moniker; IDC_STRING *file; } value; } IDC_LINK; ASN1_CHOICE(IDC_LINK) = { ASN1_IMP(IDC_LINK, value.url, ASN1_NULL, 0), ASN1_IMP(IDC_LINK, value.moniker, ASN1_NULL, 1), ASN1_EXP(IDC_LINK, value.file, IDC_STRING, 2), } ASN1_CHOICE_END(IDC_LINK); IMPLEMENT_ASN1_FUNCTIONS(IDC_LINK); typedef struct idc_pe_image_data { ASN1_BIT_STRING *flags; IDC_LINK *file; } IDC_PEID; ASN1_SEQUENCE(IDC_PEID) = { ASN1_SIMPLE(IDC_PEID, flags, ASN1_BIT_STRING), ASN1_EXP(IDC_PEID, file, IDC_LINK, 0), } ASN1_SEQUENCE_END(IDC_PEID); IMPLEMENT_ASN1_FUNCTIONS(IDC_PEID); typedef struct idc_digest { X509_ALGOR *alg; ASN1_OCTET_STRING *digest; } IDC_DIGEST; ASN1_SEQUENCE(IDC_DIGEST) = { ASN1_SIMPLE(IDC_DIGEST, alg, X509_ALGOR), ASN1_SIMPLE(IDC_DIGEST, digest, ASN1_OCTET_STRING), } ASN1_SEQUENCE_END(IDC_DIGEST) IMPLEMENT_ASN1_FUNCTIONS(IDC_DIGEST) typedef struct idc { IDC_TYPE_VALUE *data; IDC_DIGEST *digest; } IDC; ASN1_SEQUENCE(IDC) = { ASN1_SIMPLE(IDC, data, IDC_TYPE_VALUE), ASN1_SIMPLE(IDC, digest, IDC_DIGEST), } ASN1_SEQUENCE_END(IDC) IMPLEMENT_ASN1_FUNCTIONS(IDC) static int type_set_sequence(void *ctx, ASN1_TYPE *type, void *s, const ASN1_ITEM *it) { uint8_t *seq_data, *tmp; ASN1_OCTET_STRING *os; ASN1_STRING *seq = s; int len; os = ASN1_STRING_new(); len = ASN1_item_i2d((ASN1_VALUE *)seq, NULL, it); tmp = seq_data = talloc_array(ctx, uint8_t, len); ASN1_item_i2d((ASN1_VALUE *)seq, &tmp, it); ASN1_STRING_set(os, seq_data, len); ASN1_TYPE_set(type, V_ASN1_SEQUENCE, os); return 0; } const char obsolete[] = { 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e }; const char *sha256_str(const uint8_t *hash) { static char s[SHA256_DIGEST_LENGTH * 2 + 1]; int i; for (i = 0; i < SHA256_DIGEST_LENGTH; i++) snprintf(s + i * 2, 3, "%02x", hash[i]); return s; } int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image) { uint8_t *buf, *tmp, sha[SHA256_DIGEST_LENGTH]; int idc_nid, peid_nid, len, rc; IDC_PEID *peid; ASN1_STRING *s; ASN1_TYPE *t; BIO *sigbio; IDC *idc; idc_nid = OBJ_create("1.3.6.1.4.1.311.2.1.4", "spcIndirectDataContext", "Indirect Data Context"); peid_nid = OBJ_create("1.3.6.1.4.1.311.2.1.15", "spcPEImageData", "PE Image Data"); image_hash_sha256(image, sha); idc = IDC_new(); peid = IDC_PEID_new(); peid->file = IDC_LINK_new(); peid->file->type = 2; peid->file->value.file = IDC_STRING_new(); peid->file->value.file->type = 0; peid->file->value.file->value.unicode = ASN1_STRING_new(); ASN1_STRING_set(peid->file->value.file->value.unicode, obsolete, sizeof(obsolete)); idc->data->type = OBJ_nid2obj(peid_nid); idc->data->value = ASN1_TYPE_new(); type_set_sequence(image, idc->data->value, peid, &IDC_PEID_it); idc->digest->alg->parameter = ASN1_TYPE_new(); idc->digest->alg->algorithm = OBJ_nid2obj(NID_sha256); idc->digest->alg->parameter->type = V_ASN1_NULL; ASN1_OCTET_STRING_set(idc->digest->digest, sha, sizeof(sha)); len = i2d_IDC(idc, NULL); tmp = buf = talloc_array(image, uint8_t, len); i2d_IDC(idc, &tmp); /* Add the contentType authenticated attribute */ PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(idc_nid)); /* Because the PKCS7 lib has a hard time dealing with non-standard * data types, we create a temporary BIO to hold the signed data, so * that the top-level PKCS7 object calculates the correct hash... */ sigbio = PKCS7_dataInit(p7, NULL); BIO_write(sigbio, buf+2, len-2); /* ... then we finalise the p7 content, which does the actual * signing ... */ rc = PKCS7_dataFinal(p7, sigbio); if (!rc) { fprintf(stderr, "dataFinal failed\n"); ERR_print_errors_fp(stderr); return -1; } /* ... and we replace the content with the actual IDC ASN type. */ t = ASN1_TYPE_new(); s = ASN1_STRING_new(); ASN1_STRING_set(s, buf, len); ASN1_TYPE_set(t, V_ASN1_SEQUENCE, s); PKCS7_set0_type_other(p7->d.sign->contents, idc_nid, t); return 0; } struct idc *IDC_get(PKCS7 *p7, BIO *bio) { const unsigned char *buf, *idcbuf; ASN1_STRING *str; IDC *idc; /* extract the idc from the signed PKCS7 'other' data */ str = p7->d.sign->contents->d.other->value.asn1_string; idcbuf = buf = ASN1_STRING_data(str); idc = d2i_IDC(NULL, &buf, ASN1_STRING_length(str)); /* If we were passed a BIO, write the idc data, minus type and length, * to the BIO. This can be used to PKCS7_verify the idc */ if (bio) { uint32_t idclen; uint8_t tmp; tmp = idcbuf[1]; if (!(tmp & 0x80)) { idclen = tmp & 0x7f; idcbuf += 2; } else if ((tmp & 0x82) == 0x82) { idclen = (idcbuf[2] << 8) + idcbuf[3]; idcbuf += 4; } else { fprintf(stderr, "Invalid ASN.1 data in " "IndirectDataContext?\n"); return NULL; } BIO_write(bio, idcbuf, idclen); } return idc; } int IDC_check_hash(struct idc *idc, struct image *image) { unsigned char sha[SHA256_DIGEST_LENGTH]; const unsigned char *buf; ASN1_STRING *str; image_hash_sha256(image, sha); /* check hash algorithm sanity */ if (OBJ_cmp(idc->digest->alg->algorithm, OBJ_nid2obj(NID_sha256))) { fprintf(stderr, "Invalid algorithm type\n"); return -1; } str = idc->digest->digest; if (ASN1_STRING_length(str) != sizeof(sha)) { fprintf(stderr, "Invalid algorithm length\n"); return -1; } /* check hash against the one we calculated from the image */ buf = ASN1_STRING_data(str); if (memcmp(buf, sha, sizeof(sha))) { fprintf(stderr, "Hash doesn't match image\n"); fprintf(stderr, " got: %s\n", sha256_str(buf)); fprintf(stderr, " expecting: %s\n", sha256_str(sha)); return -1; } return 0; } sbsigntool-0.9.2/src/idc.h000066400000000000000000000034221342142174400154070ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #ifndef IDC_H #define IDC_H #include "image.h" #include struct idc; int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image); struct idc *IDC_get(PKCS7 *p7, BIO *bio); int IDC_check_hash(struct idc *idc, struct image *image); #endif /* IDC_H */ sbsigntool-0.9.2/src/image.c000066400000000000000000000443441342142174400157350ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "fileio.h" #include "image.h" #define DATA_DIR_CERT_TABLE 4 #define CERT_TABLE_TYPE_PKCS 0x0002 /* PKCS signedData */ #define CERT_TABLE_REVISION 0x0200 /* revision 2 */ /** * The PE/COFF headers export struct fields as arrays of chars. So, define * a couple of accessor functions that allow fields to be deferenced as their * native types, to allow strict aliasing. This also allows for endian- * neutral behaviour. */ static uint32_t __pehdr_u32(char field[]) { uint8_t *ufield = (uint8_t *)field; return (ufield[3] << 24) + (ufield[2] << 16) + (ufield[1] << 8) + ufield[0]; } static uint16_t __pehdr_u16(char field[]) { uint8_t *ufield = (uint8_t *)field; return (ufield[1] << 8) + ufield[0]; } /* wrappers to ensure type correctness */ #define pehdr_u32(f) __pehdr_u32(f + BUILD_ASSERT_OR_ZERO(sizeof(f) == 4)) #define pehdr_u16(f) __pehdr_u16(f + BUILD_ASSERT_OR_ZERO(sizeof(f) == 2)) /* Machine-specific PE/COFF parse functions. These parse the relevant a.out * header for the machine type, and set the following members of struct image: * - aouthdr_size * - file_alignment * - header_size * - data_dir * - checksum * * These functions require image->opthdr to be set by the caller. */ static int image_pecoff_parse_32(struct image *image) { if (image->opthdr.opt_32->standard.magic[0] != 0x0b || image->opthdr.opt_32->standard.magic[1] != 0x01) { fprintf(stderr, "Invalid a.out machine type\n"); return -1; } image->opthdr_min_size = sizeof(*image->opthdr.opt_32) - sizeof(image->opthdr.opt_32->DataDirectory); image->file_alignment = pehdr_u32(image->opthdr.opt_32->FileAlignment); image->header_size = pehdr_u32(image->opthdr.opt_32->SizeOfHeaders); image->data_dir = (void *)image->opthdr.opt_32->DataDirectory; image->checksum = (uint32_t *)image->opthdr.opt_32->CheckSum; return 0; } static int image_pecoff_parse_64(struct image *image) { if (image->opthdr.opt_64->standard.magic[0] != 0x0b || image->opthdr.opt_64->standard.magic[1] != 0x02) { fprintf(stderr, "Invalid a.out machine type\n"); return -1; } image->opthdr_min_size = sizeof(*image->opthdr.opt_64) - sizeof(image->opthdr.opt_64->DataDirectory); image->file_alignment = pehdr_u32(image->opthdr.opt_64->FileAlignment); image->header_size = pehdr_u32(image->opthdr.opt_64->SizeOfHeaders); image->data_dir = (void *)image->opthdr.opt_64->DataDirectory; image->checksum = (uint32_t *)image->opthdr.opt_64->CheckSum; return 0; } static int align_up(int size, int align) { return (size + align - 1) & ~(align - 1); } static uint16_t csum_update_fold(uint16_t csum, uint16_t x) { uint32_t new = csum + x; new = (new >> 16) + (new & 0xffff); return new; } static uint16_t csum_bytes(uint16_t checksum, void *buf, size_t len) { unsigned int i; uint16_t *p = buf; for (i = 0; i + sizeof(*p) <= len; i += sizeof(*p)) { checksum = csum_update_fold(checksum, *p++); } /* if length is odd, add the remaining byte */ if (i < len) checksum = csum_update_fold(checksum, *((uint8_t *)p)); return checksum; } static void image_pecoff_update_checksum(struct image *image) { bool is_signed = image->sigsize && image->sigbuf; uint32_t checksum; struct cert_table_header *cert_table = image->cert_table; /* We carefully only include the signature data in the checksum (and * in the file length) if we're outputting the signature. Otherwise, * in case of signature removal, the signature data is in the buffer * we read in (as indicated by image->size), but we do *not* want to * checksum it. * * We also skip the 32-bits of checksum data in the PE/COFF header. */ checksum = csum_bytes(0, image->buf, (void *)image->checksum - (void *)image->buf); checksum = csum_bytes(checksum, image->checksum + 1, (void *)(image->buf + image->data_size) - (void *)(image->checksum + 1)); if (is_signed) { checksum = csum_bytes(checksum, cert_table, sizeof(*cert_table)); checksum = csum_bytes(checksum, image->sigbuf, image->sigsize); } checksum += image->data_size; if (is_signed) checksum += sizeof(*cert_table) + image->sigsize; *(image->checksum) = cpu_to_le32(checksum); } static int image_pecoff_parse(struct image *image) { struct cert_table_header *cert_table; char nt_sig[] = {'P', 'E', 0, 0}; size_t size = image->size; int rc, cert_table_offset; void *buf = image->buf; uint16_t magic; uint32_t addr; /* sanity checks */ if (size < sizeof(*image->doshdr)) { fprintf(stderr, "file is too small for DOS header\n"); return -1; } image->doshdr = buf; if (image->doshdr->e_magic[0] != 0x4d || image->doshdr->e_magic[1] != 0x5a) { fprintf(stderr, "Invalid DOS header magic\n"); return -1; } addr = pehdr_u32(image->doshdr->e_lfanew); if (addr >= image->size) { fprintf(stderr, "pehdr is beyond end of file [0x%08x]\n", addr); return -1; } if (addr + sizeof(*image->pehdr) > image->size) { fprintf(stderr, "File not large enough to contain pehdr\n"); return -1; } image->pehdr = buf + addr; if (memcmp(image->pehdr->nt_signature, nt_sig, sizeof(nt_sig))) { fprintf(stderr, "Invalid PE header signature\n"); return -1; } /* a.out header directly follows PE header */ image->opthdr.addr = image->pehdr + 1; magic = pehdr_u16(image->pehdr->f_magic); switch (magic) { case IMAGE_FILE_MACHINE_AMD64: case IMAGE_FILE_MACHINE_AARCH64: rc = image_pecoff_parse_64(image); break; case IMAGE_FILE_MACHINE_I386: case IMAGE_FILE_MACHINE_THUMB: rc = image_pecoff_parse_32(image); break; default: fprintf(stderr, "Invalid PE header magic\n"); return -1; } if (rc) { fprintf(stderr, "Error parsing a.out header\n"); return -1; } /* the optional header has a variable size, as the data directory * has a variable number of entries. Ensure that the we have enough * space to include the security directory entry */ image->opthdr_size = pehdr_u16(image->pehdr->f_opthdr); cert_table_offset = sizeof(*image->data_dir) * (DATA_DIR_CERT_TABLE + 1); if (image->opthdr_size < image->opthdr_min_size + cert_table_offset) { fprintf(stderr, "PE opt header too small (%d bytes) to contain " "a suitable data directory (need %d bytes)\n", image->opthdr_size, image->opthdr_min_size + cert_table_offset); return -1; } image->data_dir_sigtable = &image->data_dir[DATA_DIR_CERT_TABLE]; if (image->size < sizeof(*image->doshdr) + sizeof(*image->pehdr) + image->opthdr_size) { fprintf(stderr, "file is too small for a.out header\n"); return -1; } image->cert_table_size = image->data_dir_sigtable->size; if (image->cert_table_size) cert_table = buf + image->data_dir_sigtable->addr; else cert_table = NULL; image->cert_table = cert_table; /* if we have a valid cert table header, populate sigbuf as a shadow * copy of the cert tables */ if (cert_table && cert_table->revision == CERT_TABLE_REVISION && cert_table->type == CERT_TABLE_TYPE_PKCS && cert_table->size < size) { image->sigsize = image->data_dir_sigtable->size; image->sigbuf = talloc_memdup(image, cert_table, image->sigsize); } image->sections = pehdr_u16(image->pehdr->f_nscns); image->scnhdr = image->opthdr.addr + image->opthdr_size; return 0; } static int cmp_regions(const void *p1, const void *p2) { const struct region *r1 = p1, *r2 = p2; if (r1->data < r2->data) return -1; if (r1->data > r2->data) return 1; return 0; } static void set_region_from_range(struct region *region, void *start, void *end) { region->data = start; region->size = end - start; } static int image_find_regions(struct image *image) { struct region *regions, *r; void *buf = image->buf; int i, gap_warn; size_t bytes; gap_warn = 0; /* now we know where the checksum and cert table data is, we can * construct regions that need to be signed */ bytes = 0; image->n_checksum_regions = 0; image->checksum_regions = NULL; image->n_checksum_regions = 3; image->checksum_regions = talloc_zero_array(image, struct region, image->n_checksum_regions); /* first region: beginning to checksum field */ regions = image->checksum_regions; set_region_from_range(®ions[0], buf, image->checksum); regions[0].name = "begin->cksum"; bytes += regions[0].size; bytes += sizeof(*image->checksum); /* second region: end of checksum to certificate table entry */ set_region_from_range(®ions[1], image->checksum + 1, image->data_dir_sigtable ); regions[1].name = "cksum->datadir[CERT]"; bytes += regions[1].size; bytes += sizeof(struct data_dir_entry); /* third region: end of checksum to end of headers */ set_region_from_range(®ions[2], (void *)image->data_dir_sigtable + sizeof(struct data_dir_entry), buf + image->header_size); regions[2].name = "datadir[CERT]->headers"; bytes += regions[2].size; /* add COFF sections */ for (i = 0; i < image->sections; i++) { uint32_t file_offset, file_size; int n; file_offset = pehdr_u32(image->scnhdr[i].s_scnptr); file_size = pehdr_u32(image->scnhdr[i].s_size); if (!file_size) continue; n = image->n_checksum_regions++; image->checksum_regions = talloc_realloc(image, image->checksum_regions, struct region, image->n_checksum_regions); regions = image->checksum_regions; regions[n].data = buf + file_offset; regions[n].size = file_size; regions[n].name = talloc_strndup(image->checksum_regions, image->scnhdr[i].s_name, 8); bytes += regions[n].size; if (file_offset + regions[n].size > image->size) { fprintf(stderr, "warning: file-aligned section %s " "extends beyond end of file\n", regions[n].name); } if (regions[n-1].data + regions[n-1].size != regions[n].data) { fprintf(stderr, "warning: gap in section table:\n"); fprintf(stderr, " %-8s: 0x%08tx - 0x%08tx,\n", regions[n-1].name, regions[n-1].data - buf, regions[n-1].data + regions[n-1].size - buf); fprintf(stderr, " %-8s: 0x%08tx - 0x%08tx,\n", regions[n].name, regions[n].data - buf, regions[n].data + regions[n].size - buf); gap_warn = 1; } } if (gap_warn) fprintf(stderr, "gaps in the section table may result in " "different checksums\n"); qsort(image->checksum_regions, image->n_checksum_regions, sizeof(struct region), cmp_regions); if (bytes + image->cert_table_size < image->size) { int n = image->n_checksum_regions++; struct region *r; image->checksum_regions = talloc_realloc(image, image->checksum_regions, struct region, image->n_checksum_regions); r = &image->checksum_regions[n]; r->name = "endjunk"; r->data = image->buf + bytes; r->size = image->size - bytes - image->cert_table_size; fprintf(stderr, "warning: data remaining[%zd vs %zd]: gaps " "between PE/COFF sections?\n", bytes + image->cert_table_size, image->size); } else if (bytes + image->cert_table_size > image->size) { fprintf(stderr, "warning: checksum areas are greater than " "image size. Invalid section table?\n"); } /* record the size of non-signature data */ r = &image->checksum_regions[image->n_checksum_regions - 1]; /* * The new Tianocore multisign does a stricter check of the signatures * in particular, the signature table must start at an aligned offset * fix this by adding bytes to the end of the text section (which must * be included in the hash) */ image->data_size = align_up((r->data - (void *)image->buf) + r->size, 8); return 0; } struct image *image_load(const char *filename) { struct image *image; int rc; image = talloc(NULL, struct image); if (!image) { perror("talloc(image)"); return NULL; } memset(image, 0, sizeof(*image)); rc = fileio_read_file(image, filename, &image->buf, &image->size); if (rc) goto err; reparse: rc = image_pecoff_parse(image); if (rc) goto err; rc = image_find_regions(image); if (rc) goto err; /* Some images may have incorrectly aligned sections, which get rounded * up to a size that is larger that the image itself (and the buffer * that we've allocated). We would have generated a warning about this, * but we can improve our chances that the verification hash will * succeed by padding the image out to the aligned size, and including * the pad in the signed data. * * In this case, do a realloc, but that may peturb the addresses that * we've calculated during the pecoff parsing, so we need to redo that * too. */ if (image->data_size > image->size) { image->buf = talloc_realloc(image, image->buf, uint8_t, image->data_size); memset(image->buf + image->size, 0, image->data_size - image->size); image->size = image->data_size; goto reparse; } return image; err: talloc_free(image); return NULL; } int image_hash_sha256(struct image *image, uint8_t digest[]) { struct region *region; SHA256_CTX ctx; int rc, i, n; rc = SHA256_Init(&ctx); if (!rc) return -1; n = 0; for (i = 0; i < image->n_checksum_regions; i++) { region = &image->checksum_regions[i]; n += region->size; #if 0 printf("sum region: 0x%04lx -> 0x%04lx [0x%04x bytes]\n", region->data - image->buf, region->data - image->buf - 1 + region->size, region->size); #endif rc = SHA256_Update(&ctx, region->data, region->size); if (!rc) return -1; } rc = SHA256_Final(digest, &ctx); return !rc; } int image_add_signature(struct image *image, void *sig, int size) { struct cert_table_header *cth; int tot_size = size + sizeof(*cth); int aligned_size = align_up(tot_size, 8); void *start; if (image->sigbuf) { fprintf(stderr, "Image was already signed; adding additional signature\n"); image->sigbuf = talloc_realloc(image, image->sigbuf, uint8_t, image->sigsize + aligned_size); start = image->sigbuf + image->sigsize; image->sigsize += aligned_size; } else { fprintf(stderr, "Signing Unsigned original image\n"); start = image->sigbuf = talloc_array(image, uint8_t, aligned_size); image->sigsize = aligned_size; } cth = start; start += sizeof(*cth); memset(cth, 0 , sizeof(*cth)); cth->size = tot_size; cth->revision = CERT_TABLE_REVISION; cth->type = CERT_TABLE_TYPE_PKCS; memcpy(start, sig, size); if (aligned_size != tot_size) memset(start + size, 0, aligned_size - tot_size); image->cert_table = cth; return 0; } int image_get_signature(struct image *image, int signum, uint8_t **buf, size_t *size) { struct cert_table_header *header; void *addr = (void *)image->sigbuf; int i; if (!image->sigbuf) { fprintf(stderr, "No signature table present\n"); return -1; } header = addr; for (i = 0; i < signum; i++) { addr += align_up(header->size, 8); header = addr; } if (addr >= ((void *)image->sigbuf + image->sigsize)) return -1; *buf = (void *)(header + 1); *size = header->size - sizeof(*header); return 0; } int image_remove_signature(struct image *image, int signum) { uint8_t *buf; size_t size, aligned_size; int rc = image_get_signature(image, signum, &buf, &size); if (rc) return rc; buf -= sizeof(struct cert_table_header); size += sizeof(struct cert_table_header); aligned_size = align_up(size, 8); /* is signature at the end? */ if (buf + aligned_size >= (uint8_t *)image->sigbuf + image->sigsize) { /* only one signature? */ if (image->sigbuf == buf) { talloc_free(image->sigbuf); image->sigbuf = NULL; image->sigsize = 0; return 0; } } else { /* sig is in the middle ... just copy the rest over it */ memmove(buf, buf + aligned_size, image->sigsize - ((void *)buf - image->sigbuf) - aligned_size); } image->sigsize -= aligned_size; image->sigbuf = talloc_realloc(image, image->sigbuf, uint8_t, image->sigsize); return 0; } int image_write(struct image *image, const char *filename) { int fd, rc; bool is_signed; is_signed = image->sigbuf && image->sigsize; /* optionally update the image to contain signature data */ if (is_signed) { image->data_dir_sigtable->addr = image->data_size; image->data_dir_sigtable->size = image->sigsize; } else { image->data_dir_sigtable->addr = 0; image->data_dir_sigtable->size = 0; } image_pecoff_update_checksum(image); fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror("open"); return -1; } rc = write_all(fd, image->buf, image->data_size); if (!rc) goto out; if (!is_signed) goto out; rc = write_all(fd, image->sigbuf, image->sigsize); if (!rc) goto out; out: close(fd); return !rc; } int image_write_detached(struct image *image, int signum, const char *filename) { uint8_t *sig; size_t len; int rc; rc = image_get_signature(image, signum, &sig, &len); if (rc) return rc; return fileio_write_file(filename, sig, len); } sbsigntool-0.9.2/src/image.h000066400000000000000000000067331342142174400157420ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #ifndef IMAGE_H #define IMAGE_H #include #include #define DO_NOT_DEFINE_LINENO #include "coff/external.h" #include "coff/pe.h" struct region { void *data; int size; char *name; }; struct image { uint8_t *buf; size_t size; /* size of the image, without signature */ size_t data_size; /* Pointers to interesting parts of the image */ uint32_t *checksum; struct external_PEI_DOS_hdr *doshdr; struct external_PEI_IMAGE_hdr *pehdr; union { PEPAOUTHDR *opt_64; PEAOUTHDR *opt_32; void *addr; } opthdr; /* size of a minimal opthdr for this machine, without data * directories */ unsigned int opthdr_min_size; /* size of the opthdr as specified by the image */ unsigned int opthdr_size; struct data_dir_entry *data_dir; struct data_dir_entry *data_dir_sigtable; struct external_scnhdr *scnhdr; int sections; void *cert_table; int cert_table_size; /* We cache a few values from the aout header, so we don't have to * keep checking whether to use the 32- or 64-bit version */ uint32_t file_alignment; uint32_t header_size; /* Regions that are included in the image hash: populated * during image parsing, then used during the hash process. */ struct region *checksum_regions; int n_checksum_regions; /* Generated signature */ void *sigbuf; size_t sigsize; }; struct data_dir_entry { uint32_t addr; uint32_t size; } __attribute__((packed)); struct cert_table_header { uint32_t size; uint16_t revision; uint16_t type; } __attribute__((packed)); struct image *image_load(const char *filename); int image_hash_sha256(struct image *image, uint8_t digest[]); int image_add_signature(struct image *, void *sig, int size); int image_get_signature(struct image *image, int signum, uint8_t **buf, size_t *size); int image_remove_signature(struct image *image, int signum); int image_write(struct image *image, const char *filename); int image_write_detached(struct image *image, int signum, const char *filename); #endif /* IMAGE_H */ sbsigntool-0.9.2/src/libcoff.h000066400000000000000000000771461342142174400162720ustar00rootroot00000000000000/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically generated from "libcoff-in.h" and "coffcode.h". Run "make headers" in your build bfd/ to regenerate. */ /* BFD COFF object file private structure. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. 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 3 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. */ #include "bfdlink.h" /* Object file tdata; access macros. */ #define coff_data(bfd) ((bfd)->tdata.coff_obj_data) #define obj_pe(bfd) (coff_data (bfd)->pe) #define obj_symbols(bfd) (coff_data (bfd)->symbols) #define obj_sym_filepos(bfd) (coff_data (bfd)->sym_filepos) #define obj_relocbase(bfd) (coff_data (bfd)->relocbase) #define obj_raw_syments(bfd) (coff_data (bfd)->raw_syments) #define obj_raw_syment_count(bfd) (coff_data (bfd)->raw_syment_count) #define obj_convert(bfd) (coff_data (bfd)->conversion_table) #define obj_conv_table_size(bfd) (coff_data (bfd)->conv_table_size) #define obj_coff_external_syms(bfd) (coff_data (bfd)->external_syms) #define obj_coff_keep_syms(bfd) (coff_data (bfd)->keep_syms) #define obj_coff_strings(bfd) (coff_data (bfd)->strings) #define obj_coff_keep_strings(bfd) (coff_data (bfd)->keep_strings) #define obj_coff_sym_hashes(bfd) (coff_data (bfd)->sym_hashes) #define obj_coff_strings_written(bfd) (coff_data (bfd)->strings_written) #define obj_coff_local_toc_table(bfd) (coff_data (bfd)->local_toc_sym_map) /* `Tdata' information kept for COFF files. */ typedef struct coff_tdata { struct coff_symbol_struct *symbols; /* Symtab for input bfd. */ unsigned int *conversion_table; int conv_table_size; file_ptr sym_filepos; struct coff_ptr_struct *raw_syments; unsigned long raw_syment_count; /* These are only valid once writing has begun. */ long int relocbase; /* These members communicate important constants about the symbol table to GDB's symbol-reading code. These `constants' unfortunately vary from coff implementation to implementation... */ unsigned local_n_btmask; unsigned local_n_btshft; unsigned local_n_tmask; unsigned local_n_tshift; unsigned local_symesz; unsigned local_auxesz; unsigned local_linesz; /* The unswapped external symbols. May be NULL. Read by _bfd_coff_get_external_symbols. */ void * external_syms; /* If this is TRUE, the external_syms may not be freed. */ bfd_boolean keep_syms; /* The string table. May be NULL. Read by _bfd_coff_read_string_table. */ char *strings; /* If this is TRUE, the strings may not be freed. */ bfd_boolean keep_strings; /* If this is TRUE, the strings have been written out already. */ bfd_boolean strings_written; /* Is this a PE format coff file? */ int pe; /* Used by the COFF backend linker. */ struct coff_link_hash_entry **sym_hashes; /* Used by the pe linker for PowerPC. */ int *local_toc_sym_map; struct bfd_link_info *link_info; /* Used by coff_find_nearest_line. */ void * line_info; /* A place to stash dwarf2 info for this bfd. */ void * dwarf2_find_line_info; /* The timestamp from the COFF file header. */ long timestamp; /* Copy of some of the f_flags bits in the COFF filehdr structure, used by ARM code. */ flagword flags; /* coff-stgo32 EXE stub header after BFD tdata has been allocated. Its data is kept in internal_filehdr.go32stub beforehand. */ char *go32stub; } coff_data_type; /* Tdata for pe image files. */ typedef struct pe_tdata { coff_data_type coff; struct internal_extra_pe_aouthdr pe_opthdr; int dll; int has_reloc_section; int dont_strip_reloc; bfd_boolean (*in_reloc_p) (bfd *, reloc_howto_type *); flagword real_flags; } pe_data_type; #define pe_data(bfd) ((bfd)->tdata.pe_obj_data) /* Tdata for XCOFF files. */ struct xcoff_tdata { /* Basic COFF information. */ coff_data_type coff; /* TRUE if this is an XCOFF64 file. */ bfd_boolean xcoff64; /* TRUE if a large a.out header should be generated. */ bfd_boolean full_aouthdr; /* TOC value. */ bfd_vma toc; /* Index of section holding TOC. */ int sntoc; /* Index of section holding entry point. */ int snentry; /* .text alignment from optional header. */ int text_align_power; /* .data alignment from optional header. */ int data_align_power; /* modtype from optional header. */ short modtype; /* cputype from optional header. */ short cputype; /* maxdata from optional header. */ bfd_vma maxdata; /* maxstack from optional header. */ bfd_vma maxstack; /* Used by the XCOFF backend linker. */ asection **csects; long *debug_indices; unsigned int *lineno_counts; unsigned int import_file_id; }; #define xcoff_data(abfd) ((abfd)->tdata.xcoff_obj_data) /* We take the address of the first element of an asymbol to ensure that the macro is only ever applied to an asymbol. */ #define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd))) /* The used_by_bfd field of a section may be set to a pointer to this structure. */ struct coff_section_tdata { /* The relocs, swapped into COFF internal form. This may be NULL. */ struct internal_reloc *relocs; /* If this is TRUE, the relocs entry may not be freed. */ bfd_boolean keep_relocs; /* The section contents. This may be NULL. */ bfd_byte *contents; /* If this is TRUE, the contents entry may not be freed. */ bfd_boolean keep_contents; /* Information cached by coff_find_nearest_line. */ bfd_vma offset; unsigned int i; const char *function; /* Optional information about a COMDAT entry; NULL if not COMDAT. */ struct coff_comdat_info *comdat; int line_base; /* A pointer used for .stab linking optimizations. */ void * stab_info; /* Available for individual backends. */ void * tdata; }; /* An accessor macro for the coff_section_tdata structure. */ #define coff_section_data(abfd, sec) \ ((struct coff_section_tdata *) (sec)->used_by_bfd) /* Tdata for sections in XCOFF files. This is used by the linker. */ struct xcoff_section_tdata { /* Used for XCOFF csects created by the linker; points to the real XCOFF section which contains this csect. */ asection *enclosing; /* The lineno_count field for the enclosing section, because we are going to clobber it there. */ unsigned int lineno_count; /* The first and last symbol indices for symbols used by this csect. */ unsigned long first_symndx; unsigned long last_symndx; }; /* An accessor macro the xcoff_section_tdata structure. */ #define xcoff_section_data(abfd, sec) \ ((struct xcoff_section_tdata *) coff_section_data ((abfd), (sec))->tdata) /* Tdata for sections in PE files. */ struct pei_section_tdata { /* The virtual size of the section. */ bfd_size_type virt_size; /* The PE section flags. */ long pe_flags; }; /* An accessor macro for the pei_section_tdata structure. */ #define pei_section_data(abfd, sec) \ ((struct pei_section_tdata *) coff_section_data ((abfd), (sec))->tdata) /* COFF linker hash table entries. */ struct coff_link_hash_entry { struct bfd_link_hash_entry root; /* Symbol index in output file. Set to -1 initially. Set to -2 if there is a reloc against this symbol. */ long indx; /* Symbol type. */ unsigned short type; /* Symbol class. */ unsigned char symbol_class; /* Number of auxiliary entries. */ char numaux; /* BFD to take auxiliary entries from. */ bfd *auxbfd; /* Pointer to array of auxiliary entries, if any. */ union internal_auxent *aux; /* Flag word; legal values follow. */ unsigned short coff_link_hash_flags; /* Symbol is a PE section symbol. */ #define COFF_LINK_HASH_PE_SECTION_SYMBOL (01) }; /* COFF linker hash table. */ struct coff_link_hash_table { struct bfd_link_hash_table root; /* A pointer to information used to link stabs in sections. */ struct stab_info stab_info; }; /* Look up an entry in a COFF linker hash table. */ #define coff_link_hash_lookup(table, string, create, copy, follow) \ ((struct coff_link_hash_entry *) \ bfd_link_hash_lookup (&(table)->root, (string), (create), \ (copy), (follow))) /* Traverse a COFF linker hash table. */ #define coff_link_hash_traverse(table, func, info) \ (bfd_link_hash_traverse \ (&(table)->root, \ (bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \ (info))) /* Get the COFF linker hash table from a link_info structure. */ #define coff_hash_table(p) ((struct coff_link_hash_table *) ((p)->hash)) /* Functions in coffgen.c. */ extern const bfd_target *coff_object_p (bfd *); extern struct bfd_section *coff_section_from_bfd_index (bfd *, int); extern long coff_get_symtab_upper_bound (bfd *); extern long coff_canonicalize_symtab (bfd *, asymbol **); extern int coff_count_linenumbers (bfd *); extern struct coff_symbol_struct *coff_symbol_from (bfd *, asymbol *); extern bfd_boolean coff_renumber_symbols (bfd *, int *); extern void coff_mangle_symbols (bfd *); extern bfd_boolean coff_write_symbols (bfd *); extern bfd_boolean coff_write_linenumbers (bfd *); extern alent *coff_get_lineno (bfd *, asymbol *); extern asymbol *coff_section_symbol (bfd *, char *); extern bfd_boolean _bfd_coff_get_external_symbols (bfd *); extern const char *_bfd_coff_read_string_table (bfd *); extern bfd_boolean _bfd_coff_free_symbols (bfd *); extern struct coff_ptr_struct *coff_get_normalized_symtab (bfd *); extern long coff_get_reloc_upper_bound (bfd *, sec_ptr); extern asymbol *coff_make_empty_symbol (bfd *); extern void coff_print_symbol (bfd *, void * filep, asymbol *, bfd_print_symbol_type); extern void coff_get_symbol_info (bfd *, asymbol *, symbol_info *ret); extern bfd_boolean _bfd_coff_is_local_label_name (bfd *, const char *); extern asymbol *coff_bfd_make_debug_symbol (bfd *, void *, unsigned long); extern bfd_boolean coff_find_nearest_line (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **, unsigned int *); extern bfd_boolean coff_find_inliner_info (bfd *, const char **, const char **, unsigned int *); extern int coff_sizeof_headers (bfd *, struct bfd_link_info *); extern bfd_boolean bfd_coff_reloc16_relax_section (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents (bfd *, struct bfd_link_info *, struct bfd_link_order *, bfd_byte *, bfd_boolean, asymbol **); extern bfd_vma bfd_coff_reloc16_get_value (arelent *, struct bfd_link_info *, asection *); extern void bfd_perform_slip (bfd *, unsigned int, asection *, bfd_vma); /* Functions and types in cofflink.c. */ #define STRING_SIZE_SIZE 4 /* We use a hash table to merge identical enum, struct, and union definitions in the linker. */ /* Information we keep for a single element (an enum value, a structure or union field) in the debug merge hash table. */ struct coff_debug_merge_element { /* Next element. */ struct coff_debug_merge_element *next; /* Name. */ const char *name; /* Type. */ unsigned int type; /* Symbol index for complex type. */ long tagndx; }; /* A linked list of debug merge entries for a given name. */ struct coff_debug_merge_type { /* Next type with the same name. */ struct coff_debug_merge_type *next; /* Class of type. */ int type_class; /* Symbol index where this type is defined. */ long indx; /* List of elements. */ struct coff_debug_merge_element *elements; }; /* Information we store in the debug merge hash table. */ struct coff_debug_merge_hash_entry { struct bfd_hash_entry root; /* A list of types with this name. */ struct coff_debug_merge_type *types; }; /* The debug merge hash table. */ struct coff_debug_merge_hash_table { struct bfd_hash_table root; }; /* Initialize a COFF debug merge hash table. */ #define coff_debug_merge_hash_table_init(table) \ (bfd_hash_table_init (&(table)->root, _bfd_coff_debug_merge_hash_newfunc, \ sizeof (struct coff_debug_merge_hash_entry))) /* Free a COFF debug merge hash table. */ #define coff_debug_merge_hash_table_free(table) \ (bfd_hash_table_free (&(table)->root)) /* Look up an entry in a COFF debug merge hash table. */ #define coff_debug_merge_hash_lookup(table, string, create, copy) \ ((struct coff_debug_merge_hash_entry *) \ bfd_hash_lookup (&(table)->root, (string), (create), (copy))) /* Information we keep for each section in the output file when doing a relocatable link. */ struct coff_link_section_info { /* The relocs to be output. */ struct internal_reloc *relocs; /* For each reloc against a global symbol whose index was not known when the reloc was handled, the global hash table entry. */ struct coff_link_hash_entry **rel_hashes; }; /* Information that we pass around while doing the final link step. */ struct coff_final_link_info { /* General link information. */ struct bfd_link_info *info; /* Output BFD. */ bfd *output_bfd; /* Used to indicate failure in traversal routine. */ bfd_boolean failed; /* If doing "task linking" set only during the time when we want the global symbol writer to convert the storage class of defined global symbols from global to static. */ bfd_boolean global_to_static; /* Hash table for long symbol names. */ struct bfd_strtab_hash *strtab; /* When doing a relocatable link, an array of information kept for each output section, indexed by the target_index field. */ struct coff_link_section_info *section_info; /* Symbol index of last C_FILE symbol (-1 if none). */ long last_file_index; /* Contents of last C_FILE symbol. */ struct internal_syment last_file; /* Symbol index of first aux entry of last .bf symbol with an empty endndx field (-1 if none). */ long last_bf_index; /* Contents of last_bf_index aux entry. */ union internal_auxent last_bf; /* Hash table used to merge debug information. */ struct coff_debug_merge_hash_table debug_merge; /* Buffer large enough to hold swapped symbols of any input file. */ struct internal_syment *internal_syms; /* Buffer large enough to hold sections of symbols of any input file. */ asection **sec_ptrs; /* Buffer large enough to hold output indices of symbols of any input file. */ long *sym_indices; /* Buffer large enough to hold output symbols for any input file. */ bfd_byte *outsyms; /* Buffer large enough to hold external line numbers for any input section. */ bfd_byte *linenos; /* Buffer large enough to hold any input section. */ bfd_byte *contents; /* Buffer large enough to hold external relocs of any input section. */ bfd_byte *external_relocs; /* Buffer large enough to hold swapped relocs of any input section. */ struct internal_reloc *internal_relocs; }; /* Most COFF variants have no way to record the alignment of a section. This struct is used to set a specific alignment based on the name of the section. */ struct coff_section_alignment_entry { /* The section name. */ const char *name; /* This is either (unsigned int) -1, indicating that the section name must match exactly, or it is the number of letters which must match at the start of the name. */ unsigned int comparison_length; /* These macros may be used to fill in the first two fields in a structure initialization. */ #define COFF_SECTION_NAME_EXACT_MATCH(name) (name), ((unsigned int) -1) #define COFF_SECTION_NAME_PARTIAL_MATCH(name) (name), (sizeof (name) - 1) /* Only use this entry if the default section alignment for this target is at least that much (as a power of two). If this field is COFF_ALIGNMENT_FIELD_EMPTY, it should be ignored. */ unsigned int default_alignment_min; /* Only use this entry if the default section alignment for this target is no greater than this (as a power of two). If this field is COFF_ALIGNMENT_FIELD_EMPTY, it should be ignored. */ unsigned int default_alignment_max; #define COFF_ALIGNMENT_FIELD_EMPTY ((unsigned int) -1) /* The desired alignment for this section (as a power of two). */ unsigned int alignment_power; }; extern struct bfd_hash_entry *_bfd_coff_link_hash_newfunc (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); extern bfd_boolean _bfd_coff_link_hash_table_init (struct coff_link_hash_table *, bfd *, struct bfd_hash_entry *(*) (struct bfd_hash_entry *, struct bfd_hash_table *, const char *), unsigned int); extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create (bfd *); extern const char *_bfd_coff_internal_syment_name (bfd *, const struct internal_syment *, char *); extern bfd_boolean _bfd_coff_section_already_linked (bfd *, asection *, struct bfd_link_info *); extern bfd_boolean _bfd_coff_link_add_symbols (bfd *, struct bfd_link_info *); extern bfd_boolean _bfd_coff_final_link (bfd *, struct bfd_link_info *); extern struct internal_reloc *_bfd_coff_read_internal_relocs (bfd *, asection *, bfd_boolean, bfd_byte *, bfd_boolean, struct internal_reloc *); extern bfd_boolean _bfd_coff_generic_relocate_section (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, struct internal_reloc *, struct internal_syment *, asection **); extern struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); extern bfd_boolean _bfd_coff_write_global_sym (struct bfd_hash_entry *, void *); extern bfd_boolean _bfd_coff_write_task_globals (struct coff_link_hash_entry *, void *); extern bfd_boolean _bfd_coff_link_input_bfd (struct coff_final_link_info *, bfd *); extern bfd_boolean _bfd_coff_reloc_link_order (bfd *, struct coff_final_link_info *, asection *, struct bfd_link_order *); #define coff_get_section_contents_in_window \ _bfd_generic_get_section_contents_in_window /* Functions in xcofflink.c. */ extern long _bfd_xcoff_get_dynamic_symtab_upper_bound (bfd *); extern long _bfd_xcoff_canonicalize_dynamic_symtab (bfd *, asymbol **); extern long _bfd_xcoff_get_dynamic_reloc_upper_bound (bfd *); extern long _bfd_xcoff_canonicalize_dynamic_reloc (bfd *, arelent **, asymbol **); extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create (bfd *); extern void _bfd_xcoff_bfd_link_hash_table_free (struct bfd_link_hash_table *); extern bfd_boolean _bfd_xcoff_bfd_link_add_symbols (bfd *, struct bfd_link_info *); extern bfd_boolean _bfd_xcoff_bfd_final_link (bfd *, struct bfd_link_info *); extern bfd_boolean _bfd_xcoff_define_common_symbol (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *); extern bfd_boolean _bfd_ppc_xcoff_relocate_section (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, struct internal_reloc *, struct internal_syment *, asection **); /* Functions in coff-ppc.c. FIXME: These are called by pe.em in the linker, and so should start with bfd and be declared in bfd.h. */ extern bfd_boolean ppc_allocate_toc_section (struct bfd_link_info *); extern bfd_boolean ppc_process_before_allocation (bfd *, struct bfd_link_info *); /* Extracted from coffcode.h. */ typedef struct coff_ptr_struct { /* Remembers the offset from the first symbol in the file for this symbol. Generated by coff_renumber_symbols. */ unsigned int offset; /* Should the value of this symbol be renumbered. Used for XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. */ unsigned int fix_value : 1; /* Should the tag field of this symbol be renumbered. Created by coff_pointerize_aux. */ unsigned int fix_tag : 1; /* Should the endidx field of this symbol be renumbered. Created by coff_pointerize_aux. */ unsigned int fix_end : 1; /* Should the x_csect.x_scnlen field be renumbered. Created by coff_pointerize_aux. */ unsigned int fix_scnlen : 1; /* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the index into the line number entries. Set by coff_slurp_symbol_table. */ unsigned int fix_line : 1; /* The container for the symbol structure as read and translated from the file. */ union { union internal_auxent auxent; struct internal_syment syment; } u; } combined_entry_type; /* Each canonical asymbol really looks like this: */ typedef struct coff_symbol_struct { /* The actual symbol which the rest of BFD works with */ asymbol symbol; /* A pointer to the hidden information for this symbol */ combined_entry_type *native; /* A pointer to the linenumber information for this symbol */ struct lineno_cache_entry *lineno; /* Have the line numbers been relocated yet ? */ bfd_boolean done_lineno; } coff_symbol_type; /* COFF symbol classifications. */ enum coff_symbol_classification { /* Global symbol. */ COFF_SYMBOL_GLOBAL, /* Common symbol. */ COFF_SYMBOL_COMMON, /* Undefined symbol. */ COFF_SYMBOL_UNDEFINED, /* Local symbol. */ COFF_SYMBOL_LOCAL, /* PE section symbol. */ COFF_SYMBOL_PE_SECTION }; typedef struct { void (*_bfd_coff_swap_aux_in) (bfd *, void *, int, int, int, int, void *); void (*_bfd_coff_swap_sym_in) (bfd *, void *, void *); void (*_bfd_coff_swap_lineno_in) (bfd *, void *, void *); unsigned int (*_bfd_coff_swap_aux_out) (bfd *, void *, int, int, int, int, void *); unsigned int (*_bfd_coff_swap_sym_out) (bfd *, void *, void *); unsigned int (*_bfd_coff_swap_lineno_out) (bfd *, void *, void *); unsigned int (*_bfd_coff_swap_reloc_out) (bfd *, void *, void *); unsigned int (*_bfd_coff_swap_filehdr_out) (bfd *, void *, void *); unsigned int (*_bfd_coff_swap_aouthdr_out) (bfd *, void *, void *); unsigned int (*_bfd_coff_swap_scnhdr_out) (bfd *, void *, void *); unsigned int _bfd_filhsz; unsigned int _bfd_aoutsz; unsigned int _bfd_scnhsz; unsigned int _bfd_symesz; unsigned int _bfd_auxesz; unsigned int _bfd_relsz; unsigned int _bfd_linesz; unsigned int _bfd_filnmlen; bfd_boolean _bfd_coff_long_filenames; bfd_boolean _bfd_coff_long_section_names; bfd_boolean (*_bfd_coff_set_long_section_names) (bfd *, int); unsigned int _bfd_coff_default_section_alignment_power; bfd_boolean _bfd_coff_force_symnames_in_strings; unsigned int _bfd_coff_debug_string_prefix_length; void (*_bfd_coff_swap_filehdr_in) (bfd *, void *, void *); void (*_bfd_coff_swap_aouthdr_in) (bfd *, void *, void *); void (*_bfd_coff_swap_scnhdr_in) (bfd *, void *, void *); void (*_bfd_coff_swap_reloc_in) (bfd *abfd, void *, void *); bfd_boolean (*_bfd_coff_bad_format_hook) (bfd *, void *); bfd_boolean (*_bfd_coff_set_arch_mach_hook) (bfd *, void *); void * (*_bfd_coff_mkobject_hook) (bfd *, void *, void *); bfd_boolean (*_bfd_styp_to_sec_flags_hook) (bfd *, void *, const char *, asection *, flagword *); void (*_bfd_set_alignment_hook) (bfd *, asection *, void *); bfd_boolean (*_bfd_coff_slurp_symbol_table) (bfd *); bfd_boolean (*_bfd_coff_symname_in_debug) (bfd *, struct internal_syment *); bfd_boolean (*_bfd_coff_pointerize_aux_hook) (bfd *, combined_entry_type *, combined_entry_type *, unsigned int, combined_entry_type *); bfd_boolean (*_bfd_coff_print_aux) (bfd *, FILE *, combined_entry_type *, combined_entry_type *, combined_entry_type *, unsigned int); void (*_bfd_coff_reloc16_extra_cases) (bfd *, struct bfd_link_info *, struct bfd_link_order *, arelent *, bfd_byte *, unsigned int *, unsigned int *); int (*_bfd_coff_reloc16_estimate) (bfd *, asection *, arelent *, unsigned int, struct bfd_link_info *); enum coff_symbol_classification (*_bfd_coff_classify_symbol) (bfd *, struct internal_syment *); bfd_boolean (*_bfd_coff_compute_section_file_positions) (bfd *); bfd_boolean (*_bfd_coff_start_final_link) (bfd *, struct bfd_link_info *); bfd_boolean (*_bfd_coff_relocate_section) (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, struct internal_reloc *, struct internal_syment *, asection **); reloc_howto_type *(*_bfd_coff_rtype_to_howto) (bfd *, asection *, struct internal_reloc *, struct coff_link_hash_entry *, struct internal_syment *, bfd_vma *); bfd_boolean (*_bfd_coff_adjust_symndx) (bfd *, struct bfd_link_info *, bfd *, asection *, struct internal_reloc *, bfd_boolean *); bfd_boolean (*_bfd_coff_link_add_one_symbol) (struct bfd_link_info *, bfd *, const char *, flagword, asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, struct bfd_link_hash_entry **); bfd_boolean (*_bfd_coff_link_output_has_begun) (bfd *, struct coff_final_link_info *); bfd_boolean (*_bfd_coff_final_link_postscript) (bfd *, struct coff_final_link_info *); bfd_boolean (*_bfd_coff_print_pdata) (bfd *, void *); } bfd_coff_backend_data; #define coff_backend_info(abfd) \ ((bfd_coff_backend_data *) (abfd)->xvec->backend_data) #define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \ ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i)) #define bfd_coff_swap_sym_in(a,e,i) \ ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i)) #define bfd_coff_swap_lineno_in(a,e,i) \ ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i)) #define bfd_coff_swap_reloc_out(abfd, i, o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o)) #define bfd_coff_swap_lineno_out(abfd, i, o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o)) #define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \ ((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o)) #define bfd_coff_swap_sym_out(abfd, i,o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o)) #define bfd_coff_swap_scnhdr_out(abfd, i,o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o)) #define bfd_coff_swap_filehdr_out(abfd, i,o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o)) #define bfd_coff_swap_aouthdr_out(abfd, i,o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o)) #define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz) #define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz) #define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz) #define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz) #define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz) #define bfd_coff_relsz(abfd) (coff_backend_info (abfd)->_bfd_relsz) #define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz) #define bfd_coff_filnmlen(abfd) (coff_backend_info (abfd)->_bfd_filnmlen) #define bfd_coff_long_filenames(abfd) \ (coff_backend_info (abfd)->_bfd_coff_long_filenames) #define bfd_coff_long_section_names(abfd) \ (coff_backend_info (abfd)->_bfd_coff_long_section_names) #define bfd_coff_set_long_section_names(abfd, enable) \ ((coff_backend_info (abfd)->_bfd_coff_set_long_section_names) (abfd, enable)) #define bfd_coff_default_section_alignment_power(abfd) \ (coff_backend_info (abfd)->_bfd_coff_default_section_alignment_power) #define bfd_coff_swap_filehdr_in(abfd, i,o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o)) #define bfd_coff_swap_aouthdr_in(abfd, i,o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o)) #define bfd_coff_swap_scnhdr_in(abfd, i,o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o)) #define bfd_coff_swap_reloc_in(abfd, i, o) \ ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_in) (abfd, i, o)) #define bfd_coff_bad_format_hook(abfd, filehdr) \ ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr)) #define bfd_coff_set_arch_mach_hook(abfd, filehdr)\ ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr)) #define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\ ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook)\ (abfd, filehdr, aouthdr)) #define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name, section, flags_ptr)\ ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook)\ (abfd, scnhdr, name, section, flags_ptr)) #define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\ ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr)) #define bfd_coff_slurp_symbol_table(abfd)\ ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd)) #define bfd_coff_symname_in_debug(abfd, sym)\ ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym)) #define bfd_coff_force_symnames_in_strings(abfd)\ (coff_backend_info (abfd)->_bfd_coff_force_symnames_in_strings) #define bfd_coff_debug_string_prefix_length(abfd)\ (coff_backend_info (abfd)->_bfd_coff_debug_string_prefix_length) #define bfd_coff_print_aux(abfd, file, base, symbol, aux, indaux)\ ((coff_backend_info (abfd)->_bfd_coff_print_aux)\ (abfd, file, base, symbol, aux, indaux)) #define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order,\ reloc, data, src_ptr, dst_ptr)\ ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ (abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)) #define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\ ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ (abfd, section, reloc, shrink, link_info)) #define bfd_coff_classify_symbol(abfd, sym)\ ((coff_backend_info (abfd)->_bfd_coff_classify_symbol)\ (abfd, sym)) #define bfd_coff_compute_section_file_positions(abfd)\ ((coff_backend_info (abfd)->_bfd_coff_compute_section_file_positions)\ (abfd)) #define bfd_coff_start_final_link(obfd, info)\ ((coff_backend_info (obfd)->_bfd_coff_start_final_link)\ (obfd, info)) #define bfd_coff_relocate_section(obfd,info,ibfd,o,con,rel,isyms,secs)\ ((coff_backend_info (ibfd)->_bfd_coff_relocate_section)\ (obfd, info, ibfd, o, con, rel, isyms, secs)) #define bfd_coff_rtype_to_howto(abfd, sec, rel, h, sym, addendp)\ ((coff_backend_info (abfd)->_bfd_coff_rtype_to_howto)\ (abfd, sec, rel, h, sym, addendp)) #define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\ ((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\ (obfd, info, ibfd, sec, rel, adjustedp)) #define bfd_coff_link_add_one_symbol(info, abfd, name, flags, section,\ value, string, cp, coll, hashp)\ ((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\ (info, abfd, name, flags, section, value, string, cp, coll, hashp)) #define bfd_coff_link_output_has_begun(a,p) \ ((coff_backend_info (a)->_bfd_coff_link_output_has_begun) (a, p)) #define bfd_coff_final_link_postscript(a,p) \ ((coff_backend_info (a)->_bfd_coff_final_link_postscript) (a, p)) #define bfd_coff_have_print_pdata(a) \ (coff_backend_info (a)->_bfd_coff_print_pdata) #define bfd_coff_print_pdata(a,p) \ ((coff_backend_info (a)->_bfd_coff_print_pdata) (a, p)) /* Macro: Returns true if the bfd is a PE executable as opposed to a PE object file. */ #define bfd_pei_p(abfd) \ (CONST_STRNEQ ((abfd)->xvec->name, "pei-")) sbsigntool-0.9.2/src/sbattach.c000066400000000000000000000152331342142174400164370ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "image.h" #include "fileio.h" static const char *toolname = "sbattach"; static struct option options[] = { { "attach", required_argument, NULL, 'a' }, { "detach", required_argument, NULL, 'd' }, { "remove", no_argument, NULL, 'r' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { "signum", required_argument, NULL, 's' }, { NULL, 0, NULL, 0 }, }; static void usage(void) { printf("Usage: %s --attach \n" " or: %s --detach [--remove] \n" " or: %s --remove \n" "Attach or detach a signature file to/from a boot image\n" "\n" "Options:\n" "\t--attach set as the boot image's\n" "\t signature table\n" "\t--detach copy the boot image's signature table\n" "\t to \n" "\t--remove remove the boot image's signature\n" "\t table from the original file\n" "\t--signum signature to operate on (defaults to\n" "\t first)\n", toolname, toolname, toolname); } static void version(void) { printf("%s %s\n", toolname, VERSION); } static int detach_sig(struct image *image, int signum, const char *sig_filename) { return image_write_detached(image, signum, sig_filename); } static int attach_sig(struct image *image, const char *image_filename, const char *sig_filename) { const uint8_t *tmp_buf; uint8_t *sigbuf; size_t size; PKCS7 *p7; int rc; rc = fileio_read_file(image, sig_filename, &sigbuf, &size); if (rc) goto out; image_add_signature(image, sigbuf, size); rc = -1; tmp_buf = sigbuf; p7 = d2i_PKCS7(NULL, &tmp_buf, size); if (!p7) { fprintf(stderr, "Unable to parse signature data in file: %s\n", sig_filename); ERR_print_errors_fp(stderr); goto out; } rc = PKCS7_verify(p7, NULL, NULL, NULL, NULL, PKCS7_BINARY | PKCS7_NOVERIFY | PKCS7_NOSIGS); if (!rc) { fprintf(stderr, "PKCS7 verification failed for file %s\n", sig_filename); ERR_print_errors_fp(stderr); goto out; } rc = image_write(image, image_filename); if (rc) fprintf(stderr, "Error writing %s: %s\n", image_filename, strerror(errno)); out: talloc_free(sigbuf); return rc; } static int remove_sig(struct image *image, int signum, const char *image_filename) { int rc; rc = image_remove_signature(image, signum); if (rc) { fprintf(stderr, "Error, image has no signature at %d\n", signum + 1); return rc; } rc = image_write(image, image_filename); if (rc) fprintf(stderr, "Error writing %s: %s\n", image_filename, strerror(errno)); return rc; } enum action { ACTION_NONE, ACTION_ATTACH, ACTION_DETACH, }; int main(int argc, char **argv) { const char *image_filename, *sig_filename; struct image *image; enum action action; bool remove; int c, rc, signum = 0; action = ACTION_NONE; sig_filename = NULL; remove = false; for (;;) { int idx; c = getopt_long(argc, argv, "a:d:s:rhV", options, &idx); if (c == -1) break; switch (c) { case 'a': case 'd': if (action != ACTION_NONE) { fprintf(stderr, "Multiple actions specified\n"); usage(); return EXIT_FAILURE; } action = (c == 'a') ? ACTION_ATTACH : ACTION_DETACH; sig_filename = optarg; break; case 's': /* humans count from 1 not zero */ signum = atoi(optarg) - 1; break; case 'r': remove = true; break; case 'V': version(); return EXIT_SUCCESS; case 'h': usage(); return EXIT_SUCCESS; } } if (argc != optind + 1) { usage(); return EXIT_FAILURE; } image_filename = argv[optind]; /* sanity check action combinations */ if (action == ACTION_ATTACH && remove) { fprintf(stderr, "Can't use --remove with --attach\n"); return EXIT_FAILURE; } if (action == ACTION_NONE && !remove) { fprintf(stderr, "No action (attach/detach/remove) specified\n"); usage(); return EXIT_FAILURE; } ERR_load_crypto_strings(); OpenSSL_add_all_digests(); OPENSSL_config(NULL); /* here we may get highly unlikely failures or we'll get a * complaint about FIPS signatures (usually becuase the FIPS * module isn't present). In either case ignore the errors * (malloc will cause other failures out lower down */ ERR_clear_error(); image = image_load(image_filename); if (!image) { fprintf(stderr, "Can't load image file %s\n", image_filename); return EXIT_FAILURE; } rc = 0; if (action == ACTION_ATTACH) rc = attach_sig(image, image_filename, sig_filename); else if (action == ACTION_DETACH) rc = detach_sig(image, signum, sig_filename); if (rc) goto out; if (remove) rc = remove_sig(image, signum, image_filename); out: talloc_free(image); return (rc == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } sbsigntool-0.9.2/src/sbkeysync.c000066400000000000000000000541001342142174400166540ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fileio.h" #include "efivars.h" #define EFIVARS_MOUNTPOINT "/sys/firmware/efi/efivars" #define PSTORE_FSTYPE 0x6165676C #define EFIVARS_FSTYPE 0xde5e81e4 #define EFI_IMAGE_SECURITY_DATABASE_GUID \ { 0xd719b2cb, 0x3d3a, 0x4596, \ { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f } } static const char *toolname = "sbkeysync"; static const uint32_t sigdb_attrs = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPEND_WRITE; struct key_database_type { const char *name; EFI_GUID guid; }; struct key_database_type keydb_types[] = { { "PK", EFI_GLOBAL_VARIABLE }, { "KEK", EFI_GLOBAL_VARIABLE }, { "db", EFI_IMAGE_SECURITY_DATABASE_GUID }, { "dbx", EFI_IMAGE_SECURITY_DATABASE_GUID }, }; enum keydb_type { KEYDB_PK = 0, KEYDB_KEK = 1, KEYDB_DB = 2, KEYDB_DBX = 3, }; static const char *default_keystore_dirs[] = { "/etc/secureboot/keys", "/usr/share/secureboot/keys", }; struct key { EFI_GUID type; int id_len; uint8_t *id; char *description; struct list_node list; /* set for keys loaded from a filesystem keystore */ struct fs_keystore_entry *keystore_entry; }; typedef int (*key_parse_func)(struct key *, uint8_t *, size_t); struct cert_type { EFI_GUID guid; key_parse_func parse; }; struct key_database { const struct key_database_type *type; struct list_head keys; }; struct keyset { struct key_database pk; struct key_database kek; struct key_database db; struct key_database dbx; }; struct fs_keystore_entry { const struct key_database_type *type; const char *root; const char *name; uint8_t *data; size_t len; struct list_node keystore_list; struct list_node new_list; }; struct fs_keystore { struct list_head keys; }; struct sync_context { const char *efivars_dir; struct keyset *filesystem_keys; struct keyset *firmware_keys; struct fs_keystore *fs_keystore; const char **keystore_dirs; unsigned int n_keystore_dirs; struct list_head new_keys; bool verbose; bool dry_run; bool set_pk; }; #define GUID_STRLEN (8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1) static void guid_to_str(const EFI_GUID *guid, char *str) { snprintf(str, GUID_STRLEN, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); } static int sha256_key_parse(struct key *key, uint8_t *data, size_t len) { const unsigned int sha256_id_size = 256 / 8; unsigned int i; if (len != sha256_id_size) return -1; key->id = talloc_memdup(key, data, sha256_id_size); key->id_len = sha256_id_size; key->description = talloc_array(key, char, len * 2 + 1); for (i = 0; i < len; i++) snprintf(&key->description[i*2], 3, "%02x", data[i]); key->description[len*2] = '\0'; return 0; } static int x509_key_parse(struct key *key, uint8_t *data, size_t len) { const int description_len = 160; ASN1_INTEGER *serial; const uint8_t *tmp; X509 *x509; int rc; rc = -1; tmp = data; x509 = d2i_X509(NULL, &tmp, len); if (!x509) return -1; /* we use the X509 serial number as the key ID */ serial = X509_get_serialNumber(x509); if (!serial) goto out; key->id_len = ASN1_STRING_length(serial); key->id = talloc_memdup(key, ASN1_STRING_data(serial), key->id_len); key->description = talloc_array(key, char, description_len); X509_NAME_oneline(X509_get_subject_name(x509), key->description, description_len); rc = 0; out: X509_free(x509); return rc; } struct cert_type cert_types[] = { { EFI_CERT_SHA256_GUID, sha256_key_parse }, { EFI_CERT_X509_GUID, x509_key_parse }, }; static int guidcmp(const EFI_GUID *a, const EFI_GUID *b) { return memcmp(a, b, sizeof(EFI_GUID)); } static int key_parse(struct key *key, const EFI_GUID *type, uint8_t *data, size_t len) { char guid_str[GUID_STRLEN]; unsigned int i; for (i = 0; i < ARRAY_SIZE(cert_types); i++) { if (guidcmp(&cert_types[i].guid, type)) continue; return cert_types[i].parse(key, data, len); } guid_to_str(type, guid_str); printf("warning: unknown signature type found:\n %s\n", guid_str); return -1; } typedef int (*sigdata_fn)(EFI_SIGNATURE_DATA *, int, const EFI_GUID *, void *); /** * Iterates an buffer of EFI_SIGNATURE_LISTs (at db_data, of length len), * and calls fn on each EFI_SIGNATURE_DATA item found. * * fn is passed the EFI_SIGNATURE_DATA pointer, and the length of the * signature data (including GUID header), the type of the signature list, * and a context pointer. */ static int sigdb_iterate(void *db_data, size_t len, sigdata_fn fn, void *arg) { EFI_SIGNATURE_LIST *siglist; EFI_SIGNATURE_DATA *sigdata; unsigned int i, j; int rc = 0; if (len == 0) return 0; if (len < sizeof(*siglist)) return -1; for (i = 0, siglist = db_data + i; i + sizeof(*siglist) <= len && i + siglist->SignatureListSize > i && i + siglist->SignatureListSize <= len && !rc; i += siglist->SignatureListSize, siglist = db_data + i) { /* ensure that the header & sig sizes are sensible */ if (siglist->SignatureHeaderSize > siglist->SignatureListSize) continue; if (siglist->SignatureSize > siglist->SignatureListSize) continue; if (siglist->SignatureSize < sizeof(*sigdata)) continue; /* iterate through the (constant-sized) signature data blocks */ for (j = sizeof(*siglist) + siglist->SignatureHeaderSize; j < siglist->SignatureListSize && !rc; j += siglist->SignatureSize) { sigdata = (void *)(siglist) + j; rc = fn(sigdata, siglist->SignatureSize, &siglist->SignatureType, arg); } } return rc; } struct keydb_add_ctx { struct fs_keystore_entry *ke; struct key_database *kdb; struct keyset *keyset; }; static int keydb_add_key(EFI_SIGNATURE_DATA *sigdata, int len, const EFI_GUID *type, void *arg) { struct keydb_add_ctx *add_ctx = arg; struct key *key; int rc; key = talloc(add_ctx->keyset, struct key); rc = key_parse(key, type, sigdata->SignatureData, len - sizeof(*sigdata)); if (rc) { talloc_free(key); return 0; } key->keystore_entry = add_ctx->ke; key->type = *type; /* add a reference to the keystore entry: we don't want it to be * deallocated if the keystore is deallocated before the * struct key. */ if (key->keystore_entry) talloc_reference(key, key->keystore_entry); list_add(&add_ctx->kdb->keys, &key->list); return 0; } static int read_firmware_keydb(struct sync_context *ctx, struct key_database *kdb) { struct keydb_add_ctx add_ctx; char guid_str[GUID_STRLEN]; char *filename; uint8_t *buf; int rc = -1; size_t len; add_ctx.keyset = ctx->firmware_keys; add_ctx.kdb = kdb; add_ctx.ke = NULL; guid_to_str(&kdb->type->guid, guid_str); filename = talloc_asprintf(ctx->firmware_keys, "%s/%s-%s", ctx->efivars_dir, kdb->type->name, guid_str); buf = NULL; rc = fileio_read_file_noerror(ctx->firmware_keys, filename, &buf, &len); if (rc) goto out; /* efivars files start with a 32-bit attribute block */ if (len < sizeof(uint32_t)) goto out; buf += sizeof(uint32_t); len -= sizeof(uint32_t); rc = 0; sigdb_iterate(buf, len, keydb_add_key, &add_ctx); out: if (rc) talloc_free(buf); talloc_free(filename); return rc; } static void __attribute__((format(printf, 2, 3))) print_keystore_key_error( struct fs_keystore_entry *ke, const char *fmt, ...) { char *errstr; va_list ap; va_start(ap, fmt); errstr = talloc_vasprintf(ke, fmt, ap); fprintf(stderr, "Invalid key %s/%s\n - %s\n", ke->root, ke->name, errstr); talloc_free(errstr); va_end(ap); } static int read_filesystem_keydb(struct sync_context *ctx, struct key_database *kdb) { EFI_GUID cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; EFI_VARIABLE_AUTHENTICATION_2 *auth; struct keydb_add_ctx add_ctx; struct fs_keystore_entry *ke; int rc; add_ctx.keyset = ctx->filesystem_keys; add_ctx.kdb = kdb; list_for_each(&ctx->fs_keystore->keys, ke, keystore_list) { unsigned int len; void *buf; if (ke->len == 0) continue; if (ke->type != kdb->type) continue; /* parse the three data structures: * EFI_VARIABLE_AUTHENTICATION_2 token * EFI_SIGNATURE_LIST * EFI_SIGNATURE_DATA * ensuring that we have enough data for each */ buf = ke->data; len = ke->len; if (len < sizeof(*auth)) { print_keystore_key_error(ke, "does not contain an " "EFI_VARIABLE_AUTHENTICATION_2 descriptor"); continue; } auth = buf; if (guidcmp(&auth->AuthInfo.CertType, &cert_type_pkcs7)) { print_keystore_key_error(ke, "unknown cert type"); continue; } if (auth->AuthInfo.Hdr.dwLength > len) { print_keystore_key_error(ke, "invalid WIN_CERTIFICATE length"); continue; } /* the dwLength field includes the size of the WIN_CERTIFICATE, * but not the other data in the EFI_VARIABLE_AUTHENTICATION_2 * descriptor */ buf += sizeof(*auth) - sizeof(auth->AuthInfo) + auth->AuthInfo.Hdr.dwLength; len -= sizeof(*auth) - sizeof(auth->AuthInfo) + auth->AuthInfo.Hdr.dwLength; add_ctx.ke = ke; rc = sigdb_iterate(buf, len, keydb_add_key, &add_ctx); if (rc) { print_keystore_key_error(ke, "error parsing " "EFI_SIGNATURE_LIST"); continue; } } return 0; } static int read_keysets(struct sync_context *ctx) { read_firmware_keydb(ctx, &ctx->firmware_keys->pk); read_firmware_keydb(ctx, &ctx->firmware_keys->kek); read_firmware_keydb(ctx, &ctx->firmware_keys->db); read_firmware_keydb(ctx, &ctx->firmware_keys->dbx); read_filesystem_keydb(ctx, &ctx->filesystem_keys->pk); read_filesystem_keydb(ctx, &ctx->filesystem_keys->kek); read_filesystem_keydb(ctx, &ctx->filesystem_keys->db); read_filesystem_keydb(ctx, &ctx->filesystem_keys->dbx); return 0; } static int check_pk(struct sync_context *ctx) { struct key *key; int i = 0; list_for_each(&ctx->filesystem_keys->pk.keys, key, list) i++; return (i <= 1) ? 0 : 1; } static void print_keyset(struct keyset *keyset, const char *name) { struct key_database *kdbs[] = { &keyset->pk, &keyset->kek, &keyset->db, &keyset->dbx }; struct key *key; unsigned int i; printf("%s keys:\n", name); for (i = 0; i < ARRAY_SIZE(kdbs); i++) { printf(" %s:\n", kdbs[i]->type->name); list_for_each(&kdbs[i]->keys, key, list) { printf(" %s\n", key->description); if (key->keystore_entry) printf(" from %s/%s\n", key->keystore_entry->root, key->keystore_entry->name); } } } static int check_efivars_mount(const char *mountpoint) { struct statfs statbuf; int rc; rc = statfs(mountpoint, &statbuf); if (rc) return -1; if (statbuf.f_type != EFIVARS_FSTYPE && statbuf.f_type != PSTORE_FSTYPE) return -1; return 0; } static int keystore_entry_read(struct fs_keystore_entry *ke) { const char *path; int rc; path = talloc_asprintf(ke, "%s/%s", ke->root, ke->name); rc = fileio_read_file(ke, path, &ke->data, &ke->len); talloc_free(path); return rc; } static bool keystore_contains_file(struct fs_keystore *keystore, const char *filename) { struct fs_keystore_entry *ke; list_for_each(&keystore->keys, ke, keystore_list) { if (!strcmp(ke->name, filename)) return true; } return false; } static int update_keystore(struct fs_keystore *keystore, const char *root) { struct fs_keystore_entry *ke; unsigned int i; for (i = 0; i < ARRAY_SIZE(keydb_types); i++) { const char *filename, *dirname; struct dirent *dirent; DIR *dir; dirname = talloc_asprintf(keystore, "%s/%s", root, keydb_types[i].name); dir = opendir(dirname); if (!dir) continue; for (dirent = readdir(dir); dirent; dirent = readdir(dir)) { if (dirent->d_name[0] == '.') continue; filename = talloc_asprintf(dirname, "%s/%s", keydb_types[i].name, dirent->d_name); if (keystore_contains_file(keystore, filename)) continue; ke = talloc(keystore, struct fs_keystore_entry); ke->name = filename; ke->root = root; ke->type = &keydb_types[i]; talloc_steal(ke, ke->name); if (keystore_entry_read(ke)) talloc_free(ke); else list_add(&keystore->keys, &ke->keystore_list); } closedir(dir); talloc_free(dirname); } return 0; } static int read_keystore(struct sync_context *ctx) { struct fs_keystore *keystore; unsigned int i; keystore = talloc(ctx, struct fs_keystore); list_head_init(&keystore->keys); for (i = 0; i < ctx->n_keystore_dirs; i++) { update_keystore(keystore, ctx->keystore_dirs[i]); } ctx->fs_keystore = keystore; return 0; } static void print_keystore(struct fs_keystore *keystore) { struct fs_keystore_entry *ke; printf("Filesystem keystore:\n"); list_for_each(&keystore->keys, ke, keystore_list) printf(" %s/%s [%zd bytes]\n", ke->root, ke->name, ke->len); } static int key_cmp(struct key *a, struct key *b) { if (a->id_len != b->id_len) return a->id_len - b->id_len; return memcmp(a->id, b->id, a->id_len); } /** * Finds the set-difference of the filesystem and firmware keys, and * populates ctx->new_keys with the keystore_entries that should be * inserted into firmware */ static int find_new_keys(struct sync_context *ctx) { struct { struct key_database *fs_kdb, *fw_kdb; } kdbs[] = { { &ctx->filesystem_keys->pk, &ctx->firmware_keys->pk }, { &ctx->filesystem_keys->kek, &ctx->firmware_keys->kek }, { &ctx->filesystem_keys->db, &ctx->firmware_keys->db }, { &ctx->filesystem_keys->dbx, &ctx->firmware_keys->dbx }, }; unsigned int i; int n = 0; for (i = 0; i < ARRAY_SIZE(kdbs); i++ ) { struct fs_keystore_entry *ke; struct key *fs_key, *fw_key; bool found; list_for_each(&kdbs[i].fs_kdb->keys, fs_key, list) { found = false; list_for_each(&kdbs[i].fw_kdb->keys, fw_key, list) { if (!key_cmp(fs_key, fw_key)) { found = true; break; } } if (found) continue; /* add the keystore entry if it's not already present */ found = false; list_for_each(&ctx->new_keys, ke, new_list) { if (fs_key->keystore_entry == ke) { found = true; break; } } if (found) continue; list_add(&ctx->new_keys, &fs_key->keystore_entry->new_list); n++; } } return n; } static void print_new_keys(struct sync_context *ctx) { struct fs_keystore_entry *ke; printf("New keys in filesystem:\n"); list_for_each(&ctx->new_keys, ke, new_list) printf(" %s/%s\n", ke->root, ke->name); } static int insert_key(struct sync_context *ctx, struct fs_keystore_entry *ke) { char guid_str[GUID_STRLEN]; char *efivars_filename; unsigned int buf_len; uint8_t *buf; int fd, rc; fd = -1; rc = -1; if (ctx->verbose) printf("Inserting key update %s/%s into %s\n", ke->root, ke->name, ke->type->name); /* we create a contiguous buffer of attributes & key data, so that * we write to the efivars file in a single syscall */ buf_len = sizeof(sigdb_attrs) + ke->len; buf = talloc_array(ke, uint8_t, buf_len); memcpy(buf, &sigdb_attrs, sizeof(sigdb_attrs)); memcpy(buf + sizeof(sigdb_attrs), ke->data, ke->len); guid_to_str(&ke->type->guid, guid_str); efivars_filename = talloc_asprintf(ke, "%s/%s-%s", ctx->efivars_dir, ke->type->name, guid_str); fd = open(efivars_filename, O_WRONLY | O_CREAT, 0600); if (fd < 0) { fprintf(stderr, "Can't create key file %s: %s\n", efivars_filename, strerror(errno)); goto out; } rc = write(fd, buf, buf_len); if (rc <= 0) { fprintf(stderr, "Error writing key update: %s\n", strerror(errno)); goto out; } if (rc != (int)buf_len) { fprintf(stderr, "Partial write during key update: " "wrote %d bytes, expecting %d\n", rc, buf_len); goto out; } rc = 0; out: if (fd >= 0) close(fd); talloc_free(efivars_filename); talloc_free(buf); if (rc) fprintf(stderr, "Error syncing keystore file %s/%s\n", ke->root, ke->name); return rc; } static int insert_new_keys(struct sync_context *ctx) { struct fs_keystore_entry *ke, *ke_pk; int pks, rc; rc = 0; pks = 0; ke_pk = NULL; list_for_each(&ctx->new_keys, ke, new_list) { /* we handle PK last */ if (ke->type == &keydb_types[KEYDB_PK]) { ke_pk = ke; pks++; continue; } if (insert_key(ctx, ke)) rc = -1; } if (rc) return rc; if (pks == 0 || !ctx->set_pk) return 0; if (pks > 1) { fprintf(stderr, "Skipping PK update due to mutiple PKs\n"); return -1; } rc = insert_key(ctx, ke_pk); return rc; } static struct keyset *init_keyset(struct sync_context *ctx) { struct keyset *keyset; keyset = talloc(ctx, struct keyset); list_head_init(&keyset->pk.keys); keyset->pk.type = &keydb_types[KEYDB_PK]; list_head_init(&keyset->kek.keys); keyset->kek.type = &keydb_types[KEYDB_KEK]; list_head_init(&keyset->db.keys); keyset->db.type = &keydb_types[KEYDB_DB]; list_head_init(&keyset->dbx.keys); keyset->dbx.type = &keydb_types[KEYDB_DBX]; return keyset; } static struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { "efivars-path", required_argument, NULL, 'e' }, { "verbose", no_argument, NULL, 'v' }, { "dry-run", no_argument, NULL, 'n' }, { "pk", no_argument, NULL, 'p' }, { "no-default-keystores", no_argument, NULL, 'd' }, { "keystore", required_argument, NULL, 'k' }, { NULL, 0, NULL, 0 }, }; static void usage(void) { printf("Usage: %s [options]\n" "Update EFI key databases from the filesystem\n" "\n" "Options:\n" "\t--efivars-path Path to efivars mountpoint\n" "\t (or regular directory for testing)\n" "\t--verbose Print verbose progress information\n" "\t--dry-run Don't update firmware key databases\n" "\t--pk Set PK\n" "\t--keystore Read keys from /{db,dbx,KEK}/*\n" "\t (can be specified multiple times,\n" "\t first dir takes precedence)\n" "\t--no-default-keystores\n" "\t Don't read keys from the default\n" "\t keystore dirs\n", toolname); } static void version(void) { printf("%s %s\n", toolname, VERSION); } static void add_keystore_dir(struct sync_context *ctx, const char *dir) { ctx->keystore_dirs = talloc_realloc(ctx, ctx->keystore_dirs, const char *, ++ctx->n_keystore_dirs); ctx->keystore_dirs[ctx->n_keystore_dirs - 1] = talloc_strdup(ctx->keystore_dirs, dir); } int main(int argc, char **argv) { bool use_default_keystore_dirs; struct sync_context *ctx; use_default_keystore_dirs = true; ctx = talloc_zero(NULL, struct sync_context); list_head_init(&ctx->new_keys); for (;;) { int idx, c; c = getopt_long(argc, argv, "e:dpkvhV", options, &idx); if (c == -1) break; switch (c) { case 'e': ctx->efivars_dir = optarg; break; case 'd': use_default_keystore_dirs = false; break; case 'k': add_keystore_dir(ctx, optarg); break; case 'p': ctx->set_pk = true; break; case 'v': ctx->verbose = true; break; case 'n': ctx->dry_run = true; break; case 'V': version(); return EXIT_SUCCESS; case 'h': usage(); return EXIT_SUCCESS; } } if (argc != optind) { usage(); return EXIT_FAILURE; } ERR_load_crypto_strings(); OpenSSL_add_all_digests(); OpenSSL_add_all_ciphers(); OPENSSL_config(NULL); /* here we may get highly unlikely failures or we'll get a * complaint about FIPS signatures (usually becuase the FIPS * module isn't present). In either case ignore the errors * (malloc will cause other failures out lower down */ ERR_clear_error(); ctx->filesystem_keys = init_keyset(ctx); ctx->firmware_keys = init_keyset(ctx); if (!ctx->efivars_dir) { ctx->efivars_dir = EFIVARS_MOUNTPOINT; if (check_efivars_mount(ctx->efivars_dir)) { fprintf(stderr, "Can't access efivars filesystem " "at %s, aborting\n", ctx->efivars_dir); return EXIT_FAILURE; } } if (use_default_keystore_dirs) { unsigned int i; for (i = 0; i < ARRAY_SIZE(default_keystore_dirs); i++) add_keystore_dir(ctx, default_keystore_dirs[i]); } read_keystore(ctx); if (ctx->verbose) print_keystore(ctx->fs_keystore); read_keysets(ctx); if (ctx->verbose) { print_keyset(ctx->firmware_keys, "firmware"); print_keyset(ctx->filesystem_keys, "filesystem"); } if (check_pk(ctx)) fprintf(stderr, "WARNING: multiple PKs found in filesystem\n"); find_new_keys(ctx); if (ctx->verbose) print_new_keys(ctx); if (!ctx->dry_run) insert_new_keys(ctx); talloc_free(ctx); return EXIT_SUCCESS; } sbsigntool-0.9.2/src/sbsiglist.c000066400000000000000000000151111342142174400166440ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "efivars.h" #include "fileio.h" static const char *toolname = "sbsiglist"; static struct option options[] = { { "output", required_argument, NULL, 'o' }, { "type", required_argument, NULL, 't' }, { "owner", required_argument, NULL, 'w' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 }, }; struct cert_type { const char *name; const EFI_GUID guid; unsigned int sigsize; }; struct cert_type cert_types[] = { { "x509", EFI_CERT_X509_GUID, 0 }, { "sha256", EFI_CERT_SHA256_GUID, 32 }, }; struct siglist_context { int verbose; const char *infilename; const char *outfilename; const struct cert_type *type; EFI_GUID owner; uint8_t *data; size_t data_len; EFI_SIGNATURE_LIST *siglist; }; void usage(void) { unsigned int i; printf("Usage: %s [options] --owner --type \n" "Create an EFI_SIGNATURE_LIST from a signature file\n" "Options:\n" "\t--owner Signature owner GUID\n" "\t--type Signature type. One of:\n", toolname); for (i = 0; i < ARRAY_SIZE(cert_types); i++) printf("\t %s\n", cert_types[i].name); printf("\t--output write signed data to \n" "\t (default .siglist)\n"); } static void version(void) { printf("%s %s\n", toolname, VERSION); } static int siglist_create(struct siglist_context *ctx) { EFI_SIGNATURE_LIST *siglist; EFI_SIGNATURE_DATA *sigdata; uint32_t size; if (ctx->type->sigsize && ctx->data_len != ctx->type->sigsize) { fprintf(stderr, "Error: signature lists of type '%s' expect " "%d bytes of data, " "%zd bytes provided.\n", ctx->type->name, ctx->type->sigsize, ctx->data_len); return -1; } size = sizeof(*siglist) + sizeof(*sigdata) + ctx->data_len; siglist = talloc_size(ctx, size); sigdata = (void *)(siglist + 1); siglist->SignatureType = ctx->type->guid; siglist->SignatureListSize = size; siglist->SignatureHeaderSize = 0; siglist->SignatureSize = ctx->data_len + sizeof(*sigdata); sigdata->SignatureOwner = ctx->owner; memcpy(sigdata->SignatureData, ctx->data, ctx->data_len); ctx->siglist = siglist; return 0; } static int parse_guid(const char *str, EFI_GUID *guid) { uuid_t uuid; if (uuid_parse(str, uuid)) return -1; /* convert to an EFI_GUID */ guid->Data1 = uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3]; guid->Data2 = uuid[4] << 8 | uuid[5]; guid->Data3 = uuid[6] << 8 | uuid[7]; memcpy(guid->Data4, &uuid[8], sizeof(guid->Data4)); return 0; } static struct cert_type *parse_type(const char *str) { unsigned int i; for (i = 0; i < ARRAY_SIZE(cert_types); i++) if (!strcasecmp(cert_types[i].name, str)) return &cert_types[i]; return NULL; } static void set_default_outfilename(struct siglist_context *ctx) { const char *extension = "siglist"; ctx->outfilename = talloc_asprintf(ctx, "%s.%s", ctx->infilename, extension); } int main(int argc, char **argv) { const char *type_str, *owner_guid_str; struct siglist_context *ctx; int c; ctx = talloc_zero(NULL, struct siglist_context); owner_guid_str = NULL; type_str = NULL; for (;;) { int idx; c = getopt_long(argc, argv, "o:t:w:ivVh", options, &idx); if (c == -1) break; switch (c) { case 'o': ctx->outfilename = optarg; break; case 't': type_str = optarg; break; case 'w': owner_guid_str = optarg; break; case 'v': ctx->verbose = 1; break; case 'V': version(); return EXIT_SUCCESS; case 'h': usage(); return EXIT_SUCCESS; } } if (argc != optind + 1) { usage(); return EXIT_FAILURE; } ctx->infilename = argv[optind]; if (!type_str) { fprintf(stderr, "No type specified\n"); usage(); return EXIT_FAILURE; } if (!type_str) { fprintf(stderr, "No owner specified\n"); usage(); return EXIT_FAILURE; } ctx->type = parse_type(type_str); if (!ctx->type) { fprintf(stderr, "Invalid type '%s'\n", type_str); return EXIT_FAILURE; } if (parse_guid(owner_guid_str, &ctx->owner)) { fprintf(stderr, "Invalid owner GUID '%s'\n", owner_guid_str); return EXIT_FAILURE; } if (!ctx->outfilename) set_default_outfilename(ctx); if (fileio_read_file(ctx, ctx->infilename, &ctx->data, &ctx->data_len)) { fprintf(stderr, "Can't read input file %s\n", ctx->infilename); return EXIT_FAILURE; } if (siglist_create(ctx)) return EXIT_FAILURE; if (fileio_write_file(ctx->outfilename, (void *)ctx->siglist, ctx->siglist->SignatureListSize)) { fprintf(stderr, "Can't write output file %s\n", ctx->outfilename); return EXIT_FAILURE; } return EXIT_SUCCESS; } sbsigntool-0.9.2/src/sbsign.c000066400000000000000000000145331342142174400161350ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "idc.h" #include "image.h" #include "fileio.h" static const char *toolname = "sbsign"; struct sign_context { struct image *image; const char *infilename; const char *outfilename; int verbose; int detached; }; static struct option options[] = { { "output", required_argument, NULL, 'o' }, { "cert", required_argument, NULL, 'c' }, { "key", required_argument, NULL, 'k' }, { "detached", no_argument, NULL, 'd' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { "engine", required_argument, NULL, 'e'}, { NULL, 0, NULL, 0 }, }; static void usage(void) { printf("Usage: %s [options] --key --cert " "\n" "Sign an EFI boot image for use with secure boot.\n\n" "Options:\n" "\t--engine use the specified engine to load the key\n" "\t--key signing key (PEM-encoded RSA " "private key)\n" "\t--cert certificate (x509 certificate)\n" "\t--detached write a detached signature, instead of\n" "\t a signed binary\n" "\t--output write signed data to \n" "\t (default .signed,\n" "\t or .pk7 for detached\n" "\t signatures)\n", toolname); } static void version(void) { printf("%s %s\n", toolname, VERSION); } static void set_default_outfilename(struct sign_context *ctx) { const char *extension; extension = ctx->detached ? "pk7" : "signed"; ctx->outfilename = talloc_asprintf(ctx, "%s.%s", ctx->infilename, extension); } int main(int argc, char **argv) { const char *keyfilename, *certfilename, *engine; struct sign_context *ctx; uint8_t *buf, *tmp; int rc, c, sigsize; EVP_PKEY *pkey; ctx = talloc_zero(NULL, struct sign_context); keyfilename = NULL; certfilename = NULL; engine = NULL; for (;;) { int idx; c = getopt_long(argc, argv, "o:c:k:dvVhe:", options, &idx); if (c == -1) break; switch (c) { case 'o': ctx->outfilename = talloc_strdup(ctx, optarg); break; case 'c': certfilename = optarg; break; case 'k': keyfilename = optarg; break; case 'd': ctx->detached = 1; break; case 'v': ctx->verbose = 1; break; case 'V': version(); return EXIT_SUCCESS; case 'h': usage(); return EXIT_SUCCESS; case 'e': engine = optarg; break; } } if (argc != optind + 1) { usage(); return EXIT_FAILURE; } ctx->infilename = argv[optind]; if (!ctx->outfilename) set_default_outfilename(ctx); if (!certfilename) { fprintf(stderr, "error: No certificate specified (with --cert)\n"); usage(); return EXIT_FAILURE; } if (!keyfilename) { fprintf(stderr, "error: No key specified (with --key)\n"); usage(); return EXIT_FAILURE; } ctx->image = image_load(ctx->infilename); if (!ctx->image) return EXIT_FAILURE; talloc_steal(ctx, ctx->image); ERR_load_crypto_strings(); OpenSSL_add_all_digests(); OpenSSL_add_all_ciphers(); OPENSSL_config(NULL); /* here we may get highly unlikely failures or we'll get a * complaint about FIPS signatures (usually becuase the FIPS * module isn't present). In either case ignore the errors * (malloc will cause other failures out lower down */ ERR_clear_error(); if (engine) pkey = fileio_read_engine_key(engine, keyfilename); else pkey = fileio_read_pkey(keyfilename); if (!pkey) return EXIT_FAILURE; X509 *cert = fileio_read_cert(certfilename); if (!cert) return EXIT_FAILURE; const EVP_MD *md = EVP_get_digestbyname("SHA256"); /* set up the PKCS7 object */ PKCS7 *p7 = PKCS7_new(); PKCS7_set_type(p7, NID_pkcs7_signed); PKCS7_SIGNER_INFO *si = PKCS7_sign_add_signer(p7, cert, pkey, md, PKCS7_BINARY); if (!si) { fprintf(stderr, "error in key/certificate chain\n"); ERR_print_errors_fp(stderr); return EXIT_FAILURE; } PKCS7_content_new(p7, NID_pkcs7_data); rc = IDC_set(p7, si, ctx->image); if (rc) return EXIT_FAILURE; sigsize = i2d_PKCS7(p7, NULL); tmp = buf = talloc_array(ctx->image, uint8_t, sigsize); i2d_PKCS7(p7, &tmp); ERR_print_errors_fp(stdout); image_add_signature(ctx->image, buf, sigsize); if (ctx->detached) { int i; uint8_t *buf; size_t len; for (i = 0; !image_get_signature(ctx->image, i, &buf, &len); i++) ; image_write_detached(ctx->image, i - 1, ctx->outfilename); } else image_write(ctx->image, ctx->outfilename); talloc_free(ctx); return EXIT_SUCCESS; } sbsigntool-0.9.2/src/sbvarsign.c000066400000000000000000000332451342142174400166470ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "efivars.h" #include "fileio.h" static const char *toolname = "sbvarsign"; struct varsign_context { const char *infilename; const char *outfilename; uint8_t *data; size_t data_len; CHAR16 *var_name; int var_name_bytes; EFI_GUID var_guid; uint32_t var_attrs; EVP_PKEY *key; X509 *cert; EFI_VARIABLE_AUTHENTICATION_2 *auth_descriptor; int auth_descriptor_len; EFI_TIME timestamp; int verbose; }; struct attr { const char *name; int value; }; #define EFI_VAR_ATTR(n) { #n, EFI_VARIABLE_ ## n } static struct attr attrs[] = { EFI_VAR_ATTR(NON_VOLATILE), EFI_VAR_ATTR(BOOTSERVICE_ACCESS), EFI_VAR_ATTR(RUNTIME_ACCESS), EFI_VAR_ATTR(TIME_BASED_AUTHENTICATED_WRITE_ACCESS), EFI_VAR_ATTR(APPEND_WRITE), }; static uint32_t default_attrs = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPEND_WRITE; static uint32_t attr_invalid = 0xffffffffu; static const char *attr_prefix = "EFI_VARIABLE_"; static const EFI_GUID default_guid = EFI_GLOBAL_VARIABLE; static const EFI_GUID cert_pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID; static void set_default_outfilename(struct varsign_context *ctx) { const char *extension = "signed"; ctx->outfilename = talloc_asprintf(ctx, "%s.%s", ctx->infilename, extension); } static uint32_t parse_single_attr(const char *attr_str) { unsigned int i; /* skip standard prefix, if present */ if (!strncmp(attr_str, attr_prefix, strlen(attr_prefix))) attr_str += strlen(attr_prefix); for (i = 0; i < ARRAY_SIZE(attrs); i++) { if (!strcmp(attr_str, attrs[i].name)) return attrs[i].value; } return attr_invalid; } static uint32_t parse_attrs(const char *attrs_str) { uint32_t attr, attrs_val; const char *attr_str; char *str; /* we always need E_V_T_B_A_W_A */ attrs_val = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; if (!attrs_str[0]) return attrs_val; str = strdup(attrs_str); for (attr_str = strtok(str, ","); attr_str; attr_str = strtok(NULL, ",")) { attr = parse_single_attr(attr_str); if (attr == attr_invalid) { fprintf(stderr, "Invalid attribute string %s\n", attr_str); return attr_invalid; } attrs_val |= attr; } return attrs_val; } static int set_varname(struct varsign_context *ctx, const char *str) { CHAR16 *wstr; int i, len; len = strlen(str); wstr = talloc_array(ctx, CHAR16, len); for (i = 0; i < len; i++) wstr[i] = str[i]; ctx->var_name = wstr; ctx->var_name_bytes = len * sizeof(CHAR16); return 0; } static int parse_guid(const char *str, EFI_GUID *guid) { uuid_t uuid; if (uuid_parse(str, uuid)) return -1; /* convert to an EFI_GUID */ guid->Data1 = uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3]; guid->Data2 = uuid[4] << 8 | uuid[5]; guid->Data3 = uuid[6] << 8 | uuid[7]; memcpy(guid->Data4, &uuid[8], sizeof(guid->Data4)); return 0; } static int set_timestamp(EFI_TIME *timestamp) { struct tm *tm; time_t t; time(&t); tm = gmtime(&t); if (!tm) { perror("gmtime"); return -1; } /* copy to our EFI-specific time structure. Other fields (Nanosecond, * TimeZone, Daylight and Pad) are defined to be zero */ memset(timestamp, 0, sizeof(*timestamp)); timestamp->Year = tm->tm_year; timestamp->Month = tm->tm_mon; timestamp->Day = tm->tm_mday; timestamp->Hour = tm->tm_hour; timestamp->Minute = tm->tm_min; timestamp->Second = tm->tm_sec; return 0; } static int add_auth_descriptor(struct varsign_context *ctx) { EFI_VARIABLE_AUTHENTICATION_2 *auth; int rc, len, flags; EFI_TIME timestamp; const EVP_MD *md; BIO *data_bio; uint8_t *tmp; PKCS7 *p7; if (set_timestamp(×tamp)) return -1; /* create a BIO for our variable data, containing: * * Variablename (not including trailing nul) * * VendorGUID * * Attributes * * TimeStamp * * Data */ data_bio = BIO_new(BIO_s_mem()); BIO_write(data_bio, ctx->var_name, ctx->var_name_bytes); BIO_write(data_bio, &ctx->var_guid, sizeof(ctx->var_guid)); BIO_write(data_bio, &ctx->var_attrs, sizeof(ctx->var_attrs)); BIO_write(data_bio, ×tamp, sizeof(timestamp)); BIO_write(data_bio, ctx->data, ctx->data_len); md = EVP_get_digestbyname("SHA256"); p7 = PKCS7_new(); flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOSMIMECAP;; PKCS7_set_type(p7, NID_pkcs7_signed); PKCS7_content_new(p7, NID_pkcs7_data); PKCS7_sign_add_signer(p7, ctx->cert, ctx->key, md, flags); PKCS7_set_detached(p7, 1); rc = PKCS7_final(p7, data_bio, flags); if (!rc) { fprintf(stderr, "Error signing variable data\n"); ERR_print_errors_fp(stderr); BIO_free_all(data_bio); return -1; } len = i2d_PKCS7_SIGNED(p7->d.sign, NULL); /* set up our auth descriptor */ auth = talloc_size(ctx, sizeof(*auth) + len); auth->TimeStamp = timestamp; auth->AuthInfo.Hdr.dwLength = len + sizeof(auth->AuthInfo); auth->AuthInfo.Hdr.wRevision = 0x0200; auth->AuthInfo.Hdr.wCertificateType = 0x0EF1; auth->AuthInfo.CertType = cert_pkcs7_guid; tmp = auth->AuthInfo.CertData; i2d_PKCS7_SIGNED(p7->d.sign, &tmp); ctx->auth_descriptor = auth; ctx->auth_descriptor_len = sizeof(*auth) + len; BIO_free_all(data_bio); return 0; } int write_signed(struct varsign_context *ctx, int include_attrs) { int fd, rc; fd = open(ctx->outfilename, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror("open"); goto err; } /* For some uses (eg, writing to the efivars filesystem), we may * want to prefix the signed variable with four bytes of attribute * data */ if (include_attrs) { rc = write_all(fd, &ctx->var_attrs, sizeof(ctx->var_attrs)); if (!rc) { perror("write_all"); goto err; } } /* Write the authentication descriptor */ rc = write_all(fd, ctx->auth_descriptor, ctx->auth_descriptor_len); if (!rc) { perror("write_all"); goto err; } /* ... and the variable data itself */ rc = write_all(fd, ctx->data, ctx->data_len); if (!rc) { perror("write_all"); goto err; } if (ctx->verbose) { size_t i = 0; printf("Wrote signed data:\n"); if (include_attrs) { i = sizeof(ctx->var_attrs); printf(" [%04zx:%04zx] attrs\n", 0l, i); } printf(" [%04zx:%04x] authentication descriptor\n", i, ctx->auth_descriptor_len); printf(" [%04zx:%04zx] EFI_VAR_AUTH_2 header\n", i, sizeof(EFI_VARIABLE_AUTHENTICATION_2)); printf(" [%04zx:%04zx] WIN_CERT_UEFI_GUID header\n", i + offsetof(EFI_VARIABLE_AUTHENTICATION_2, AuthInfo), sizeof(WIN_CERTIFICATE_UEFI_GUID)); printf(" [%04zx:%04zx] WIN_CERT header\n", i + offsetof(EFI_VARIABLE_AUTHENTICATION_2, AuthInfo.Hdr), sizeof(WIN_CERTIFICATE)); printf(" [%04zx:%04zx] pkcs7 data\n", i + offsetof(EFI_VARIABLE_AUTHENTICATION_2, AuthInfo.CertData), ctx->auth_descriptor_len - sizeof(EFI_VARIABLE_AUTHENTICATION_2)); i += ctx->auth_descriptor_len; printf(" [%04zx:%04zx] variable data\n", i, i + ctx->data_len); } close(fd); return 0; err: fprintf(stderr, "Can't write signed data to file '%s'\n", ctx->outfilename); if (fd >= 0) close(fd); return -1; } static void set_default_guid(struct varsign_context *ctx, const char *varname) { EFI_GUID secdb_guid = EFI_IMAGE_SECURITY_DATABASE_GUID; EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; if (!strcmp(varname, "db") || !strcmp(varname, "dbx")) ctx->var_guid = secdb_guid; else ctx->var_guid = global_guid; } static struct option options[] = { { "output", required_argument, NULL, 'o' }, { "guid", required_argument, NULL, 'g' }, { "attrs", required_argument, NULL, 'a' }, { "key", required_argument, NULL, 'k' }, { "cert", required_argument, NULL, 'c' }, { "include-attrs", no_argument, NULL, 'i' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { "engine", required_argument, NULL, 'e'}, { NULL, 0, NULL, 0 }, }; void usage(void) { unsigned int i; printf("Usage: %s [options] --key --cert " " \n" "Sign a blob of data for use in SetVariable().\n\n" "Options:\n" "\t--engine use the specified engine to load the key\n" "\t--key signing key (PEM-encoded RSA " "private key)\n" "\t--cert certificate (x509 certificate)\n" "\t--include-attrs include attrs at beginning of output file\n" "\t--guid EFI GUID for the variable. If omitted,\n" "\t EFI_IMAGE_SECURITY_DATABASE or\n" "\t EFI_GLOBAL_VARIABLE (depending on\n" "\t ) will be used.\n" "\t--attr variable attributes. One or more of:\n", toolname); for (i = 0; i < ARRAY_SIZE(attrs); i++) printf("\t %s\n", attrs[i].name); printf("\t Separate multiple attrs with a comma,\n" "\t default is all attributes,\n" "\t TIME_BASED_AUTH... is always included.\n" "\t--output write signed data to \n" "\t (default .signed)\n"); } static void version(void) { printf("%s %s\n", toolname, VERSION); } int main(int argc, char **argv) { const char *guid_str, *attr_str, *varname, *engine; const char *keyfilename, *certfilename; struct varsign_context *ctx; bool include_attrs; int c; ctx = talloc_zero(NULL, struct varsign_context); keyfilename = NULL; certfilename = NULL; engine = NULL; guid_str = NULL; attr_str= NULL; include_attrs = false; for (;;) { int idx; c = getopt_long(argc, argv, "o:g:a:k:c:ivVhe:", options, &idx); if (c == -1) break; switch (c) { case 'o': ctx->outfilename = optarg; break; case 'g': guid_str = optarg; break; case 'a': attr_str = optarg; break; case 'k': keyfilename = optarg; break; case 'c': certfilename = optarg; break; case 'i': include_attrs = true; break; case 'v': ctx->verbose = 1; break; case 'V': version(); return EXIT_SUCCESS; case 'h': usage(); return EXIT_SUCCESS; case 'e': engine = optarg; break; } } if (argc != optind + 2) { usage(); return EXIT_FAILURE; } if (!keyfilename) { fprintf(stderr, "No signing key specified\n"); return EXIT_FAILURE; } if (!certfilename) { fprintf(stderr, "No signing certificate specified\n"); return EXIT_FAILURE; } /* initialise openssl */ OpenSSL_add_all_digests(); OpenSSL_add_all_ciphers(); ERR_load_crypto_strings(); OPENSSL_config(NULL); /* here we may get highly unlikely failures or we'll get a * complaint about FIPS signatures (usually becuase the FIPS * module isn't present). In either case ignore the errors * (malloc will cause other failures out lower down */ ERR_clear_error(); /* set up the variable signing context */ varname = argv[optind]; set_varname(ctx, varname); ctx->infilename = argv[optind+1]; if (!ctx->outfilename) set_default_outfilename(ctx); if (attr_str) { ctx->var_attrs = parse_attrs(attr_str); if (ctx->var_attrs == attr_invalid) return EXIT_FAILURE; } else { ctx->var_attrs = default_attrs; } if (guid_str) { if (parse_guid(guid_str, &ctx->var_guid)) { fprintf(stderr, "Invalid GUID '%s'\n", guid_str); return EXIT_FAILURE; } } else { set_default_guid(ctx, varname); } if (fileio_read_file(ctx, ctx->infilename, &ctx->data, &ctx->data_len)) return EXIT_FAILURE; if (engine) ctx->key = fileio_read_engine_key(engine, keyfilename); else ctx->key = fileio_read_pkey(keyfilename); if (!ctx->key) return EXIT_FAILURE; ctx->cert = fileio_read_cert(certfilename); if (!ctx->cert) return EXIT_FAILURE; /* do the signing */ if (add_auth_descriptor(ctx)) return EXIT_FAILURE; /* write the resulting image */ if (write_signed(ctx, include_attrs)) return EXIT_FAILURE; return EXIT_SUCCESS; } sbsigntool-0.9.2/src/sbverify.c000066400000000000000000000233021342142174400164730ustar00rootroot00000000000000/* * Copyright (C) 2012 Jeremy Kerr * * 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 3 * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the OpenSSL * library under certain conditions as described in each individual source file, * and distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all * of the code used other than OpenSSL. If you modify file(s) with this * exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do * so, delete this exception statement from your version. If you delete * this exception statement from all source files in the program, then * also delete it here. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "image.h" #include "idc.h" #include "fileio.h" #include #include #include #include #include #include #include #if OPENSSL_VERSION_NUMBER < 0x10100000L #define X509_OBJECT_get0_X509(obj) ((obj)->data.x509) #define X509_OBJECT_get_type(obj) ((obj)->type) #define X509_STORE_CTX_get0_cert(ctx) ((ctx)->cert) #define X509_STORE_get0_objects(certs) ((certs)->objs) #define X509_get_extended_key_usage(cert) ((cert)->ex_xkusage) #if OPENSSL_VERSION_NUMBER < 0x10020000L #define X509_STORE_CTX_get0_store(ctx) ((ctx)->ctx) #endif #endif static const char *toolname = "sbverify"; static const int cert_name_len = 160; enum verify_status { VERIFY_FAIL = 0, VERIFY_OK = 1, }; static struct option options[] = { { "cert", required_argument, NULL, 'c' }, { "list", no_argument, NULL, 'l' }, { "detached", required_argument, NULL, 'd' }, { "verbose", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 }, }; static void usage(void) { printf("Usage: %s [options] --cert \n" "Verify a UEFI secure boot image.\n\n" "Options:\n" "\t--cert certificate (x509 certificate)\n" "\t--list list all signatures (but don't verify)\n" "\t--detached read signature from , instead of\n" "\t looking for an embedded signature\n", toolname); } static void version(void) { printf("%s %s\n", toolname, VERSION); } int load_cert(X509_STORE *certs, const char *filename) { X509 *cert; cert = fileio_read_cert(filename); if (!cert) return -1; X509_STORE_add_cert(certs, cert); return 0; } static void print_signature_info(PKCS7 *p7) { char subject_name[cert_name_len + 1], issuer_name[cert_name_len + 1]; PKCS7_SIGNER_INFO *si; X509 *cert; int i; printf("image signature issuers:\n"); for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(p7->d.sign->signer_info); i++) { si = sk_PKCS7_SIGNER_INFO_value(p7->d.sign->signer_info, i); X509_NAME_oneline(si->issuer_and_serial->issuer, issuer_name, cert_name_len); printf(" - %s\n", issuer_name); } printf("image signature certificates:\n"); for (i = 0; i < sk_X509_num(p7->d.sign->cert); i++) { cert = sk_X509_value(p7->d.sign->cert, i); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, cert_name_len); X509_NAME_oneline(X509_get_issuer_name(cert), issuer_name, cert_name_len); printf(" - subject: %s\n", subject_name); printf(" issuer: %s\n", issuer_name); } } static void print_certificate_store_certs(X509_STORE *certs) { char subject_name[cert_name_len + 1], issuer_name[cert_name_len + 1]; STACK_OF(X509_OBJECT) *objs; X509_OBJECT *obj; X509 *cert; int i; printf("certificate store:\n"); objs = X509_STORE_get0_objects(certs); for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { obj = sk_X509_OBJECT_value(objs, i); if (X509_OBJECT_get_type(obj) != X509_LU_X509) continue; cert = X509_OBJECT_get0_X509(obj); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, cert_name_len); X509_NAME_oneline(X509_get_issuer_name(cert), issuer_name, cert_name_len); printf(" - subject: %s\n", subject_name); printf(" issuer: %s\n", issuer_name); } } static int load_detached_signature_data(struct image *image, const char *filename, uint8_t **buf, size_t *len) { return fileio_read_file(image, filename, buf, len); } static int cert_in_store(X509 *cert, X509_STORE_CTX *ctx) { STACK_OF(X509_OBJECT) *objs; X509_OBJECT *obj; int i; objs = X509_STORE_get0_objects(X509_STORE_CTX_get0_store(ctx)); for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { obj = sk_X509_OBJECT_value(objs, i); if (X509_OBJECT_get_type(obj) == X509_LU_X509 && !X509_cmp(X509_OBJECT_get0_X509(obj), cert)) return 1; } return 0; } static int x509_verify_cb(int status, X509_STORE_CTX *ctx) { int err = X509_STORE_CTX_get_error(ctx); /* also accept code-signing keys */ if (err == X509_V_ERR_INVALID_PURPOSE && X509_get_extended_key_usage(X509_STORE_CTX_get0_cert(ctx)) == XKU_CODE_SIGN) status = 1; else if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || err == X509_V_ERR_CERT_UNTRUSTED || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT || err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) { /* all certs given with the --cert argument are trusted */ if (cert_in_store(X509_STORE_CTX_get_current_cert(ctx), ctx)) status = 1; } else if (err == X509_V_ERR_CERT_HAS_EXPIRED || err == X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD || err == X509_V_ERR_CERT_NOT_YET_VALID || err == X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD) /* UEFI explicitly allows expired certificates */ status = 1; return status; } int main(int argc, char **argv) { const char *detached_sig_filename, *image_filename; enum verify_status status; int rc, c, flags, list; const uint8_t *tmp_buf; struct image *image; X509_STORE *certs; uint8_t *sig_buf; size_t sig_size; struct idc *idc; bool verbose; BIO *idcbio; PKCS7 *p7; int sig_count = 0; status = VERIFY_FAIL; certs = X509_STORE_new(); list = 0; verbose = false; detached_sig_filename = NULL; OpenSSL_add_all_digests(); ERR_load_crypto_strings(); OPENSSL_config(NULL); /* here we may get highly unlikely failures or we'll get a * complaint about FIPS signatures (usually becuase the FIPS * module isn't present). In either case ignore the errors * (malloc will cause other failures out lower down */ ERR_clear_error(); for (;;) { int idx; c = getopt_long(argc, argv, "c:d:lvVh", options, &idx); if (c == -1) break; switch (c) { case 'c': rc = load_cert(certs, optarg); if (rc) return EXIT_FAILURE; break; case 'd': detached_sig_filename = optarg; break; case 'l': list = 1; break; case 'v': verbose = true; break; case 'V': version(); return EXIT_SUCCESS; case 'h': usage(); return EXIT_SUCCESS; } } if (argc != optind + 1) { usage(); return EXIT_FAILURE; } image_filename = argv[optind]; image = image_load(image_filename); if (!image) { fprintf(stderr, "Can't open image %s\n", image_filename); return EXIT_FAILURE; } for (;;) { if (detached_sig_filename) { if (sig_count++) break; rc = load_detached_signature_data(image, detached_sig_filename, &sig_buf, &sig_size); } else rc = image_get_signature(image, sig_count++, &sig_buf, &sig_size); if (rc) { if (sig_count == 0) { fprintf(stderr, "Unable to read signature data from %s\n", detached_sig_filename ? : image_filename); } break; } tmp_buf = sig_buf; if (verbose || list) printf("signature %d\n", sig_count); p7 = d2i_PKCS7(NULL, &tmp_buf, sig_size); if (!p7) { fprintf(stderr, "Unable to parse signature data\n"); ERR_print_errors_fp(stderr); break; } if (verbose || list) { print_signature_info(p7); //print_certificate_store_certs(certs); } if (list) continue; idcbio = BIO_new(BIO_s_mem()); idc = IDC_get(p7, idcbio); if (!idc) { fprintf(stderr, "Unable to get IDC from PKCS7\n"); break; } rc = IDC_check_hash(idc, image); if (rc) { fprintf(stderr, "Image fails hash check\n"); break; } flags = PKCS7_BINARY; /* OpenSSL 1.0.2e no longer allows calling PKCS7_verify with * both data and content. Empty out the content. */ p7->d.sign->contents->d.ptr = NULL; X509_STORE_set_verify_cb_func(certs, x509_verify_cb); rc = PKCS7_verify(p7, NULL, certs, idcbio, NULL, flags); if (rc) { if (verbose) printf("PKCS7 verification passed\n"); status = VERIFY_OK; } else if (verbose) { printf("PKCS7 verification failed\n"); ERR_print_errors_fp(stderr); } } talloc_free(image); if (list) exit(EXIT_SUCCESS); if (status == VERIFY_OK) printf("Signature verification OK\n"); else printf("Signature verification failed\n"); return status == VERIFY_OK ? EXIT_SUCCESS : EXIT_FAILURE; } sbsigntool-0.9.2/src/verify.c000066400000000000000000000001671342142174400161520ustar00rootroot00000000000000 #include #include #include "image.h" int main(int argc, char **argv) { return EXIT_SUCCESS; } sbsigntool-0.9.2/tests/000077500000000000000000000000001342142174400150515ustar00rootroot00000000000000sbsigntool-0.9.2/tests/Makefile.am000066400000000000000000000033751342142174400171150ustar00rootroot00000000000000 AUTOMAKE_OPTIONS = parallel-tests test_key = private-key.rsa test_cert = public-cert.pem test_arches = $(EFI_ARCH) check_PROGRAMS = test.pecoff # override the automake rule to say we build from .elf files test.pecoff$(EXEEXT): test.elf if TEST_BINARY_FORMAT EFILDFLAGS = --defsym=EFI_SUBSYSTEM=0x0a FORMAT = -O binary else FORMAT = --target=efi-app-$(EFI_ARCH) endif check_DATA = $(test_key) $(test_cert) check_SCRIPTS = test-wrapper.sh .elf.pecoff: echo "TEST ARCHES $(test_arches) TEST_COMPAT=$(TEST_COMPAT_FALSE)" $(OBJCOPY) -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel \ -j .rela -j .reloc \ $(FORMAT) $^ $@ .$(OBJEXT).elf: $(LD) $(EFILDFLAGS) -nostdlib -L /usr/lib -L /usr/lib64 -L $(CRTPATH) -shared -Bsymbolic $(CRTPATH)/crt0-efi-$(EFI_ARCH).o -T elf_$(EFI_ARCH)_efi.lds $< -o $@ -lefi -lgnuefi AM_CFLAGS=-fpic -I/usr/include/efi -I/usr/include/efi/$(EFI_ARCH) $(test_key): Makefile openssl genrsa -out $@ 2048 $(test_cert): $(test_key) Makefile openssl req -x509 -sha256 -subj '/' -new -key $< -out $@ TESTS = sign-verify.sh \ sign-verify-detached.sh \ sign-detach-verify.sh \ sign-attach-verify.sh \ sign-missing-image.sh \ sign-missing-cert.sh \ sign-missing-key.sh \ verify-missing-image.sh \ verify-missing-cert.sh \ sign-invalidattach-verify.sh \ resign-warning.sh \ reattach-warning.sh if !TEST_BINARY_FORMAT ## # These tests involve objdump which will fail because the format # is not recognised. Someone needs to fix arm bfd to add efi ## TESTS += cert-table-header.sh \ detach-remove.sh endif TEST_EXTENSIONS = .sh AM_TESTS_ENVIRONMENT = TEST_ARCHES='$(test_arches)'; export TEST_ARCHES; SH_LOG_COMPILER = $(srcdir)/test-wrapper.sh EXTRA_DIST = test.S $(TESTS) $(check_SCRIPTS) CLEANFILES = $(test_key) $(test_cert) sbsigntool-0.9.2/tests/cert-table-header.sh000077500000000000000000000033361342142174400206650ustar00rootroot00000000000000#!/bin/bash -e # Parse the data directory of a PE/COFF file and returns two hex values: # the file offset and size of the signature table. function sigtable_params() { filename="$1" objdump -p "$filename" | awk '/^Entry 4/ {print "0x"$3 " " "0x"$4}' } # Extract the signature from a file containing a signature table, # and write to stdout function extract_sig() { filename="$1" cert_table_header_size=8 params=($(hexdump -n$cert_table_header_size \ -e '/4 "%u " /2 "%04x " /2 "%04x\n"' \ "$filename")) cert_size=${params[0]} cert_revision=${params[1]} cert_type=${params[2]} # check type & revision [ "$cert_revision" -eq '0200' ] [ "$cert_type" -eq '0002' ] dd if="$filename" bs=1 skip=$cert_table_header_size \ count=$(($cert_size - $cert_table_header_size)) 2>/dev/null } function repeat() { str=$1 count=$2 for (( i = 0; $i < $count; i++ )) do echo -n "$str" done } cert="test.cert" signed="test.signed" for i in {1..8} do # generate a variable-length parameter for the certificate subject subj="/CN=$(repeat 'x' $i)" # create a temporary cert, and sign the image with it openssl req -x509 -sha256 -subj "$subj" -new -key "$key" -out "$cert" "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" # extract the sigtable params=($(sigtable_params "$signed")) # split and convert to base-10 sigtable_offset=$((${params[0]})) sigtable_size=$((${params[1]})) # check that we have a correctly-padded sigtable [ $(($sigtable_size % 8)) -eq 0 ] sigtable='test.sigtable' dd if="$signed" bs=1 skip=$sigtable_offset count=$sigtable_size \ of=$sigtable 2>/dev/null # extract sig, and feed to openssl's PKCS7 parser extract_sig "$sigtable" | openssl pkcs7 -inform DER -noout done sbsigntool-0.9.2/tests/detach-remove.sh000077500000000000000000000011411342142174400201300ustar00rootroot00000000000000#!/bin/bash -ex signed="test.signed" unsigned="test.unsigned" "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" cp "$signed" "$unsigned" "$sbattach" --remove "$unsigned" # ensure that there is no security directory objdump -p $unsigned | grep -q '0\+ 0\+ Security Directory' ## # somewhat tricky: i386 pecoff binaries can be too short, so we add padding # when signing, so make sure the sizes match modulo the padding ## # ensure that the unsigned file is the same size as our original binary [ $(( ($(stat --format=%s "$image")+7)&~7)) -eq $(( ($(stat --format=%s "$unsigned")+7)&~7)) ] sbsigntool-0.9.2/tests/reattach-warning.sh000077500000000000000000000006451342142174400206530ustar00rootroot00000000000000#!/bin/bash -e ## # The original warning is gone because we now do multiple signatures # instead check that the second signature is added ## signed="test.signed" sig="test.sig" "$sbsign" --cert "$cert" --key "$key" --detached --output "$sig" "$image" cp "$image" "$signed" "$sbattach" --attach "$sig" "$signed" "$sbattach" --attach "$sig" "$signed" 2>&1 | grep '^Image was already signed; adding additional signature' sbsigntool-0.9.2/tests/resign-warning.sh000077500000000000000000000005571342142174400203510ustar00rootroot00000000000000#!/bin/bash -e ## # The original warning is gone because we now do multiple signatures # instead check that the second signature is added ## signed="test.signed" "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$signed" 2>&1 | grep '^Image was already signed; adding additional signature' sbsigntool-0.9.2/tests/sign-attach-verify.sh000077500000000000000000000003401342142174400211110ustar00rootroot00000000000000#!/bin/bash -e sig="test.sig" signed="test.signed" "$sbsign" --cert "$cert" --key "$key" --detached --output "$sig" "$image" cp "$image" "$signed" "$sbattach" --attach "$sig" "$signed" "$sbverify" --cert "$cert" "$signed" sbsigntool-0.9.2/tests/sign-detach-verify.sh000077500000000000000000000003211342142174400210740ustar00rootroot00000000000000#!/bin/bash -e signed="test.signed" sig="test.sig" "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" "$sbattach" --detach "$sig" "$signed" "$sbverify" --cert "$cert" --detached $sig "$image" sbsigntool-0.9.2/tests/sign-invalidattach-verify.sh000077500000000000000000000003201342142174400224560ustar00rootroot00000000000000#!/bin/bash -e invsig="test.invsig" dd if=/dev/zero of="$invsig" bs=1 count=1k tmp_image=test.pecoff cp "$image" "$tmp_image" set +e "$sbattach" --attach "$invsig" "$tmp_image" rc=$? set -e test $rc -eq 1 sbsigntool-0.9.2/tests/sign-missing-cert.sh000077500000000000000000000002231342142174400207470ustar00rootroot00000000000000#!/bin/bash -e signed="test.signed" set +e "$sbsign" --cert "missing-cert" --key "$key" --output "$signed" "$image" rc=$? set -e test $rc -eq 1 sbsigntool-0.9.2/tests/sign-missing-image.sh000077500000000000000000000002231342142174400210740ustar00rootroot00000000000000#!/bin/bash -e signed="test.signed" set +e "$sbsign" --cert "$cert" --key "$key" --output "$signed" "missing-image" rc=$? set -e test $rc -eq 1 sbsigntool-0.9.2/tests/sign-missing-key.sh000077500000000000000000000002231342142174400206020ustar00rootroot00000000000000#!/bin/bash -e signed="test.signed" set +e "$sbsign" --cert "$cert" --key "missing-key" --output "$signed" "$image" rc=$? set -e test $rc -eq 1 sbsigntool-0.9.2/tests/sign-verify-detached.sh000077500000000000000000000002341342142174400214100ustar00rootroot00000000000000#!/bin/bash -e sig="test.sig" "$sbsign" --cert "$cert" --key "$key" --detached --output $sig "$image" "$sbverify" --cert "$cert" --detached $sig "$image" sbsigntool-0.9.2/tests/sign-verify.sh000077500000000000000000000002151342142174400176500ustar00rootroot00000000000000#!/bin/bash -e signed="test.signed" "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" "$sbverify" --cert "$cert" "$signed" sbsigntool-0.9.2/tests/test-wrapper.sh000077500000000000000000000016321342142174400200470ustar00rootroot00000000000000#!/bin/bash # set a few global variables that may be used by the test basedir=$(cd $srcdir && pwd) datadir=$(pwd) bindir="$datadir/../src" sbsign=$bindir/sbsign sbverify=$bindir/sbverify sbattach=$bindir/sbattach key="$datadir/private-key.rsa" cert="$datadir/public-cert.pem" export basedir datadir bindir sbsign sbverify sbattach key cert # 'test' needs to be an absolute path, as we will cd to a temporary # directory before running the test test="$PWD/$1" rc=0 function run_test() { test="$1" # image depends on the test arch image="$datadir/test.pecoff" export image # create the temporary directory... tempdir=$(mktemp --directory) # ... and run the test in it. ( cd "$tempdir"; $test ) if [ $? -ne 0 ] then echo "test $(basename $test) failed on arch $arch" echo rc=1 fi rm -rf "$tempdir" } # run test on all available arches for arch in $TEST_ARCHES do run_test $test done exit $rc sbsigntool-0.9.2/tests/test.c000066400000000000000000000002001342142174400161640ustar00rootroot00000000000000#include #include EFI_STATUS efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) { return EFI_SUCCESS; } sbsigntool-0.9.2/tests/verify-missing-cert.sh000077500000000000000000000002711342142174400213160ustar00rootroot00000000000000#!/bin/bash -e signed="test.signed" "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" set +e "$sbverify" --cert "missing-cert" "$signed" rc=$? set -e test $rc -eq 1 sbsigntool-0.9.2/tests/verify-missing-image.sh000077500000000000000000000001461342142174400214440ustar00rootroot00000000000000#!/bin/bash -e signed="test.signed" set +e "$sbverify" "missing-image" rc=$? set -e test $rc -eq 1