=== removed directory '.bzr-builddeb'
=== removed file '.bzr-builddeb/default.conf'
--- .bzr-builddeb/default.conf 2008-09-17 00:34:09 +0000
+++ .bzr-builddeb/default.conf 1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
-[BUILDDEB]
-split = True
=== removed file '.bzrignore'
--- .bzrignore 2019-07-27 10:11:45 +0000
+++ .bzrignore 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
-*.5
-*.8
-*.8mandos
-confdir
-keydir
-statedir
-man
-plugin-runner
-plugins.d/askpass-fifo
-plugins.d/mandos-client
-plugins.d/password-prompt
-plugins.d/splashy
-plugins.d/usplash
-plugins.d/plymouth
-plugin-helpers/mandos-client-iprouteadddel
-dracut-module/password-agent
-.tramp_history
=== removed file 'COPYING'
--- COPYING 2008-08-15 20:17:32 +0000
+++ COPYING 1970-01-01 00:00:00 +0000
@@ -1,676 +0,0 @@
-
- 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
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 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, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
-
=== removed file 'DBUS-API'
--- DBUS-API 2019-02-10 04:20:26 +0000
+++ DBUS-API 1970-01-01 00:00:00 +0000
@@ -1,155 +0,0 @@
- -*- mode: org; coding: utf-8 -*-
-
- Mandos Server D-Bus Interface
-
-This file documents the D-Bus interface to the Mandos server.
-
-* Bus: System bus
- Bus name: "se.recompile.Mandos"
-
-
-* Object Paths:
-
- | Path | Object |
- |-----------------------+-------------------|
- | "/" | The Mandos Server |
-
- (To get a list of paths to client objects, use the standard D-Bus
- org.freedesktop.DBus.ObjectManager interface, which the server
- object supports.)
-
-
-* Mandos Server Interface:
- Interface name: "se.recompile.Mandos"
-
-** Methods:
-*** RemoveClient(o: ObjectPath) → nothing
- Removes a client
-
-** Signals:
-*** ClientNotFound(s: KeyID, s: Address)
- A client connected from Address using KeyID, but was
- rejected because it was not found in the server. The key ID
- is represented as a string of hexadecimal digits. The address is
- an IPv4 or IPv6 address in its normal string format.
-
-
-* Mandos Client Interface:
- Interface name: "se.recompile.Mandos.Client"
-
-** Methods
-*** Approve(b: Approve) → nothing
- Approve or deny a connected client waiting for approval. If
- denied, a client will not be sent its secret.
-
-*** CheckedOK() → nothing
- Assert that this client has been checked and found to be alive.
- This will restart the timeout before disabling this client. See
- also the "LastCheckedOK" property.
-
-** Properties
-
- Note: Many of these properties directly correspond to a setting in
- "clients.conf", in which case they are fully documented in
- mandos-clients.conf(5).
-
- | Name | Type | Access | clients.conf |
- |-------------------------+------+------------+---------------------|
- | ApprovedByDefault | b | Read/Write | approved_by_default |
- | ApprovalDelay (a) | t | Read/Write | approval_delay |
- | ApprovalDuration (a) | t | Read/Write | approval_duration |
- | ApprovalPending (b) | b | Read | N/A |
- | Checker | s | Read/Write | checker |
- | CheckerRunning (c) | b | Read/Write | N/A |
- | Created (d) | s | Read | N/A |
- | Enabled (e) | b | Read/Write | N/A |
- | Expires (f) | s | Read | N/A |
- | ExtendedTimeout (a) | t | Read/Write | extended_timeout |
- | Fingerprint | s | Read | fingerprint |
- | KeyID | s | Read | key_id |
- | Host | s | Read/Write | host |
- | Interval (a) | t | Read/Write | interval |
- | LastApprovalRequest (g) | s | Read | N/A |
- | LastCheckedOK (h) | s | Read/Write | N/A |
- | LastCheckerStatus (i) | n | Read | N/A |
- | LastEnabled (j) | s | Read | N/A |
- | Name | s | Read | (Section name) |
- | Secret (k) | ay | Write | secret (or secfile) |
- | Timeout (a) | t | Read/Write | timeout |
-
- a) Represented as milliseconds.
-
- b) An approval is currently pending.
-
- c) Changing this property can either start a new checker or abort a
- running one.
-
- d) The creation time of this client object, as an RFC 3339 string.
-
- e) Changing this property enables or disables a client.
-
- f) The date and time this client will be disabled, as an RFC 3339
- string, or an empty string if this is not scheduled.
-
- g) The date and time of the last approval request, as an RFC 3339
- string, or an empty string if this has not happened.
-
- h) The date and time a checker was last successful, as an RFC 3339
- string, or an empty string if this has not happened. Setting
- this property is equivalent to calling CheckedOK(), i.e. the
- current time is set, regardless of the string sent. Please
- always use an empty string when setting this property, to allow
- for possible future expansion.
-
- i) The exit status of the last checker, -1 if it did not exit
- cleanly, -2 if a checker has not yet returned.
-
- j) The date and time this client was last enabled, as an RFC 3339
- string, or an empty string if this has not happened.
-
- k) A raw byte array, not hexadecimal digits.
-
-** Signals
-*** CheckerCompleted(n: Exitcode, x: Waitstatus, s: Command)
- A checker (Command) has completed. Exitcode is either the exit
- code or -1 for abnormal exit. In any case, the full Waitstatus
- (as from wait(2)) is also available.
-
-*** CheckerStarted(s: Command)
- A checker command (Command) has just been started.
-
-*** GotSecret()
- This client has been sent its secret.
-
-*** NeedApproval(t: Timeout, b: ApprovedByDefault)
- This client will be approved or denied in exactly Timeout
- milliseconds, depending on ApprovedByDefault. Approve() can now
- usefully be called on this client object.
-
-*** Rejected(s: Reason)
- This client was not given its secret for a specified Reason.
-
-* Copyright
-
- Copyright © 2010-2019 Teddy Hogeborn
- Copyright © 2010-2019 Björn Påhlsson
-
-** License:
-
- This file is part of Mandos.
-
- Mandos 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.
-
- Mandos 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 Mandos. If not, see .
-
-
-#+STARTUP: showall
=== removed file 'INSTALL'
--- INSTALL 2019-11-03 19:17:57 +0000
+++ INSTALL 1970-01-01 00:00:00 +0000
@@ -1,157 +0,0 @@
--*- org -*-
-
-* Prerequisites
-
-** Operating System
-
- Debian 8.0 "jessie" or Ubuntu 15.10 "Wily Werewolf" (or later).
-
- This is mostly for the support scripts which make sure that the
- client is installed and started in the initial RAM disk environment
- and that the initial RAM file system image file is automatically
- made unreadable. The server and client programs themselves *could*
- be run in other distributions, but they *are* specific to GNU/Linux
- systems, and are not written with portabillity to other Unixes in
- mind.
-
-** Libraries
-
- The following libraries and packages are needed. (It is possible
- that it might work with older versions of some of these, but these
- versions are confirmed to work. Newer versions are almost
- certainly OK.)
-
-*** Documentation
- These are required to build the manual pages for both the server
- and client:
-
- + DocBook 4.5 http://www.docbook.org/
- Note: DocBook 5.0 is not compatible.
- + DocBook XSL stylesheets 1.71.0
- http://wiki.docbook.org/DocBookXslStylesheets
-
- Package names:
- docbook docbook-xsl
-
- To build just the documentation, run the command "make doc". Then
- the manual page "mandos.8", for example, can be read by running
- "man -l mandos.8".
-
-*** Mandos Server
- + GnuTLS 3.3 https://www.gnutls.org/
- (but not 3.6.0 or later, until 3.6.6, which works)
- + Avahi 0.6.16 https://www.avahi.org/
- + Python 3 https://www.python.org/
- Note: Python 2.7 is still supported, if the "mandos",
- "mandos-ctl", and "mandos-monitor" files are edited to contain
- "#!/usr/bin/python" instead of python3.
- + dbus-python 0.82.4 https://dbus.freedesktop.org/doc/dbus-python/
- + PyGObject 3.8 https://wiki.gnome.org/Projects/PyGObject
- + pkg-config https://www.freedesktop.org/wiki/Software/pkg-config/
- + Urwid 1.0.1 http://urwid.org/
- (Only needed by the "mandos-monitor" tool.)
-
- Strongly recommended:
- + fping 2.4b2-to-ipv6 http://www.fping.org/
- + ssh-keyscan from OpenSSH http://www.openssh.com/
-
- Package names:
- avahi-daemon python3 python3-dbus python3-gi python3-urwid
- pkg-config fping ssh-client
-
-*** Mandos Client
- + GNU C Library 2.17 https://gnu.org/software/libc/
- + GnuTLS 3.3 https://www.gnutls.org/
- (but not 3.6.0 or later, until 3.6.6 which works)
- + Avahi 0.6.16 https://www.avahi.org/
- + GnuPG 1.4.9 https://www.gnupg.org/
- + GPGME 1.1.6 https://www.gnupg.org/related_software/gpgme/
- + pkg-config https://www.freedesktop.org/wiki/Software/pkg-config/
- + libnl-route 3 https://www.infradead.org/~tgr/libnl/
- + GLib 2.40 http://www.gtk.org/
-
- One of:
- + initramfs-tools 0.85i
- https://tracker.debian.org/pkg/initramfs-tools
- + dracut 044+241
- http://www.kernel.org/pub/linux/utils/boot/dracut/dracut.html
-
- Strongly recommended:
- + OpenSSH http://www.openssh.com/
-
- Package names:
- initramfs-tools dracut libgnutls-dev gnutls-bin libavahi-core-dev
- gnupg libgpgme11-dev pkg-config ssh libnl-route-3-dev
- libglib2.0-dev
-
-* Installing the Mandos server
-
- 1. Do "make doc".
-
- 2. On the computer to run as a Mandos server, run the following
- command:
- For Debian: su - -c 'make install-server'
- For Ubuntu: sudo make install-server
-
- (This creates a configuration without any clients configured; you
- need an actually configured client to do that; see below.)
-
-* Installing the Mandos client.
-
- 1. Do "make all doc".
-
- 2. On the computer to run as a Mandos client, run the following
- command:
- For Debian: su - -c 'make install-client'
- For Ubuntu: sudo make install-client
-
- This will also create an OpenPGP key, which will take some time
- and entropy, so be patient.
-
- 3. Run the following command:
- For Debian: su - -c 'mandos-keygen --password'
- For Ubuntu: sudo mandos-keygen --password
-
- When prompted, enter the password/passphrase for the encrypted
- root file system on this client computer. The command will
- output a section of text, starting with a [section header]. Copy
- and append this to the file "/etc/mandos/clients.conf" *on the
- server computer*.
-
- 4. Configure the client to use any special configuration needed for
- your local system. Note: This is not necessary if the server is
- present on the same wired local network as the client. If you do
- make changes to /etc/mandos/plugin-runner.conf, the initrd.img
- file must be updated, possibly using the following command:
-
- # update-initramfs -k all -u
-
- 5. On the server computer, start the server by running the command
- For Debian: su - -c 'invoke-rc.d mandos start'
- For Ubuntu: sudo service mandos start
-
- At this point, it is possible to verify that the correct password
- will be received by the client by running the command:
-
- # /usr/lib/mandos/plugins.d/mandos-client \
- --pubkey=/etc/keys/mandos/pubkey.txt \
- --seckey=/etc/keys/mandos/seckey.txt \
- --tls-privkey=/etc/keys/mandos/tls-privkey.pem \
- --tls-pubkey=/etc/keys/mandos/tls-pubkey.pem; echo
-
- This command should retrieve the password from the server,
- decrypt it, and output it to standard output.
-
- After this, the client computer should be able to reboot without
- needing a password entered on the console, as long as it does not
- take more than five minutes to reboot.
-
-* Further customizations
-
- You may want to tighten or loosen the timeouts in the server
- configuration files; see mandos.conf(5) and mandos-clients.conf(5).
- If IPsec is not used and SSH is not installed, it is suggested that
- a more cryptographically secure checker program is used and
- configured, since, without IPsec, ping packets can be faked.
-
-#+STARTUP: showall
=== modified file 'Makefile'
--- Makefile 2019-09-03 19:06:41 +0000
+++ Makefile 2008-07-29 03:35:39 +0000
@@ -1,605 +1,31 @@
-WARN:=-O -Wall -Wextra -Wdouble-promotion -Wformat=2 -Winit-self \
- -Wmissing-include-dirs -Wswitch-default -Wswitch-enum \
- -Wunused -Wuninitialized -Wstrict-overflow=5 \
- -Wsuggest-attribute=pure -Wsuggest-attribute=const \
- -Wsuggest-attribute=noreturn -Wfloat-equal -Wundef -Wshadow \
- -Wunsafe-loop-optimizations -Wpointer-arith \
- -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings \
- -Wconversion -Wlogical-op -Waggregate-return \
- -Wstrict-prototypes -Wold-style-definition \
- -Wmissing-format-attribute -Wnormalized=nfc -Wpacked \
- -Wredundant-decls -Wnested-externs -Winline -Wvla \
- -Wvolatile-register-var -Woverlength-strings
-
-#DEBUG:=-ggdb3 -fsanitize=address $(SANITIZE)
-## Check which sanitizing options can be used
-#SANITIZE:=$(foreach option,$(ALL_SANITIZE_OPTIONS),$(shell \
-# echo 'int main(){}' | $(CC) --language=c $(option) \
-# /dev/stdin -o /dev/null >/dev/null 2>&1 && echo $(option)))
-#
-ALL_SANITIZE_OPTIONS:=-fsanitize=leak -fsanitize=undefined \
- -fsanitize=shift -fsanitize=integer-divide-by-zero \
- -fsanitize=unreachable -fsanitize=vla-bound -fsanitize=null \
- -fsanitize=return -fsanitize=signed-integer-overflow \
- -fsanitize=bounds -fsanitize=alignment \
- -fsanitize=object-size -fsanitize=float-divide-by-zero \
- -fsanitize=float-cast-overflow -fsanitize=nonnull-attribute \
- -fsanitize=returns-nonnull-attribute -fsanitize=bool \
- -fsanitize=enum -fsanitize-address-use-after-scope
-
-# For info about _FORTIFY_SOURCE, see feature_test_macros(7)
-# and .
-FORTIFY:=-D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIC
-LINK_FORTIFY_LD:=-z relro -z now
-LINK_FORTIFY:=
-
-# If BROKEN_PIE is set, do not build with -pie
-ifndef BROKEN_PIE
-FORTIFY += -fPIE
-LINK_FORTIFY += -pie
-endif
+WARN=-O -Wall -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wswitch-enum -Wunused-parameter -Wstrict-aliasing=2 -Wextra -Wfloat-equal -Wundef -Wshadow -Wunsafe-loop-optimizations -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Wstrict-prototypes -Wold-style-definition -Wpacked -Wnested-externs -Wunreachable-code -Winline -Wvolatile-register-var
+DEBUG=-ggdb3
+# For info about _FORTIFY_SOURCE, see
+#
+FORTIFY=-D_FORTIFY_SOURCE=2 # -fstack-protector-all
#COVERAGE=--coverage
-OPTIMIZE:=-Os -fno-strict-aliasing
-LANGUAGE:=-std=gnu11
-FEATURES:=-D_FILE_OFFSET_BITS=64
-htmldir:=man
-version:=1.8.9
-SED:=sed
-PKG_CONFIG?=pkg-config
-
-USER:=$(firstword $(subst :, ,$(shell getent passwd _mandos \
- || getent passwd nobody || echo 65534)))
-GROUP:=$(firstword $(subst :, ,$(shell getent group _mandos \
- || getent group nogroup || echo 65534)))
-
-LINUXVERSION:=$(shell uname --kernel-release)
-
-## Use these settings for a traditional /usr/local install
-# PREFIX:=$(DESTDIR)/usr/local
-# CONFDIR:=$(DESTDIR)/etc/mandos
-# KEYDIR:=$(DESTDIR)/etc/mandos/keys
-# MANDIR:=$(PREFIX)/man
-# INITRAMFSTOOLS:=$(DESTDIR)/etc/initramfs-tools
-# DRACUTMODULE:=$(DESTDIR)/usr/lib/dracut/modules.d/90mandos
-# STATEDIR:=$(DESTDIR)/var/lib/mandos
-# LIBDIR:=$(PREFIX)/lib
-##
-
-## These settings are for a package-type install
-PREFIX:=$(DESTDIR)/usr
-CONFDIR:=$(DESTDIR)/etc/mandos
-KEYDIR:=$(DESTDIR)/etc/keys/mandos
-MANDIR:=$(PREFIX)/share/man
-INITRAMFSTOOLS:=$(DESTDIR)/usr/share/initramfs-tools
-DRACUTMODULE:=$(DESTDIR)/usr/lib/dracut/modules.d/90mandos
-STATEDIR:=$(DESTDIR)/var/lib/mandos
-LIBDIR:=$(shell \
- for d in \
- "/usr/lib/`dpkg-architecture \
- -qDEB_HOST_MULTIARCH 2>/dev/null`" \
- "`rpm --eval='%{_libdir}' 2>/dev/null`" /usr/lib; do \
- if [ -d "$$d" -a "$$d" = "$${d%/}" ]; then \
- echo "$(DESTDIR)$$d"; \
- break; \
- fi; \
- done)
-##
-
-SYSTEMD:=$(DESTDIR)$(shell $(PKG_CONFIG) systemd \
- --variable=systemdsystemunitdir)
-TMPFILES:=$(DESTDIR)$(shell $(PKG_CONFIG) systemd \
- --variable=tmpfilesdir)
-SYSUSERS:=$(DESTDIR)$(shell $(PKG_CONFIG) systemd \
- --variable=sysusersdir)
-
-GNUTLS_CFLAGS:=$(shell $(PKG_CONFIG) --cflags-only-I gnutls)
-GNUTLS_LIBS:=$(shell $(PKG_CONFIG) --libs gnutls)
-AVAHI_CFLAGS:=$(shell $(PKG_CONFIG) --cflags-only-I avahi-core)
-AVAHI_LIBS:=$(shell $(PKG_CONFIG) --libs avahi-core)
-GPGME_CFLAGS:=$(shell gpgme-config --cflags; getconf LFS_CFLAGS)
-GPGME_LIBS:=$(shell gpgme-config --libs; getconf LFS_LIBS; \
- getconf LFS_LDFLAGS)
-LIBNL3_CFLAGS:=$(shell $(PKG_CONFIG) --cflags-only-I libnl-route-3.0)
-LIBNL3_LIBS:=$(shell $(PKG_CONFIG) --libs libnl-route-3.0)
-GLIB_CFLAGS:=$(shell $(PKG_CONFIG) --cflags glib-2.0)
-GLIB_LIBS:=$(shell $(PKG_CONFIG) --libs glib-2.0)
+OPTIMIZE=-Os
+LANGUAGE=-std=gnu99
# Do not change these two
-CFLAGS+=$(WARN) $(DEBUG) $(FORTIFY) $(COVERAGE) $(OPTIMIZE) \
- $(LANGUAGE) $(FEATURES) -DVERSION='"$(version)"'
-LDFLAGS+=-Xlinker --as-needed $(COVERAGE) $(LINK_FORTIFY) $(strip \
- ) $(foreach flag,$(LINK_FORTIFY_LD),-Xlinker $(flag))
-
-# Commands to format a DocBook document into a manual page
-DOCBOOKTOMAN=$(strip cd $(dir $<); xsltproc --nonet --xinclude \
- --param man.charmap.use.subset 0 \
- --param make.year.ranges 1 \
- --param make.single.year.ranges 1 \
- --param man.output.quietly 1 \
- --param man.authors.section.enabled 0 \
- /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl \
- $(notdir $<); \
- if locale --all 2>/dev/null | grep --regexp='^en_US\.utf8$$' \
- && command -v man >/dev/null; then LANG=en_US.UTF-8 \
- MANWIDTH=80 man --warnings --encoding=UTF-8 --local-file \
- $(notdir $@); fi >/dev/null)
-
-DOCBOOKTOHTML=$(strip xsltproc --nonet --xinclude \
- --param make.year.ranges 1 \
- --param make.single.year.ranges 1 \
- --param man.output.quietly 1 \
- --param man.authors.section.enabled 0 \
- --param citerefentry.link 1 \
- --output $@ \
- /usr/share/xml/docbook/stylesheet/nwalsh/xhtml/docbook.xsl \
- $<; $(HTMLPOST) $@)
-# Fix citerefentry links
-HTMLPOST:=$(SED) --in-place \
- --expression='s/\(\)\([^<]*\)\(<\/span>(\)\([^)]*\)\()<\/span><\/a>\)/\1\3.\5\2\3\4\5\6/g'
-
-PLUGINS:=plugins.d/password-prompt plugins.d/mandos-client \
- plugins.d/usplash plugins.d/splashy plugins.d/askpass-fifo \
- plugins.d/plymouth
-PLUGIN_HELPERS:=plugin-helpers/mandos-client-iprouteadddel
-CPROGS:=plugin-runner dracut-module/password-agent $(PLUGINS) \
- $(PLUGIN_HELPERS)
-PROGS:=mandos mandos-keygen mandos-ctl mandos-monitor $(CPROGS)
-DOCS:=mandos.8 mandos-keygen.8 mandos-monitor.8 mandos-ctl.8 \
- mandos.conf.5 mandos-clients.conf.5 plugin-runner.8mandos \
- dracut-module/password-agent.8mandos \
- plugins.d/mandos-client.8mandos \
- plugins.d/password-prompt.8mandos plugins.d/usplash.8mandos \
- plugins.d/splashy.8mandos plugins.d/askpass-fifo.8mandos \
- plugins.d/plymouth.8mandos intro.8mandos
-
-htmldocs:=$(addsuffix .xhtml,$(DOCS))
-
-objects:=$(addsuffix .o,$(CPROGS))
-
-all: $(PROGS) mandos.lsm
-
-doc: $(DOCS)
-
-html: $(htmldocs)
-
-%.5: %.xml common.ent legalnotice.xml
- $(DOCBOOKTOMAN)
-%.5.xhtml: %.xml common.ent legalnotice.xml
- $(DOCBOOKTOHTML)
-
-%.8: %.xml common.ent legalnotice.xml
- $(DOCBOOKTOMAN)
-%.8.xhtml: %.xml common.ent legalnotice.xml
- $(DOCBOOKTOHTML)
-
-%.8mandos: %.xml common.ent legalnotice.xml
- $(DOCBOOKTOMAN)
-%.8mandos.xhtml: %.xml common.ent legalnotice.xml
- $(DOCBOOKTOHTML)
-
-intro.8mandos: intro.xml common.ent legalnotice.xml
- $(DOCBOOKTOMAN)
-intro.8mandos.xhtml: intro.xml common.ent legalnotice.xml
- $(DOCBOOKTOHTML)
-
-mandos.8: mandos.xml common.ent mandos-options.xml overview.xml \
- legalnotice.xml
- $(DOCBOOKTOMAN)
-mandos.8.xhtml: mandos.xml common.ent mandos-options.xml \
- overview.xml legalnotice.xml
- $(DOCBOOKTOHTML)
-
-mandos-keygen.8: mandos-keygen.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOMAN)
-mandos-keygen.8.xhtml: mandos-keygen.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOHTML)
-
-mandos-monitor.8: mandos-monitor.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOMAN)
-mandos-monitor.8.xhtml: mandos-monitor.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOHTML)
-
-mandos-ctl.8: mandos-ctl.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOMAN)
-mandos-ctl.8.xhtml: mandos-ctl.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOHTML)
-
-mandos.conf.5: mandos.conf.xml common.ent mandos-options.xml \
- legalnotice.xml
- $(DOCBOOKTOMAN)
-mandos.conf.5.xhtml: mandos.conf.xml common.ent mandos-options.xml \
- legalnotice.xml
- $(DOCBOOKTOHTML)
-
-plugin-runner.8mandos: plugin-runner.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOMAN)
-plugin-runner.8mandos.xhtml: plugin-runner.xml common.ent \
- overview.xml legalnotice.xml
- $(DOCBOOKTOHTML)
-
-dracut-module/password-agent.8mandos: \
- dracut-module/password-agent.xml common.ent \
- overview.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-dracut-module/password-agent.8mandos.xhtml: \
- dracut-module/password-agent.xml common.ent \
- overview.xml legalnotice.xml
- $(DOCBOOKTOHTML)
-
-plugins.d/mandos-client.8mandos: plugins.d/mandos-client.xml \
- common.ent \
- mandos-options.xml \
- overview.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-plugins.d/mandos-client.8mandos.xhtml: plugins.d/mandos-client.xml \
- common.ent \
- mandos-options.xml \
- overview.xml legalnotice.xml
- $(DOCBOOKTOHTML)
-
-# Update all these files with version number $(version)
-common.ent: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\($$/\1$(version)">/' \
- $@)
-
-mandos: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\(version = "\)[^"]*"$$/\1$(version)"/' \
- $@)
-
-mandos-keygen: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\(VERSION="\)[^"]*"$$/\1$(version)"/' \
- $@)
-
-mandos-ctl: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\(version = "\)[^"]*"$$/\1$(version)"/' \
- $@)
-
-mandos-monitor: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\(version = "\)[^"]*"$$/\1$(version)"/' \
- $@)
-
-mandos.lsm: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\(Version:\).*/\1\t$(version)/' \
- $@)
- $(strip $(SED) --in-place \
- --expression='s/^\(Entered-date:\).*/\1\t$(shell date --rfc-3339=date --reference=Makefile)/' \
- $@)
- $(strip $(SED) --in-place \
- --expression='s/\(mandos_\)[0-9.]\+\(\.orig\.tar\.gz\)/\1$(version)\2/' \
- $@)
-
-# Need to add the GnuTLS, Avahi and GPGME libraries
-plugins.d/mandos-client: plugins.d/mandos-client.c
- $(LINK.c) $^ $(GNUTLS_CFLAGS) $(AVAHI_CFLAGS) $(strip\
- ) $(GPGME_CFLAGS) $(GNUTLS_LIBS) $(strip\
- ) $(AVAHI_LIBS) $(GPGME_LIBS) $(LOADLIBES) $(strip\
- ) $(LDLIBS) -o $@
-
-# Need to add the libnl-route library
-plugin-helpers/mandos-client-iprouteadddel: plugin-helpers/mandos-client-iprouteadddel.c
- $(LINK.c) $(LIBNL3_CFLAGS) $^ $(LIBNL3_LIBS) $(strip\
- ) $(LOADLIBES) $(LDLIBS) -o $@
-
-# Need to add the GLib and pthread libraries
-dracut-module/password-agent: dracut-module/password-agent.c
- $(LINK.c) $(GLIB_CFLAGS) $^ $(GLIB_LIBS) -lpthread $(strip\
- ) $(LOADLIBES) $(LDLIBS) -o $@
-
-.PHONY : all doc html clean distclean mostlyclean maintainer-clean \
- check run-client run-server install install-html \
- install-server install-client-nokey install-client uninstall \
- uninstall-server uninstall-client purge purge-server \
- purge-client
-
+CFLAGS=$(WARN) $(DEBUG) $(FORTIFY) $(COVERAGE) $(OPTIMIZE) $(LANGUAGE)
+LDFLAGS=$(COVERAGE)
+
+PROGS=plugbasedclient plugins.d/mandosclient plugins.d/passprompt
+
+objects=$(shell for p in $(PROGS); do echo $${p}.o; done)
+
+all: $(PROGS)
+
+plugbasedclient: plugbasedclient.o
+ $(LINK.o) -lgnutls $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@
+
+plugins.d/mandosclient: plugins.d/mandosclient.o
+ $(LINK.o) -lgnutls -lavahi-core -lgpgme $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@
+
+plugins.d/passprompt: plugins.d/passprompt.o
+ $(LINK.o) $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@
+
+.PHONY : clean
clean:
- -rm --force $(CPROGS) $(objects) $(htmldocs) $(DOCS) core
-
-distclean: clean
-mostlyclean: clean
-maintainer-clean: clean
- -rm --force --recursive keydir confdir statedir
-
-check: all
- ./mandos --check
- ./mandos-ctl --check
- ./mandos-keygen --version
- ./plugin-runner --version
- ./plugin-helpers/mandos-client-iprouteadddel --version
- ./dracut-module/password-agent --test
-
-# Run the client with a local config and key
-run-client: all keydir/seckey.txt keydir/pubkey.txt \
- keydir/tls-privkey.pem keydir/tls-pubkey.pem
- @echo '######################################################'
- @echo '# The following error messages are harmless and can #'
- @echo '# be safely ignored: #'
- @echo '## From plugin-runner: #'
- @echo '# setgid: Operation not permitted #'
- @echo '# setuid: Operation not permitted #'
- @echo '## From askpass-fifo: #'
- @echo '# mkfifo: Permission denied #'
- @echo '## From mandos-client: #'
- @echo '# Failed to raise privileges: Operation not permi... #'
- @echo '# Warning: network hook "*" exited with status * #'
- @echo '# ioctl SIOCSIFFLAGS +IFF_UP: Operation not permi... #'
- @echo '# Failed to bring up interface "*": Operation not... #'
- @echo '# #'
- @echo '# (The messages are caused by not running as root, #'
- @echo '# but you should NOT run "make run-client" as root #'
- @echo '# unless you also unpacked and compiled Mandos as #'
- @echo '# root, which is also NOT recommended.) #'
- @echo '######################################################'
-# We set GNOME_KEYRING_CONTROL to block pam_gnome_keyring
- ./plugin-runner --plugin-dir=plugins.d \
- --plugin-helper-dir=plugin-helpers \
- --config-file=plugin-runner.conf \
- --options-for=mandos-client:--seckey=keydir/seckey.txt,--pubkey=keydir/pubkey.txt,--tls-privkey=keydir/tls-privkey.pem,--tls-pubkey=keydir/tls-pubkey.pem,--network-hook-dir=network-hooks.d \
- --env-for=mandos-client:GNOME_KEYRING_CONTROL= \
- $(CLIENTARGS)
-
-# Used by run-client
-keydir/seckey.txt keydir/pubkey.txt keydir/tls-privkey.pem keydir/tls-pubkey.pem: mandos-keygen
- install --directory keydir
- ./mandos-keygen --dir keydir --force
-
-# Run the server with a local config
-run-server: confdir/mandos.conf confdir/clients.conf statedir
- ./mandos --debug --no-dbus --configdir=confdir \
- --statedir=statedir $(SERVERARGS)
-
-# Used by run-server
-confdir/mandos.conf: mandos.conf
- install --directory confdir
- install --mode=u=rw,go=r $^ $@
-confdir/clients.conf: clients.conf keydir/seckey.txt keydir/tls-pubkey.pem
- install --directory confdir
- install --mode=u=rw $< $@
-# Add a client password
- ./mandos-keygen --dir keydir --password --no-ssh >> $@
-statedir:
- install --directory statedir
-
-install: install-server install-client-nokey
-
-install-html: html
- install --directory $(htmldir)
- install --mode=u=rw,go=r --target-directory=$(htmldir) \
- $(htmldocs)
-
-install-server: doc
- install --directory $(CONFDIR)
- if install --directory --mode=u=rwx --owner=$(USER) \
- --group=$(GROUP) $(STATEDIR); then \
- :; \
- elif install --directory --mode=u=rwx $(STATEDIR); then \
- chown -- $(USER):$(GROUP) $(STATEDIR) || :; \
- fi
- if [ "$(TMPFILES)" != "$(DESTDIR)" \
- -a -d "$(TMPFILES)" ]; then \
- install --mode=u=rw,go=r tmpfiles.d-mandos.conf \
- $(TMPFILES)/mandos.conf; \
- fi
- if [ "$(SYSUSERS)" != "$(DESTDIR)" \
- -a -d "$(SYSUSERS)" ]; then \
- install --mode=u=rw,go=r sysusers.d-mandos.conf \
- $(SYSUSERS)/mandos.conf; \
- fi
- install --mode=u=rwx,go=rx mandos $(PREFIX)/sbin/mandos
- install --mode=u=rwx,go=rx --target-directory=$(PREFIX)/sbin \
- mandos-ctl
- install --mode=u=rwx,go=rx --target-directory=$(PREFIX)/sbin \
- mandos-monitor
- install --mode=u=rw,go=r --target-directory=$(CONFDIR) \
- mandos.conf
- install --mode=u=rw --target-directory=$(CONFDIR) \
- clients.conf
- install --mode=u=rw,go=r dbus-mandos.conf \
- $(DESTDIR)/etc/dbus-1/system.d/mandos.conf
- install --mode=u=rwx,go=rx init.d-mandos \
- $(DESTDIR)/etc/init.d/mandos
- if [ "$(SYSTEMD)" != "$(DESTDIR)" -a -d "$(SYSTEMD)" ]; then \
- install --mode=u=rw,go=r mandos.service $(SYSTEMD); \
- fi
- install --mode=u=rw,go=r default-mandos \
- $(DESTDIR)/etc/default/mandos
- if [ -z $(DESTDIR) ]; then \
- update-rc.d mandos defaults 25 15;\
- fi
- gzip --best --to-stdout mandos.8 \
- > $(MANDIR)/man8/mandos.8.gz
- gzip --best --to-stdout mandos-monitor.8 \
- > $(MANDIR)/man8/mandos-monitor.8.gz
- gzip --best --to-stdout mandos-ctl.8 \
- > $(MANDIR)/man8/mandos-ctl.8.gz
- gzip --best --to-stdout mandos.conf.5 \
- > $(MANDIR)/man5/mandos.conf.5.gz
- gzip --best --to-stdout mandos-clients.conf.5 \
- > $(MANDIR)/man5/mandos-clients.conf.5.gz
- gzip --best --to-stdout intro.8mandos \
- > $(MANDIR)/man8/intro.8mandos.gz
-
-install-client-nokey: all doc
- install --directory $(LIBDIR)/mandos $(CONFDIR)
- install --directory --mode=u=rwx $(KEYDIR) \
- $(LIBDIR)/mandos/plugins.d \
- $(LIBDIR)/mandos/plugin-helpers
- if [ "$(SYSUSERS)" != "$(DESTDIR)" \
- -a -d "$(SYSUSERS)" ]; then \
- install --mode=u=rw,go=r sysusers.d-mandos.conf \
- $(SYSUSERS)/mandos-client.conf; \
- fi
- if [ "$(CONFDIR)" != "$(LIBDIR)/mandos" ]; then \
- install --mode=u=rwx \
- --directory "$(CONFDIR)/plugins.d" \
- "$(CONFDIR)/plugin-helpers"; \
- fi
- install --mode=u=rwx,go=rx --directory \
- "$(CONFDIR)/network-hooks.d"
- install --mode=u=rwx,go=rx \
- --target-directory=$(LIBDIR)/mandos plugin-runner
- install --mode=u=rwx,go=rx \
- --target-directory=$(LIBDIR)/mandos \
- mandos-to-cryptroot-unlock
- install --mode=u=rwx,go=rx --target-directory=$(PREFIX)/sbin \
- mandos-keygen
- install --mode=u=rwx,go=rx \
- --target-directory=$(LIBDIR)/mandos/plugins.d \
- plugins.d/password-prompt
- install --mode=u=rwxs,go=rx \
- --target-directory=$(LIBDIR)/mandos/plugins.d \
- plugins.d/mandos-client
- install --mode=u=rwxs,go=rx \
- --target-directory=$(LIBDIR)/mandos/plugins.d \
- plugins.d/usplash
- install --mode=u=rwxs,go=rx \
- --target-directory=$(LIBDIR)/mandos/plugins.d \
- plugins.d/splashy
- install --mode=u=rwxs,go=rx \
- --target-directory=$(LIBDIR)/mandos/plugins.d \
- plugins.d/askpass-fifo
- install --mode=u=rwxs,go=rx \
- --target-directory=$(LIBDIR)/mandos/plugins.d \
- plugins.d/plymouth
- install --mode=u=rwx,go=rx \
- --target-directory=$(LIBDIR)/mandos/plugin-helpers \
- plugin-helpers/mandos-client-iprouteadddel
- install initramfs-tools-hook \
- $(INITRAMFSTOOLS)/hooks/mandos
- install --mode=u=rw,go=r initramfs-tools-conf \
- $(INITRAMFSTOOLS)/conf.d/mandos-conf
- install --mode=u=rw,go=r initramfs-tools-conf-hook \
- $(INITRAMFSTOOLS)/conf-hooks.d/zz-mandos
- install initramfs-tools-script \
- $(INITRAMFSTOOLS)/scripts/init-premount/mandos
- install initramfs-tools-script-stop \
- $(INITRAMFSTOOLS)/scripts/local-premount/mandos
- install --directory $(DRACUTMODULE)
- install --mode=u=rw,go=r --target-directory=$(DRACUTMODULE) \
- dracut-module/ask-password-mandos.path \
- dracut-module/ask-password-mandos.service
- install --mode=u=rwxs,go=rx \
- --target-directory=$(DRACUTMODULE) \
- dracut-module/module-setup.sh \
- dracut-module/cmdline-mandos.sh \
- dracut-module/password-agent
- install --mode=u=rw,go=r plugin-runner.conf $(CONFDIR)
- gzip --best --to-stdout mandos-keygen.8 \
- > $(MANDIR)/man8/mandos-keygen.8.gz
- gzip --best --to-stdout plugin-runner.8mandos \
- > $(MANDIR)/man8/plugin-runner.8mandos.gz
- gzip --best --to-stdout plugins.d/mandos-client.8mandos \
- > $(MANDIR)/man8/mandos-client.8mandos.gz
- gzip --best --to-stdout plugins.d/password-prompt.8mandos \
- > $(MANDIR)/man8/password-prompt.8mandos.gz
- gzip --best --to-stdout plugins.d/usplash.8mandos \
- > $(MANDIR)/man8/usplash.8mandos.gz
- gzip --best --to-stdout plugins.d/splashy.8mandos \
- > $(MANDIR)/man8/splashy.8mandos.gz
- gzip --best --to-stdout plugins.d/askpass-fifo.8mandos \
- > $(MANDIR)/man8/askpass-fifo.8mandos.gz
- gzip --best --to-stdout plugins.d/plymouth.8mandos \
- > $(MANDIR)/man8/plymouth.8mandos.gz
- gzip --best --to-stdout dracut-module/password-agent.8mandos \
- > $(MANDIR)/man8/password-agent.8mandos.gz
-
-install-client: install-client-nokey
-# Post-installation stuff
- -$(PREFIX)/sbin/mandos-keygen --dir "$(KEYDIR)"
- if command -v update-initramfs >/dev/null; then \
- update-initramfs -k all -u; \
- elif command -v dracut >/dev/null; then \
- for initrd in $(DESTDIR)/boot/initr*-$(LINUXVERSION); do \
- if [ -w "$$initrd" ]; then \
- chmod go-r "$$initrd"; \
- dracut --force "$$initrd"; \
- fi; \
- done; \
- fi
- echo "Now run mandos-keygen --password --dir $(KEYDIR)"
-
-uninstall: uninstall-server uninstall-client
-
-uninstall-server:
- -rm --force $(PREFIX)/sbin/mandos \
- $(PREFIX)/sbin/mandos-ctl \
- $(PREFIX)/sbin/mandos-monitor \
- $(MANDIR)/man8/mandos.8.gz \
- $(MANDIR)/man8/mandos-monitor.8.gz \
- $(MANDIR)/man8/mandos-ctl.8.gz \
- $(MANDIR)/man5/mandos.conf.5.gz \
- $(MANDIR)/man5/mandos-clients.conf.5.gz
- update-rc.d -f mandos remove
- -rmdir $(CONFDIR)
-
-uninstall-client:
-# Refuse to uninstall client if /etc/crypttab is explicitly configured
-# to use it.
- ! grep --regexp='^ *[^ #].*keyscript=[^,=]*/mandos/' \
- $(DESTDIR)/etc/crypttab
- -rm --force $(PREFIX)/sbin/mandos-keygen \
- $(LIBDIR)/mandos/plugin-runner \
- $(LIBDIR)/mandos/plugins.d/password-prompt \
- $(LIBDIR)/mandos/plugins.d/mandos-client \
- $(LIBDIR)/mandos/plugins.d/usplash \
- $(LIBDIR)/mandos/plugins.d/splashy \
- $(LIBDIR)/mandos/plugins.d/askpass-fifo \
- $(LIBDIR)/mandos/plugins.d/plymouth \
- $(INITRAMFSTOOLS)/hooks/mandos \
- $(INITRAMFSTOOLS)/conf-hooks.d/mandos \
- $(INITRAMFSTOOLS)/scripts/init-premount/mandos \
- $(INITRAMFSTOOLS)/scripts/local-premount/mandos \
- $(DRACUTMODULE)/ask-password-mandos.path \
- $(DRACUTMODULE)/ask-password-mandos.service \
- $(DRACUTMODULE)/module-setup.sh \
- $(DRACUTMODULE)/cmdline-mandos.sh \
- $(DRACUTMODULE)/password-agent \
- $(MANDIR)/man8/mandos-keygen.8.gz \
- $(MANDIR)/man8/plugin-runner.8mandos.gz \
- $(MANDIR)/man8/mandos-client.8mandos.gz
- $(MANDIR)/man8/password-prompt.8mandos.gz \
- $(MANDIR)/man8/usplash.8mandos.gz \
- $(MANDIR)/man8/splashy.8mandos.gz \
- $(MANDIR)/man8/askpass-fifo.8mandos.gz \
- $(MANDIR)/man8/plymouth.8mandos.gz \
- $(MANDIR)/man8/password-agent.8mandos.gz \
- -rmdir $(LIBDIR)/mandos/plugins.d $(CONFDIR)/plugins.d \
- $(LIBDIR)/mandos $(CONFDIR) $(KEYDIR) $(DRACUTMODULE)
- if command -v update-initramfs >/dev/null; then \
- update-initramfs -k all -u; \
- elif command -v dracut >/dev/null; then \
- for initrd in $(DESTDIR)/boot/initr*-$(LINUXVERSION); do \
- test -w "$$initrd" && dracut --force "$$initrd"; \
- done; \
- fi
-
-purge: purge-server purge-client
-
-purge-server: uninstall-server
- -rm --force $(CONFDIR)/mandos.conf $(CONFDIR)/clients.conf \
- $(DESTDIR)/etc/dbus-1/system.d/mandos.conf
- $(DESTDIR)/etc/default/mandos \
- $(DESTDIR)/etc/init.d/mandos \
- $(SYSTEMD)/mandos.service \
- $(DESTDIR)/run/mandos.pid \
- $(DESTDIR)/var/run/mandos.pid
- -rmdir $(CONFDIR)
-
-purge-client: uninstall-client
- -shred --remove $(KEYDIR)/seckey.txt $(KEYDIR)/tls-privkey.pem
- -rm --force $(CONFDIR)/plugin-runner.conf \
- $(KEYDIR)/pubkey.txt $(KEYDIR)/seckey.txt \
- $(KEYDIR)/tls-pubkey.txt $(KEYDIR)/tls-privkey.txt
- -rmdir $(KEYDIR) $(CONFDIR)/plugins.d $(CONFDIR)
+ -rm -f $(PROGS) $(objects) core
=== removed file 'NEWS'
--- NEWS 2019-09-03 19:06:41 +0000
+++ NEWS 1970-01-01 00:00:00 +0000
@@ -1,570 +0,0 @@
-This NEWS file records noteworthy changes, very tersely.
-See the manual for detailed information.
-
-Version 1.8.9 (2019-09-03)
-* No user-visible changes
-
-Version 1.8.8 (2019-08-18)
-* No user-visible changes
-
-Version 1.8.7 (2019-08-05)
-* Client:
-** Always compile with LFS (Large File Support) enabled.
-* Server
-** Improve intro(8mandos) manual page to cover dracut(8) support.
-
-Version 1.8.6 (2019-08-03)
-* Client:
-** dracut support: In password-agent, properly ignore deleted and
- renamed question files, and also fix memory alignment issue.
-
-Version 1.8.5 (2019-07-30)
-* Client
-** Support dracut(8) as well as initramfs-tools(7).
-** Minor bug fix: Allow the mandos-keygen --passfile option to use
- passfiles with names starting with "-".
-** Document known limitation of mandos-keygen --password; it strips
- white space from start and end of the password.
-* Server
-** Bug fix: The server used to fail to restart if the "port" setting
- was used. This has been fixed.
-** Minor bug fix: Reap zombies left over from checker runs. (Debian
- bug #933387)
-
-Version 1.8.4 (2019-04-09)
-* Client
-** Fix minor memory leak in plugin-runner.
-* Server
-** mandos-ctl now has a --debug option to show D-Bus calls.
-
-Version 1.8.3 (2019-02-11)
-* No user-visible changes.
-
-Version 1.8.2 (2019-02-10)
-* Client
-** In mandos-keygen, ignore failures to remove files in some cases.
-
-Version 1.8.1 (2019-02-10)
-* Client
-** Only generate TLS keys using GnuTLS' certtool, of sufficient
- version. Key generation of TLS keys will not happen until a
- version of GnuTLS is installed with support for raw public keys.
-** Remove any bad keys created by 1.8.0 and openssl.
-* Server
-** On installation, edit clients.conf and remove the same bad key ID
- which was erroneously reported by all 1.8.0 clients. Also do not
- trust this key ID in the server.
-
-Version 1.8.0 (2019-02-10)
-* Client
-** Use new TLS keys for server communication and identification.
- With GnuTLS 3.6 or later, OpenPGP keys are no longer supported.
- The client can now use the new "raw public keys" (RFC 7250) API
- instead, using GnuTLS 3.6.6. Please note: This *requires* new key
- IDs to be added to server's client.conf file.
-** New --tls-privkey and --tls-pubkey options to load TLS key files.
- If GnuTLS is too old, these options do nothing.
-* Server
-** Supports either old or new GnuTLS.
- The server now supports using GnuTLS 3.6.6 and clients connecting
- with "raw public keys" as identification. The server will read
- both fingerprints and key IDs from clients.conf file, and will use
- either one or the other, depending on what is supported by GnuTLS
- on the system. Please note: both are *not* supported at once; if
- one type is supported by GnuTLS, all values of the other type from
- clients.conf are ignored.
-
-Version 1.7.20 (2018-08-19)
-* Client
-** Fix: Adapt to the Debian cryptsetup package 2.0.3 or later.
- Important: in that version or later, the plugins "askpass-fifo",
- "password-prompt", and "plymouth" will no longer be run, since they
- would conflict with what cryptsetup is doing. Other plugins, such
- as mandos-client and any user-supplied plugins, will still run.
-** Better error message if failing to decrypt secret data
-** Check for (and report) any key import failure from GPGME
-** Better error message if self-signature verification fails
-** Set system clock if not set; required by GnuPG for key import
-** When debugging plugin-runner, it will now show starting plugins
-
-Version 1.7.19 (2018-02-22)
-* Client
-** Do not print "unlink(...): No such file or directory".
-** Bug fixes: Fix file descriptor leaks.
-** Bug fix: Don't use leak sanitizer with leaking libraries.
-
-Version 1.7.18 (2018-02-12)
-* Client
-** Bug fix: Revert faulty fix for a nonexistent bug in the
- plugin-runner
-
-Version 1.7.17 (2018-02-10)
-* Client
-** Bug fix: Fix a memory leak in the plugin-runner
-** Bug fix: Fix memory leaks in the plymouth plugin
-
-Version 1.7.16 (2017-08-20)
-* Client
-** Bug fix: ignore "resumedev" entries in initramfs' cryptroot file
-** Bug fix in plymouth plugin: fix memory leak, avoid warning output
-
-Version 1.7.15 (2017-02-23)
-* Server
-** Bug fix: Respect the mandos.conf "zeroconf" and "restore" options
-* Client
-** Bug fix in mandos-keygen: Handle backslashes in passphrases
-
-Version 1.7.14 (2017-01-25)
-* Server
-** Use "Requisite" instead of "RequisiteOverridable" in systemd
- service file.
-
-Version 1.7.13 (2016-10-08)
-* Client
-** Minor bug fix: Don't ask for passphrase or fail when generating
- keys using GnuPG 2.1 in a chrooted environment.
-
-Version 1.7.12 (2016-10-05)
-* Client
-** Bug fix: Don't crash after exit() when using DH parameters file
-
-Version 1.7.11 (2016-10-01)
-* Client
-** Security fix: Don't compile with AddressSanitizer
-* Server
-** Bug fix: Find GnuTLS library when gnutls28-dev is not installed
-** Bug fix: Include "Expires" and "Last Checker Status" in mandos-ctl
- verbose output
-** New option for mandos-ctl: --dump-json
-
-Version 1.7.10 (2016-06-23)
-* Client
-** Security fix: restrict permissions of /etc/mandos/plugin-helpers
-* Server
-** Bug fix: Make the --interface flag work with Python 2.7 when "cc"
- is not installed
-
-Version 1.7.9 (2016-06-22)
-* Client
-** Do not include intro(8mandos) man page
-
-Version 1.7.8 (2016-06-21)
-* Client
-** Include intro(8mandos) man page
-** mandos-keygen: Use ECDSA SSH keys by default
-** Bug fix: Work with GnuPG 2 when booting (Debian bug #819982)
- by copying /usr/bin/gpg-agent into initramfs
-* Server
-** Bug fix: Work with GnuPG 2 (don't use --no-use-agent option)
-** Bug fix: Make the --interface option work when using Python 2.7
- by trying harder to find SO_BINDTODEVICE
-
-Version 1.7.7 (2016-03-19)
-* Client
-** Fix bug in Plymouth client, broken since 1.7.2
-
-Version 1.7.6 (2016-03-13)
-* Server
-** Fix bug where stopping server would time out
-** Make server runnable with Python 3
-
-Version 1.7.5 (2016-03-08)
-* Server
-** Fix security restrictions in systemd service file.
-** Work around bug where stopping server would time out
-
-Version 1.7.4 (2016-03-05)
-* Client
-** Bug fix: Tolerate errors from configure_networking (Debian Bug
- #816513)
-** Compilation: Only use sanitizing options which work with the
- compiler used when building. This should fix compilation with GCC
- 4.9 on mips, mipsel, and s390x.
-* Server
-** Add extra security restrictions in systemd service file.
-
-Version 1.7.3 (2016-02-29)
-* Client
-** Bug fix: Remove new type of keyring directory user by GnuPG 2.1.
-** Bug fix: Remove "nonnull" attribute from a function argument, which
- would otherwise generate a spurious runtime warning.
-
-Version 1.7.2 (2016-02-28)
-* Server
-** Stop using python-gnutls library; it was not updated to GnuTLS 3.3.
-** Bug fix: Only send D-Bus signal ClientRemoved if using D-Bus.
-** Use GnuPG 2 if available.
-* Client
-** Compile with various sanitizing flags.
-
-Version 1.7.1 (2015-10-24)
-* Client
-** Bug fix: Can now really find Mandos server even if the server has
- an IPv6 address on a network other than the one which the Mandos
- server is on.
-
-Version 1.7.0 (2015-08-10)
-* Server
-** Bug fix: Handle local Zeroconf service name collisions better.
-** Bug fix: Finally fix "ERROR: Child process vanished" bug.
-** Bug fix: Fix systemd service file to start server correctly.
-** Bug fix: Be compatible with old 2048-bit DSA keys.
-** The D-Bus API now provides the standard D-Bus ObjectManager
- interface, and deprecates older functionality. See the DBUS-API
- file for the currently recommended API. Note: the original API
- still works, but is deprecated.
-* Client
-** Can now find Mandos server even if the server has an IPv6 address
- on a network without IPv6 Router Advertisment (like if the Mandos
- client itself is the router, or there is an IPv6 router advertising
- a network other than the one which the Mandos server is on.)
-** Use a better value than 1024 for the default number of DH bits.
- This better value is either provided by a DH parameters file (see
- below) or an appropriate number of DH bits is determined based on
- the PGP key.
-** Bug fix: mandos-keygen now generates correct output for the
- "Checker" variable even if the SSH server on the Mandos client has
- multiple SSH key types.
-** Can now use pre-generated Diffie-Hellman parameters from a file.
-
-Version 1.6.9 (2014-10-05)
-* Server
-** Changed to emit standard D-Bus signal when D-Bus properties change.
- (The old signal is still emitted too, but marked as deprecated.)
-
-Version 1.6.8 (2014-08-06)
-* Client
-** Bug fix: mandos-keygen now generates working SSH checker commands.
-* Server
-** Bug fix: "mandos-monitor" now really redraws screen on Ctrl-L.
-** Now requires Python 2.7.
-
-Version 1.6.7 (2014-07-17)
-* Client
-** Bug fix: Now compatible with GPGME 1.5.0.
-** Bug fix: Fixed minor memory leaks.
-* Server
-** "mandos-monitor" now has verbose logging, toggleable with "v".
-
-Version 1.6.6 (2014-07-13)
-* Client
-** If client host has an SSH server, "mandos-keygen --password" now
- outputs "checker" option which uses "ssh-keyscan"; this is more
- secure than the default "fping" checker.
-** Bug fix: allow "." in network hook names, to match documentation.
-** Better error messages.
-* Server
-** New --no-zeroconf option.
-** Bug fix: Fix --servicename option, broken since 1.6.4.
-** Bug fix: Fix --socket option work for --socket=0.
-
-Version 1.6.5 (2014-05-11)
-* Client
-** Work around bug in GnuPG
-** Give better error messages when run without sufficient privileges
-** Only warn if workaround for Debian bug #633582 was necessary and
- failed, not if it failed and was unnecessary.
-
-Version 1.6.4 (2014-02-16)
-* Server
-** Very minor fix to self-test code.
-
-Version 1.6.3 (2014-01-21)
-* Server
-** Add systemd support.
-** For PID file, fall back to /var/run if /run does not exist.
-* Client
-** Moved files from /usr/lib/mandos to whatever the architecture
- specifies, like /usr/lib/x86_64-linux-gnu/mandos or
- /usr/lib64/mandos.
-
-Version 1.6.2 (2013-10-24)
-* Server
-** PID file moved from /var/run to /run.
-** Bug fix: Handle long secrets when saving client state.
-** Bug fix: Use more magic in the GnuTLS priority string to handle
- both old DSA/ELG 2048-bit keys and new RSA/RSA 4096-bit keys.
-* Client
-** mandos-keygen: Bug fix: now generate RSA keys which GnuTLS can use.
- Bug fix: Output passphrase prompts even when
- redirecting standard output.
-
-Version 1.6.1 (2013-10-13)
-* Server
-** All client options for time intervals now also take an RFC 3339
- duration. The same for all options to mandos-ctl.
-** Bug fix: Handle fast checkers (like ":") correctly.
-** Bug fix: Don't print output from checkers when running in
- foreground.
-** Bug fix: Do not fail when client is removed from clients.conf but
- saved settings remain.
-** Bug fix: mandos-monitor now displays standout (reverse video) again
- using new version of Urwid.
-** Bug fix: Make boolean options work from the config file again.
-** Bug fix: Make --no-ipv6 work again.
-** New default priority string to be slightly more compatible with
- older versions of GnuTLS.
-* Client
-** Bug fix: Fix bashism in mandos-keygen.
-** Default key and subkey types are now RSA and RSA, respectively.
- Also, new default key size is 4096 bits.
-
-Version 1.6.0 (2012-06-18)
-* Server
-** Takes new --foreground option
-** Init script supports new "status" action.
-* Client
-** Now uses all interfaces by default; the --interface option can
- still be used to restrict it, and the argument to --interface (as
- well as the $DEVICE environment variable for the network hooks) is
- now a comma-separated list of interfaces to use.
-
-Version 1.5.5 (2012-06-01)
-* Server
-** Server takes new --socket option
-
-Version 1.5.4 (2012-05-20)
-* Server
-** Bug fix: Regression fix: Make non-zero approval timeout values work.
-** Bug fix: Regression fix: Allow changing the Timeout D-Bus property.
-** Fall back to not bind to an interface if an invalid interface name
- is given.
-** Removed support for undocumented feature of using plain "%%s" in
- "checker" client option.
-** Old D-Bus interface are now marked as deprecated.
-** mandos-monitor: Bug fix: show approval timers correctly.
-** mandos-ctl: Show "Extended Timeout" correctly, not as milliseconds.
-
-Version 1.5.3 (2012-01-15)
-* Server
-** Add D-Bus property se.recompile.Client.LastCheckerStatus and use it
- in mandos-monitor.
-* Client
-** Fix bugs in the example "bridge" network hook.
-
-Version 1.5.2 (2012-01-08)
-* Server
-** Removed D-Bus signal se.recompile.Mandos.NewRequest() added in
- 1.5.0. It was buggy and was of questionable utility.
-
-Version 1.5.1 (2012-01-01)
-* Server
-** Include intro(8mandos) manual page, missing since migration from
- README file in version 1.4.0.
-
-Version 1.5.0 (2012-01-01)
-* Client
-** Network hooks. The Mandos client can now run custom scripts to take
- up a network interface before the client is run. Three example
- scripts are provided: "wireless", "openvpn", and "bridge".
- To facilitate this, the client now prefers network interfaces which
- are up (if any) over all other interfaces.
-* Server
-** Persistent state. Client state is now saved between server
- restarts.
-** clients.conf file can now contain "enabled" setting for clients.
-** Bug fix: Fix rare crash bug.
-** Bug fix: Send corrent D-Bus type in PropertyChanged for
- "ApprovalDelay", "ApprovalDuration", "Timeout", and
- "ExtendedTimeout".
-** mandos-ctl: Bare numbers as arguments are taken to be milliseconds.
-** Bug fix: mandos-ctl --secret option now works.
-** New D-Bus signal: se.recompile.Mandos.NewRequest(s).
-
-Version 1.4.1 (2011-10-15)
-* Server
-** Make D-Bus properties settable again, and handle checkers
- for disabled clients correctly.
-* Miscellaneous fixes to "pedantic" Lintian warnings
-
-Version 1.4.0 (2011-10-09)
-* README file migrated to manual page intro(8mandos).
-* Client:
-** Fixed warning about "rmdir: Directory not empty".
-* Server:
-** Default values changed: timeout 5 minutes, interval 2 minutes.
-** Clients gets an expiration extension when receiving a password,
- controlled by new "extended_timeout" setting.
-** New domain name: "fukt.bsnet.se" changes to "recompile.se". This
- also affects the D-Bus bus and interface names (old names still
- work). Users should start using the new names immediately.
-** New D-Bus Client object properties "Expires" and "ExtendedTimeout";
- see DBUS-API for details.
-
-Version 1.3.1 (2011-07-27)
-* Client:
-** Client now retries all Mandos servers periodically.
-** Work around Debian bug #633582 - fixes "Permission denied" problem.
-
-Version 1.3.0 (2011-03-08)
-* Server:
-** Updated for Python 2.6.
-* Client:
-** Bug fix: Make the password-prompt plugin not conflict with
- Plymouth.
-** Bug fix: Bug fix: update initramfs also when purging package.
-
-Version 1.2.3 (2010-10-11)
-* Server:
-** Bug fix: Expose D-Bus API also in non-debug mode.
-
-Version 1.2.2 (2010-10-07)
-* Client:
-** splashy: Minor fix to compile with non-Linux kernels.
-
-Version 1.2.1 (2010-10-02)
-* Server:
-** mandos-monitor(8): Documentation bug fix: Key for removing client
- is "R", not "r".
-
-Version 1.2 (2010-09-28)
-* Client:
-** New "plymouth" plugin to ask for a password using the Plymouth
- graphical boot system.
-** The Mandos client now automatically chooses a network interface if
- the DEVICE setting in /etc/initramfs-tools/initramfs.conf is set to
- the empty string. This is also the new default instead of "eth0".
-** The Mandos client --connect option now loops indefinitely until a
- password is received from the specified server.
-** Bug fix: Quote directory correctly in mandos-keygen with --password
-** Bug fix: don't use "echo -e" in mandos-keygen; unsupported by dash.
-* Server:
-** Terminology change: clients are now "ENABLED" or "DISABLED", not
- "valid" or "invalid".
-** New D-Bus API; see the file "DBUS-API".
-** New control utilities using the new D-Bus API:
- + mandos-ctl A command-line based utility
- + mandos-monitor A text-based GUI interface
-** New feature: manual interactive approval or denying of clients on a
- case-by-case basis.
-** New --debuglevel option to control logging
-** Will not write PID file if --debug is passed
-** Bug fix: Avoid race conditions with short "interval" values or
- fast checkers.
-** Bug fix: Don't try to bind to a network interface when none is
- specified
-
-Version 1.0.14 (2009-10-25)
-Enable building without -pie and -fPIE if BROKEN_PIE is set.
-
-Version 1.0.13 (2009-10-22)
-* Client
-** Security bug fix: If Mandos server is also installed, do not copy
- its config files (with encrypted passwords) into the initrd.img-*
- files.
-
-Version 1.0.12 (2009-09-17)
-* Client
-** Bug fix: Allow network interface renaming by "udev" by taking down
- the network interface after using it.
-** Bug fix: User-supplied plugins are now installed correctly.
-** Bug fix: If usplash was used but the password was instead provided
- by the Mandos server, the usplash daemon used to ignore the first
- command passed to it. This has been fixed.
-** Bug fix: Make the "--userid" and "--groupid" options in
- "plugin-runner.conf" work.
-* Server
-** Bug fix: Fix the LSB header in the init.d script to make dependency
- based booting work.
-** A client receiving its password now also counts as if a checker was
- run successfully (i.e. the timeout timer is reset).
-
-Version 1.0.11 (2009-05-23)
-* Client
-** Bug fix: Use "pkg-config" instead of old "libgnutls-config".
-
-Version 1.0.10 (2009-05-17)
-* Client
-** Security bug fix: Fix permissions on initrd.img-*.bak files when
- upgrading from older versions.
-
-Version 1.0.9 (2009-05-17)
-* Client
-** Security bug fix: Fix permissions on initrd.img file when
- installing new linux-image-* packages calling mkinitramfs-kpkg (all
- version lower than 2.6.28-1-* does this).
-
-Version 1.0.8 (2009-02-25)
-* Client
-** Bug fix: Fix missing quote characters in initramfs-tools-hook.
-
-Version 1.0.7 (2009-02-24)
-* Client
-** Bug fix: Do not depend on GNU awk.
-
-Version 1.0.6 (2009-02-13)
-* Server
-** Fix bug where server would stop responding, with a zombie checker
-** Support for disabling IPv6 (only for advanced users)
-** Fix bug which made server not change group ID
-
-* Client
-** Bug fix: Fix permission for /lib64 (on relevant architechtures).
-** Add support for IPv4 addresses.
-** Add support in mandos-client for not bringing up a network
- interface by specifying an empty string to "--interface".
-** Make password prompt on boot not be mangled by kernel log messages
- about network interface.
-** Get network interface from initramfs.conf and/or from kernel
- command line.
-** If set by "ip=" kernel command line, configure network on boot.
-** Support connecting directly using "mandos=connect" kernel command.
- line option, provided network is configured using "ip=".
-** Fix bug which made plugin-runner and mandos-client not change group
- ID.
-** Fix bug where the "--options-for" option of plugin-runner would
- truncate the value at the first colon character.
-** Fix bug where plugin-runner would not go to fallback if all plugins
- failed.
-** Fix bug where mandos-client would not clean temporary directory on
- a signal or on certain file systems.
-** Bug fix: remove bashism in /bin/sh script "mandos-keygen".
-
-Version 1.0.5 (2009-01-17)
-* Client
-** Fix small memory leak in plugin-runner.
-
-Version 1.0.4 (2009-01-15)
-* Server
-** Only find matched user/group pairs when searching for suitable
- nonprivileged user/group to switch to.
-
-* Client
-** New kernel parameter "mandos=off" makes client not run at boot.
-** Fix linking errors and compilation warnings on AMD64.
-** Parse numbers in command line options better.
-** The splashy and usplash plugins are more robust while traversing
- /proc, and will not abort if a process suddenly disappears.
-
-Version 1.0.3 (2009-01-06)
-* Server
-** Now tries to change to user and group "_mandos" before falling back
- to trying the old values "mandos", "nobody:nogroup", and "65534".
-** Now does not abort on startup even if no clients are defined in
- clients.conf.
-
-* Client
-** Plugins named "*.dpkg-bak" are now ignored.
-** Hopefully fixed compilation failure on some architectures where the
- C compiler does not recognize the "-z" option as a linker option.
-
-Version 1.0.2 (2008-10-17)
-* mandos-keygen now signs the encrypted key blobs. This signature is
- not currently verified by mandos-client, but this may change in the
- future.
-
-Version 1.0.1 (2008-10-07)
-* Server
-** Expand environment variables and ~user in clients.conf's "secfile"
- The "secfile" option in /etc/mandos/clients.conf now expands
- "~user/foo" and "$ENVVAR" strings.
-
-* Client (plugin-runner, plugins, etc.)
-** Manual pages for the usplash, splashy, and askpass-fifo plugins.
- All plugins now have man pages.
-** More secure compilation and linking flags.
- All programs are now compiled with "-fstack-protector-all -fPIE
- -pie", and linked using "-z relro -pie" for additional security.
-
-* There is now a "NEWS" file (this one), giving a history of
- noteworthy changes.
=== removed file 'README'
--- README 2016-03-23 07:11:22 +0000
+++ README 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
-Please see: https://www.recompile.se/mandos/man/intro.8mandos
-
-This information previously in this file has been moved to the
-intro(8mandos) manual page. Go to the above URL, or install the
-Mandos server and run this command:
-
- man 8mandos intro
-
-In short, this is the Mandos system; it allows computers to have
-encrypted root file systems and at the same time be capable of remote
-and/or unattended reboots.
=== modified file 'TODO'
--- TODO 2019-04-09 19:41:53 +0000
+++ TODO 2008-07-29 03:35:39 +0000
@@ -1,124 +1,33 @@
--*- org -*-
-
-* Testing
-** python-nemu
-
-* mandos-applet
-
-* mandos-client
-** TODO A --server option which only adds to the server list.
- (Unlike --connect, which implicitly disables zeroconf.)
-** TODO [#B] Use capabilities instead of seteuid().
- https://forums.grsecurity.net/viewtopic.php?f=7&t=2522
-** TODO [#B] Use getaddrinfo(hints=AI_NUMERICHOST) instead of inet_pton()
-** TODO [#C] Make start_mandos_communication() take "struct server".
-** TODO [#C] --interfaces=regex,eth*,noregex (bridge-utils-interfaces(5))
-** TODO [#A] Detect partial writes to stdout and exit with EX_TEMPFAIL
-** TODO [#B] Use reallocarray() with GNU LibC 2.29 or later.
-
-* splashy
-** TODO [#B] use scandir(3) instead of readdir(3)
-** TODO [#A] Detect partial writes to stdout and exit with EX_TEMPFAIL
-
-* usplash (Deprecated)
-** TODO [#B] Make it work again
-** TODO [#B] use scandir(3) instead of readdir(3)
-** TODO [#A] Detect partial writes to stdout and exit with EX_TEMPFAIL
-
-* askpass-fifo
-** TODO [#A] Detect partial writes to stdout and exit with EX_TEMPFAIL
-
-* password-prompt
-** TODO [#B] lock stdin (with flock()?)
-** TODO [#A] Detect partial writes to stdout and exit with EX_TEMPFAIL
-
-* plymouth
-** TODO [#A] Detect partial writes to stdout and exit with EX_TEMPFAIL
-** TODO [#B] Use reallocarray() with GNU LibC 2.29 or later.
-
-* TODO [#B] passdev
-
-* plugin-runner
-** TODO handle printing for errors for plugins
-*** Hook up stderr of plugins, buffer them, and prepend "Mandos Plugin [plugin name]"
-** TODO [#C] use same file name rules as run-parts(8)
-** kernel command line option for debug info
-** TODO [#A] Restart plugins which exit with EX_TEMPFAIL
-
-* mandos (server)
-** TODO [#B] --notify-command
- This would allow the mandos.service to use
- --notify-command="systemd-notify --pid --ready"
-** TODO [#B] python-systemd
-*** import systemd.daemon; systemd.daemon.notify()
-** TODO [#B] Log level :BUGS:
-*** TODO /etc/mandos/clients.d/*.conf
- Watch this directory and add/remove/update clients?
-** TODO [#C] config for TXT record
-** TODO Log level dbus option
- SetLogLevel D-Bus call
-** TODO [#C] DBusServiceObjectUsingSuper
-** TODO [#B] Global enable/disable flag
-** TODO [#B] By-client countdown on number of secrets given
-** D-Bus Client method NeedsPassword(50) - Timeout, default disapprove
- + SetPass(u"gazonk", True) -> Approval, persistent
- + Approve(False) -> Close client connection immediately
-** TODO [#C] python-parsedatetime
-** TODO Separate logging logic to own object
-** TODO [#B] Limit approval_delay to max gnutls/tls timeout value
-** TODO [#B] break the wait on approval_delay if connection dies
-** TODO Generate Client.runtime_expansions from client options + extra
-** TODO Allow %%(checker)s as a runtime expansion
-** TODO D-Bus AddClient() method on server object
-** TODO Use org.freedesktop.DBus.Method.NoReply annotation on async methods. :2:
-** TODO Save state periodically to recover better from hard shutdowns
-** TODO CheckerCompleted method, deprecate CheckedOK
-** TODO Secret Service API?
- https://standards.freedesktop.org/secret-service/
-** TODO Remove D-Bus interfaces with old domain name :2:
-** TODO Remove old string_to_delta format :2:
-** TODO http://0pointer.de/blog/projects/stateless.html
-*** File in /usr/lib/sysusers.d to create user+group "_mandos"
-** TODO Error handling on error parsing config files
-** TODO init.d script error handling
-** TODO D-Bus server properties; address, port, interface, etc. :2:
-** Python 3 :2:
-*** TODO [#C] In Python 3.3, use shlex.quote() instead of re.escape()
-
-* mandos-ctl
-** TODO Remove old string_to_delta format :2:
-
-* TODO mandos-dispatch
- Listens for specified D-Bus signals and spawns shell commands with
- arguments.
-
-* mandos-monitor
-** TODO --servicename :BUGS:
-** TODO help should be toggleable
-** Urwid client data displayer
- Better view of client data in the listing
-*** Properties popup
-** Print a nice "We are sorry" message, save stack trace to log.
-
-* mandos-keygen
-** TODO "--secfile" option
- Using the "secfile" option instead of "secret"
-** TODO [#B] "--test" option
- For testing decryption before rebooting.
-
-* Package
-** /usr/share/initramfs-tools/hooks/mandos
-*** TODO [#C] use same file name rules as run-parts(8)
-*** TODO [#C] Do not install in initrd.img if configured not to.
- Use "/etc/initramfs-tools/hooksconf.d/mandos"?
-** TODO [#C] $(pkg-config --variable=completionsdir bash-completion)
- From XML sources directly?
-
-* Side Stuff
-** TODO Locate which package moves the other bin/sh when busybox is deactivated
-** TODO contact owner of package, and ask them to have that shell static in position regardless of busybox
-
-* [[http://www.undeadly.org/cgi?action=article&sid=20110530221728][OpenBSD]]
-
-
-#+STARTUP: showall
+[Mandos client]
+configuration for OpenPGP key dir
+header files/symbols tally
+check exit codes of all system calls
+IPv4 support
+protocol version header
+use strsep instead of strtok?
+
+[Pluginbasedclient]
+disable certain plugins
+header files/symbols tally
+check exit codes of all system calls
+change uid to nobody:nogroup
+ other drop privs stuff?
+pass things in environment, like device name, etc
+ Does cryptsetup already do this?
+Configurable plugin dir
+use strsep instead of strtok?
+
+[Server]
+config for:
+ TXT record
+protocol version header
+Run-time communication with server
+ probably using D-Bus
+
+[Mandos-tools/utilities]
+ List clients
+ Enable client
+ Disable client
+
+[Installer]
+...
=== removed file 'bugs.xml'
--- bugs.xml 2016-03-05 21:42:56 +0000
+++ bugs.xml 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
-
-
-
- Please report bugs to the Mandos development mailing list:
- mandos-dev@recompile.se (subscription required).
- Note that this list is public. The developers can be reached
- privately at mandos@recompile.se (OpenPGP key
- fingerprint 153A 37F1 0BBA 0435 987F 2C4A 7223 2973 CA34
- C2C4 for encrypted mail).
-
=== added file 'ca.pem'
--- ca.pem 1970-01-01 00:00:00 +0000
+++ ca.pem 2007-10-20 21:38:25 +0000
@@ -0,0 +1,40 @@
+-----BEGIN CERTIFICATE-----
+MIIHEzCCBPugAwIBAgIJAMCSQPxm3Tm7MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD
+VQQGEwJTRTELMAkGA1UECBMCQkwxEDAOBgNVBAcTB1Jvbm5lYnkxITAfBgNVBAoT
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEWMBQGA1UEAxMNQnJheGVuIHVuaXRl
+ZDEjMCEGCSqGSIb3DQEJARYUYmVsb3JuQGZ1a3QuYnNuZXQuc2UwHhcNMDcxMDE1
+MTczNDQ1WhcNMTcxMDEyMTczNDQ1WjCBjDELMAkGA1UEBhMCU0UxCzAJBgNVBAgT
+AkJMMRAwDgYDVQQHEwdSb25uZWJ5MSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRz
+IFB0eSBMdGQxFjAUBgNVBAMTDUJyYXhlbiB1bml0ZWQxIzAhBgkqhkiG9w0BCQEW
+FGJlbG9ybkBmdWt0LmJzbmV0LnNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAxrMpGUiDUI0X3XgYovgRGaKaSIoCL7RlNVRHxWLEaNIEmHuhQv40fksa
+ndO7KcbxBRTMvF/XNYyEEyks+D3jQrBmWBjsOSdZkLhP64HLnx2eYLd1HEAXIhB8
+wip180m9tfT6XeXX6cOh5AowMOGHv364xcZXJvYJgxVuMW1vlh9F79N1bnnR2rJ6
+4nmebJ91QW7ecSwA6h0fnx6GF3d5PfEC24/Fys/1NbdYiy8EYsP+lIEHQC4oD0Za
+kjclNWT3O1I8lnLdm4F1KdgDIva7aCyoAI4rLsxFxnnaqQcPo+8gGhusfnbOSymd
+m2tdz91x3Z2rSoo/cgc2TaPYKYuiJScsw1FftYGOZLiXbAedCqmoEC9XdMlZrbPn
+AWhjSvbFY8B2LCoy23OFpV2h+QrnKXOzsxyfxexwkjytIn9Msy5DlcCQz93vO/c9
+CGN/GpXJf5ebNk4oTE7pXNMM27shvubtXa6BL7A+S7yB8xmQ3NA+CABsQsKHcgVy
+2+SLD65Ms6OpwXn9BPlT1aJxbTiCXlSIQ7OIDPE1okwjxLTHc9dygoYuqjLG9Dkx
+WOqZWNxyj3kU40mX96qbOhJG5Zgq9J9fUT4ZJETO754YIFGKltlT6RSqeLrNOuLg
+9cYNGOLqoCVIyUi5HiTR7iIukNDeZy4YN6BiQH+TnYjC5+FwZbsCAwEAAaOCAXQw
+ggFwMB0GA1UdDgQWBBT4/xxxSVgFPLkDVNc8Ocdvodu3JTCBwQYDVR0jBIG5MIG2
+gBT4/xxxSVgFPLkDVNc8Ocdvodu3JaGBkqSBjzCBjDELMAkGA1UEBhMCU0UxCzAJ
+BgNVBAgTAkJMMRAwDgYDVQQHEwdSb25uZWJ5MSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxFjAUBgNVBAMTDUJyYXhlbiB1bml0ZWQxIzAhBgkqhkiG
+9w0BCQEWFGJlbG9ybkBmdWt0LmJzbmV0LnNlggkAwJJA/GbdObswDwYDVR0TAQH/
+BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQYwCQYDVR0SBAIwADArBglghkgBhvhC
+AQ0EHhYcVGlueUNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAfBgNVHREEGDAWgRRi
+ZWxvcm5AZnVrdC5ic25ldC5zZTAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEF
+BQADggIBAD/AJL0dKb4CcVEBzYsKV5JAxZQBTFYXm4TlMzbNJnl6C3FH636xSfvE
+qWWPrIplbmNn0tyXNf1dvb2Xy4QVFTo5lnp6PKwhqpV5JK7+4/LiDZj5R4VNl36B
+RUleXSSGV/+PJ1hRC9J/s+oziK1025hPpDB+n13sFrBv9DyqP/3GDSVoi13Mldf1
+vTWRnvugi7XlMhFdemB1Vz0eyIde0FtFpPrd3HeFrXQX8617XfcEYJmCU2aDT1fy
+77RHFG+3dL286UcK2D85bqNCntP9W3zP6rwerkO1pGmT2cBn9AO6Qt2MI7klTJmw
+SRqbeBcF+gaBRGY8iZHcqow7vqTvo65p/ZH9AUqMQh41W40FbepUA3354xGmwAlB
+LBXRuVjaDvKyargh936dOyzIDr+fZtr6BEthmt6BghgOZlezAV/P60P56DlFvpK8
+4wHyT5KI9LOqbg+W2ToB/GdRZz4p7K90JljrgVlnQhYIQ1YT/5OzPu6Uq5+4Q4hc
+ORb5hRCWHwre95kgEzUPqrteqV/g99XaOgqpK6KhY/dpmb7Z5I9f6d61XYYFfxYm
+iuNJiTLCQlLyfXFSRlJubWD8hNHo2HNRYdiWF3cttuGL9aC0uSIk4xq/Oi/guqIn
+sZlrO3I4MaiUnUXntMLU4zh0o/RPqhoT3lY1VubwgmpkOw8p7ggE
+-----END CERTIFICATE-----
=== added file 'cert.pem'
--- cert.pem 1970-01-01 00:00:00 +0000
+++ cert.pem 2007-10-20 21:38:25 +0000
@@ -0,0 +1,40 @@
+-----BEGIN CERTIFICATE-----
+MIIG8zCCBNugAwIBAgIBATANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMCU0Ux
+CzAJBgNVBAgTAkJMMRAwDgYDVQQHEwdSb25uZWJ5MSEwHwYDVQQKExhJbnRlcm5l
+dCBXaWRnaXRzIFB0eSBMdGQxFjAUBgNVBAMTDUJyYXhlbiB1bml0ZWQxIzAhBgkq
+hkiG9w0BCQEWFGJlbG9ybkBmdWt0LmJzbmV0LnNlMB4XDTA3MTAxNTE3MzczMVoX
+DTA4MTAxNDE3MzczMVowdTELMAkGA1UEBhMCU0UxCzAJBgNVBAgTAkJMMRAwDgYD
+VQQHEwdSb25uZWJ5MREwDwYDVQQKEwhHbnVzdHVmZjEPMA0GA1UEAxMGQnJheGVu
+MSMwIQYJKoZIhvcNAQkBFhRiZWxvcm5AZnVrdC5ic25ldC5zZTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAK4j59iJGfir5jxl4gCeLyhXED4YGd42o/ll
+XdWtYO9IHtrCZknnRIjjviQ0PJk6JQpIGkNrdW5uRSQcTKshcEOL8cprUHe+Mpi8
+34i7bOaPlDdJYoMatkHEvq92weXFfKa8yG5UtmAbiuo388JbnVgU7HAqq1ipi+dS
+MoJU0FR3qxKC3eioQQdq+QB257BeZNDq3SrWTqZXw7pu4DmiOZJhpMAV5CmjQKt4
+ZC0EdByGct0tp3X3swpBY+0a+wlFMKVe1WGy9dfhkNRVhUCXNKOCuaaIMsn8iuCc
+NlkIw4GVhvJj9ALfRZS5VzRaKIhOnFub4+PxYClt1ghfTBhk1aQjiSl1JT+qtgpv
+Sqd34OnYtLRp+L5EcLQSPoykG2TjsUxnYXtBiPoZuIk7v5alQlbT20DmuWhpCMm4
+fw1W0Q6eXL2APtrjAt7HS79qDopySL4st8nTkY3fzmjW8Vpg1Y4HyN6aY8tR9OIj
+SwZhCv+NoixbZToUnLXmoRtQnO6rSp7qLuJCPC1gbDc1TR4mclr5Vumb8ag1iQTi
+i0SvhqY8u1sDMGlL9aZW0WaykfoC64cUdBKm9R6dt08Y0xAevSaxdcsmK9kCfCJO
+o6nJ2pQ9+WdSjYEhq5DLBGhpfhzs+U1ZL0HYmTfyVjmbWuDZaQ1Yht4vHf1TYwAp
+FjGJGt/7AgMBAAGjggF0MIIBcDAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIG
+QDArBglghkgBhvhCAQ0EHhYcVGlueUNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd
+BgNVHQ4EFgQUoq4JMCRt6ToFRTrLNUFd4xQ0hGUwgcEGA1UdIwSBuTCBtoAU+P8c
+cUlYBTy5A1TXPDnHb6HbtyWhgZKkgY8wgYwxCzAJBgNVBAYTAlNFMQswCQYDVQQI
+EwJCTDEQMA4GA1UEBxMHUm9ubmVieTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMRYwFAYDVQQDEw1CcmF4ZW4gdW5pdGVkMSMwIQYJKoZIhvcNAQkB
+FhRiZWxvcm5AZnVrdC5ic25ldC5zZYIJAMCSQPxm3Tm7MB8GA1UdEgQYMBaBFGJl
+bG9ybkBmdWt0LmJzbmV0LnNlMB8GA1UdEQQYMBaBFGJlbG9ybkBmdWt0LmJzbmV0
+LnNlMA0GCSqGSIb3DQEBBQUAA4ICAQBC5Hz334l9o0RnjjjzZZyfYpEuAK7MJr6g
+r7hPqZzAAXL7i4w5AEutthIxo+JGGL0P4xv2Swc6uwodU0GE4/6DUEBQrjaDhr/F
+Uw3GaXYVopdDa/kYWAXF6lP+hkNhb1hI5onLMtRpoICLpfePNALZn3lMaBPI2efC
+EvViu3dpjJKKNm/HlXOl/wgrrcLwHKlbPSozaiXe2qxik4fr15cXtm4/nXetZq1g
+8NAOcZpdurZNEieMhtFSvLbQ3X/yNYKLgukz/zVCzL0IXLQXA4B2URBbzQJtrjOD
+Agq5mAXhrlGuEEvaMJeQP+VrfsIZU2fFKvr8LVQO37GprQizPFBC8FDkrE4XrpET
+A6ztDijyWRxT5x+4MbZrfL3GE9ZO57HZaAdXil1cjxXMlFqtJ6yoLNil3v+mgp9G
+yJeEz6L3jYRxVZqXYy7VMh+rJ7Mdr31g9pT8TT0/LGoCBorCTcUYIBP3BE3F85Nk
+JCPR5GG7Mfk3s8VTxTFAMZGKgst+i+YiMQSLkXIHNph5Fi18qIacpD9kkCXVj+JU
+UW/fYcTd4vQdR2HhyJdPddtHkprMN3ZlICEug3junMOJb0PWByqfuaihkPYIZ2xw
+puEkrP8cMdTXiUXep2RHTwByqy3/EQMC3ZWRiMIHZRIkl+o5bklOHwadUmzrJ1vL
+QjmtPc7y1g==
+-----END CERTIFICATE-----
=== added file 'client-cert.pem'
--- client-cert.pem 1970-01-01 00:00:00 +0000
+++ client-cert.pem 2007-10-20 21:38:25 +0000
@@ -0,0 +1,40 @@
+-----BEGIN CERTIFICATE-----
+MIIHBzCCBO+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMCU0Ux
+CzAJBgNVBAgTAkJMMRAwDgYDVQQHEwdSb25uZWJ5MSEwHwYDVQQKExhJbnRlcm5l
+dCBXaWRnaXRzIFB0eSBMdGQxFjAUBgNVBAMTDUJyYXhlbiB1bml0ZWQxIzAhBgkq
+hkiG9w0BCQEWFGJlbG9ybkBmdWt0LmJzbmV0LnNlMB4XDTA3MTAxNTIwNDkwNloX
+DTA4MTAxNDIwNDkwNlowfDELMAkGA1UEBhMCU0UxCzAJBgNVBAgTAkJMMRAwDgYD
+VQQHEwdSb25uZWJ5MREwDwYDVQQKEwhnbnVzdHVmZjEWMBQGA1UEAxQNYnJheGVu
+X2NsaWVudDEjMCEGCSqGSIb3DQEJARYUYmVsb3JuQGZ1a3QuYnNuZXQuc2UwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDWAwsXT4jeKCKg7/4g8KTmwEZ6
+88zfaJeqpzpkpc25J47Qmr5Mf6NiKUIAqjD8KycApG1cwVoLEvxvQOip2lSzL4ex
+ipTpZO45O6N5blKG4XKqJRE2VE5N1j2Z+jJmfFEaHqMDYb9+dlnSZ2c0c1d2qcgC
+HgOR5iZHWQCGtEK3y9HfWsFpULuzfYMIpYZjPic+kAuisT5cl/wIDVI/MbpB3/vk
+9vMpRCFRjvbOcN7rEW4UihuVSFmzFNk99QR8e3Li1HtqbXmmtJps9u16ugGQO4ED
+4gk65i5TU15sZJgFLXBuFuZFYH8WF2CIu6o4oylCLVjFRZHl8jKwZdPtNUZ01cJk
+oj+M9Yc9m6F1dLafLThhvSLMuRfUvHY9bFAkF6QkkgIjY1mN1VTm6XxLN991DJd7
+67IfpFrBaKi47C4abBc4lZYfBlmXdkpOt3UcYxh3YT+KTUK/7S/arj2iEypTic4x
+PVDsA4DbnHJ1+6ZzyMAM7ACmZnWhq7gXhjT8z3eEyaqaZVOracG1DFln781Mm6b9
+Eb3qJfczKR/QXiMsF4gwwH+Dclkd/THjjv/SPQYCiWm2Fo8IXG/hdZzBx4dWoSMZ
+kgQM5GDLQU80/jAvDni6n97I48fcxjL6YnEgQeoasKoayGaOmnhEs/eytpcGocNi
+3pJUpD0coYyAemeL5wIDAQABo4IBgTCCAX0wCQYDVR0TBAIwADARBglghkgBhvhC
+AQEEBAMCBLAwKwYJYIZIAYb4QgENBB4WHFRpbnlDQSBHZW5lcmF0ZWQgQ2VydGlm
+aWNhdGUwHQYDVR0OBBYEFK9FlbSWMi9o063eYNprvQ4Msg/FMIHBBgNVHSMEgbkw
+gbaAFPj/HHFJWAU8uQNU1zw5x2+h27cloYGSpIGPMIGMMQswCQYDVQQGEwJTRTEL
+MAkGA1UECBMCQkwxEDAOBgNVBAcTB1Jvbm5lYnkxITAfBgNVBAoTGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDEWMBQGA1UEAxMNQnJheGVuIHVuaXRlZDEjMCEGCSqG
+SIb3DQEJARYUYmVsb3JuQGZ1a3QuYnNuZXQuc2WCCQDAkkD8Zt05uzAfBgNVHRIE
+GDAWgRRiZWxvcm5AZnVrdC5ic25ldC5zZTAfBgNVHREEGDAWgRRiZWxvcm5AZnVr
+dC5ic25ldC5zZTALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggIBAINB3d3z
+FDRV5/+vov3KhyKhhDYdhO2IqkSXARRQffrd94/F/8YcrOgJJrvnz6THbQIzuSM7
+sSE2Y2JqyWfaA0J8CQm9JrOgVTE9I74/IZONC3jSBrt/Q9dG74otaeaHNOTaH4lU
+nAH5Cv6CgMFi58n+yQLxrYBAimWx8x1u40OxUXM+AbpAgDo3uXNt62SdrWAldwh3
+9Eqog3qUcN7R1VGx535VXJGg3e8yZFRPnFLiYuO1afjO/tlOyYBG0wvCfmNMSpcx
++/ycIXzTH5kvIcPoa8oCaAuCMgtsMZ2SoBJ37xgwb1qKjfVAOfju1qVYgI5jqQLp
+sNsS4FqyS7jpKoUxbcShvOui5GUunXgxZ/VMd7rqSqbC8ozKXvOEYaJWf9lY7DCR
+RdFR03CmWZ8EDO2JM1sKRni9gVz7wflSPjI8vDw9EbQzrW0Du64i4aBC2/kuJq9g
+7rEQrjMRh8/kQigCP1BUk1l+r/gPO8UeIBc7tTls0FsPIkKQq7cPNQgNiNIIV8v2
+iLW1bZmT2vswpiyqbz7LtGzYj+x1Ce+7U9iXgY08QgbiqiXl/eNw/xNVkFaMMDc2
+4+APQMF790OaZvWtme9XzePsy16wLgF4G/Xh1M8RfG3z7vXXm4Vl38iErZkXTmMl
+63Z87xA2LHvcoMEpP/nJHnvts3X2o3u7FFG9
+-----END CERTIFICATE-----
=== added file 'client-key.pem'
--- client-key.pem 1970-01-01 00:00:00 +0000
+++ client-key.pem 2007-10-20 21:38:25 +0000
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEA1gMLF0+I3igioO/+IPCk5sBGevPM32iXqqc6ZKXNuSeO0Jq+
+TH+jYilCAKow/CsnAKRtXMFaCxL8b0DoqdpUsy+HsYqU6WTuOTujeW5ShuFyqiUR
+NlROTdY9mfoyZnxRGh6jA2G/fnZZ0mdnNHNXdqnIAh4DkeYmR1kAhrRCt8vR31rB
+aVC7s32DCKWGYz4nPpALorE+XJf8CA1SPzG6Qd/75PbzKUQhUY72znDe6xFuFIob
+lUhZsxTZPfUEfHty4tR7am15prSabPbteroBkDuBA+IJOuYuU1NebGSYBS1wbhbm
+RWB/FhdgiLuqOKMpQi1YxUWR5fIysGXT7TVGdNXCZKI/jPWHPZuhdXS2ny04Yb0i
+zLkX1Lx2PWxQJBekJJICI2NZjdVU5ul8SzffdQyXe+uyH6RawWiouOwuGmwXOJWW
+HwZZl3ZKTrd1HGMYd2E/ik1Cv+0v2q49ohMqU4nOMT1Q7AOA25xydfumc8jADOwA
+pmZ1oau4F4Y0/M93hMmqmmVTq2nBtQxZZ+/NTJum/RG96iX3Mykf0F4jLBeIMMB/
+g3JZHf0x447/0j0GAolpthaPCFxv4XWcwceHVqEjGZIEDORgy0FPNP4wLw54up/e
+yOPH3MYy+mJxIEHqGrCqGshmjpp4RLP3sraXBqHDYt6SVKQ9HKGMgHpni+cCAwEA
+AQKCAgBha4c7+EecoXaJ/lWXlxPpurMauyqStGD+HRvWvycz1s8LJLXlyuCMCa3y
+8YZU9CvP/gmOhLHBgsYIuupuj2WpH8TMTAJXcEuFICHdYBwPLEdvLmp0adIvWow2
+MI+K2aJtmm6oVnG+Vo+y2MFBPhQdf1H9rL4BR1w7dEdqClqoog6Kdxy+HTMklMj2
+Qas4OA3TS+0QBVEXA1SGMdIz1CYuYJCg/M1aBpqILuUounavWQLcNLYzsXirrZzq
+uENvix6UJRd9LhKHkYUOfyVBjbSyfHPRWa7L8gY6hiPggbY1/SZF5wSxpiiT3NZj
+x9HH8HYSmuPjATVWEHeElwXu4CaOqax6OCMUwrIHWXUq/ydWjDXk/vK6PU1d2Fvh
+Y274QkBHwrDRZ7HiDLZDO6VVJx9O0WKajkLqidVMFzSZem+rxlIW8KwJUto8ObEi
+DK6VfkD0f1VfhWbVyb4dzgmloseHc9S/31ZBY4MfESpgVOh3rg12eXl4BVTRzDlf
+Qq0Z9hKuBaURt/CNv+ALpAp+u6mvzmNuSnjuXOkD3bmYwPZljykf1A3Cr8eyPK1E
+4PbLZN6Te7pbbjDvj+k23dzk1HUZ+I+5ykJi1v7tsQIiUOxFVJRMEmsfG+rMmKp6
++9fsgcqK0wpnZUJ325ghjaaGR4i4AUMYVHn+mTmbhCDis97Q2QKCAQEA71FMbFGt
+pBzYOCn9hMrBDIAU2tQNkmukeg7HremIyh5zm3Lt9YdSNGM/D1WqN3XdsdVczLoy
+l89jUTyoqoFQkackTkPxftUd6655CuOqSGFhr8xVk7SSvC9ZbwV69WgVJkYfrYv5
+3gXPAmBgc3S8S400ik5AtKh3XIQMsWwKPdpHKQZvbpyw851IoRQEzUhiT/Bi3Uug
+PzZHyFNmJMrPqSaot73zwkmkPK3KOCgAxStB/Ab2JNx8yjfL2UxIqunU5TaO65Wp
+2Be2mSPwYe0FZ8oE4HPKmOWJC7jHgT88OzdaeT9jBTOecGbvm/Wz2Rr83wUkMZlf
++/sF2XOrIsCSjQKCAQEA5O4oDf+t0vvEonTC9YE5bQ/rkSz4SKYI23nnI+u19C4E
+ntsHzrU9VMrnZV/Zc+j+z5hObgN179ePTvHLSjhvfo1zONGznl05YZRUE0dLf9bw
+ns3tNjxYc86BtYGGJfX8WqgsTLCTotrRY8hk2D2NupzB21WfaalWi2pZEsEq5vk4
+gqh7IwraS7x56GQTQIPfdQmv9XNfDh7VO4bcaqAI1n+KIpJTFVcEHnu6RpoQyE12
+F2oEQOo/S4nY2N+MZioavO46o9r4p/3V8CyuXQghkal2GHZeCkTpMto1BayHYOKc
+ZwxxLV/F/Nhr2BqJwiUojvbDcjcDeZVysjHQfNI1QwKCAQEAwwbd4OgvOa7IBf0y
+PSV+bVFzrWFiLhDK2S1yTKgkcZKfY+8lPRIqS8cVfMmzDb9gC6x1E+IpmM3JgkqM
+qWb44bn0PFPiWhoTaB2nRtiBzLqPgVRj6Rse+X0cxP0SVyubELXU2vlXhzf0m1sv
+PufDC07nok5jLNadbyetsGj7b6ySkTxNUzcefWmP5rUJtMFoXPzplK4syVbS6M4O
+T613zcFTfWmvXIXm8gwu39S5y/SUsW566U9F4wXVeiBQl/g3JxRvJE2zPAcXJ3XC
+UAt4fDyF/ORgFnn4VTUgYJPH4foaIPUnHPYUCEXavp5dEnCL4rOt6z2ymwbWnX9F
+1+xXgQKCAQEAr1XAE8ipRxhRJ+OplgKdCuzQjOYWWv3fdslMwHQ9bYD5RPmYZzbk
+fFbTFw9sKpxe3HxYRWYdI87DEcGa44OJ0TFg+DmUCkx4MEY8hm9qYcUrkVVCwvFB
+BaE6Mtu69MQLvRtkom/zAx34lSXcJsouDKkWyHgxmel6QVj4U6bixvhF0bxcYyBi
+xPLbo6NSI21c7fS3cZQlT1lKE0dc9cUQP8h68bOEMqnsm7RDnONOyzqYoaIvE9DV
+HXO8Q44jp/PDesQy4WBKZc/B1StDeDlMDJXvvxiZOeBBgxMg3PGg1hF5nGspG4lo
+yBixsFfS/oEbKTPRyV5dKPfPWq9QcOlGpQKCAQEAwe2qtx7tzI7cdx1JLSHNZyPp
+h9/WTjYKVg3Sl6dXfDsNTqIUkRrwpB1tEZXs1PIq5641ev4LmRxGDPLJWIwNZ1LN
+slR12towc6LTY/05OIBHrTIAW8fGs2E4YcqYcLWsWuzU9BsJLQeBdUth9zF6qZoK
+USN6a3326dx8lhUcQ4zJ9c/DtK+99WAXtt0Cki7aICvLbcsmRbKPHpJyzRpDI7uH
+Ex/UgjSR1w5L2Seou3e6ljxYGAecqa86HIkHVleDIrIYl6GlKDBKSVzfmLh/97mi
+o3oTNqRal934xYS6ZTId/ZkRL5c78U/NJlK1H5gYzfL65mJ1+c2N3cR3sy4jtQ==
+-----END RSA PRIVATE KEY-----
=== modified file 'clients.conf'
--- clients.conf 2019-02-09 23:34:15 +0000
+++ clients.conf 2008-07-29 03:35:39 +0000
@@ -1,93 +1,33 @@
-# Default settings for all clients. These values are the default
-# values, so uncomment and change them if you want different ones.
[DEFAULT]
-
-# How long until a client is disabled and not be allowed to get the
-# data this server holds.
-;timeout = PT5M
-
-# How often to run the checker to confirm that a client is still up.
-# Note: a new checker will not be started if an old one is still
-# running. The server will wait for a checker to complete until the
-# above "timeout" occurs, at which time the client will be disabled,
-# and any running checker killed.
-;interval = PT2M
-
-# Extended timeout is an added timeout that is given once after a
-# password has been sent sucessfully to a client. This allows for
-# additional delays caused by file system checks and quota checks.
-;extended_timeout = PT15M
-
-# What command to run as "the checker".
-;checker = fping -q -- %%(host)s
-
-# Whether to approve a client by default after the approval delay.
-;approved_by_default = True
-
-# How long to wait for approval.
-;approval_delay = PT0S
-
-# How long one approval will last.
-;approval_duration = PT1S
-
-# Whether this client is enabled by default
-;enabled = True
-
-
-;####
-;# Example client
-;[foo]
-;
-;# TLS public key ID
-;key_id = f33fcbed11ed5e03073f6a55b86ffe92af0e24c045fb6e3b40547b3dc0c030ed
-;
-;# OpenPGP key fingerprint
-;fingerprint = 7788 2722 5BA7 DE53 9C5A 7CFA 59CF F7CD BD9A 5920
-;
-;# This is base64-encoded binary data. It will be decoded and sent to
-;# the client matching the above fingerprint. This should, of course,
-;# be OpenPGP encrypted data, decryptable only by the client.
-;secret =
-; hQIOA6QdEjBs2L/HEAf/TCyrDe5Xnm9esa+Pb/vWF9CUqfn4srzVgSu234
-; REJMVv7lBSrPE2132Lmd2gqF1HeLKDJRSVxJpt6xoWOChGHg+TMyXDxK+N
-; Xl89vGvdU1XfhKkVm9MDLOgT5ECDPysDGHFPDhqHOSu3Kaw2DWMV/iH9vz
-; 3Z20erVNbdcvyBnuojcoWO/6yfB5EQO0BXp7kcyy00USA3CjD5FGZdoQGI
-; Tb8A/ar0tVA5crSQmaSotm6KmNLhrFnZ5BxX+TiE+eTUTqSloWRY6VAvqW
-; QHC7OASxK5E6RXPBuFH5IohUA2Qbk5AHt99pYvsIPX88j2rWauOokoiKZo
-; t/9leJ8VxO5l3wf/U64IH8bkPIoWmWZfd/nqh4uwGNbCgKMyT+AnvH7kMJ
-; 3i7DivfWl2mKLV0PyPHUNva0VQxX6yYjcOhj1R6fCr/at8/NSLe2OhLchz
-; dC+Ls9h+kvJXgF8Sisv+Wk/1RadPLFmraRlqvJwt6Ww21LpiXqXHV2mIgq
-; WnR98YgSvUi3TJHrUQiNc9YyBzuRo0AjgG2C9qiE3FM+Y28+iQ/sR3+bFs
-; zYuZKVTObqiIslwXu7imO0cvvFRgJF/6u3HNFQ4LUTGhiM3FQmC6NNlF3/
-; vJM2hwRDMcJqDd54Twx90Wh+tYz0z7QMsK4ANXWHHWHR0JchnLWmenzbtW
-; 5MHdW9AYsNJZAQSOpirE4Xi31CSlWAi9KV+cUCmWF5zOFy1x23P6PjdaRm
-; 4T2zw4dxS5NswXWU0sVEXxjs6PYxuIiCTL7vdpx8QjBkrPWDrAbcMyBr2O
-; QlnHIvPzEArRQLo=
-;
-;# Host name; used only by the checker, not used by the server itself.
-;host = foo.example.org
-;####
-
-;####
-;# Another example client, named "bar".
-;[bar]
-;# The key ID is not space or case sensitive
-;key_id = F33FCBED11ED5E03073F6A55B86FFE92 AF0E24C045FB6E3B40547B3DC0C030ED
-;
-;# The fingerprint is not space or case sensitive
-;fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27
-;
-;# If "secret" is not specified, a file can be read for the data.
-;secfile = /etc/keys/mandos/bar-secret.bin
-;
-;# An IP address for host is also fine, if the checker accepts it.
-;host = 192.0.2.3
-;
-;# Parameters from the [DEFAULT] section can be overridden per client.
-;interval = PT1M
-;
-;# This client requires manual approval before it receives its secret.
-;approved_by_default = False
-;# Require approval within 30 seconds.
-;approval_delay = PT30S
-;####
+timeout = 1h
+interval = 5m
+checker = fping -q -- %%(fqdn)s
+
+# Example
+[foo]
+fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27
+secret = Base+64+encoded+OpenPGP+encrypted+data/=
+# secfile = /etc/mandos/foo-secret.txt.asc
+fqdn = foo.example.org
+checker = fping -q -- %%(fqdn)s
+timeout = 10m
+
+[braxen_client]
+fingerprint = 7788 2722 5BA7 DE53 9C5A 7CFA 59CF F7CD BD9A 5920
+secret =
+ hQIOA6QdEjBs2L/HEAf/TCyrDe5Xnm9esa+Pb/vWF9CUqfn4srzVgSu234REJMVv
+ 7lBSrPE2132Lmd2gqF1HeLKDJRSVxJpt6xoWOChGHg+TMyXDxK+NXl89vGvdU1Xf
+ hKkVm9MDLOgT5ECDPysDGHFPDhqHOSu3Kaw2DWMV/iH9vz3Z20erVNbdcvyBnuoj
+ coWO/6yfB5EQO0BXp7kcyy00USA3CjD5FGZdoQGITb8A/ar0tVA5crSQmaSotm6K
+ mNLhrFnZ5BxX+TiE+eTUTqSloWRY6VAvqWQHC7OASxK5E6RXPBuFH5IohUA2Qbk5
+ AHt99pYvsIPX88j2rWauOokoiKZot/9leJ8VxO5l3wf/U64IH8bkPIoWmWZfd/nq
+ h4uwGNbCgKMyT+AnvH7kMJ3i7DivfWl2mKLV0PyPHUNva0VQxX6yYjcOhj1R6fCr
+ /at8/NSLe2OhLchzdC+Ls9h+kvJXgF8Sisv+Wk/1RadPLFmraRlqvJwt6Ww21Lpi
+ XqXHV2mIgqWnR98YgSvUi3TJHrUQiNc9YyBzuRo0AjgG2C9qiE3FM+Y28+iQ/sR3
+ +bFszYuZKVTObqiIslwXu7imO0cvvFRgJF/6u3HNFQ4LUTGhiM3FQmC6NNlF3/vJ
+ M2hwRDMcJqDd54Twx90Wh+tYz0z7QMsK4ANXWHHWHR0JchnLWmenzbtW5MHdW9AY
+ sNJZAQSOpirE4Xi31CSlWAi9KV+cUCmWF5zOFy1x23P6PjdaRm4T2zw4dxS5NswX
+ WU0sVEXxjs6PYxuIiCTL7vdpx8QjBkrPWDrAbcMyBr2OQlnHIvPzEArRQLo=
+ =iHhv
+fqdn = localhost
+interval = 5m
=== removed file 'common.ent'
--- common.ent 2019-09-03 19:06:41 +0000
+++ common.ent 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
-
-
-
=== added file 'crl.pem'
--- crl.pem 1970-01-01 00:00:00 +0000
+++ crl.pem 2007-10-20 21:38:25 +0000
@@ -0,0 +1,18 @@
+-----BEGIN X509 CRL-----
+MIIC0zCBvDANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMCU0UxCzAJBgNVBAgT
+AkJMMRAwDgYDVQQHEwdSb25uZWJ5MSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRz
+IFB0eSBMdGQxFjAUBgNVBAMTDUJyYXhlbiB1bml0ZWQxIzAhBgkqhkiG9w0BCQEW
+FGJlbG9ybkBmdWt0LmJzbmV0LnNlFw0wNzEwMTUxNzQ2MTlaFw0wNzExMTQxNzQ2
+MTlaMA0GCSqGSIb3DQEBBQUAA4ICAQCYTCUYRfx8+lTNXsVMhLT/890agPGj7BQw
+NhwHTZuEudPTxBtOLPf0za4z7eGTD9ggu7SayQWEOV4bfjv1yiOLzf6vEHdzv1Ee
+mlLhYgDMIhACrQmfKAmjoabsaK+VccBJW/R1oNW5Z9sWjFP91+3T7lfp8pPvWAlf
++9mJaaysd1yguY0OITAIWEL2lLlGtd85RYLvJe2nWZ6GrH5mIEYA7IQrnPgcU3ij
+eAEn88I7EofUHfn1TMpMDJgMKm/edvEerLKb62AblcGLfo4gOBQWcvCAWLPzqxhE
+wKag1xL8ucG6250yfkYBf3KEMLZAU8py5MwaIqMVOQzz3gsQ7dE87xR5GndLvPvr
+149RbKDSZDdPDOEmCqlmb/Sxppm7jsNwqAphrZlNsBgLTrxih7Ex1cFph4jA5AZ5
+Hgqpftb94CdauOPz/AVu5aeXIwG0dpxhN0dtemwhHIxslFwDtuFWwcmP3upDZUOM
+Q4ZZBp2A1lhDW86w3law8E2TCuDFmwNtqp5zOMtOwAJF2RK2DquaaxKQG0JRhdTi
+f3mzjTTRPXomBgf7U1W25RFMO91uslCijAr/ELAa9SkFYWArnbfGabDsoy3OGL8D
+fjuaz2eIdwvASyPwUkGlfeFBRDNIRCZ3szsvtThMFWUxKvKTRBTJf4AFLwx3XWOS
+R6IxSk3t0A==
+-----END X509 CRL-----
=== removed file 'dbus-mandos.conf'
--- dbus-mandos.conf 2011-10-02 19:18:24 +0000
+++ dbus-mandos.conf 1970-01-01 00:00:00 +0000
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
=== removed directory 'debian'
=== removed file 'debian/changelog'
--- debian/changelog 2019-09-04 21:17:42 +0000
+++ debian/changelog 1970-01-01 00:00:00 +0000
@@ -1,928 +0,0 @@
-mandos (1.8.9-2) unstable; urgency=medium
-
- * Fix failing autopkgtest.
- * debian/tests/control (mandos-check/Restrictions): Add "allow-stderr".
-
- -- Teddy Hogeborn Wed, 04 Sep 2019 23:14:06 +0200
-
-mandos (1.8.9-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "Python2 removal in sid/bullseye" by using Python 3 instead
- (Closes: #936987)
- * debian/control (Build-Depends, Build-Depends-Indep): Move "systemd"
- from indep to regular build-depends.
- (Build-Depends-Indep, Package: mandos/Depends): Depend on Python 3 and
- Python 3 modules instead of Python 2.
-
- -- Teddy Hogeborn Tue, 03 Sep 2019 20:58:27 +0200
-
-mandos (1.8.8-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/po/de.po: New; Fix "[INTL:de] Initial German debconf
- translation" by including the contributed translation (Closes:
- #934373)
- * debian/po/fr.po: New; Fix "[INTL:fr] French debconf templates
- translation" by including the contributed translation (Closes:
- #934888)
- * debian/po/sv.po: New Swedish translation.
- * debian/mandos.postinst: Only reload D-Bus daemon if new user was
- created.
- * debian/mandos.dirs (usr/lib/sysusers.d): New.
- * debian/mandos-client.dirs (usr/lib/sysusers.d): - '' -
-
- -- Teddy Hogeborn Sun, 18 Aug 2019 22:01:13 +0200
-
-mandos (1.8.7-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/upstream/metadata: New.
- * debian/mandos-client.postrm: Use the same logic as the
- update_initramfs function in debian/mandos-client.postinst.
- * debian/mandos-client.templates (mandos-client/key_id): Line which
- should not be wrapped should be prefixed by a space.
- * debian/mandos.templates (mandos/key_id): - '' -
- * debian/po/en_US.po: New "translation" from ASCII to UTF-8.
- * debian/po/templates.pot: Updated.
- * debian/source/lintian-overrides
- (package-uses-old-debhelper-compat-version): New; set to "10".
- * debian/mandos-client.lintian-overrides
- (maintainer-script-supports-ancient-package-version): New.
- debian/mandos.lintian-overrides
- (maintainer-script-supports-ancient-package-version): - '' -
-
- -- Teddy Hogeborn Mon, 05 Aug 2019 23:22:00 +0200
-
-mandos (1.8.6-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "mandos FTCBFS: hard codes build architecture pkg-config"
- by making pkg-config overridable (Closes: #933701)
- * debian/mandos.postinst (configure): After creating (or renaming) user
- & group, reload D-Bus daemon (if present).
-
- -- Teddy Hogeborn Sat, 03 Aug 2019 14:51:01 +0200
-
-mandos (1.8.5-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "does not reap children" by reaping children (Closes: #933387)
- * debian/mandos-client.README.Debian: Use new-style interface name.
- * debian/tests/control: New file; implements autopkgtest support.
- * debian/mandos-client.lintian-overrides
- (manpage-has-errors-from-man): Remove; unnecessary.
- * debian/mandos.lintian-overrides
- (init.d-script-needs-depends-on-lsb-base): - '' -
- * debian/mandos-client.postinst (update_initramfs): Upstream now
- supports dracut(8), so update commands here to and run the correct
- command to update initramfs.
- * debian/control (Build-Depends): Add GLib -dev package.
- (mandos-client/Depends): Add dracut(8) as an alternative dependency to
- initramfs-tools.
- (mandos-client/Conflicts): New; set to "dracut-config-generic".
- (debian/mandos-client.README.Debian): Update for dracut(8) support.
- * debian/mandos-client.templates: Reflowed by debconf-gettextize(1).
- * debian/mandos.templates: - '' -
- * debian/po/POTFILES.in: New.
- * debian/po/templates.pot: - '' -
- * debian/source/lintian-overrides: New.
- * debian/control (Standards-Version): Update to "4.4.0".
-
- -- Teddy Hogeborn Tue, 30 Jul 2019 20:41:29 +0200
-
-mandos (1.8.4-1) unstable; urgency=medium
-
- * Fix "dirs in initrd are not accessible by mandos plugin-runner" by
- making sure UMASK is set, no matter what other packages have installed
- in "/usr/share/initramfs-tools/conf-hooks.d". (Closes: #926641)
- * Fix "LeakSanitizer: detected memory leaks, fails to decrypt"
- by fixing memory leak in plugin-runner. (Closes: #926643)
- * debian/mandos-client.dirs: Add
- "usr/share/initramfs-tools/conf-hooks.d", needed by fix for #926641.
-
- -- Teddy Hogeborn Tue, 09 Apr 2019 22:05:39 +0200
-
-mandos (1.8.3-3) unstable; urgency=medium
-
- * Fix "src:mandos: modifies d/control during build" by not doing that
- anymore. (Closes: #922202)
- * debian/rules (override_dh_shlibdeps-arch): Commented out.
-
- -- Teddy Hogeborn Wed, 13 Feb 2019 09:52:39 +0100
-
-mandos (1.8.3-2) unstable; urgency=medium
-
- * debian/rules (override_dh_shlibdeps-arch): New; conditionally edit
- debian/control before running dh_shlibdeps.
-
- -- Teddy Hogeborn Mon, 11 Feb 2019 12:49:57 +0100
-
-mandos (1.8.3-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/watch: Make the ".orig" file name suffix non-optional;
- otherwise uscan thinks that ".orig" is part of the version number.
- * debian/control (Build-Depends): Changed GnuTLS dependencies; move
- 3.6.6 alternative to first in list, and remove dependencies on the
- virtual package "gnutls-dev", since we need the version restrictions.
- (Package: mandos/Depends): Remove dependency on libgnutls28-dev
- package.
- (Package: mandos/Suggests): New; set to "libc6-dev, c-compiler". (Used
- to find value of "SO_BINDTODEVICE").
- (Package: mandos-client/Depends): Don't depend on openssl anymore;
- instead depend on either a gnutls-bin (>= 3.6.6) (in which case TLS
- key generation will work), or on libgnutls30 (<< 3.6.0) (in which case
- TLS key generation will not be needed).
-
- -- Teddy Hogeborn Mon, 11 Feb 2019 07:30:32 +0100
-
-mandos (1.8.2-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/mandos-client.postinst (create_keys): Ignore failure to remove
- bad keys.
-
- -- Teddy Hogeborn Sun, 10 Feb 2019 11:44:56 +0100
-
-mandos (1.8.1-1) unstable; urgency=high
-
- * New upstream release.
- * debian/mandos-client.postinst (create_keys): Remove any bad keys
- created by 1.8.0-1. Only create TLS keys if certtool succeeds.
- * debian/mandos.postinst (configure): Remove any bad keys from
- clients.conf, and inform the user if any were found.
- * debian/mandos.templates (mandos/removed_bad_key_ids): New message.
-
- -- Teddy Hogeborn Sun, 10 Feb 2019 10:00:21 +0100
-
-mandos (1.8.0-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "(tries to) use GnuTLS OpenPGP support" by using raw public keys
- when available (Closes: #879538)
- * Fix "mandos : Depends: libgnutls30 (< 3.6.0) but 3.6.5-2 is to be
- installed" by now also allowing GnuTLS >= 3.6.6 (Closes: #916673)
- * debian/control (Standards-Version): Update to "4.3.0".
- (Package: mandos-client/Depends): Change from "cryptsetup" to
- "cryptsetup (<< 2:2.0.3-1) | cryptsetup-initramfs". Add "debconf (>=
- 1.5.5) | debconf-2.0".
- (Source: mandos/Build-Depends): Also allow libgnutls30 (>= 3.6.6).
- (Package: mandos/Depends): - '' - and add debconf (>= 1.5.5) |
- debconf-2.0".
- (Package: mandos/Description): Alter description to match new design.
- (Package: mandos-client/Description): - '' -
- (Package: mandos-client/Depends): Move "gnutls-bin | openssl" to here
- from "Recommends".
- * debian/mandos-client.README.Debian: Add --tls-privkey and --tls-pubkey
- options to test command.
- * debian/mandos-client.postinst (create_key): Renamed to "create_keys"
- - all callers changed - and also create TLS key files. Show notice if
- new TLS key files were created.
- * debian/mandos-client.postrm (purge): Also remove TLS key files.
- * debian/mandos-client.lintian-overrides: Override warnings.
- * debian/mandos-client.templates: New.
- * debian/mandos.lintian-overrides: Override warnings.
- * debian/mandos.postinst (configure): If GnuTLS 3.6.6 or later is
- detected, show an important notice (once) about the new key_id option
- required in clients.conf.
- * debian/mandos.templates: New.
- * debian/copyright: Update copyright year to 2019.
-
- -- Teddy Hogeborn Sun, 10 Feb 2019 05:52:49 +0100
-
-mandos (1.7.20-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "[tethys] mandos-client: Mandos client fails while booting but
- works from chroot into unpacked initramfs" by setting system clock if
- necessary (Closes: #894495)
- * Fix "initramfs boot script assumes internal cryptsetup implementation
- details and is now broken" by only using documented
- interfaces (Closes: #904899)
- * debian/mandos-client.dirs: Add
- "usr/share/initramfs-tools/scripts/local-premount" and
- "usr/share/initramfs-tools/conf.d", and remove
- "usr/share/initramfs-tools/conf-hooks.d".
- * debian/control (mandos-client/Depends): Add "(>= 0.99)" to dependency
- on "initramfs-tools".
- * debian/control (Source: mandos/Rules-Requires-Root): New; set to
- "binary-targets".
- (Standards-Version): Update to "4.2.0".
-
- -- Teddy Hogeborn Sun, 19 Aug 2018 22:14:04 +0200
-
-mandos (1.7.19-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "fails with "LeakSanitizer has encountered a fatal error"" by not
- using LeakSanitizer in affected binary (Closes: #886595)
-
- -- Teddy Hogeborn Thu, 22 Feb 2018 19:47:59 +0100
-
-mandos (1.7.18-1) unstable; urgency=medium
-
- * New upstream release.
-
- -- Teddy Hogeborn Mon, 12 Feb 2018 16:00:11 +0100
-
-mandos (1.7.17-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "fails with "LeakSanitizer has encountered a fatal error""
- by fixing memory leak in plugin-runner (Closes: #886595)
- * debian/control (Build-Depends): Also depend on "libgnutls28-dev (<<
- 3.6.0) | libgnutls30 (<< 3.6.0)".
- (Package: mandos/Depends): - '' -
- * debian/compat: Change to "10".
- * debian/watch (version): Change to "4".
- (opts/pgpsigurlmangle): Remove.
- (opts/pgpmode): New; set to "auto".
- (URL): Change to "https://ftp.recompile.se/pub/@PACKAGE@/@PACKAGE@
- @ANY_VERSION@(?:\.orig)?@ARCHIVE_EXT@".
- * debian/copyright: Update copyright year to 2018.
- * debian/rules: Support the "noopt" and "parallel" DEB_BUILD_OPTIONS.
- (override_dh_fixperms-arch): Use the DEB_HOST_MULTIARCH
- variable directly instead of shelling out to "dpkg-architecture".
- * debian/control (Standards-Version): Update to "4.1.3".
- (Build-Depends): Change version of debhelper dependency to ">= 10".
- * debian/mandos.lintian-overrides
- (init.d-script-needs-depends-on-lsb-base): Change line number to "46".
-
- -- Teddy Hogeborn Sat, 10 Feb 2018 19:09:50 +0100
-
-mandos (1.7.16-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/copyright (License): Use program name explicitly.
- (Format): Use https in URL.
- * debian/control (Priority): Change from "extra" to "optional".
- (Standards-Version): Update to "4.0.1".
-
- -- Teddy Hogeborn Sun, 20 Aug 2017 21:05:26 +0200
-
-mandos (1.7.15-1) unstable; urgency=medium
-
- * New upstream release.
- * Upstream release fixes "Seems not to be honoring zeroconf option at
- mandos.conf" (Closes: #855589)
- * debian/mandos.lintian-overrides (mandos): Add new line
- "init.d-script-needs-depends-on-lsb-base etc/init.d/mandos (line 49)".
- * debian/copyright: Update copyright year to 2017.
-
- -- Teddy Hogeborn Thu, 23 Feb 2017 21:29:36 +0100
-
-mandos (1.7.14-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/mandos-client.postinst (create_key): Stop GPG agent after
- running mandos-keygen.
- * debian/control (Package: mandos/Depends): Add "systemd-sysv | lsb-base
- (>= 3.0-6)", change "gnupg" to "gnupg2 | gnupg", and change
- "libgpgme11-dev" to "libgpgme-dev | libgpgme11-dev".
-
- -- Teddy Hogeborn Wed, 25 Jan 2017 20:36:03 +0100
-
-mandos (1.7.13-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "fails to install noninteractively" by using the "%no-protection"
- statement in the GnuPG batch parameter file. (Closes: #840001)
-
- -- Teddy Hogeborn Sat, 08 Oct 2016 06:31:07 +0200
-
-mandos (1.7.12-1) unstable; urgency=medium
-
- * New upstream release.
-
- -- Teddy Hogeborn Wed, 05 Oct 2016 22:06:55 +0200
-
-mandos (1.7.11-1) unstable; urgency=high
-
- * New upstream release.
- * debian/control (Source: mandos/Vcs-Bzr): Change to use HTTPS.
- (Vcs-Browser): - '' -
-
- -- Teddy Hogeborn Sat, 01 Oct 2016 16:20:48 +0200
-
-mandos (1.7.10-1) unstable; urgency=high
-
- * New upstream release.
- * debian/rules (override_dh_fixperms-arch): Also exclude
- "etc/mandos/plugin-helpers" from changes by dh_fixperms.
- * debian/mandos-client.postinst: Fix the permissions of
- "/etc/mandos/plugin-helpers" for those systems which had a fresh
- install of an older version.
-
- -- Teddy Hogeborn Thu, 23 Jun 2016 22:00:29 +0200
-
-mandos (1.7.9-1) unstable; urgency=medium
-
- * New upstream release.
-
- -- Teddy Hogeborn Wed, 22 Jun 2016 07:30:12 +0200
-
-mandos (1.7.8-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "bad gpgme_op_decrypt: GPGME: Decryption failed." by copying
- /usr/bin/gpg-agent into initramfs (Closes: #819982)
- * debian/control (Homepage): Change URL to use HTTPS.
- (Standards-Version): Update to 3.9.8.
- * debian/copyright (Source): Change URL to HTTPS.
- * debian/mandos-client.README.Debian: Change wording to match updated
- capabilities.
-
- -- Teddy Hogeborn Tue, 21 Jun 2016 21:36:10 +0200
-
-mandos (1.7.7-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/mandos-client.postinst (configure): If older version, fix
- permissions on plugin helper directory. Also fix permissions on
- plugin helper local override directory (/etc/mandos/plugin-helpers),
- but only if not listed by "dpkg-statoverride".
- * debian/rules (override_dh_fixperms-arch): Exclude plugin helper
- directory from dh_fixperms.
- * debian/mandos.postinst (configure): Fix state directory permissions,
- but only if not listed by "dpkg-statoverride".
- * debian/mandos-client.lintian-overrides: Do not warn about permissions
- on plugin helper directory.
- * debian/mandos.dirs (usr/lib/tmpfiles.d): Added.
-
- -- Teddy Hogeborn Sat, 19 Mar 2016 22:58:49 +0100
-
-mandos (1.7.6-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/control (Source: mandos/Build-Depends-Indep): Remove
- "python-avahi".
- (Source: mandos/Build-Depends-Indep): Change "python-gi |
- python-gobject" to "python-gi"; i.e. remove "python-gobject".
-
- -- Teddy Hogeborn Sun, 13 Mar 2016 22:58:23 +0100
-
-mandos (1.7.5-1) unstable; urgency=high
-
- * New upstream release.
- * debian/mandos.postinst (configure): If old version was 1.7.4-1 or
- 1.7.4-1~bpo8+1, fix situation where clients.pickle file is owned by
- root.
-
- -- Teddy Hogeborn Tue, 08 Mar 2016 01:09:55 +0100
-
-mandos (1.7.4-1) unstable; urgency=medium
-
- * New upstream release.
- * initramfs-tools-script: Fix "Call to configure_network in initramfs
- script broken due to set -e" by surrounding call by "set +x" and "set
- -e" (Closes: #816513)
- * debian/control: (Source: mandos/Build-Depends-Indep): Change
- "python-gobject | python-gi" to "python-gi | python-gobject"
- (Package: mandos/Depends): - '' -
-
- -- Teddy Hogeborn Sat, 05 Mar 2016 23:10:07 +0100
-
-mandos (1.7.3-1) unstable; urgency=medium
-
- * New upstream release.
-
- -- Teddy Hogeborn Mon, 29 Feb 2016 22:26:38 +0100
-
-mandos (1.7.2-1) unstable; urgency=medium
-
- * New upstream release.
- * Fix "Uses unneeded and obsolete version specific python packages"
- by removing version-specific dependencies (Closes: #811159)
- * debian/control (Source: mandos/Build-Depends): Add (>= 3.3.0) to
- "libgnutls28-dev" and "gnutls-dev".
- (Source: mandos/Build-Depends-Indep): Remove "python2.7-gnutls",
- "python2.7", "python2.7-dbus", "python2.7-avahi", and
- "python2.7-gobject"; replace with "python (>= 2.7), python (<< 3)",
- "python-dbus", "python-avahi", "python-gobject | python-gi".
- (Package: mandos/Depends): Remove "python-gnutls" and
- "python2.7-gnutls", add "libgnutls28-dev (>= 3.3.0) | libgnutls30 (>=
- 3.3.0)". Add "python (<< 3)". Remove "python2.7-dbus",
- "python2.7-avahi", "python2.7-gobject", and "python2.7-urwid".
- Replace "python-gobject" with "python-gobject | python-gi" and "gnupg
- (<< 2)" with "gnupg".
- (Package: mandos-client/Depends): Replace
- "gnupg (<< 2)" with "gnupg".
- (Source: mandos/Standards-Version): Change to 3.9.7.
- * debian/copyright (Copyright): Update copyright year.
-
- -- Teddy Hogeborn Sun, 28 Feb 2016 16:09:01 +0100
-
-mandos (1.7.1-2) unstable; urgency=medium
-
- * debian/control (Package: mandos/Depends): Fix "Please drop versioned
- dependency on initscripts package" by removing initscripts dependency
- (Closes: #804967)
- * debian/rules (override_dh_fixperms) Fix "FTBFS when built with
- dpkg-buildpackage -A (No such file or directory)" by splitting into
- "override_dh_fixperms-arch" and "override_dh_fixperms-indep".
- (Closes: #806073)
-
- -- Teddy Hogeborn Sat, 05 Dec 2015 02:27:40 +0100
-
-mandos (1.7.1-1) unstable; urgency=medium
-
- * New upstream release.
-
- -- Teddy Hogeborn Sat, 24 Oct 2015 19:43:40 +0200
-
-mandos (1.7.0-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/control (Standards-Version): Updated to "3.9.6".
- (Build-Depends): Add "libnl-route-3-dev".
- (Package: mandos-client/Recommends): Added "gnutls-bin | openssl" for
- the generating of DH parameters.
- * debian/mandos-client.README.Debian: Update example command line to use
- new MANDOSPLUGINHELPERDIR environment variable. Also document the new
- dhparams.pem file.
- * debian/mandos-client.postinst: Create DH parameters file.
- * debian/mandos.prerm: Don't run init script, use only invoke-rc.d.
- * debian/mandos-client.postinst: Don't use absolute paths to commands.
- * debian/mandos-client.postrm: Don't use absolute paths to commands.
- Also remove dhparams.pem file.
- * debian/copyright (Copyright): Update copyright year.
- * Upstream changed systemd service file to implicitly be of
- "Type=dbus". (Closes: #786845)
-
- -- Teddy Hogeborn Mon, 10 Aug 2015 22:00:29 +0200
-
-mandos (1.6.9-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/control (Build-Depends): Fix "still uses GnutLS 2.x" by
- changing from "libgnutls-dev" to "libgnutls28-dev | gnutls-dev"
- (Closes: #762349)
-
- -- Teddy Hogeborn Sun, 05 Oct 2014 22:05:06 +0200
-
-mandos (1.6.8-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/control (Source: mandos/Build-Depends-Indep): Since upstream
- now requires Python 2.7, depend on exactly the python2.7 package and
- all the Python 2.7 versions of the python modules.
- (Package: mandos/Depends): - '' - but still depend on python (>=2.7)
- and the generic versions of the Python modules; this is for mandos-ctl
- and mandos-monitor, both of which are compatible with Python 3, and
- use #!/usr/bin/python.
-
- -- Teddy Hogeborn Wed, 06 Aug 2014 22:55:24 +0200
-
-mandos (1.6.7-1) unstable; urgency=medium
-
- * New upstream release.
-
- -- Teddy Hogeborn Thu, 17 Jul 2014 05:22:45 +0200
-
-mandos (1.6.6-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/mandos.postinst: Fix typo in comment.
- * debian/control (mandos/Recommends): Changed to "ssh-client | fping".
- (mandos-client/Recommends): New; set to "ssh".
-
- -- Teddy Hogeborn Sun, 13 Jul 2014 22:49:21 +0200
-
-mandos (1.6.5-3) unstable; urgency=medium
-
- * debian/control (mandos-client/Depends): Add "dpkg-dev (>=1.16.0)";
- initramfs-tools-hook runs "dpkg-architecture -qDEB_HOST_MULTIARCH".
- (Closes: #750221)
-
- -- Teddy Hogeborn Fri, 06 Jun 2014 04:27:15 +0200
-
-mandos (1.6.5-2) unstable; urgency=medium
-
- * debian/rules (override_dh_auto_test-arch): New; does nothing. Fixes
- FTBFS for build-indep.
-
- -- Teddy Hogeborn Tue, 13 May 2014 08:08:31 +0200
-
-mandos (1.6.5-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/copyright: Change year to "2014".
- * debian/control (Build-Depends, Build-Depends-Indep): Moved build
- dependencies of "mandos" package to "Build-Depends-Indep".
- * debian/upstream/signing-key.asc: New; upstream source public key.
- * debian/control (Standards-Version): Updated to "3.9.5".
- * debian/control (mandos/Depends): Remove the dependency on
- "avahi-daemon (>= 0.6.31-3) | systemd-sysv". It is unnecessary
- since we have a workaround in debian/mandos.postinst anyway.
-
- -- Teddy Hogeborn Sun, 11 May 2014 22:16:33 +0200
-
-mandos (1.6.4-1) unstable; urgency=medium
-
- * New upstream release.
- * debian/control (Build-Depends): Add Python dependencies to
- successfully run self-tests.
- * debian/copyright: GPLv3 now has its own license file - use it.
- * debian/watch: Set PGP signature URL.
-
- -- Teddy Hogeborn Sun, 16 Feb 2014 14:09:25 +0100
-
-mandos (1.6.3-1) unstable; urgency=low
-
- * New upstream release.
- * debian/control (Build-Depends): Added "systemd".
- * debian/mandos.dirs (lib/systemd/system): New.
- * debian/mandos-client.README.Debian: Refer to architecture libdir.
- * debian/control (mandos/Depends): Add "avahi-daemon (>= 0.6.31-3) |
- systemd-sysv".
- * debian/mandos.postinst: If avahi-daemon is version 0.6.31-2 or older,
- edit /etc/init.d script headers Required-Start
- and Required-Stop to have "avahi" instead of
- "avahi-daemon", before insserv(8) sees it.
- * debian/mandos-client.lintian-overrides: Libdir changes.
- * debian/rules (override_dh_fixperms): - '' -
-
- -- Teddy Hogeborn Tue, 21 Jan 2014 22:01:30 +0100
-
-mandos (1.6.2-1) unstable; urgency=low
-
- * New upstream release.
- * debian/compat: Changed to "9".
- * debian/control (Build-Depends): Changed debhelper version to (>= 9).
- (Standards-Version): Updated to "3.9.4".
- (DM-Upload-Allowed): Removed.
- (mandos/Depends): Add "initscripts (>= 2.88dsf-13.3)" to be able to
- use the "/run" directory (for mandos.pid).
- * debian/copyright (Copyright): Update year.
- * Fix "Mandos/gnutls fails to establish connection, "an algorithm that
- is not enabled was negotiated"" fixed by upstream. (Closes: #702120)
-
- -- Teddy Hogeborn Thu, 24 Oct 2013 22:33:40 +0200
-
-mandos (1.6.1-1) unstable; urgency=low
-
- * New upstream release.
- * debian/control (mandos/Depends): No longer depends on
- python-gnupginterface, but does
- depend on gnupg (<< 2).
- (Build-Depends): Depend on debhelper 8.9.7 for using "override-*-arch"
- and "override-*-indep" targets in debian/rules.
- * debian/mandos-client.README: Update Linux documentation link.
- * debian/rules: Completely rewritten to use debhelper v7.
- * initramfs-tools-hook: Bug fix: Make sure the right version of GnuPG is
- copied into the initramfs image. Always assume that GPGME is used to
- avoid searching for it since the path might not be /usr/lib. Thanks
- to Félix Sipma for the initial bug report,
- and also thanks to Dick Middleton for some more
- debugging. (Closes: #721903)
- * Fix "bashism in /bin/sh script" fixed by upstream. (Closes: #690639)
-
- -- Teddy Hogeborn Sun, 13 Oct 2013 19:03:23 +0200
-
-mandos (1.6.0-1) unstable; urgency=low
-
- * New upstream release.
- * debian/copyright (Copyright): Join the two lines to a single line.
- * debian/mandos-client.README.Debian: Update to refer to the new
- location of the example network hooks, and the new feature of using
- all network interfaces.
- * debian/mandos-client.docs (network-hooks.d): Removed.
- * debian/mandos-client.examples (network-hooks.d): New.
- * debian/rules (binary-common): Added "dh_installexamples".
- (binary-common/dh_fixperms): Exclude new location of
- "network-hooks.d".
-
- -- Teddy Hogeborn Mon, 18 Jun 2012 00:15:23 +0200
-
-mandos (1.5.5-1) unstable; urgency=low
-
- * New upstream release.
- * debian/copyright (Format): Updated to
- "http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/".
- * debian/control (Build-Depends): Removed "man, locales-all".
-
- -- Teddy Hogeborn Fri, 01 Jun 2012 20:30:41 +0200
-
-mandos (1.5.4-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Sun, 20 May 2012 15:38:34 +0200
-
-mandos (1.5.3-1.2) unstable; urgency=low
-
- * Non-maintainer upload.
- * Set Architecture to linux-any. (Closes: #647670)
-
- -- Robert Millan Sun, 22 Apr 2012 16:22:01 +0200
-
-mandos (1.5.3-1.1) unstable; urgency=low
-
- * Non-maintainer upload.
- * Fix "mandos FTBFS on buildds": add build-dependency on locales-all and
- pass LC_ALL to dh_auto_build to make sure we have and use the en_US.UTF-8
- locale for manpage creation.
- (Closes: #656178)
-
- -- gregor herrmann Tue, 31 Jan 2012 17:56:05 +0100
-
-mandos (1.5.3-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Sun, 15 Jan 2012 22:05:54 +0100
-
-mandos (1.5.2-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Sun, 08 Jan 2012 11:17:20 +0100
-
-mandos (1.5.1-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Sun, 01 Jan 2012 21:53:31 +0100
-
-mandos (1.5.0-1) unstable; urgency=low
-
- * New upstream release.
- * debian/control (mandos-client/Depends): Added "initramfs-tools".
- * debian/mandos-client.README.Debian: Corrected mail address and adjust
- wording.
- * debian/rules (binary-common): Exclude new nework-hooks.d directory
- from dh_fixperms.
- * debian/mandos-client.README.Debian: Document network hook facility.
- * debian/mandos-client.docs (network-hooks.d): Added.
- * debian/mandos.dirs (var/lib/mandos): Added.
- * debian/mandos.postinst: Fix ownership of /var/lib/mandos.
- * debian/control (mandos/Depends): Added "python-gnupginterface".
-
- -- Teddy Hogeborn Sun, 01 Jan 2012 05:58:11 +0100
-
-mandos (1.4.1-1) unstable; urgency=low
-
- * New upstream release.
- * debian/control (Build-Depends): Added "man".
- * debian/control (Conflicts): Changed to "Breaks:".
- * debian/copyright: Updated format.
- * debian/mandos-client.postinst: Use "set -e" instead of "#!/bin/sh -e".
- * debian/mandos-client.postrm: - '' -
- * debian/mandos.postinst: - '' -
- * debian/mandos.prerm: Consistent magic.
-
- -- Björn Påhlsson Sat, 15 Oct 2011 18:18:52 +0200
-
-mandos (1.4.0-1) unstable; urgency=low
-
- * New upstream release.
- * Fix "FTBFS with binutils-gold": Added "-Xlinker --as-needed" to
- LDFLAGS in Makefile. (Closes: #632145)
- * Fix "/run transition: uses obsolete /dev/.initramfs": Try both old and
- new PID file locations. (Closes: #643554)
- * debian/source/local-options: New; contains "--single-debian-patch".
- * debian/control (Standards-Version): Upgraded to "3.9.2".
- (DM-Upload-Allowed): New; set to "yes".
- * debian/control: Changed domain from "fukt.bsnet.se" to "recompile.se".
- * debian/copyright: - '' -
- * debian/mandos-client.README.Debian: - '' -
- * debian/mandos.README.Debian: - '' -
- * debian/watch: - '' -
- * debian/control (mandos/Description): Fix language to placate lintian.
-
- -- Teddy Hogeborn Sun, 09 Oct 2011 19:15:08 +0200
-
-mandos (1.3.1-1) unstable; urgency=low
-
- * New upstream release.
- * Conflict with correct version of dropbear.
- * New version uses argparse; depend on python (<=2.7) | python-argparse.
-
- -- Teddy Hogeborn Wed, 27 Jul 2011 19:47:17 +0200
-
-mandos (1.3.0-1) unstable; urgency=low
-
- * New upstream release.
- * debian/control (mandos): Depend on Python 2.6, remove dependency on
- python-multiprocessing.
- (mandos-client): Conflict with dropbear (<< 0.52-5).
- * debian/mandos-client.postrm (purge): Bug fix: update initramfs also on
- purge.
- * debian/mandos-client.lintian-overrides: Added plugins.d/plymouth.
-
- -- Teddy Hogeborn Tue, 08 Mar 2011 20:22:57 +0100
-
-mandos (1.2.3-1) experimental; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Mon, 11 Oct 2010 19:37:31 +0200
-
-mandos (1.2.2-1) experimental; urgency=low
-
- * New upstream release.
- * plugins.d/splashy.c: Only use ELIBBAD if defined. (Closes: #599256)
-
- -- Teddy Hogeborn Thu, 07 Oct 2010 20:27:54 +0200
-
-mandos (1.2.1-3) experimental; urgency=low
-
- * debian/changelog: Include entry for NMU of version 1.0.14-1.1.
-
- -- Teddy Hogeborn Tue, 05 Oct 2010 20:58:38 +0200
-
-mandos (1.2.1-2) unstable; urgency=low
-
- * debian/source/format: New; contains "3.0 (quilt)". Really.
-
- -- Björn Påhlsson Sat, 02 Oct 2010 19:46:59 +0200
-
-mandos (1.2.1-1) unstable; urgency=low
-
- * New upstream release.
- * debian/source/format: New; contains "3.0 (quilt)".
-
- -- Björn Påhlsson Sat, 02 Oct 2010 19:03:58 +0200
-
-mandos (1.2-1) unstable; urgency=low
-
- * New upstream release.
- * Makefile (LINK_FORTIFY_LD): Remove "-fPIE". (Closes: #557076)
- * debian/control: Add gnupg dependency to "mandos-client" and removed it
- from "mandos". Added dependency on "python-urwid" "mandos" since the
- new "mandos-monitor" utility needs it, and on "python (>=2.6) |
- python-multiprocessing" since the Mandos server now uses it.
- * debian/rules: Set BROKEN_PIE on mips and mipsel if a known buggy
- version of binutils is used.
- * debian/mandos.docs: Also install "/usr/share/doc/mandos/DBUS-API".
- * debian/mandos.dirs: Added "etc/dbus-1/system.d".
- * debian/mandos-client.README.Debian: Update info about DEVICE setting
- of initramfs.conf.
- * debian/mandos-client.README.Debian: Remove warning about --connect not
- looping, since it now does.
-
- -- Teddy Hogeborn Tue, 28 Sep 2010 20:46:11 +0200
-
-mandos (1.0.14-1.1) unstable; urgency=low
-
- * Non-maintainer upload.
- * Rebuild against libavahi-core-dev (>= 0.6.26-1).
-
- -- Michael Biebl Mon, 12 Jul 2010 16:34:34 +0200
-
-mandos (1.0.14-1) unstable; urgency=low (HIGH on mips and mipsel)
-
- * New upstream release.
- * debian/rules: Build with BROKEN_PIE set on mips and mipsel
- architectures - fixes FTBFS there.
-
- -- Teddy Hogeborn Sun, 25 Oct 2009 20:10:09 +0100
-
-mandos (1.0.13-1) unstable; urgency=high
-
- * New upstream release.
- * Do not copy unnecessary files to initrd (Closes: #551907)
-
- -- Teddy Hogeborn Thu, 22 Oct 2009 00:53:21 +0200
-
-mandos (1.0.12-1) unstable; urgency=low
-
- * New upstream release.
- * init.d-mandos: Correct dependencies (Closes: #546928)
- * debian/control (Standards-Version): Changed to "3.8.3".
- * debian/mandos-client.README.Debian: Improved wording and formatting.
- Updated location of nfsroot.txt.
- * debian/mandos.README.Debian: Improved wording and formatting.
- * debian/mandos-client.postinst (configure): Don't look for user and
- group with the old name if upgrading from a new enough version.
- * debian/mandos.postinst (configure): - '' -
- * debian/mandos-client.README.Debian: Added text about non-usability of
- pseudo-network interfaces.
-
- -- Teddy Hogeborn Thu, 17 Sep 2009 15:03:59 +0200
-
-mandos (1.0.11-1) unstable; urgency=low
-
- * debian/control (Standards-Version): Changed to "3.8.1".
- * Makefile (GNUTLS_CFLAGS, GNUTLS_CFLAGS): Use "pkg-config" instead of
- the old "libgnutls-config" script. (Closes: #529836)
-
- -- Teddy Hogeborn Sat, 23 May 2009 07:12:20 +0200
-
-mandos (1.0.10-1) unstable; urgency=low
-
- * New upstream release.
- * debian/mandos-client.postinst (update_initramfs): Fix permissions of
- old initrd.img-*.bak files.
-
- -- Teddy Hogeborn Sun, 17 May 2009 04:56:35 +0200
-
-mandos (1.0.9-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Sun, 17 May 2009 02:59:45 +0200
-
-mandos (1.0.8-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Wed, 25 Feb 2009 02:26:57 +0100
-
-mandos (1.0.7-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Tue, 24 Feb 2009 12:58:06 +0100
-
-mandos (1.0.6-1) unstable; urgency=low
-
- * New upstream release.
- * debian/mandos-client.postinst: Converted to Bourne shell. Also
- minor message change.
- * debian/mandos-client.postrm: Minor message change.
- * debian/mandos.postinst: Converted to Bourne shell. Also minor
- message change.
- * debian/mandos.prerm: Minor message change.
- * debian/rules (install-indep): Removed "--no-start" from
- dh_installinit.
- * debian/mandos-client.lintian-overrides: Remove obsolete override for
- unbreakable line in plugin-runner manual page.
- * debian/control (mandos/Depends): Added "python-gobject".
- * debian/mandos-client.dirs: Change
- "usr/share/initramfs-tools/scripts/local-top" to
- "usr/share/initramfs-tools/scripts/init-premount".
- * debian/mandos-client.README.Debian: Add reference to initramfs.conf
- and nfsroot.txt. New section about the new non-local connection
- feature.
-
- -- Teddy Hogeborn Fri, 13 Feb 2009 09:27:25 +0100
-
-mandos (1.0.5-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Sat, 17 Jan 2009 02:26:00 +0100
-
-mandos (1.0.4-1) unstable; urgency=low
-
- * New upstream release.
- * debian/watch: New file.
- * debian/mandos-client.README.Debian: Document new "mandos=off" kernel
- parameter.
-
- -- Teddy Hogeborn Thu, 15 Jan 2009 05:49:22 +0100
-
-mandos (1.0.3-2) unstable; urgency=low
-
- * Removed some now-unused debconf files.
- * Changed postinst scripts to not source debconf/confmodule.
- * Removed po-debconf from build-depends.
-
- -- Teddy Hogeborn Tue, 06 Jan 2009 21:28:20 +0100
-
-mandos (1.0.3-1) unstable; urgency=low
-
- * New upstream release.
- * Add -Xlinker to linker flags to fix FTBFS for some architectures.
- Thanks to Thiemo Seufer for the report and
- fix. (Closes: #509398)
- * Remove debconf use altogether, thereby stopping debconf abuse. Thanks
- to Christian Perrier . (Closes: #509653)
- * Add NEWS file to /usr/share/doc directories.
- * Use and create "_mandos" user+group. Rename old user+group created by
- older versions of this package.
- * Fix manual pages by adding build-depend on "docbook-xml".
-
- -- Teddy Hogeborn Tue, 06 Jan 2009 01:21:20 +0100
-
-mandos (1.0.2-1) unstable; urgency=low
-
- * New upstream release.
- * debian/copyright: Rewritten to conform to
- .
-
- -- Teddy Hogeborn Fri, 17 Oct 2008 20:42:12 +0200
-
-mandos (1.0.1-1) unstable; urgency=low
-
- * New upstream release.
- * Separate /usr/share/doc/mandos-client/README.Debian into sections with
- headlines. Add instructions on how to test the server and verify the
- password.
-
- -- Teddy Hogeborn Tue, 07 Oct 2008 23:07:23 +0200
-
-mandos (1.0-2) unstable; urgency=low
-
- * Added comments in debian/*.lintian-overrides files. Added Debian
- revison number to version number.
-
- -- Teddy Hogeborn Wed, 01 Oct 2008 17:23:35 +0200
-
-mandos (1.0-1) unstable; urgency=low
-
- * Initial Release. (Closes: #500727).
-
- -- Teddy Hogeborn Tue, 30 Sep 2008 21:58:43 +0200
=== removed file 'debian/compat'
--- debian/compat 2018-02-06 20:03:50 +0000
+++ debian/compat 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-10
=== removed file 'debian/control'
--- debian/control 2019-10-20 03:39:15 +0000
+++ debian/control 1970-01-01 00:00:00 +0000
@@ -1,70 +0,0 @@
-Source: mandos
-Section: admin
-Priority: optional
-Maintainer: Mandos Maintainers
-Uploaders: Teddy Hogeborn ,
- Björn Påhlsson
-Build-Depends: debhelper (>= 10), docbook-xml, docbook-xsl,
- libavahi-core-dev, libgpgme-dev | libgpgme11-dev,
- libglib2.0-dev (>=2.40), libgnutls28-dev (>= 3.3.0),
- libgnutls28-dev (>= 3.6.6) | libgnutls28-dev (<< 3.6.0),
- xsltproc, pkg-config, libnl-route-3-dev, systemd
-Build-Depends-Indep: python3 (>= 3), python3-dbus, python3-gi,
- po-debconf
-Standards-Version: 4.4.1
-Vcs-Bzr: https://ftp.recompile.se/pub/mandos/trunk
-Vcs-Browser: https://bzr.recompile.se/loggerhead/mandos/trunk/files
-Homepage: https://www.recompile.se/mandos
-Rules-Requires-Root: binary-targets
-
-Package: mandos
-Architecture: all
-Depends: ${misc:Depends}, python3 (>= 3), libgnutls30 (>= 3.3.0),
- libgnutls30 (>= 3.6.6) | libgnutls30 (<< 3.6.0),
- python3-dbus, python3-gi, avahi-daemon, adduser,
- python3-urwid, gnupg2 | gnupg,
- systemd-sysv | lsb-base (>= 3.0-6),
- debconf (>= 1.5.5) | debconf-2.0
-Recommends: ssh-client | fping
-Suggests: libc6-dev | libc-dev, c-compiler
-Description: server giving encrypted passwords to Mandos clients
- This is the server part of the Mandos system, which allows
- computers to have encrypted root file systems and at the
- same time be capable of remote and/or unattended reboots.
- .
- The computers run a small client program in the initial RAM
- disk environment which will communicate with a server over a
- network. All network communication is encrypted using TLS.
- The clients are identified by the server using a TLS public
- key; each client has one unique to it. The server sends the
- clients an encrypted password. The encrypted password is
- decrypted by the clients using an OpenPGP key, and the
- password is then used to unlock the root file system,
- whereupon the computers can continue booting normally.
-
-Package: mandos-client
-Architecture: linux-any
-Depends: ${shlibs:Depends}, ${misc:Depends}, adduser,
- cryptsetup (<< 2:2.0.3-1) | cryptsetup-initramfs,
- initramfs-tools (>= 0.99) | dracut (>= 044+241-3),
- dpkg-dev (>=1.16.0),
- gnutls-bin (>= 3.6.6) | libgnutls30 (<< 3.6.0),
- debconf (>= 1.5.5) | debconf-2.0
-Recommends: ssh
-Breaks: dropbear (<= 0.53.1-1)
-Enhances: cryptsetup
-Conflicts: dracut-config-generic
-Description: do unattended reboots with an encrypted root file system
- This is the client part of the Mandos system, which allows
- computers to have encrypted root file systems and at the
- same time be capable of remote and/or unattended reboots.
- .
- The computers run a small client program in the initial RAM
- disk environment which will communicate with a server over a
- network. All network communication is encrypted using TLS.
- The clients are identified by the server using a TLS public
- key; each client has one unique to it. The server sends the
- clients an encrypted password. The encrypted password is
- decrypted by the clients using an OpenPGP key, and the
- password is then used to unlock the root file system,
- whereupon the computers can continue booting normally.
=== removed file 'debian/copyright'
--- debian/copyright 2019-02-10 04:20:26 +0000
+++ debian/copyright 1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: Mandos
-Upstream-Contact: Mandos
-Source:
-
-Files: *
-Copyright: Copyright © 2008-2019 Teddy Hogeborn
- Copyright © 2008-2019 Björn Påhlsson
-License: GPL-3+
- This file is part of Mandos.
- .
- Mandos 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.
- .
- Mandos 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 Mandos. If not, see .
- .
- On Debian systems, the complete text of the GNU General Public
- License can be found in "/usr/share/common-licenses/GPL-3".
=== removed file 'debian/mandos-client.README.Debian'
--- debian/mandos-client.README.Debian 2019-07-27 10:11:45 +0000
+++ debian/mandos-client.README.Debian 1970-01-01 00:00:00 +0000
@@ -1,119 +0,0 @@
-This file documents the next steps to take after installation of the
-Debian package, and also contain some notes specific to the Debian
-packaging which are not also in the manual.
-
-* Adding a Client Password to the Server
-
- The server must be given a password to give back to the client on
- boot time. This password must be a one which can be used to unlock
- the root file system device. On the *client*, run this command:
-
- mandos-keygen --password
-
- It will prompt for a password and output a config file section.
- This output should be copied to the Mandos server and added to the
- file "/etc/mandos/clients.conf" there.
-
-* Testing that it Works (Without Rebooting)
-
- After the server has been started with this client's key added, it
- is possible to verify that the correct password will be received by
- this client by running the command, on the client:
-
- MANDOSPLUGINHELPERDIR=/usr/lib/$(dpkg-architecture \
- -qDEB_HOST_MULTIARCH)/mandos/plugin-helpers \
- /usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH \
- )/mandos/plugins.d/mandos-client \
- --pubkey=/etc/keys/mandos/pubkey.txt \
- --seckey=/etc/keys/mandos/seckey.txt \
- --tls-privkey=/etc/keys/mandos/tls-privkey.pem \
- --tls-pubkey=/etc/keys/mandos/tls-pubkey.pem; echo
-
- This command should retrieve the password from the server, decrypt
- it, and output it to standard output. There it can be verified to
- be the correct password, before rebooting.
-
-* Emergency Escape
-
- If it ever should be necessary, the Mandos client can be temporarily
- prevented from running at startup by passing the parameter
- "mandos=off" to the kernel.
-
-* Specifying a Client Network Interface
-
- At boot time the network interfaces to use will by default be
- automatically detected. If this should result in incorrect
- interfaces, edit the DEVICE setting in the
- "/etc/initramfs-tools/initramfs.conf" file. (The default setting is
- empty, meaning it will autodetect the interfaces.) *If* the DEVICE
- setting is changed, it will be necessary to update the initrd image
- by running this command:
-
- (For initramfs-tools:)
- update-initramfs -k all -u
-
- (For dracut:)
- dpkg-reconfigure dracut
-
- The device can also be overridden at boot time on the Linux kernel
- command line using the sixth colon-separated field of the "ip="
- option; for exact syntax, read the documentation in the file
- "/usr/share/doc/linux-doc-*/Documentation/filesystems/nfs/nfsroot.txt",
- available in the "linux-doc-*" package.
-
- Note that since the network interfaces are used in the initial RAM
- disk environment, the network interfaces *must* exist at that stage.
- Thus, an interface can *not* be a pseudo-interface such as "br0" or
- "tun0"; instead, only real interfaces (such as "enp1s0" or "eth0")
- can be used. This can be overcome by writing a "network hook"
- program to create an interface (see mandos-client(8mandos)) and
- placing it in "/etc/mandos/network-hooks.d", from where it will be
- copied into the initial RAM disk. Example network hook scripts can
- be found in "/usr/share/doc/mandos-client/examples/network-hooks.d".
-
-* User-Supplied Plugins
-
- Any plugins found in "/etc/mandos/plugins.d" will override and add
- to the normal Mandos plugins. When adding or changing plugins, do
- not forget to update the initital RAM disk image:
-
- (For initramfs-tools:)
- update-initramfs -k all -u
-
- (For dracut:)
- dpkg-reconfigure dracut
-
-* Do *NOT* Edit "/etc/crypttab"
-
- It is NOT necessary to edit "/etc/crypttab" to specify
- "/usr/lib/mandos/plugin-runner" as a keyscript for the root file
- system; if no keyscript is given for the root file system, the
- Mandos client will be the new default way for getting a password for
- the root file system when booting.
-
-* Non-local Connection (Not Using ZeroConf)
-
- If the "ip=" kernel command line option is used to specify a
- complete IP address and device name, as noted above, it then becomes
- possible to specify a specific IP address and port to connect to,
- instead of using ZeroConf. The syntax for doing this is
- "mandos=connect::" on the kernel command
- line.
-
- For very advanced users, it is possible to specify simply
- "mandos=connect" on the kernel command line to make the system only
- set up the network (using the data in the "ip=" option) and not pass
- any extra "--connect" options to mandos-client at boot. For this to
- work, "--options-for=mandos-client:--connect=:" needs
- to be manually added to the file "/etc/mandos/plugin-runner.conf".
-
-* Diffie-Hellman Parameters
-
- On installation, a file with Diffie-Hellman parameters,
- /etc/keys/mandos/dhparams.pem, will be generated and automatically
- installed into the initital RAM disk image and also used by the
- Mandos Client on boot. If different parameters are needed for
- policy or other reasons, simply replace the existing dhparams.pem
- file and update the initital RAM disk image.
-
- -- Teddy Hogeborn , Mon, 15 Jul 2019 16:47:02 +0200
=== removed file 'debian/mandos-client.dirs'
--- debian/mandos-client.dirs 2019-08-18 04:14:31 +0000
+++ debian/mandos-client.dirs 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
-usr/share/man/man8
-usr/sbin
-usr/share/initramfs-tools/hooks
-usr/share/initramfs-tools/conf.d
-usr/share/initramfs-tools/conf-hooks.d
-usr/share/initramfs-tools/scripts/init-premount
-usr/share/initramfs-tools/scripts/local-premount
-usr/lib/sysusers.d
=== removed file 'debian/mandos-client.docs'
--- debian/mandos-client.docs 2012-06-01 21:48:12 +0000
+++ debian/mandos-client.docs 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
-NEWS
-README
-TODO
=== removed file 'debian/mandos-client.examples'
--- debian/mandos-client.examples 2012-06-01 21:48:12 +0000
+++ debian/mandos-client.examples 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-network-hooks.d
=== removed file 'debian/mandos-client.links'
--- debian/mandos-client.links 2008-09-19 13:50:22 +0000
+++ debian/mandos-client.links 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-usr/share/man/man8/plugin-runner.8mandos.gz usr/share/man/man5/plugin-runner.conf.5mandos.gz
=== removed file 'debian/mandos-client.lintian-overrides'
--- debian/mandos-client.lintian-overrides 2019-08-05 21:14:05 +0000
+++ debian/mandos-client.lintian-overrides 1970-01-01 00:00:00 +0000
@@ -1,44 +0,0 @@
-# This directory contains secret client key files.
-#
-mandos-client binary: non-standard-dir-perm etc/keys/mandos/ 0700 != 0755
-
-# The directory /usr/lib//mandos/plugins.d contains setuid
-# binaries which are not meant to be run outside an initial RAM disk
-# environment (except for test purposes). It would be insecure to
-# allow anyone to run them.
-#
-mandos-client binary: non-standard-dir-perm usr/lib/*/mandos/plugins.d/ 0700 != 0755
-# Likewise for helper executables for plugins
-mandos-client binary: non-standard-dir-perm usr/lib/*/mandos/plugin-helpers/ 0700 != 0755
-
-# These binaries must be setuid root, since they need root powers, but
-# are started by plugin-runner(8mandos), which runs all plugins as
-# user/group "_mandos". These binaries are not run in a running
-# system, but in an initial RAM disk environment. Here they are
-# protected from non-root access by the directory permissions, above.
-#
-mandos-client binary: setuid-binary usr/lib/*/mandos/plugins.d/mandos-client 4755 root/root
-mandos-client binary: setuid-binary usr/lib/*/mandos/plugins.d/askpass-fifo 4755 root/root
-mandos-client binary: setuid-binary usr/lib/*/mandos/plugins.d/splashy 4755 root/root
-mandos-client binary: setuid-binary usr/lib/*/mandos/plugins.d/usplash 4755 root/root
-mandos-client binary: setuid-binary usr/lib/*/mandos/plugins.d/plymouth 4755 root/root
-
-# The directory /etc/mandos/plugins.d can be used by local system
-# administrators to place plugins in, overriding and complementing
-# /usr/lib//mandos/plugins.d, and must be likewise protected.
-#
-mandos-client binary: non-standard-dir-perm etc/mandos/plugins.d/ 0700 != 0755
-# Likewise for plugin-helpers directory
-mandos-client binary: non-standard-dir-perm etc/mandos/plugin-helpers/ 0700 != 0755
-
-# The debconf templates is only used for displaying information
-# detected in the postinst, not for saving answers to questions, so we
-# don't need a .config file.
-mandos-client binary: no-debconf-config
-
-# The notice displayed from the postinst script really is critical
-mandos-client binary: postinst-uses-db-input
-
-# These are very important to work around bugs or changes in the old
-# versions, and there is no pressing need to remove them.
-mandos-client binary: maintainer-script-supports-ancient-package-version *
=== removed file 'debian/mandos-client.postinst'
--- debian/mandos-client.postinst 2019-07-27 10:11:45 +0000
+++ debian/mandos-client.postinst 1970-01-01 00:00:00 +0000
@@ -1,204 +0,0 @@
-#!/bin/sh
-# This script can be called in the following ways:
-#
-# After the package was installed:
-# configure
-#
-#
-# If prerm fails during upgrade or fails on failed upgrade:
-# abort-upgrade
-#
-# If prerm fails during deconfiguration of a package:
-# abort-deconfigure in-favour
-# removing
-#
-# If prerm fails during replacement due to conflict:
-# abort-remove in-favour
-
-. /usr/share/debconf/confmodule
-
-set -e
-
-# Update the initial RAM file system image
-update_initramfs()
-{
- if command -v update-initramfs >/dev/null; then
- update-initramfs -k all -u
- elif command -v dracut >/dev/null; then
- dracut_version="`dpkg-query --showformat='${Version}' --show dracut`"
- if dpkg --compare-versions "$dracut_version" lt 043-1 \
- && bash -c '. /etc/dracut.conf; . /etc/dracut.conf.d/*; [ "$hostonly" != yes ]'; then
- echo 'Dracut is not configured to use hostonly mode!' >&2
- return 1
- fi
- # Logic taken from dracut.postinst
- for kernel in /boot/vmlinu[xz]-*; do
- kversion="${kernel#/boot/vmlinu[xz]-}"
- # Dracut preserves old permissions of initramfs image
- # files, so we adjust permissions before creating new
- # initramfs image containing secret keys.
- chmod go-r /boot/initrd.img-"$kversion"
- if [ "$kversion" != "*" ]; then
- /etc/kernel/postinst.d/dracut "$kversion"
- fi
- done
- fi
-
- if dpkg --compare-versions "$2" lt-nl "1.0.10-1"; then
- # Make old initrd.img files unreadable too, in case they were
- # created with mandos-client 1.0.8 or older.
- find /boot -maxdepth 1 -type f -name "initrd.img-*.bak" \
- -print0 | xargs --null --no-run-if-empty chmod o-r
- fi
-}
-
-# Add user and group
-add_mandos_user(){
- # Rename old "mandos" user and group
- if dpkg --compare-versions "$2" lt "1.0.3-1"; then
- case "`getent passwd mandos`" in
- *:Mandos\ password\ system,,,:/nonexistent:/bin/false)
- usermod --login _mandos mandos
- groupmod --new-name _mandos mandos
- return
- ;;
- esac
- fi
- # Create new user and group
- if ! getent passwd _mandos >/dev/null; then
- adduser --system --force-badname --quiet --home /nonexistent \
- --no-create-home --group --disabled-password \
- --gecos "Mandos password system" _mandos
- fi
-}
-
-# Create client key pairs
-create_keys(){
- # If the OpenPGP key files do not exist, generate all keys using
- # mandos-keygen
- if ! [ -r /etc/keys/mandos/pubkey.txt \
- -a -r /etc/keys/mandos/seckey.txt ]; then
- mandos-keygen
- gpg-connect-agent KILLAGENT /bye || :
- return 0
- fi
-
- # Remove any bad TLS keys by 1.8.0-1
- if dpkg --compare-versions "$2" eq "1.8.0-1" \
- || dpkg --compare-versions "$2" eq "1.8.0-1~bpo9+1"; then
- # Is the key bad?
- if ! certtool --password='' \
- --load-privkey=/etc/keys/mandos/tls-privkey.pem \
- --outfile=/dev/null --pubkey-info --no-text \
- 2>/dev/null; then
- shred --remove -- /etc/keys/mandos/tls-privkey.pem \
- 2>/dev/null || :
- rm --force -- /etc/keys/mandos/tls-pubkey.pem
- fi
- fi
-
- # If the TLS keys already exists, do nothing
- if [ -r /etc/keys/mandos/tls-privkey.pem \
- -a -r /etc/keys/mandos/tls-pubkey.pem ]; then
- return 0
- fi
-
- # Try to create the TLS keys
-
- TLS_PRIVKEYTMP="`mktemp -t mandos-client-privkey.XXXXXXXXXX`"
-
- if certtool --generate-privkey --password='' \
- --outfile "$TLS_PRIVKEYTMP" --sec-param ultra \
- --key-type=ed25519 --pkcs8 --no-text 2>/dev/null; then
-
- local umask=$(umask)
- umask 077
- cp --archive "$TLS_PRIVKEYTMP" /etc/keys/mandos/tls-privkey.pem
- shred --remove -- "$TLS_PRIVKEYTMP" 2>/dev/null || :
-
- # First try certtool from GnuTLS
- if ! certtool --password='' \
- --load-privkey=/etc/keys/mandos/tls-privkey.pem \
- --outfile=/etc/keys/mandos/tls-pubkey.pem --pubkey-info \
- --no-text 2>/dev/null; then
- # Otherwise try OpenSSL
- if ! openssl pkey -in /etc/keys/mandos/tls-privkey.pem \
- -out /etc/keys/mandos/tls-pubkey.pem -pubout; then
- rm --force /etc/keys/mandos/tls-pubkey.pem
- # None of the commands succeded; give up
- umask $umask
- return 1
- fi
- fi
- umask $umask
-
- key_id=$(mandos-keygen --passfile=/dev/null \
- | grep --regexp="^key_id[ =]")
-
- db_version 2.0
- db_fset mandos-client/key_id seen false
- db_reset mandos-client/key_id
- db_subst mandos-client/key_id key_id $key_id
- db_input critical mandos-client/key_id || true
- db_go
- db_stop
- else
- shred --remove -- "$TLS_PRIVKEYTMP" 2>/dev/null || :
- fi
-}
-
-create_dh_params(){
- if [ -r /etc/keys/mandos/dhparams.pem ]; then
- return 0
- fi
- # Create a Diffe-Hellman parameters file
- DHFILE="`mktemp -t mandos-client-dh-parameters.XXXXXXXXXX.pem`"
- # First try certtool from GnuTLS
- if ! certtool --generate-dh-params --sec-param high \
- --outfile "$DHFILE"; then
- # Otherwise try OpenSSL
- if ! openssl genpkey -genparam -algorithm DH -out "$DHFILE" \
- -pkeyopt dh_paramgen_prime_len:3072; then
- # None of the commands succeded; give up
- rm -- "$DHFILE"
- return 1
- fi
- fi
- sed --in-place --expression='0,/^-----BEGIN DH PARAMETERS-----$/d' \
- "$DHFILE"
- sed --in-place --expression='1i-----BEGIN DH PARAMETERS-----' \
- "$DHFILE"
- cp --archive "$DHFILE" /etc/keys/mandos/dhparams.pem
- rm -- "$DHFILE"
-}
-
-case "$1" in
- configure)
- add_mandos_user "$@"
- create_keys "$@"
- create_dh_params "$@" || :
- update_initramfs "$@"
- if dpkg --compare-versions "$2" lt-nl "1.7.10-1"; then
- PLUGINHELPERDIR=/usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null)/mandos/plugin-helpers
- if ! dpkg-statoverride --list "$PLUGINHELPERDIR" \
- >/dev/null 2>&1; then
- chmod u=rwx,go= -- "$PLUGINHELPERDIR"
- fi
- if ! dpkg-statoverride --list /etc/mandos/plugin-helpers \
- >/dev/null 2>&1; then
- chmod u=rwx,go= -- /etc/mandos/plugin-helpers
- fi
- fi
- ;;
- abort-upgrade|abort-deconfigure|abort-remove)
- ;;
-
- *)
- echo "$0 called with unknown argument '$1'" 1>&2
- exit 1
- ;;
-esac
-
-#DEBHELPER#
-
-exit 0
=== removed file 'debian/mandos-client.postrm'
--- debian/mandos-client.postrm 2019-08-05 14:31:51 +0000
+++ debian/mandos-client.postrm 1970-01-01 00:00:00 +0000
@@ -1,73 +0,0 @@
-#!/bin/sh
-# This script can be called in the following ways:
-#
-# After the package was removed:
-# remove
-#
-# After the package was purged:
-# purge
-#
-# After the package was upgraded:
-# upgrade
-# if that fails:
-# failed-upgrade
-#
-#
-# After all of the packages files have been replaced:
-# disappear
-#
-#
-# If preinst fails during install:
-# abort-install
-#
-# If preinst fails during upgrade of removed package:
-# abort-install
-#
-# If preinst fails during upgrade:
-# abort-upgrade
-
-set -e
-
-# Update the initial RAM file system image
-update_initramfs()
-{
- if command -v update-initramfs >/dev/null; then
- update-initramfs -k all -u
- elif command -v dracut >/dev/null; then
- # Logic taken from dracut.postinst
- for kernel in /boot/vmlinu[xz]-*; do
- kversion="${kernel#/boot/vmlinu[xz]-}"
- if [ "$kversion" != "*" ]; then
- /etc/kernel/postinst.d/dracut "$kversion"
- fi
- done
- fi
-}
-
-case "$1" in
- remove)
- update_initramfs
- ;;
-
- purge)
- shred --remove /etc/keys/mandos/seckey.txt 2>/dev/null || :
- rm --force /etc/mandos/plugin-runner.conf \
- /etc/keys/mandos/pubkey.txt \
- /etc/keys/mandos/seckey.txt \
- /etc/keys/mandos/tls-privkey.pem \
- /etc/keys/mandos/tls-pubkey.pem \
- /etc/keys/mandos/dhparams.pem 2>/dev/null
- update_initramfs
- ;;
- upgrade|failed-upgrade|disappear|abort-install|abort-upgrade)
- ;;
-
- *)
- echo "$0 called with unknown argument '$1'" 1>&2
- exit 1
- ;;
-esac
-
-#DEBHELPER#
-
-exit 0
=== removed file 'debian/mandos-client.templates'
--- debian/mandos-client.templates 2019-08-05 21:00:35 +0000
+++ debian/mandos-client.templates 1970-01-01 00:00:00 +0000
@@ -1,19 +0,0 @@
-Template: mandos-client/key_id
-Type: note
-_description: New client option "${key_id}" is REQUIRED on server
- A new "key_id" client option is REQUIRED in the server's clients.conf
- file, otherwise this computer most likely will not reboot unattended.
- This option:
- .
- ${key_id}
- .
- must be added (all on one line!) on the Mandos server host, in the file
- /etc/mandos/clients.conf, right before the "fingerprint" option for this
- Mandos client. You must edit that file on that server and add this
- option.
- .
- With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP keys as
- TLS session keys. A new TLS key pair has been generated and will be used
- as identification, but the key ID of the public key needs to be added to
- the server, since this will now be used to identify the client to the
- server.
=== removed file 'debian/mandos.README.Debian'
--- debian/mandos.README.Debian 2011-10-05 16:00:56 +0000
+++ debian/mandos.README.Debian 1970-01-01 00:00:00 +0000
@@ -1,10 +0,0 @@
-The Mandos server is useless without at least one configured client in
-/etc/mandos/clients.conf. To create one, install the "mandos-client"
-package on a client computer, and, on the client, run the command
-
- # mandos-keygen --password
-
-to get a config file stanza. Append the output of that command to the
-file "/etc/mandos/clients.conf" on the Mandos server computer.
-
- -- Teddy Hogeborn , Wed, 5 Oct 2011 17:51:22 +0200
=== removed file 'debian/mandos.dirs'
--- debian/mandos.dirs 2019-08-18 00:23:21 +0000
+++ debian/mandos.dirs 1970-01-01 00:00:00 +0000
@@ -1,10 +0,0 @@
-usr/share/man/man5
-usr/share/man/man8
-etc/init.d
-etc/default
-etc/dbus-1/system.d
-usr/sbin
-var/lib/mandos
-lib/systemd/system
-usr/lib/tmpfiles.d
-usr/lib/sysusers.d
=== removed file 'debian/mandos.docs'
--- debian/mandos.docs 2010-09-12 03:00:40 +0000
+++ debian/mandos.docs 1970-01-01 00:00:00 +0000
@@ -1,4 +0,0 @@
-NEWS
-README
-TODO
-DBUS-API
=== removed file 'debian/mandos.lintian-overrides'
--- debian/mandos.lintian-overrides 2019-08-05 21:14:05 +0000
+++ debian/mandos.lintian-overrides 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
-# This config file will normally have encrypted secret client keys in
-# it, so it must be kept unreadable for non-root users.
-#
-mandos binary: non-standard-file-perm etc/mandos/clients.conf 0600 != 0644
-
-# The debconf templates is only used for displaying information
-# detected in the postinst, not for saving answers to questions, so we
-# don't need a .config file.
-mandos binary: no-debconf-config
-
-# The notice displayed from the postinst script really is critical
-mandos binary: postinst-uses-db-input
-
-# These are very important to work around bugs or changes in the old
-# versions, and there is no pressing need to remove them.
-mandos binary: maintainer-script-supports-ancient-package-version *
=== removed file 'debian/mandos.postinst'
--- debian/mandos.postinst 2019-08-18 00:05:36 +0000
+++ debian/mandos.postinst 1970-01-01 00:00:00 +0000
@@ -1,118 +0,0 @@
-#!/bin/sh
-# This script can be called in the following ways:
-#
-# After the package was installed:
-# configure
-#
-#
-# If prerm fails during upgrade or fails on failed upgrade:
-# abort-upgrade
-#
-# If prerm fails during deconfiguration of a package:
-# abort-deconfigure in-favour
-# removing
-#
-# If prerm fails during replacement due to conflict:
-# abort-remove in-favour
-
-. /usr/share/debconf/confmodule
-
-set -e
-
-case "$1" in
- configure)
- # Rename old "mandos" user and group
- if dpkg --compare-versions "$2" lt "1.0.3-1"; then
- case "`getent passwd mandos`" in
- *:Mandos\ password\ system,,,:/nonexistent:/bin/false)
- usermod --login _mandos mandos
- groupmod --new-name _mandos mandos
- # Reload D-Bus daemon to be aware of the _mandos
- # user & group
- if [ -x /etc/init.d/dbus ]; then
- invoke-rc.d dbus force-reload || :
- fi
- ;;
- esac
- fi
- # Create new user and group
- if ! getent passwd _mandos >/dev/null; then
- adduser --system --force-badname --quiet \
- --home /nonexistent --no-create-home --group \
- --disabled-password --gecos "Mandos password system" \
- _mandos
- # Reload D-Bus daemon to be aware of the _mandos user &
- # group
- if [ -x /etc/init.d/dbus ]; then
- invoke-rc.d dbus force-reload || :
- fi
- elif dpkg --compare-versions "$2" eq 1.7.4-1 \
- || dpkg --compare-versions "$2" eq "1.7.4-1~bpo8+1"
- then
- start=no
- if ! [ -f /var/lib/mandos/clients.pickle ]; then
- invoke-rc.d mandos stop
- start=yes
- fi
- chown _mandos:_mandos /var/lib/mandos/clients.pickle \
- 2>/dev/null || :
- if [ "$start" = yes ]; then
- invoke-rc.d mandos start
- fi
- fi
- if ! dpkg-statoverride --list "/var/lib/mandos" >/dev/null \
- 2>&1; then
- chown _mandos:_mandos /var/lib/mandos
- chmod u=rwx,go= /var/lib/mandos
- fi
-
- if dpkg --compare-versions "$2" eq "1.8.0-1" \
- || dpkg --compare-versions "$2" eq "1.8.0-1~bpo9+1"; then
- if grep --quiet --regexp='^[[:space:]]*key_id[[:space:]]*=[[:space:]]*[Ee]3[Bb]0[Cc]44298[Ff][Cc]1[Cc]149[Aa][Ff][Bb][Ff]4[Cc]8996[Ff][Bb]92427[Aa][Ee]41[Ee]4649[Bb]934[Cc][Aa]495991[Bb]7852[Bb]855[[:space:]]*$' /etc/mandos/clients.conf; then
- sed --in-place \
- --expression='/^[[:space:]]*key_id[[:space:]]*=[[:space:]]*[Ee]3[Bb]0[Cc]44298[Ff][Cc]1[Cc]149[Aa][Ff][Bb][Ff]4[Cc]8996[Ff][Bb]92427[Aa][Ee]41[Ee]4649[Bb]934[Cc][Aa]495991[Bb]7852[Bb]855[[:space:]]*$/d' \
- /etc/mandos/clients.conf
- invoke-rc.d mandos restart
- db_version 2.0
- db_fset mandos/removed_bad_key_ids seen false
- db_reset mandos/removed_bad_key_ids
- db_input critical mandos/removed_bad_key_ids || true
- db_go
- db_stop
- fi
- fi
-
- gnutls_version=$(dpkg-query --showformat='${Version}' \
- --show libgnutls30 \
- 2>/dev/null || :)
- if [ -n "$gnutls_version" ] \
- && dpkg --compare-versions $gnutls_version ge 3.6.6; then
- db_version 2.0
- db_input critical mandos/key_id || true
- db_go
- db_stop
- fi
- ;;
-
- abort-upgrade|abort-deconfigure|abort-remove)
- ;;
-
- *)
- echo "$0 called with unknown argument '$1'" 1>&2
- exit 1
- ;;
-esac
-
-# Avahi version 0.6.31-2 and older provides "avahi" (instead of
-# "avahi-daemon") in its /etc/init.d script header. To make
-# insserv(8) happy, we edit our /etc/init.d script header to contain
-# the correct string before the code added by dh_installinit calls
-# update.rc-d, which calls insserv.
-avahi_version="`dpkg-query --showformat='${Version}' --show avahi-daemon`"
-if dpkg --compare-versions "$avahi_version" le 0.6.31-2; then
- sed --in-place --expression='/^### BEGIN INIT INFO$/,/^### END INIT INFO$/s/^\(# Required-\(Stop\|Start\):.*avahi\)-daemon\>/\1/g' /etc/init.d/mandos
-fi
-
-#DEBHELPER#
-
-exit 0
=== removed file 'debian/mandos.prerm'
--- debian/mandos.prerm 2015-07-12 01:57:54 +0000
+++ debian/mandos.prerm 1970-01-01 00:00:00 +0000
@@ -1,32 +0,0 @@
-#!/bin/sh
-# prerm script for mandos
-#
-# see: dh_installdeb(1)
-
-set -e
-
-# summary of how this script can be called:
-# * 'remove'
-# * 'upgrade'
-# * 'failed-upgrade'
-# * 'remove' 'in-favour'
-# * 'deconfigure' 'in-favour'
-# 'removing'
-#
-# for details, see /usr/share/doc/packaging-manual/
-
-case "$1" in
- remove|deconfigure)
- invoke-rc.d mandos stop || :
- ;;
- upgrade|failed-upgrade)
- ;;
- *)
- echo "prerm called with unknown argument '$1'" >&2
- exit 0
- ;;
-esac
-
-#DEBHELPER#
-
-exit 0
=== removed file 'debian/mandos.templates'
--- debian/mandos.templates 2019-08-05 21:00:35 +0000
+++ debian/mandos.templates 1970-01-01 00:00:00 +0000
@@ -1,29 +0,0 @@
-Template: mandos/key_id
-Type: note
-_Description: New client option "key_id" is REQUIRED on server
- A new "key_id" client option is REQUIRED in the clients.conf file,
- otherwise the client most likely will not reboot unattended. This option:
- .
- key_id =
- .
- must be added in the file /etc/mandos/clients.conf, right before the
- "fingerprint" option, for each Mandos client. You must edit that file and
- add this option for all clients. To see the correct key ID for each
- client, run this command (on each client):
- .
- mandos-keygen -F/dev/null|grep ^key_id
- .
- Note: the clients must all also be using GnuTLS 3.6.6 or later; the server
- cannot serve passwords for both old and new clients!
- .
- Rationale: With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP
- keys as TLS session keys. A new TLS key pair will be generated on each
- client and will be used as identification, but the key ID of the public
- key needs to be added to this server, since this will now be used to
- identify the client to the server.
-
-Template: mandos/removed_bad_key_ids
-Type: note
-_Description: Bad key IDs have been removed from clients.conf
- Bad key IDs, which were created by a bug in Mandos client 1.8.0, have been
- removed from /etc/mandos/clients.conf
=== removed directory 'debian/po'
=== removed file 'debian/po/POTFILES.in'
--- debian/po/POTFILES.in 2019-07-27 19:28:14 +0000
+++ debian/po/POTFILES.in 1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
-[type: gettext/rfc822deb] mandos.templates
-[type: gettext/rfc822deb] mandos-client.templates
=== removed file 'debian/po/de.po'
--- debian/po/de.po 2019-08-16 19:28:16 +0000
+++ debian/po/de.po 1970-01-01 00:00:00 +0000
@@ -1,155 +0,0 @@
-# German debconf translation of mandos.
-# This file is distributed under the same license as the mandos package.
-# Copyright (C) 2008-2019 Teddy Hogeborn and Björn Påhlsson
-# Copyright (C) of this file 2019 Chris Leick .
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: mandos 1.8.7-1\n"
-"Report-Msgid-Bugs-To: mandos@packages.debian.org\n"
-"POT-Creation-Date: 2019-08-05 22:57+0200\n"
-"PO-Revision-Date: 2019-08-10 12:06+0100\n"
-"Last-Translator: Chris Leick \n"
-"Language-Team: German \n"
-"Language: de\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid "New client option \"key_id\" is REQUIRED on server"
-msgstr "Auf diesem Server ist die Client-Option »key_id« ERFORDERLICH"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the clients.conf file, "
-"otherwise the client most likely will not reboot unattended. This option:"
-msgstr ""
-"In der Datei clients.conf ist eine neue Client-Option »key_id« ERFORDERLICH, "
-"andernfalls werden die Clients höchstwahrscheinlich nicht unbeaufsichtigt neu "
-"starten. Die Option"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " key_id = "
-msgstr " key_id = "
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"must be added in the file /etc/mandos/clients.conf, right before the "
-"\"fingerprint\" option, for each Mandos client. You must edit that file and "
-"add this option for all clients. To see the correct key ID for each client, "
-"run this command (on each client):"
-msgstr ""
-"muss der Datei /etc/mandos/clients.conf kurz vor der Option »fingerprint« "
-"auf jedem Mandos-Client hinzugefügt werden. Sie müssen diese Datei bearbeiten "
-"und diese Option auf allen Clients hinzufügen. Um die korrekte "
-"Schlüsselkennung für jeden Client anzusehen, führen Sie (auf jedem Client) "
-"diesen Befehl aus:"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " mandos-keygen -F/dev/null|grep ^key_id"
-msgstr " mandos-keygen -F/dev/null|grep ^key_id"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Note: the clients must all also be using GnuTLS 3.6.6 or later; the server "
-"cannot serve passwords for both old and new clients!"
-msgstr ""
-"Hinweis: Die Clients müssen außerdem alle GnuTLS 3.6.6 oder neuer nutzen; der "
-"Server kann keine Passwörter für sowohl alte als auch neue Clients anbieten!"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Rationale: With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP "
-"keys as TLS session keys. A new TLS key pair will be generated on each "
-"client and will be used as identification, but the key ID of the public key "
-"needs to be added to this server, since this will now be used to identify "
-"the client to the server."
-msgstr ""
-"Begründung: Mit GnuTLS 3.6.6 wurde erzwungen, dass Mandos die Benutzung von "
-"OpenPGP als TLS-Sitzungsschlüssel stoppt. Auf jedem Client wird ein neues "
-"TLS-Schlüsselpaar erzeugt und zur Identifizierung benutzt, aber der "
-"öffentliche Schlüssel muss auf diesem Server hinzugefügt werden, da dies nun "
-"zur Identifizierung des Clients auf dem Server verwendet wird."
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid "Bad key IDs have been removed from clients.conf"
-msgstr "Falsche Schlüsselkennungen wurden aus der clients.conf entfernt."
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid ""
-"Bad key IDs, which were created by a bug in Mandos client 1.8.0, have been "
-"removed from /etc/mandos/clients.conf"
-msgstr ""
-"Falsche Schlüsselkennungen, die durch einen Fehler im Mandos-Client 1.8.0 "
-"erzeugt wurden, wurden aus /etc/mandos/clients.conf entfernt."
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid "New client option \"${key_id}\" is REQUIRED on server"
-msgstr "Auf dem Server ist die neue Client-Option »${key_id}« ERFORDERLICH."
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the server's clients.conf "
-"file, otherwise this computer most likely will not reboot unattended. This "
-"option:"
-msgstr ""
-"In der Datei clients.conf des Servers ist eine neue Client-Option »key_id« "
-"ERFORDERLICH, andernfalls wird dieser Rechner höchstwahrscheinlich nicht "
-"unbeaufsichtigt neu starten. Die Option "
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid " ${key_id}"
-msgstr " ${key_id}"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"must be added (all on one line!) on the Mandos server host, in the file /etc/"
-"mandos/clients.conf, right before the \"fingerprint\" option for this Mandos "
-"client. You must edit that file on that server and add this option."
-msgstr ""
-"muss (in einer einzigen Zeile!) der Datei /etc/mandos/clients.conf auf dem "
-"Mandos-Server kurz vor der Option »fingerprint« für diesen Mandos-Client "
-"hinzugefügt werden. Sie müssen diese Datei auf diesem Server bearbeiten und "
-"diese Option hinzufügen."
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP keys as TLS "
-"session keys. A new TLS key pair has been generated and will be used as "
-"identification, but the key ID of the public key needs to be added to the "
-"server, since this will now be used to identify the client to the server."
-msgstr ""
-"Mit GnuTLS 3.6.6 wurde erzwungen, dass Mandos die Benutzung von OpenPGP als "
-"TLS-Sitzungsschlüssel stoppt. Ein neues TLS-Schlüsselpaar wurde erzeugt und "
-"wird zur Identifizierung benutzt, aber die Schlüsselkennung des öffentlichen "
-"Schlüssels muss auf diesem Server hinzugefügt werden, da dies nun "
-"zur Identifizierung des Clients auf dem Server verwendet wird."
=== removed file 'debian/po/en_US.po'
--- debian/po/en_US.po 2019-08-05 21:00:35 +0000
+++ debian/po/en_US.po 1970-01-01 00:00:00 +0000
@@ -1,150 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the mandos package.
-# FIRST AUTHOR , YEAR.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: mandos\n"
-"Report-Msgid-Bugs-To: mandos@packages.debian.org\n"
-"POT-Creation-Date: 2019-08-05 22:57+0200\n"
-"PO-Revision-Date: 2019-08-05 22:59+0200\n"
-"Last-Translator: Teddy Hogeborn \n"
-"Language-Team: English\n"
-"Language: en_US\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid "New client option \"key_id\" is REQUIRED on server"
-msgstr "New client option “key_id” is REQUIRED on server"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the clients.conf file, "
-"otherwise the client most likely will not reboot unattended. This option:"
-msgstr ""
-"A new “key_id” client option is REQUIRED in the clients.conf file, otherwise "
-"the client most likely will not reboot unattended. This option:"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " key_id = "
-msgstr " key_id = "
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"must be added in the file /etc/mandos/clients.conf, right before the "
-"\"fingerprint\" option, for each Mandos client. You must edit that file and "
-"add this option for all clients. To see the correct key ID for each client, "
-"run this command (on each client):"
-msgstr ""
-"must be added in the file /etc/mandos/clients.conf, right before the "
-"“fingerprint” option, for each Mandos client. You must edit that file and "
-"add this option for all clients. To see the correct key ID for each client, "
-"run this command (on each client):"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " mandos-keygen -F/dev/null|grep ^key_id"
-msgstr " mandos-keygen -F/dev/null|grep ^key id"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Note: the clients must all also be using GnuTLS 3.6.6 or later; the server "
-"cannot serve passwords for both old and new clients!"
-msgstr ""
-"Note: the clients must all also be using GnuTLS 3.6.6 or later; the server "
-"cannot serve passwords for both old and new clients!"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Rationale: With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP "
-"keys as TLS session keys. A new TLS key pair will be generated on each "
-"client and will be used as identification, but the key ID of the public key "
-"needs to be added to this server, since this will now be used to identify "
-"the client to the server."
-msgstr ""
-"Rationale: With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP "
-"keys as TLS session keys. A new TLS key pair will be generated on each "
-"client and will be used as identification, but the key ID of the public key "
-"needs to be added to this server, since this will now be used to identify "
-"the client to the server. "
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid "Bad key IDs have been removed from clients.conf"
-msgstr "Bad key IDs have been removed from clients.conf"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid ""
-"Bad key IDs, which were created by a bug in Mandos client 1.8.0, have been "
-"removed from /etc/mandos/clients.conf"
-msgstr ""
-"Bad key IDs, which were created by a bug in Mandos client 1.8.0, have been "
-"removed from /etc/mandos/clients.conf"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid "New client option \"${key_id}\" is REQUIRED on server"
-msgstr "New client option “${key_id}” is REQUIRED on server"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the server's clients.conf "
-"file, otherwise this computer most likely will not reboot unattended. This "
-"option:"
-msgstr ""
-"A new “key_id” client option is REQUIRED in the server’s clients.conf file, "
-"otherwise this computer most likely will not reboot unattended. This option:"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid " ${key_id}"
-msgstr " ${key_id}"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"must be added (all on one line!) on the Mandos server host, in the file /etc/"
-"mandos/clients.conf, right before the \"fingerprint\" option for this Mandos "
-"client. You must edit that file on that server and add this option."
-msgstr ""
-"must be added (all on one line!) on the Mandos server host, in the file /"
-"etc/ mandos/clients.conf, right before the “fingerprint” option for this "
-"Mandos client. You must edit that file on that server and add this option."
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP keys as TLS "
-"session keys. A new TLS key pair has been generated and will be used as "
-"identification, but the key ID of the public key needs to be added to the "
-"server, since this will now be used to identify the client to the server."
-msgstr ""
-"With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP keys as TLS "
-"session keys. A new TLS key pair has been generated and will be used as "
-"identification, but the key ID of the public key needs to be added to the "
-"server, since this will now be used to identify the client to the server."
=== removed file 'debian/po/fr.po'
--- debian/po/fr.po 2019-08-16 19:32:47 +0000
+++ debian/po/fr.po 1970-01-01 00:00:00 +0000
@@ -1,156 +0,0 @@
-# Translation of mandos debconf templates to French
-# Copyright (C) 2019, French l10n team
-# This file is distributed under the same license as the mandos package.
-# Grégoire Scano , 2019.
-msgid ""
-msgstr ""
-"Project-Id-Version: mandos\n"
-"Report-Msgid-Bugs-To: mandos@packages.debian.org\n"
-"POT-Creation-Date: 2019-07-27 21:06+0200\n"
-"PO-Revision-Date: 2019-08-11 15:58+0800\n"
-"Last-Translator: Grégoire Scano \n"
-"Language-Team: French \n"
-"Language: fr_FR\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid "New client option \"key_id\" is REQUIRED on server"
-msgstr "La nouvelle option de client « key_id » est NÉCESSAIRE sur le serveur"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the clients.conf file, "
-"otherwise the client most likely will not reboot unattended. This option:"
-msgstr ""
-"Une nouvelle option de client « key_id » est NÉCESSAIRE dans le fichier "
-"clients.conf, autrement le client ne redémarrera probablement pas de lui-"
-"même. Cette option :"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid "key_id = "
-msgstr "key_id = "
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"must be added in the file /etc/mandos/clients.conf, right before the "
-"\"fingerprint\" option, for each Mandos client. You must edit that file and "
-"add this option for all clients. To see the correct key ID for each client, "
-"run this command (on each client):"
-msgstr ""
-"doit être ajoutée dans le fichier /etc/mandos/clients.conf, juste avant "
-"l'option « fingerprint », pour chaque client Mandos. Vous devez éditer ce "
-"fichier et ajouter cette option pour tous les clients. Pour voir "
-"l'identifiant de clef correct pour chaque client, exécutez la commande (sur "
-"chaque client) :"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid "mandos-keygen -F/dev/null|grep ^key_id"
-msgstr "mandos-keygen -F/dev/null|grep ^key_id"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Note: the clients must all also be using GnuTLS 3.6.6 or later; the server "
-"cannot serve passwords for both old and new clients!"
-msgstr ""
-"Note : les clients doivent également tous utiliser GnuTLS 3.6.6 ou "
-"ultérieur ; le serveur ne peut pas servir des mots de passe pour des clients "
-"anciens et récents en même temps !"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Rationale: With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP "
-"keys as TLS session keys. A new TLS key pair will be generated on each "
-"client and will be used as identification, but the key ID of the public key "
-"needs to be added to this server, since this will now be used to identify "
-"the client to the server."
-msgstr ""
-"Explication : avec GnuTLS 3.6.6, Mandos a été contraint d'arrêter d'utiliser "
-"des clefs OpenPGP comme clefs de session TLS. Une nouvelle paire de clefs "
-"TLS sera générée pour chaque client et sera utilisée pour l'identification, "
-"mais l'identifiant de la clef publique doit être ajouté à ce serveur, "
-"puisqu'il sera utilisé pour identifier le client auprès du serveur."
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid "Bad key IDs have been removed from clients.conf"
-msgstr "Les identifiants de clef incorrects ont été supprimés de clients.conf"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid ""
-"Bad key IDs, which were created by a bug in Mandos client 1.8.0, have been "
-"removed from /etc/mandos/clients.conf"
-msgstr ""
-"Les identifiants de clef incorrects, créés par un bogue dans le client "
-"Mandos 1.8.0, ont été supprimés de /etc/mandos/clients.conf"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid "New client option \"${key_id}\" is REQUIRED on server"
-msgstr ""
-"La nouvelle option de client « ${key_id} » est NÉCESSAIRE sur le serveur"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the server's clients.conf "
-"file, otherwise this computer most likely will not reboot unattended. This "
-"option:"
-msgstr ""
-"Une nouvelle option de client « key_id » est NÉCESSAIRE dans le fichier "
-"clients.conf du serveur, autrement cette machine ne pourra pas redémarrer "
-"d'elle-même. Cette option :"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid "${key_id}"
-msgstr "${key_id}"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"must be added (all on one line!) on the Mandos server host, in the file /etc/"
-"mandos/clients.conf, right before the \"fingerprint\" option for this Mandos "
-"client. You must edit that file on that server and add this option."
-msgstr ""
-"doit être ajoutée (tout sur une seule ligne !) sur le serveur Mandos hôte, "
-"dans le fichier /etc/mandos/clients.conf, juste avant l'option "
-"« fingerprint » de ce client Mandos. Vous devez éditer ce fichier sur ce "
-"serveur et ajouter cette option."
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP keys as TLS "
-"session keys. A new TLS key pair has been generated and will be used as "
-"identification, but the key ID of the public key needs to be added to the "
-"server, since this will now be used to identify the client to the server."
-msgstr ""
-"Avec GnuTLS 3.6.6, Mandos a été contraint d'arrêter d'utiliser des clefs "
-"OpenPGP comme clefs de session TLS. Une nouvelle paire de clefs TLS a été "
-"générée et sera utilisée pour l'identification, mais l'identifiant de la "
-"clef publique doit être ajouté au serveur, puisqu'il sera utilisé pour "
-"identifier le client auprès du serveur."
=== removed file 'debian/po/pt.po'
--- debian/po/pt.po 2019-10-19 17:37:00 +0000
+++ debian/po/pt.po 1970-01-01 00:00:00 +0000
@@ -1,158 +0,0 @@
-# Translation of mandos debconf messages to European Portuguese
-# Copyright (C) 2019 THE mandos'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the mandos package.
-#
-# Américo Monteiro , 2019.
-msgid ""
-msgstr ""
-"Project-Id-Version: mandos 1.8.9-2\n"
-"Report-Msgid-Bugs-To: mandos@packages.debian.org\n"
-"POT-Creation-Date: 2019-08-05 22:57+0200\n"
-"PO-Revision-Date: 2019-10-18 18:45+0000\n"
-"Last-Translator: Américo Monteiro \n"
-"Language-Team: Portuguese <>\n"
-"Language: pt\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Lokalize 2.0\n"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid "New client option \"key_id\" is REQUIRED on server"
-msgstr "Nova opção \"key_id\" de cliente é NECESSÁRIA no servidor"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the clients.conf file, "
-"otherwise the client most likely will not reboot unattended. This option:"
-msgstr ""
-"Uma nova opção de cliente \"key_id\" é NECESSÁRIA no ficheiro clients.conf, "
-"caso contrário o mais provável é o cliente não conseguir reinicicar sozinho. "
-"Esta opção:"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " key_id = "
-msgstr " key_id = "
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"must be added in the file /etc/mandos/clients.conf, right before the "
-"\"fingerprint\" option, for each Mandos client. You must edit that file and "
-"add this option for all clients. To see the correct key ID for each client, "
-"run this command (on each client):"
-msgstr ""
-"tem de ser adicionada ao ficheiro /etc/mandos/clients.conf, logo antes "
-"da opção \"fingerprint\", para cada cliente Mandos. Você tem de editar esse "
-"ficheiro e adicionar esta opção para todos os clientes. Para ver a key ID "
-"para cada cliente, corra este comando (em cada cliente):"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " mandos-keygen -F/dev/null|grep ^key_id"
-msgstr " mandos-keygen -F/dev/null|grep ^key_id"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Note: the clients must all also be using GnuTLS 3.6.6 or later; the server "
-"cannot serve passwords for both old and new clients!"
-msgstr ""
-"Note: os clientes têm de também usar GnuTLS 3.6.6 ou posterior; o servidor "
-"não consegue servir palavras passe para ambos clientes antigos e novos!"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Rationale: With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP "
-"keys as TLS session keys. A new TLS key pair will be generated on each "
-"client and will be used as identification, but the key ID of the public key "
-"needs to be added to this server, since this will now be used to identify "
-"the client to the server."
-msgstr ""
-"Razão: Com GnuTLS 3.6.6, o Mandos foi forçado a parar de usar chaves OpenPGP "
-"como chaves de sessão TLS. Será gerado um novo par de chaves TLS em cada "
-"cliente e será usado como identificação, mas o ID de chave da chave pública "
-"precisa de ser adicionada a este servidor, pois esta irá agora ser usada "
-"para identificar o cliente no servidor."
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid "Bad key IDs have been removed from clients.conf"
-msgstr "IDs de chave errados foram removidos de clients.conf"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid ""
-"Bad key IDs, which were created by a bug in Mandos client 1.8.0, have been "
-"removed from /etc/mandos/clients.conf"
-msgstr ""
-"IDs de chave errados, que foram criados por um bug no cliente Mandos 1.8.0, "
-"foram removidos de /etc/mandos/clients.conf"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid "New client option \"${key_id}\" is REQUIRED on server"
-msgstr "Nova opção \"${key_id}\" de cliente é NECESSÁRIA no servidor"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the server's clients.conf "
-"file, otherwise this computer most likely will not reboot unattended. This "
-"option:"
-msgstr ""
-"Uma nova opção \"key_id\" de cliente é NECESSÁRIA no ficheiro clients.conf "
-"do servidor, caso contrário, é bem provável que este computador não consiga "
-"reiniciar sozinho. Esta opção:"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid " ${key_id}"
-msgstr " ${key_id}"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"must be added (all on one line!) on the Mandos server host, in the file /etc/"
-"mandos/clients.conf, right before the \"fingerprint\" option for this Mandos "
-"client. You must edit that file on that server and add this option."
-msgstr ""
-"tem de ser adicionada (toda numa linha) na máquina servidor do Mandos, no "
-"ficheiro /etc/mandos/clients.conf, logo antes da opção \"fingerprint\" para "
-"este cliente Mandos. Você tem de editar esse ficheiro nesse servidor e "
-"adicionar esta opção."
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP keys as TLS "
-"session keys. A new TLS key pair has been generated and will be used as "
-"identification, but the key ID of the public key needs to be added to the "
-"server, since this will now be used to identify the client to the server."
-msgstr ""
-"Com GnuTLS 3.6.6, o Mandos foi forçado a parar de usar chaves OpenPGP "
-"como chaves de sessão TLS. Foi gerado um novo par de chaves TLS e será "
-"usado como identificação, mas o ID de chave da chave pública precisa de ser "
-"adicionada ao servidor, pois esta irá agora ser usada para identificar o "
-"cliente no servidor."
-
-
=== removed file 'debian/po/sv.po'
--- debian/po/sv.po 2019-08-16 20:47:52 +0000
+++ debian/po/sv.po 1970-01-01 00:00:00 +0000
@@ -1,156 +0,0 @@
-# Translation of mandos debconf templates to Swedish
-# Copyright (C) 2019, Mandos Maintainers
-# This file is distributed under the same license as the mandos package.
-# Teddy Hogeborn , 2019.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: mandos\n"
-"Report-Msgid-Bugs-To: mandos@packages.debian.org\n"
-"POT-Creation-Date: 2019-08-05 22:57+0200\n"
-"PO-Revision-Date: 2019-08-16 22:45+0200\n"
-"Last-Translator: Teddy Hogeborn \n"
-"Language-Team: Swedish \n"
-"Language: sv\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid "New client option \"key_id\" is REQUIRED on server"
-msgstr "Ny klientinställning ”key_id” KRÄVS på servern"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the clients.conf file, "
-"otherwise the client most likely will not reboot unattended. This option:"
-msgstr ""
-"En ny klientinställning, ”key_id”, KRÄVS i filen clients.conf, annars\n"
-"kommer klienten antagligen inte att starta upp av sig själv. Denna\n"
-"inställning:"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " key_id = "
-msgstr " key_id = "
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"must be added in the file /etc/mandos/clients.conf, right before the "
-"\"fingerprint\" option, for each Mandos client. You must edit that file and "
-"add this option for all clients. To see the correct key ID for each client, "
-"run this command (on each client):"
-msgstr ""
-"måste läggas till i filen /etc/mandos/clients.conf, precis ovanför\n"
-"inställningen ”fingerprint”, för varje Mandosklient. Du måste ändra i\n"
-"den filen och lägga till den inställningen för alla klienter. För att\n"
-"se det korrekta nyckel-IDt för varje klient, kör följande kommando (på\n"
-"varje klient):"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " mandos-keygen -F/dev/null|grep ^key_id"
-msgstr " mandos-keygen -F/dev/null|grep ^key_id"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Note: the clients must all also be using GnuTLS 3.6.6 or later; the server "
-"cannot serve passwords for both old and new clients!"
-msgstr ""
-"Observera: Alla klienter måste också använda GnuTLS 3.6.6 eller nyare;\n"
-"servern kan inte ge lösenord till både nya och gamla klienter!"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Rationale: With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP "
-"keys as TLS session keys. A new TLS key pair will be generated on each "
-"client and will be used as identification, but the key ID of the public key "
-"needs to be added to this server, since this will now be used to identify "
-"the client to the server."
-msgstr ""
-"Förklaring: Med GnuTLS 3.6.6 så har Mandos nödgats att sluta använda\n"
-"OpenPGP-nycklar som TLS-sessionsnycklar. Ett nytt TLS-nyckelpar\n"
-"kommer att genereras på varje klient och kommer att användas för\n"
-"identifiering, men nyckel-IDt för den publika nyckeln måste läggas\n"
-"till på denna server, då denna numera kommer att användas för att\n"
-"identifiera klienten för servern."
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid "Bad key IDs have been removed from clients.conf"
-msgstr "Dåliga nyckel-IDn har tagits bort från clients.conf"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid ""
-"Bad key IDs, which were created by a bug in Mandos client 1.8.0, have been "
-"removed from /etc/mandos/clients.conf"
-msgstr ""
-"Dåliga nyckel-IDn, som skapats av en bugg i Mandosklienten 1.8.0, har\n"
-"tagits bort från /etc/mandos/clients.conf"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid "New client option \"${key_id}\" is REQUIRED on server"
-msgstr "Ny klientinställning ”${key_id}” KRÄVS på servern"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the server's clients.conf "
-"file, otherwise this computer most likely will not reboot unattended. This "
-"option:"
-msgstr ""
-"En ny klientinställning, ”key_id”, KRÄVS i serverns clients.conf-fil,\n"
-"annars kommer denna dator antagligen inte att starta upp av sig själv.\n"
-"Denna inställning:"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid " ${key_id}"
-msgstr " ${key_id}"
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"must be added (all on one line!) on the Mandos server host, in the file /etc/"
-"mandos/clients.conf, right before the \"fingerprint\" option for this Mandos "
-"client. You must edit that file on that server and add this option."
-msgstr ""
-"måste läggas till (allt på en rad!) på Mandosservervärddatorn, i filen\n"
-"/etc/mandos/clients.conf, precis ovanför inställningen ”fingerprint”,\n"
-"för denna Mandosklient. Du måste ändra i den filen och lägga till den\n"
-"inställningen."
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP keys as TLS "
-"session keys. A new TLS key pair has been generated and will be used as "
-"identification, but the key ID of the public key needs to be added to the "
-"server, since this will now be used to identify the client to the server."
-msgstr ""
-"Med GnuTLS 3.6.6 så har Mandos nödgats att sluta använda\n"
-"OpenPGP-nycklar som TLS-sessionsnycklar. Ett nytt TLS-nyckelpar har\n"
-"genererats och kommer att användas för identifiering, men nyckel-IDt\n"
-"för den publika nyckeln måste läggas till på servern, då detta numera\n"
-"kommer att användas för att identifiera klienten för servern."
=== removed file 'debian/po/templates.pot'
--- debian/po/templates.pot 2019-08-05 21:00:35 +0000
+++ debian/po/templates.pot 1970-01-01 00:00:00 +0000
@@ -1,127 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the mandos package.
-# FIRST AUTHOR , YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: mandos\n"
-"Report-Msgid-Bugs-To: mandos@packages.debian.org\n"
-"POT-Creation-Date: 2019-08-05 22:57+0200\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid "New client option \"key_id\" is REQUIRED on server"
-msgstr ""
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the clients.conf file, "
-"otherwise the client most likely will not reboot unattended. This option:"
-msgstr ""
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " key_id = "
-msgstr ""
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"must be added in the file /etc/mandos/clients.conf, right before the "
-"\"fingerprint\" option, for each Mandos client. You must edit that file and "
-"add this option for all clients. To see the correct key ID for each client, "
-"run this command (on each client):"
-msgstr ""
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid " mandos-keygen -F/dev/null|grep ^key_id"
-msgstr ""
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Note: the clients must all also be using GnuTLS 3.6.6 or later; the server "
-"cannot serve passwords for both old and new clients!"
-msgstr ""
-
-#. Type: note
-#. Description
-#: ../mandos.templates:1001
-msgid ""
-"Rationale: With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP "
-"keys as TLS session keys. A new TLS key pair will be generated on each "
-"client and will be used as identification, but the key ID of the public key "
-"needs to be added to this server, since this will now be used to identify "
-"the client to the server."
-msgstr ""
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid "Bad key IDs have been removed from clients.conf"
-msgstr ""
-
-#. Type: note
-#. Description
-#: ../mandos.templates:2001
-msgid ""
-"Bad key IDs, which were created by a bug in Mandos client 1.8.0, have been "
-"removed from /etc/mandos/clients.conf"
-msgstr ""
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid "New client option \"${key_id}\" is REQUIRED on server"
-msgstr ""
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"A new \"key_id\" client option is REQUIRED in the server's clients.conf "
-"file, otherwise this computer most likely will not reboot unattended. This "
-"option:"
-msgstr ""
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid " ${key_id}"
-msgstr ""
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"must be added (all on one line!) on the Mandos server host, in the file /etc/"
-"mandos/clients.conf, right before the \"fingerprint\" option for this Mandos "
-"client. You must edit that file on that server and add this option."
-msgstr ""
-
-#. Type: note
-#. description
-#: ../mandos-client.templates:1001
-msgid ""
-"With GnuTLS 3.6.6, Mandos has been forced to stop using OpenPGP keys as TLS "
-"session keys. A new TLS key pair has been generated and will be used as "
-"identification, but the key ID of the public key needs to be added to the "
-"server, since this will now be used to identify the client to the server."
-msgstr ""
=== removed file 'debian/rules'
--- debian/rules 2019-04-09 22:31:23 +0000
+++ debian/rules 1970-01-01 00:00:00 +0000
@@ -1,61 +0,0 @@
-#!/usr/bin/make -f
-
-ifeq (,$(filter noopt,$(DEB_BUILD_OPTIONS)))
- MAKEFLAGS += OPTIMIZE=-O0
-endif
-
-ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
- NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
- MAKEFLAGS += -j$(NUMJOBS)
-endif
-
-%:
- dh $@
-
-override_dh_auto_build-arch:
- LC_ALL=en_US.utf8 dh_auto_build -- all doc
-
-override_dh_auto_build-indep:
- LC_ALL=en_US.utf8 dh_auto_build -- doc
-
-override_dh_installinit-indep:
- dh_installinit --onlyscripts \
- --update-rcd-params="defaults 25 15"
-
-override_dh_auto_install-indep:
- $(MAKE) DESTDIR=$(CURDIR)/debian/mandos install-server
-
-override_dh_auto_install-arch:
- $(MAKE) DESTDIR=$(CURDIR)/debian/mandos-client \
- install-client-nokey
-
-override_dh_fixperms-arch:
- dh_fixperms --exclude etc/keys/mandos \
- --exclude etc/mandos/plugins.d \
- --exclude etc/mandos/plugin-helpers \
- --exclude usr/lib/$(DEB_HOST_MULTIARCH)/mandos/plugins.d \
- --exclude usr/lib/$(DEB_HOST_MULTIARCH)/mandos/plugin-helpers \
- --exclude usr/share/doc/mandos-client/examples/network-hooks.d
- chmod --recursive g-w -- \
- "$(CURDIR)/debian/mandos-client/usr/share/doc/mandos-client/examples/network-hooks.d"
-
-override_dh_fixperms-indep:
- dh_fixperms --exclude etc/mandos/clients.conf
-
-override_dh_auto_test-arch: ;
-
-#bpo## dpkg-shlibdeps sees the "libgnutls28-dev (>= 3.6.6) |
-#bpo## libgnutls28-dev (<< 3.6.0)," in the build-dependencies not as two
-#bpo## alternatives, but as an absolute dependency on libgnutls30 >= 3.6.6.
-#bpo## So we have to do this ugly hack to hide this build dependency if we
-#bpo## compiled with libgnutls30 << 3.6.0.
-#bpo#override_dh_shlibdeps-arch:
-#bpo# -gnutls_version=$$(dpkg-query --showformat='$${Version}' \
-#bpo# --show libgnutls30); \
-#bpo# dpkg --compare-versions $$gnutls_version lt 3.6.0 \
-#bpo# && { cp --archive debian/control debian/control.orig; sed --in-place --expression='s/libgnutls28-dev (>= 3\.6\.6) |//' debian/control; }
-#bpo# dh_shlibdeps
-#bpo# -gnutls_version=$$(dpkg-query --showformat='$${Version}' \
-#bpo# --show libgnutls30); \
-#bpo# dpkg --compare-versions $$gnutls_version lt 3.6.0 \
-#bpo# && mv debian/control.orig debian/control
=== removed directory 'debian/source'
=== removed file 'debian/source/format'
--- debian/source/format 2010-10-02 17:41:05 +0000
+++ debian/source/format 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-3.0 (quilt)
=== removed file 'debian/source/lintian-overrides'
--- debian/source/lintian-overrides 2019-08-05 21:03:31 +0000
+++ debian/source/lintian-overrides 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
-# We are both upstream and Debian maintainer for this package, so the
-# .asc signature can not exist until after the orig.tar.gz has been
-# built as part of the Debian package build.
-mandos source: orig-tarball-missing-upstream-signature mandos_*.tar.gz
-
-# We want to backport to stretch for as long as reasonably practical
-mandos source: package-uses-old-debhelper-compat-version 10
=== removed file 'debian/source/local-options'
--- debian/source/local-options 2011-10-08 21:13:46 +0000
+++ debian/source/local-options 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
---single-debian-patch
=== removed directory 'debian/tests'
=== removed file 'debian/tests/control'
--- debian/tests/control 2019-09-04 05:31:20 +0000
+++ debian/tests/control 1970-01-01 00:00:00 +0000
@@ -1,33 +0,0 @@
-Test-Command: /usr/sbin/mandos --check
-Restrictions: superficial, allow-stderr
-Features: test-name=mandos-check
-Depends: mandos
-
-Test-Command: /usr/sbin/mandos-ctl --check --verbose
-Restrictions: allow-stderr
-Features: test-name=mandos-ctl
-Depends: mandos
-
-Test-Command: /usr/sbin/mandos-keygen --version
-Restrictions: superficial
-Features: test-name=mandos-keygen-version
-Depends: mandos-client
-
-Test-Command: /usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null)/mandos/plugin-runner --version
-Restrictions: needs-root, superficial
-Features: test-name=plugin-runner-version
-Depends: mandos-client
-
-Test-Command: /usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null)/mandos/plugin-helpers/mandos-client-iprouteadddel --version
-Restrictions: needs-root, superficial
-Features: test-name=mandos-client-iprouteadddel-version
-Depends: mandos-client
-
-Test-Command: /usr/lib/dracut/modules.d/90mandos/password-agent --test --verbose
-Features: test-name=password-agent
-Depends: mandos-client
-
-Test-Command: /usr/lib/dracut/modules.d/90mandos/password-agent --test --verbose -p /task-creators/start_mandos_client/suid
-Restrictions: needs-root
-Features: test-name=password-agent-suid
-Depends: mandos-client
=== removed directory 'debian/upstream'
=== removed file 'debian/upstream/metadata'
--- debian/upstream/metadata 2019-08-04 12:39:39 +0000
+++ debian/upstream/metadata 1970-01-01 00:00:00 +0000
@@ -1,13 +0,0 @@
-# -*- yaml -*-
----
-Bug-Submit: mailto:mandos-dev@recompile.se
-Changelog: https://bzr.recompile.se/loggerhead/mandos/trunk/view/head:/NEWS
-Contact: mandos@recompile.se
-Documentation: https://www.recompile.se/mandos/man/intro.8mandos
-FAQ: https://www.recompile.se/mandos/man/intro.8mandos#faq
-Name: Mandos
-Other-References: https://www.recompile.se/mandos
-Registration: https://mail.recompile.se/cgi-bin/mailman/listinfo/mandos-dev
-Repository: https://ftp.recompile.se/pub/mandos/trunk
-Repository-Browse: https://bzr.recompile.se/loggerhead/mandos/trunk/files
-Security-Contact: mandos@recompile.se
=== removed file 'debian/upstream/signing-key.asc'
--- debian/upstream/signing-key.asc 2014-03-28 22:32:21 +0000
+++ debian/upstream/signing-key.asc 1970-01-01 00:00:00 +0000
@@ -1,52 +0,0 @@
------BEGIN PGP PUBLIC KEY BLOCK-----
-Version: GnuPG v1.4.12 (GNU/Linux)
-
-mQINBFJQOFYBEACoWsEGlOxVWFUAxOxdd3GDLaqEKkKihJwLp102Ks7JKMd9friR
-7+OZuo3U0gdqLU9q1jPJn36J1QbaUTOvcaKtZp+QpUoYJ2OaGtlOY5ML8LSoC0rZ
-MIzGYTtvriwpU/YplLNGPl/90KsB2VqjrY1l1he5M8zziWDlPdJxwg8GFvmPWoif
-6oo+1iCswL5IdQ6c5MVO53zYu0cgyUSazLsVD5Xzy59lefgtaDydahJpPycf5aEQ
-DAoC9fZt2mgG3FLIUCZdXIhZdOJGCMdjLThBnJXYgGbG4rbGLNlI4W/uA5aqa4ME
-WYSAcCyX3ucKY/LkXRtC+z5s05e7tZ3Z+uAJy1eDsbhDXgZERye7a/zPWx1tAlzQ
-E80Oltjh1uXWjQORyx99a0jK87zjm49YjhYw1ZN6Z0HfSaws4Yj2QOzp9t4B3l7f
-DIUYoWBfHW7mseQeQ+t3TwQU5gjFCNu7oDeATqi5A5MksXN0+BcksterbGRBhEyp
-CybIEyrZE033jIs407Ool4Kv10cnjc8oy609BXex/dxwcvVr2vQHle4NPUZd+Xhg
-zC+9Z4jFwE0M/EPvtyieA/DWQse+TZ5itDGMYDub/GJfv1U61ANOgPIbTEF7iSa9
-5nWmq7zyUy/txmABka842Kt0Vp6ayoKcF8EIXCaDrVfPnXj+JlKf3c2u6wARAQAB
-tCxNYW5kb3MgTWFpbnRhaW5lciBUZWFtIDxtYW5kb3NAcmVjb21waWxlLnNlPokC
-PQQTAQgAJwUCUlA4VgIbAwUJCWYBgAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAK
-CRByIylzyjTCxETXEACi56jCV9lJNSBbTp0Iet4X/i7Mx0Z8UkFFa3l7o0i4jFQj
-CIBrWECDlcxqZziii2dgh7L0ma93vB3rfjfCWeYLcEQw43MFBsd4dHuobrLXTcqU
-7n0Zmc8BsXwk5B25CnEYgvlbWX9BCYtxHGRcZzQrqOFjCMKatq0EIIVuWaz5yuCU
-V2rEgnr+veTd/rBOE9ez6Ju6xH11Teob5G7pMM0YPKHtZG/J3rvWPw4BDM6Tc60B
-G0sTDZNgkrGWxuB8YaLIwVWzliQK/17Jv/0alajyA3cWLWMkcK9Yhi/einzdMRoD
-IjnbtoHcSC9g6i0VGelwnMpHlFTwXriXEBSttULarK3iKE4tOv9nxMAEwicqlw14
-X96PPgz6ogtJG7FiwZfy1CQ81Uby+YuIhHZx3ZEyR1TFq70e98EgCuvjMZWMIhSy
-gB5Vssfq7c2lXQjltV3ujhK1PD+7/iHlL7t4QRxPDN8fbMS2VPfAdtnWS1K48d5J
-D/jP1LrGWS81HIaX8GFVLVw+jSQEu9cn3TFiZxK/4MMsITmlouJdtZWmQ/otMSMl
-wiCCZp3dGpRXMmaqR1N8V0nMKshM8mci7bD92ubd/t6cR/G6l+VIp45WyFONvtde
-F3ccfmfrKJuroMDfHxPxMf58EroAuWwzJKCPRH4JmwDvSSQoIIAGNL1lOKp6wrkC
-DQRSUDhWARAAzN7pbpAu7XLNPODotV/N+JaCFvNAIqTcr9PrbhxiKFCDs9/IExwP
-sGENL9GZd1DfoGEgxQ8j3l8VGw9VSeUoN7uMY2NwwbXTilAFkn/S8xnr2zQDRZ+n
-EeFSq9MMFxj4Kt1TqVYDbO8vmFfOT3gRCRHeJ+pn4yJeSPau/ndNrmbQ1/Z6vaUG
-yfo931ottx7SXZwkHA6jJVFT9rbHTyx9tzOqMKDJiMrx8qKaHpE9B45oHNR0WJJJ
-75zoDVuOZ6wAxXZuqBFu2lKPqDTZeawfzcu5qplrm1RPgSOjz6w1A41HBLqGe+v9
-7Twx5wfNMgnKC0V2wUe0xR6hQHQlyZoCwcGyrasiu+v/joZ1p66SSWKjs+LGjoe4
-Lwh6VjZU2x+irVBjcgIoRWf3k4JAef0nGYsm0cFjAnwXac+/CYxVt+7Y4+HG8wPB
-oUNZkW+bvdHQouxEClxnccIEgX/AkriJTYDQ4q3tkl2HVE/51R4pdQVLer2a5ov+
-Jwk44DdqzYstMsvqu+iD48hXzADg6HFvofkpct15h463pMaJf99uVVM9ZDNQ6B34
-l3tPX9ZDkIDl6n9dE2Jkaxx1yNVhPXpeMf4EzL+CEdUErVStB66lUkw+tNkuZyVT
-ZTQel9h0196+CNSiqAaL8+ZZdbjKKfzlcB4Qnd897XzMfsFQ7mzJ9QsAEQEAAYkC
-JQQYAQgADwUCUlA4VgIbDAUJCWYBgAAKCRByIylzyjTCxFmlEACBTOg5NqX63d8D
-mwk4smlFPppQBIduxZaMG9HsLcPi3VKTG9Zg6WI6rEdr/4MnoINsudLsEbrQLgRH
-2q1Zs+HqIIP5H2/sYHmswyokYB10zKB6gNUUg/GSlcAcrelsHVKx5B8kccWGT5gk
-Wo/X0BGMUTOvQ6lJ6YNo1idcQ2ZjsyfZoz3G8JS7/EXN//jAZf+017yj8WsAS7hw
-JRFMy7VET4g00JcBoNOAMP7PkozimZ2OwwsggJSYWkR1RaU2tKR1VmDF8R6UxuEd
-BJzwFmz+wNC1Kq+FoSaRNsrKEmzLnfV9unDnF2z7Lc4LqOysXdzOk9zTBPur0gd2
-Lh5H/g5rTAMQBARqXfvIwiTtrBGgil8JW8e4Bc0LQUuHAE7x9gMRil+OtkQrCRk9
-0LWXVS+K0tvvruE4EDtCGiS5046+BEI3aYsp4hNzjHADq0TJeCYjNg9kY0CjxcEq
-cfuMoUbQ0MkARGuBbykCdlylfTrkxrj/dPhr49lctY3H+Pj6F4fMDM4TP6UTGA8k
-993RRNYhkDWSxIp6G7RJpBZobHN+eHQ3r8A4tWdYb4Fvd2lvwEDjUFT9uD6WAff4
-8A1hM2uSy91UYBOPrIjqYdRFKJc9rThYdXH2T6SiRMYtZMrEKhqPffB/i9mqVBlD
-6vKRsaQikZujRdP9Dkf0mLmJ7LANWw==
-=9Noe
------END PGP PUBLIC KEY BLOCK-----
=== removed file 'debian/watch'
--- debian/watch 2019-02-11 05:15:24 +0000
+++ debian/watch 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
-version=4
-opts=pgpmode=auto \
- https://ftp.recompile.se/pub/@PACKAGE@/@PACKAGE@@ANY_VERSION@\.orig@ARCHIVE_EXT@
=== removed file 'default-mandos'
--- default-mandos 2008-09-17 00:34:09 +0000
+++ default-mandos 1970-01-01 00:00:00 +0000
@@ -1,7 +0,0 @@
-# Directory where configuration files are located. Default is
-# "/etc/mandos".
-#
-#CONFIGDIR=/etc/mandos
-
-# Additional options that are passed to the Daemon.
-DAEMON_ARGS=""
=== removed directory 'dracut-module'
=== removed file 'dracut-module/ask-password-mandos.path'
--- dracut-module/ask-password-mandos.path 2019-07-27 10:11:45 +0000
+++ dracut-module/ask-password-mandos.path 1970-01-01 00:00:00 +0000
@@ -1,47 +0,0 @@
-# -*- systemd -*-
-#
-# Copyright © 2019 Teddy Hogeborn
-# Copyright © 2019 Björn Påhlsson
-#
-# This file is part of Mandos.
-#
-# Mandos 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.
-#
-# Mandos 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 Mandos. If not, see .
-#
-# Contact the authors at .
-#
-# This systemd.path(5) unit will wait until there are any password
-# questions present, represented by files named "ask.*" in the
-# /run/systemd/ask-password directory, and then start the
-# "ask-password-mandos.service" systemd.service(5) unit.
-
-# This file should be installed in the root file system as
-# "/usr/lib/dracut/modules.d/90mandos/ask-password-mandos.path" and
-# will be installed in the initramfs image file as
-# "/lib/systemd/system/ask-password-mandos.path", and symlinked to
-# "/lib/systemd/system//sysinit.target.wants/ask-password-mandos.path"
-# by dracut when dracut creates the initramfs image file.
-
-[Unit]
-Description=Forward Password Requests to remote Mandos server
-Documentation=man:intro(8mandos) man:password-agent(8mandos) man:mandos-client(8mandos)
-DefaultDependencies=no
-Conflicts=shutdown.target
-Before=basic.target shutdown.target
-ConditionKernelCommandLine=!mandos=off
-ConditionFileIsExecutable=/lib/mandos/password-agent
-ConditionPathIsMountPoint=!/sysroot
-
-[Path]
-PathExistsGlob=/run/systemd/ask-password/ask.*
-MakeDirectory=yes
=== removed file 'dracut-module/ask-password-mandos.service'
--- dracut-module/ask-password-mandos.service 2019-07-27 10:11:45 +0000
+++ dracut-module/ask-password-mandos.service 1970-01-01 00:00:00 +0000
@@ -1,51 +0,0 @@
-# -*- systemd -*-
-#
-# Copyright © 2019 Teddy Hogeborn
-# Copyright © 2019 Björn Påhlsson
-#
-# This file is part of Mandos.
-#
-# Mandos 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.
-#
-# Mandos 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 Mandos. If not, see .
-#
-# Contact the authors at .
-#
-# This systemd.service(5) unit file will start the Mandos
-# password-agent(8mandos) program, which will in turn run
-# mandos-client(8mandos) to get a password and send the password to
-# any and all active password questions using the systemd “Password
-# Agent” mechanism.
-
-# This file should be installed in the root file system as
-# "/usr/lib/dracut/modules.d/90mandos/ask-password-mandos.service" and
-# will be installed in the initramfs image file as
-# "/lib/systemd/system/ask-password-mandos.service" by dracut when
-# dracut creates the initramfs image file.
-
-[Unit]
-Description=Forward Password Requests to remote Mandos server
-Documentation=man:intro(8mandos) man:password-agent(8mandos) man:mandos-client(8mandos)
-DefaultDependencies=no
-Conflicts=shutdown.target
-Before=shutdown.target
-ConditionKernelCommandLine=!mandos=off
-ConditionFileIsExecutable=/lib/mandos/password-agent
-ConditionFileIsExecutable=/lib/mandos/mandos-client
-ConditionFileNotEmpty=/etc/mandos/keys/pubkey.txt
-ConditionFileNotEmpty=/etc/mandos/keys/seckey.txt
-ConditionFileNotEmpty=/etc/mandos/keys/tls-pubkey.pem
-ConditionFileNotEmpty=/etc/mandos/keys/tls-privkey.pem
-ConditionPathIsMountPoint=!/sysroot
-
-[Service]
-ExecStart=/lib/mandos/password-agent -- /lib/mandos/mandos-client --pubkey=/etc/mandos/keys/pubkey.txt --seckey=/etc/mandos/keys/seckey.txt --tls-pubkey=/etc/mandos/keys/tls-pubkey.pem --tls-privkey=/etc/mandos/keys/tls-privkey.pem
=== removed file 'dracut-module/cmdline-mandos.sh'
--- dracut-module/cmdline-mandos.sh 2019-07-27 10:11:45 +0000
+++ dracut-module/cmdline-mandos.sh 1970-01-01 00:00:00 +0000
@@ -1,74 +0,0 @@
-#!/bin/sh
-#
-# This file should be present in the root file system directory
-# /usr/lib/dracut/modules.d/90mandos. When dracut creates the
-# initramfs image, dracut will run the "module-setup.sh" file in the
-# same directory, which (when *not* using the "systemd" dracut module)
-# will copy this file ("cmdline-mandos.sh") into the initramfs as
-# "/lib/dracut/hooks/cmdline/20-cmdline-mandos.sh".
-#
-# Despite the above #!/bin/sh line and the executable flag, this file
-# is not executed; this file is sourced by the /init script in the
-# initramfs image created by dracut.
-
-if getargbool 1 mandos && [ -e /lib/dracut-crypt-lib.sh ]; then
- cat >> /lib/dracut-crypt-lib.sh <<- "EOF"
- ask_for_password(){
- local cmd; local prompt; local tries=3
- local ply_cmd; local ply_prompt; local ply_tries=3
- local tty_cmd; local tty_prompt; local tty_tries=3
- local ret
-
- while [ $# -gt 0 ]; do
- case "$1" in
- --cmd) ply_cmd="$2"; tty_cmd="$2"; shift;;
- --ply-cmd) ply_cmd="$2"; shift;;
- --tty-cmd) tty_cmd="$2"; shift;;
- --prompt) ply_prompt="$2"; tty_prompt="$2"; shift;;
- --ply-prompt) ply_prompt="$2"; shift;;
- --tty-prompt) tty_prompt="$2"; shift;;
- --tries) ply_tries="$2"; tty_tries="$2"; shift;;
- --ply-tries) ply_tries="$2"; shift;;
- --tty-tries) tty_tries="$2"; shift;;
- --tty-echo-off) tty_echo_off=yes;;
- -*) :;;
- esac
- shift
- done
- if [ -z "$ply_cmd" ]; then
- ply_cmd="$tty_cmd"
- fi
- # Extract device and luksname from $ply_cmd
- set -- $ply_cmd
- shift
- for arg in "$@"; do
- case "$arg" in
- -*) :;;
- *)
- if [ -z "$device" ]; then
- device="$arg"
- else
- luksname="$arg"
- break
- fi
- ;;
- esac
- done
- { flock -s 9;
- if [ -z "$ply_prompt" ]; then
- if [ -z "$tty_prompt" ]; then
- CRYPTTAB_SOURCE="$device" cryptsource="$device" CRYPTTAB_NAME="$luksname" crypttarget="$luksname" /lib/mandos/plugin-runner --config-file=/etc/mandos/plugin-runner.conf | $ply_cmd
- else
- CRYPTTAB_SOURCE="$device" cryptsource="$device" CRYPTTAB_NAME="$luksname" crypttarget="$luksname" /lib/mandos/plugin-runner --options-for=password-prompt:--prompt="${tty_prompt}" --config-file=/etc/mandos/plugin-runner.conf | $ply_cmd
- fi
- else
- if [ -z "$tty_prompt" ]; then
- CRYPTTAB_SOURCE="$device" cryptsource="$device" CRYPTTAB_NAME="$luksname" crypttarget="$luksname" /lib/mandos/plugin-runner --options-for=plymouth:--prompt="${ply_prompt}" --config-file=/etc/mandos/plugin-runner.conf | $ply_cmd
- else
- CRYPTTAB_SOURCE="$device" cryptsource="$device" CRYPTTAB_NAME="$luksname" crypttarget="$luksname" /lib/mandos/plugin-runner --options-for=password-prompt:--prompt="${tty_prompt}" --options-for=plymouth:--prompt="${ply_prompt}" --config-file=/etc/mandos/plugin-runner.conf | $ply_cmd
- fi
- fi
- } 9>/.console_lock
- }
- EOF
-fi
=== removed file 'dracut-module/module-setup.sh'
--- dracut-module/module-setup.sh 2019-07-27 10:11:45 +0000
+++ dracut-module/module-setup.sh 1970-01-01 00:00:00 +0000
@@ -1,253 +0,0 @@
-#!/bin/sh
-#
-# This file should be present in the root file system directory
-# /usr/lib/dracut/modules.d/90mandos. When dracut creates the
-# initramfs image, dracut will source this file and run the shell
-# functions defined in this file: "install", "check", "depends",
-# "cmdline", and "installkernel".
-#
-# Despite the above #!/bin/sh line and the executable flag, this file
-# is not executed; this file is sourced by dracut when creating the
-# initramfs image file.
-
-mandos_libdir(){
- for dir in /usr/lib \
- "/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null`" \
- "`rpm --eval='%{_libdir}' 2>/dev/null`" /usr/local/lib; do
- if [ -d "$dir"/mandos ]; then
- echo "$dir"/mandos
- return
- fi
- done
- # Mandos not found
- return 1
-}
-
-mandos_keydir(){
- for dir in /etc/keys/mandos /etc/mandos/keys; do
- if [ -d "$dir" ]; then
- echo "$dir"
- return
- fi
- done
- # Mandos key directory not found
- return 1
-}
-
-check(){
- if [ "${hostonly:-no}" = "no" ]; then
- dwarning "Mandos: Dracut not in hostonly mode"
- return 1
- fi
-
- local libdir=`mandos_libdir`
- if [ -z "$libdir" ]; then
- dwarning "Mandos lib directory not found"
- return 1
- fi
-
- local keydir=`mandos_keydir`
- if [ -z "$keydir" ]; then
- dwarning "Mandos key directory not found"
- return 1
- fi
-}
-
-install(){
- chmod go+w,+t "$initdir"/tmp
- local libdir=`mandos_libdir`
- local keydir=`mandos_keydir`
- set `{ getent passwd _mandos \
- || getent passwd nobody \
- || echo ::65534:65534:::; } \
- | cut --delimiter=: --fields=3,4 --only-delimited \
- --output-delimiter=" "`
- local mandos_user="$1"
- local mandos_group="$2"
- inst "${libdir}" /lib/mandos
- if dracut_module_included "systemd"; then
- plugindir=/lib/mandos
- inst "${libdir}/plugins.d/mandos-client" \
- "${plugindir}/mandos-client"
- chmod u-s "${initdir}/${plugindir}/mandos-client"
- inst "${moddir}/ask-password-mandos.service" \
- "${systemdsystemunitdir}/ask-password-mandos.service"
- if [ ${mandos_user} != 65534 ]; then
- sed --in-place \
- --expression="s,^ExecStart=/lib/mandos/password-agent ,&--user=${mandos_user} ," \
- "${initdir}/${systemdsystemunitdir}/ask-password-mandos.service"
- fi
- if [ ${mandos_group} != 65534 ]; then
- sed --in-place \
- --expression="s,^ExecStart=/lib/mandos/password-agent ,&--group=${mandos_group} ," \
- "${initdir}/${systemdsystemunitdir}/ask-password-mandos.service"
- fi
- else
- inst_hook cmdline 20 "$moddir"/cmdline-mandos.sh
- plugindir=/lib/mandos/plugins.d
- inst "${libdir}/plugin-runner" /lib/mandos/plugin-runner
- inst /etc/mandos/plugin-runner.conf
- sed --in-place \
- --expression='1i--options-for=mandos-client:--pubkey=/etc/mandos/keys/pubkey.txt,--seckey=/etc/mandos/keys/seckey.txt,--tls-pubkey=/etc/mandos/keys/tls-pubkey.pem,--tls-privkey=/etc/mandos/keys/tls-privkey.pem' \
- "${initdir}/etc/mandos/plugin-runner.conf"
- if [ ${mandos_user} != 65534 ]; then
- sed --in-place --expression="1i--userid=${mandos_user}" \
- "${initdir}/etc/mandos/plugin-runner.conf"
- fi
- if [ ${mandos_group} != 65534 ]; then
- sed --in-place \
- --expression="1i--groupid=${mandos_group}" \
- "${initdir}/etc/mandos/plugin-runner.conf"
- fi
- inst "${libdir}/plugins.d" "$plugindir"
- chown ${mandos_user}:${mandos_group} "${initdir}/${plugindir}"
- # Copy the packaged plugins
- for file in "$libdir"/plugins.d/*; do
- base="`basename \"$file\"`"
- # Is this plugin overridden?
- if [ -e "/etc/mandos/plugins.d/$base" ]; then
- continue
- fi
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") dwarning "Mandos client plugin directory is empty." >&2 ;;
- askpass-fifo) : ;; # Ignore packaged for dracut
- *) inst "${file}" "${plugindir}/${base}" ;;
- esac
- done
- # Copy any user-supplied plugins
- for file in /etc/mandos/plugins.d/*; do
- base="`basename \"$file\"`"
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *) inst "$file" "${plugindir}/${base}" ;;
- esac
- done
- # Copy any user-supplied plugin helpers
- for file in /etc/mandos/plugin-helpers/*; do
- base="`basename \"$file\"`"
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *) inst "$file" "/lib/mandos/plugin-helpers/$base";;
- esac
- done
- fi
- # Copy network hooks
- for hook in /etc/mandos/network-hooks.d/*; do
- basename=`basename "$hook"`
- case "$basename" in
- "*") continue ;;
- *[!A-Za-z0-9_.-]*) continue ;;
- *) test -d "$hook" || inst "$hook" "/lib/mandos/network-hooks.d/$basename" ;;
- esac
- if [ -x "$hook" ]; then
- # Copy any files needed by the network hook
- MANDOSNETHOOKDIR=/etc/mandos/network-hooks.d MODE=files \
- VERBOSITY=0 "$hook" files | while read file target; do
- if [ ! -e "${file}" ]; then
- dwarning "WARNING: file ${file} not found, requested by Mandos network hook '${basename}'" >&2
- fi
- if [ -z "${target}" ]; then
- inst "$file"
- else
- inst "$file" "$target"
- fi
- done
- fi
- done
- # Copy the packaged plugin helpers
- for file in "$libdir"/plugin-helpers/*; do
- base="`basename \"$file\"`"
- # Is this plugin overridden?
- if [ -e "/etc/mandos/plugin-helpers/$base" ]; then
- continue
- fi
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *) inst "$file" "/lib/mandos/plugin-helpers/$base";;
- esac
- done
- local gpg=/usr/bin/gpg
- if [ -e /usr/bin/gpgconf ]; then
- inst /usr/bin/gpgconf
- gpg="`/usr/bin/gpgconf|sed --quiet --expression='s/^gpg:[^:]*://p'`"
- gpgagent="`/usr/bin/gpgconf|sed --quiet --expression='s/^gpg-agent:[^:]*://p'`"
- # Newer versions of GnuPG 2 requires the gpg-agent binary
- if [ -e "$gpgagent" ]; then
- inst "$gpgagent"
- fi
- fi
- inst "$gpg"
- if dracut_module_included "systemd"; then
- inst "${moddir}/password-agent" /lib/mandos/password-agent
- inst "${moddir}/ask-password-mandos.path" \
- "${systemdsystemunitdir}/ask-password-mandos.path"
- ln_r "${systemdsystemunitdir}/ask-password-mandos.path" \
- "${systemdsystemunitdir}/sysinit.target.wants/ask-password-mandos.path"
- fi
- # Key files
- for file in "$keydir"/*; do
- if [ -d "$file" ]; then
- continue
- fi
- case "$file" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *)
- inst "$file" "/etc/mandos/keys/`basename \"$file\"`"
- chown ${mandos_user}:${mandos_group} \
- "${initdir}/etc/mandos/keys/`basename \"$file\"`"
- if [ `basename "$file"` = dhparams.pem ]; then
- # Use Diffie-Hellman parameters file
- if dracut_module_included "systemd"; then
- sed --in-place \
- --expression='/^ExecStart/s/$/ --dh-params=\/etc\/mandos\/keys\/dhparams.pem/' \
- "${initdir}/${systemdsystemunitdir}/ask-password-mandos.service"
- else
- sed --in-place \
- --expression="1i--options-for=mandos-client:--dh-params=/etc/mandos/keys/dhparams.pem" \
- "${initdir}/etc/mandos/plugin-runner.conf"
- fi
- fi
- ;;
- esac
- done
-}
-
-installkernel(){
- instmods =drivers/net
- hostonly='' instmods ipv6
- # Copy any kernel modules needed by network hooks
- for hook in /etc/mandos/network-hooks.d/*; do
- basename=`basename "$hook"`
- case "$basename" in
- "*") continue ;;
- *[!A-Za-z0-9_.-]*) continue ;;
- esac
- if [ -x "$hook" ]; then
- # Copy and load any modules needed by the network hook
- MANDOSNETHOOKDIR=/etc/mandos/network-hooks.d MODE=modules \
- VERBOSITY=0 "$hook" modules | while read module; do
- if [ -z "${target}" ]; then
- instmods "$module"
- fi
- done
- fi
- done
-}
-
-depends(){
- echo crypt
-}
-
-cmdline(){
- :
-}
=== removed file 'dracut-module/password-agent.c'
--- dracut-module/password-agent.c 2019-10-20 01:48:38 +0000
+++ dracut-module/password-agent.c 1970-01-01 00:00:00 +0000
@@ -1,8112 +0,0 @@
-/* -*- mode: c; coding: utf-8; after-save-hook: (lambda () (let* ((find-build-directory (lambda (try-directory &optional base-directory) (let ((base-directory (or base-directory try-directory))) (cond ((equal try-directory "/") base-directory) ((file-readable-p (concat (file-name-as-directory try-directory) "Makefile")) try-directory) ((funcall find-build-directory (directory-file-name (file-name-directory try-directory)) base-directory)))))) (build-directory (funcall find-build-directory (buffer-file-name))) (local-build-directory (if (fboundp 'file-local-name) (file-local-name build-directory) (or (file-remote-p build-directory 'localname) build-directory))) (command (file-relative-name (file-name-sans-extension (buffer-file-name)) build-directory))) (pcase (progn (if (get-buffer "*Test*") (kill-buffer "*Test*")) (process-file-shell-command (let ((qbdir (shell-quote-argument local-build-directory)) (qcmd (shell-quote-argument command))) (format "cd %s && CFLAGS=-Werror make --silent %s && %s --test --verbose" qbdir qcmd qcmd)) nil "*Test*")) (0 (let ((w (get-buffer-window "*Test*"))) (if w (delete-window w)))) (_ (with-current-buffer "*Test*" (compilation-mode) (cd-absolute build-directory)) (display-buffer "*Test*" '(display-buffer-in-side-window)))))); -*- */
-/*
- * Mandos password agent - Simple password agent to run Mandos client
- *
- * Copyright © 2019 Teddy Hogeborn
- * Copyright © 2019 Björn Påhlsson
- *
- * This file is part of Mandos.
- *
- * Mandos 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.
- *
- * Mandos 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 Mandos. If not, see .
- *
- * Contact the authors at .
- */
-
-#define _GNU_SOURCE
-#include /* uintmax_t, PRIuMAX, PRIdMAX,
- intmax_t, uint32_t, SCNx32,
- SCNuMAX, SCNxMAX */
-#include /* size_t */
-#include /* pid_t, uid_t, gid_t, getuid(),
- getpid() */
-#include /* bool, true, false */
-#include /* struct sigaction, sigset_t,
- sigemptyset(), sigaddset(),
- SIGCHLD, pthread_sigmask(),
- SIG_BLOCK, SIG_SETMASK, SA_RESTART,
- SA_NOCLDSTOP, sigfillset(), kill(),
- SIGTERM, sigdelset(), SIGKILL,
- NSIG, sigismember(), SA_ONSTACK,
- SIG_DFL, SIG_IGN, SIGINT, SIGQUIT,
- SIGHUP, SIGSTOP, SIG_UNBLOCK */
-#include /* EXIT_SUCCESS, EXIT_FAILURE,
- malloc(), free(), strtoumax(),
- realloc(), setenv(), calloc(),
- mkdtemp(), mkostemp() */
-#include /* not, or, and, xor */
-#include /* error() */
-#include /* EX_USAGE, EX_OSERR, EX_OSFILE */
-#include /* errno, error_t, EACCES,
- ENAMETOOLONG, ENOENT, ENOTDIR,
- EEXIST, ECHILD, EPERM, ENOMEM,
- EAGAIN, EINTR, ENOBUFS, EADDRINUSE,
- ECONNREFUSED, ECONNRESET,
- ETOOMANYREFS, EMSGSIZE, EBADF,
- EINVAL */
-#include /* strdup(), memcpy(),
- explicit_bzero(), memset(),
- strcmp(), strlen(), strncpy(),
- memcmp(), basename() */
-#include /* argz_create(), argz_count(),
- argz_extract(), argz_next(),
- argz_add() */
-#include /* epoll_create1(), EPOLL_CLOEXEC,
- epoll_ctl(), EPOLL_CTL_ADD,
- struct epoll_event, EPOLLIN,
- EPOLLRDHUP, EPOLLOUT,
- epoll_pwait() */
-#include /* struct timespec, clock_gettime(),
- CLOCK_MONOTONIC */
-#include /* struct argp_option, OPTION_HIDDEN,
- OPTION_ALIAS, struct argp_state,
- ARGP_ERR_UNKNOWN, ARGP_KEY_ARGS,
- struct argp, argp_parse(),
- ARGP_NO_EXIT */
-#include /* uid_t, gid_t, close(), pipe2(),
- fork(), _exit(), dup2(),
- STDOUT_FILENO, setresgid(),
- setresuid(), execv(), ssize_t,
- read(), dup3(), getuid(), dup(),
- STDERR_FILENO, pause(), write(),
- rmdir(), unlink(), getpid() */
-#include /* munlock(), mlock() */
-#include /* O_CLOEXEC, O_NONBLOCK, fcntl(),
- F_GETFD, F_GETFL, FD_CLOEXEC,
- open(), O_WRONLY, O_NOCTTY,
- O_RDONLY, O_NOFOLLOW */
-#include /* waitpid(), WNOHANG, WIFEXITED(),
- WEXITSTATUS() */
-#include /* PIPE_BUF, NAME_MAX, INT_MAX */
-#include /* inotify_init1(), IN_NONBLOCK,
- IN_CLOEXEC, inotify_add_watch(),
- IN_CLOSE_WRITE, IN_MOVED_TO,
- IN_MOVED_FROM, IN_DELETE,
- IN_EXCL_UNLINK, IN_ONLYDIR,
- struct inotify_event */
-#include /* fnmatch(), FNM_FILE_NAME */
-#include /* asprintf(), FILE, fopen(),
- getline(), sscanf(), feof(),
- ferror(), fclose(), stderr,
- rename(), fdopen(), fprintf(),
- fscanf() */
-#include /* GKeyFile, g_key_file_free(), g_key_file_new(),
- GError, g_key_file_load_from_file(),
- G_KEY_FILE_NONE, TRUE, G_FILE_ERROR_NOENT,
- g_key_file_get_string(), guint64,
- g_key_file_get_uint64(),
- G_KEY_FILE_ERROR_KEY_NOT_FOUND, gconstpointer,
- g_assert_true(), g_assert_nonnull(),
- g_assert_null(), g_assert_false(),
- g_assert_cmpint(), g_assert_cmpuint(),
- g_test_skip(), g_assert_cmpstr(),
- g_test_init(), g_test_add(), g_test_run(),
- GOptionContext, g_option_context_new(),
- g_option_context_set_help_enabled(), FALSE,
- g_option_context_set_ignore_unknown_options(),
- gboolean, GOptionEntry, G_OPTION_ARG_NONE,
- g_option_context_add_main_entries(),
- g_option_context_parse(),
- g_option_context_free(), g_error() */
-#include /* struct sockaddr_un, SUN_LEN */
-#include /* AF_LOCAL, socket(), PF_LOCAL,
- SOCK_DGRAM, SOCK_NONBLOCK,
- SOCK_CLOEXEC, connect(),
- struct sockaddr, socklen_t,
- shutdown(), SHUT_RD, send(),
- MSG_NOSIGNAL, bind(), recv(),
- socketpair() */
-#include /* globfree(), glob_t, glob(),
- GLOB_ERR, GLOB_NOSORT, GLOB_MARK,
- GLOB_ABORTED, GLOB_NOMATCH,
- GLOB_NOSPACE */
-
-/* End of includes */
-
-/* Start of declarations of private types and functions */
-
-/* microseconds of CLOCK_MONOTONIC absolute time; 0 means unset */
-typedef uintmax_t mono_microsecs;
-
-/* "task_queue" - A queue of tasks to be run */
-typedef struct {
- struct task_struct *tasks; /* Tasks in this queue */
- size_t length; /* Number of tasks */
- /* Memory allocated for "tasks", in bytes */
- size_t allocated;
- /* Time when this queue should be run, at the latest */
- mono_microsecs next_run;
-} __attribute__((designated_init)) task_queue;
-
-/* "task_func" - A function type for task functions
-
- I.e. functions for the code which runs when a task is run, all have
- this type */
-typedef void (task_func) (const struct task_struct,
- task_queue *const)
- __attribute__((nonnull));
-
-/* "buffer" - A data buffer for a growing array of bytes
-
- Used for the "password" variable */
-typedef struct {
- char *data;
- size_t length;
- size_t allocated;
-} __attribute__((designated_init)) buffer;
-
-/* "string_set" - A set type which can contain strings
-
- Used by the "cancelled_filenames" variable */
-typedef struct {
- char *argz; /* Do not access these except in */
- size_t argz_len; /* the string_set_* functions */
-} __attribute__((designated_init)) string_set;
-
-/* "task_context" - local variables for tasks
-
- This data structure distinguishes between different tasks which are
- using the same function. This data structure is passed to every
- task function when each task is run.
-
- Note that not every task uses every struct member. */
-typedef struct task_struct {
- task_func *const func; /* The function run by this task */
- char *const question_filename; /* The question file */
- const pid_t pid; /* Mandos client process ID */
- const int epoll_fd; /* The epoll set file descriptor */
- bool *const quit_now; /* Set to true on fatal errors */
- const int fd; /* General purpose file descriptor */
- bool *const mandos_client_exited; /* Set true when client exits */
- buffer *const password; /* As read from client process */
- bool *const password_is_read; /* "password" is done growing */
- char *filename; /* General purpose file name */
- /* A set of strings of all the file names of questions which have
- been cancelled for any reason; tasks pertaining to these question
- files should not be run */
- string_set *const cancelled_filenames;
- const mono_microsecs notafter; /* "NotAfter" from question file */
- /* Updated before each queue run; is compared with queue.next_run */
- const mono_microsecs *const current_time;
-} __attribute__((designated_init)) task_context;
-
-/* Declare all our functions here so we can define them in any order
- below. Note: test functions are *not* declared here, they are
- declared in the test section. */
-__attribute__((warn_unused_result))
-static bool should_only_run_tests(int *, char **[]);
-__attribute__((warn_unused_result, cold))
-static bool run_tests(int, char *[]);
-static void handle_sigchld(__attribute__((unused)) int sig){}
-__attribute__((warn_unused_result, malloc))
-task_queue *create_queue(void);
-__attribute__((nonnull, warn_unused_result))
-bool add_to_queue(task_queue *const, const task_context);
-__attribute__((nonnull))
-void cleanup_task(const task_context *const);
-__attribute__((nonnull))
-void cleanup_queue(task_queue *const *const);
-__attribute__((pure, nonnull, warn_unused_result))
-bool queue_has_question(const task_queue *const);
-__attribute__((nonnull))
-void cleanup_close(const int *const);
-__attribute__((nonnull))
-void cleanup_string(char *const *const);
-__attribute__((nonnull))
-void cleanup_buffer(buffer *const);
-__attribute__((pure, nonnull, warn_unused_result))
-bool string_set_contains(const string_set, const char *const);
-__attribute__((nonnull, warn_unused_result))
-bool string_set_add(string_set *const, const char *const);
-__attribute__((nonnull))
-void string_set_clear(string_set *);
-void string_set_swap(string_set *const, string_set *const);
-__attribute__((nonnull, warn_unused_result))
-bool start_mandos_client(task_queue *const, const int, bool *const,
- bool *const, buffer *const, bool *const,
- const struct sigaction *const,
- const sigset_t, const char *const,
- const uid_t, const gid_t,
- const char *const *const);
-__attribute__((nonnull))
-task_func wait_for_mandos_client_exit;
-__attribute__((nonnull))
-task_func read_mandos_client_output;
-__attribute__((warn_unused_result))
-bool add_inotify_dir_watch(task_queue *const, const int, bool *const,
- buffer *const, const char *const,
- string_set *, const mono_microsecs *const,
- bool *const, bool *const);
-__attribute__((nonnull))
-task_func read_inotify_event;
-__attribute__((nonnull))
-task_func open_and_parse_question;
-__attribute__((nonnull))
-task_func cancel_old_question;
-__attribute__((nonnull))
-task_func connect_question_socket;
-__attribute__((nonnull))
-task_func send_password_to_socket;
-__attribute__((warn_unused_result))
-bool add_existing_questions(task_queue *const, const int,
- buffer *const, string_set *,
- const mono_microsecs *const,
- bool *const, bool *const,
- const char *const);
-__attribute__((nonnull, warn_unused_result))
-bool wait_for_event(const int, const mono_microsecs,
- const mono_microsecs);
-bool run_queue(task_queue **const, string_set *const, bool *const);
-bool clear_all_fds_from_epoll_set(const int);
-mono_microsecs get_current_time(void);
-__attribute__((nonnull, warn_unused_result))
-bool setup_signal_handler(struct sigaction *const);
-__attribute__((nonnull))
-bool restore_signal_handler(const struct sigaction *const);
-__attribute__((nonnull, warn_unused_result))
-bool block_sigchld(sigset_t *const);
-__attribute__((nonnull))
-bool restore_sigmask(const sigset_t *const);
-__attribute__((nonnull))
-bool parse_arguments(int, char *[], const bool, char **, char **,
- uid_t *const , gid_t *const, char **, size_t *);
-
-/* End of declarations of private types and functions */
-
-/* Start of "main" section; this section LACKS TESTS!
-
- Code here should be as simple as possible. */
-
-/* These are required to be global by Argp */
-const char *argp_program_version = "password-agent " VERSION;
-const char *argp_program_bug_address = "";
-
-int main(int argc, char *argv[]){
-
- /* If the --test option is passed, skip all normal operations and
- instead only run the run_tests() function, which also does all
- its own option parsing, so we don't have to do anything here. */
- if(should_only_run_tests(&argc, &argv)){
- if(run_tests(argc, argv)){
- return EXIT_SUCCESS; /* All tests successful */
- }
- return EXIT_FAILURE; /* Some test(s) failed */
- }
-
- __attribute__((cleanup(cleanup_string)))
- char *agent_directory = NULL;
-
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
-
- uid_t user = 0;
- gid_t group = 0;
-
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- if(not parse_arguments(argc, argv, true, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length)){
- /* This should never happen, since "true" is passed as the third
- argument to parse_arguments() above, which should make
- argp_parse() call exit() if any parsing error occurs. */
- error(EX_USAGE, errno, "Failed to parse arguments");
- }
-
- const char default_agent_directory[] = "/run/systemd/ask-password";
- const char default_helper_directory[]
- = "/lib/mandos/plugin-helpers";
- const char *const default_argv[]
- = {"/lib/mandos/plugins.d/mandos-client", NULL };
-
- /* Set variables to default values if unset */
- if(agent_directory == NULL){
- agent_directory = strdup(default_agent_directory);
- if(agent_directory == NULL){
- error(EX_OSERR, errno, "Failed strdup()");
- }
- }
- if(helper_directory == NULL){
- helper_directory = strdup(default_helper_directory);
- if(helper_directory == NULL){
- error(EX_OSERR, errno, "Failed strdup()");
- }
- }
- if(user == 0){
- user = 65534; /* nobody */
- }
- if(group == 0){
- group = 65534; /* nogroup */
- }
- /* If parse_opt did not create an argz vector, create one with
- default values */
- if(mandos_argz == NULL){
-#ifdef __GNUC__
-#pragma GCC diagnostic push
- /* argz_create() takes a non-const argv for some unknown reason -
- argz_create() isn't modifying the strings, just copying them.
- Therefore, this cast to non-const should be safe. */
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#endif
- errno = argz_create((char *const *)default_argv, &mandos_argz,
- &mandos_argz_length);
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
- if(errno != 0){
- error(EX_OSERR, errno, "Failed argz_create()");
- }
- }
- /* Use argz vector to create a normal argv, usable by execv() */
-
- char **mandos_argv = malloc((argz_count(mandos_argz,
- mandos_argz_length)
- + 1) * sizeof(char *));
- if(mandos_argv == NULL){
- error_t saved_errno = errno;
- free(mandos_argz);
- error(EX_OSERR, saved_errno, "Failed malloc()");
- }
- argz_extract(mandos_argz, mandos_argz_length, mandos_argv);
-
- sigset_t orig_sigmask;
- if(not block_sigchld(&orig_sigmask)){
- return EX_OSERR;
- }
-
- struct sigaction old_sigchld_action;
- if(not setup_signal_handler(&old_sigchld_action)){
- return EX_OSERR;
- }
-
- mono_microsecs current_time = 0;
-
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- if(epoll_fd < 0){
- error(EX_OSERR, errno, "Failed to create epoll set fd");
- }
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- if(queue == NULL){
- error(EX_OSERR, errno, "Failed to create task queue");
- }
-
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- bool password_is_read = false;
-
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
-
- /* Add tasks to queue */
- if(not start_mandos_client(queue, epoll_fd, &mandos_client_exited,
- &quit_now, &password, &password_is_read,
- &old_sigchld_action, orig_sigmask,
- helper_directory, user, group,
- (const char *const *)mandos_argv)){
- return EX_OSERR; /* Error has already been printed */
- }
- /* These variables were only for start_mandos_client() and are not
- needed anymore */
- free(mandos_argv);
- free(mandos_argz);
- mandos_argz = NULL;
- if(not add_inotify_dir_watch(queue, epoll_fd, &quit_now, &password,
- agent_directory, &cancelled_filenames,
- ¤t_time, &mandos_client_exited,
- &password_is_read)){
- switch(errno){ /* Error has already been printed */
- case EACCES:
- case ENAMETOOLONG:
- case ENOENT:
- case ENOTDIR:
- return EX_OSFILE;
- default:
- return EX_OSERR;
- }
- }
- if(not add_existing_questions(queue, epoll_fd, &password,
- &cancelled_filenames, ¤t_time,
- &mandos_client_exited,
- &password_is_read, agent_directory)){
- return EXIT_FAILURE; /* Error has already been printed */
- }
-
- /* Run queue */
- do {
- current_time = get_current_time();
- if(not wait_for_event(epoll_fd, queue->next_run, current_time)){
- const error_t saved_errno = errno;
- error(EXIT_FAILURE, saved_errno, "Failure while waiting for"
- " events");
- }
-
- current_time = get_current_time();
- if(not run_queue(&queue, &cancelled_filenames, &quit_now)){
- const error_t saved_errno = errno;
- error(EXIT_FAILURE, saved_errno, "Failure while running queue");
- }
-
- /* When no tasks about questions are left in the queue, break out
- of the loop (and implicitly exit the program) */
- } while(queue_has_question(queue));
-
- restore_signal_handler(&old_sigchld_action);
- restore_sigmask(&orig_sigmask);
-
- return EXIT_SUCCESS;
-}
-
-__attribute__((warn_unused_result))
-mono_microsecs get_current_time(void){
- struct timespec currtime;
- if(clock_gettime(CLOCK_MONOTONIC, &currtime) != 0){
- error(0, errno, "Failed to get current time");
- return 0;
- }
- return ((mono_microsecs)currtime.tv_sec * 1000000) /* seconds */
- + ((mono_microsecs)currtime.tv_nsec / 1000); /* nanoseconds */
-}
-
-/* End of "main" section */
-
-/* Start of regular code section; ALL this code has tests */
-
-__attribute__((nonnull))
-bool parse_arguments(int argc, char *argv[], const bool exit_failure,
- char **agent_directory, char **helper_directory,
- uid_t *const user, gid_t *const group,
- char **mandos_argz, size_t *mandos_argz_length){
-
- const struct argp_option options[] = {
- { .name="agent-directory",.key='d', .arg="DIRECTORY",
- .doc="Systemd password agent directory" },
- { .name="helper-directory",.key=128, .arg="DIRECTORY",
- .doc="Mandos Client password helper directory" },
- { .name="plugin-helper-dir", .key=129, /* From plugin-runner */
- .flags=OPTION_HIDDEN | OPTION_ALIAS },
- { .name="user", .key='u', .arg="USERID",
- .doc="User ID the Mandos Client will use as its unprivileged"
- " user" },
- { .name="userid", .key=130, /* From plugin--runner */
- .flags=OPTION_HIDDEN | OPTION_ALIAS },
- { .name="group", .key='g', .arg="GROUPID",
- .doc="Group ID the Mandos Client will use as its unprivileged"
- " group" },
- { .name="groupid", .key=131, /* From plugin--runner */
- .flags=OPTION_HIDDEN | OPTION_ALIAS },
- { .name="test", .key=255, /* See should_only_run_tests() */
- .doc="Skip normal operation, and only run self-tests. See"
- " --test --help.", .group=10, },
- { NULL },
- };
-
- __attribute__((nonnull(3)))
- error_t parse_opt(int key, char *arg, struct argp_state *state){
- errno = 0;
- switch(key){
- case 'd': /* --agent-directory */
- *agent_directory = strdup(arg);
- break;
- case 128: /* --helper-directory */
- case 129: /* --plugin-helper-dir */
- *helper_directory = strdup(arg);
- break;
- case 'u': /* --user */
- case 130: /* --userid */
- {
- char *tmp;
- uintmax_t tmp_id = 0;
- errno = 0;
- tmp_id = (uid_t)strtoumax(arg, &tmp, 10);
- if(errno != 0 or tmp == arg or *tmp != '\0'
- or tmp_id != (uid_t)tmp_id or (uid_t)tmp_id == 0){
- return ARGP_ERR_UNKNOWN;
- }
- *user = (uid_t)tmp_id;
- errno = 0;
- break;
- }
- case 'g': /* --group */
- case 131: /* --groupid */
- {
- char *tmp;
- uintmax_t tmp_id = 0;
- errno = 0;
- tmp_id = (uid_t)strtoumax(arg, &tmp, 10);
- if(errno != 0 or tmp == arg or *tmp != '\0'
- or tmp_id != (gid_t)tmp_id or (gid_t)tmp_id == 0){
- return ARGP_ERR_UNKNOWN;
- }
- *group = (gid_t)tmp_id;
- errno = 0;
- break;
- }
- case ARGP_KEY_ARGS:
- /* Copy arguments into argz vector */
- return argz_create(state->argv + state->next, mandos_argz,
- mandos_argz_length);
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return errno;
- }
-
- const struct argp argp = {
- .options=options,
- .parser=parse_opt,
- .args_doc="[MANDOS_CLIENT [OPTION...]]\n--test",
- .doc = "Mandos password agent -- runs Mandos client as a"
- " systemd password agent",
- };
-
- errno = argp_parse(&argp, argc, argv,
- exit_failure ? 0 : ARGP_NO_EXIT, NULL, NULL);
-
- return errno == 0;
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool block_sigchld(sigset_t *const orig_sigmask){
- sigset_t sigchld_sigmask;
- if(sigemptyset(&sigchld_sigmask) < 0){
- error(0, errno, "Failed to empty signal set");
- return false;
- }
- if(sigaddset(&sigchld_sigmask, SIGCHLD) < 0){
- error(0, errno, "Failed to add SIGCHLD to signal set");
- return false;
- }
- if(pthread_sigmask(SIG_BLOCK, &sigchld_sigmask, orig_sigmask) != 0){
- error(0, errno, "Failed to block SIGCHLD signal");
- return false;
- }
- return true;
-}
-
-__attribute__((nonnull, warn_unused_result, const))
-bool restore_sigmask(const sigset_t *const orig_sigmask){
- if(pthread_sigmask(SIG_SETMASK, orig_sigmask, NULL) != 0){
- error(0, errno, "Failed to restore blocked signals");
- return false;
- }
- return true;
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool setup_signal_handler(struct sigaction *const old_sigchld_action){
- struct sigaction sigchld_action = {
- .sa_handler=handle_sigchld,
- .sa_flags=SA_RESTART | SA_NOCLDSTOP,
- };
- /* Set all signals in "sa_mask" struct member; this makes all
- signals automatically blocked during signal handler */
- if(sigfillset(&sigchld_action.sa_mask) != 0){
- error(0, errno, "Failed to do sigfillset()");
- return false;
- }
- if(sigaction(SIGCHLD, &sigchld_action, old_sigchld_action) != 0){
- error(0, errno, "Failed to set SIGCHLD signal handler");
- return false;
- }
- return true;
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool restore_signal_handler(const struct sigaction *const
- old_sigchld_action){
- if(sigaction(SIGCHLD, old_sigchld_action, NULL) != 0){
- error(0, errno, "Failed to restore signal handler");
- return false;
- }
- return true;
-}
-
-__attribute__((warn_unused_result, malloc))
-task_queue *create_queue(void){
- task_queue *queue = malloc(sizeof(task_queue));
- if(queue){
- queue->tasks = NULL;
- queue->length = 0;
- queue->allocated = 0;
- queue->next_run = 0;
- }
- return queue;
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool add_to_queue(task_queue *const queue, const task_context task){
- const size_t needed_size = sizeof(task_context)*(queue->length + 1);
- if(needed_size > (queue->allocated)){
- task_context *const new_tasks = realloc(queue->tasks,
- needed_size);
- if(new_tasks == NULL){
- error(0, errno, "Failed to allocate %" PRIuMAX
- " bytes for queue->tasks", (uintmax_t)needed_size);
- return false;
- }
- queue->tasks = new_tasks;
- queue->allocated = needed_size;
- }
- /* Using memcpy here is necessary because doing */
- /* queue->tasks[queue->length++] = task; */
- /* would violate const-ness of task members */
- memcpy(&(queue->tasks[queue->length++]), &task,
- sizeof(task_context));
- return true;
-}
-
-__attribute__((nonnull))
-void cleanup_task(const task_context *const task){
- const error_t saved_errno = errno;
- /* free and close all task data */
- free(task->question_filename);
- if(task->filename != task->question_filename){
- free(task->filename);
- }
- if(task->pid > 0){
- kill(task->pid, SIGTERM);
- }
- if(task->fd > 0){
- close(task->fd);
- }
- errno = saved_errno;
-}
-
-__attribute__((nonnull))
-void free_queue(task_queue *const queue){
- free(queue->tasks);
- free(queue);
-}
-
-__attribute__((nonnull))
-void cleanup_queue(task_queue *const *const queue){
- if(*queue == NULL){
- return;
- }
- for(size_t i = 0; i < (*queue)->length; i++){
- const task_context *const task = ((*queue)->tasks)+i;
- cleanup_task(task);
- }
- free_queue(*queue);
-}
-
-__attribute__((pure, nonnull, warn_unused_result))
-bool queue_has_question(const task_queue *const queue){
- for(size_t i=0; i < queue->length; i++){
- if(queue->tasks[i].question_filename != NULL){
- return true;
- }
- }
- return false;
-}
-
-__attribute__((nonnull))
-void cleanup_close(const int *const fd){
- const error_t saved_errno = errno;
- close(*fd);
- errno = saved_errno;
-}
-
-__attribute__((nonnull))
-void cleanup_string(char *const *const ptr){
- free(*ptr);
-}
-
-__attribute__((nonnull))
-void cleanup_buffer(buffer *buf){
- if(buf->allocated > 0){
-#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 25)
- explicit_bzero(buf->data, buf->allocated);
-#else
- memset(buf->data, '\0', buf->allocated);
-#endif
- }
- if(buf->data != NULL){
- if(munlock(buf->data, buf->allocated) != 0){
- error(0, errno, "Failed to unlock memory of old buffer");
- }
- free(buf->data);
- buf->data = NULL;
- }
- buf->length = 0;
- buf->allocated = 0;
-}
-
-__attribute__((pure, nonnull, warn_unused_result))
-bool string_set_contains(const string_set set, const char *const str){
- for(const char *s = set.argz; s != NULL and set.argz_len > 0;
- s = argz_next(set.argz, set.argz_len, s)){
- if(strcmp(s, str) == 0){
- return true;
- }
- }
- return false;
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool string_set_add(string_set *const set, const char *const str){
- if(string_set_contains(*set, str)){
- return true;
- }
- error_t error = argz_add(&set->argz, &set->argz_len, str);
- if(error == 0){
- return true;
- }
- errno = error;
- return false;
-}
-
-__attribute__((nonnull))
-void string_set_clear(string_set *set){
- free(set->argz);
- set->argz = NULL;
- set->argz_len = 0;
-}
-
-__attribute__((nonnull))
-void string_set_swap(string_set *const set1, string_set *const set2){
- /* Swap contents of two string sets */
- {
- char *const tmp_argz = set1->argz;
- set1->argz = set2->argz;
- set2->argz = tmp_argz;
- }
- {
- const size_t tmp_argz_len = set1->argz_len;
- set1->argz_len = set2->argz_len;
- set2->argz_len = tmp_argz_len;
- }
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool start_mandos_client(task_queue *const queue,
- const int epoll_fd,
- bool *const mandos_client_exited,
- bool *const quit_now, buffer *const password,
- bool *const password_is_read,
- const struct sigaction *const
- old_sigchld_action, const sigset_t sigmask,
- const char *const helper_directory,
- const uid_t user, const gid_t group,
- const char *const *const argv){
- int pipefds[2];
- if(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK) != 0){
- error(0, errno, "Failed to pipe2(..., O_CLOEXEC | O_NONBLOCK)");
- return false;
- }
-
- const pid_t pid = fork();
- if(pid == 0){
- if(not restore_signal_handler(old_sigchld_action)){
- _exit(EXIT_FAILURE);
- }
- if(not restore_sigmask(&sigmask)){
- _exit(EXIT_FAILURE);
- }
- if(close(pipefds[0]) != 0){
- error(0, errno, "Failed to close() parent pipe fd");
- _exit(EXIT_FAILURE);
- }
- if(dup2(pipefds[1], STDOUT_FILENO) == -1){
- error(0, errno, "Failed to dup2() pipe fd to stdout");
- _exit(EXIT_FAILURE);
- }
- if(close(pipefds[1]) != 0){
- error(0, errno, "Failed to close() old child pipe fd");
- _exit(EXIT_FAILURE);
- }
- if(setenv("MANDOSPLUGINHELPERDIR", helper_directory, 1) != 0){
- error(0, errno, "Failed to setenv(\"MANDOSPLUGINHELPERDIR\","
- " \"%s\", 1)", helper_directory);
- _exit(EXIT_FAILURE);
- }
- if(group != 0 and setresgid(group, 0, 0) == -1){
- error(0, errno, "Failed to setresgid(-1, %" PRIuMAX ", %"
- PRIuMAX")", (uintmax_t)group, (uintmax_t)group);
- _exit(EXIT_FAILURE);
- }
- if(user != 0 and setresuid(user, 0, 0) == -1){
- error(0, errno, "Failed to setresuid(-1, %" PRIuMAX ", %"
- PRIuMAX")", (uintmax_t)user, (uintmax_t)user);
- _exit(EXIT_FAILURE);
- }
-#ifdef __GNUC__
-#pragma GCC diagnostic push
- /* For historical reasons, the "argv" argument to execv() is not
- const, but it is safe to override this. */
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#endif
- execv(argv[0], (char **)argv);
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
- error(0, errno, "execv(\"%s\", ...) failed", argv[0]);
- _exit(EXIT_FAILURE);
- }
- close(pipefds[1]);
-
- if(not add_to_queue(queue, (task_context){
- .func=wait_for_mandos_client_exit,
- .pid=pid,
- .mandos_client_exited=mandos_client_exited,
- .quit_now=quit_now,
- })){
- error(0, errno, "Failed to add wait_for_mandos_client to queue");
- close(pipefds[0]);
- return false;
- }
-
- const int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipefds[0],
- &(struct epoll_event)
- { .events=EPOLLIN | EPOLLRDHUP });
- if(ret != 0 and errno != EEXIST){
- error(0, errno, "Failed to add file descriptor to epoll set");
- close(pipefds[0]);
- return false;
- }
-
- return add_to_queue(queue, (task_context){
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=quit_now,
- .password=password,
- .password_is_read=password_is_read,
- });
-}
-
-__attribute__((nonnull))
-void wait_for_mandos_client_exit(const task_context task,
- task_queue *const queue){
- const pid_t pid = task.pid;
- bool *const mandos_client_exited = task.mandos_client_exited;
- bool *const quit_now = task.quit_now;
-
- int status;
- switch(waitpid(pid, &status, WNOHANG)){
- case 0: /* Not exited yet */
- if(not add_to_queue(queue, task)){
- error(0, errno, "Failed to add myself to queue");
- *quit_now = true;
- }
- break;
- case -1: /* Error */
- error(0, errno, "waitpid(%" PRIdMAX ") failed", (intmax_t)pid);
- if(errno != ECHILD){
- kill(pid, SIGTERM);
- }
- *quit_now = true;
- break;
- default: /* Has exited */
- *mandos_client_exited = true;
- if((not WIFEXITED(status))
- or (WEXITSTATUS(status) != EXIT_SUCCESS)){
- error(0, 0, "Mandos client failed or was killed");
- *quit_now = true;
- }
- }
-}
-
-__attribute__((nonnull))
-void read_mandos_client_output(const task_context task,
- task_queue *const queue){
- buffer *const password = task.password;
- bool *const quit_now = task.quit_now;
- bool *const password_is_read = task.password_is_read;
- const int fd = task.fd;
- const int epoll_fd = task.epoll_fd;
-
- const size_t new_potential_size = (password->length + PIPE_BUF);
- if(password->allocated < new_potential_size){
- char *const new_buffer = calloc(new_potential_size, 1);
- if(new_buffer == NULL){
- error(0, errno, "Failed to allocate %" PRIuMAX
- " bytes for password", (uintmax_t)new_potential_size);
- *quit_now = true;
- close(fd);
- return;
- }
- if(mlock(new_buffer, new_potential_size) != 0){
- /* Warn but do not treat as fatal error */
- if(errno != EPERM and errno != ENOMEM){
- error(0, errno, "Failed to lock memory for password");
- }
- }
- if(password->length > 0){
- memcpy(new_buffer, password->data, password->length);
-#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 25)
- explicit_bzero(password->data, password->allocated);
-#else
- memset(password->data, '\0', password->allocated);
-#endif
- }
- if(password->data != NULL){
- if(munlock(password->data, password->allocated) != 0){
- error(0, errno, "Failed to unlock memory of old buffer");
- }
- free(password->data);
- }
- password->data = new_buffer;
- password->allocated = new_potential_size;
- }
-
- const ssize_t read_length = read(fd, password->data
- + password->length, PIPE_BUF);
-
- if(read_length == 0){ /* EOF */
- *password_is_read = true;
- close(fd);
- return;
- }
- if(read_length < 0 and errno != EAGAIN){ /* Actual error */
- error(0, errno, "Failed to read password from Mandos client");
- *quit_now = true;
- close(fd);
- return;
- }
- if(read_length > 0){ /* Data has been read */
- password->length += (size_t)read_length;
- }
-
- /* Either data was read, or EAGAIN was indicated, meaning no data
- available yet */
-
- /* Re-add the fd to the epoll set */
- const int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd,
- &(struct epoll_event)
- { .events=EPOLLIN | EPOLLRDHUP });
- if(ret != 0 and errno != EEXIST){
- error(0, errno, "Failed to re-add file descriptor to epoll set");
- *quit_now = true;
- close(fd);
- return;
- }
-
- /* Re-add myself to the queue */
- if(not add_to_queue(queue, task)){
- error(0, errno, "Failed to add myself to queue");
- *quit_now = true;
- close(fd);
- }
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool add_inotify_dir_watch(task_queue *const queue,
- const int epoll_fd, bool *const quit_now,
- buffer *const password,
- const char *const dir,
- string_set *cancelled_filenames,
- const mono_microsecs *const current_time,
- bool *const mandos_client_exited,
- bool *const password_is_read){
- const int fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
- if(fd == -1){
- error(0, errno, "Failed to create inotify instance");
- return false;
- }
-
- if(inotify_add_watch(fd, dir, IN_CLOSE_WRITE | IN_MOVED_TO
- | IN_MOVED_FROM| IN_DELETE | IN_EXCL_UNLINK
- | IN_ONLYDIR)
- == -1){
- error(0, errno, "Failed to create inotify watch on %s", dir);
- return false;
- }
-
- /* Add the inotify fd to the epoll set */
- const int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd,
- &(struct epoll_event)
- { .events=EPOLLIN | EPOLLRDHUP });
- if(ret != 0 and errno != EEXIST){
- error(0, errno, "Failed to add file descriptor to epoll set");
- close(fd);
- return false;
- }
-
- const task_context read_inotify_event_task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .quit_now=quit_now,
- .password=password,
- .fd=fd,
- .filename=strdup(dir),
- .cancelled_filenames=cancelled_filenames,
- .current_time=current_time,
- .mandos_client_exited=mandos_client_exited,
- .password_is_read=password_is_read,
- };
- if(read_inotify_event_task.filename == NULL){
- error(0, errno, "Failed to strdup(\"%s\")", dir);
- close(fd);
- return false;
- }
-
- return add_to_queue(queue, read_inotify_event_task);
-}
-
-__attribute__((nonnull))
-void read_inotify_event(const task_context task,
- task_queue *const queue){
- const int fd = task.fd;
- const int epoll_fd = task.epoll_fd;
- char *const filename = task.filename;
- bool *quit_now = task.quit_now;
- buffer *const password = task.password;
- string_set *const cancelled_filenames = task.cancelled_filenames;
- const mono_microsecs *const current_time = task.current_time;
- bool *const mandos_client_exited = task.mandos_client_exited;
- bool *const password_is_read = task.password_is_read;
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const ssize_t read_length = read(fd, ievent, ievent_size);
- if(read_length == 0){ /* EOF */
- error(0, 0, "Got EOF from inotify fd for directory %s", filename);
- *quit_now = true;
- cleanup_task(&task);
- return;
- }
- if(read_length < 0 and errno != EAGAIN){ /* Actual error */
- error(0, errno, "Failed to read from inotify fd for directory %s",
- filename);
- *quit_now = true;
- cleanup_task(&task);
- return;
- }
- if(read_length > 0 /* Data has been read */
- and fnmatch("ask.*", ievent->name, FNM_FILE_NAME) == 0){
- char *question_filename = NULL;
- const ssize_t question_filename_length
- = asprintf(&question_filename, "%s/%s", filename, ievent->name);
- if(question_filename_length < 0){
- error(0, errno, "Failed to create file name from directory name"
- " %s and file name %s", filename, ievent->name);
- } else {
- if(ievent->mask & (IN_CLOSE_WRITE | IN_MOVED_TO)){
- if(not add_to_queue(queue, (task_context){
- .func=open_and_parse_question,
- .epoll_fd=epoll_fd,
- .question_filename=question_filename,
- .filename=question_filename,
- .password=password,
- .cancelled_filenames=cancelled_filenames,
- .current_time=current_time,
- .mandos_client_exited=mandos_client_exited,
- .password_is_read=password_is_read,
- })){
- error(0, errno, "Failed to add open_and_parse_question task"
- " for file name %s to queue", filename);
- } else {
- /* Force the added task (open_and_parse_question) to run
- immediately */
- queue->next_run = 1;
- }
- } else if(ievent->mask & (IN_MOVED_FROM | IN_DELETE)){
- if(not string_set_add(cancelled_filenames,
- question_filename)){
- error(0, errno, "Could not add question %s to"
- " cancelled_questions", question_filename);
- *quit_now = true;
- free(question_filename);
- cleanup_task(&task);
- return;
- }
- free(question_filename);
- }
- }
- }
-
- /* Either data was read, or EAGAIN was indicated, meaning no data
- available yet */
-
- /* Re-add myself to the queue */
- if(not add_to_queue(queue, task)){
- error(0, errno, "Failed to re-add read_inotify_event(%s) to"
- " queue", filename);
- *quit_now = true;
- cleanup_task(&task);
- return;
- }
-
- /* Re-add the fd to the epoll set */
- const int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd,
- &(struct epoll_event)
- { .events=EPOLLIN | EPOLLRDHUP });
- if(ret != 0 and errno != EEXIST){
- error(0, errno, "Failed to re-add inotify file descriptor %d for"
- " directory %s to epoll set", fd, filename);
- /* Force the added task (read_inotify_event) to run again, at most
- one second from now */
- if((queue->next_run == 0)
- or (queue->next_run > (*current_time + 1000000))){
- queue->next_run = *current_time + 1000000;
- }
- }
-}
-
-__attribute__((nonnull))
-void open_and_parse_question(const task_context task,
- task_queue *const queue){
- __attribute__((cleanup(cleanup_string)))
- char *question_filename = task.question_filename;
- const int epoll_fd = task.epoll_fd;
- buffer *const password = task.password;
- string_set *const cancelled_filenames = task.cancelled_filenames;
- const mono_microsecs *const current_time = task.current_time;
- bool *const mandos_client_exited = task.mandos_client_exited;
- bool *const password_is_read = task.password_is_read;
-
- /* We use the GLib "Key-value file parser" functions to parse the
- question file. See for specification of contents */
- __attribute__((nonnull))
- void cleanup_g_key_file(GKeyFile **key_file){
- if(*key_file != NULL){
- g_key_file_free(*key_file);
- }
- }
-
- __attribute__((cleanup(cleanup_g_key_file)))
- GKeyFile *key_file = g_key_file_new();
- if(key_file == NULL){
- error(0, errno, "Failed g_key_file_new() for \"%s\"",
- question_filename);
- return;
- }
- GError *glib_error = NULL;
- if(g_key_file_load_from_file(key_file, question_filename,
- G_KEY_FILE_NONE, &glib_error) != TRUE){
- /* If a file was removed, we should ignore it, so */
- /* only show error message if file actually existed */
- if(glib_error->code != G_FILE_ERROR_NOENT){
- error(0, 0, "Failed to load question data from file \"%s\": %s",
- question_filename, glib_error->message);
- }
- return;
- }
-
- __attribute__((cleanup(cleanup_string)))
- char *socket_name = g_key_file_get_string(key_file, "Ask",
- "Socket",
- &glib_error);
- if(socket_name == NULL){
- error(0, 0, "Question file \"%s\" did not contain \"Socket\": %s",
- question_filename, glib_error->message);
- return;
- }
-
- if(strlen(socket_name) == 0){
- error(0, 0, "Question file \"%s\" had empty \"Socket\" value",
- question_filename);
- return;
- }
-
- const guint64 pid = g_key_file_get_uint64(key_file, "Ask", "PID",
- &glib_error);
- if(glib_error != NULL){
- error(0, 0, "Question file \"%s\" contained bad \"PID\": %s",
- question_filename, glib_error->message);
- return;
- }
-
- if((pid != (guint64)((pid_t)pid))
- or (kill((pid_t)pid, 0) != 0)){
- error(0, 0, "PID %" PRIuMAX " in question file \"%s\" is bad or"
- " does not exist", (uintmax_t)pid, question_filename);
- return;
- }
-
- guint64 notafter = g_key_file_get_uint64(key_file, "Ask",
- "NotAfter", &glib_error);
- if(glib_error != NULL){
- if(glib_error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND){
- error(0, 0, "Question file \"%s\" contained bad \"NotAfter\":"
- " %s", question_filename, glib_error->message);
- }
- notafter = 0;
- }
- if(notafter != 0){
- if(queue->next_run == 0 or (queue->next_run > notafter)){
- queue->next_run = notafter;
- }
- if(*current_time >= notafter){
- return;
- }
- }
-
- const task_context connect_question_socket_task = {
- .func=connect_question_socket,
- .question_filename=strdup(question_filename),
- .epoll_fd=epoll_fd,
- .password=password,
- .filename=strdup(socket_name),
- .cancelled_filenames=task.cancelled_filenames,
- .mandos_client_exited=mandos_client_exited,
- .password_is_read=password_is_read,
- .current_time=current_time,
- };
- if(connect_question_socket_task.question_filename == NULL
- or connect_question_socket_task.filename == NULL
- or not add_to_queue(queue, connect_question_socket_task)){
- error(0, errno, "Failed to add connect_question_socket for socket"
- " %s (from \"%s\") to queue", socket_name,
- question_filename);
- cleanup_task(&connect_question_socket_task);
- return;
- }
- /* Force the added task (connect_question_socket) to run
- immediately */
- queue->next_run = 1;
-
- if(notafter > 0){
- char *const dup_filename = strdup(question_filename);
- const task_context cancel_old_question_task = {
- .func=cancel_old_question,
- .question_filename=dup_filename,
- .notafter=notafter,
- .filename=dup_filename,
- .cancelled_filenames=cancelled_filenames,
- .current_time=current_time,
- };
- if(cancel_old_question_task.question_filename == NULL
- or not add_to_queue(queue, cancel_old_question_task)){
- error(0, errno, "Failed to add cancel_old_question for file "
- "\"%s\" to queue", question_filename);
- cleanup_task(&cancel_old_question_task);
- return;
- }
- }
-}
-
-__attribute__((nonnull))
-void cancel_old_question(const task_context task,
- task_queue *const queue){
- char *const question_filename = task.question_filename;
- string_set *const cancelled_filenames = task.cancelled_filenames;
- const mono_microsecs notafter = task.notafter;
- const mono_microsecs *const current_time = task.current_time;
-
- if(*current_time >= notafter){
- if(not string_set_add(cancelled_filenames, question_filename)){
- error(0, errno, "Failed to cancel question for file %s",
- question_filename);
- }
- cleanup_task(&task);
- return;
- }
-
- if(not add_to_queue(queue, task)){
- error(0, errno, "Failed to add cancel_old_question for file "
- "%s to queue", question_filename);
- cleanup_task(&task);
- return;
- }
-
- if((queue->next_run == 0) or (queue->next_run > notafter)){
- queue->next_run = notafter;
- }
-}
-
-__attribute__((nonnull))
-void connect_question_socket(const task_context task,
- task_queue *const queue){
- char *const question_filename = task.question_filename;
- char *const filename = task.filename;
- const int epoll_fd = task.epoll_fd;
- buffer *const password = task.password;
- string_set *const cancelled_filenames = task.cancelled_filenames;
- bool *const mandos_client_exited = task.mandos_client_exited;
- bool *const password_is_read = task.password_is_read;
- const mono_microsecs *const current_time = task.current_time;
-
- struct sockaddr_un sock_name = { .sun_family=AF_LOCAL };
-
- if(sizeof(sock_name.sun_path) <= strlen(filename)){
- error(0, 0, "Socket filename is larger than"
- " sizeof(sockaddr_un.sun_path); %" PRIuMAX ": \"%s\"",
- (uintmax_t)sizeof(sock_name.sun_path), filename);
- if(not string_set_add(cancelled_filenames, question_filename)){
- error(0, errno, "Failed to cancel question for file %s",
- question_filename);
- }
- cleanup_task(&task);
- return;
- }
-
- const int fd = socket(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
- if(fd < 0){
- error(0, errno,
- "Failed to create socket(PF_LOCAL, SOCK_DGRAM, 0)");
- if(not add_to_queue(queue, task)){
- error(0, errno, "Failed to add connect_question_socket for file"
- " \"%s\" and socket \"%s\" to queue", question_filename,
- filename);
- cleanup_task(&task);
- } else {
- /* Force the added task (connect_question_socket) to run
- immediately */
- queue->next_run = 1;
- }
- return;
- }
-
- strncpy(sock_name.sun_path, filename, sizeof(sock_name.sun_path));
- if(connect(fd, (struct sockaddr *)&sock_name,
- (socklen_t)SUN_LEN(&sock_name)) != 0){
- error(0, errno, "Failed to connect socket to \"%s\"", filename);
- if(not add_to_queue(queue, task)){
- error(0, errno, "Failed to add connect_question_socket for file"
- " \"%s\" and socket \"%s\" to queue", question_filename,
- filename);
- cleanup_task(&task);
- } else {
- /* Force the added task (connect_question_socket) to run again,
- at most one second from now */
- if((queue->next_run == 0)
- or (queue->next_run > (*current_time + 1000000))){
- queue->next_run = *current_time + 1000000;
- }
- }
- return;
- }
-
- /* Not necessary, but we can try, and merely warn on failure */
- if(shutdown(fd, SHUT_RD) != 0){
- error(0, errno, "Failed to shutdown reading from socket \"%s\"",
- filename);
- }
-
- /* Add the fd to the epoll set */
- if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd,
- &(struct epoll_event){ .events=EPOLLOUT })
- != 0){
- error(0, errno, "Failed to add inotify file descriptor %d for"
- " socket %s to epoll set", fd, filename);
- if(not add_to_queue(queue, task)){
- error(0, errno, "Failed to add connect_question_socket for file"
- " \"%s\" and socket \"%s\" to queue", question_filename,
- filename);
- cleanup_task(&task);
- } else {
- /* Force the added task (connect_question_socket) to run again,
- at most one second from now */
- if((queue->next_run == 0)
- or (queue->next_run > (*current_time + 1000000))){
- queue->next_run = *current_time + 1000000;
- }
- }
- return;
- }
-
- /* add task send_password_to_socket to queue */
- const task_context send_password_to_socket_task = {
- .func=send_password_to_socket,
- .question_filename=question_filename,
- .filename=filename,
- .epoll_fd=epoll_fd,
- .fd=fd,
- .password=password,
- .cancelled_filenames=cancelled_filenames,
- .mandos_client_exited=mandos_client_exited,
- .password_is_read=password_is_read,
- .current_time=current_time,
- };
-
- if(not add_to_queue(queue, send_password_to_socket_task)){
- error(0, errno, "Failed to add send_password_to_socket for"
- " file \"%s\" and socket \"%s\" to queue",
- question_filename, filename);
- cleanup_task(&send_password_to_socket_task);
- }
-}
-
-__attribute__((nonnull))
-void send_password_to_socket(const task_context task,
- task_queue *const queue){
- char *const question_filename=task.question_filename;
- char *const filename=task.filename;
- const int epoll_fd=task.epoll_fd;
- const int fd=task.fd;
- buffer *const password=task.password;
- string_set *const cancelled_filenames=task.cancelled_filenames;
- bool *const mandos_client_exited = task.mandos_client_exited;
- bool *const password_is_read = task.password_is_read;
- const mono_microsecs *const current_time = task.current_time;
-
- if(*mandos_client_exited and *password_is_read){
-
- const size_t send_buffer_length = password->length + 2;
- char *send_buffer = malloc(send_buffer_length);
- if(send_buffer == NULL){
- error(0, errno, "Failed to allocate send_buffer");
- } else {
- if(mlock(send_buffer, send_buffer_length) != 0){
- /* Warn but do not treat as fatal error */
- if(errno != EPERM and errno != ENOMEM){
- error(0, errno, "Failed to lock memory for password"
- " buffer");
- }
- }
- /* “[…] send a single datagram to the socket consisting of the
- password string either prefixed with "+" or with "-"
- depending on whether the password entry was successful or
- not. You may but don't have to include a final NUL byte in
- your message.
-
- — (Wed 08 Oct 2014 02:14:28 AM UTC)
- */
- send_buffer[0] = '+'; /* Prefix with "+" */
- /* Always add an extra NUL */
- send_buffer[password->length + 1] = '\0';
- if(password->length > 0){
- memcpy(send_buffer + 1, password->data, password->length);
- }
- errno = 0;
- ssize_t ssret = send(fd, send_buffer, send_buffer_length,
- MSG_NOSIGNAL);
- const error_t saved_errno = errno;
-#if defined(__GLIBC_PREREQ) and __GLIBC_PREREQ(2, 25)
- explicit_bzero(send_buffer, send_buffer_length);
-#else
- memset(send_buffer, '\0', send_buffer_length);
-#endif
- if(munlock(send_buffer, send_buffer_length) != 0){
- error(0, errno, "Failed to unlock memory of send buffer");
- }
- free(send_buffer);
- if(ssret < 0 or ssret < (ssize_t)send_buffer_length){
- switch(saved_errno){
- case EINTR:
- case ENOBUFS:
- case ENOMEM:
- case EADDRINUSE:
- case ECONNREFUSED:
- case ECONNRESET:
- case ENOENT:
- case ETOOMANYREFS:
- case EAGAIN:
- /* Retry, below */
- break;
- case EMSGSIZE:
- error(0, 0, "Password of size %" PRIuMAX " is too big",
- (uintmax_t)password->length);
-#if __GNUC__ < 7
- /* FALLTHROUGH */
-#else
- __attribute__((fallthrough));
-#endif
- case 0:
- if(ssret >= 0 and ssret < (ssize_t)send_buffer_length){
- error(0, 0, "Password only partially sent to socket");
- }
-#if __GNUC__ < 7
- /* FALLTHROUGH */
-#else
- __attribute__((fallthrough));
-#endif
- default:
- error(0, saved_errno, "Failed to send() to socket %s",
- filename);
- if(not string_set_add(cancelled_filenames,
- question_filename)){
- error(0, errno, "Failed to cancel question for file %s",
- question_filename);
- }
- cleanup_task(&task);
- return;
- }
- } else {
- /* Success */
- cleanup_task(&task);
- return;
- }
- }
- }
-
- /* We failed or are not ready yet; retry later */
-
- if(not add_to_queue(queue, task)){
- error(0, errno, "Failed to add send_password_to_socket for"
- " file %s and socket %s to queue", question_filename,
- filename);
- cleanup_task(&task);
- }
-
- /* Add the fd to the epoll set */
- if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd,
- &(struct epoll_event){ .events=EPOLLOUT })
- != 0){
- error(0, errno, "Failed to add socket file descriptor %d for"
- " socket %s to epoll set", fd, filename);
- /* Force the added task (send_password_to_socket) to run again, at
- most one second from now */
- if((queue->next_run == 0)
- or (queue->next_run > (*current_time + 1000000))){
- queue->next_run = *current_time + 1000000;
- }
- }
-}
-
-__attribute__((warn_unused_result))
-bool add_existing_questions(task_queue *const queue,
- const int epoll_fd,
- buffer *const password,
- string_set *cancelled_filenames,
- const mono_microsecs *const current_time,
- bool *const mandos_client_exited,
- bool *const password_is_read,
- const char *const dirname){
- __attribute__((cleanup(cleanup_string)))
- char *dir_pattern = NULL;
- const int ret = asprintf(&dir_pattern, "%s/ask.*", dirname);
- if(ret < 0 or dir_pattern == NULL){
- error(0, errno, "Could not create glob pattern for directory %s",
- dirname);
- return false;
- }
- __attribute__((cleanup(globfree)))
- glob_t question_filenames = {};
- switch(glob(dir_pattern, GLOB_ERR | GLOB_NOSORT | GLOB_MARK,
- NULL, &question_filenames)){
- case GLOB_ABORTED:
- default:
- error(0, errno, "Failed to open directory %s", dirname);
- return false;
- case GLOB_NOMATCH:
- error(0, errno, "There are no question files in %s", dirname);
- return false;
- case GLOB_NOSPACE:
- error(0, errno, "Could not allocate memory for question file"
- " names in %s", dirname);
-#if __GNUC__ < 7
- /* FALLTHROUGH */
-#else
- __attribute__((fallthrough));
-#endif
- case 0:
- for(size_t i = 0; i < question_filenames.gl_pathc; i++){
- char *const question_filename = strdup(question_filenames
- .gl_pathv[i]);
- const task_context task = {
- .func=open_and_parse_question,
- .epoll_fd=epoll_fd,
- .question_filename=question_filename,
- .filename=question_filename,
- .password=password,
- .cancelled_filenames=cancelled_filenames,
- .current_time=current_time,
- .mandos_client_exited=mandos_client_exited,
- .password_is_read=password_is_read,
- };
-
- if(question_filename == NULL
- or not add_to_queue(queue, task)){
- error(0, errno, "Failed to add open_and_parse_question for"
- " file %s to queue",
- question_filenames.gl_pathv[i]);
- free(question_filename);
- } else {
- queue->next_run = 1;
- }
- }
- return true;
- }
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool wait_for_event(const int epoll_fd,
- const mono_microsecs queue_next_run,
- const mono_microsecs current_time){
- __attribute__((const))
- int milliseconds_to_wait(const mono_microsecs currtime,
- const mono_microsecs nextrun){
- if(currtime >= nextrun){
- return 0;
- }
- const uintmax_t wait_time_ms = (nextrun - currtime) / 1000;
- if(wait_time_ms > (uintmax_t)INT_MAX){
- return INT_MAX;
- }
- return (int)wait_time_ms;
- }
-
- const int wait_time_ms = milliseconds_to_wait(current_time,
- queue_next_run);
-
- /* Prepare unblocking of SIGCHLD during epoll_pwait */
- sigset_t temporary_unblocked_sigmask;
- /* Get current signal mask */
- if(pthread_sigmask(-1, NULL, &temporary_unblocked_sigmask) != 0){
- return false;
- }
- /* Remove SIGCHLD from the signal mask */
- if(sigdelset(&temporary_unblocked_sigmask, SIGCHLD) != 0){
- return false;
- }
- struct epoll_event events[8]; /* Ignored */
- int ret = epoll_pwait(epoll_fd, events,
- sizeof(events) / sizeof(struct epoll_event),
- queue_next_run == 0 ? -1 : (int)wait_time_ms,
- &temporary_unblocked_sigmask);
- if(ret < 0 and errno != EINTR){
- error(0, errno, "Failed epoll_pwait(epfd=%d, ..., timeout=%d,"
- " ...", epoll_fd,
- queue_next_run == 0 ? -1 : (int)wait_time_ms);
- return false;
- }
- return clear_all_fds_from_epoll_set(epoll_fd);
-}
-
-bool clear_all_fds_from_epoll_set(const int epoll_fd){
- /* Create a new empty epoll set */
- __attribute__((cleanup(cleanup_close)))
- const int new_epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- if(new_epoll_fd < 0){
- return false;
- }
- /* dup3() the new epoll set fd over the old one, replacing it */
- if(dup3(new_epoll_fd, epoll_fd, O_CLOEXEC) < 0){
- return false;
- }
- return true;
-}
-
-__attribute__((nonnull, warn_unused_result))
-bool run_queue(task_queue **const queue,
- string_set *const cancelled_filenames,
- bool *const quit_now){
-
- task_queue *new_queue = create_queue();
- if(new_queue == NULL){
- return false;
- }
-
- __attribute__((cleanup(string_set_clear)))
- string_set old_cancelled_filenames = {};
- string_set_swap(cancelled_filenames, &old_cancelled_filenames);
-
- /* Declare i outside the for loop, since we might need i after the
- loop in case we aborted in the middle */
- size_t i;
- for(i=0; i < (*queue)->length and not *quit_now; i++){
- task_context *const task = &((*queue)->tasks[i]);
- const char *const question_filename = task->question_filename;
- /* Skip any task referencing a cancelled question filename */
- if(question_filename != NULL
- and string_set_contains(old_cancelled_filenames,
- question_filename)){
- cleanup_task(task);
- continue;
- }
- task->func(*task, new_queue);
- }
-
- if(*quit_now){
- /* we might be in the middle of the queue, so clean up any
- remaining tasks in the current queue */
- for(; i < (*queue)->length; i++){
- cleanup_task(&((*queue)->tasks[i]));
- }
- free_queue(*queue);
- *queue = new_queue;
- new_queue = NULL;
- return false;
- }
- free_queue(*queue);
- *queue = new_queue;
- new_queue = NULL;
-
- return true;
-}
-
-/* End of regular code section */
-
-/* Start of tests section; here are the tests for the above code */
-
-/* This "fixture" data structure is used by the test setup and
- teardown functions */
-typedef struct {
- struct sigaction orig_sigaction;
- sigset_t orig_sigmask;
-} test_fixture;
-
-static void test_setup(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- g_assert_true(setup_signal_handler(&fixture->orig_sigaction));
- g_assert_true(block_sigchld(&fixture->orig_sigmask));
-}
-
-static void test_teardown(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- g_assert_true(restore_signal_handler(&fixture->orig_sigaction));
- g_assert_true(restore_sigmask(&fixture->orig_sigmask));
-}
-
-/* Utility function used by tests to search queue for matching task */
-__attribute__((pure, nonnull, warn_unused_result))
-static task_context *find_matching_task(const task_queue *const queue,
- const task_context task){
- /* The argument "task" structure is a pattern to match; 0 in any
- member means any value matches, otherwise the value must match.
- The filename strings are compared by strcmp(), not by pointer. */
- for(size_t i = 0; i < queue->length; i++){
- task_context *const current_task = queue->tasks+i;
- /* Check all members of task_context, if set to a non-zero value.
- If a member does not match, continue to next task in queue */
-
- /* task_func *const func */
- if(task.func != NULL and current_task->func != task.func){
- continue;
- }
- /* char *const question_filename; */
- if(task.question_filename != NULL
- and (current_task->question_filename == NULL
- or strcmp(current_task->question_filename,
- task.question_filename) != 0)){
- continue;
- }
- /* const pid_t pid; */
- if(task.pid != 0 and current_task->pid != task.pid){
- continue;
- }
- /* const int epoll_fd; */
- if(task.epoll_fd != 0
- and current_task->epoll_fd != task.epoll_fd){
- continue;
- }
- /* bool *const quit_now; */
- if(task.quit_now != NULL
- and current_task->quit_now != task.quit_now){
- continue;
- }
- /* const int fd; */
- if(task.fd != 0 and current_task->fd != task.fd){
- continue;
- }
- /* bool *const mandos_client_exited; */
- if(task.mandos_client_exited != NULL
- and current_task->mandos_client_exited
- != task.mandos_client_exited){
- continue;
- }
- /* buffer *const password; */
- if(task.password != NULL
- and current_task->password != task.password){
- continue;
- }
- /* bool *const password_is_read; */
- if(task.password_is_read != NULL
- and current_task->password_is_read != task.password_is_read){
- continue;
- }
- /* char *filename; */
- if(task.filename != NULL
- and (current_task->filename == NULL
- or strcmp(current_task->filename, task.filename) != 0)){
- continue;
- }
- /* string_set *const cancelled_filenames; */
- if(task.cancelled_filenames != NULL
- and current_task->cancelled_filenames
- != task.cancelled_filenames){
- continue;
- }
- /* const mono_microsecs notafter; */
- if(task.notafter != 0
- and current_task->notafter != task.notafter){
- continue;
- }
- /* const mono_microsecs *const current_time; */
- if(task.current_time != NULL
- and current_task->current_time != task.current_time){
- continue;
- }
- /* Current task matches all members; return it */
- return current_task;
- }
- /* No task in queue matches passed pattern task */
- return NULL;
-}
-
-static void test_create_queue(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *const queue = create_queue();
- g_assert_nonnull(queue);
- g_assert_null(queue->tasks);
- g_assert_true(queue->length == 0);
- g_assert_true(queue->next_run == 0);
-}
-
-static task_func dummy_func;
-
-static void test_add_to_queue(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- g_assert_true(add_to_queue(queue,
- (task_context){ .func=dummy_func }));
- g_assert_true(queue->length == 1);
- g_assert_nonnull(queue->tasks);
- g_assert_true(queue->tasks[0].func == dummy_func);
-}
-
-static void dummy_func(__attribute__((unused))
- const task_context task,
- __attribute__((unused))
- task_queue *const queue){
-}
-
-static void test_queue_has_question_empty(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- g_assert_false(queue_has_question(queue));
-}
-
-static void test_queue_has_question_false(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- g_assert_true(add_to_queue(queue,
- (task_context){ .func=dummy_func }));
- g_assert_false(queue_has_question(queue));
-}
-
-static void test_queue_has_question_true(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- char *const question_filename
- = strdup("/nonexistent/question_filename");
- g_assert_nonnull(question_filename);
- task_context task = {
- .func=dummy_func,
- .question_filename=question_filename,
- };
- g_assert_true(add_to_queue(queue, task));
- g_assert_true(queue_has_question(queue));
-}
-
-static void test_queue_has_question_false2(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- task_context task = { .func=dummy_func };
- g_assert_true(add_to_queue(queue, task));
- g_assert_true(add_to_queue(queue, task));
- g_assert_cmpint((int)queue->length, ==, 2);
- g_assert_false(queue_has_question(queue));
-}
-
-static void test_queue_has_question_true2(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- task_context task1 = { .func=dummy_func };
- g_assert_true(add_to_queue(queue, task1));
- char *const question_filename
- = strdup("/nonexistent/question_filename");
- g_assert_nonnull(question_filename);
- task_context task2 = {
- .func=dummy_func,
- .question_filename=question_filename,
- };
- g_assert_true(add_to_queue(queue, task2));
- g_assert_cmpint((int)queue->length, ==, 2);
- g_assert_true(queue_has_question(queue));
-}
-
-static void test_cleanup_buffer(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- buffer buf = {};
-
- const size_t buffersize = 10;
-
- buf.data = malloc(buffersize);
- g_assert_nonnull(buf.data);
- if(mlock(buf.data, buffersize) != 0){
- g_assert_true(errno == EPERM or errno == ENOMEM);
- }
-
- cleanup_buffer(&buf);
- g_assert_null(buf.data);
-}
-
-static
-void test_string_set_new_set_contains_nothing(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(string_set_clear)))
- string_set set = {};
- g_assert_false(string_set_contains(set, "")); /* Empty string */
- g_assert_false(string_set_contains(set, "test_string"));
-}
-
-static void
-test_string_set_with_added_string_contains_it(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(string_set_clear)))
- string_set set = {};
- g_assert_true(string_set_add(&set, "test_string"));
- g_assert_true(string_set_contains(set, "test_string"));
-}
-
-static void
-test_string_set_cleared_does_not_contain_str(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(string_set_clear)))
- string_set set = {};
- g_assert_true(string_set_add(&set, "test_string"));
- string_set_clear(&set);
- g_assert_false(string_set_contains(set, "test_string"));
-}
-
-static
-void test_string_set_swap_one_with_empty(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(string_set_clear)))
- string_set set1 = {};
- __attribute__((cleanup(string_set_clear)))
- string_set set2 = {};
- g_assert_true(string_set_add(&set1, "test_string1"));
- string_set_swap(&set1, &set2);
- g_assert_false(string_set_contains(set1, "test_string1"));
- g_assert_true(string_set_contains(set2, "test_string1"));
-}
-
-static
-void test_string_set_swap_empty_with_one(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(string_set_clear)))
- string_set set1 = {};
- __attribute__((cleanup(string_set_clear)))
- string_set set2 = {};
- g_assert_true(string_set_add(&set2, "test_string2"));
- string_set_swap(&set1, &set2);
- g_assert_true(string_set_contains(set1, "test_string2"));
- g_assert_false(string_set_contains(set2, "test_string2"));
-}
-
-static void test_string_set_swap_one_with_one(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(string_set_clear)))
- string_set set1 = {};
- __attribute__((cleanup(string_set_clear)))
- string_set set2 = {};
- g_assert_true(string_set_add(&set1, "test_string1"));
- g_assert_true(string_set_add(&set2, "test_string2"));
- string_set_swap(&set1, &set2);
- g_assert_false(string_set_contains(set1, "test_string1"));
- g_assert_true(string_set_contains(set1, "test_string2"));
- g_assert_false(string_set_contains(set2, "test_string2"));
- g_assert_true(string_set_contains(set2, "test_string1"));
-}
-
-static bool fd_has_cloexec_and_nonblock(const int);
-
-static bool epoll_set_contains(int, int, uint32_t);
-
-static void test_start_mandos_client(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
-
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- buffer password = {};
- bool password_is_read = false;
- const char helper_directory[] = "/nonexistent";
- const char *const argv[] = { "/bin/true", NULL };
-
- g_assert_true(start_mandos_client(queue, epoll_fd,
- &mandos_client_exited, &quit_now,
- &password, &password_is_read,
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, 0, 0, argv));
-
- g_assert_cmpuint((unsigned int)queue->length, >=, 2);
-
- const task_context *const added_wait_task
- = find_matching_task(queue, (task_context){
- .func=wait_for_mandos_client_exit,
- .mandos_client_exited=&mandos_client_exited,
- .quit_now=&quit_now,
- });
- g_assert_nonnull(added_wait_task);
- g_assert_cmpint(added_wait_task->pid, >, 0);
- g_assert_cmpint(kill(added_wait_task->pid, SIGKILL), ==, 0);
- waitpid(added_wait_task->pid, NULL, 0);
-
- const task_context *const added_read_task
- = find_matching_task(queue, (task_context){
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- });
- g_assert_nonnull(added_read_task);
- g_assert_cmpint(added_read_task->fd, >, 2);
- g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
- g_assert_true(epoll_set_contains(epoll_fd, added_read_task->fd,
- EPOLLIN | EPOLLRDHUP));
-}
-
-static bool fd_has_cloexec_and_nonblock(const int fd){
- const int socket_fd_flags = fcntl(fd, F_GETFD, 0);
- const int socket_file_flags = fcntl(fd, F_GETFL, 0);
- return ((socket_fd_flags >= 0)
- and (socket_fd_flags & FD_CLOEXEC)
- and (socket_file_flags >= 0)
- and (socket_file_flags & O_NONBLOCK));
-}
-
-__attribute__((const))
-bool is_privileged(void){
- uid_t user = getuid() + 1;
- if(user == 0){ /* Overflow check */
- user++;
- }
- gid_t group = getuid() + 1;
- if(group == 0){ /* Overflow check */
- group++;
- }
- const pid_t pid = fork();
- if(pid == 0){ /* Child */
- if(setresgid((uid_t)-1, group, group) == -1){
- if(errno != EPERM){
- error(EXIT_FAILURE, errno, "Failed to setresgid(-1, %" PRIuMAX
- ", %" PRIuMAX")", (uintmax_t)group, (uintmax_t)group);
- }
- exit(EXIT_FAILURE);
- }
- if(setresuid((uid_t)-1, user, user) == -1){
- if(errno != EPERM){
- error(EXIT_FAILURE, errno, "Failed to setresuid(-1, %" PRIuMAX
- ", %" PRIuMAX")", (uintmax_t)user, (uintmax_t)user);
- }
- exit(EXIT_FAILURE);
- }
- exit(EXIT_SUCCESS);
- }
- int status;
- waitpid(pid, &status, 0);
- if(WIFEXITED(status) and (WEXITSTATUS(status) == EXIT_SUCCESS)){
- return true;
- }
- return false;
-}
-
-static bool epoll_set_contains(int epoll_fd, int fd, uint32_t events){
- /* Only scan for events in this eventmask */
- const uint32_t eventmask = EPOLLIN | EPOLLOUT | EPOLLRDHUP;
- __attribute__((cleanup(cleanup_string)))
- char *fdinfo_name = NULL;
- int ret = asprintf(&fdinfo_name, "/proc/self/fdinfo/%d", epoll_fd);
- g_assert_cmpint(ret, >, 0);
- g_assert_nonnull(fdinfo_name);
-
- FILE *fdinfo = fopen(fdinfo_name, "r");
- g_assert_nonnull(fdinfo);
- uint32_t reported_events;
- buffer line = {};
- int found_fd = -1;
-
- do {
- if(getline(&line.data, &line.allocated, fdinfo) < 0){
- break;
- }
- /* See proc(5) for format of /proc/PID/fdinfo/FD for epoll fd's */
- if(sscanf(line.data, "tfd: %d events: %" SCNx32 " ",
- &found_fd, &reported_events) == 2){
- if(found_fd == fd){
- break;
- }
- }
- } while(not feof(fdinfo) and not ferror(fdinfo));
- g_assert_cmpint(fclose(fdinfo), ==, 0);
- free(line.data);
- if(found_fd != fd){
- return false;
- }
-
- if(events == 0){
- /* Don't check events if none are given */
- return true;
- }
- return (reported_events & eventmask) == (events & eventmask);
-}
-
-static void test_start_mandos_client_execv(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- const char helper_directory[] = "/nonexistent";
- /* Can't execv("/", ...), so this should fail */
- const char *const argv[] = { "/", NULL };
-
- {
- __attribute__((cleanup(cleanup_close)))
- const int devnull_fd = open("/dev/null",
- O_WRONLY | O_CLOEXEC | O_NOCTTY);
- g_assert_cmpint(devnull_fd, >=, 0);
- __attribute__((cleanup(cleanup_close)))
- const int real_stderr_fd = dup(STDERR_FILENO);
- g_assert_cmpint(real_stderr_fd, >=, 0);
- dup2(devnull_fd, STDERR_FILENO);
-
- const bool success = start_mandos_client(queue, epoll_fd,
- &mandos_client_exited,
- &quit_now,
- &password,
- (bool[]){false},
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, 0, 0,
- argv);
- dup2(real_stderr_fd, STDERR_FILENO);
- g_assert_true(success);
- }
- g_assert_cmpuint((unsigned int)queue->length, ==, 2);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- queue->next_run = 0;
- string_set cancelled_filenames = {};
-
- {
- __attribute__((cleanup(cleanup_close)))
- const int devnull_fd = open("/dev/null",
- O_WRONLY | O_CLOEXEC | O_NOCTTY);
- g_assert_cmpint(devnull_fd, >=, 0);
- __attribute__((cleanup(cleanup_close)))
- const int real_stderr_fd = dup(STDERR_FILENO);
- g_assert_cmpint(real_stderr_fd, >=, 0);
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- dup2(devnull_fd, STDERR_FILENO);
- const bool success = run_queue(&queue, &cancelled_filenames,
- &quit_now);
- dup2(real_stderr_fd, STDERR_FILENO);
- if(not success){
- break;
- }
- }
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while(((queue->length) > 0)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_true(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(mandos_client_exited);
-}
-
-static void test_start_mandos_client_suid_euid(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- if(not is_privileged()){
- g_test_skip("Not privileged");
- return;
- }
-
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- bool password_is_read = false;
- const char helper_directory[] = "/nonexistent";
- const char *const argv[] = { "/usr/bin/id", "--user", NULL };
- uid_t user = 1000;
- gid_t group = 1001;
-
- const bool success = start_mandos_client(queue, epoll_fd,
- &mandos_client_exited,
- &quit_now, &password,
- &password_is_read,
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, user,
- group, argv);
- g_assert_true(success);
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- queue->next_run = 0;
- string_set cancelled_filenames = {};
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while(((queue->length) > 0)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(mandos_client_exited);
-
- g_assert_true(password_is_read);
- g_assert_nonnull(password.data);
-
- uintmax_t id;
- g_assert_cmpint(sscanf(password.data, "%" SCNuMAX "\n", &id),
- ==, 1);
- g_assert_true((uid_t)id == id);
-
- g_assert_cmpuint((unsigned int)id, ==, 0);
-}
-
-static void test_start_mandos_client_suid_egid(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- if(not is_privileged()){
- g_test_skip("Not privileged");
- return;
- }
-
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- bool password_is_read = false;
- const char helper_directory[] = "/nonexistent";
- const char *const argv[] = { "/usr/bin/id", "--group", NULL };
- uid_t user = 1000;
- gid_t group = 1001;
-
- const bool success = start_mandos_client(queue, epoll_fd,
- &mandos_client_exited,
- &quit_now, &password,
- &password_is_read,
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, user,
- group, argv);
- g_assert_true(success);
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- queue->next_run = 0;
- string_set cancelled_filenames = {};
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while(((queue->length) > 0)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(mandos_client_exited);
-
- g_assert_true(password_is_read);
- g_assert_nonnull(password.data);
-
- uintmax_t id;
- g_assert_cmpint(sscanf(password.data, "%" SCNuMAX "\n", &id),
- ==, 1);
- g_assert_true((gid_t)id == id);
-
- g_assert_cmpuint((unsigned int)id, ==, 0);
-}
-
-static void test_start_mandos_client_suid_ruid(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- if(not is_privileged()){
- g_test_skip("Not privileged");
- return;
- }
-
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- bool password_is_read = false;
- const char helper_directory[] = "/nonexistent";
- const char *const argv[] = { "/usr/bin/id", "--user", "--real",
- NULL };
- uid_t user = 1000;
- gid_t group = 1001;
-
- const bool success = start_mandos_client(queue, epoll_fd,
- &mandos_client_exited,
- &quit_now, &password,
- &password_is_read,
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, user,
- group, argv);
- g_assert_true(success);
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- queue->next_run = 0;
- string_set cancelled_filenames = {};
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while(((queue->length) > 0)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(mandos_client_exited);
-
- g_assert_true(password_is_read);
- g_assert_nonnull(password.data);
-
- uintmax_t id;
- g_assert_cmpint(sscanf(password.data, "%" SCNuMAX "\n", &id),
- ==, 1);
- g_assert_true((uid_t)id == id);
-
- g_assert_cmpuint((unsigned int)id, ==, user);
-}
-
-static void test_start_mandos_client_suid_rgid(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- if(not is_privileged()){
- g_test_skip("Not privileged");
- return;
- }
-
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- bool password_is_read = false;
- const char helper_directory[] = "/nonexistent";
- const char *const argv[] = { "/usr/bin/id", "--group", "--real",
- NULL };
- uid_t user = 1000;
- gid_t group = 1001;
-
- const bool success = start_mandos_client(queue, epoll_fd,
- &mandos_client_exited,
- &quit_now, &password,
- &password_is_read,
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, user,
- group, argv);
- g_assert_true(success);
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- queue->next_run = 0;
- string_set cancelled_filenames = {};
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while(((queue->length) > 0)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(mandos_client_exited);
-
- g_assert_true(password_is_read);
- g_assert_nonnull(password.data);
-
- uintmax_t id;
- g_assert_cmpint(sscanf(password.data, "%" SCNuMAX "\n", &id),
- ==, 1);
- g_assert_true((gid_t)id == id);
-
- g_assert_cmpuint((unsigned int)id, ==, group);
-}
-
-static void test_start_mandos_client_read(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- bool password_is_read = false;
- const char dummy_test_password[] = "dummy test password";
- const char helper_directory[] = "/nonexistent";
- const char *const argv[] = { "/bin/echo", "-n", dummy_test_password,
- NULL };
-
- const bool success = start_mandos_client(queue, epoll_fd,
- &mandos_client_exited,
- &quit_now, &password,
- &password_is_read,
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, 0, 0,
- argv);
- g_assert_true(success);
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- queue->next_run = 0;
- string_set cancelled_filenames = {};
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while(((queue->length) > 0)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(mandos_client_exited);
-
- g_assert_true(password_is_read);
- g_assert_cmpint((int)password.length, ==,
- sizeof(dummy_test_password)-1);
- g_assert_nonnull(password.data);
- g_assert_cmpint(memcmp(dummy_test_password, password.data,
- sizeof(dummy_test_password)-1), ==, 0);
-}
-
-static
-void test_start_mandos_client_helper_directory(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- bool password_is_read = false;
- const char helper_directory[] = "/nonexistent";
- const char *const argv[] = { "/bin/sh", "-c",
- "echo -n ${MANDOSPLUGINHELPERDIR}", NULL };
-
- const bool success = start_mandos_client(queue, epoll_fd,
- &mandos_client_exited,
- &quit_now, &password,
- &password_is_read,
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, 0, 0,
- argv);
- g_assert_true(success);
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- queue->next_run = 0;
- string_set cancelled_filenames = {};
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while(((queue->length) > 0)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(mandos_client_exited);
-
- g_assert_true(password_is_read);
- g_assert_cmpint((int)password.length, ==,
- sizeof(helper_directory)-1);
- g_assert_nonnull(password.data);
- g_assert_cmpint(memcmp(helper_directory, password.data,
- sizeof(helper_directory)-1), ==, 0);
-}
-
-__attribute__((nonnull, warn_unused_result))
-static bool proc_status_sigblk_to_sigset(const char *const,
- sigset_t *const);
-
-static void test_start_mandos_client_sigmask(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- bool mandos_client_exited = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- bool password_is_read = false;
- const char helper_directory[] = "/nonexistent";
- /* see proc(5) for format of /proc/self/status */
- const char *const argv[] = { "/usr/bin/awk",
- "$1==\"SigBlk:\"{ print $2 }", "/proc/self/status", NULL };
-
- g_assert_true(start_mandos_client(queue, epoll_fd,
- &mandos_client_exited, &quit_now,
- &password, &password_is_read,
- &fixture->orig_sigaction,
- fixture->orig_sigmask,
- helper_directory, 0, 0, argv));
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- queue->next_run = 0;
- string_set cancelled_filenames = {};
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while((not (mandos_client_exited and password_is_read))
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
- g_assert_true(mandos_client_exited);
- g_assert_true(password_is_read);
-
- sigset_t parsed_sigmask;
- g_assert_true(proc_status_sigblk_to_sigset(password.data,
- &parsed_sigmask));
-
- for(int signum = 1; signum < NSIG; signum++){
- const bool has_signal = sigismember(&parsed_sigmask, signum);
- if(sigismember(&fixture->orig_sigmask, signum)){
- g_assert_true(has_signal);
- } else {
- g_assert_false(has_signal);
- }
- }
-}
-
-__attribute__((nonnull, warn_unused_result))
-static bool proc_status_sigblk_to_sigset(const char *const sigblk,
- sigset_t *const sigmask){
- /* parse /proc/PID/status SigBlk value and convert to a sigset_t */
- uintmax_t scanned_sigmask;
- if(sscanf(sigblk, "%" SCNxMAX " ", &scanned_sigmask) != 1){
- return false;
- }
- if(sigemptyset(sigmask) != 0){
- return false;
- }
- for(int signum = 1; signum < NSIG; signum++){
- if(scanned_sigmask & ((uintmax_t)1 << (signum-1))){
- if(sigaddset(sigmask, signum) != 0){
- return false;
- }
- }
- }
- return true;
-}
-
-static void run_task_with_stderr_to_dev_null(const task_context task,
- task_queue *const queue);
-
-static
-void test_wait_for_mandos_client_exit_badpid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
-
- bool mandos_client_exited = false;
- bool quit_now = false;
-
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- const task_context task = {
- .func=wait_for_mandos_client_exit,
- .pid=1,
- .mandos_client_exited=&mandos_client_exited,
- .quit_now=&quit_now,
- };
- run_task_with_stderr_to_dev_null(task, queue);
-
- g_assert_false(mandos_client_exited);
- g_assert_true(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static void run_task_with_stderr_to_dev_null(const task_context task,
- task_queue *const queue){
- FILE *real_stderr = stderr;
- FILE *devnull = fopen("/dev/null", "we");
- g_assert_nonnull(devnull);
-
- stderr = devnull;
- task.func(task, queue);
- stderr = real_stderr;
-
- g_assert_cmpint(fclose(devnull), ==, 0);
-}
-
-static
-void test_wait_for_mandos_client_exit_noexit(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- bool mandos_client_exited = false;
- bool quit_now = false;
-
- pid_t create_eternal_process(void){
- const pid_t pid = fork();
- if(pid == 0){ /* Child */
- if(not restore_signal_handler(&fixture->orig_sigaction)){
- _exit(EXIT_FAILURE);
- }
- if(not restore_sigmask(&fixture->orig_sigmask)){
- _exit(EXIT_FAILURE);
- }
- while(true){
- pause();
- }
- }
- return pid;
- }
- pid_t pid = create_eternal_process();
- g_assert_true(pid != -1);
-
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- const task_context task = {
- .func=wait_for_mandos_client_exit,
- .pid=pid,
- .mandos_client_exited=&mandos_client_exited,
- .quit_now=&quit_now,
- };
- task.func(task, queue);
-
- g_assert_false(mandos_client_exited);
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=wait_for_mandos_client_exit,
- .pid=task.pid,
- .mandos_client_exited=&mandos_client_exited,
- .quit_now=&quit_now,
- }));
-}
-
-static
-void test_wait_for_mandos_client_exit_success(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- bool mandos_client_exited = false;
- bool quit_now = false;
-
- pid_t create_successful_process(void){
- const pid_t pid = fork();
- if(pid == 0){ /* Child */
- if(not restore_signal_handler(&fixture->orig_sigaction)){
- _exit(EXIT_FAILURE);
- }
- if(not restore_sigmask(&fixture->orig_sigmask)){
- _exit(EXIT_FAILURE);
- }
- exit(EXIT_SUCCESS);
- }
- return pid;
- }
- const pid_t pid = create_successful_process();
- g_assert_true(pid != -1);
-
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- const task_context initial_task = {
- .func=wait_for_mandos_client_exit,
- .pid=pid,
- .mandos_client_exited=&mandos_client_exited,
- .quit_now=&quit_now,
- };
- g_assert_true(add_to_queue(queue, initial_task));
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- do {
- queue->next_run = 0;
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- g_assert_true(run_queue(&queue, (string_set[]){{}}, &quit_now));
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while((not mandos_client_exited)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_true(mandos_client_exited);
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static
-void test_wait_for_mandos_client_exit_failure(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- bool mandos_client_exited = false;
- bool quit_now = false;
-
- pid_t create_failing_process(void){
- const pid_t pid = fork();
- if(pid == 0){ /* Child */
- if(not restore_signal_handler(&fixture->orig_sigaction)){
- _exit(EXIT_FAILURE);
- }
- if(not restore_sigmask(&fixture->orig_sigmask)){
- _exit(EXIT_FAILURE);
- }
- exit(EXIT_FAILURE);
- }
- return pid;
- }
- const pid_t pid = create_failing_process();
- g_assert_true(pid != -1);
-
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- g_assert_true(add_to_queue(queue, (task_context){
- .func=wait_for_mandos_client_exit,
- .pid=pid,
- .mandos_client_exited=&mandos_client_exited,
- .quit_now=&quit_now,
- }));
-
- g_assert_true(sigismember(&fixture->orig_sigmask, SIGCHLD) == 0);
-
- __attribute__((cleanup(cleanup_close)))
- const int devnull_fd = open("/dev/null",
- O_WRONLY | O_CLOEXEC | O_NOCTTY);
- g_assert_cmpint(devnull_fd, >=, 0);
- __attribute__((cleanup(cleanup_close)))
- const int real_stderr_fd = dup(STDERR_FILENO);
- g_assert_cmpint(real_stderr_fd, >=, 0);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- dup2(devnull_fd, STDERR_FILENO);
- const bool success = run_queue(&queue, &cancelled_filenames,
- &quit_now);
- dup2(real_stderr_fd, STDERR_FILENO);
- if(not success){
- break;
- }
-
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while((not mandos_client_exited)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_true(quit_now);
- g_assert_true(mandos_client_exited);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static
-void test_wait_for_mandos_client_exit_killed(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- bool mandos_client_exited = false;
- bool quit_now = false;
-
- pid_t create_killed_process(void){
- const pid_t pid = fork();
- if(pid == 0){ /* Child */
- if(not restore_signal_handler(&fixture->orig_sigaction)){
- _exit(EXIT_FAILURE);
- }
- if(not restore_sigmask(&fixture->orig_sigmask)){
- _exit(EXIT_FAILURE);
- }
- while(true){
- pause();
- }
- }
- kill(pid, SIGKILL);
- return pid;
- }
- const pid_t pid = create_killed_process();
- g_assert_true(pid != -1);
-
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- g_assert_true(add_to_queue(queue, (task_context){
- .func=wait_for_mandos_client_exit,
- .pid=pid,
- .mandos_client_exited=&mandos_client_exited,
- .quit_now=&quit_now,
- }));
-
- __attribute__((cleanup(cleanup_close)))
- const int devnull_fd = open("/dev/null",
- O_WRONLY | O_CLOEXEC, O_NOCTTY);
- g_assert_cmpint(devnull_fd, >=, 0);
- __attribute__((cleanup(cleanup_close)))
- const int real_stderr_fd = dup(STDERR_FILENO);
- g_assert_cmpint(real_stderr_fd, >=, 0);
-
- struct timespec starttime, currtime;
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &starttime) == 0);
- do {
- g_assert_true(wait_for_event(epoll_fd, queue->next_run, 0));
- dup2(devnull_fd, STDERR_FILENO);
- const bool success = run_queue(&queue, &cancelled_filenames,
- &quit_now);
- dup2(real_stderr_fd, STDERR_FILENO);
- if(not success){
- break;
- }
-
- g_assert_true(clock_gettime(CLOCK_MONOTONIC, &currtime) == 0);
- } while((not mandos_client_exited)
- and (not quit_now)
- and ((currtime.tv_sec - starttime.tv_sec) < 10));
-
- g_assert_true(mandos_client_exited);
- g_assert_true(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static bool epoll_set_does_not_contain(int, int);
-
-static
-void test_read_mandos_client_output_readerror(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
-
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
-
- /* Reading /proc/self/mem from offset 0 will always give EIO */
- const int fd = open("/proc/self/mem",
- O_RDONLY | O_CLOEXEC | O_NOCTTY);
-
- bool password_is_read = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=fd,
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_false(password_is_read);
- g_assert_cmpint((int)password.length, ==, 0);
- g_assert_true(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_true(epoll_set_does_not_contain(epoll_fd, fd));
-
- g_assert_cmpint(close(fd), ==, -1);
-}
-
-static bool epoll_set_does_not_contain(int epoll_fd, int fd){
- return not epoll_set_contains(epoll_fd, fd, 0);
-}
-
-static
-void test_read_mandos_client_output_nodata(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
-
- bool password_is_read = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- };
- task.func(task, queue);
- g_assert_false(password_is_read);
- g_assert_cmpint((int)password.length, ==, 0);
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-}
-
-static void test_read_mandos_client_output_eof(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
-
- bool password_is_read = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- };
- task.func(task, queue);
- g_assert_true(password_is_read);
- g_assert_cmpint((int)password.length, ==, 0);
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_true(epoll_set_does_not_contain(epoll_fd, pipefds[0]));
-
- g_assert_cmpint(close(pipefds[0]), ==, -1);
-}
-
-static
-void test_read_mandos_client_output_once(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- const char dummy_test_password[] = "dummy test password";
- /* Start with a pre-allocated buffer */
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {
- .data=malloc(sizeof(dummy_test_password)),
- .length=0,
- .allocated=sizeof(dummy_test_password),
- };
- g_assert_nonnull(password.data);
- if(mlock(password.data, password.allocated) != 0){
- g_assert_true(errno == EPERM or errno == ENOMEM);
- }
-
- bool password_is_read = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- g_assert_true(sizeof(dummy_test_password) <= PIPE_BUF);
- g_assert_cmpint((int)write(pipefds[1], dummy_test_password,
- sizeof(dummy_test_password)),
- ==, (int)sizeof(dummy_test_password));
-
- task_context task = {
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- };
- task.func(task, queue);
-
- g_assert_false(password_is_read);
- g_assert_cmpint((int)password.length, ==,
- (int)sizeof(dummy_test_password));
- g_assert_nonnull(password.data);
- g_assert_cmpint(memcmp(password.data, dummy_test_password,
- sizeof(dummy_test_password)), ==, 0);
-
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-}
-
-static
-void test_read_mandos_client_output_malloc(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- const char dummy_test_password[] = "dummy test password";
- /* Start with an empty buffer */
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
-
- bool password_is_read = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- g_assert_true(sizeof(dummy_test_password) <= PIPE_BUF);
- g_assert_cmpint((int)write(pipefds[1], dummy_test_password,
- sizeof(dummy_test_password)),
- ==, (int)sizeof(dummy_test_password));
-
- task_context task = {
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- };
- task.func(task, queue);
-
- g_assert_false(password_is_read);
- g_assert_cmpint((int)password.length, ==,
- (int)sizeof(dummy_test_password));
- g_assert_nonnull(password.data);
- g_assert_cmpint(memcmp(password.data, dummy_test_password,
- sizeof(dummy_test_password)), ==, 0);
-
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-}
-
-static
-void test_read_mandos_client_output_append(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- const char dummy_test_password[] = "dummy test password";
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {
- .data=malloc(PIPE_BUF),
- .length=PIPE_BUF,
- .allocated=PIPE_BUF,
- };
- g_assert_nonnull(password.data);
- if(mlock(password.data, password.allocated) != 0){
- g_assert_true(errno == EPERM or errno == ENOMEM);
- }
-
- memset(password.data, 'x', PIPE_BUF);
- char password_expected[PIPE_BUF];
- memcpy(password_expected, password.data, PIPE_BUF);
-
- bool password_is_read = false;
- bool quit_now = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- g_assert_true(sizeof(dummy_test_password) <= PIPE_BUF);
- g_assert_cmpint((int)write(pipefds[1], dummy_test_password,
- sizeof(dummy_test_password)),
- ==, (int)sizeof(dummy_test_password));
-
- task_context task = {
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- };
- task.func(task, queue);
-
- g_assert_false(password_is_read);
- g_assert_cmpint((int)password.length, ==,
- PIPE_BUF + sizeof(dummy_test_password));
- g_assert_nonnull(password.data);
- g_assert_cmpint(memcmp(password_expected, password.data, PIPE_BUF),
- ==, 0);
- g_assert_cmpint(memcmp(password.data + PIPE_BUF,
- dummy_test_password,
- sizeof(dummy_test_password)), ==, 0);
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_mandos_client_output,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .password=&password,
- .password_is_read=&password_is_read,
- .quit_now=&quit_now,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-}
-
-static char *make_temporary_directory(void);
-
-static void test_add_inotify_dir_watch(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
-
- g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, tempdir,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
-
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- const task_context *const added_read_task
- = find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .quit_now=&quit_now,
- .password=&password,
- .filename=tempdir,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- });
- g_assert_nonnull(added_read_task);
-
- g_assert_cmpint(added_read_task->fd, >, 2);
- g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
- g_assert_true(epoll_set_contains(added_read_task->epoll_fd,
- added_read_task->fd,
- EPOLLIN | EPOLLRDHUP));
-
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static char *make_temporary_directory(void){
- char *name = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(name);
- char *result = mkdtemp(name);
- if(result == NULL){
- free(name);
- }
- return result;
-}
-
-static void test_add_inotify_dir_watch_fail(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- const char nonexistent_dir[] = "/nonexistent";
-
- FILE *real_stderr = stderr;
- FILE *devnull = fopen("/dev/null", "we");
- g_assert_nonnull(devnull);
- stderr = devnull;
- g_assert_false(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, nonexistent_dir,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
- stderr = real_stderr;
- g_assert_cmpint(fclose(devnull), ==, 0);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static void test_add_inotify_dir_watch_nondir(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- const char not_a_directory[] = "/dev/tty";
-
- FILE *real_stderr = stderr;
- FILE *devnull = fopen("/dev/null", "we");
- g_assert_nonnull(devnull);
- stderr = devnull;
- g_assert_false(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, not_a_directory,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
- stderr = real_stderr;
- g_assert_cmpint(fclose(devnull), ==, 0);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static void test_add_inotify_dir_watch_EAGAIN(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
-
- g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, tempdir,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
-
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- const task_context *const added_read_task
- = find_matching_task(queue,
- (task_context){ .func=read_inotify_event });
- g_assert_nonnull(added_read_task);
-
- g_assert_cmpint(added_read_task->fd, >, 2);
- g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- struct inotify_event *ievent = malloc(ievent_size);
- g_assert_nonnull(ievent);
-
- g_assert_cmpint(read(added_read_task->fd, ievent, ievent_size), ==,
- -1);
- g_assert_cmpint(errno, ==, EAGAIN);
-
- free(ievent);
-
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static char *make_temporary_file_in_directory(const char
- *const dir);
-
-static
-void test_add_inotify_dir_watch_IN_CLOSE_WRITE(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
-
- g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, tempdir,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
-
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- const task_context *const added_read_task
- = find_matching_task(queue,
- (task_context){ .func=read_inotify_event });
- g_assert_nonnull(added_read_task);
-
- g_assert_cmpint(added_read_task->fd, >, 2);
- g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
-
- __attribute__((cleanup(cleanup_string)))
- char *filename = make_temporary_file_in_directory(tempdir);
- g_assert_nonnull(filename);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- struct inotify_event *ievent = malloc(ievent_size);
- g_assert_nonnull(ievent);
-
- ssize_t read_size = 0;
- read_size = read(added_read_task->fd, ievent, ievent_size);
-
- g_assert_cmpint((int)read_size, >, 0);
- g_assert_true(ievent->mask & IN_CLOSE_WRITE);
- g_assert_cmpstr(ievent->name, ==, basename(filename));
-
- free(ievent);
-
- g_assert_cmpint(unlink(filename), ==, 0);
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static char *make_temporary_prefixed_file_in_directory(const char
- *const prefix,
- const char
- *const dir){
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%sXXXXXX", dir, prefix),
- >, 0);
- g_assert_nonnull(filename);
- const int fd = mkostemp(filename, O_CLOEXEC);
- g_assert_cmpint(fd, >=, 0);
- g_assert_cmpint(close(fd), ==, 0);
- return filename;
-}
-
-static char *make_temporary_file_in_directory(const char
- *const dir){
- return make_temporary_prefixed_file_in_directory("temp", dir);
-}
-
-static
-void test_add_inotify_dir_watch_IN_MOVED_TO(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- __attribute__((cleanup(cleanup_string)))
- char *watchdir = make_temporary_directory();
- g_assert_nonnull(watchdir);
-
- g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, watchdir,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
-
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- const task_context *const added_read_task
- = find_matching_task(queue,
- (task_context){ .func=read_inotify_event });
- g_assert_nonnull(added_read_task);
-
- g_assert_cmpint(added_read_task->fd, >, 2);
- g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
-
- char *sourcedir = make_temporary_directory();
- g_assert_nonnull(sourcedir);
-
- __attribute__((cleanup(cleanup_string)))
- char *filename = make_temporary_file_in_directory(sourcedir);
- g_assert_nonnull(filename);
-
- __attribute__((cleanup(cleanup_string)))
- char *targetfilename = NULL;
- g_assert_cmpint(asprintf(&targetfilename, "%s/%s", watchdir,
- basename(filename)), >, 0);
- g_assert_nonnull(targetfilename);
-
- g_assert_cmpint(rename(filename, targetfilename), ==, 0);
- g_assert_cmpint(rmdir(sourcedir), ==, 0);
- free(sourcedir);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- struct inotify_event *ievent = malloc(ievent_size);
- g_assert_nonnull(ievent);
-
- ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
-
- g_assert_cmpint((int)read_size, >, 0);
- g_assert_true(ievent->mask & IN_MOVED_TO);
- g_assert_cmpstr(ievent->name, ==, basename(targetfilename));
-
- free(ievent);
-
- g_assert_cmpint(unlink(targetfilename), ==, 0);
- g_assert_cmpint(rmdir(watchdir), ==, 0);
-}
-
-static
-void test_add_inotify_dir_watch_IN_MOVED_FROM(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = make_temporary_file_in_directory(tempdir);
- g_assert_nonnull(tempfilename);
-
- __attribute__((cleanup(cleanup_string)))
- char *targetdir = make_temporary_directory();
- g_assert_nonnull(targetdir);
-
- __attribute__((cleanup(cleanup_string)))
- char *targetfilename = NULL;
- g_assert_cmpint(asprintf(&targetfilename, "%s/%s", targetdir,
- basename(tempfilename)), >, 0);
- g_assert_nonnull(targetfilename);
-
- g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, tempdir,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
-
- g_assert_cmpint(rename(tempfilename, targetfilename), ==, 0);
-
- const task_context *const added_read_task
- = find_matching_task(queue,
- (task_context){ .func=read_inotify_event });
- g_assert_nonnull(added_read_task);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- struct inotify_event *ievent = malloc(ievent_size);
- g_assert_nonnull(ievent);
-
- ssize_t read_size = read(added_read_task->fd, ievent, ievent_size);
-
- g_assert_cmpint((int)read_size, >, 0);
- g_assert_true(ievent->mask & IN_MOVED_FROM);
- g_assert_cmpstr(ievent->name, ==, basename(tempfilename));
-
- free(ievent);
-
- g_assert_cmpint(unlink(targetfilename), ==, 0);
- g_assert_cmpint(rmdir(targetdir), ==, 0);
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static
-void test_add_inotify_dir_watch_IN_DELETE(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfile = make_temporary_file_in_directory(tempdir);
- g_assert_nonnull(tempfile);
-
- g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, tempdir,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
- g_assert_cmpint(unlink(tempfile), ==, 0);
-
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- const task_context *const added_read_task
- = find_matching_task(queue,
- (task_context){ .func=read_inotify_event });
- g_assert_nonnull(added_read_task);
-
- g_assert_cmpint(added_read_task->fd, >, 2);
- g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- struct inotify_event *ievent = malloc(ievent_size);
- g_assert_nonnull(ievent);
-
- ssize_t read_size = 0;
- read_size = read(added_read_task->fd, ievent, ievent_size);
-
- g_assert_cmpint((int)read_size, >, 0);
- g_assert_true(ievent->mask & IN_DELETE);
- g_assert_cmpstr(ievent->name, ==, basename(tempfile));
-
- free(ievent);
-
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static
-void test_add_inotify_dir_watch_IN_EXCL_UNLINK(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfile = make_temporary_file_in_directory(tempdir);
- g_assert_nonnull(tempfile);
- int tempfile_fd = open(tempfile, O_WRONLY | O_CLOEXEC | O_NOCTTY
- | O_NOFOLLOW);
- g_assert_cmpint(tempfile_fd, >, 2);
-
- g_assert_true(add_inotify_dir_watch(queue, epoll_fd, &quit_now,
- &password, tempdir,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read));
- g_assert_cmpint(unlink(tempfile), ==, 0);
-
- g_assert_cmpuint((unsigned int)queue->length, >, 0);
-
- const task_context *const added_read_task
- = find_matching_task(queue,
- (task_context){ .func=read_inotify_event });
- g_assert_nonnull(added_read_task);
-
- g_assert_cmpint(added_read_task->fd, >, 2);
- g_assert_true(fd_has_cloexec_and_nonblock(added_read_task->fd));
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- struct inotify_event *ievent = malloc(ievent_size);
- g_assert_nonnull(ievent);
-
- ssize_t read_size = 0;
- read_size = read(added_read_task->fd, ievent, ievent_size);
-
- g_assert_cmpint((int)read_size, >, 0);
- g_assert_true(ievent->mask & IN_DELETE);
- g_assert_cmpstr(ievent->name, ==, basename(tempfile));
-
- g_assert_cmpint(close(tempfile_fd), ==, 0);
-
- /* IN_EXCL_UNLINK should make the closing of the previously unlinked
- file not appear as an ievent, so we should not see it now. */
- read_size = read(added_read_task->fd, ievent, ievent_size);
- g_assert_cmpint((int)read_size, ==, -1);
- g_assert_true(errno == EAGAIN);
-
- free(ievent);
-
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static void test_read_inotify_event_readerror(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const mono_microsecs current_time = 0;
-
- /* Reading /proc/self/mem from offset 0 will always result in EIO */
- const int fd = open("/proc/self/mem",
- O_RDONLY | O_CLOEXEC | O_NOCTTY);
-
- bool quit_now = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=fd,
- .quit_now=&quit_now,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames = &(string_set){},
- .notafter=0,
- .current_time=¤t_time,
- };
- g_assert_nonnull(task.filename);
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_true(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_true(epoll_set_does_not_contain(epoll_fd, fd));
-
- g_assert_cmpint(close(fd), ==, -1);
-}
-
-static void test_read_inotify_event_bad_epoll(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- const mono_microsecs current_time = 17;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
- const int epoll_fd = pipefds[0]; /* This will obviously fail */
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames = &(string_set){},
- .notafter=0,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- g_assert_nonnull(task.filename);
- run_task_with_stderr_to_dev_null(task, queue);
-
- g_assert_nonnull(find_matching_task(queue, task));
- g_assert_true(queue->next_run == 1000000 + current_time);
-
- g_assert_cmpint(close(pipefds[0]), ==, 0);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-}
-
-static void test_read_inotify_event_nodata(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames = &(string_set){},
- .notafter=0,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- g_assert_nonnull(task.filename);
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=task.cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-}
-
-static void test_read_inotify_event_eof(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames = &(string_set){},
- .notafter=0,
- .current_time=¤t_time,
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_true(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_true(epoll_set_does_not_contain(epoll_fd, pipefds[0]));
-
- g_assert_cmpint(close(pipefds[0]), ==, -1);
-}
-
-static
-void test_read_inotify_event_IN_CLOSE_WRITE(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_max_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const char dummy_file_name[] = "ask.dummy_file_name";
- ievent->mask = IN_CLOSE_WRITE;
- ievent->len = sizeof(dummy_file_name);
- memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
- const size_t ievent_size = (sizeof(struct inotify_event)
- + sizeof(dummy_file_name));
- g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
- ==, ievent_size);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames = &(string_set){},
- .notafter=0,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run != 0);
- g_assert_cmpuint((unsigned int)queue->length, >=, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=task.cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- g_assert_cmpuint((unsigned int)queue->length, >=, 2);
-
- __attribute__((cleanup(cleanup_string)))
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
- dummy_file_name), >, 0);
- g_assert_nonnull(filename);
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=open_and_parse_question,
- .epoll_fd=epoll_fd,
- .filename=filename,
- .question_filename=filename,
- .password=&password,
- .cancelled_filenames=task.cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-}
-
-static
-void test_read_inotify_event_IN_MOVED_TO(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_max_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const char dummy_file_name[] = "ask.dummy_file_name";
- ievent->mask = IN_MOVED_TO;
- ievent->len = sizeof(dummy_file_name);
- memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
- const size_t ievent_size = (sizeof(struct inotify_event)
- + sizeof(dummy_file_name));
- g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
- ==, ievent_size);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames = &(string_set){},
- .notafter=0,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run != 0);
- g_assert_cmpuint((unsigned int)queue->length, >=, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=task.cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- g_assert_cmpuint((unsigned int)queue->length, >=, 2);
-
- __attribute__((cleanup(cleanup_string)))
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
- dummy_file_name), >, 0);
- g_assert_nonnull(filename);
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=open_and_parse_question,
- .epoll_fd=epoll_fd,
- .filename=filename,
- .question_filename=filename,
- .password=&password,
- .cancelled_filenames=task.cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-}
-
-static
-void test_read_inotify_event_IN_MOVED_FROM(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_max_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const char dummy_file_name[] = "ask.dummy_file_name";
- ievent->mask = IN_MOVED_FROM;
- ievent->len = sizeof(dummy_file_name);
- memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
- const size_t ievent_size = (sizeof(struct inotify_event)
- + sizeof(dummy_file_name));
- g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
- ==, ievent_size);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- __attribute__((cleanup(cleanup_string)))
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
- dummy_file_name), >, 0);
- g_assert_nonnull(filename);
- g_assert_true(string_set_contains(*task.cancelled_filenames,
- filename));
-}
-
-static void test_read_inotify_event_IN_DELETE(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_max_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const char dummy_file_name[] = "ask.dummy_file_name";
- ievent->mask = IN_DELETE;
- ievent->len = sizeof(dummy_file_name);
- memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
- const size_t ievent_size = (sizeof(struct inotify_event)
- + sizeof(dummy_file_name));
- g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
- ==, ievent_size);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- __attribute__((cleanup(cleanup_string)))
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
- dummy_file_name), >, 0);
- g_assert_nonnull(filename);
- g_assert_true(string_set_contains(*task.cancelled_filenames,
- filename));
-}
-
-static void
-test_read_inotify_event_IN_CLOSE_WRITE_badname(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_max_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const char dummy_file_name[] = "ignored.dummy_file_name";
- ievent->mask = IN_CLOSE_WRITE;
- ievent->len = sizeof(dummy_file_name);
- memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
- const size_t ievent_size = (sizeof(struct inotify_event)
- + sizeof(dummy_file_name));
- g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
- ==, ievent_size);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames = &(string_set){},
- .notafter=0,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=task.cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-}
-
-static void
-test_read_inotify_event_IN_MOVED_TO_badname(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_max_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const char dummy_file_name[] = "ignored.dummy_file_name";
- ievent->mask = IN_MOVED_TO;
- ievent->len = sizeof(dummy_file_name);
- memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
- const size_t ievent_size = (sizeof(struct inotify_event)
- + sizeof(dummy_file_name));
- g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
- ==, ievent_size);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames = &(string_set){},
- .notafter=0,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=task.cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-}
-
-static void
-test_read_inotify_event_IN_MOVED_FROM_badname(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_max_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const char dummy_file_name[] = "ignored.dummy_file_name";
- ievent->mask = IN_MOVED_FROM;
- ievent->len = sizeof(dummy_file_name);
- memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
- const size_t ievent_size = (sizeof(struct inotify_event)
- + sizeof(dummy_file_name));
- g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
- ==, ievent_size);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- __attribute__((cleanup(cleanup_string)))
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
- dummy_file_name), >, 0);
- g_assert_nonnull(filename);
- g_assert_false(string_set_contains(cancelled_filenames, filename));
-}
-
-static
-void test_read_inotify_event_IN_DELETE_badname(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
-
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
-
- /* "sufficient to read at least one event." - inotify(7) */
- const size_t ievent_max_size = (sizeof(struct inotify_event)
- + NAME_MAX + 1);
- g_assert_cmpint(ievent_max_size, <=, PIPE_BUF);
- struct {
- struct inotify_event event;
- char name_buffer[NAME_MAX + 1];
- } ievent_buffer;
- struct inotify_event *const ievent = &ievent_buffer.event;
-
- const char dummy_file_name[] = "ignored.dummy_file_name";
- ievent->mask = IN_DELETE;
- ievent->len = sizeof(dummy_file_name);
- memcpy(ievent->name, dummy_file_name, sizeof(dummy_file_name));
- const size_t ievent_size = (sizeof(struct inotify_event)
- + sizeof(dummy_file_name));
- g_assert_cmpint(write(pipefds[1], (char *)ievent, ievent_size),
- ==, ievent_size);
- g_assert_cmpint(close(pipefds[1]), ==, 0);
-
- bool quit_now = false;
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- task_context task = {
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=strdup("/nonexistent"),
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_false(quit_now);
- g_assert_true(queue->next_run == 0);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=read_inotify_event,
- .epoll_fd=epoll_fd,
- .fd=pipefds[0],
- .quit_now=&quit_now,
- .password=&password,
- .filename=task.filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(epoll_set_contains(epoll_fd, pipefds[0],
- EPOLLIN | EPOLLRDHUP));
-
- __attribute__((cleanup(cleanup_string)))
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", task.filename,
- dummy_file_name), >, 0);
- g_assert_nonnull(filename);
- g_assert_false(string_set_contains(cancelled_filenames, filename));
-}
-
-static
-void test_open_and_parse_question_ENOENT(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- char *const filename = strdup("/nonexistent");
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=(mono_microsecs[]){0},
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static void test_open_and_parse_question_EIO(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- const mono_microsecs current_time = 0;
-
- char *filename = strdup("/proc/self/mem");
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static void
-test_open_and_parse_question_parse_error(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int tempfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(tempfile, >, 0);
- const char bad_data[] = "this is bad syntax\n";
- g_assert_cmpint(write(tempfile, bad_data, sizeof(bad_data)),
- ==, sizeof(bad_data));
- g_assert_cmpint(close(tempfile), ==, 0);
-
- char *const filename = strdup(tempfilename);
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=(mono_microsecs[]){0},
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- };
- run_task_with_stderr_to_dev_null(task, queue);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static
-void test_open_and_parse_question_nosocket(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int questionfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(questionfile, >, 0);
- FILE *qf = fdopen(questionfile, "w");
- g_assert_cmpint(fprintf(qf, "[Ask]\nPID=1\n"), >, 0);
- g_assert_cmpint(fclose(qf), ==, 0);
-
- char *const filename = strdup(tempfilename);
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=(mono_microsecs[]){0},
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static
-void test_open_and_parse_question_badsocket(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int questionfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(questionfile, >, 0);
- FILE *qf = fdopen(questionfile, "w");
- g_assert_cmpint(fprintf(qf, "[Ask]\nSocket=\nPID=1\n"), >, 0);
- g_assert_cmpint(fclose(qf), ==, 0);
-
- char *const filename = strdup(tempfilename);
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=(mono_microsecs[]){0},
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static
-void test_open_and_parse_question_nopid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int questionfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(questionfile, >, 0);
- FILE *qf = fdopen(questionfile, "w");
- g_assert_cmpint(fprintf(qf, "[Ask]\nSocket=/nonexistent\n"), >, 0);
- g_assert_cmpint(fclose(qf), ==, 0);
-
- char *const filename = strdup(tempfilename);
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=(mono_microsecs[]){0},
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static
-void test_open_and_parse_question_badpid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int questionfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(questionfile, >, 0);
- FILE *qf = fdopen(questionfile, "w");
- g_assert_cmpint(fprintf(qf, "[Ask]\nSocket=/nonexistent\nPID=\n"),
- >, 0);
- g_assert_cmpint(fclose(qf), ==, 0);
-
- char *const filename = strdup(tempfilename);
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=(mono_microsecs[]){0},
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static void
-test_open_and_parse_question_noexist_pid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- const mono_microsecs current_time = 0;
-
- /* Find value of sysctl kernel.pid_max */
- uintmax_t pid_max = 0;
- FILE *sysctl_pid_max = fopen("/proc/sys/kernel/pid_max", "r");
- g_assert_nonnull(sysctl_pid_max);
- g_assert_cmpint(fscanf(sysctl_pid_max, "%" PRIuMAX, &pid_max),
- ==, 1);
- g_assert_cmpint(fclose(sysctl_pid_max), ==, 0);
-
- pid_t nonexisting_pid = ((pid_t)pid_max)+1;
- g_assert_true(nonexisting_pid > 0); /* Overflow check */
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int questionfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(questionfile, >, 0);
- FILE *qf = fdopen(questionfile, "w");
- g_assert_cmpint(fprintf(qf, "[Ask]\nSocket=/nonexistent\nPID=%"
- PRIuMAX"\n", (uintmax_t)nonexisting_pid),
- >, 0);
- g_assert_cmpint(fclose(qf), ==, 0);
-
- char *const question_filename = strdup(tempfilename);
- g_assert_nonnull(question_filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=question_filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .filename=question_filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static void
-test_open_and_parse_question_no_notafter(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- const mono_microsecs current_time = 0;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int questionfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(questionfile, >, 0);
- FILE *qf = fdopen(questionfile, "w");
- g_assert_cmpint(fprintf(qf, "[Ask]\nSocket=/nonexistent\nPID=%"
- PRIuMAX "\n", (uintmax_t)getpid()), >, 0);
- g_assert_cmpint(fclose(qf), ==, 0);
-
- char *const filename = strdup(tempfilename);
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- __attribute__((cleanup(cleanup_string)))
- char *socket_filename = strdup("/nonexistent");
- g_assert_nonnull(socket_filename);
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=connect_question_socket,
- .question_filename=tempfilename,
- .filename=socket_filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(queue->next_run != 0);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static void
-test_open_and_parse_question_bad_notafter(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- const mono_microsecs current_time = 0;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int questionfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(questionfile, >, 0);
- FILE *qf = fdopen(questionfile, "w");
- g_assert_cmpint(fprintf(qf, "[Ask]\nSocket=/nonexistent\nPID=%"
- PRIuMAX "\nNotAfter=\n",
- (uintmax_t)getpid()), >, 0);
- g_assert_cmpint(fclose(qf), ==, 0);
-
- char *const filename = strdup(tempfilename);
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- run_task_with_stderr_to_dev_null(task, queue);
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- __attribute__((cleanup(cleanup_string)))
- char *socket_filename = strdup("/nonexistent");
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=connect_question_socket,
- .question_filename=tempfilename,
- .filename=socket_filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
- g_assert_true(queue->next_run != 0);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static
-void assert_open_and_parse_question_with_notafter(const mono_microsecs
- current_time,
- const mono_microsecs
- notafter,
- const mono_microsecs
- next_queue_run){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- queue->next_run = next_queue_run;
-
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename = strdup("/tmp/mandosXXXXXX");
- g_assert_nonnull(tempfilename);
- int questionfile = mkostemp(tempfilename, O_CLOEXEC);
- g_assert_cmpint(questionfile, >, 0);
- FILE *qf = fdopen(questionfile, "w");
- g_assert_cmpint(fprintf(qf, "[Ask]\nSocket=/nonexistent\nPID=%"
- PRIuMAX "\nNotAfter=%" PRIuMAX "\n",
- (uintmax_t)getpid(), notafter), >, 0);
- g_assert_cmpint(fclose(qf), ==, 0);
-
- char *const filename = strdup(tempfilename);
- g_assert_nonnull(filename);
- task_context task = {
- .func=open_and_parse_question,
- .question_filename=filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- };
- task.func(task, queue);
-
- if(queue->length >= 1){
- __attribute__((cleanup(cleanup_string)))
- char *socket_filename = strdup("/nonexistent");
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=connect_question_socket,
- .filename=socket_filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .current_time=¤t_time,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
- g_assert_true(queue->next_run != 0);
- }
-
- if(notafter == 0){
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
- } else if(current_time >= notafter) {
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- } else {
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=cancel_old_question,
- .question_filename=tempfilename,
- .filename=tempfilename,
- .notafter=notafter,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- }));
- }
- g_assert_true(queue->next_run == 1);
-
- g_assert_cmpint(unlink(tempfilename), ==, 0);
-}
-
-static void
-test_open_and_parse_question_notafter_0(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* current_time, notafter, next_queue_run */
- assert_open_and_parse_question_with_notafter(0, 0, 0);
-}
-
-static void
-test_open_and_parse_question_notafter_1(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* current_time, notafter, next_queue_run */
- assert_open_and_parse_question_with_notafter(0, 1, 0);
-}
-
-static void
-test_open_and_parse_question_notafter_1_1(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* current_time, notafter, next_queue_run */
- assert_open_and_parse_question_with_notafter(0, 1, 1);
-}
-
-static void
-test_open_and_parse_question_notafter_1_2(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* current_time, notafter, next_queue_run */
- assert_open_and_parse_question_with_notafter(0, 1, 2);
-}
-
-static void
-test_open_and_parse_question_equal_notafter(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* current_time, notafter, next_queue_run */
- assert_open_and_parse_question_with_notafter(1, 1, 0);
-}
-
-static void
-test_open_and_parse_question_late_notafter(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* current_time, notafter, next_queue_run */
- assert_open_and_parse_question_with_notafter(2, 1, 0);
-}
-
-static void assert_cancel_old_question_param(const mono_microsecs
- next_queue_run,
- const mono_microsecs
- notafter,
- const mono_microsecs
- current_time,
- const mono_microsecs
- next_set_to){
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- queue->next_run = next_queue_run;
-
- char *const question_filename = strdup("/nonexistent");
- g_assert_nonnull(question_filename);
- task_context task = {
- .func=cancel_old_question,
- .question_filename=question_filename,
- .filename=question_filename,
- .notafter=notafter,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- };
- task.func(task, queue);
-
- if(current_time >= notafter){
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(string_set_contains(cancelled_filenames,
- "/nonexistent"));
- } else {
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=cancel_old_question,
- .question_filename=question_filename,
- .filename=question_filename,
- .notafter=notafter,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- }));
-
- g_assert_false(string_set_contains(cancelled_filenames,
- question_filename));
- }
- g_assert_cmpuint((unsigned int)queue->next_run, ==,
- (unsigned int)next_set_to);
-}
-
-static void test_cancel_old_question_0_1_2(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* next_queue_run unset,
- cancellation should happen because time has come,
- next_queue_run should be unchanged */
- /* next_queue_run, notafter, current_time, next_set_to */
- assert_cancel_old_question_param(0, 1, 2, 0);
-}
-
-static void test_cancel_old_question_0_2_1(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* If next_queue_run is 0, meaning unset, and notafter is 2,
- and current_time is not yet notafter or greater,
- update value of next_queue_run to value of notafter */
- /* next_queue_run, notafter, current_time, next_set_to */
- assert_cancel_old_question_param(0, 2, 1, 2);
-}
-
-static void test_cancel_old_question_1_2_3(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* next_queue_run 1,
- cancellation should happen because time has come,
- next_queue_run should be unchanged */
- /* next_queue_run, notafter, current_time, next_set_to */
- assert_cancel_old_question_param(1, 2, 3, 1);
-}
-
-static void test_cancel_old_question_1_3_2(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* If next_queue_run is set,
- and current_time is not yet notafter or greater,
- and notafter is larger than next_queue_run
- next_queue_run should be unchanged */
- /* next_queue_run, notafter, current_time, next_set_to */
- assert_cancel_old_question_param(1, 3, 2, 1);
-}
-
-static void test_cancel_old_question_2_1_3(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* next_queue_run 2,
- cancellation should happen because time has come,
- next_queue_run should be unchanged */
- /* next_queue_run, notafter, current_time, next_set_to */
- assert_cancel_old_question_param(2, 1, 3, 2);
-}
-
-static void test_cancel_old_question_2_3_1(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* If next_queue_run is set,
- and current_time is not yet notafter or greater,
- and notafter is larger than next_queue_run
- next_queue_run should be unchanged */
- /* next_queue_run, notafter, current_time, next_set_to */
- assert_cancel_old_question_param(2, 3, 1, 2);
-}
-
-static void test_cancel_old_question_3_1_2(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* next_queue_run 3,
- cancellation should happen because time has come,
- next_queue_run should be unchanged */
- /* next_queue_run, notafter, current_time, next_set_to */
- assert_cancel_old_question_param(3, 1, 2, 3);
-}
-
-static void test_cancel_old_question_3_2_1(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* If next_queue_run is set,
- and current_time is not yet notafter or greater,
- and notafter is smaller than next_queue_run
- update value of next_queue_run to value of notafter */
- /* next_queue_run, notafter, current_time, next_set_to */
- assert_cancel_old_question_param(3, 2, 1, 2);
-}
-
-static void
-test_connect_question_socket_name_too_long(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const char question_filename[] = "/nonexistent/question";
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
- struct sockaddr_un unix_socket = { .sun_family=AF_LOCAL };
- char socket_name[sizeof(unix_socket.sun_path)];
- memset(socket_name, 'x', sizeof(socket_name));
- socket_name[sizeof(socket_name)-1] = '\0';
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", tempdir, socket_name),
- >, 0);
- g_assert_nonnull(filename);
-
- task_context task = {
- .func=connect_question_socket,
- .question_filename=strdup(question_filename),
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- .current_time=(mono_microsecs[]){0},
- };
- g_assert_nonnull(task.question_filename);
- run_task_with_stderr_to_dev_null(task, queue);
-
- g_assert_true(string_set_contains(cancelled_filenames,
- question_filename));
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(queue->next_run == 0);
-
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static
-void test_connect_question_socket_connect_fail(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const char question_filename[] = "/nonexistent/question";
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 3;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
- char socket_name[] = "nonexistent";
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", tempdir, socket_name),
- >, 0);
- g_assert_nonnull(filename);
-
- task_context task = {
- .func=connect_question_socket,
- .question_filename=strdup(question_filename),
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=filename,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- .current_time=¤t_time,
- };
- g_assert_nonnull(task.question_filename);
- run_task_with_stderr_to_dev_null(task, queue);
-
- g_assert_nonnull(find_matching_task(queue, task));
-
- g_assert_false(string_set_contains(cancelled_filenames,
- question_filename));
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
- g_assert_true(queue->next_run == 1000000 + current_time);
-
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static
-void test_connect_question_socket_bad_epoll(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = open("/dev/null",
- O_WRONLY | O_CLOEXEC | O_NOCTTY);
- __attribute__((cleanup(cleanup_string)))
- char *const question_filename = strdup("/nonexistent/question");
- g_assert_nonnull(question_filename);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 5;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
- __attribute__((cleanup(cleanup_close)))
- const int sock_fd = socket(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
- g_assert_cmpint(sock_fd, >=, 0);
- struct sockaddr_un sock_name = { .sun_family=AF_LOCAL };
- const char socket_name[] = "socket_name";
- __attribute__((cleanup(cleanup_string)))
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", tempdir, socket_name),
- >, 0);
- g_assert_nonnull(filename);
- g_assert_cmpint((int)strlen(filename), <,
- (int)sizeof(sock_name.sun_path));
- strncpy(sock_name.sun_path, filename, sizeof(sock_name.sun_path));
- sock_name.sun_path[sizeof(sock_name.sun_path)-1] = '\0';
- g_assert_cmpint((int)bind(sock_fd, (struct sockaddr *)&sock_name,
- (socklen_t)SUN_LEN(&sock_name)), >=, 0);
- task_context task = {
- .func=connect_question_socket,
- .question_filename=strdup(question_filename),
- .epoll_fd=epoll_fd,
- .password=(buffer[]){{}},
- .filename=strdup(filename),
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- .current_time=¤t_time,
- };
- g_assert_nonnull(task.question_filename);
- run_task_with_stderr_to_dev_null(task, queue);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
- const task_context *const added_task
- = find_matching_task(queue, task);
- g_assert_nonnull(added_task);
- g_assert_true(queue->next_run == 1000000 + current_time);
-
- g_assert_cmpint(unlink(filename), ==, 0);
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static
-void test_connect_question_socket_usable(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_string)))
- char *const question_filename = strdup("/nonexistent/question");
- g_assert_nonnull(question_filename);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- buffer password = {};
- bool mandos_client_exited = false;
- bool password_is_read = false;
- const mono_microsecs current_time = 0;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
- __attribute__((cleanup(cleanup_close)))
- const int sock_fd = socket(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
- g_assert_cmpint(sock_fd, >=, 0);
- struct sockaddr_un sock_name = { .sun_family=AF_LOCAL };
- const char socket_name[] = "socket_name";
- __attribute__((cleanup(cleanup_string)))
- char *filename = NULL;
- g_assert_cmpint(asprintf(&filename, "%s/%s", tempdir, socket_name),
- >, 0);
- g_assert_nonnull(filename);
- g_assert_cmpint((int)strlen(filename), <,
- (int)sizeof(sock_name.sun_path));
- strncpy(sock_name.sun_path, filename, sizeof(sock_name.sun_path));
- sock_name.sun_path[sizeof(sock_name.sun_path)-1] = '\0';
- g_assert_cmpint((int)bind(sock_fd, (struct sockaddr *)&sock_name,
- (socklen_t)SUN_LEN(&sock_name)), >=, 0);
- task_context task = {
- .func=connect_question_socket,
- .question_filename=strdup(question_filename),
- .epoll_fd=epoll_fd,
- .password=&password,
- .filename=strdup(filename),
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- .current_time=¤t_time,
- };
- g_assert_nonnull(task.question_filename);
- task.func(task, queue);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
- const task_context *const added_task
- = find_matching_task(queue, (task_context){
- .func=send_password_to_socket,
- .question_filename=question_filename,
- .filename=filename,
- .epoll_fd=epoll_fd,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- .current_time=¤t_time,
- });
- g_assert_nonnull(added_task);
- g_assert_cmpint(added_task->fd, >, 0);
-
- g_assert_true(epoll_set_contains(epoll_fd, added_task->fd,
- EPOLLOUT));
-
- const int fd = added_task->fd;
- g_assert_cmpint(fd, >, 0);
- g_assert_true(fd_has_cloexec_and_nonblock(fd));
-
- /* write to fd */
- char write_data[PIPE_BUF];
- {
- /* Construct test password buffer */
- /* Start with + since that is what the real procotol uses */
- write_data[0] = '+';
- /* Set a special character at string end just to mark the end */
- write_data[sizeof(write_data)-2] = 'y';
- /* Set NUL at buffer end, as suggested by the protocol */
- write_data[sizeof(write_data)-1] = '\0';
- /* Fill rest of password with 'x' */
- memset(write_data+1, 'x', sizeof(write_data)-3);
- g_assert_cmpint((int)send(fd, write_data, sizeof(write_data),
- MSG_NOSIGNAL), ==, sizeof(write_data));
- }
-
- /* read from sock_fd */
- char read_data[sizeof(write_data)];
- g_assert_cmpint((int)read(sock_fd, read_data, sizeof(read_data)),
- ==, sizeof(read_data));
-
- g_assert_true(memcmp(write_data, read_data, sizeof(write_data))
- == 0);
-
- /* writing to sock_fd should fail */
- g_assert_cmpint(send(sock_fd, write_data, sizeof(write_data),
- MSG_NOSIGNAL), <, 0);
-
- /* reading from fd should fail */
- g_assert_cmpint((int)recv(fd, read_data, sizeof(read_data),
- MSG_NOSIGNAL), <, 0);
-
- g_assert_cmpint(unlink(filename), ==, 0);
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static void
-test_send_password_to_socket_client_not_exited(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_string)))
- char *const question_filename = strdup("/nonexistent/question");
- g_assert_nonnull(question_filename);
- __attribute__((cleanup(cleanup_string)))
- char *const filename = strdup("/nonexistent/socket");
- g_assert_nonnull(filename);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- buffer password = {};
- bool password_is_read = true;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- int socketfds[2];
- g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
- socketfds), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_socket = socketfds[0];
- const int write_socket = socketfds[1];
- task_context task = {
- .func=send_password_to_socket,
- .question_filename=strdup(question_filename),
- .filename=strdup(filename),
- .epoll_fd=epoll_fd,
- .fd=write_socket,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){false},
- .password_is_read=&password_is_read,
- .current_time=(mono_microsecs[]){0},
- };
- g_assert_nonnull(task.question_filename);
-
- task.func(task, queue);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- const task_context *const added_task
- = find_matching_task(queue, task);
- g_assert_nonnull(added_task);
- g_assert_cmpuint((unsigned int)password.length, ==, 0);
- g_assert_true(password_is_read);
-
- g_assert_cmpint(added_task->fd, >, 0);
- g_assert_true(epoll_set_contains(epoll_fd, added_task->fd,
- EPOLLOUT));
-}
-
-static void
-test_send_password_to_socket_password_not_read(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_string)))
- char *const question_filename = strdup("/nonexistent/question");
- g_assert_nonnull(question_filename);
- __attribute__((cleanup(cleanup_string)))
- char *const filename = strdup("/nonexistent/socket");
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- buffer password = {};
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- int socketfds[2];
- g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
- socketfds), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_socket = socketfds[0];
- const int write_socket = socketfds[1];
- task_context task = {
- .func=send_password_to_socket,
- .question_filename=strdup(question_filename),
- .filename=strdup(filename),
- .epoll_fd=epoll_fd,
- .fd=write_socket,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){false},
- .password_is_read=(bool[]){false},
- .current_time=(mono_microsecs[]){0},
- };
- g_assert_nonnull(task.question_filename);
-
- task.func(task, queue);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- const task_context *const added_task = find_matching_task(queue,
- task);
- g_assert_nonnull(added_task);
- g_assert_cmpuint((unsigned int)password.length, ==, 0);
- g_assert_true(queue->next_run == 0);
-
- g_assert_cmpint(added_task->fd, >, 0);
- g_assert_true(epoll_set_contains(epoll_fd, added_task->fd,
- EPOLLOUT));
-}
-
-static
-void test_send_password_to_socket_EMSGSIZE(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- const char question_filename[] = "/nonexistent/question";
- char *const filename = strdup("/nonexistent/socket");
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const size_t oversized = 1024*1024; /* Limit seems to be 212960 */
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {
- .data=malloc(oversized),
- .length=oversized,
- .allocated=oversized,
- };
- g_assert_nonnull(password.data);
- if(mlock(password.data, password.allocated) != 0){
- g_assert_true(errno == EPERM or errno == ENOMEM);
- }
- /* Construct test password buffer */
- /* Start with + since that is what the real procotol uses */
- password.data[0] = '+';
- /* Set a special character at string end just to mark the end */
- password.data[oversized-3] = 'y';
- /* Set NUL at buffer end, as suggested by the protocol */
- password.data[oversized-2] = '\0';
- /* Fill rest of password with 'x' */
- memset(password.data+1, 'x', oversized-3);
-
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- int socketfds[2];
- g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
- socketfds), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_socket = socketfds[0];
- __attribute__((cleanup(cleanup_close)))
- const int write_socket = socketfds[1];
- task_context task = {
- .func=send_password_to_socket,
- .question_filename=strdup(question_filename),
- .filename=filename,
- .epoll_fd=epoll_fd,
- .fd=write_socket,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){true},
- .password_is_read=(bool[]){true},
- .current_time=(mono_microsecs[]){0},
- };
- g_assert_nonnull(task.question_filename);
-
- run_task_with_stderr_to_dev_null(task, queue);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
- g_assert_true(string_set_contains(cancelled_filenames,
- question_filename));
-}
-
-static void test_send_password_to_socket_retry(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_string)))
- char *const question_filename = strdup("/nonexistent/question");
- g_assert_nonnull(question_filename);
- __attribute__((cleanup(cleanup_string)))
- char *const filename = strdup("/nonexistent/socket");
- g_assert_nonnull(filename);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
-
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- int socketfds[2];
- g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
- socketfds), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_socket = socketfds[0];
- const int write_socket = socketfds[1];
- /* Close the server side socket to force ECONNRESET on client */
- g_assert_cmpint(close(read_socket), ==, 0);
- task_context task = {
- .func=send_password_to_socket,
- .question_filename=strdup(question_filename),
- .filename=strdup(filename),
- .epoll_fd=epoll_fd,
- .fd=write_socket,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){true},
- .password_is_read=(bool[]){true},
- .current_time=(mono_microsecs[]){0},
- };
- g_assert_nonnull(task.question_filename);
-
- task.func(task, queue);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- const task_context *const added_task = find_matching_task(queue,
- task);
- g_assert_nonnull(added_task);
- g_assert_cmpuint((unsigned int)password.length, ==, 0);
-
- g_assert_true(epoll_set_contains(epoll_fd, added_task->fd,
- EPOLLOUT));
-}
-
-static
-void test_send_password_to_socket_bad_epoll(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = open("/dev/null",
- O_WRONLY | O_CLOEXEC | O_NOCTTY);
- __attribute__((cleanup(cleanup_string)))
- char *const question_filename = strdup("/nonexistent/question");
- g_assert_nonnull(question_filename);
- __attribute__((cleanup(cleanup_string)))
- char *const filename = strdup("/nonexistent/socket");
- g_assert_nonnull(filename);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
-
- const mono_microsecs current_time = 11;
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- int socketfds[2];
- g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
- socketfds), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_socket = socketfds[0];
- const int write_socket = socketfds[1];
- /* Close the server side socket to force ECONNRESET on client */
- g_assert_cmpint(close(read_socket), ==, 0);
- task_context task = {
- .func=send_password_to_socket,
- .question_filename=strdup(question_filename),
- .filename=strdup(filename),
- .epoll_fd=epoll_fd,
- .fd=write_socket,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){true},
- .password_is_read=(bool[]){true},
- .current_time=¤t_time,
- };
- g_assert_nonnull(task.question_filename);
-
- run_task_with_stderr_to_dev_null(task, queue);
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- const task_context *const added_task = find_matching_task(queue,
- task);
- g_assert_nonnull(added_task);
- g_assert_true(queue->next_run == current_time + 1000000);
- g_assert_cmpuint((unsigned int)password.length, ==, 0);
-}
-
-static void assert_send_password_to_socket_password(buffer password){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- char *const question_filename = strdup("/nonexistent/question");
- g_assert_nonnull(question_filename);
- char *const filename = strdup("/nonexistent/socket");
- g_assert_nonnull(filename);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
-
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- int socketfds[2];
- g_assert_cmpint(socketpair(PF_LOCAL, SOCK_DGRAM
- | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
- socketfds), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_socket = socketfds[0];
- const int write_socket = socketfds[1];
- task_context task = {
- .func=send_password_to_socket,
- .question_filename=question_filename,
- .filename=filename,
- .epoll_fd=epoll_fd,
- .fd=write_socket,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .mandos_client_exited=(bool[]){true},
- .password_is_read=(bool[]){true},
- .current_time=(mono_microsecs[]){0},
- };
-
- char *expected_written_data = malloc(password.length + 2);
- g_assert_nonnull(expected_written_data);
- expected_written_data[0] = '+';
- expected_written_data[password.length + 1] = '\0';
- if(password.length > 0){
- g_assert_nonnull(password.data);
- memcpy(expected_written_data + 1, password.data, password.length);
- }
-
- task.func(task, queue);
-
- char buf[PIPE_BUF];
- g_assert_cmpint((int)read(read_socket, buf, PIPE_BUF), ==,
- (int)(password.length + 2));
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_true(memcmp(expected_written_data, buf,
- password.length + 2) == 0);
-
- g_assert_true(epoll_set_does_not_contain(epoll_fd, write_socket));
-
- free(expected_written_data);
-}
-
-static void
-test_send_password_to_socket_null_password(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- assert_send_password_to_socket_password(password);
-}
-
-static void
-test_send_password_to_socket_empty_password(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {
- .data=malloc(1), /* because malloc(0) may return NULL */
- .length=0,
- .allocated=0, /* deliberate lie */
- };
- g_assert_nonnull(password.data);
- assert_send_password_to_socket_password(password);
-}
-
-static void
-test_send_password_to_socket_empty_str_pass(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {
- .data=strdup(""),
- .length=0,
- .allocated=1,
- };
- if(mlock(password.data, password.allocated) != 0){
- g_assert_true(errno == EPERM or errno == ENOMEM);
- }
- assert_send_password_to_socket_password(password);
-}
-
-static void
-test_send_password_to_socket_text_password(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- const char dummy_test_password[] = "dummy test password";
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {
- .data = strdup(dummy_test_password),
- .length = strlen(dummy_test_password),
- .allocated = sizeof(dummy_test_password),
- };
- if(mlock(password.data, password.allocated) != 0){
- g_assert_true(errno == EPERM or errno == ENOMEM);
- }
- assert_send_password_to_socket_password(password);
-}
-
-static void
-test_send_password_to_socket_binary_password(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {
- .data=malloc(255),
- .length=255,
- .allocated=255,
- };
- g_assert_nonnull(password.data);
- if(mlock(password.data, password.allocated) != 0){
- g_assert_true(errno == EPERM or errno == ENOMEM);
- }
- char c = 1; /* Start at 1, avoiding NUL */
- for(int i=0; i < 255; i++){
- password.data[i] = c++;
- }
- assert_send_password_to_socket_password(password);
-}
-
-static void
-test_send_password_to_socket_nuls_in_password(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- char test_password[] = {'\0', 'a', '\0', 'b', '\0', 'c', '\0'};
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {
- .data=malloc(sizeof(test_password)),
- .length=sizeof(test_password),
- .allocated=sizeof(test_password),
- };
- g_assert_nonnull(password.data);
- if(mlock(password.data, password.allocated) !=0){
- g_assert_true(errno == EPERM or errno == ENOMEM);
- }
- memcpy(password.data, test_password, password.allocated);
- assert_send_password_to_socket_password(password);
-}
-
-static bool assert_add_existing_questions_to_devnull(task_queue
- *const,
- const int,
- buffer *const,
- string_set *,
- const
- mono_microsecs
- *const,
- bool *const,
- bool *const,
- const char
- *const);
-
-static void test_add_existing_questions_ENOENT(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
-
- g_assert_false(assert_add_existing_questions_to_devnull
- (queue,
- epoll_fd,
- (buffer[]){{}}, /* password */
- &cancelled_filenames,
- (mono_microsecs[]){0}, /* current_time */
- (bool[]){false}, /* mandos_client_exited */
- (bool[]){false}, /* password_is_read */
- "/nonexistent")); /* dirname */
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-}
-
-static
-bool assert_add_existing_questions_to_devnull(task_queue
- *const queue,
- const int
- epoll_fd,
- buffer *const
- password,
- string_set
- *cancelled_filenames,
- const mono_microsecs
- *const current_time,
- bool *const
- mandos_client_exited,
- bool *const
- password_is_read,
- const char *const
- dirname){
- __attribute__((cleanup(cleanup_close)))
- const int devnull_fd = open("/dev/null",
- O_WRONLY | O_CLOEXEC | O_NOCTTY);
- g_assert_cmpint(devnull_fd, >=, 0);
- __attribute__((cleanup(cleanup_close)))
- const int real_stderr_fd = dup(STDERR_FILENO);
- g_assert_cmpint(real_stderr_fd, >=, 0);
- dup2(devnull_fd, STDERR_FILENO);
- const bool ret = add_existing_questions(queue, epoll_fd, password,
- cancelled_filenames,
- current_time,
- mandos_client_exited,
- password_is_read, dirname);
- dup2(real_stderr_fd, STDERR_FILENO);
- return ret;
-}
-
-static
-void test_add_existing_questions_no_questions(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
-
- g_assert_false(assert_add_existing_questions_to_devnull
- (queue,
- epoll_fd,
- (buffer[]){{}}, /* password */
- &cancelled_filenames,
- (mono_microsecs[]){0}, /* current_time */
- (bool[]){false}, /* mandos_client_exited */
- (bool[]){false}, /* password_is_read */
- tempdir));
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static char *make_question_file_in_directory(const char *const);
-
-static
-void test_add_existing_questions_one_question(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
- __attribute__((cleanup(cleanup_string)))
- char *question_filename
- = make_question_file_in_directory(tempdir);
- g_assert_nonnull(question_filename);
-
- g_assert_true(assert_add_existing_questions_to_devnull
- (queue,
- epoll_fd,
- &password,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read,
- tempdir));
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=open_and_parse_question,
- .epoll_fd=epoll_fd,
- .filename=question_filename,
- .question_filename=question_filename,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(queue->next_run == 1);
-
- g_assert_cmpint(unlink(question_filename), ==, 0);
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static char *make_question_file_in_directory(const char
- *const dir){
- return make_temporary_prefixed_file_in_directory("ask.", dir);
-}
-
-static
-void test_add_existing_questions_two_questions(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
- __attribute__((cleanup(cleanup_string)))
- char *question_filename1
- = make_question_file_in_directory(tempdir);
- g_assert_nonnull(question_filename1);
- __attribute__((cleanup(cleanup_string)))
- char *question_filename2
- = make_question_file_in_directory(tempdir);
- g_assert_nonnull(question_filename2);
-
- g_assert_true(assert_add_existing_questions_to_devnull
- (queue,
- epoll_fd,
- &password,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read,
- tempdir));
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 2);
-
- g_assert_true(queue->next_run == 1);
-
- __attribute__((cleanup(string_set_clear)))
- string_set seen_questions = {};
-
- bool queue_contains_question_opener(char *const question_filename){
- return(find_matching_task(queue, (task_context){
- .func=open_and_parse_question,
- .epoll_fd=epoll_fd,
- .question_filename=question_filename,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }) != NULL);
- }
-
- g_assert_true(queue_contains_question_opener(question_filename1));
- g_assert_true(queue_contains_question_opener(question_filename2));
-
- g_assert_true(queue->next_run == 1);
-
- g_assert_cmpint(unlink(question_filename1), ==, 0);
- g_assert_cmpint(unlink(question_filename2), ==, 0);
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static void
-test_add_existing_questions_non_questions(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
- __attribute__((cleanup(cleanup_string)))
- char *question_filename1
- = make_temporary_file_in_directory(tempdir);
- g_assert_nonnull(question_filename1);
- __attribute__((cleanup(cleanup_string)))
- char *question_filename2
- = make_temporary_file_in_directory(tempdir);
- g_assert_nonnull(question_filename2);
-
- g_assert_false(assert_add_existing_questions_to_devnull
- (queue,
- epoll_fd,
- (buffer[]){{}}, /* password */
- &cancelled_filenames,
- (mono_microsecs[]){0}, /* current_time */
- (bool[]){false}, /* mandos_client_exited */
- (bool[]){false}, /* password_is_read */
- tempdir));
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 0);
-
- g_assert_cmpint(unlink(question_filename1), ==, 0);
- g_assert_cmpint(unlink(question_filename2), ==, 0);
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static void
-test_add_existing_questions_both_types(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- __attribute__((cleanup(cleanup_buffer)))
- buffer password = {};
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- const mono_microsecs current_time = 0;
- bool mandos_client_exited = false;
- bool password_is_read = false;
- __attribute__((cleanup(cleanup_string)))
- char *tempdir = make_temporary_directory();
- g_assert_nonnull(tempdir);
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename1 = make_temporary_file_in_directory(tempdir);
- g_assert_nonnull(tempfilename1);
- __attribute__((cleanup(cleanup_string)))
- char *tempfilename2 = make_temporary_file_in_directory(tempdir);
- g_assert_nonnull(tempfilename2);
- __attribute__((cleanup(cleanup_string)))
- char *question_filename
- = make_question_file_in_directory(tempdir);
- g_assert_nonnull(question_filename);
-
- g_assert_true(assert_add_existing_questions_to_devnull
- (queue,
- epoll_fd,
- &password,
- &cancelled_filenames,
- ¤t_time,
- &mandos_client_exited,
- &password_is_read,
- tempdir));
-
- g_assert_cmpuint((unsigned int)queue->length, ==, 1);
-
- g_assert_nonnull(find_matching_task(queue, (task_context){
- .func=open_and_parse_question,
- .epoll_fd=epoll_fd,
- .filename=question_filename,
- .question_filename=question_filename,
- .password=&password,
- .cancelled_filenames=&cancelled_filenames,
- .current_time=¤t_time,
- .mandos_client_exited=&mandos_client_exited,
- .password_is_read=&password_is_read,
- }));
-
- g_assert_true(queue->next_run == 1);
-
- g_assert_cmpint(unlink(tempfilename1), ==, 0);
- g_assert_cmpint(unlink(tempfilename2), ==, 0);
- g_assert_cmpint(unlink(question_filename), ==, 0);
- g_assert_cmpint(rmdir(tempdir), ==, 0);
-}
-
-static void test_wait_for_event_timeout(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
-
- g_assert_true(wait_for_event(epoll_fd, 1, 0));
-}
-
-static void test_wait_for_event_event(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_pipe = pipefds[0];
- __attribute__((cleanup(cleanup_close)))
- const int write_pipe = pipefds[1];
- g_assert_cmpint(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, read_pipe,
- &(struct epoll_event)
- { .events=EPOLLIN | EPOLLRDHUP }), ==, 0);
- g_assert_cmpint((int)write(write_pipe, "x", 1), ==, 1);
-
- g_assert_true(wait_for_event(epoll_fd, 0, 0));
-}
-
-static void test_wait_for_event_sigchld(test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- const pid_t pid = fork();
- if(pid == 0){ /* Child */
- if(not restore_signal_handler(&fixture->orig_sigaction)){
- _exit(EXIT_FAILURE);
- }
- if(not restore_sigmask(&fixture->orig_sigmask)){
- _exit(EXIT_FAILURE);
- }
- exit(EXIT_SUCCESS);
- }
- g_assert_true(pid != -1);
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- g_assert_cmpint(epoll_fd, >=, 0);
-
- g_assert_true(wait_for_event(epoll_fd, 0, 0));
-
- int status;
- g_assert_true(waitpid(pid, &status, 0) == pid);
- g_assert_true(WIFEXITED(status));
- g_assert_cmpint(WEXITSTATUS(status), ==, EXIT_SUCCESS);
-}
-
-static void test_run_queue_zeroes_next_run(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- queue->next_run = 1;
- __attribute__((cleanup(cleanup_close)))
- const int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- bool quit_now = false;
-
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)queue->next_run, ==, 0);
-}
-
-static
-void test_run_queue_clears_cancelled_filenames(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- bool quit_now = false;
- const char question_filename[] = "/nonexistent/question_filename";
- g_assert_true(string_set_add(&cancelled_filenames,
- question_filename));
-
- g_assert_true(add_to_queue(queue,
- (task_context){ .func=dummy_func }));
-
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)(queue->length), ==, 0);
- g_assert_false(string_set_contains(cancelled_filenames,
- question_filename));
-}
-
-static
-void test_run_queue_skips_cancelled_filenames(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- bool quit_now = false;
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_pipe = pipefds[0];
- g_assert_cmpint(close(pipefds[1]), ==, 0);
- const char question_filename[] = "/nonexistent/question_filename";
- g_assert_true(string_set_add(&cancelled_filenames,
- question_filename));
- __attribute__((nonnull))
- void quit_func(const task_context task,
- __attribute__((unused)) task_queue *const q){
- g_assert_nonnull(task.quit_now);
- *task.quit_now = true;
- }
- task_context task = {
- .func=quit_func,
- .question_filename=strdup(question_filename),
- .quit_now=&quit_now,
- .fd=read_pipe,
- };
- g_assert_nonnull(task.question_filename);
-
- g_assert_true(add_to_queue(queue, task));
-
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_false(quit_now);
-
- /* read_pipe should be closed already */
- errno = 0;
- bool read_pipe_closed = (close(read_pipe) == -1);
- read_pipe_closed &= (errno == EBADF);
- g_assert_true(read_pipe_closed);
-}
-
-static void test_run_queue_one_task(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- bool quit_now = false;
-
- __attribute__((nonnull))
- void next_run_func(__attribute__((unused))
- const task_context task,
- task_queue *const q){
- q->next_run = 1;
- }
-
- task_context task = {
- .func=next_run_func,
- };
- g_assert_true(add_to_queue(queue, task));
-
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_cmpuint((unsigned int)(queue->next_run), ==, 1);
- g_assert_cmpuint((unsigned int)(queue->length), ==, 0);
-}
-
-static void test_run_queue_two_tasks(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- queue->next_run = 1;
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- bool quit_now = false;
- bool mandos_client_exited = false;
-
- __attribute__((nonnull))
- void next_run_func(__attribute__((unused))
- const task_context task,
- task_queue *const q){
- q->next_run = 1;
- }
-
- __attribute__((nonnull))
- void exited_func(const task_context task,
- __attribute__((unused)) task_queue *const q){
- *task.mandos_client_exited = true;
- }
-
- task_context task1 = {
- .func=next_run_func,
- };
- g_assert_true(add_to_queue(queue, task1));
-
- task_context task2 = {
- .func=exited_func,
- .mandos_client_exited=&mandos_client_exited,
- };
- g_assert_true(add_to_queue(queue, task2));
-
- g_assert_true(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_false(quit_now);
- g_assert_cmpuint((unsigned int)(queue->next_run), ==, 1);
- g_assert_true(mandos_client_exited);
- g_assert_cmpuint((unsigned int)(queue->length), ==, 0);
-}
-
-static void test_run_queue_two_tasks_quit(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- bool quit_now = false;
- bool mandos_client_exited = false;
- bool password_is_read = false;
-
- __attribute__((nonnull))
- void set_exited_func(const task_context task,
- __attribute__((unused)) task_queue *const q){
- *task.mandos_client_exited = true;
- *task.quit_now = true;
- }
- task_context task1 = {
- .func=set_exited_func,
- .quit_now=&quit_now,
- .mandos_client_exited=&mandos_client_exited,
- };
- g_assert_true(add_to_queue(queue, task1));
-
- __attribute__((nonnull))
- void set_read_func(const task_context task,
- __attribute__((unused)) task_queue *const q){
- *task.quit_now = true;
- *task.password_is_read = true;
- }
- task_context task2 = {
- .func=set_read_func,
- .quit_now=&quit_now,
- .password_is_read=&password_is_read,
- };
- g_assert_true(add_to_queue(queue, task2));
-
- g_assert_false(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(quit_now);
- g_assert_true(mandos_client_exited xor password_is_read);
- g_assert_cmpuint((unsigned int)(queue->length), ==, 0);
-}
-
-static void test_run_queue_two_tasks_cleanup(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- __attribute__((cleanup(cleanup_queue)))
- task_queue *queue = create_queue();
- g_assert_nonnull(queue);
- __attribute__((cleanup(string_set_clear)))
- string_set cancelled_filenames = {};
- int pipefds[2];
- g_assert_cmpint(pipe2(pipefds, O_CLOEXEC | O_NONBLOCK), ==, 0);
- __attribute__((cleanup(cleanup_close)))
- const int read_pipe = pipefds[0];
- __attribute__((cleanup(cleanup_close)))
- const int write_pipe = pipefds[1];
- bool quit_now = false;
-
- __attribute__((nonnull))
- void read_func(const task_context task,
- __attribute__((unused)) task_queue *const q){
- *task.quit_now = true;
- }
- task_context task1 = {
- .func=read_func,
- .quit_now=&quit_now,
- .fd=read_pipe,
- };
- g_assert_true(add_to_queue(queue, task1));
-
- __attribute__((nonnull))
- void write_func(const task_context task,
- __attribute__((unused)) task_queue *const q){
- *task.quit_now = true;
- }
- task_context task2 = {
- .func=write_func,
- .quit_now=&quit_now,
- .fd=write_pipe,
- };
- g_assert_true(add_to_queue(queue, task2));
-
- g_assert_false(run_queue(&queue, &cancelled_filenames, &quit_now));
- g_assert_true(quit_now);
-
- /* Either read_pipe or write_pipe should be closed already */
- errno = 0;
- bool close_read_pipe = (close(read_pipe) == -1);
- close_read_pipe &= (errno == EBADF);
- errno = 0;
- bool close_write_pipe = (close(write_pipe) == -1);
- close_write_pipe &= (errno == EBADF);
- g_assert_true(close_read_pipe xor close_write_pipe);
- g_assert_cmpuint((unsigned int)(queue->length), ==, 0);
-}
-
-static void test_setup_signal_handler(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* Save current SIGCHLD action, whatever it is */
- struct sigaction expected_sigchld_action;
- g_assert_cmpint(sigaction(SIGCHLD, NULL, &expected_sigchld_action),
- ==, 0);
-
- /* Act; i.e. run the setup_signal_handler() function */
- struct sigaction actual_old_sigchld_action;
- g_assert_true(setup_signal_handler(&actual_old_sigchld_action));
-
- /* Check that the function correctly set "actual_old_sigchld_action"
- to the same values as the previously saved
- "expected_sigchld_action" */
- /* Check member sa_handler */
- g_assert_true(actual_old_sigchld_action.sa_handler
- == expected_sigchld_action.sa_handler);
- /* Check member sa_mask */
- for(int signum = 1; signum < NSIG; signum++){
- const int expected_old_block_state
- = sigismember(&expected_sigchld_action.sa_mask, signum);
- g_assert_cmpint(expected_old_block_state, >=, 0);
- const int actual_old_block_state
- = sigismember(&actual_old_sigchld_action.sa_mask, signum);
- g_assert_cmpint(actual_old_block_state, >=, 0);
- g_assert_cmpint(actual_old_block_state,
- ==, expected_old_block_state);
- }
- /* Check member sa_flags */
- g_assert_true((actual_old_sigchld_action.sa_flags
- & (SA_NOCLDSTOP | SA_ONSTACK | SA_RESTART))
- == (expected_sigchld_action.sa_flags
- & (SA_NOCLDSTOP | SA_ONSTACK | SA_RESTART)));
-
- /* Retrieve the current signal handler for SIGCHLD as set by
- setup_signal_handler() */
- struct sigaction actual_new_sigchld_action;
- g_assert_cmpint(sigaction(SIGCHLD, NULL,
- &actual_new_sigchld_action), ==, 0);
- /* Check that the signal handler (member sa_handler) is correctly
- set to the "handle_sigchld" function */
- g_assert_true(actual_new_sigchld_action.sa_handler != SIG_DFL);
- g_assert_true(actual_new_sigchld_action.sa_handler != SIG_IGN);
- g_assert_true(actual_new_sigchld_action.sa_handler
- == handle_sigchld);
- /* Check (in member sa_mask) that at least a handful of signals are
- actually blocked during the signal handler */
- for(int signum = 1; signum < NSIG; signum++){
- int actual_new_block_state;
- switch(signum){
- case SIGTERM:
- case SIGINT:
- case SIGQUIT:
- case SIGHUP:
- actual_new_block_state
- = sigismember(&actual_new_sigchld_action.sa_mask, signum);
- g_assert_cmpint(actual_new_block_state, ==, 1);
- continue;
- case SIGKILL: /* non-blockable */
- case SIGSTOP: /* non-blockable */
- case SIGCHLD: /* always blocked */
- default:
- continue;
- }
- }
- /* Check member sa_flags */
- g_assert_true((actual_new_sigchld_action.sa_flags
- & (SA_NOCLDSTOP | SA_ONSTACK | SA_RESTART))
- == (SA_NOCLDSTOP | SA_RESTART));
-
- /* Restore signal handler */
- g_assert_cmpint(sigaction(SIGCHLD, &expected_sigchld_action, NULL),
- ==, 0);
-}
-
-static void test_restore_signal_handler(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* Save current SIGCHLD action, whatever it is */
- struct sigaction expected_sigchld_action;
- g_assert_cmpint(sigaction(SIGCHLD, NULL, &expected_sigchld_action),
- ==, 0);
- /* Since we haven't established a signal handler yet, there should
- not be one established. But another test may have relied on
- restore_signal_handler() to restore the signal handler, and if
- restore_signal_handler() is buggy (which we should be prepared
- for in this test) the signal handler may not have been restored
- properly; check for this: */
- g_assert_true(expected_sigchld_action.sa_handler != handle_sigchld);
-
- /* Establish a signal handler */
- struct sigaction sigchld_action = {
- .sa_handler=handle_sigchld,
- .sa_flags=SA_RESTART | SA_NOCLDSTOP,
- };
- g_assert_cmpint(sigfillset(&sigchld_action.sa_mask), ==, 0);
- g_assert_cmpint(sigaction(SIGCHLD, &sigchld_action, NULL), ==, 0);
-
- /* Act; i.e. run the restore_signal_handler() function */
- g_assert_true(restore_signal_handler(&expected_sigchld_action));
-
- /* Retrieve the restored signal handler data */
- struct sigaction actual_restored_sigchld_action;
- g_assert_cmpint(sigaction(SIGCHLD, NULL,
- &actual_restored_sigchld_action), ==, 0);
-
- /* Check that the function correctly restored the signal action, as
- saved in "actual_restored_sigchld_action", to the same values as
- the previously saved "expected_sigchld_action" */
- /* Check member sa_handler */
- g_assert_true(actual_restored_sigchld_action.sa_handler
- == expected_sigchld_action.sa_handler);
- /* Check member sa_mask */
- for(int signum = 1; signum < NSIG; signum++){
- const int expected_old_block_state
- = sigismember(&expected_sigchld_action.sa_mask, signum);
- g_assert_cmpint(expected_old_block_state, >=, 0);
- const int actual_restored_block_state
- = sigismember(&actual_restored_sigchld_action.sa_mask, signum);
- g_assert_cmpint(actual_restored_block_state, >=, 0);
- g_assert_cmpint(actual_restored_block_state,
- ==, expected_old_block_state);
- }
- /* Check member sa_flags */
- g_assert_true((actual_restored_sigchld_action.sa_flags
- & (SA_NOCLDSTOP | SA_ONSTACK | SA_RESTART))
- == (expected_sigchld_action.sa_flags
- & (SA_NOCLDSTOP | SA_ONSTACK | SA_RESTART)));
-}
-
-static void test_block_sigchld(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* Save original signal mask */
- sigset_t expected_sigmask;
- g_assert_cmpint(pthread_sigmask(-1, NULL, &expected_sigmask),
- ==, 0);
-
- /* Make sure SIGCHLD is unblocked for this test */
- sigset_t sigchld_sigmask;
- g_assert_cmpint(sigemptyset(&sigchld_sigmask), ==, 0);
- g_assert_cmpint(sigaddset(&sigchld_sigmask, SIGCHLD), ==, 0);
- g_assert_cmpint(pthread_sigmask(SIG_UNBLOCK, &sigchld_sigmask,
- NULL), ==, 0);
-
- /* Act; i.e. run the block_sigchld() function */
- sigset_t actual_old_sigmask;
- g_assert_true(block_sigchld(&actual_old_sigmask));
-
- /* Check the actual_old_sigmask; it should be the same as the
- previously saved signal mask "expected_sigmask". */
- for(int signum = 1; signum < NSIG; signum++){
- const int expected_old_block_state
- = sigismember(&expected_sigmask, signum);
- g_assert_cmpint(expected_old_block_state, >=, 0);
- const int actual_old_block_state
- = sigismember(&actual_old_sigmask, signum);
- g_assert_cmpint(actual_old_block_state, >=, 0);
- g_assert_cmpint(actual_old_block_state,
- ==, expected_old_block_state);
- }
-
- /* Retrieve the newly set signal mask */
- sigset_t actual_sigmask;
- g_assert_cmpint(pthread_sigmask(-1, NULL, &actual_sigmask), ==, 0);
-
- /* SIGCHLD should be blocked */
- g_assert_cmpint(sigismember(&actual_sigmask, SIGCHLD), ==, 1);
-
- /* Restore signal mask */
- g_assert_cmpint(pthread_sigmask(SIG_SETMASK, &expected_sigmask,
- NULL), ==, 0);
-}
-
-static void test_restore_sigmask(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- /* Save original signal mask */
- sigset_t orig_sigmask;
- g_assert_cmpint(pthread_sigmask(-1, NULL, &orig_sigmask), ==, 0);
-
- /* Make sure SIGCHLD is blocked for this test */
- sigset_t sigchld_sigmask;
- g_assert_cmpint(sigemptyset(&sigchld_sigmask), ==, 0);
- g_assert_cmpint(sigaddset(&sigchld_sigmask, SIGCHLD), ==, 0);
- g_assert_cmpint(pthread_sigmask(SIG_BLOCK, &sigchld_sigmask,
- NULL), ==, 0);
-
- /* Act; i.e. run the restore_sigmask() function */
- g_assert_true(restore_sigmask(&orig_sigmask));
-
- /* Retrieve the newly restored signal mask */
- sigset_t restored_sigmask;
- g_assert_cmpint(pthread_sigmask(-1, NULL, &restored_sigmask),
- ==, 0);
-
- /* Check the restored_sigmask; it should be the same as the
- previously saved signal mask "orig_sigmask". */
- for(int signum = 1; signum < NSIG; signum++){
- const int orig_block_state = sigismember(&orig_sigmask, signum);
- g_assert_cmpint(orig_block_state, >=, 0);
- const int restored_block_state = sigismember(&restored_sigmask,
- signum);
- g_assert_cmpint(restored_block_state, >=, 0);
- g_assert_cmpint(restored_block_state, ==, orig_block_state);
- }
-
- /* Restore signal mask */
- g_assert_cmpint(pthread_sigmask(SIG_SETMASK, &orig_sigmask,
- NULL), ==, 0);
-}
-
-static void test_parse_arguments_noargs(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
- g_assert_null(agent_directory);
- g_assert_null(helper_directory);
- g_assert_true(user == 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-__attribute__((nonnull))
-static bool parse_arguments_devnull(int argc, char *argv[],
- const bool exit_failure,
- char **agent_directory,
- char **helper_directory,
- uid_t *const user,
- gid_t *const group,
- char **mandos_argz,
- size_t *mandos_argz_length){
-
- FILE *real_stderr = stderr;
- FILE *devnull = fopen("/dev/null", "we");
- g_assert_nonnull(devnull);
- stderr = devnull;
-
- const bool ret = parse_arguments(argc, argv, exit_failure,
- agent_directory,
- helper_directory, user, group,
- mandos_argz, mandos_argz_length);
- const error_t saved_errno = errno;
-
- stderr = real_stderr;
- g_assert_cmpint(fclose(devnull), ==, 0);
-
- errno = saved_errno;
-
- return ret;
-}
-
-static void test_parse_arguments_invalid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--invalid"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_false(parse_arguments_devnull(argc, argv, false,
- &agent_directory,
- &helper_directory, &user,
- &group, &mandos_argz,
- &mandos_argz_length));
-
- g_assert_true(errno == EINVAL);
- g_assert_null(agent_directory);
- g_assert_null(helper_directory);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_long_dir(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--agent-directory"),
- strdup("/tmp"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- __attribute__((cleanup(cleanup_string)))
- char *agent_directory = NULL;
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_cmpstr(agent_directory, ==, "/tmp");
- g_assert_null(helper_directory);
- g_assert_true(user == 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_short_dir(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("-d"),
- strdup("/tmp"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- __attribute__((cleanup(cleanup_string)))
- char *agent_directory = NULL;
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_cmpstr(agent_directory, ==, "/tmp");
- g_assert_null(helper_directory);
- g_assert_true(user == 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static
-void test_parse_arguments_helper_directory(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--helper-directory"),
- strdup("/tmp"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_cmpstr(helper_directory, ==, "/tmp");
- g_assert_null(agent_directory);
- g_assert_true(user == 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static
-void test_parse_arguments_plugin_helper_dir(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--plugin-helper-dir"),
- strdup("/tmp"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_cmpstr(helper_directory, ==, "/tmp");
- g_assert_null(agent_directory);
- g_assert_true(user == 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_user(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--user"),
- strdup("1000"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_null(helper_directory);
- g_assert_null(agent_directory);
- g_assert_cmpuint((unsigned int)user, ==, 1000);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_user_invalid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--user"),
- strdup("invalid"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_false(parse_arguments_devnull(argc, argv, false,
- &agent_directory,
- &helper_directory, &user,
- &group, &mandos_argz,
- &mandos_argz_length));
-
- g_assert_null(helper_directory);
- g_assert_null(agent_directory);
- g_assert_cmpuint((unsigned int)user, ==, 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static
-void test_parse_arguments_user_zero_invalid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--user"),
- strdup("0"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_false(parse_arguments_devnull(argc, argv, false,
- &agent_directory,
- &helper_directory, &user,
- &group, &mandos_argz,
- &mandos_argz_length));
-
- g_assert_null(helper_directory);
- g_assert_null(agent_directory);
- g_assert_cmpuint((unsigned int)user, ==, 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_group(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--group"),
- strdup("1000"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_null(helper_directory);
- g_assert_null(agent_directory);
- g_assert_true(user == 0);
- g_assert_cmpuint((unsigned int)group, ==, 1000);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_group_invalid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--group"),
- strdup("invalid"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_false(parse_arguments_devnull(argc, argv, false,
- &agent_directory,
- &helper_directory, &user,
- &group, &mandos_argz,
- &mandos_argz_length));
-
- g_assert_null(helper_directory);
- g_assert_null(agent_directory);
- g_assert_true(user == 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static
-void test_parse_arguments_group_zero_invalid(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--group"),
- strdup("0"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_false(parse_arguments_devnull(argc, argv, false,
- &agent_directory,
- &helper_directory, &user,
- &group, &mandos_argz,
- &mandos_argz_length));
-
- g_assert_null(helper_directory);
- g_assert_null(agent_directory);
- g_assert_cmpuint((unsigned int)group, ==, 0);
- g_assert_true(group == 0);
- g_assert_null(mandos_argz);
- g_assert_true(mandos_argz_length == 0);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_mandos_noargs(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer
- user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("mandos-client"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- __attribute__((cleanup(cleanup_string)))
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_null(agent_directory);
- g_assert_null(helper_directory);
- g_assert_true(user == 0);
- g_assert_true(group == 0);
- g_assert_cmpstr(mandos_argz, ==, "mandos-client");
- g_assert_cmpuint((unsigned int)argz_count(mandos_argz,
- mandos_argz_length),
- ==, 1);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_mandos_args(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("mandos-client"),
- strdup("one"),
- strdup("two"),
- strdup("three"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- __attribute__((cleanup(cleanup_string)))
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_null(agent_directory);
- g_assert_null(helper_directory);
- g_assert_true(user == 0);
- g_assert_true(group == 0);
- char *marg = mandos_argz;
- g_assert_cmpstr(marg, ==, "mandos-client");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "one");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "two");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "three");
- g_assert_cmpuint((unsigned int)argz_count(mandos_argz,
- mandos_argz_length),
- ==, 4);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_all_args(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("--agent-directory"),
- strdup("/tmp"),
- strdup("--helper-directory"),
- strdup("/var/tmp"),
- strdup("--user"),
- strdup("1"),
- strdup("--group"),
- strdup("2"),
- strdup("mandos-client"),
- strdup("one"),
- strdup("two"),
- strdup("three"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- __attribute__((cleanup(cleanup_string)))
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_cmpstr(agent_directory, ==, "/tmp");
- g_assert_cmpstr(helper_directory, ==, "/var/tmp");
- g_assert_true(user == 1);
- g_assert_true(group == 2);
- char *marg = mandos_argz;
- g_assert_cmpstr(marg, ==, "mandos-client");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "one");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "two");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "three");
- g_assert_cmpuint((unsigned int)argz_count(mandos_argz,
- mandos_argz_length),
- ==, 4);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-static void test_parse_arguments_mixed(__attribute__((unused))
- test_fixture *fixture,
- __attribute__((unused))
- gconstpointer user_data){
- char *argv[] = {
- strdup("prgname"),
- strdup("mandos-client"),
- strdup("--user"),
- strdup("1"),
- strdup("one"),
- strdup("--agent-directory"),
- strdup("/tmp"),
- strdup("two"),
- strdup("three"),
- strdup("--helper-directory=/var/tmp"),
- NULL };
- const int argc = (sizeof(argv) / sizeof(char *)) - 1;
-
- __attribute__((cleanup(cleanup_string)))
- char *agent_directory = NULL;
- __attribute__((cleanup(cleanup_string)))
- char *helper_directory = NULL;
- uid_t user = 0;
- gid_t group = 0;
- __attribute__((cleanup(cleanup_string)))
- char *mandos_argz = NULL;
- size_t mandos_argz_length = 0;
-
- g_assert_true(parse_arguments(argc, argv, false, &agent_directory,
- &helper_directory, &user, &group,
- &mandos_argz, &mandos_argz_length));
-
- g_assert_cmpstr(agent_directory, ==, "/tmp");
- g_assert_cmpstr(helper_directory, ==, "/var/tmp");
- g_assert_true(user == 1);
- g_assert_true(group == 0);
- char *marg = mandos_argz;
- g_assert_cmpstr(marg, ==, "mandos-client");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "one");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "two");
- marg = argz_next(mandos_argz, mandos_argz_length, marg);
- g_assert_cmpstr(marg, ==, "three");
- g_assert_cmpuint((unsigned int)argz_count(mandos_argz,
- mandos_argz_length),
- ==, 4);
-
- for(char **arg = argv; *arg != NULL; arg++){
- free(*arg);
- }
-}
-
-/* End of tests section */
-
-/* Test boilerplate section; New tests should be added to the test
- suite definition here, in the "run_tests" function.
-
- Finally, this section also contains the should_only_run_tests()
- function used by main() for deciding if tests should be run or to
- start normally. */
-
-__attribute__((cold))
-static bool run_tests(int argc, char *argv[]){
- g_test_init(&argc, &argv, NULL);
-
- /* A macro to add a test with no setup or teardown functions */
-#define test_add(testpath, testfunc) \
- do { \
- g_test_add((testpath), test_fixture, NULL, NULL, \
- (testfunc), NULL); \
- } while(false)
-
- /* Test the signal-related functions first, since some other tests
- depend on these functions in their setups and teardowns */
- test_add("/signal-handling/setup", test_setup_signal_handler);
- test_add("/signal-handling/restore", test_restore_signal_handler);
- test_add("/signal-handling/block", test_block_sigchld);
- test_add("/signal-handling/restore-sigmask", test_restore_sigmask);
-
- /* Regular non-signal-related tests; these use no setups or
- teardowns */
- test_add("/parse_arguments/noargs", test_parse_arguments_noargs);
- test_add("/parse_arguments/invalid", test_parse_arguments_invalid);
- test_add("/parse_arguments/long-dir",
- test_parse_arguments_long_dir);
- test_add("/parse_arguments/short-dir",
- test_parse_arguments_short_dir);
- test_add("/parse_arguments/helper-directory",
- test_parse_arguments_helper_directory);
- test_add("/parse_arguments/plugin-helper-dir",
- test_parse_arguments_plugin_helper_dir);
- test_add("/parse_arguments/user", test_parse_arguments_user);
- test_add("/parse_arguments/user-invalid",
- test_parse_arguments_user_invalid);
- test_add("/parse_arguments/user-zero-invalid",
- test_parse_arguments_user_zero_invalid);
- test_add("/parse_arguments/group", test_parse_arguments_group);
- test_add("/parse_arguments/group-invalid",
- test_parse_arguments_group_invalid);
- test_add("/parse_arguments/group-zero-invalid",
- test_parse_arguments_group_zero_invalid);
- test_add("/parse_arguments/mandos-noargs",
- test_parse_arguments_mandos_noargs);
- test_add("/parse_arguments/mandos-args",
- test_parse_arguments_mandos_args);
- test_add("/parse_arguments/all-args",
- test_parse_arguments_all_args);
- test_add("/parse_arguments/mixed", test_parse_arguments_mixed);
- test_add("/queue/create", test_create_queue);
- test_add("/queue/add", test_add_to_queue);
- test_add("/queue/has_question/empty",
- test_queue_has_question_empty);
- test_add("/queue/has_question/false",
- test_queue_has_question_false);
- test_add("/queue/has_question/true", test_queue_has_question_true);
- test_add("/queue/has_question/false2",
- test_queue_has_question_false2);
- test_add("/queue/has_question/true2",
- test_queue_has_question_true2);
- test_add("/buffer/cleanup", test_cleanup_buffer);
- test_add("/string_set/net-set-contains-nothing",
- test_string_set_new_set_contains_nothing);
- test_add("/string_set/with-added-string-contains-it",
- test_string_set_with_added_string_contains_it);
- test_add("/string_set/cleared-does-not-contain-string",
- test_string_set_cleared_does_not_contain_str);
- test_add("/string_set/swap/one-with-empty",
- test_string_set_swap_one_with_empty);
- test_add("/string_set/swap/empty-with-one",
- test_string_set_swap_empty_with_one);
- test_add("/string_set/swap/one-with-one",
- test_string_set_swap_one_with_one);
-
- /* A macro to add a test using the setup and teardown functions */
-#define test_add_st(path, func) \
- do { \
- g_test_add((path), test_fixture, NULL, test_setup, (func), \
- test_teardown); \
- } while(false)
-
- /* Signal-related tests; these use setups and teardowns which
- establish, during each test run, a signal handler for, and a
- signal mask blocking, the SIGCHLD signal, just like main() */
- test_add_st("/wait_for_event/timeout", test_wait_for_event_timeout);
- test_add_st("/wait_for_event/event", test_wait_for_event_event);
- test_add_st("/wait_for_event/sigchld", test_wait_for_event_sigchld);
- test_add_st("/run_queue/zeroes-next-run",
- test_run_queue_zeroes_next_run);
- test_add_st("/run_queue/clears-cancelled_filenames",
- test_run_queue_clears_cancelled_filenames);
- test_add_st("/run_queue/skips-cancelled-filenames",
- test_run_queue_skips_cancelled_filenames);
- test_add_st("/run_queue/one-task", test_run_queue_one_task);
- test_add_st("/run_queue/two-tasks", test_run_queue_two_tasks);
- test_add_st("/run_queue/two-tasks/quit",
- test_run_queue_two_tasks_quit);
- test_add_st("/run_queue/two-tasks-cleanup",
- test_run_queue_two_tasks_cleanup);
- test_add_st("/task-creators/start_mandos_client",
- test_start_mandos_client);
- test_add_st("/task-creators/start_mandos_client/execv",
- test_start_mandos_client_execv);
- test_add_st("/task-creators/start_mandos_client/suid/euid",
- test_start_mandos_client_suid_euid);
- test_add_st("/task-creators/start_mandos_client/suid/egid",
- test_start_mandos_client_suid_egid);
- test_add_st("/task-creators/start_mandos_client/suid/ruid",
- test_start_mandos_client_suid_ruid);
- test_add_st("/task-creators/start_mandos_client/suid/rgid",
- test_start_mandos_client_suid_rgid);
- test_add_st("/task-creators/start_mandos_client/read",
- test_start_mandos_client_read);
- test_add_st("/task-creators/start_mandos_client/helper-directory",
- test_start_mandos_client_helper_directory);
- test_add_st("/task-creators/start_mandos_client/sigmask",
- test_start_mandos_client_sigmask);
- test_add_st("/task/wait_for_mandos_client_exit/badpid",
- test_wait_for_mandos_client_exit_badpid);
- test_add_st("/task/wait_for_mandos_client_exit/noexit",
- test_wait_for_mandos_client_exit_noexit);
- test_add_st("/task/wait_for_mandos_client_exit/success",
- test_wait_for_mandos_client_exit_success);
- test_add_st("/task/wait_for_mandos_client_exit/failure",
- test_wait_for_mandos_client_exit_failure);
- test_add_st("/task/wait_for_mandos_client_exit/killed",
- test_wait_for_mandos_client_exit_killed);
- test_add_st("/task/read_mandos_client_output/readerror",
- test_read_mandos_client_output_readerror);
- test_add_st("/task/read_mandos_client_output/nodata",
- test_read_mandos_client_output_nodata);
- test_add_st("/task/read_mandos_client_output/eof",
- test_read_mandos_client_output_eof);
- test_add_st("/task/read_mandos_client_output/once",
- test_read_mandos_client_output_once);
- test_add_st("/task/read_mandos_client_output/malloc",
- test_read_mandos_client_output_malloc);
- test_add_st("/task/read_mandos_client_output/append",
- test_read_mandos_client_output_append);
- test_add_st("/task-creators/add_inotify_dir_watch",
- test_add_inotify_dir_watch);
- test_add_st("/task-creators/add_inotify_dir_watch/fail",
- test_add_inotify_dir_watch_fail);
- test_add_st("/task-creators/add_inotify_dir_watch/not-a-directory",
- test_add_inotify_dir_watch_nondir);
- test_add_st("/task-creators/add_inotify_dir_watch/EAGAIN",
- test_add_inotify_dir_watch_EAGAIN);
- test_add_st("/task-creators/add_inotify_dir_watch/IN_CLOSE_WRITE",
- test_add_inotify_dir_watch_IN_CLOSE_WRITE);
- test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_TO",
- test_add_inotify_dir_watch_IN_MOVED_TO);
- test_add_st("/task-creators/add_inotify_dir_watch/IN_MOVED_FROM",
- test_add_inotify_dir_watch_IN_MOVED_FROM);
- test_add_st("/task-creators/add_inotify_dir_watch/IN_EXCL_UNLINK",
- test_add_inotify_dir_watch_IN_EXCL_UNLINK);
- test_add_st("/task-creators/add_inotify_dir_watch/IN_DELETE",
- test_add_inotify_dir_watch_IN_DELETE);
- test_add_st("/task/read_inotify_event/readerror",
- test_read_inotify_event_readerror);
- test_add_st("/task/read_inotify_event/bad-epoll",
- test_read_inotify_event_bad_epoll);
- test_add_st("/task/read_inotify_event/nodata",
- test_read_inotify_event_nodata);
- test_add_st("/task/read_inotify_event/eof",
- test_read_inotify_event_eof);
- test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE",
- test_read_inotify_event_IN_CLOSE_WRITE);
- test_add_st("/task/read_inotify_event/IN_MOVED_TO",
- test_read_inotify_event_IN_MOVED_TO);
- test_add_st("/task/read_inotify_event/IN_MOVED_FROM",
- test_read_inotify_event_IN_MOVED_FROM);
- test_add_st("/task/read_inotify_event/IN_DELETE",
- test_read_inotify_event_IN_DELETE);
- test_add_st("/task/read_inotify_event/IN_CLOSE_WRITE/badname",
- test_read_inotify_event_IN_CLOSE_WRITE_badname);
- test_add_st("/task/read_inotify_event/IN_MOVED_TO/badname",
- test_read_inotify_event_IN_MOVED_TO_badname);
- test_add_st("/task/read_inotify_event/IN_MOVED_FROM/badname",
- test_read_inotify_event_IN_MOVED_FROM_badname);
- test_add_st("/task/read_inotify_event/IN_DELETE/badname",
- test_read_inotify_event_IN_DELETE_badname);
- test_add_st("/task/open_and_parse_question/ENOENT",
- test_open_and_parse_question_ENOENT);
- test_add_st("/task/open_and_parse_question/EIO",
- test_open_and_parse_question_EIO);
- test_add_st("/task/open_and_parse_question/parse-error",
- test_open_and_parse_question_parse_error);
- test_add_st("/task/open_and_parse_question/nosocket",
- test_open_and_parse_question_nosocket);
- test_add_st("/task/open_and_parse_question/badsocket",
- test_open_and_parse_question_badsocket);
- test_add_st("/task/open_and_parse_question/nopid",
- test_open_and_parse_question_nopid);
- test_add_st("/task/open_and_parse_question/badpid",
- test_open_and_parse_question_badpid);
- test_add_st("/task/open_and_parse_question/noexist_pid",
- test_open_and_parse_question_noexist_pid);
- test_add_st("/task/open_and_parse_question/no-notafter",
- test_open_and_parse_question_no_notafter);
- test_add_st("/task/open_and_parse_question/bad-notafter",
- test_open_and_parse_question_bad_notafter);
- test_add_st("/task/open_and_parse_question/notafter-0",
- test_open_and_parse_question_notafter_0);
- test_add_st("/task/open_and_parse_question/notafter-1",
- test_open_and_parse_question_notafter_1);
- test_add_st("/task/open_and_parse_question/notafter-1-1",
- test_open_and_parse_question_notafter_1_1);
- test_add_st("/task/open_and_parse_question/notafter-1-2",
- test_open_and_parse_question_notafter_1_2);
- test_add_st("/task/open_and_parse_question/equal-notafter",
- test_open_and_parse_question_equal_notafter);
- test_add_st("/task/open_and_parse_question/late-notafter",
- test_open_and_parse_question_late_notafter);
- test_add_st("/task/cancel_old_question/0-1-2",
- test_cancel_old_question_0_1_2);
- test_add_st("/task/cancel_old_question/0-2-1",
- test_cancel_old_question_0_2_1);
- test_add_st("/task/cancel_old_question/1-2-3",
- test_cancel_old_question_1_2_3);
- test_add_st("/task/cancel_old_question/1-3-2",
- test_cancel_old_question_1_3_2);
- test_add_st("/task/cancel_old_question/2-1-3",
- test_cancel_old_question_2_1_3);
- test_add_st("/task/cancel_old_question/2-3-1",
- test_cancel_old_question_2_3_1);
- test_add_st("/task/cancel_old_question/3-1-2",
- test_cancel_old_question_3_1_2);
- test_add_st("/task/cancel_old_question/3-2-1",
- test_cancel_old_question_3_2_1);
- test_add_st("/task/connect_question_socket/name-too-long",
- test_connect_question_socket_name_too_long);
- test_add_st("/task/connect_question_socket/connect-fail",
- test_connect_question_socket_connect_fail);
- test_add_st("/task/connect_question_socket/bad-epoll",
- test_connect_question_socket_bad_epoll);
- test_add_st("/task/connect_question_socket/usable",
- test_connect_question_socket_usable);
- test_add_st("/task/send_password_to_socket/client-not-exited",
- test_send_password_to_socket_client_not_exited);
- test_add_st("/task/send_password_to_socket/password-not-read",
- test_send_password_to_socket_password_not_read);
- test_add_st("/task/send_password_to_socket/EMSGSIZE",
- test_send_password_to_socket_EMSGSIZE);
- test_add_st("/task/send_password_to_socket/retry",
- test_send_password_to_socket_retry);
- test_add_st("/task/send_password_to_socket/bad-epoll",
- test_send_password_to_socket_bad_epoll);
- test_add_st("/task/send_password_to_socket/null-password",
- test_send_password_to_socket_null_password);
- test_add_st("/task/send_password_to_socket/empty-password",
- test_send_password_to_socket_empty_password);
- test_add_st("/task/send_password_to_socket/empty-str-password",
- test_send_password_to_socket_empty_str_pass);
- test_add_st("/task/send_password_to_socket/text-password",
- test_send_password_to_socket_text_password);
- test_add_st("/task/send_password_to_socket/binary-password",
- test_send_password_to_socket_binary_password);
- test_add_st("/task/send_password_to_socket/nuls-in-password",
- test_send_password_to_socket_nuls_in_password);
- test_add_st("/task-creators/add_existing_questions/ENOENT",
- test_add_existing_questions_ENOENT);
- test_add_st("/task-creators/add_existing_questions/no-questions",
- test_add_existing_questions_no_questions);
- test_add_st("/task-creators/add_existing_questions/one-question",
- test_add_existing_questions_one_question);
- test_add_st("/task-creators/add_existing_questions/two-questions",
- test_add_existing_questions_two_questions);
- test_add_st("/task-creators/add_existing_questions/non-questions",
- test_add_existing_questions_non_questions);
- test_add_st("/task-creators/add_existing_questions/both-types",
- test_add_existing_questions_both_types);
-
- return g_test_run() == 0;
-}
-
-static bool should_only_run_tests(int *argc_p, char **argv_p[]){
- GOptionContext *context = g_option_context_new("");
-
- g_option_context_set_help_enabled(context, FALSE);
- g_option_context_set_ignore_unknown_options(context, TRUE);
-
- gboolean run_tests = FALSE;
- GOptionEntry entries[] = {
- { "test", 0, 0, G_OPTION_ARG_NONE,
- &run_tests, "Run tests", NULL },
- { NULL }
- };
- g_option_context_add_main_entries(context, entries, NULL);
-
- GError *error = NULL;
-
- if(g_option_context_parse(context, argc_p, argv_p, &error) != TRUE){
- g_option_context_free(context);
- g_error("Failed to parse options: %s", error->message);
- }
-
- g_option_context_free(context);
- return run_tests != FALSE;
-}
=== removed file 'dracut-module/password-agent.xml'
--- dracut-module/password-agent.xml 2019-07-27 10:11:45 +0000
+++ dracut-module/password-agent.xml 1970-01-01 00:00:00 +0000
@@ -1,469 +0,0 @@
-
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@recompile.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@recompile.se
-
-
-
-
- 2019
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8mandos
-
-
-
- &COMMANDNAME;
-
- Run Mandos client as a systemd password agent.
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- --
-
- MANDOS_CLIENT
-
- OPTIONS
-
-
-
-
- &COMMANDNAME;
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is a program which is meant to
- be a systemd
- 1 Password
- Agent
(See Password Agents). The aim of this program is therefore
- to acquire and then send a password to some other program which
- will use the password to unlock the encrypted root disk.
-
-
- This program is not meant to be invoked directly, but can be in
- order to test it.
-
-
-
-
- PURPOSE
-
- The purpose of this is to enable remote and unattended
- rebooting of client host computer with an
- encrypted root file system. See for details.
-
-
-
-
- OPTIONS
-
-
-
-
-
-
- Specify a different agent directory. The default is
- /run/systemd/ask-password
as per the
- Password Agents specification.
-
-
-
-
-
-
-
-
- Specify a different helper directory. The default is
- /lib/mandos/plugin-helpers
, which
- will exist in the initial RAM disk
- environment. (This will simply be passed to the
- MANDOS_CLIENT program via the
- MANDOSPLUGINHELPERDIR environment variable.
- See
- mandos-client8mandos.)
-
-
-
-
-
-
-
-
- Change real user ID to USERID
- when running MANDOS_CLIENT.
- The default is 65534. Note: This
- must be a number, not a name.
-
-
-
-
-
-
-
-
- Change real group ID to GROUPID
- when running MANDOS_CLIENT.
- The default is 65534. Note: This
- must be a number, not a name.
-
-
-
-
-
- MANDOS_CLIENT
-
-
- This specifies the file name for
- mandos-client8mandos. If the
-
option is given, any
- following options are passed to the MANDOS_CLIENT program. The default is
- /lib/mandos/plugins.d/mandos-client
- (which is the correct location for the initial
- RAM disk environment) without any
- options.
-
-
-
-
-
-
-
-
-
- Gives a help message about options and their meanings.
-
-
-
-
-
-
-
-
- Ignore normal operation; instead only run self-tests.
- Adding the option may show more
- options possible in combination with
- .
-
-
-
-
-
-
-
-
- Gives a short usage message.
-
-
-
-
-
-
-
-
-
- Prints the program version.
-
-
-
-
-
-
-
- OVERVIEW
-
-
- This program, &COMMANDNAME;, will run on the client side in the
- initial RAM disk environment, and is
- responsible for getting a password from the Mandos client
- program itself, and to send that password to whatever is
- currently asking for a password using the systemd Password Agents mechanism.
-
- To accomplish this, &COMMANDNAME; runs the
- mandos-client program (which is the actual
- client program communicating with the Mandos server) or,
- alternatively, any executable file specified as
- MANDOS_CLIENT, and, as soon as a
- password is acquired from the
- MANDOS_CLIENT program, sends that
- password (as per the Password Agents specification) to all currently
- unanswered password questions.
-
-
- This program should be started (normally as a systemd service,
- which in turn is normally started by a systemd.path
- 5 file) as a reaction to
- files named ask.xxxx
appearing in the agent directory
- /run/systemd/ask-password
- (or the directory specified by
- ).
-
-
-
-
- EXIT STATUS
-
- Exit status of this program is zero if no errors were
- encountered, and otherwise not.
-
-
-
-
- ENVIRONMENT
-
- This program does not use any environment variables itself, it
- only passes on its environment to
- MANDOS_CLIENT. Also, the
- option will affect the
- environment variable MANDOSPLUGINHELPERDIR for
- MANDOS_CLIENT.
-
-
-
-
- FILES
-
-
-
- /run/systemd/ask-password
-
-
- The default directory to watch for password questions as
- per the Password Agents specification; can be changed
- by the option.
-
-
-
-
- /lib/mandos/plugin-helpers
-
-
- The helper directory as supplied to
- MANDOS_CLIENT via the
- MANDOSPLUGINHELPERDIR environment
- variable; can be changed by the
- option.
-
-
-
-
-
-
-
-
- BUGS
-
-
-
-
- EXAMPLE
-
-
- Normal invocation needs no options:
-
-
- &COMMANDNAME;
-
-
-
-
- Run an alternative MANDOS_CLIENT
- program::
-
-
- &COMMANDNAME; /usr/local/sbin/alternate
-
-
-
-
- Use alternative locations for the helper directory and the
- Mandos client, and add extra options suitable for running in
- the normal file system:
-
-
-
-
- &COMMANDNAME; --helper-directory=/usr/lib/x86_64-linux-gnu/mandos/plugin-helpers -- /usr/lib/x86_64-linux-gnu/mandos/plugins.d/mandos-client --pubkey=/etc/keys/mandos/pubkey.txt --seckey=/etc/keys/mandos/seckey.txt --tls-pubkey=/etc/keys/mandos/tls-pubkey.pem --tls-privkey=/etc/keys/mandos/tls-privkey.pem
-
-
-
-
-
- Use the default location for
- mandos-client
- 8mandos, but add many
- options to it:
-
-
-
-
-&COMMANDNAME; -- /lib/mandos/mandos-client --pubkey=/etc/mandos/keys/pubkey.txt --seckey=/etc/mandos/keys/seckey.txt --tls-pubkey=/etc/mandos/keys/tls-pubkey.pem --tls-privkey=/etc/mandos/keys/tls-privkey.pem
-
-
-
-
-
- Only run the self-tests:
-
-
- &COMMANDNAME; --test
-
-
-
-
- SECURITY
-
- This program will need to run as the root user in order to read
- the agent directory and the ask.xxxx
files
- there, and will, when starting the Mandos client program,
- require the ability to set the real
user and
- group ids to another user, by default user and group 65534,
- which are assumed to be non-privileged. This is done in order
- to match the expectations of mandos-client8mandos, which assumes that its executable file is
- owned by the root user and also has the set-user-ID bit set (see
- execve2).
-
-
-
-
- SEE ALSO
-
- intro
- 8mandos,
- mandos-client
- 8mandos,
- systemd
- 1,
-
-
-
-
- Password Agents
-
-
-
- The specification for systemd Password
- Agent
programs, which
- &COMMANDNAME; follows.
-
-
-
-
-
-
-
-
-
-
-
-
=== removed file 'init.d-mandos'
--- init.d-mandos 2018-02-10 13:23:58 +0000
+++ init.d-mandos 1970-01-01 00:00:00 +0000
@@ -1,164 +0,0 @@
-#! /bin/sh
-### BEGIN INIT INFO
-# Provides: mandos
-# Required-Start: $remote_fs $syslog avahi-daemon
-# Required-Stop: $remote_fs $syslog avahi-daemon
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Mandos server
-# Description: Server of encrypted passwords to Mandos clients
-### END INIT INFO
-
-# Author: Teddy Hogeborn
-# Author: Björn Påhlsson
-
-# Do NOT "set -e"
-
-# PATH should only include /usr/* if it runs after the mountnfs.sh script
-PATH=/sbin:/usr/sbin:/bin:/usr/bin
-DESC="Mandos root file system password server"
-NAME=mandos
-DAEMON=/usr/sbin/$NAME
-DAEMON_ARGS=""
-if [ -d /run/. ]; then
- PIDFILE=/run/$NAME.pid
-else
- PIDFILE=/var/run/$NAME.pid
-fi
-SCRIPTNAME=/etc/init.d/$NAME
-
-# Exit if the package is not installed
-[ -x "$DAEMON" ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/$NAME ] && . /etc/default/$NAME
-
-if [ -n "$CONFIGDIR" ]; then
- DAEMON_ARGS="$DAEMON_ARGS --configdir $CONFIGDIR"
-fi
-
-# Load the VERBOSE setting and other rcS variables
-. /lib/init/vars.sh
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
-# and status_of_proc is working.
-. /lib/lsb/init-functions
-
-#
-# Function that starts the daemon/service
-#
-do_start()
-{
- # Return
- # 0 if daemon has been started
- # 1 if daemon was already running
- # 2 if daemon could not be started
- start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
- || return 1
- start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
- $DAEMON_ARGS \
- || return 2
- # Add code here, if necessary, that waits for the process to be ready
- # to handle requests from services started subsequently which depend
- # on this one. As a last resort, sleep for some time.
-}
-
-#
-# Function that stops the daemon/service
-#
-do_stop()
-{
- # Return
- # 0 if daemon has been stopped
- # 1 if daemon was already stopped
- # 2 if daemon could not be stopped
- # other if a failure occurred
- start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
- RETVAL="$?"
- [ "$RETVAL" = 2 ] && return 2
- # Wait for children to finish too if this is a daemon that forks
- # and if the daemon is only ever run from this initscript.
- # If the above conditions are not satisfied then add some other code
- # that waits for the process to drop all resources that could be
- # needed by services started subsequently. A last resort is to
- # sleep for some time.
- start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
- [ "$?" = 2 ] && return 2
- # Many daemons don't delete their pidfiles when they exit.
- rm -f $PIDFILE
- return "$RETVAL"
-}
-
-#
-# Function that sends a SIGHUP to the daemon/service
-#
-do_reload() {
- #
- # If the daemon can reload its configuration without
- # restarting (for example, when it is sent a SIGHUP),
- # then implement that here.
- #
- start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
- return 0
-}
-
-case "$1" in
- start)
- [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
- do_start
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- stop)
- [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- status)
- status_of_proc "$DAEMON" "$NAME" -p "$PIDFILE" && exit 0 || exit $?
- ;;
- #reload|force-reload)
- #
- # If do_reload() is not implemented then leave this commented out
- # and leave 'force-reload' as an alias for 'restart'.
- #
- #log_daemon_msg "Reloading $DESC" "$NAME"
- #do_reload
- #log_end_msg $?
- #;;
- restart|force-reload)
- #
- # If the "reload" option is implemented then remove the
- # 'force-reload' alias
- #
- log_daemon_msg "Restarting $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1)
- do_start
- case "$?" in
- 0) log_end_msg 0 ;;
- 1) log_end_msg 1 ;; # Old process is still running
- *) log_end_msg 1 ;; # Failed to start
- esac
- ;;
- *)
- # Failed to stop
- log_end_msg 1
- ;;
- esac
- ;;
- *)
- #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
- echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
- exit 3
- ;;
-esac
-
-:
=== removed file 'initramfs-tools-conf'
--- initramfs-tools-conf 2018-08-19 14:06:55 +0000
+++ initramfs-tools-conf 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
-# -*- shell-script -*-
-
-# Since the initramfs image will contain key files, we need to
-# restrict permissions on it by setting UMASK here.
-#
-# The proper place to set UMASK is (according to
-# /etc/cryptsetup-initramfs/conf-hook), in
-# /etc/initramfs-tools/initramfs.conf, which we shouldn't edit. The
-# corresponding directory for drop-in files from packages is
-# /usr/share/initramfs-tools/conf.d, and this file will be installed
-# there as "mandos-conf".
-#
-# This setting of UMASK will have unfortunate unintended side effects
-# on the files *inside* the initramfs, but these are later fixed by
-# "initramfs-tools-hook", installed as
-# "/usr/share/initramfs-tools/hooks/mandos".
-UMASK=0027
=== removed file 'initramfs-tools-conf-hook'
--- initramfs-tools-conf-hook 2019-04-09 19:33:36 +0000
+++ initramfs-tools-conf-hook 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
-# -*- shell-script -*-
-
-# The UMASK is set by the file "initramfs-tools-conf" (which is copied
-# to /usr/share/initramfs-tools/conf.d/mandos-conf on installation)
-# since there, as described therein, is the proper place to do that.
-# However, it is possible for other packages to override the UMASK in
-# any file in /usr/share/initramfs-tools/conf-hooks.d. Therefore,
-# this file ("initramfs-tools-conf-hook") will be installed as
-# "zz-mandos" in that directory to make sure UMASK is set correctly.
-
-# For more information on the effects of setting UMASK, see the
-# aforementioned /usr/share/initramfs-tools/conf.d/mandos-conf file.
-
-UMASK=0027
=== removed file 'initramfs-tools-hook'
--- initramfs-tools-hook 2018-08-19 14:06:55 +0000
+++ initramfs-tools-hook 1970-01-01 00:00:00 +0000
@@ -1,277 +0,0 @@
-#!/bin/sh
-
-# This script will be run by 'mkinitramfs' when it creates the image.
-# Its job is to decide which files to install, then install them into
-# the staging area, where the initramfs is being created. This
-# happens when a new 'linux-image' package is installed, or when an
-# administrator runs 'update-initramfs' by hand to update an initramfs
-# image.
-
-# The environment contains at least:
-#
-# DESTDIR -- The staging directory where the image is being built.
-
-# No initramfs pre-requirements
-PREREQ="cryptroot"
-
-prereqs()
-{
- echo "$PREREQ"
-}
-
-case $1 in
-# get pre-requisites
-prereqs)
- prereqs
- exit 0
- ;;
-esac
-
-. /usr/share/initramfs-tools/hook-functions
-
-for d in /usr/lib \
- "/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null`" \
- "`rpm --eval='%{_libdir}' 2>/dev/null`" /usr/local/lib; do
- if [ -d "$d"/mandos ]; then
- libdir="$d"
- break
- fi
-done
-if [ -z "$libdir" ]; then
- # Mandos not found
- exit 1
-fi
-
-for d in /etc/keys/mandos /etc/mandos/keys; do
- if [ -d "$d" ]; then
- keydir="$d"
- break
- fi
-done
-if [ -z "$keydir" ]; then
- # Mandos key directory not found
- exit 1
-fi
-
-set `{ getent passwd _mandos \
- || getent passwd nobody \
- || echo ::65534:65534:::; } \
- | cut --delimiter=: --fields=3,4 --only-delimited \
- --output-delimiter=" "`
-mandos_user="$1"
-mandos_group="$2"
-
-# The Mandos network client uses the network
-auto_add_modules net
-# The Mandos network client uses IPv6
-force_load ipv6
-
-# These are directories inside the initrd
-CONFDIR="/conf/conf.d/mandos"
-MANDOSDIR="/lib/mandos"
-PLUGINDIR="${MANDOSDIR}/plugins.d"
-PLUGINHELPERDIR="${MANDOSDIR}/plugin-helpers"
-HOOKDIR="${MANDOSDIR}/network-hooks.d"
-
-# Make directories
-install --directory --mode=u=rwx,go=rx "${DESTDIR}${CONFDIR}" \
- "${DESTDIR}${MANDOSDIR}" "${DESTDIR}${HOOKDIR}"
-install --owner=${mandos_user} --group=${mandos_group} --directory \
- --mode=u=rwx "${DESTDIR}${PLUGINDIR}" \
- "${DESTDIR}${PLUGINHELPERDIR}"
-
-copy_exec "$libdir"/mandos/mandos-to-cryptroot-unlock "${MANDOSDIR}"
-
-# Copy the Mandos plugin runner
-copy_exec "$libdir"/mandos/plugin-runner "${MANDOSDIR}"
-
-# Copy the plugins
-
-# Copy the packaged plugins
-for file in "$libdir"/mandos/plugins.d/*; do
- base="`basename \"$file\"`"
- # Is this plugin overridden?
- if [ -e "/etc/mandos/plugins.d/$base" ]; then
- continue
- fi
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") echo "W: Mandos client plugin directory is empty." >&2 ;;
- *) copy_exec "$file" "${PLUGINDIR}" ;;
- esac
-done
-
-# Copy the packaged plugin helpers
-for file in "$libdir"/mandos/plugin-helpers/*; do
- base="`basename \"$file\"`"
- # Is this plugin overridden?
- if [ -e "/etc/mandos/plugin-helpers/$base" ]; then
- continue
- fi
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *) copy_exec "$file" "${PLUGINHELPERDIR}" ;;
- esac
-done
-
-# Copy any user-supplied plugins
-for file in /etc/mandos/plugins.d/*; do
- base="`basename \"$file\"`"
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *) copy_exec "$file" "${PLUGINDIR}" ;;
- esac
-done
-
-# Copy any user-supplied plugin helpers
-for file in /etc/mandos/plugin-helpers/*; do
- base="`basename \"$file\"`"
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *) copy_exec "$file" "${PLUGINHELPERDIR}" ;;
- esac
-done
-
-# Get DEVICE from initramfs.conf and other files
-. /etc/initramfs-tools/initramfs.conf
-for conf in /etc/initramfs-tools/conf.d/*; do
- if [ -n `basename \"$conf\" | grep '^[[:alnum:]][[:alnum:]\._-]*$' \
- | grep -v '\.dpkg-.*$'` ]; then
- [ -f "${conf}" ] && . "${conf}"
- fi
-done
-export DEVICE
-
-# Copy network hooks
-for hook in /etc/mandos/network-hooks.d/*; do
- case "`basename \"$hook\"`" in
- "*") continue ;;
- *[!A-Za-z0-9_.-]*) continue ;;
- *) test -d "$hook" || copy_exec "$hook" "${HOOKDIR}" ;;
- esac
- if [ -x "$hook" ]; then
- # Copy any files needed by the network hook
- MANDOSNETHOOKDIR=/etc/mandos/network-hooks.d MODE=files \
- VERBOSITY=0 "$hook" files | while read -r file target; do
- if [ ! -e "${file}" ]; then
- echo "WARNING: file ${file} not found, requested by Mandos network hook '${hook##*/}'" >&2
- fi
- if [ -z "${target}" ]; then
- copy_exec "$file"
- else
- copy_exec "$file" "$target"
- fi
- done
- # Copy and load any modules needed by the network hook
- MANDOSNETHOOKDIR=/etc/mandos/network-hooks.d MODE=modules \
- VERBOSITY=0 "$hook" modules | while read -r module; do
- force_load "$module"
- done
- fi
-done
-
-# GPGME needs GnuPG
-gpg=/usr/bin/gpg
-libgpgme11_version="`dpkg-query --showformat='${Version}' --show libgpgme11`"
-if dpkg --compare-versions "$libgpgme11_version" ge 1.5.0-0.1; then
- if [ -e /usr/bin/gpgconf ]; then
- if [ ! -e "${DESTDIR}/usr/bin/gpgconf" ]; then
- copy_exec /usr/bin/gpgconf
- fi
- gpg="`/usr/bin/gpgconf|sed --quiet --expression='s/^gpg:[^:]*://p'`"
- gpgagent="`/usr/bin/gpgconf|sed --quiet --expression='s/^gpg-agent:[^:]*://p'`"
- # Newer versions of GnuPG 2 requires the gpg-agent binary
- if [ -e "$gpgagent" ] && [ ! -e "${DESTDIR}$gpgagent" ]; then
- copy_exec "$gpgagent"
- fi
- fi
-elif dpkg --compare-versions "$libgpgme11_version" ge 1.4.1-0.1; then
- gpg=/usr/bin/gpg2
-fi
-if [ ! -e "${DESTDIR}$gpg" ]; then
- copy_exec "$gpg"
-fi
-unset gpg
-unset libgpgme11_version
-
-# Config files
-for file in /etc/mandos/plugin-runner.conf; do
- if [ -d "$file" ]; then
- continue
- fi
- cp --archive --sparse=always "$file" "${DESTDIR}${CONFDIR}"
-done
-
-if [ ${mandos_user} != 65534 ]; then
- sed --in-place --expression="1i--userid=${mandos_user}" \
- "${DESTDIR}${CONFDIR}/plugin-runner.conf"
-fi
-
-if [ ${mandos_group} != 65534 ]; then
- sed --in-place --expression="1i--groupid=${mandos_group}" \
- "${DESTDIR}${CONFDIR}/plugin-runner.conf"
-fi
-
-# Key files
-for file in "$keydir"/*; do
- if [ -d "$file" ]; then
- continue
- fi
- case "$file" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *)
- cp --archive --sparse=always "$file" \
- "${DESTDIR}${CONFDIR}"
- chown ${mandos_user}:${mandos_group} \
- "${DESTDIR}${CONFDIR}/`basename \"$file\"`"
- ;;
- esac
-done
-# Use Diffie-Hellman parameters file if available
-if [ -e "${DESTDIR}${CONFDIR}"/dhparams.pem ]; then
- sed --in-place \
- --expression="1i--options-for=mandos-client:--dh-params=${CONFDIR}/dhparams.pem" \
- "${DESTDIR}/${CONFDIR}/plugin-runner.conf"
-fi
-
-# /lib/mandos/plugin-runner will drop priviliges, but needs access to
-# its plugin directory and its config file. However, since almost all
-# files in initrd have been created with umask 027, this opening of
-# permissions is needed.
-#
-# (The umask is not really intended to affect the files inside the
-# initrd; it is intended to affect the initrd.img file itself, since
-# it now contains secret key files. There is, however, no other way
-# to set the permission of the initrd.img file without a race
-# condition. This umask is set by "initramfs-tools-conf", installed
-# as "/usr/share/initramfs-tools/conf.d/mandos-conf".)
-#
-for full in "${MANDOSDIR}" "${CONFDIR}"; do
- while [ "$full" != "/" ]; do
- chmod a+rX "${DESTDIR}$full"
- full="`dirname \"$full\"`"
- done
-done
-
-# Reset some other things to sane permissions which we have
-# inadvertently affected with our umask setting.
-for dir in / /bin /etc /keyscripts /sbin /scripts /usr /usr/bin; do
- if [ -d "${DESTDIR}$dir" ]; then
- chmod a+rX "${DESTDIR}$dir"
- fi
-done
-for dir in "${DESTDIR}"/lib* "${DESTDIR}"/usr/lib*; do
- if [ -d "$dir" ]; then
- find "$dir" \! -perm -u+rw,g+r -prune -or \! -type l -print0 \
- | xargs --null --no-run-if-empty chmod a+rX --
- fi
-done
=== removed file 'initramfs-tools-script'
--- initramfs-tools-script 2018-08-19 01:35:11 +0000
+++ initramfs-tools-script 1970-01-01 00:00:00 +0000
@@ -1,181 +0,0 @@
-#!/bin/sh -e
-#
-# This script will run in the initrd environment at boot and edit
-# /conf/conf.d/cryptroot to set /lib/mandos/plugin-runner as keyscript
-# when no other keyscript is set, before cryptsetup.
-#
-
-# This script should be installed as
-# "/usr/share/initramfs-tools/scripts/init-premount/mandos" which will
-# eventually be "/scripts/init-premount/mandos" in the initrd.img
-# file.
-
-PREREQ="udev"
-prereqs()
-{
- echo "$PREREQ"
-}
-
-case $1 in
-prereqs)
- prereqs
- exit 0
- ;;
-esac
-
-. /scripts/functions
-
-for param in `cat /proc/cmdline`; do
- case "$param" in
- ip=*) IPOPTS="${param#ip=}" ;;
- mandos=*)
- # Split option line on commas
- old_ifs="$IFS"
- IFS="$IFS,"
- for mpar in ${param#mandos=}; do
- IFS="$old_ifs"
- case "$mpar" in
- off) exit 0 ;;
- connect) connect="" ;;
- connect:*) connect="${mpar#connect:}" ;;
- *) log_warning_msg "$0: Bad option ${mpar}" ;;
- esac
- done
- unset mpar
- IFS="$old_ifs"
- unset old_ifs
- ;;
- esac
-done
-unset param
-
-chmod a=rwxt /tmp
-
-# Get DEVICE from /conf/initramfs.conf and other files
-. /conf/initramfs.conf
-for conf in /conf/conf.d/*; do
- [ -f "${conf}" ] && . "${conf}"
-done
-if [ -e /conf/param.conf ]; then
- . /conf/param.conf
-fi
-
-# Override DEVICE from sixth field of ip= kernel option, if passed
-case "$IPOPTS" in
- *:*:*:*:*:*) # At least six fields
- # Remove the first five fields
- device="${IPOPTS#*:*:*:*:*:}"
- # Remove all fields except the first one
- DEVICE="${device%%:*}"
- ;;
-esac
-
-# Add device setting (if any) to plugin-runner.conf
-if [ "${DEVICE+set}" = set ]; then
- # Did we get the device from an ip= option?
- if [ "${device+set}" = set ]; then
- # Let ip= option override local config; append:
- cat <<-EOF >>/conf/conf.d/mandos/plugin-runner.conf
-
- --options-for=mandos-client:--interface=${DEVICE}
-EOF
- else
- # Prepend device setting so any later options would override:
- sed -i -e \
- '1i--options-for=mandos-client:--interface='"${DEVICE}" \
- /conf/conf.d/mandos/plugin-runner.conf
- fi
-fi
-unset device
-
-# If we are connecting directly, run "configure_networking" (from
-# /scripts/functions); it needs IPOPTS and DEVICE
-if [ "${connect+set}" = set ]; then
- set +e # Required by library functions
- configure_networking
- set -e
- if [ -n "$connect" ]; then
- cat <<-EOF >>/conf/conf.d/mandos/plugin-runner.conf
-
- --options-for=mandos-client:--connect=${connect}
-EOF
- fi
-fi
-
-if [ -r /conf/conf.d/cryptroot ]; then
- test -w /conf/conf.d
-
- # Do not replace cryptroot file unless we need to.
- replace_cryptroot=no
-
- # Our keyscript
- mandos=/lib/mandos/plugin-runner
- test -x "$mandos"
-
- # parse /conf/conf.d/cryptroot. Format:
- # target=sda2_crypt,source=/dev/sda2,rootdev,key=none,keyscript=/foo/bar/baz
- # Is the root device specially marked?
- changeall=yes
- while read -r options; do
- case "$options" in
- rootdev,*|*,rootdev,*|*,rootdev)
- # If the root device is specially marked, don't change all
- # lines in crypttab by default.
- changeall=no
- ;;
- esac
- done < /conf/conf.d/cryptroot
-
- exec 3>/conf/conf.d/cryptroot.mandos
- while read -r options; do
- newopts=""
- keyscript=""
- changethis="$changeall"
- # Split option line on commas
- old_ifs="$IFS"
- IFS="$IFS,"
- for opt in $options; do
- # Find the keyscript option, if any
- case "$opt" in
- keyscript=*)
- keyscript="${opt#keyscript=}"
- newopts="$newopts,$opt"
- ;;
- "") : ;;
- # Always use Mandos on the root device, if marked
- rootdev)
- changethis=yes
- newopts="$newopts,$opt"
- ;;
- # Don't use Mandos on resume device, if marked
- resumedev)
- changethis=no
- newopts="$newopts,$opt"
- ;;
- *)
- newopts="$newopts,$opt"
- ;;
- esac
- done
- IFS="$old_ifs"
- unset old_ifs
- # If there was no keyscript option, add one.
- if [ "$changethis" = yes ] && [ -z "$keyscript" ]; then
- replace_cryptroot=yes
- newopts="$newopts,keyscript=$mandos"
- fi
- newopts="${newopts#,}"
- echo "$newopts" >&3
- done < /conf/conf.d/cryptroot
- exec 3>&-
-
- # If we need to, replace the old cryptroot file with the new file.
- if [ "$replace_cryptroot" = yes ]; then
- mv /conf/conf.d/cryptroot /conf/conf.d/cryptroot.mandos-old
- mv /conf/conf.d/cryptroot.mandos /conf/conf.d/cryptroot
- else
- rm -f /conf/conf.d/cryptroot.mandos
- fi
-elif [ -x /usr/bin/cryptroot-unlock ]; then
- setsid /lib/mandos/mandos-to-cryptroot-unlock &
-fi
=== removed file 'initramfs-tools-script-stop'
--- initramfs-tools-script-stop 2018-08-19 14:58:40 +0000
+++ initramfs-tools-script-stop 1970-01-01 00:00:00 +0000
@@ -1,65 +0,0 @@
-#!/bin/sh -e
-#
-# Script to wait for plugin-runner to exit before continuing boot
-#
-# Copyright © 2018 Teddy Hogeborn
-# Copyright © 2018 Björn Påhlsson
-#
-# This file is part of Mandos.
-#
-# Mandos 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.
-#
-# Mandos 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 Mandos. If not, see .
-#
-# Contact the authors at .
-#
-# This script will run in the initrd environment at boot and remove
-# the file keeping the dummy plugin running, forcing plugin-runner to
-# exit if it is still running.
-
-# This script should be installed as
-# "/usr/share/initramfs-tools/scripts/local-premount/mandos" which will
-# eventually be "/scripts/local-premount/mandos" in the initrd.img
-# file.
-
-PREREQ=""
-prereqs()
-{
- echo "$PREREQ"
-}
-
-case $1 in
-prereqs)
- prereqs
- exit 0
- ;;
-esac
-
-. /scripts/functions
-
-pid=$(cat /run/mandos-plugin-runner.pid 2>/dev/null)
-
-# If the dummy plugin is running, removing this file should force the
-# dummy plugin to exit successfully, thereby making plugin-runner shut
-# down all its other plugins and then exit itself.
-rm -f /run/mandos-keep-running >/dev/null 2>&1
-
-# Wait for exit of plugin-runner, if still running
-if [ -n "$pid" ]; then
- while :; do
- case "$(readlink /proc/"$pid"/exe 2>/dev/null)" in
- */plugin-runner) sleep 1;;
- *) break;;
- esac
- done
- rm -f /run/mandos-plugin-runner.pid >/dev/null 2>&1
-fi
=== removed file 'initramfs-unpack'
--- initramfs-unpack 2019-07-27 10:11:45 +0000
+++ initramfs-unpack 1970-01-01 00:00:00 +0000
@@ -1,84 +0,0 @@
-#!/bin/bash
-#
-# Initramfs unpacker - unpacks initramfs images into /tmp
-#
-# Copyright © 2013-2019 Teddy Hogeborn
-# Copyright © 2013-2019 Björn Påhlsson
-#
-# This file is part of Mandos.
-#
-# Mandos 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.
-#
-# Mandos 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 Mandos. If not, see
-# .
-#
-# Contact the authors at .
-
-cpio="cpio --extract --make-directories --unconditional --preserve-modification-time"
-
-if [ -z "$*" ]; then
- set -- /boot/initrd.img-*
-fi
-
-for imgfile in "$@"; do
- if ! [ -f "$imgfile" ]; then
- echo "Error: Not an existing file: $imgfile" >&2
- continue
- fi
- imgdir="${TMPDIR:-/tmp}/${imgfile##*/}"
- if [ -d "$imgdir" ]; then
- rm --recursive -- "$imgdir"
- fi
- mkdir --parents "$imgdir"
- # Does this image contain microcode?
- if $cpio --quiet --list --file="$imgfile" >/dev/null 2>&1; then
- # Number of bytes to skip to get to the compressed archive
- skip=$(($(LANG=C $cpio --io-size=1 --list --file="$imgfile" 2>&1 \
- | sed --quiet \
- --expression='s/^\([0-9]\+\) blocks$/\1/p')+8))
- if [ -x /usr/lib/dracut/skipcpio ]; then
- catimg="/usr/lib/dracut/skipcpio $imgfile"
- else
- catimg="dd if=$imgfile bs=$skip skip=1 status=noxfer"
- fi
- else
- echo "No microcode detected"
- catimg="cat -- $imgfile"
- fi
- while :; do
- # Determine the compression method
- if { $catimg 2>/dev/null | zcat --test >/dev/null 2>&1;
- [ ${PIPESTATUS[-1]} -eq 0 ]; }; then
- decomp="zcat"
- elif { $catimg 2>/dev/null | bzip2 --test >/dev/null 2>&1;
- [ ${PIPESTATUS[-1]} -eq 0 ]; }; then
- decomp="bzip2 --stdout --decompress"
- elif { $catimg 2>/dev/null | lzop --test >/dev/null 2>&1;
- [ ${PIPESTATUS[-1]} -eq 0 ]; }; then
- decomp="lzop --stdout --decompress"
- else
- skip=$((${skip}+1))
- echo "Could not determine compression of ${imgfile}; trying to skip ${skip} bytes" >&2
- catimg="dd if=$imgfile bs=$skip skip=1 status=noxfer"
- continue
- fi
- break
- done
- case "$catimg" in
- *skipcpio*) echo "Microcode detected, skipping";;
- *) echo "Microcode detected, skipping ${skip} bytes";;
- esac
- $catimg 2>/dev/null | $decomp | ( cd -- "$imgdir" && $cpio --quiet )
- if [ ${PIPESTATUS[-1]} -eq 0 ]; then
- echo "$imgfile unpacked into $imgdir"
- fi
-done
=== removed file 'intro.xml'
--- intro.xml 2019-08-04 12:42:49 +0000
+++ intro.xml 1970-01-01 00:00:00 +0000
@@ -1,472 +0,0 @@
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@recompile.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@recompile.se
-
-
-
-
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- intro
- 8mandos
-
-
-
- intro
-
- Introduction to the Mandos system
-
-
-
-
- DESCRIPTION
-
- This is the the Mandos system, which allows computers to have
- encrypted root file systems and at the same time be capable of
- remote and/or unattended reboots.
-
-
- The computers run a small client program in the initial RAM disk
- environment which will communicate with a server over a network.
- All network communication is encrypted using TLS. The clients
- are identified by the server using a TLS public key; each client
- has one unique to it. The server sends the clients an encrypted
- password. The encrypted password is decrypted by the clients
- using a separate OpenPGP key, and the password is then used to
- unlock the root file system, whereupon the computers can
- continue booting normally.
-
-
-
-
- INTRODUCTION
-
-
- You know how it is. You’ve heard of it happening. The Man
- comes and takes away your servers, your friends’ servers, the
- servers of everybody in the same hosting facility. The servers
- of their neighbors, and their neighbors’ friends. The servers
- of people who owe them money. And like
- that, they’re gone. And you doubt you’ll
- ever see them again.
-
-
- That is why your servers have encrypted root file systems.
- However, there’s a downside. There’s no going around it:
- rebooting is a pain. Dragging out that rarely-used keyboard and
- screen and unraveling cables behind your servers to plug them in
- to type in that password is messy, especially if you have many
- servers. There are some people who do clever things like using
- serial line consoles and daisy-chain it to the next server, and
- keep all the servers connected in a ring with serial cables,
- which will work, if your servers are physically close enough.
- There are also other out-of-band management solutions, but with
- all these, you still have to be on hand and
- manually type in the password at boot time. Otherwise the
- server just sits there, waiting for a password.
-
-
- Wouldn’t it be great if you could have the security of encrypted
- root file systems and still have servers that could boot up
- automatically if there was a short power outage while you were
- asleep? That you could reboot at will, without having someone
- run over to the server to type in the password?
-
-
- Well, with Mandos, you (almost) can! The gain in convenience
- will only be offset by a small loss in security. The setup is
- as follows:
-
-
- The server will still have its encrypted root file system. The
- password to this file system will be stored on another computer
- (henceforth known as the Mandos server) on the same local
- network. The password will not be stored
- in plaintext, but encrypted with OpenPGP. To decrypt this
- password, a key is needed. This key (the Mandos client key)
- will not be stored there, but back on the original server
- (henceforth known as the Mandos client) in the initial RAM disk
- image. Oh, and all network Mandos client/server communications
- will be encrypted, using TLS (SSL).
-
-
- So, at boot time, the Mandos client will ask for its encrypted
- data over the network, decrypt the data to get the password, use
- the password to decrypt the root file system, and the client can
- then continue booting.
-
-
- Now, of course the initial RAM disk image is not on the
- encrypted root file system, so anyone who had physical access
- could take the Mandos client computer offline and read the disk
- with their own tools to get the authentication keys used by a
- client. But, by then the Mandos server
- should notice that the original server has been offline for too
- long, and will no longer give out the encrypted key. The timing
- here is the only real weak point, and the method, frequency and
- timeout of the server’s checking can be adjusted to any desired
- level of paranoia.
-
-
- (The encrypted keys on the Mandos server is on its normal file
- system, so those are safe, provided the root file system of
- that server is encrypted.)
-
-
-
-
- FREQUENTLY ASKED QUESTIONS
-
- Couldn’t the security be defeated by…
-
-
- Grabbing the Mandos client key from the
- initrd really quickly?
-
- This, as mentioned above, is the only real weak point. But if
- you set the timing values tight enough, this will be really
- difficult to do. An attacker would have to physically
- disassemble the client computer, extract the key from the
- initial RAM disk image, and then connect to a still
- online Mandos server to get the encrypted key, and do
- all this before the Mandos server timeout
- kicks in and the Mandos server refuses to give out the key to
- anyone.
-
-
- Now, as the typical procedure seems to be to barge in and turn
- off and grab all computers, to maybe look
- at them months later, this is not likely. If someone does that,
- the whole system will lock itself up
- completely, since Mandos servers are no longer running.
-
-
- For sophisticated attackers who could do
- the clever thing, and had physical access
- to the server for enough time, it would be simpler to get a key
- for an encrypted file system by using hardware memory scanners
- and reading it right off the memory bus.
-
-
-
-
- Replay attacks?
-
- Nope, the network stuff is all done over TLS, which provides
- protection against that.
-
-
-
-
- Man-in-the-middle?
-
- No. The server only gives out the passwords to clients which
- have in the TLS handshake proven that
- they do indeed hold the private key corresponding to that
- client.
-
-
-
-
- How about sniffing the network traffic and decrypting it
- later by physically grabbing the Mandos client and using its
- key?
-
- We only use PFS (Perfect Forward Security)
- key exchange algorithms in TLS, which protects against this.
-
-
-
-
- Physically grabbing the Mandos server computer?
-
- You could protect that computer the
- old-fashioned way, with a must-type-in-the-password-at-boot
- method. Or you could have two computers be the Mandos server
- for each other.
-
-
- Multiple Mandos servers can coexist on a network without any
- trouble. They do not clash, and clients will try all
- available servers. This means that if just one reboots then
- the other can bring it back up, but if both reboot at the same
- time they will stay down until someone types in the password
- on one of them.
-
-
-
-
- Faking checker results?
-
- If the Mandos client does not have an SSH server, the default
- is for the Mandos server to use
- fping
, the replies to which
- could be faked to eliminate the timeout. But this could
- easily be changed to any shell command, with any security
- measures you like. If the Mandos client
- has an SSH server, the default
- configuration (as generated by
- mandos-keygen with the
- option) is for the Mandos server
- to use an ssh-keyscan command with strict
- keychecking, which can not be faked. Alternatively, IPsec
- could be used for the ping packets, making them secure.
-
-
-
-
-
- SECURITY
-
- So, in summary: The only weakness in the Mandos system is from
- people who have:
-
-
-
-
- The power to come in and physically take your servers,
- and
-
-
-
-
- The cunning and patience to do it carefully, one at a time,
- and quickly, faking Mandos
- client/server responses for each one before the timeout.
-
-
-
-
- While there are some who may be threatened by people who have
- both these attributes, they do not,
- probably, constitute the majority.
-
-
- If you do face such opponents, you must
- figure that they could just as well open your servers and read
- the file system keys right off the memory by running wires to
- the memory bus.
-
-
- What Mandos is designed to protect against is
- not such determined, focused, and competent
- attacks, but against the early morning knock on your door and
- the sudden absence of all the servers in your server room.
- Which it does nicely.
-
-
-
-
- PLUGINS
-
- In the early designs, the
- mandos-client8mandos program (which
- retrieves a password from the Mandos server) also prompted for a
- password on the terminal, in case a Mandos server could not be
- found. Other ways of retrieving a password could easily be
- envisoned, but this multiplicity of purpose was seen to be too
- complex to be a viable way to continue. Instead, the original
- program was separated into mandos-client8mandos and password-prompt8mandos, and a plugin-runner8mandos exist to run them both in parallel, allowing
- the first successful plugin to provide the password. This
- opened up for any number of additional plugins to run, all
- competing to be the first to find a password and provide it to
- the plugin runner.
-
-
- Four additional plugins are provided:
-
-
-
-
- plymouth
- 8mandos
-
-
-
- This prompts for a password when using
- plymouth8.
-
-
-
-
-
- usplash
- 8mandos
-
-
-
- This prompts for a password when using
- usplash8.
-
-
-
-
-
- splashy
- 8mandos
-
-
-
- This prompts for a password when using
- splashy8.
-
-
-
-
-
- askpass-fifo
- 8mandos
-
-
-
- To provide compatibility with the "askpass" program from
- cryptsetup, this plugin listens to the same FIFO as
- askpass would do.
-
-
-
-
-
- More plugins can easily be written and added by the system
- administrator; see the section called "WRITING PLUGINS" in
- plugin-runner
- 8mandos to learn the
- plugin requirements.
-
-
-
-
- SYSTEMD
-
- More advanced startup systems like systemd1,
- already have their own plugin-like mechanisms for allowing
- multiple agents to independently retrieve a password and deliver
- it to the subsystem requesting a password to unlock the root
- file system. On these systems, it would make no sense to run
- plugin-runner8mandos, the plugins of
- which would largely duplicate the work of (and conflict with)
- the existing systems prompting for passwords.
-
-
- As for systemd1 in particular, it has
- its own Password Agents system. Mandos uses this via its
- password-agent8mandos program, which
- is run instead of plugin-runner8mandos when systemd1
- is used during system startup.
-
-
-
- BUGS
-
-
-
-
- SEE ALSO
-
- mandos
- 8,
- mandos.conf
- 5,
- mandos-clients.conf
- 5,
- mandos-ctl
- 8,
- mandos-monitor
- 8,
- plugin-runner
- 8mandos,
- password-agent
- 8mandos,
- mandos-client
- 8mandos,
- password-prompt
- 8mandos,
- plymouth
- 8mandos,
- usplash
- 8mandos,
- splashy
- 8mandos,
- askpass-fifo
- 8mandos,
- mandos-keygen
- 8
-
-
-
-
- Mandos
-
-
-
- The Mandos home page.
-
-
-
-
-
-
-
-
-
-
-
=== added file 'key.pem'
--- key.pem 1970-01-01 00:00:00 +0000
+++ key.pem 2007-10-20 21:38:25 +0000
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKAIBAAKCAgEAriPn2IkZ+KvmPGXiAJ4vKFcQPhgZ3jaj+WVd1a1g70ge2sJm
+SedEiOO+JDQ8mTolCkgaQ2t1bm5FJBxMqyFwQ4vxymtQd74ymLzfiLts5o+UN0li
+gxq2QcS+r3bB5cV8przIblS2YBuK6jfzwludWBTscCqrWKmL51IyglTQVHerEoLd
+6KhBB2r5AHbnsF5k0OrdKtZOplfDum7gOaI5kmGkwBXkKaNAq3hkLQR0HIZy3S2n
+dfezCkFj7Rr7CUUwpV7VYbL11+GQ1FWFQJc0o4K5pogyyfyK4Jw2WQjDgZWG8mP0
+At9FlLlXNFooiE6cW5vj4/FgKW3WCF9MGGTVpCOJKXUlP6q2Cm9Kp3fg6di0tGn4
+vkRwtBI+jKQbZOOxTGdhe0GI+hm4iTu/lqVCVtPbQOa5aGkIybh/DVbRDp5cvYA+
+2uMC3sdLv2oOinJIviy3ydORjd/OaNbxWmDVjgfI3ppjy1H04iNLBmEK/42iLFtl
+OhScteahG1Cc7qtKnuou4kI8LWBsNzVNHiZyWvlW6ZvxqDWJBOKLRK+Gpjy7WwMw
+aUv1plbRZrKR+gLrhxR0Eqb1Hp23TxjTEB69JrF1yyYr2QJ8Ik6jqcnalD35Z1KN
+gSGrkMsEaGl+HOz5TVkvQdiZN/JWOZta4NlpDViG3i8d/VNjACkWMYka3/sCAwEA
+AQKCAgEApV0fWvbGnOfQGOa++Ms+CNa0a+LDHctRZxElTDX6aP9ZnW8hZ2igIkXy
+V7rrGK6oYd0aY4910koQijv9ajy0uM/56biCj1MkBPrGYrdosIEDxISBcfI5xLaq
+RUFG24Tv2/5FbtAu55EAF27OoXASOISWCeXbFLTcT+w0XqNfufZxk4CGbdro9bxV
+fGVtmoPoxKNjJryfr0KEcVO8xb4RYborkuS25/tI/Au1RTKHeFcMWJB0B4gSktiJ
+pa0LWkBD86Xch4xD/J8MwzX69d0gdW08ErIfWMPitWxiB6ZU0YdGwIK+QsP29UYT
+U3mSJ+5OeIfOnrSmFnFg4E5umnOWk1fCkX9FpFwjFy2H9FrF/BHyZrIbv8IeKgzw
+mySRXFl2KZUk8r8YyCTm4dtf2ZCU5KcUo9TOae1VzywjXFyV+AyOtFYcJ+FjHQag
+CjuT4NzmFqlwa4JWXsAtnom7eR+f4jpn3nPW2CYCE/tYxtF9fpGXdXCNaKo8fbsA
+FzOkvoPSAeOjDjcKba6Z/mMBb8or1ide06NEu77e8de8rWCEfdGbMGDmdLQaYI6u
+/WIY7ALRppqT9WKnAjKGgYkxFeZGGF8D4ARaLJYYJ71DGAKeSkK6RqHqhmWDcSI8
+cLh5WHqzCflQhxjVf5rCF/ASwTnbw0dsClqF35gw+TKAlXc/uhECggEBAOMVwVIR
+ZkCvcfH35RGxqMZ/Ca8Viqap5zLY/gL0YTM/HYhRPE8iUutCWGN1SBDQm2yKuk84
+H1Jjj7zTOxIVW0yov1m36KCsF31s8ks1b3uo+yEOyLhGpJPUq8mYAVbl/13Tcwp3
+0zs7oflZxK65vICUreJM9P/BqXJ/Edfddj88uIqjW98XGgTCgCHpFBxKfRzNkmi+
+3TBswZm2yqQ3qcrFN6H7ieUNCgN2Bj6tWlNmB/RCV+stbbEWwXbDlv1M+JNoM/Jw
+c1A++csAhx04BphNeKi01W0zEyRt6tlZWqolvhSUTom6xxWtjikqwfad6HMwn09V
+8luh5Ote2WNE8JcCggEBAMRQUlYKCTSvHuIscDukLExW+9JVKaufeXZvCuTK94Bs
+P0MtAgrHkgXdiRIBBFAViPjadMQitGkwKYd+zRPUmdzTuH9Lamqjl6e8dUpcO+Bf
+0scM94Te0gD8Gtv2Uu4Kw75P2RTXHRk9e8VbFpgYvfl9H0Uc8BK8jzlgWPqHgFnB
+WUXuMTAcKax4UwXdxWUjyv3xPmDygt7koPqpuX6FKvfxRq50a3TVIFku+8hRQtQR
+N+U0ScYrTOClTuc/QE0Q6rmw06lWHmytK3QiVhgpKxdw1xvVyjw5rMbB2eQdz7IQ
+2zn/o5+0gYdg/jvamo1HIxKjPCP1Lxm++manmy6kVD0CggEAeDwwm89yoJVEc6WZ
+uAClKFRjQDzbqNsU+ytBczcJsCSe8mpw0EWQOdhrDF4wxhZt9M6PTxqcGvd0R7pf
+8Hc2XCSNDGf/1/LGjTZ+I6wrVwJl1V8Kj+d3hH56ZscBDo3A5GDs7IH9acNtQ6Vw
+KkNVt48Bcmzk2/YiTelR/UXZMipoW5+bKUgGErcZONs8Nq6KCBIgjy1f2B/9cfIC
+4WhHkoFRr4aLwKdiwepf7BfFV5sSYxYtjuwCxF0UGln9PCjhBMuLlbZMmBSAFig1
+YhckBsgeNtVom+ULIaLBUkupYaWSOzs7SlmGx8eZGdr10CpTxYndEBiltjbGComx
++ImsCQKCAQBaaX+yHock225Gzh6WaUL5man6sbwyTY0cLYH/4zZfz/rGzmi9XDJ1
+PxVM1GkPFQvzSHE0j6M1Org1rgF3G5gNKvkyryIAoP1MhDAkohv1d0xU3jT03cYs
+K++W1HhXJ2AFOzMINRYytK1XNF9QhzyfNa/8HZq3ll4EF8qC/3ruW2zpFw1SUfYj
+d3sNHZk2vmhT0hJfhfEeBH/bUeWbTmt+q4FZAUcoFKwERu4w0LQNhSyQBCfh+7k5
+UQjo2amclKj2AmlI+N+kP5DeuJ2cHQG6lv6K1EiCujFHjKn0NIKeSMMekAzklbZ+
+Cf6sxD4fyN5vS/x7twUNP3aFZrXCom4lAoIBABSGp/CGw6xeQDPXvZZ7gpLr5m5P
+mp+gS3S2MJZUv+6TEwXgHxnbxt5DMe25RAlqVHTuw9/TVccD6qcERvnhxUFMoscD
+5Vg/Hj+D1nPEVxvFgq0xEPI2FcwS6xT8gicV5dsCWIlOY3ZxBzOzByW1iA2YNymj
+pNTypqkARnheZZCK+4ortIeczll5XpbyGIXyxfIrKLYyv38gqLwCdb+MJsih91qc
+SrijfhjqqK9sr5KyHlPJDI4Mlw//qkPwIiKv70TGsSgu775OyyZFEl3uS+Y4BUGa
+dk5d+8OviBYIReMvvyl6U0jFCUK579lEDpEOPDF2C6VvDQ3FyHP7UXaOWrI=
+-----END RSA PRIVATE KEY-----
=== removed file 'legalnotice.xml'
--- legalnotice.xml 2017-08-20 16:20:54 +0000
+++ legalnotice.xml 1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
-
-
-
-
- This manual page is part of Mandos.
-
-
-
- Mandos 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.
-
-
-
- Mandos 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 Mandos. If not, see http://www.gnu.org/licenses/.
-
-
=== removed file 'mandos-clients.conf.xml'
--- mandos-clients.conf.xml 2019-02-10 04:20:26 +0000
+++ mandos-clients.conf.xml 1970-01-01 00:00:00 +0000
@@ -1,567 +0,0 @@
-
-
-/etc/mandos/clients.conf">
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@recompile.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@recompile.se
-
-
-
-
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &CONFNAME;
- 5
-
-
-
- &CONFNAME;
-
- Configuration file for the Mandos server
-
-
-
-
- &CONFPATH;
-
-
-
- DESCRIPTION
-
- The file &CONFPATH; is a configuration file for mandos
- 8, read by it at startup.
- The file needs to list all clients that should be able to use
- the service. The settings in this file can be overridden by
- runtime changes to the server, which it saves across restarts.
- (See the section called PERSISTENT STATE
in
- mandos8.) However, any changes to this file (including adding and removing
- clients) will, at startup, override changes done during runtime.
-
-
- The format starts with a [section
- header] which is either
- [DEFAULT] or [client
- name]. The client
- name can be anything, and is not tied to a host
- name. Following the section header is any number of
- option=value
entries,
- with continuations in the style of RFC 822. option: value
is also accepted. Note that
- leading whitespace is removed from values. Values can contain
- format strings which refer to other values in the same section,
- or values in the DEFAULT
section (see ). Lines beginning with #
- or ;
are ignored and may be used to provide
- comments.
-
-
-
-
- OPTIONS
-
- Note: all option values are subject to
- start time expansion, see .
-
-
- Unknown options are ignored. The used options are as follows:
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- How long to wait for external approval before resorting to
- use the value. The
- default is PT0S
, i.e. not to wait.
-
-
- The format of TIME is the same
- as for timeout below.
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- How long an external approval lasts. The default is 1
- second.
-
-
- The format of TIME is the same
- as for timeout below.
-
-
-
-
-
-
-
-
- Whether to approve a client by default after
- the . The default
- is True
.
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- This option overrides the default shell command that the
- server will use to check if the client is still up. Any
- output of the command will be ignored, only the exit code
- is checked: If the exit code of the command is zero, the
- client is considered up. The command will be run using
- /bin/sh
-
, so
- PATH will be searched. The default
- value for the checker command is fping %%(host)s
. Note that
- mandos-keygen, when generating output
- to be inserted into this file, normally looks for an SSH
- server on the Mandos client, and, if it finds one, outputs
- a option to check for the
- client’s SSH key fingerprint – this is more secure against
- spoofing.
-
-
- In addition to normal start time expansion, this option
- will also be subject to runtime expansion; see .
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- Extended timeout is an added timeout that is given once
- after a password has been sent successfully to a client.
- The timeout is by default longer than the normal timeout,
- and is used for handling the extra long downtime while a
- machine is booting up. Time to take into consideration
- when changing this value is file system checks and quota
- checks. The default value is 15 minutes.
-
-
- The format of TIME is the same
- as for timeout below.
-
-
-
-
-
-
-
-
- This option is required.
-
-
- This option sets the OpenPGP fingerprint that identifies
- the public key that clients authenticate themselves with
- through TLS. The string needs to be in hexadecimal form,
- but spaces or upper/lower case are not significant.
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- This option sets the certificate key ID that identifies
- the public key that clients authenticate themselves with
- through TLS. The string needs to be in hexadecimal form,
- but spaces or upper/lower case are not significant.
-
-
-
-
-
-
-
-
- This option is optional, but highly
- recommended unless the
- option is modified to a
- non-standard value without %%(host)s
in it.
-
-
- Host name for this client. This is not used by the server
- directly, but can be, and is by default, used by the
- checker. See the option.
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- How often to run the checker to confirm that a client is
- still up. Note: a new checker will
- not be started if an old one is still running. The server
- will wait for a checker to complete until the below
- timeout
occurs, at which
- time the client will be disabled, and any running checker
- killed. The default interval is 2 minutes.
-
-
- The format of TIME is the same
- as for timeout below.
-
-
-
-
-
-
-
-
- This option is only used if is not
- specified, in which case this option is
- required.
-
-
- Similar to the , except the secret
- data is in an external file. The contents of the file
- should not be base64-encoded, but
- will be sent to clients verbatim.
-
-
- File names of the form ~user/foo/bar
- and $ENVVAR/foo/bar
- are supported.
-
-
-
-
-
-
-
-
- If this option is not specified, the option is required
- to be present.
-
-
- If present, this option must be set to a string of
- base64-encoded binary data. It will be decoded and sent
- to the client matching the above
- or . This should, of course,
- be OpenPGP encrypted data, decryptable only by the client.
- The program mandos-keygen8 can, using its
- option, be used to generate
- this, if desired.
-
-
- Note: this value of this option will probably be very
- long. A useful feature to avoid having unreadably-long
- lines is that a line beginning with white space adds to
- the value of the previous line, RFC 822-style.
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- The timeout is how long the server will wait, after a
- successful checker run, until a client is disabled and not
- allowed to get the data this server holds. By default
- Mandos will use 5 minutes. See also the
- option.
-
-
- The TIME is specified as an RFC
- 3339 duration; for example
- P1Y2M3DT4H5M6S
meaning
- one year, two months, three days, four hours, five
- minutes, and six seconds. Some values can be omitted, see
- RFC 3339 Appendix A for details.
-
-
-
-
-
-
-
-
- Whether this client should be enabled by default. The
- default is true
.
-
-
-
-
-
-
-
-
- EXPANSION
-
- There are two forms of expansion: Start time expansion and
- runtime expansion.
-
-
- START TIME EXPANSION
-
- Any string in an option value of the form
- %(foo)s
will be replaced by the value of the option
- foo either in the same section, or, if it
- does not exist there, the [DEFAULT]
- section. This is done at start time, when the configuration
- file is read.
-
-
- Note that this means that, in order to include an actual
- percent character (%
) in an option value, two
- percent characters in a row (%%
) must be
- entered.
-
-
-
- RUNTIME EXPANSION
-
- This is currently only done for the checker
- option.
-
-
- Any string in an option value of the form
- %%(foo)s
will be replaced by the value of the attribute
- foo of the internal
- Client
object in the
- Mandos server. The currently allowed values for
- foo are:
- approval_delay
,
- approval_duration
,
- created
,
- enabled
,
- expires
,
- key_id
,
- fingerprint
,
- host
,
- interval
,
- last_approval_request
,
- last_checked_ok
,
- last_enabled
,
- name
,
- timeout
, and, if using
- D-Bus, dbus_object_path
.
- See the source code for details. Currently, none of these attributes
- except host
are guaranteed
- to be valid in future versions. Therefore, please
- let the authors know of any attributes that are useful so they
- may be preserved to any new versions of this software.
-
-
- Note that this means that, in order to include an actual
- percent character (%
) in a
- checker option, four
- percent characters in a row (%%%%
) must be
- entered. Also, a bad format here will lead to an immediate
- but silent run-time fatal exit; debug
- mode is needed to expose an error of this kind.
-
-
-
-
-
-
- FILES
-
- The file described here is &CONFPATH;
-
-
-
-
- BUGS
-
- The format for specifying times for timeout
- and interval is not very good.
-
-
- The difference between
- %%(foo)s and
- %(foo)s is
- obscure.
-
-
-
-
-
- EXAMPLE
-
-
-[DEFAULT]
-timeout = PT5M
-interval = PT2M
-checker = fping -q -- %%(host)s
-
-# Client "foo"
-[foo]
-key_id = 788cd77115cd0bb7b2d5e0ae8496f6b48149d5e712c652076b1fd2d957ef7c1f
-fingerprint = 7788 2722 5BA7 DE53 9C5A 7CFA 59CF F7CD BD9A 5920
-secret =
- hQIOA6QdEjBs2L/HEAf/TCyrDe5Xnm9esa+Pb/vWF9CUqfn4srzVgSu234
- REJMVv7lBSrPE2132Lmd2gqF1HeLKDJRSVxJpt6xoWOChGHg+TMyXDxK+N
- Xl89vGvdU1XfhKkVm9MDLOgT5ECDPysDGHFPDhqHOSu3Kaw2DWMV/iH9vz
- 3Z20erVNbdcvyBnuojcoWO/6yfB5EQO0BXp7kcyy00USA3CjD5FGZdoQGI
- Tb8A/ar0tVA5crSQmaSotm6KmNLhrFnZ5BxX+TiE+eTUTqSloWRY6VAvqW
- QHC7OASxK5E6RXPBuFH5IohUA2Qbk5AHt99pYvsIPX88j2rWauOokoiKZo
- t/9leJ8VxO5l3wf/U64IH8bkPIoWmWZfd/nqh4uwGNbCgKMyT+AnvH7kMJ
- 3i7DivfWl2mKLV0PyPHUNva0VQxX6yYjcOhj1R6fCr/at8/NSLe2OhLchz
- dC+Ls9h+kvJXgF8Sisv+Wk/1RadPLFmraRlqvJwt6Ww21LpiXqXHV2mIgq
- WnR98YgSvUi3TJHrUQiNc9YyBzuRo0AjgG2C9qiE3FM+Y28+iQ/sR3+bFs
- zYuZKVTObqiIslwXu7imO0cvvFRgJF/6u3HNFQ4LUTGhiM3FQmC6NNlF3/
- vJM2hwRDMcJqDd54Twx90Wh+tYz0z7QMsK4ANXWHHWHR0JchnLWmenzbtW
- 5MHdW9AYsNJZAQSOpirE4Xi31CSlWAi9KV+cUCmWF5zOFy1x23P6PjdaRm
- 4T2zw4dxS5NswXWU0sVEXxjs6PYxuIiCTL7vdpx8QjBkrPWDrAbcMyBr2O
- QlnHIvPzEArRQLo=
-host = foo.example.org
-interval = PT1M
-
-# Client "bar"
-[bar]
-key_id = F90C7A81D72D1EA69A51031A91FF8885F36C8B46D155C8C58709A4C99AE9E361
-fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27
-secfile = /etc/mandos/bar-secret
-timeout = PT15M
-approved_by_default = False
-approval_delay = PT30S
-
-
-
-
-
- SEE ALSO
-
- intro
- 8mandos,
- mandos-keygen
- 8,
- mandos.conf
- 5,
- mandos
- 8,
- fping
- 8
-
-
-
-
- RFC 3339: Date and Time on the Internet:
- Timestamps
-
-
-
- The time intervals are in the "duration" format, as
- specified in ABNF in Appendix A of RFC 3339.
-
-
-
-
-
-
-
-
-
-
-
=== removed file 'mandos-ctl'
--- mandos-ctl 2019-11-03 19:09:41 +0000
+++ mandos-ctl 1970-01-01 00:00:00 +0000
@@ -1,2535 +0,0 @@
-#!/usr/bin/python3 -bbI
-# -*- after-save-hook: (lambda () (let ((command (if (fboundp 'file-local-name) (file-local-name (buffer-file-name)) (or (file-remote-p (buffer-file-name) 'localname) (buffer-file-name))))) (if (= (progn (if (get-buffer "*Test*") (kill-buffer "*Test*")) (process-file-shell-command (format "%s --check" (shell-quote-argument command)) nil "*Test*")) 0) (let ((w (get-buffer-window "*Test*"))) (if w (delete-window w))) (progn (with-current-buffer "*Test*" (compilation-mode)) (display-buffer "*Test*" '(display-buffer-in-side-window)))))); coding: utf-8 -*-
-#
-# Mandos Monitor - Control and monitor the Mandos server
-#
-# Copyright © 2008-2019 Teddy Hogeborn
-# Copyright © 2008-2019 Björn Påhlsson
-#
-# This file is part of Mandos.
-#
-# Mandos 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.
-#
-# Mandos 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 Mandos. If not, see .
-#
-# Contact the authors at .
-#
-
-from __future__ import (division, absolute_import, print_function,
- unicode_literals)
-
-try:
- from future_builtins import *
-except ImportError:
- pass
-
-import sys
-import argparse
-import locale
-import datetime
-import re
-import os
-import collections
-import json
-import unittest
-import logging
-import io
-import tempfile
-import contextlib
-
-if sys.version_info.major == 2:
- __metaclass__ = type
-
-try:
- import pydbus
- import gi
- dbus_python = None
-except ImportError:
- import dbus as dbus_python
- pydbus = None
- class gi:
- """Dummy gi module, for the tests"""
- class repository:
- class GLib:
- class Error(Exception):
- pass
-
-# Show warnings by default
-if not sys.warnoptions:
- import warnings
- warnings.simplefilter("default")
-
-log = logging.getLogger(sys.argv[0])
-logging.basicConfig(level="INFO", # Show info level messages
- format="%(message)s") # Show basic log messages
-
-logging.captureWarnings(True) # Show warnings via the logging system
-
-if sys.version_info.major == 2:
- str = unicode
- import StringIO
- io.StringIO = StringIO.StringIO
-
-locale.setlocale(locale.LC_ALL, "")
-
-version = "1.8.9"
-
-
-def main():
- parser = argparse.ArgumentParser()
- add_command_line_options(parser)
-
- options = parser.parse_args()
- check_option_syntax(parser, options)
-
- clientnames = options.client
-
- if options.debug:
- log.setLevel(logging.DEBUG)
-
- if pydbus is not None:
- bus = pydbus_adapter.CachingBus(pydbus)
- else:
- bus = dbus_python_adapter.CachingBus(dbus_python)
-
- try:
- all_clients = bus.get_clients_and_properties()
- except dbus.ConnectFailed as e:
- log.critical("Could not connect to Mandos server: %s", e)
- sys.exit(1)
- except dbus.Error as e:
- log.critical(
- "Failed to access Mandos server through D-Bus:\n%s", e)
- sys.exit(1)
-
- # Compile dict of (clientpath: properties) to process
- if not clientnames:
- clients = all_clients
- else:
- clients = {}
- for name in clientnames:
- for objpath, properties in all_clients.items():
- if properties["Name"] == name:
- clients[objpath] = properties
- break
- else:
- log.critical("Client not found on server: %r", name)
- sys.exit(1)
-
- commands = commands_from_options(options)
-
- for command in commands:
- command.run(clients, bus)
-
-
-def add_command_line_options(parser):
- parser.add_argument("--version", action="version",
- version="%(prog)s {}".format(version),
- help="show version number and exit")
- parser.add_argument("-a", "--all", action="store_true",
- help="Select all clients")
- parser.add_argument("-v", "--verbose", action="store_true",
- help="Print all fields")
- parser.add_argument("-j", "--dump-json", dest="commands",
- action="append_const", default=[],
- const=command.DumpJSON(),
- help="Dump client data in JSON format")
- enable_disable = parser.add_mutually_exclusive_group()
- enable_disable.add_argument("-e", "--enable", dest="commands",
- action="append_const", default=[],
- const=command.Enable(),
- help="Enable client")
- enable_disable.add_argument("-d", "--disable", dest="commands",
- action="append_const", default=[],
- const=command.Disable(),
- help="disable client")
- parser.add_argument("-b", "--bump-timeout", dest="commands",
- action="append_const", default=[],
- const=command.BumpTimeout(),
- help="Bump timeout for client")
- start_stop_checker = parser.add_mutually_exclusive_group()
- start_stop_checker.add_argument("--start-checker",
- dest="commands",
- action="append_const", default=[],
- const=command.StartChecker(),
- help="Start checker for client")
- start_stop_checker.add_argument("--stop-checker", dest="commands",
- action="append_const", default=[],
- const=command.StopChecker(),
- help="Stop checker for client")
- parser.add_argument("-V", "--is-enabled", dest="commands",
- action="append_const", default=[],
- const=command.IsEnabled(),
- help="Check if client is enabled")
- parser.add_argument("-r", "--remove", dest="commands",
- action="append_const", default=[],
- const=command.Remove(),
- help="Remove client")
- parser.add_argument("-c", "--checker", dest="commands",
- action="append", default=[],
- metavar="COMMAND", type=command.SetChecker,
- help="Set checker command for client")
- parser.add_argument(
- "-t", "--timeout", dest="commands", action="append",
- default=[], metavar="TIME",
- type=command.SetTimeout.argparse(string_to_delta),
- help="Set timeout for client")
- parser.add_argument(
- "--extended-timeout", dest="commands", action="append",
- default=[], metavar="TIME",
- type=command.SetExtendedTimeout.argparse(string_to_delta),
- help="Set extended timeout for client")
- parser.add_argument(
- "-i", "--interval", dest="commands", action="append",
- default=[], metavar="TIME",
- type=command.SetInterval.argparse(string_to_delta),
- help="Set checker interval for client")
- approve_deny_default = parser.add_mutually_exclusive_group()
- approve_deny_default.add_argument(
- "--approve-by-default", dest="commands",
- action="append_const", default=[],
- const=command.ApproveByDefault(),
- help="Set client to be approved by default")
- approve_deny_default.add_argument(
- "--deny-by-default", dest="commands",
- action="append_const", default=[],
- const=command.DenyByDefault(),
- help="Set client to be denied by default")
- parser.add_argument(
- "--approval-delay", dest="commands", action="append",
- default=[], metavar="TIME",
- type=command.SetApprovalDelay.argparse(string_to_delta),
- help="Set delay before client approve/deny")
- parser.add_argument(
- "--approval-duration", dest="commands", action="append",
- default=[], metavar="TIME",
- type=command.SetApprovalDuration.argparse(string_to_delta),
- help="Set duration of one client approval")
- parser.add_argument("-H", "--host", dest="commands",
- action="append", default=[], metavar="STRING",
- type=command.SetHost,
- help="Set host for client")
- parser.add_argument(
- "-s", "--secret", dest="commands", action="append",
- default=[], metavar="FILENAME",
- type=command.SetSecret.argparse(argparse.FileType(mode="rb")),
- help="Set password blob (file) for client")
- approve_deny = parser.add_mutually_exclusive_group()
- approve_deny.add_argument(
- "-A", "--approve", dest="commands", action="append_const",
- default=[], const=command.Approve(),
- help="Approve any current client request")
- approve_deny.add_argument("-D", "--deny", dest="commands",
- action="append_const", default=[],
- const=command.Deny(),
- help="Deny any current client request")
- parser.add_argument("--debug", action="store_true",
- help="Debug mode (show D-Bus commands)")
- parser.add_argument("--check", action="store_true",
- help="Run self-test")
- parser.add_argument("client", nargs="*", help="Client name")
-
-
-def string_to_delta(interval):
- """Parse a string and return a datetime.timedelta"""
-
- try:
- return rfc3339_duration_to_delta(interval)
- except ValueError as e:
- log.warning("%s - Parsing as pre-1.6.1 interval instead",
- ' '.join(e.args))
- return parse_pre_1_6_1_interval(interval)
-
-
-def rfc3339_duration_to_delta(duration):
- """Parse an RFC 3339 "duration" and return a datetime.timedelta
-
- >>> rfc3339_duration_to_delta("P7D") == datetime.timedelta(7)
- True
- >>> rfc3339_duration_to_delta("PT60S") == datetime.timedelta(0, 60)
- True
- >>> rfc3339_duration_to_delta("PT60M") == datetime.timedelta(hours=1)
- True
- >>> # 60 months
- >>> rfc3339_duration_to_delta("P60M") == datetime.timedelta(1680)
- True
- >>> rfc3339_duration_to_delta("PT24H") == datetime.timedelta(1)
- True
- >>> rfc3339_duration_to_delta("P1W") == datetime.timedelta(7)
- True
- >>> rfc3339_duration_to_delta("PT5M30S") == datetime.timedelta(0, 330)
- True
- >>> rfc3339_duration_to_delta("P1DT3M20S") == datetime.timedelta(1, 200)
- True
- >>> # Can not be empty:
- >>> rfc3339_duration_to_delta("")
- Traceback (most recent call last):
- ...
- ValueError: Invalid RFC 3339 duration: ""
- >>> # Must start with "P":
- >>> rfc3339_duration_to_delta("1D")
- Traceback (most recent call last):
- ...
- ValueError: Invalid RFC 3339 duration: "1D"
- >>> # Must use correct order
- >>> rfc3339_duration_to_delta("PT1S2M")
- Traceback (most recent call last):
- ...
- ValueError: Invalid RFC 3339 duration: "PT1S2M"
- >>> # Time needs time marker
- >>> rfc3339_duration_to_delta("P1H2S")
- Traceback (most recent call last):
- ...
- ValueError: Invalid RFC 3339 duration: "P1H2S"
- >>> # Weeks can not be combined with anything else
- >>> rfc3339_duration_to_delta("P1D2W")
- Traceback (most recent call last):
- ...
- ValueError: Invalid RFC 3339 duration: "P1D2W"
- >>> rfc3339_duration_to_delta("P2W2H")
- Traceback (most recent call last):
- ...
- ValueError: Invalid RFC 3339 duration: "P2W2H"
- """
-
- # Parsing an RFC 3339 duration with regular expressions is not
- # possible - there would have to be multiple places for the same
- # values, like seconds. The current code, while more esoteric, is
- # cleaner without depending on a parsing library. If Python had a
- # built-in library for parsing we would use it, but we'd like to
- # avoid excessive use of external libraries.
-
- # New type for defining tokens, syntax, and semantics all-in-one
- Token = collections.namedtuple("Token", (
- "regexp", # To match token; if "value" is not None, must have
- # a "group" containing digits
- "value", # datetime.timedelta or None
- "followers")) # Tokens valid after this token
- # RFC 3339 "duration" tokens, syntax, and semantics; taken from
- # the "duration" ABNF definition in RFC 3339, Appendix A.
- token_end = Token(re.compile(r"$"), None, frozenset())
- token_second = Token(re.compile(r"(\d+)S"),
- datetime.timedelta(seconds=1),
- frozenset((token_end, )))
- token_minute = Token(re.compile(r"(\d+)M"),
- datetime.timedelta(minutes=1),
- frozenset((token_second, token_end)))
- token_hour = Token(re.compile(r"(\d+)H"),
- datetime.timedelta(hours=1),
- frozenset((token_minute, token_end)))
- token_time = Token(re.compile(r"T"),
- None,
- frozenset((token_hour, token_minute,
- token_second)))
- token_day = Token(re.compile(r"(\d+)D"),
- datetime.timedelta(days=1),
- frozenset((token_time, token_end)))
- token_month = Token(re.compile(r"(\d+)M"),
- datetime.timedelta(weeks=4),
- frozenset((token_day, token_end)))
- token_year = Token(re.compile(r"(\d+)Y"),
- datetime.timedelta(weeks=52),
- frozenset((token_month, token_end)))
- token_week = Token(re.compile(r"(\d+)W"),
- datetime.timedelta(weeks=1),
- frozenset((token_end, )))
- token_duration = Token(re.compile(r"P"), None,
- frozenset((token_year, token_month,
- token_day, token_time,
- token_week)))
- # Define starting values:
- # Value so far
- value = datetime.timedelta()
- found_token = None
- # Following valid tokens
- followers = frozenset((token_duration, ))
- # String left to parse
- s = duration
- # Loop until end token is found
- while found_token is not token_end:
- # Search for any currently valid tokens
- for token in followers:
- match = token.regexp.match(s)
- if match is not None:
- # Token found
- if token.value is not None:
- # Value found, parse digits
- factor = int(match.group(1), 10)
- # Add to value so far
- value += factor * token.value
- # Strip token from string
- s = token.regexp.sub("", s, 1)
- # Go to found token
- found_token = token
- # Set valid next tokens
- followers = found_token.followers
- break
- else:
- # No currently valid tokens were found
- raise ValueError("Invalid RFC 3339 duration: \"{}\""
- .format(duration))
- # End token found
- return value
-
-
-def parse_pre_1_6_1_interval(interval):
- """Parse an interval string as documented by Mandos before 1.6.1,
- and return a datetime.timedelta
-
- >>> parse_pre_1_6_1_interval('7d') == datetime.timedelta(days=7)
- True
- >>> parse_pre_1_6_1_interval('60s') == datetime.timedelta(0, 60)
- True
- >>> parse_pre_1_6_1_interval('60m') == datetime.timedelta(hours=1)
- True
- >>> parse_pre_1_6_1_interval('24h') == datetime.timedelta(days=1)
- True
- >>> parse_pre_1_6_1_interval('1w') == datetime.timedelta(days=7)
- True
- >>> parse_pre_1_6_1_interval('5m 30s') == datetime.timedelta(0, 330)
- True
- >>> parse_pre_1_6_1_interval('') == datetime.timedelta(0)
- True
- >>> # Ignore unknown characters, allow any order and repetitions
- >>> parse_pre_1_6_1_interval('2dxy7zz11y3m5m') == datetime.timedelta(2, 480, 18000)
- True
-
- """
-
- value = datetime.timedelta(0)
- regexp = re.compile(r"(\d+)([dsmhw]?)")
-
- for num, suffix in regexp.findall(interval):
- if suffix == "d":
- value += datetime.timedelta(int(num))
- elif suffix == "s":
- value += datetime.timedelta(0, int(num))
- elif suffix == "m":
- value += datetime.timedelta(0, 0, 0, 0, int(num))
- elif suffix == "h":
- value += datetime.timedelta(0, 0, 0, 0, 0, int(num))
- elif suffix == "w":
- value += datetime.timedelta(0, 0, 0, 0, 0, 0, int(num))
- elif suffix == "":
- value += datetime.timedelta(0, 0, 0, int(num))
- return value
-
-
-def check_option_syntax(parser, options):
- """Apply additional restrictions on options, not expressible in
-argparse"""
-
- def has_commands(options, commands=None):
- if commands is None:
- commands = (command.Enable,
- command.Disable,
- command.BumpTimeout,
- command.StartChecker,
- command.StopChecker,
- command.IsEnabled,
- command.Remove,
- command.SetChecker,
- command.SetTimeout,
- command.SetExtendedTimeout,
- command.SetInterval,
- command.ApproveByDefault,
- command.DenyByDefault,
- command.SetApprovalDelay,
- command.SetApprovalDuration,
- command.SetHost,
- command.SetSecret,
- command.Approve,
- command.Deny)
- return any(isinstance(cmd, commands)
- for cmd in options.commands)
-
- if has_commands(options) and not (options.client or options.all):
- parser.error("Options require clients names or --all.")
- if options.verbose and has_commands(options):
- parser.error("--verbose can only be used alone.")
- if (has_commands(options, (command.DumpJSON,))
- and (options.verbose or len(options.commands) > 1)):
- parser.error("--dump-json can only be used alone.")
- if options.all and not has_commands(options):
- parser.error("--all requires an action.")
- if (has_commands(options, (command.IsEnabled,))
- and len(options.client) > 1):
- parser.error("--is-enabled requires exactly one client")
- if (len(options.commands) > 1
- and has_commands(options, (command.Remove,))
- and not has_commands(options, (command.Deny,))):
- parser.error("--remove can only be combined with --deny")
-
-
-class dbus:
-
- class SystemBus:
-
- object_manager_iface = "org.freedesktop.DBus.ObjectManager"
- def get_managed_objects(self, busname, objectpath):
- return self.call_method("GetManagedObjects", busname,
- objectpath,
- self.object_manager_iface)
-
- properties_iface = "org.freedesktop.DBus.Properties"
- def set_property(self, busname, objectpath, interface, key,
- value):
- self.call_method("Set", busname, objectpath,
- self.properties_iface, interface, key,
- value)
-
-
- class MandosBus(SystemBus):
- busname_domain = "se.recompile"
- busname = busname_domain + ".Mandos"
- server_path = "/"
- server_interface = busname_domain + ".Mandos"
- client_interface = busname_domain + ".Mandos.Client"
- del busname_domain
-
- def get_clients_and_properties(self):
- managed_objects = self.get_managed_objects(
- self.busname, self.server_path)
- return {objpath: properties[self.client_interface]
- for objpath, properties in managed_objects.items()
- if self.client_interface in properties}
-
- def set_client_property(self, objectpath, key, value):
- return self.set_property(self.busname, objectpath,
- self.client_interface, key,
- value)
-
- def call_client_method(self, objectpath, method, *args):
- return self.call_method(method, self.busname, objectpath,
- self.client_interface, *args)
-
- def call_server_method(self, method, *args):
- return self.call_method(method, self.busname,
- self.server_path,
- self.server_interface, *args)
-
- class Error(Exception):
- pass
-
- class ConnectFailed(Error):
- pass
-
-
-class dbus_python_adapter:
-
- class SystemBus(dbus.MandosBus):
- """Use dbus-python"""
-
- def __init__(self, module=dbus_python):
- self.dbus_python = module
- self.bus = self.dbus_python.SystemBus()
-
- @contextlib.contextmanager
- def convert_exception(self, exception_class=dbus.Error):
- try:
- yield
- except self.dbus_python.exceptions.DBusException as e:
- # This does what "raise from" would do
- exc = exception_class(*e.args)
- exc.__cause__ = e
- raise exc
-
- def call_method(self, methodname, busname, objectpath,
- interface, *args):
- proxy_object = self.get_object(busname, objectpath)
- log.debug("D-Bus: %s:%s:%s.%s(%s)", busname, objectpath,
- interface, methodname,
- ", ".join(repr(a) for a in args))
- method = getattr(proxy_object, methodname)
- with self.convert_exception():
- with dbus_python_adapter.SilenceLogger(
- "dbus.proxies"):
- value = method(*args, dbus_interface=interface)
- return self.type_filter(value)
-
- def get_object(self, busname, objectpath):
- log.debug("D-Bus: Connect to: (busname=%r, path=%r)",
- busname, objectpath)
- with self.convert_exception(dbus.ConnectFailed):
- return self.bus.get_object(busname, objectpath)
-
- def type_filter(self, value):
- """Convert the most bothersome types to Python types"""
- if isinstance(value, self.dbus_python.Boolean):
- return bool(value)
- if isinstance(value, self.dbus_python.ObjectPath):
- return str(value)
- # Also recurse into dictionaries
- if isinstance(value, self.dbus_python.Dictionary):
- return {self.type_filter(key):
- self.type_filter(subval)
- for key, subval in value.items()}
- return value
-
- def set_client_property(self, objectpath, key, value):
- if key == "Secret":
- if not isinstance(value, bytes):
- value = value.encode("utf-8")
- value = self.dbus_python.ByteArray(value)
- return self.set_property(self.busname, objectpath,
- self.client_interface, key,
- value)
-
- class SilenceLogger:
- "Simple context manager to silence a particular logger"
- def __init__(self, loggername):
- self.logger = logging.getLogger(loggername)
-
- def __enter__(self):
- self.logger.addFilter(self.nullfilter)
-
- class NullFilter(logging.Filter):
- def filter(self, record):
- return False
-
- nullfilter = NullFilter()
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.logger.removeFilter(self.nullfilter)
-
-
- class CachingBus(SystemBus):
- """A caching layer for dbus_python_adapter.SystemBus"""
- def __init__(self, *args, **kwargs):
- self.object_cache = {}
- super(dbus_python_adapter.CachingBus,
- self).__init__(*args, **kwargs)
- def get_object(self, busname, objectpath):
- try:
- return self.object_cache[(busname, objectpath)]
- except KeyError:
- new_object = super(
- dbus_python_adapter.CachingBus,
- self).get_object(busname, objectpath)
- self.object_cache[(busname, objectpath)] = new_object
- return new_object
-
-
-class pydbus_adapter:
- class SystemBus(dbus.MandosBus):
- def __init__(self, module=pydbus):
- self.pydbus = module
- self.bus = self.pydbus.SystemBus()
-
- @contextlib.contextmanager
- def convert_exception(self, exception_class=dbus.Error):
- try:
- yield
- except gi.repository.GLib.Error as e:
- # This does what "raise from" would do
- exc = exception_class(*e.args)
- exc.__cause__ = e
- raise exc
-
- def call_method(self, methodname, busname, objectpath,
- interface, *args):
- proxy_object = self.get(busname, objectpath)
- log.debug("D-Bus: %s:%s:%s.%s(%s)", busname, objectpath,
- interface, methodname,
- ", ".join(repr(a) for a in args))
- method = getattr(proxy_object[interface], methodname)
- with self.convert_exception():
- return method(*args)
-
- def get(self, busname, objectpath):
- log.debug("D-Bus: Connect to: (busname=%r, path=%r)",
- busname, objectpath)
- with self.convert_exception(dbus.ConnectFailed):
- if sys.version_info.major <= 2:
- with warnings.catch_warnings():
- warnings.filterwarnings(
- "ignore", "", DeprecationWarning,
- r"^xml\.etree\.ElementTree$")
- return self.bus.get(busname, objectpath)
- else:
- return self.bus.get(busname, objectpath)
-
- def set_property(self, busname, objectpath, interface, key,
- value):
- proxy_object = self.get(busname, objectpath)
- log.debug("D-Bus: %s:%s:%s.Set(%r, %r, %r)", busname,
- objectpath, self.properties_iface, interface,
- key, value)
- setattr(proxy_object[interface], key, value)
-
- class CachingBus(SystemBus):
- """A caching layer for pydbus_adapter.SystemBus"""
- def __init__(self, *args, **kwargs):
- self.object_cache = {}
- super(pydbus_adapter.CachingBus,
- self).__init__(*args, **kwargs)
- def get(self, busname, objectpath):
- try:
- return self.object_cache[(busname, objectpath)]
- except KeyError:
- new_object = (super(pydbus_adapter.CachingBus, self)
- .get(busname, objectpath))
- self.object_cache[(busname, objectpath)] = new_object
- return new_object
-
-
-def commands_from_options(options):
-
- commands = list(options.commands)
-
- def find_cmd(cmd, commands):
- i = 0
- for i, c in enumerate(commands):
- if isinstance(c, cmd):
- return i
- return i+1
-
- # If command.Remove is present, move any instances of command.Deny
- # to occur ahead of command.Remove.
- index_of_remove = find_cmd(command.Remove, commands)
- before_remove = commands[:index_of_remove]
- after_remove = commands[index_of_remove:]
- cleaned_after = []
- for cmd in after_remove:
- if isinstance(cmd, command.Deny):
- before_remove.append(cmd)
- else:
- cleaned_after.append(cmd)
- if cleaned_after != after_remove:
- commands = before_remove + cleaned_after
-
- # If no command option has been given, show table of clients,
- # optionally verbosely
- if not commands:
- commands.append(command.PrintTable(verbose=options.verbose))
-
- return commands
-
-
-class command:
- """A namespace for command classes"""
-
- class Base:
- """Abstract base class for commands"""
- def run(self, clients, bus=None):
- """Normal commands should implement run_on_one_client(),
-but commands which want to operate on all clients at the same time can
-override this run() method instead.
-"""
- self.bus = bus
- for client, properties in clients.items():
- self.run_on_one_client(client, properties)
-
-
- class IsEnabled(Base):
- def run(self, clients, bus=None):
- properties = next(iter(clients.values()))
- if properties["Enabled"]:
- sys.exit(0)
- sys.exit(1)
-
-
- class Approve(Base):
- def run_on_one_client(self, client, properties):
- self.bus.call_client_method(client, "Approve", True)
-
-
- class Deny(Base):
- def run_on_one_client(self, client, properties):
- self.bus.call_client_method(client, "Approve", False)
-
-
- class Remove(Base):
- def run(self, clients, bus):
- for clientpath in frozenset(clients.keys()):
- bus.call_server_method("RemoveClient", clientpath)
-
-
- class Output(Base):
- """Abstract class for commands outputting client details"""
- all_keywords = ("Name", "Enabled", "Timeout", "LastCheckedOK",
- "Created", "Interval", "Host", "KeyID",
- "Fingerprint", "CheckerRunning",
- "LastEnabled", "ApprovalPending",
- "ApprovedByDefault", "LastApprovalRequest",
- "ApprovalDelay", "ApprovalDuration",
- "Checker", "ExtendedTimeout", "Expires",
- "LastCheckerStatus")
-
-
- class DumpJSON(Output):
- def run(self, clients, bus=None):
- data = {properties["Name"]:
- {key: properties[key]
- for key in self.all_keywords}
- for properties in clients.values()}
- print(json.dumps(data, indent=4, separators=(',', ': ')))
-
-
- class PrintTable(Output):
- def __init__(self, verbose=False):
- self.verbose = verbose
-
- def run(self, clients, bus=None):
- default_keywords = ("Name", "Enabled", "Timeout",
- "LastCheckedOK")
- keywords = default_keywords
- if self.verbose:
- keywords = self.all_keywords
- print(self.TableOfClients(clients.values(), keywords))
-
- class TableOfClients:
- tableheaders = {
- "Name": "Name",
- "Enabled": "Enabled",
- "Timeout": "Timeout",
- "LastCheckedOK": "Last Successful Check",
- "LastApprovalRequest": "Last Approval Request",
- "Created": "Created",
- "Interval": "Interval",
- "Host": "Host",
- "Fingerprint": "Fingerprint",
- "KeyID": "Key ID",
- "CheckerRunning": "Check Is Running",
- "LastEnabled": "Last Enabled",
- "ApprovalPending": "Approval Is Pending",
- "ApprovedByDefault": "Approved By Default",
- "ApprovalDelay": "Approval Delay",
- "ApprovalDuration": "Approval Duration",
- "Checker": "Checker",
- "ExtendedTimeout": "Extended Timeout",
- "Expires": "Expires",
- "LastCheckerStatus": "Last Checker Status",
- }
-
- def __init__(self, clients, keywords):
- self.clients = clients
- self.keywords = keywords
-
- def __str__(self):
- return "\n".join(self.rows())
-
- if sys.version_info.major == 2:
- __unicode__ = __str__
- def __str__(self):
- return str(self).encode(
- locale.getpreferredencoding())
-
- def rows(self):
- format_string = self.row_formatting_string()
- rows = [self.header_line(format_string)]
- rows.extend(self.client_line(client, format_string)
- for client in self.clients)
- return rows
-
- def row_formatting_string(self):
- "Format string used to format table rows"
- return " ".join("{{{key}:{width}}}".format(
- width=max(len(self.tableheaders[key]),
- *(len(self.string_from_client(client,
- key))
- for client in self.clients)),
- key=key)
- for key in self.keywords)
-
- def string_from_client(self, client, key):
- return self.valuetostring(client[key], key)
-
- @classmethod
- def valuetostring(cls, value, keyword):
- if isinstance(value, bool):
- return "Yes" if value else "No"
- if keyword in ("Timeout", "Interval", "ApprovalDelay",
- "ApprovalDuration", "ExtendedTimeout"):
- return cls.milliseconds_to_string(value)
- return str(value)
-
- def header_line(self, format_string):
- return format_string.format(**self.tableheaders)
-
- def client_line(self, client, format_string):
- return format_string.format(
- **{key: self.string_from_client(client, key)
- for key in self.keywords})
-
- @staticmethod
- def milliseconds_to_string(ms):
- td = datetime.timedelta(0, 0, 0, ms)
- return ("{days}{hours:02}:{minutes:02}:{seconds:02}"
- .format(days="{}T".format(td.days)
- if td.days else "",
- hours=td.seconds // 3600,
- minutes=(td.seconds % 3600) // 60,
- seconds=td.seconds % 60))
-
-
- class PropertySetter(Base):
- "Abstract class for Actions for setting one client property"
-
- def run_on_one_client(self, client, properties=None):
- """Set the Client's D-Bus property"""
- self.bus.set_client_property(client, self.propname,
- self.value_to_set)
-
- @property
- def propname(self):
- raise NotImplementedError()
-
-
- class Enable(PropertySetter):
- propname = "Enabled"
- value_to_set = True
-
-
- class Disable(PropertySetter):
- propname = "Enabled"
- value_to_set = False
-
-
- class BumpTimeout(PropertySetter):
- propname = "LastCheckedOK"
- value_to_set = ""
-
-
- class StartChecker(PropertySetter):
- propname = "CheckerRunning"
- value_to_set = True
-
-
- class StopChecker(PropertySetter):
- propname = "CheckerRunning"
- value_to_set = False
-
-
- class ApproveByDefault(PropertySetter):
- propname = "ApprovedByDefault"
- value_to_set = True
-
-
- class DenyByDefault(PropertySetter):
- propname = "ApprovedByDefault"
- value_to_set = False
-
-
- class PropertySetterValue(PropertySetter):
- """Abstract class for PropertySetter recieving a value as
-constructor argument instead of a class attribute."""
- def __init__(self, value):
- self.value_to_set = value
-
- @classmethod
- def argparse(cls, argtype):
- def cmdtype(arg):
- return cls(argtype(arg))
- return cmdtype
-
- class SetChecker(PropertySetterValue):
- propname = "Checker"
-
-
- class SetHost(PropertySetterValue):
- propname = "Host"
-
-
- class SetSecret(PropertySetterValue):
- propname = "Secret"
-
- @property
- def value_to_set(self):
- return self._vts
-
- @value_to_set.setter
- def value_to_set(self, value):
- """When setting, read data from supplied file object"""
- self._vts = value.read()
- value.close()
-
-
- class PropertySetterValueMilliseconds(PropertySetterValue):
- """Abstract class for PropertySetterValue taking a value
-argument as a datetime.timedelta() but should store it as
-milliseconds."""
-
- @property
- def value_to_set(self):
- return self._vts
-
- @value_to_set.setter
- def value_to_set(self, value):
- "When setting, convert value from a datetime.timedelta"
- self._vts = int(round(value.total_seconds() * 1000))
-
-
- class SetTimeout(PropertySetterValueMilliseconds):
- propname = "Timeout"
-
-
- class SetExtendedTimeout(PropertySetterValueMilliseconds):
- propname = "ExtendedTimeout"
-
-
- class SetInterval(PropertySetterValueMilliseconds):
- propname = "Interval"
-
-
- class SetApprovalDelay(PropertySetterValueMilliseconds):
- propname = "ApprovalDelay"
-
-
- class SetApprovalDuration(PropertySetterValueMilliseconds):
- propname = "ApprovalDuration"
-
-
-
-class TestCaseWithAssertLogs(unittest.TestCase):
- """unittest.TestCase.assertLogs only exists in Python 3.4"""
-
- if not hasattr(unittest.TestCase, "assertLogs"):
- @contextlib.contextmanager
- def assertLogs(self, logger, level=logging.INFO):
- capturing_handler = self.CapturingLevelHandler(level)
- old_level = logger.level
- old_propagate = logger.propagate
- logger.addHandler(capturing_handler)
- logger.setLevel(level)
- logger.propagate = False
- try:
- yield capturing_handler.watcher
- finally:
- logger.propagate = old_propagate
- logger.removeHandler(capturing_handler)
- logger.setLevel(old_level)
- self.assertGreater(len(capturing_handler.watcher.records),
- 0)
-
- class CapturingLevelHandler(logging.Handler):
- def __init__(self, level, *args, **kwargs):
- logging.Handler.__init__(self, *args, **kwargs)
- self.watcher = self.LoggingWatcher([], [])
- def emit(self, record):
- self.watcher.records.append(record)
- self.watcher.output.append(self.format(record))
-
- LoggingWatcher = collections.namedtuple("LoggingWatcher",
- ("records",
- "output"))
-
-
-class Unique:
- """Class for objects which exist only to be unique objects, since
-unittest.mock.sentinel only exists in Python 3.3"""
-
-
-class Test_string_to_delta(TestCaseWithAssertLogs):
- # Just test basic RFC 3339 functionality here, the doc string for
- # rfc3339_duration_to_delta() already has more comprehensive
- # tests, which are run by doctest.
-
- def test_rfc3339_zero_seconds(self):
- self.assertEqual(datetime.timedelta(),
- string_to_delta("PT0S"))
-
- def test_rfc3339_zero_days(self):
- self.assertEqual(datetime.timedelta(), string_to_delta("P0D"))
-
- def test_rfc3339_one_second(self):
- self.assertEqual(datetime.timedelta(0, 1),
- string_to_delta("PT1S"))
-
- def test_rfc3339_two_hours(self):
- self.assertEqual(datetime.timedelta(0, 7200),
- string_to_delta("PT2H"))
-
- def test_falls_back_to_pre_1_6_1_with_warning(self):
- with self.assertLogs(log, logging.WARNING):
- value = string_to_delta("2h")
- self.assertEqual(datetime.timedelta(0, 7200), value)
-
-
-class Test_check_option_syntax(unittest.TestCase):
- def setUp(self):
- self.parser = argparse.ArgumentParser()
- add_command_line_options(self.parser)
-
- def test_actions_requires_client_or_all(self):
- for action, value in self.actions.items():
- args = self.actionargs(action, value)
- with self.assertParseError():
- self.parse_args(args)
-
- # This mostly corresponds to the definition from has_commands() in
- # check_option_syntax()
- actions = {
- "--enable": None,
- "--disable": None,
- "--bump-timeout": None,
- "--start-checker": None,
- "--stop-checker": None,
- "--is-enabled": None,
- "--remove": None,
- "--checker": "x",
- "--timeout": "PT0S",
- "--extended-timeout": "PT0S",
- "--interval": "PT0S",
- "--approve-by-default": None,
- "--deny-by-default": None,
- "--approval-delay": "PT0S",
- "--approval-duration": "PT0S",
- "--host": "hostname",
- "--secret": "/dev/null",
- "--approve": None,
- "--deny": None,
- }
-
- @staticmethod
- def actionargs(action, value, *args):
- if value is not None:
- return [action, value] + list(args)
- else:
- return [action] + list(args)
-
- @contextlib.contextmanager
- def assertParseError(self):
- with self.assertRaises(SystemExit) as e:
- with self.redirect_stderr_to_devnull():
- yield
- # Exit code from argparse is guaranteed to be "2". Reference:
- # https://docs.python.org/3/library
- # /argparse.html#exiting-methods
- self.assertEqual(2, e.exception.code)
-
- def parse_args(self, args):
- options = self.parser.parse_args(args)
- check_option_syntax(self.parser, options)
-
- @staticmethod
- @contextlib.contextmanager
- def redirect_stderr_to_devnull():
- old_stderr = sys.stderr
- with contextlib.closing(open(os.devnull, "w")) as null:
- sys.stderr = null
- try:
- yield
- finally:
- sys.stderr = old_stderr
-
- def check_option_syntax(self, options):
- check_option_syntax(self.parser, options)
-
- def test_actions_all_conflicts_with_verbose(self):
- for action, value in self.actions.items():
- args = self.actionargs(action, value, "--all",
- "--verbose")
- with self.assertParseError():
- self.parse_args(args)
-
- def test_actions_with_client_conflicts_with_verbose(self):
- for action, value in self.actions.items():
- args = self.actionargs(action, value, "--verbose",
- "client")
- with self.assertParseError():
- self.parse_args(args)
-
- def test_dump_json_conflicts_with_verbose(self):
- args = ["--dump-json", "--verbose"]
- with self.assertParseError():
- self.parse_args(args)
-
- def test_dump_json_conflicts_with_action(self):
- for action, value in self.actions.items():
- args = self.actionargs(action, value, "--dump-json")
- with self.assertParseError():
- self.parse_args(args)
-
- def test_all_can_not_be_alone(self):
- args = ["--all"]
- with self.assertParseError():
- self.parse_args(args)
-
- def test_all_is_ok_with_any_action(self):
- for action, value in self.actions.items():
- args = self.actionargs(action, value, "--all")
- self.parse_args(args)
-
- def test_any_action_is_ok_with_one_client(self):
- for action, value in self.actions.items():
- args = self.actionargs(action, value, "client")
- self.parse_args(args)
-
- def test_one_client_with_all_actions_except_is_enabled(self):
- for action, value in self.actions.items():
- if action == "--is-enabled":
- continue
- args = self.actionargs(action, value, "client")
- self.parse_args(args)
-
- def test_two_clients_with_all_actions_except_is_enabled(self):
- for action, value in self.actions.items():
- if action == "--is-enabled":
- continue
- args = self.actionargs(action, value, "client1",
- "client2")
- self.parse_args(args)
-
- def test_two_clients_are_ok_with_actions_except_is_enabled(self):
- for action, value in self.actions.items():
- if action == "--is-enabled":
- continue
- args = self.actionargs(action, value, "client1",
- "client2")
- self.parse_args(args)
-
- def test_is_enabled_fails_without_client(self):
- args = ["--is-enabled"]
- with self.assertParseError():
- self.parse_args(args)
-
- def test_is_enabled_fails_with_two_clients(self):
- args = ["--is-enabled", "client1", "client2"]
- with self.assertParseError():
- self.parse_args(args)
-
- def test_remove_can_only_be_combined_with_action_deny(self):
- for action, value in self.actions.items():
- if action in {"--remove", "--deny"}:
- continue
- args = self.actionargs(action, value, "--all",
- "--remove")
- with self.assertParseError():
- self.parse_args(args)
-
-
-class Test_dbus_exceptions(unittest.TestCase):
-
- def test_dbus_ConnectFailed_is_Error(self):
- with self.assertRaises(dbus.Error):
- raise dbus.ConnectFailed()
-
-
-class Test_dbus_MandosBus(unittest.TestCase):
-
- class MockMandosBus(dbus.MandosBus):
- def __init__(self):
- self._name = "se.recompile.Mandos"
- self._server_path = "/"
- self._server_interface = "se.recompile.Mandos"
- self._client_interface = "se.recompile.Mandos.Client"
- self.calls = []
- self.call_method_return = Unique()
-
- def call_method(self, methodname, busname, objectpath,
- interface, *args):
- self.calls.append((methodname, busname, objectpath,
- interface, args))
- return self.call_method_return
-
- def setUp(self):
- self.bus = self.MockMandosBus()
-
- def test_set_client_property(self):
- self.bus.set_client_property("objectpath", "key", "value")
- expected_call = ("Set", self.bus._name, "objectpath",
- "org.freedesktop.DBus.Properties",
- (self.bus._client_interface, "key", "value"))
- self.assertIn(expected_call, self.bus.calls)
-
- def test_call_client_method(self):
- ret = self.bus.call_client_method("objectpath", "methodname")
- self.assertIs(self.bus.call_method_return, ret)
- expected_call = ("methodname", self.bus._name, "objectpath",
- self.bus._client_interface, ())
- self.assertIn(expected_call, self.bus.calls)
-
- def test_call_client_method_with_args(self):
- args = (Unique(), Unique())
- ret = self.bus.call_client_method("objectpath", "methodname",
- *args)
- self.assertIs(self.bus.call_method_return, ret)
- expected_call = ("methodname", self.bus._name, "objectpath",
- self.bus._client_interface,
- (args[0], args[1]))
- self.assertIn(expected_call, self.bus.calls)
-
- def test_get_clients_and_properties(self):
- managed_objects = {
- "objectpath": {
- self.bus._client_interface: {
- "key": "value",
- "bool": True,
- },
- "irrelevant_interface": {
- "key": "othervalue",
- "bool": False,
- },
- },
- "other_objectpath": {
- "other_irrelevant_interface": {
- "key": "value 3",
- "bool": None,
- },
- },
- }
- expected_clients_and_properties = {
- "objectpath": {
- "key": "value",
- "bool": True,
- }
- }
- self.bus.call_method_return = managed_objects
- ret = self.bus.get_clients_and_properties()
- self.assertDictEqual(expected_clients_and_properties, ret)
- expected_call = ("GetManagedObjects", self.bus._name,
- self.bus._server_path,
- "org.freedesktop.DBus.ObjectManager", ())
- self.assertIn(expected_call, self.bus.calls)
-
- def test_call_server_method(self):
- ret = self.bus.call_server_method("methodname")
- self.assertIs(self.bus.call_method_return, ret)
- expected_call = ("methodname", self.bus._name,
- self.bus._server_path,
- self.bus._server_interface, ())
- self.assertIn(expected_call, self.bus.calls)
-
- def test_call_server_method_with_args(self):
- args = (Unique(), Unique())
- ret = self.bus.call_server_method("methodname", *args)
- self.assertIs(self.bus.call_method_return, ret)
- expected_call = ("methodname", self.bus._name,
- self.bus._server_path,
- self.bus._server_interface,
- (args[0], args[1]))
- self.assertIn(expected_call, self.bus.calls)
-
-
-class Test_dbus_python_adapter_SystemBus(TestCaseWithAssertLogs):
-
- def MockDBusPython_func(self, func):
- class mock_dbus_python:
- """mock dbus-python module"""
- class exceptions:
- """Pseudo-namespace"""
- class DBusException(Exception):
- pass
- class SystemBus:
- @staticmethod
- def get_object(busname, objectpath):
- DBusObject = collections.namedtuple(
- "DBusObject", ("methodname", "Set"))
- def method(*args, **kwargs):
- self.assertEqual({"dbus_interface":
- "interface"},
- kwargs)
- return func(*args)
- def set_property(interface, key, value,
- dbus_interface=None):
- self.assertEqual(
- "org.freedesktop.DBus.Properties",
- dbus_interface)
- self.assertEqual("Secret", key)
- return func(interface, key, value,
- dbus_interface=dbus_interface)
- return DBusObject(methodname=method,
- Set=set_property)
- class Boolean:
- def __init__(self, value):
- self.value = bool(value)
- def __bool__(self):
- return self.value
- if sys.version_info.major == 2:
- __nonzero__ = __bool__
- class ObjectPath(str):
- pass
- class Dictionary(dict):
- pass
- class ByteArray(bytes):
- pass
- return mock_dbus_python
-
- def call_method(self, bus, methodname, busname, objectpath,
- interface, *args):
- with self.assertLogs(log, logging.DEBUG):
- return bus.call_method(methodname, busname, objectpath,
- interface, *args)
-
- def test_call_method_returns(self):
- expected_method_return = Unique()
- method_args = (Unique(), Unique())
- def func(*args):
- self.assertEqual(len(method_args), len(args))
- for marg, arg in zip(method_args, args):
- self.assertIs(marg, arg)
- return expected_method_return
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface",
- *method_args)
- self.assertIs(ret, expected_method_return)
-
- def test_call_method_filters_bool_true(self):
- def func():
- return method_return
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- method_return = mock_dbus_python.Boolean(True)
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
- self.assertTrue(ret)
- self.assertNotIsInstance(ret, mock_dbus_python.Boolean)
-
- def test_call_method_filters_bool_false(self):
- def func():
- return method_return
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- method_return = mock_dbus_python.Boolean(False)
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
- self.assertFalse(ret)
- self.assertNotIsInstance(ret, mock_dbus_python.Boolean)
-
- def test_call_method_filters_objectpath(self):
- def func():
- return method_return
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- method_return = mock_dbus_python.ObjectPath("objectpath")
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
- self.assertEqual("objectpath", ret)
- self.assertIsNot("objectpath", ret)
- self.assertNotIsInstance(ret, mock_dbus_python.ObjectPath)
-
- def test_call_method_filters_booleans_in_dict(self):
- def func():
- return method_return
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- method_return = mock_dbus_python.Dictionary(
- {mock_dbus_python.Boolean(True):
- mock_dbus_python.Boolean(False),
- mock_dbus_python.Boolean(False):
- mock_dbus_python.Boolean(True)})
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
- expected_method_return = {True: False,
- False: True}
- self.assertEqual(expected_method_return, ret)
- self.assertNotIsInstance(ret, mock_dbus_python.Dictionary)
-
- def test_call_method_filters_objectpaths_in_dict(self):
- def func():
- return method_return
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- method_return = mock_dbus_python.Dictionary(
- {mock_dbus_python.ObjectPath("objectpath_key_1"):
- mock_dbus_python.ObjectPath("objectpath_value_1"),
- mock_dbus_python.ObjectPath("objectpath_key_2"):
- mock_dbus_python.ObjectPath("objectpath_value_2")})
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
- expected_method_return = {str(key): str(value)
- for key, value in
- method_return.items()}
- self.assertEqual(expected_method_return, ret)
- self.assertIsInstance(ret, dict)
- self.assertNotIsInstance(ret, mock_dbus_python.Dictionary)
-
- def test_call_method_filters_dict_in_dict(self):
- def func():
- return method_return
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- method_return = mock_dbus_python.Dictionary(
- {"key1": mock_dbus_python.Dictionary({"key11": "value11",
- "key12": "value12"}),
- "key2": mock_dbus_python.Dictionary({"key21": "value21",
- "key22": "value22"})})
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
- expected_method_return = {
- "key1": {"key11": "value11",
- "key12": "value12"},
- "key2": {"key21": "value21",
- "key22": "value22"},
- }
- self.assertEqual(expected_method_return, ret)
- self.assertIsInstance(ret, dict)
- self.assertNotIsInstance(ret, mock_dbus_python.Dictionary)
- for key, value in ret.items():
- self.assertIsInstance(value, dict)
- self.assertEqual(expected_method_return[key], value)
- self.assertNotIsInstance(value,
- mock_dbus_python.Dictionary)
-
- def test_call_method_filters_dict_three_deep(self):
- def func():
- return method_return
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- method_return = mock_dbus_python.Dictionary(
- {"key1":
- mock_dbus_python.Dictionary(
- {"key2":
- mock_dbus_python.Dictionary(
- {"key3":
- mock_dbus_python.Boolean(True),
- }),
- }),
- })
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
- expected_method_return = {"key1": {"key2": {"key3": True}}}
- self.assertEqual(expected_method_return, ret)
- self.assertIsInstance(ret, dict)
- self.assertNotIsInstance(ret, mock_dbus_python.Dictionary)
- self.assertIsInstance(ret["key1"], dict)
- self.assertNotIsInstance(ret["key1"],
- mock_dbus_python.Dictionary)
- self.assertIsInstance(ret["key1"]["key2"], dict)
- self.assertNotIsInstance(ret["key1"]["key2"],
- mock_dbus_python.Dictionary)
- self.assertTrue(ret["key1"]["key2"]["key3"])
- self.assertNotIsInstance(ret["key1"]["key2"]["key3"],
- mock_dbus_python.Boolean)
-
- def test_call_method_handles_exception(self):
- dbus_logger = logging.getLogger("dbus.proxies")
-
- def func():
- dbus_logger.error("Test")
- raise mock_dbus_python.exceptions.DBusException()
-
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
-
- class CountingHandler(logging.Handler):
- count = 0
- def emit(self, record):
- self.count += 1
-
- counting_handler = CountingHandler()
-
- dbus_logger.addHandler(counting_handler)
-
- try:
- with self.assertRaises(dbus.Error) as e:
- self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
- finally:
- dbus_logger.removeFilter(counting_handler)
-
- self.assertNotIsInstance(e, dbus.ConnectFailed)
-
- # Make sure the dbus logger was suppressed
- self.assertEqual(0, counting_handler.count)
-
- def test_Set_Secret_sends_bytearray(self):
- ret = [None]
- def func(*args, **kwargs):
- ret[0] = (args, kwargs)
- mock_dbus_python = self.MockDBusPython_func(func)
- bus = dbus_python_adapter.SystemBus(mock_dbus_python)
- bus.set_client_property("objectpath", "Secret", "value")
- expected_call = (("se.recompile.Mandos.Client", "Secret",
- mock_dbus_python.ByteArray(b"value")),
- {"dbus_interface":
- "org.freedesktop.DBus.Properties"})
- self.assertEqual(expected_call, ret[0])
- if sys.version_info.major == 2:
- self.assertIsInstance(ret[0][0][-1],
- mock_dbus_python.ByteArray)
-
- def test_get_object_converts_to_correct_exception(self):
- bus = dbus_python_adapter.SystemBus(
- self.fake_dbus_python_raises_exception_on_connect)
- with self.assertRaises(dbus.ConnectFailed):
- self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
-
- class fake_dbus_python_raises_exception_on_connect:
- """fake dbus-python module"""
- class exceptions:
- """Pseudo-namespace"""
- class DBusException(Exception):
- pass
-
- @classmethod
- def SystemBus(cls):
- def get_object(busname, objectpath):
- raise cls.exceptions.DBusException()
- Bus = collections.namedtuple("Bus", ["get_object"])
- return Bus(get_object=get_object)
-
-
-class Test_dbus_python_adapter_CachingBus(unittest.TestCase):
- class mock_dbus_python:
- """mock dbus-python modules"""
- class SystemBus:
- @staticmethod
- def get_object(busname, objectpath):
- return Unique()
-
- def setUp(self):
- self.bus = dbus_python_adapter.CachingBus(
- self.mock_dbus_python)
-
- def test_returns_distinct_objectpaths(self):
- obj1 = self.bus.get_object("busname", "objectpath1")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get_object("busname", "objectpath2")
- self.assertIsInstance(obj2, Unique)
- self.assertIsNot(obj1, obj2)
-
- def test_returns_distinct_busnames(self):
- obj1 = self.bus.get_object("busname1", "objectpath")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get_object("busname2", "objectpath")
- self.assertIsInstance(obj2, Unique)
- self.assertIsNot(obj1, obj2)
-
- def test_returns_distinct_both(self):
- obj1 = self.bus.get_object("busname1", "objectpath")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get_object("busname2", "objectpath")
- self.assertIsInstance(obj2, Unique)
- self.assertIsNot(obj1, obj2)
-
- def test_returns_same(self):
- obj1 = self.bus.get_object("busname", "objectpath")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get_object("busname", "objectpath")
- self.assertIsInstance(obj2, Unique)
- self.assertIs(obj1, obj2)
-
- def test_returns_same_old(self):
- obj1 = self.bus.get_object("busname1", "objectpath1")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get_object("busname2", "objectpath2")
- self.assertIsInstance(obj2, Unique)
- obj1b = self.bus.get_object("busname1", "objectpath1")
- self.assertIsInstance(obj1b, Unique)
- self.assertIsNot(obj1, obj2)
- self.assertIsNot(obj2, obj1b)
- self.assertIs(obj1, obj1b)
-
-
-class Test_pydbus_adapter_SystemBus(TestCaseWithAssertLogs):
-
- def Stub_pydbus_func(self, func):
- class stub_pydbus:
- """stub pydbus module"""
- class SystemBus:
- @staticmethod
- def get(busname, objectpath):
- DBusObject = collections.namedtuple(
- "DBusObject", ("methodname",))
- return {"interface":
- DBusObject(methodname=func)}
- return stub_pydbus
-
- def call_method(self, bus, methodname, busname, objectpath,
- interface, *args):
- with self.assertLogs(log, logging.DEBUG):
- return bus.call_method(methodname, busname, objectpath,
- interface, *args)
-
- def test_call_method_returns(self):
- expected_method_return = Unique()
- method_args = (Unique(), Unique())
- def func(*args):
- self.assertEqual(len(method_args), len(args))
- for marg, arg in zip(method_args, args):
- self.assertIs(marg, arg)
- return expected_method_return
- stub_pydbus = self.Stub_pydbus_func(func)
- bus = pydbus_adapter.SystemBus(stub_pydbus)
- ret = self.call_method(bus, "methodname", "busname",
- "objectpath", "interface",
- *method_args)
- self.assertIs(ret, expected_method_return)
-
- def test_call_method_handles_exception(self):
- dbus_logger = logging.getLogger("dbus.proxies")
-
- def func():
- raise gi.repository.GLib.Error()
-
- stub_pydbus = self.Stub_pydbus_func(func)
- bus = pydbus_adapter.SystemBus(stub_pydbus)
-
- with self.assertRaises(dbus.Error) as e:
- self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
-
- self.assertNotIsInstance(e, dbus.ConnectFailed)
-
- def test_get_converts_to_correct_exception(self):
- bus = pydbus_adapter.SystemBus(
- self.fake_pydbus_raises_exception_on_connect)
- with self.assertRaises(dbus.ConnectFailed):
- self.call_method(bus, "methodname", "busname",
- "objectpath", "interface")
-
- class fake_pydbus_raises_exception_on_connect:
- """fake dbus-python module"""
- @classmethod
- def SystemBus(cls):
- def get(busname, objectpath):
- raise gi.repository.GLib.Error()
- Bus = collections.namedtuple("Bus", ["get"])
- return Bus(get=get)
-
- def test_set_property_uses_setattr(self):
- class Object:
- pass
- obj = Object()
- class pydbus_spy:
- class SystemBus:
- @staticmethod
- def get(busname, objectpath):
- return {"interface": obj}
- bus = pydbus_adapter.SystemBus(pydbus_spy)
- value = Unique()
- bus.set_property("busname", "objectpath", "interface", "key",
- value)
- self.assertIs(value, obj.key)
-
- def test_get_suppresses_xml_deprecation_warning(self):
- if sys.version_info.major >= 3:
- return
- class stub_pydbus_get:
- class SystemBus:
- @staticmethod
- def get(busname, objectpath):
- warnings.warn_explicit(
- "deprecated", DeprecationWarning,
- "xml.etree.ElementTree", 0)
- bus = pydbus_adapter.SystemBus(stub_pydbus_get)
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
- bus.get("busname", "objectpath")
- self.assertEqual(0, len(w))
-
-
-class Test_pydbus_adapter_CachingBus(unittest.TestCase):
- class stub_pydbus:
- """stub pydbus module"""
- class SystemBus:
- @staticmethod
- def get(busname, objectpath):
- return Unique()
-
- def setUp(self):
- self.bus = pydbus_adapter.CachingBus(self.stub_pydbus)
-
- def test_returns_distinct_objectpaths(self):
- obj1 = self.bus.get("busname", "objectpath1")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get("busname", "objectpath2")
- self.assertIsInstance(obj2, Unique)
- self.assertIsNot(obj1, obj2)
-
- def test_returns_distinct_busnames(self):
- obj1 = self.bus.get("busname1", "objectpath")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get("busname2", "objectpath")
- self.assertIsInstance(obj2, Unique)
- self.assertIsNot(obj1, obj2)
-
- def test_returns_distinct_both(self):
- obj1 = self.bus.get("busname1", "objectpath")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get("busname2", "objectpath")
- self.assertIsInstance(obj2, Unique)
- self.assertIsNot(obj1, obj2)
-
- def test_returns_same(self):
- obj1 = self.bus.get("busname", "objectpath")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get("busname", "objectpath")
- self.assertIsInstance(obj2, Unique)
- self.assertIs(obj1, obj2)
-
- def test_returns_same_old(self):
- obj1 = self.bus.get("busname1", "objectpath1")
- self.assertIsInstance(obj1, Unique)
- obj2 = self.bus.get("busname2", "objectpath2")
- self.assertIsInstance(obj2, Unique)
- obj1b = self.bus.get("busname1", "objectpath1")
- self.assertIsInstance(obj1b, Unique)
- self.assertIsNot(obj1, obj2)
- self.assertIsNot(obj2, obj1b)
- self.assertIs(obj1, obj1b)
-
-
-class Test_commands_from_options(unittest.TestCase):
-
- def setUp(self):
- self.parser = argparse.ArgumentParser()
- add_command_line_options(self.parser)
-
- def test_is_enabled(self):
- self.assert_command_from_args(["--is-enabled", "client"],
- command.IsEnabled)
-
- def assert_command_from_args(self, args, command_cls, length=1,
- clients=None, **cmd_attrs):
- """Assert that parsing ARGS should result in an instance of
-COMMAND_CLS with (optionally) all supplied attributes (CMD_ATTRS)."""
- options = self.parser.parse_args(args)
- check_option_syntax(self.parser, options)
- commands = commands_from_options(options)
- self.assertEqual(length, len(commands))
- for command in commands:
- if isinstance(command, command_cls):
- break
- else:
- self.assertIsInstance(command, command_cls)
- if clients is not None:
- self.assertEqual(clients, options.client)
- for key, value in cmd_attrs.items():
- self.assertEqual(value, getattr(command, key))
-
- def assert_commands_from_args(self, args, commands, clients=None):
- for cmd in commands:
- self.assert_command_from_args(args, cmd,
- length=len(commands),
- clients=clients)
-
- def test_is_enabled_short(self):
- self.assert_command_from_args(["-V", "client"],
- command.IsEnabled)
-
- def test_approve(self):
- self.assert_command_from_args(["--approve", "client"],
- command.Approve)
-
- def test_approve_short(self):
- self.assert_command_from_args(["-A", "client"],
- command.Approve)
-
- def test_deny(self):
- self.assert_command_from_args(["--deny", "client"],
- command.Deny)
-
- def test_deny_short(self):
- self.assert_command_from_args(["-D", "client"], command.Deny)
-
- def test_remove(self):
- self.assert_command_from_args(["--remove", "client"],
- command.Remove)
-
- def test_deny_before_remove(self):
- options = self.parser.parse_args(["--deny", "--remove",
- "client"])
- check_option_syntax(self.parser, options)
- commands = commands_from_options(options)
- self.assertEqual(2, len(commands))
- self.assertIsInstance(commands[0], command.Deny)
- self.assertIsInstance(commands[1], command.Remove)
-
- def test_deny_before_remove_reversed(self):
- options = self.parser.parse_args(["--remove", "--deny",
- "--all"])
- check_option_syntax(self.parser, options)
- commands = commands_from_options(options)
- self.assertEqual(2, len(commands))
- self.assertIsInstance(commands[0], command.Deny)
- self.assertIsInstance(commands[1], command.Remove)
-
- def test_remove_short(self):
- self.assert_command_from_args(["-r", "client"],
- command.Remove)
-
- def test_dump_json(self):
- self.assert_command_from_args(["--dump-json"],
- command.DumpJSON)
-
- def test_enable(self):
- self.assert_command_from_args(["--enable", "client"],
- command.Enable)
-
- def test_enable_short(self):
- self.assert_command_from_args(["-e", "client"],
- command.Enable)
-
- def test_disable(self):
- self.assert_command_from_args(["--disable", "client"],
- command.Disable)
-
- def test_disable_short(self):
- self.assert_command_from_args(["-d", "client"],
- command.Disable)
-
- def test_bump_timeout(self):
- self.assert_command_from_args(["--bump-timeout", "client"],
- command.BumpTimeout)
-
- def test_bump_timeout_short(self):
- self.assert_command_from_args(["-b", "client"],
- command.BumpTimeout)
-
- def test_start_checker(self):
- self.assert_command_from_args(["--start-checker", "client"],
- command.StartChecker)
-
- def test_stop_checker(self):
- self.assert_command_from_args(["--stop-checker", "client"],
- command.StopChecker)
-
- def test_approve_by_default(self):
- self.assert_command_from_args(["--approve-by-default",
- "client"],
- command.ApproveByDefault)
-
- def test_deny_by_default(self):
- self.assert_command_from_args(["--deny-by-default", "client"],
- command.DenyByDefault)
-
- def test_checker(self):
- self.assert_command_from_args(["--checker", ":", "client"],
- command.SetChecker,
- value_to_set=":")
-
- def test_checker_empty(self):
- self.assert_command_from_args(["--checker", "", "client"],
- command.SetChecker,
- value_to_set="")
-
- def test_checker_short(self):
- self.assert_command_from_args(["-c", ":", "client"],
- command.SetChecker,
- value_to_set=":")
-
- def test_host(self):
- self.assert_command_from_args(
- ["--host", "client.example.org", "client"],
- command.SetHost, value_to_set="client.example.org")
-
- def test_host_short(self):
- self.assert_command_from_args(
- ["-H", "client.example.org", "client"], command.SetHost,
- value_to_set="client.example.org")
-
- def test_secret_devnull(self):
- self.assert_command_from_args(["--secret", os.path.devnull,
- "client"], command.SetSecret,
- value_to_set=b"")
-
- def test_secret_tempfile(self):
- with tempfile.NamedTemporaryFile(mode="r+b") as f:
- value = b"secret\0xyzzy\nbar"
- f.write(value)
- f.seek(0)
- self.assert_command_from_args(["--secret", f.name,
- "client"],
- command.SetSecret,
- value_to_set=value)
-
- def test_secret_devnull_short(self):
- self.assert_command_from_args(["-s", os.path.devnull,
- "client"], command.SetSecret,
- value_to_set=b"")
-
- def test_secret_tempfile_short(self):
- with tempfile.NamedTemporaryFile(mode="r+b") as f:
- value = b"secret\0xyzzy\nbar"
- f.write(value)
- f.seek(0)
- self.assert_command_from_args(["-s", f.name, "client"],
- command.SetSecret,
- value_to_set=value)
-
- def test_timeout(self):
- self.assert_command_from_args(["--timeout", "PT5M", "client"],
- command.SetTimeout,
- value_to_set=300000)
-
- def test_timeout_short(self):
- self.assert_command_from_args(["-t", "PT5M", "client"],
- command.SetTimeout,
- value_to_set=300000)
-
- def test_extended_timeout(self):
- self.assert_command_from_args(["--extended-timeout", "PT15M",
- "client"],
- command.SetExtendedTimeout,
- value_to_set=900000)
-
- def test_interval(self):
- self.assert_command_from_args(["--interval", "PT2M",
- "client"], command.SetInterval,
- value_to_set=120000)
-
- def test_interval_short(self):
- self.assert_command_from_args(["-i", "PT2M", "client"],
- command.SetInterval,
- value_to_set=120000)
-
- def test_approval_delay(self):
- self.assert_command_from_args(["--approval-delay", "PT30S",
- "client"],
- command.SetApprovalDelay,
- value_to_set=30000)
-
- def test_approval_duration(self):
- self.assert_command_from_args(["--approval-duration", "PT1S",
- "client"],
- command.SetApprovalDuration,
- value_to_set=1000)
-
- def test_print_table(self):
- self.assert_command_from_args([], command.PrintTable,
- verbose=False)
-
- def test_print_table_verbose(self):
- self.assert_command_from_args(["--verbose"],
- command.PrintTable,
- verbose=True)
-
- def test_print_table_verbose_short(self):
- self.assert_command_from_args(["-v"], command.PrintTable,
- verbose=True)
-
-
- def test_manual_page_example_1(self):
- self.assert_command_from_args("",
- command.PrintTable,
- clients=[],
- verbose=False)
-
- def test_manual_page_example_2(self):
- self.assert_command_from_args(
- "--verbose foo1.example.org foo2.example.org".split(),
- command.PrintTable, clients=["foo1.example.org",
- "foo2.example.org"],
- verbose=True)
-
- def test_manual_page_example_3(self):
- self.assert_command_from_args("--enable --all".split(),
- command.Enable,
- clients=[])
-
- def test_manual_page_example_4(self):
- self.assert_commands_from_args(
- ("--timeout=PT5M --interval=PT1M foo1.example.org"
- " foo2.example.org").split(),
- [command.SetTimeout, command.SetInterval],
- clients=["foo1.example.org", "foo2.example.org"])
-
- def test_manual_page_example_5(self):
- self.assert_command_from_args("--approve --all".split(),
- command.Approve,
- clients=[])
-
-
-class TestCommand(unittest.TestCase):
- """Abstract class for tests of command classes"""
-
- class FakeMandosBus(dbus.MandosBus):
- def __init__(self, testcase):
- self.client_properties = {
- "Name": "foo",
- "KeyID": ("92ed150794387c03ce684574b1139a65"
- "94a34f895daaaf09fd8ea90a27cddb12"),
- "Secret": b"secret",
- "Host": "foo.example.org",
- "Enabled": True,
- "Timeout": 300000,
- "LastCheckedOK": "2019-02-03T00:00:00",
- "Created": "2019-01-02T00:00:00",
- "Interval": 120000,
- "Fingerprint": ("778827225BA7DE539C5A"
- "7CFA59CFF7CDBD9A5920"),
- "CheckerRunning": False,
- "LastEnabled": "2019-01-03T00:00:00",
- "ApprovalPending": False,
- "ApprovedByDefault": True,
- "LastApprovalRequest": "",
- "ApprovalDelay": 0,
- "ApprovalDuration": 1000,
- "Checker": "fping -q -- %(host)s",
- "ExtendedTimeout": 900000,
- "Expires": "2019-02-04T00:00:00",
- "LastCheckerStatus": 0,
- }
- self.other_client_properties = {
- "Name": "barbar",
- "KeyID": ("0558568eedd67d622f5c83b35a115f79"
- "6ab612cff5ad227247e46c2b020f441c"),
- "Secret": b"secretbar",
- "Host": "192.0.2.3",
- "Enabled": True,
- "Timeout": 300000,
- "LastCheckedOK": "2019-02-04T00:00:00",
- "Created": "2019-01-03T00:00:00",
- "Interval": 120000,
- "Fingerprint": ("3E393AEAEFB84C7E89E2"
- "F547B3A107558FCA3A27"),
- "CheckerRunning": True,
- "LastEnabled": "2019-01-04T00:00:00",
- "ApprovalPending": False,
- "ApprovedByDefault": False,
- "LastApprovalRequest": "2019-01-03T00:00:00",
- "ApprovalDelay": 30000,
- "ApprovalDuration": 93785000,
- "Checker": ":",
- "ExtendedTimeout": 900000,
- "Expires": "2019-02-05T00:00:00",
- "LastCheckerStatus": -2,
- }
- self.clients = collections.OrderedDict(
- [
- ("client_objectpath", self.client_properties),
- ("other_client_objectpath",
- self.other_client_properties),
- ])
- self.one_client = {"client_objectpath":
- self.client_properties}
- self.testcase = testcase
- self.calls = []
-
- def call_method(self, methodname, busname, objectpath,
- interface, *args):
- self.testcase.assertEqual("se.recompile.Mandos", busname)
- self.calls.append((methodname, busname, objectpath,
- interface, args))
- if interface == "org.freedesktop.DBus.Properties":
- if methodname == "Set":
- self.testcase.assertEqual(3, len(args))
- interface, key, value = args
- self.testcase.assertEqual(
- "se.recompile.Mandos.Client", interface)
- self.clients[objectpath][key] = value
- return
- elif interface == "se.recompile.Mandos":
- self.testcase.assertEqual("RemoveClient", methodname)
- self.testcase.assertEqual(1, len(args))
- clientpath = args[0]
- del self.clients[clientpath]
- return
- elif interface == "se.recompile.Mandos.Client":
- if methodname == "Approve":
- self.testcase.assertEqual(1, len(args))
- return
- raise ValueError()
-
- def setUp(self):
- self.bus = self.FakeMandosBus(self)
-
-
-class TestBaseCommands(TestCommand):
-
- def test_IsEnabled_exits_successfully(self):
- with self.assertRaises(SystemExit) as e:
- command.IsEnabled().run(self.bus.one_client)
- if e.exception.code is not None:
- self.assertEqual(0, e.exception.code)
- else:
- self.assertIsNone(e.exception.code)
-
- def test_IsEnabled_exits_with_failure(self):
- self.bus.client_properties["Enabled"] = False
- with self.assertRaises(SystemExit) as e:
- command.IsEnabled().run(self.bus.one_client)
- if isinstance(e.exception.code, int):
- self.assertNotEqual(0, e.exception.code)
- else:
- self.assertIsNotNone(e.exception.code)
-
- def test_Approve(self):
- busname = "se.recompile.Mandos"
- client_interface = "se.recompile.Mandos.Client"
- command.Approve().run(self.bus.clients, self.bus)
- for clientpath in self.bus.clients:
- self.assertIn(("Approve", busname, clientpath,
- client_interface, (True,)), self.bus.calls)
-
- def test_Deny(self):
- busname = "se.recompile.Mandos"
- client_interface = "se.recompile.Mandos.Client"
- command.Deny().run(self.bus.clients, self.bus)
- for clientpath in self.bus.clients:
- self.assertIn(("Approve", busname, clientpath,
- client_interface, (False,)),
- self.bus.calls)
-
- def test_Remove(self):
- command.Remove().run(self.bus.clients, self.bus)
- for clientpath in self.bus.clients:
- self.assertIn(("RemoveClient", dbus_busname,
- dbus_server_path, dbus_server_interface,
- (clientpath,)), self.bus.calls)
-
- expected_json = {
- "foo": {
- "Name": "foo",
- "KeyID": ("92ed150794387c03ce684574b1139a65"
- "94a34f895daaaf09fd8ea90a27cddb12"),
- "Host": "foo.example.org",
- "Enabled": True,
- "Timeout": 300000,
- "LastCheckedOK": "2019-02-03T00:00:00",
- "Created": "2019-01-02T00:00:00",
- "Interval": 120000,
- "Fingerprint": ("778827225BA7DE539C5A"
- "7CFA59CFF7CDBD9A5920"),
- "CheckerRunning": False,
- "LastEnabled": "2019-01-03T00:00:00",
- "ApprovalPending": False,
- "ApprovedByDefault": True,
- "LastApprovalRequest": "",
- "ApprovalDelay": 0,
- "ApprovalDuration": 1000,
- "Checker": "fping -q -- %(host)s",
- "ExtendedTimeout": 900000,
- "Expires": "2019-02-04T00:00:00",
- "LastCheckerStatus": 0,
- },
- "barbar": {
- "Name": "barbar",
- "KeyID": ("0558568eedd67d622f5c83b35a115f79"
- "6ab612cff5ad227247e46c2b020f441c"),
- "Host": "192.0.2.3",
- "Enabled": True,
- "Timeout": 300000,
- "LastCheckedOK": "2019-02-04T00:00:00",
- "Created": "2019-01-03T00:00:00",
- "Interval": 120000,
- "Fingerprint": ("3E393AEAEFB84C7E89E2"
- "F547B3A107558FCA3A27"),
- "CheckerRunning": True,
- "LastEnabled": "2019-01-04T00:00:00",
- "ApprovalPending": False,
- "ApprovedByDefault": False,
- "LastApprovalRequest": "2019-01-03T00:00:00",
- "ApprovalDelay": 30000,
- "ApprovalDuration": 93785000,
- "Checker": ":",
- "ExtendedTimeout": 900000,
- "Expires": "2019-02-05T00:00:00",
- "LastCheckerStatus": -2,
- },
- }
-
- def test_DumpJSON_normal(self):
- with self.capture_stdout_to_buffer() as buffer:
- command.DumpJSON().run(self.bus.clients)
- json_data = json.loads(buffer.getvalue())
- self.assertDictEqual(self.expected_json, json_data)
-
- @staticmethod
- @contextlib.contextmanager
- def capture_stdout_to_buffer():
- capture_buffer = io.StringIO()
- old_stdout = sys.stdout
- sys.stdout = capture_buffer
- try:
- yield capture_buffer
- finally:
- sys.stdout = old_stdout
-
- def test_DumpJSON_one_client(self):
- with self.capture_stdout_to_buffer() as buffer:
- command.DumpJSON().run(self.bus.one_client)
- json_data = json.loads(buffer.getvalue())
- expected_json = {"foo": self.expected_json["foo"]}
- self.assertDictEqual(expected_json, json_data)
-
- def test_PrintTable_normal(self):
- with self.capture_stdout_to_buffer() as buffer:
- command.PrintTable().run(self.bus.clients)
- expected_output = "\n".join((
- "Name Enabled Timeout Last Successful Check",
- "foo Yes 00:05:00 2019-02-03T00:00:00 ",
- "barbar Yes 00:05:00 2019-02-04T00:00:00 ",
- )) + "\n"
- self.assertEqual(expected_output, buffer.getvalue())
-
- def test_PrintTable_verbose(self):
- with self.capture_stdout_to_buffer() as buffer:
- command.PrintTable(verbose=True).run(self.bus.clients)
- columns = (
- (
- "Name ",
- "foo ",
- "barbar ",
- ),(
- "Enabled ",
- "Yes ",
- "Yes ",
- ),(
- "Timeout ",
- "00:05:00 ",
- "00:05:00 ",
- ),(
- "Last Successful Check ",
- "2019-02-03T00:00:00 ",
- "2019-02-04T00:00:00 ",
- ),(
- "Created ",
- "2019-01-02T00:00:00 ",
- "2019-01-03T00:00:00 ",
- ),(
- "Interval ",
- "00:02:00 ",
- "00:02:00 ",
- ),(
- "Host ",
- "foo.example.org ",
- "192.0.2.3 ",
- ),(
- ("Key ID "
- " "),
- ("92ed150794387c03ce684574b1139a6594a34f895daaaf09fd8"
- "ea90a27cddb12 "),
- ("0558568eedd67d622f5c83b35a115f796ab612cff5ad227247e"
- "46c2b020f441c "),
- ),(
- "Fingerprint ",
- "778827225BA7DE539C5A7CFA59CFF7CDBD9A5920 ",
- "3E393AEAEFB84C7E89E2F547B3A107558FCA3A27 ",
- ),(
- "Check Is Running ",
- "No ",
- "Yes ",
- ),(
- "Last Enabled ",
- "2019-01-03T00:00:00 ",
- "2019-01-04T00:00:00 ",
- ),(
- "Approval Is Pending ",
- "No ",
- "No ",
- ),(
- "Approved By Default ",
- "Yes ",
- "No ",
- ),(
- "Last Approval Request ",
- " ",
- "2019-01-03T00:00:00 ",
- ),(
- "Approval Delay ",
- "00:00:00 ",
- "00:00:30 ",
- ),(
- "Approval Duration ",
- "00:00:01 ",
- "1T02:03:05 ",
- ),(
- "Checker ",
- "fping -q -- %(host)s ",
- ": ",
- ),(
- "Extended Timeout ",
- "00:15:00 ",
- "00:15:00 ",
- ),(
- "Expires ",
- "2019-02-04T00:00:00 ",
- "2019-02-05T00:00:00 ",
- ),(
- "Last Checker Status",
- "0 ",
- "-2 ",
- )
- )
- num_lines = max(len(rows) for rows in columns)
- expected_output = ("\n".join("".join(rows[line]
- for rows in columns)
- for line in range(num_lines))
- + "\n")
- self.assertEqual(expected_output, buffer.getvalue())
-
- def test_PrintTable_one_client(self):
- with self.capture_stdout_to_buffer() as buffer:
- command.PrintTable().run(self.bus.one_client)
- expected_output = "\n".join((
- "Name Enabled Timeout Last Successful Check",
- "foo Yes 00:05:00 2019-02-03T00:00:00 ",
- )) + "\n"
- self.assertEqual(expected_output, buffer.getvalue())
-
-
-class TestPropertySetterCmd(TestCommand):
- """Abstract class for tests of command.PropertySetter classes"""
-
- def runTest(self):
- if not hasattr(self, "command"):
- return # Abstract TestCase class
-
- if hasattr(self, "values_to_set"):
- cmd_args = [(value,) for value in self.values_to_set]
- values_to_get = getattr(self, "values_to_get",
- self.values_to_set)
- else:
- cmd_args = [() for x in range(len(self.values_to_get))]
- values_to_get = self.values_to_get
- for value_to_get, cmd_arg in zip(values_to_get, cmd_args):
- for clientpath in self.bus.clients:
- self.bus.clients[clientpath][self.propname] = (
- Unique())
- self.command(*cmd_arg).run(self.bus.clients, self.bus)
- for clientpath in self.bus.clients:
- value = (self.bus.clients[clientpath]
- [self.propname])
- self.assertNotIsInstance(value, Unique)
- self.assertEqual(value_to_get, value)
-
-
-class TestEnableCmd(TestPropertySetterCmd):
- command = command.Enable
- propname = "Enabled"
- values_to_get = [True]
-
-
-class TestDisableCmd(TestPropertySetterCmd):
- command = command.Disable
- propname = "Enabled"
- values_to_get = [False]
-
-
-class TestBumpTimeoutCmd(TestPropertySetterCmd):
- command = command.BumpTimeout
- propname = "LastCheckedOK"
- values_to_get = [""]
-
-
-class TestStartCheckerCmd(TestPropertySetterCmd):
- command = command.StartChecker
- propname = "CheckerRunning"
- values_to_get = [True]
-
-
-class TestStopCheckerCmd(TestPropertySetterCmd):
- command = command.StopChecker
- propname = "CheckerRunning"
- values_to_get = [False]
-
-
-class TestApproveByDefaultCmd(TestPropertySetterCmd):
- command = command.ApproveByDefault
- propname = "ApprovedByDefault"
- values_to_get = [True]
-
-
-class TestDenyByDefaultCmd(TestPropertySetterCmd):
- command = command.DenyByDefault
- propname = "ApprovedByDefault"
- values_to_get = [False]
-
-
-class TestSetCheckerCmd(TestPropertySetterCmd):
- command = command.SetChecker
- propname = "Checker"
- values_to_set = ["", ":", "fping -q -- %s"]
-
-
-class TestSetHostCmd(TestPropertySetterCmd):
- command = command.SetHost
- propname = "Host"
- values_to_set = ["192.0.2.3", "client.example.org"]
-
-
-class TestSetSecretCmd(TestPropertySetterCmd):
- command = command.SetSecret
- propname = "Secret"
- values_to_set = [io.BytesIO(b""),
- io.BytesIO(b"secret\0xyzzy\nbar")]
- values_to_get = [f.getvalue() for f in values_to_set]
-
-
-class TestSetTimeoutCmd(TestPropertySetterCmd):
- command = command.SetTimeout
- propname = "Timeout"
- values_to_set = [datetime.timedelta(),
- datetime.timedelta(minutes=5),
- datetime.timedelta(seconds=1),
- datetime.timedelta(weeks=1),
- datetime.timedelta(weeks=52)]
- values_to_get = [dt.total_seconds()*1000 for dt in values_to_set]
-
-
-class TestSetExtendedTimeoutCmd(TestPropertySetterCmd):
- command = command.SetExtendedTimeout
- propname = "ExtendedTimeout"
- values_to_set = [datetime.timedelta(),
- datetime.timedelta(minutes=5),
- datetime.timedelta(seconds=1),
- datetime.timedelta(weeks=1),
- datetime.timedelta(weeks=52)]
- values_to_get = [dt.total_seconds()*1000 for dt in values_to_set]
-
-
-class TestSetIntervalCmd(TestPropertySetterCmd):
- command = command.SetInterval
- propname = "Interval"
- values_to_set = [datetime.timedelta(),
- datetime.timedelta(minutes=5),
- datetime.timedelta(seconds=1),
- datetime.timedelta(weeks=1),
- datetime.timedelta(weeks=52)]
- values_to_get = [dt.total_seconds()*1000 for dt in values_to_set]
-
-
-class TestSetApprovalDelayCmd(TestPropertySetterCmd):
- command = command.SetApprovalDelay
- propname = "ApprovalDelay"
- values_to_set = [datetime.timedelta(),
- datetime.timedelta(minutes=5),
- datetime.timedelta(seconds=1),
- datetime.timedelta(weeks=1),
- datetime.timedelta(weeks=52)]
- values_to_get = [dt.total_seconds()*1000 for dt in values_to_set]
-
-
-class TestSetApprovalDurationCmd(TestPropertySetterCmd):
- command = command.SetApprovalDuration
- propname = "ApprovalDuration"
- values_to_set = [datetime.timedelta(),
- datetime.timedelta(minutes=5),
- datetime.timedelta(seconds=1),
- datetime.timedelta(weeks=1),
- datetime.timedelta(weeks=52)]
- values_to_get = [dt.total_seconds()*1000 for dt in values_to_set]
-
-
-
-def should_only_run_tests():
- parser = argparse.ArgumentParser(add_help=False)
- parser.add_argument("--check", action='store_true')
- args, unknown_args = parser.parse_known_args()
- run_tests = args.check
- if run_tests:
- # Remove --check argument from sys.argv
- sys.argv[1:] = unknown_args
- return run_tests
-
-# Add all tests from doctest strings
-def load_tests(loader, tests, none):
- import doctest
- tests.addTests(doctest.DocTestSuite())
- return tests
-
-if __name__ == "__main__":
- try:
- if should_only_run_tests():
- # Call using ./tdd-python-script --check [--verbose]
- unittest.main()
- else:
- main()
- finally:
- logging.shutdown()
=== removed file 'mandos-ctl.xml'
--- mandos-ctl.xml 2019-07-29 16:35:53 +0000
+++ mandos-ctl.xml 1970-01-01 00:00:00 +0000
@@ -1,652 +0,0 @@
-
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@recompile.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@recompile.se
-
-
-
-
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8
-
-
-
- &COMMANDNAME;
-
- Control or query the operation of the Mandos server
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
- CLIENT
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CLIENT
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CLIENT
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
- CLIENT
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is a program to control or
- query the operation of the Mandos server
- mandos8.
-
-
- This program can be used to change client settings, approve or
- deny client requests, and to remove clients from the server.
-
-
-
-
- PURPOSE
-
- The purpose of this is to enable remote and unattended
- rebooting of client host computer with an
- encrypted root file system. See for details.
-
-
-
-
- OPTIONS
-
-
-
-
-
-
-
- Show a help message and exit
-
-
-
-
-
-
-
-
-
- Enable client(s). An enabled client will be eligble to
- receive its secret.
-
-
-
-
-
-
-
-
-
- Disable client(s). A disabled client will not be eligble
- to receive its secret, and no checkers will be started for
- it.
-
-
-
-
-
-
-
-
- Bump the timeout of the specified client(s), just as if a
- checker had completed successfully for it/them.
-
-
-
-
-
-
-
-
- Start a new checker now for the specified client(s).
-
-
-
-
-
-
-
-
- Stop any running checker for the specified client(s).
-
-
-
-
-
-
-
-
-
- Remove the specified client(s) from the server.
-
-
-
-
-
-
-
-
-
- Set the checker option of the specified
- client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the timeout option of the specified
- client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
- Set the extended_timeout option of the
- specified client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the interval option of the
- specified client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the approved_by_default option of
- the specified client(s) to True or
- False, respectively; see
- mandos-clients.conf5.
-
-
-
-
-
-
-
-
- Set the approval_delay option of the
- specified client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
- Set the approval_duration option of the
- specified client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the host option of the specified
- client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the secfile option of the specified
- client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Approve client(s) if currently waiting for approval.
-
-
-
-
-
-
-
-
-
- Deny client(s) if currently waiting for approval.
-
-
-
-
-
-
-
-
-
- Make the client-modifying options modify all clients.
-
-
-
-
-
-
-
-
-
- Show all client settings, not just a subset.
-
-
-
-
-
-
-
-
-
- Dump client settings as JSON to standard output.
-
-
-
-
-
-
-
-
-
- Check if a single client is enabled or not, and exit with
- a successful exit status only if the client is enabled.
-
-
-
-
-
-
-
-
- Show debug output; currently, this means show D-Bus calls.
-
-
-
-
-
-
-
-
- Run self-tests. This includes any unit tests, etc.
-
-
-
-
-
-
-
-
- OVERVIEW
-
-
- This program is a small utility to generate new OpenPGP keys for
- new Mandos clients, and to generate sections for inclusion in
- clients.conf on the server.
-
-
-
-
- EXIT STATUS
-
- If the option is used, the exit
- status will be 0 only if the specified client is enabled.
-
-
-
-
- BUGS
-
-
-
-
- EXAMPLE
-
-
-
-
- To list all clients:
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- To list all settings for the clients
- named foo1.example.org
and foo2.example.org
:
-
-
-
-
-&COMMANDNAME; --verbose foo1.example.org foo2.example.org
-
-
-
-
-
-
-
- To enable all clients:
-
-
- &COMMANDNAME; --enable --all
-
-
-
-
-
-
- To change timeout and interval value for the clients
- named foo1.example.org
and foo2.example.org
:
-
-
-
-
-&COMMANDNAME; --timeout=PT5M --interval=PT1M foo1.example.org foo2.example.org
-
-
-
-
-
-
-
- To approve all clients currently waiting for approval:
-
-
- &COMMANDNAME; --approve --all
-
-
-
-
-
- SECURITY
-
- This program must be permitted to access the Mandos server via
- the D-Bus interface. This normally requires the root user, but
- could be configured otherwise by reconfiguring the D-Bus server.
-
-
-
-
- SEE ALSO
-
- intro
- 8mandos,
- mandos
- 8,
- mandos-clients.conf
- 5,
- mandos-monitor
- 8
-
-
-
-
-
-
-
-
-
=== removed file 'mandos-keygen'
--- mandos-keygen 2019-09-03 19:06:41 +0000
+++ mandos-keygen 1970-01-01 00:00:00 +0000
@@ -1,451 +0,0 @@
-#!/bin/sh -e
-#
-# Mandos key generator - create new keys for a Mandos client
-#
-# Copyright © 2008-2019 Teddy Hogeborn
-# Copyright © 2008-2019 Björn Påhlsson
-#
-# This file is part of Mandos.
-#
-# Mandos 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.
-#
-# Mandos 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 Mandos. If not, see .
-#
-# Contact the authors at .
-#
-
-VERSION="1.8.9"
-
-KEYDIR="/etc/keys/mandos"
-KEYTYPE=RSA
-KEYLENGTH=4096
-SUBKEYTYPE=RSA
-SUBKEYLENGTH=4096
-KEYNAME="`hostname --fqdn 2>/dev/null || hostname`"
-KEYEMAIL=""
-KEYCOMMENT=""
-KEYEXPIRE=0
-TLS_KEYTYPE=ed25519
-FORCE=no
-SSH=yes
-KEYCOMMENT_ORIG="$KEYCOMMENT"
-mode=keygen
-
-if [ ! -d "$KEYDIR" ]; then
- KEYDIR="/etc/mandos/keys"
-fi
-
-# Parse options
-TEMP=`getopt --options vhpF:d:t:l:s:L:n:e:c:x:T:fS \
- --longoptions version,help,password,passfile:,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,tls-keytype:,force,no-ssh \
- --name "$0" -- "$@"`
-
-help(){
-basename="`basename "$0"`"
-cat <&2; exit 1;;
- esac
-done
-if [ "$#" -gt 0 ]; then
- echo "Unknown arguments: '$*'" >&2
- exit 1
-fi
-
-SECKEYFILE="$KEYDIR/seckey.txt"
-PUBKEYFILE="$KEYDIR/pubkey.txt"
-TLS_PRIVKEYFILE="$KEYDIR/tls-privkey.pem"
-TLS_PUBKEYFILE="$KEYDIR/tls-pubkey.pem"
-
-# Check for some invalid values
-if [ ! -d "$KEYDIR" ]; then
- echo "$KEYDIR not a directory" >&2
- exit 1
-fi
-if [ ! -r "$KEYDIR" ]; then
- echo "Directory $KEYDIR not readable" >&2
- exit 1
-fi
-
-if [ "$mode" = keygen ]; then
- if [ ! -w "$KEYDIR" ]; then
- echo "Directory $KEYDIR not writeable" >&2
- exit 1
- fi
- if [ -z "$KEYTYPE" ]; then
- echo "Empty key type" >&2
- exit 1
- fi
-
- if [ -z "$KEYNAME" ]; then
- echo "Empty key name" >&2
- exit 1
- fi
-
- if [ -z "$KEYLENGTH" ] || [ "$KEYLENGTH" -lt 512 ]; then
- echo "Invalid key length" >&2
- exit 1
- fi
-
- if [ -z "$KEYEXPIRE" ]; then
- echo "Empty key expiration" >&2
- exit 1
- fi
-
- # Make FORCE be 0 or 1
- case "$FORCE" in
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) FORCE=1;;
- [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
- esac
-
- if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ] \
- || [ -e "$TLS_PRIVKEYFILE" ] \
- || [ -e "$TLS_PUBKEYFILE" ]; } \
- && [ "$FORCE" -eq 0 ]; then
- echo "Refusing to overwrite old key files; use --force" >&2
- exit 1
- fi
-
- # Set lines for GnuPG batch file
- if [ -n "$KEYCOMMENT" ]; then
- KEYCOMMENTLINE="Name-Comment: $KEYCOMMENT"
- fi
- if [ -n "$KEYEMAIL" ]; then
- KEYEMAILLINE="Name-Email: $KEYEMAIL"
- fi
-
- # Create temporary gpg batch file
- BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
- TLS_PRIVKEYTMP="`mktemp -t mandos-keygen-privkey.XXXXXXXXXX`"
-fi
-
-if [ "$mode" = password ]; then
- # Create temporary encrypted password file
- SECFILE="`mktemp -t mandos-keygen-secfile.XXXXXXXXXX`"
-fi
-
-# Create temporary key ring directory
-RINGDIR="`mktemp -d -t mandos-keygen-keyrings.XXXXXXXXXX`"
-
-# Remove temporary files on exit
-trap "
-set +e; \
-test -n \"$SECFILE\" && shred --remove \"$SECFILE\"; \
-test -n \"$TLS_PRIVKEYTMP\" && shred --remove \"$TLS_PRIVKEYTMP\"; \
-shred --remove \"$RINGDIR\"/sec* 2>/dev/null;
-test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
-rm --recursive --force \"$RINGDIR\";
-tty --quiet && stty echo; \
-" EXIT
-
-set -e
-
-umask 077
-
-if [ "$mode" = keygen ]; then
- # Create batch file for GnuPG
- cat >"$BATCHFILE" <<-EOF
- Key-Type: $KEYTYPE
- Key-Length: $KEYLENGTH
- Key-Usage: sign,auth
- Subkey-Type: $SUBKEYTYPE
- Subkey-Length: $SUBKEYLENGTH
- Subkey-Usage: encrypt
- Name-Real: $KEYNAME
- $KEYCOMMENTLINE
- $KEYEMAILLINE
- Expire-Date: $KEYEXPIRE
- #Preferences:
- #Handle:
- #%pubring pubring.gpg
- #%secring secring.gpg
- %no-protection
- %commit
- EOF
-
- if tty --quiet; then
- cat <<-EOF
- Note: Due to entropy requirements, key generation could take
- anything from a few minutes to SEVERAL HOURS. Please be
- patient and/or supply the system with more entropy if needed.
- EOF
- echo -n "Started: "
- date
- fi
-
- # Generate TLS private key
- if certtool --generate-privkey --password='' \
- --outfile "$TLS_PRIVKEYTMP" --sec-param ultra \
- --key-type="$TLS_KEYTYPE" --pkcs8 --no-text 2>/dev/null; then
-
- # Backup any old key files
- if cp --backup=numbered --force "$TLS_PRIVKEYFILE" "$TLS_PRIVKEYFILE" \
- 2>/dev/null; then
- shred --remove "$TLS_PRIVKEYFILE" 2>/dev/null || :
- fi
- if cp --backup=numbered --force "$TLS_PUBKEYFILE" "$TLS_PUBKEYFILE" \
- 2>/dev/null; then
- rm --force "$TLS_PUBKEYFILE"
- fi
- cp --archive "$TLS_PRIVKEYTMP" "$TLS_PRIVKEYFILE"
- shred --remove "$TLS_PRIVKEYTMP" 2>/dev/null || :
-
- ## TLS public key
-
- # First try certtool from GnuTLS
- if ! certtool --password='' --load-privkey="$TLS_PRIVKEYFILE" \
- --outfile="$TLS_PUBKEYFILE" --pubkey-info --no-text \
- 2>/dev/null; then
- # Otherwise try OpenSSL
- if ! openssl pkey -in "$TLS_PRIVKEYFILE" \
- -out "$TLS_PUBKEYFILE" -pubout; then
- rm --force "$TLS_PUBKEYFILE"
- # None of the commands succeded; give up
- return 1
- fi
- fi
- fi
-
- # Make sure trustdb.gpg exists;
- # this is a workaround for Debian bug #737128
- gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
- --homedir "$RINGDIR" \
- --import-ownertrust < /dev/null
- # Generate a new key in the key rings
- gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
- --homedir "$RINGDIR" --trust-model always \
- --gen-key "$BATCHFILE"
- rm --force "$BATCHFILE"
-
- if tty --quiet; then
- echo -n "Finished: "
- date
- fi
-
- # Backup any old key files
- if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
- 2>/dev/null; then
- shred --remove "$SECKEYFILE" 2>/dev/null || :
- fi
- if cp --backup=numbered --force "$PUBKEYFILE" "$PUBKEYFILE" \
- 2>/dev/null; then
- rm --force "$PUBKEYFILE"
- fi
-
- FILECOMMENT="Mandos client key for $KEYNAME"
- if [ "$KEYCOMMENT" != "$KEYCOMMENT_ORIG" ]; then
- FILECOMMENT="$FILECOMMENT ($KEYCOMMENT)"
- fi
-
- if [ -n "$KEYEMAIL" ]; then
- FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
- fi
-
- # Export key from key rings to key files
- gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
- --homedir "$RINGDIR" --armor --export-options export-minimal \
- --comment "$FILECOMMENT" --output "$SECKEYFILE" \
- --export-secret-keys
- gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
- --homedir "$RINGDIR" --armor --export-options export-minimal \
- --comment "$FILECOMMENT" --output "$PUBKEYFILE" --export
-fi
-
-if [ "$mode" = password ]; then
-
- # Make SSH be 0 or 1
- case "$SSH" in
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) SSH=1;;
- [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) SSH=0;;
- esac
-
- if [ $SSH -eq 1 ]; then
- for ssh_keytype in ecdsa-sha2-nistp256 ed25519 rsa; do
- set +e
- ssh_fingerprint="`ssh-keyscan -t $ssh_keytype localhost 2>/dev/null`"
- err=$?
- set -e
- if [ $err -ne 0 ]; then
- ssh_fingerprint=""
- continue
- fi
- if [ -n "$ssh_fingerprint" ]; then
- ssh_fingerprint="${ssh_fingerprint#localhost }"
- break
- fi
- done
- fi
-
- # Import key into temporary key rings
- gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
- --homedir "$RINGDIR" --trust-model always --armor \
- --import "$SECKEYFILE"
- gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
- --homedir "$RINGDIR" --trust-model always --armor \
- --import "$PUBKEYFILE"
-
- # Get fingerprint of key
- FINGERPRINT="`gpg --quiet --batch --no-tty --no-options \
- --enable-dsa2 --homedir "$RINGDIR" --trust-model always \
- --fingerprint --with-colons \
- | sed --quiet \
- --expression='/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
-
- test -n "$FINGERPRINT"
-
- if [ -r "$TLS_PUBKEYFILE" ]; then
- KEY_ID="$(certtool --key-id --hash=sha256 \
- --infile="$TLS_PUBKEYFILE" 2>/dev/null || :)"
-
- if [ -z "$KEY_ID" ]; then
- KEY_ID=$(openssl pkey -pubin -in "$TLS_PUBKEYFILE" \
- -outform der \
- | openssl sha256 \
- | sed --expression='s/^.*[^[:xdigit:]]//')
- fi
- test -n "$KEY_ID"
- fi
-
- FILECOMMENT="Encrypted password for a Mandos client"
-
- while [ ! -s "$SECFILE" ]; do
- if [ -n "$PASSFILE" ]; then
- cat -- "$PASSFILE"
- else
- tty --quiet && stty -echo
- echo -n "Enter passphrase: " >/dev/tty
- read -r first
- tty --quiet && echo >&2
- echo -n "Repeat passphrase: " >/dev/tty
- read -r second
- if tty --quiet; then
- echo >&2
- stty echo
- fi
- if [ "$first" != "$second" ]; then
- echo "Passphrase mismatch" >&2
- touch "$RINGDIR"/mismatch
- else
- echo -n "$first"
- fi
- fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
- --homedir "$RINGDIR" --trust-model always --armor \
- --encrypt --sign --recipient "$FINGERPRINT" --comment \
- "$FILECOMMENT" > "$SECFILE"
- if [ -e "$RINGDIR"/mismatch ]; then
- rm --force "$RINGDIR"/mismatch
- if tty --quiet; then
- > "$SECFILE"
- else
- exit 1
- fi
- fi
- done
-
- cat <<-EOF
- [$KEYNAME]
- host = $KEYNAME
- EOF
- if [ -n "$KEY_ID" ]; then
- echo "key_id = $KEY_ID"
- fi
- cat <<-EOF
- fingerprint = $FINGERPRINT
- secret =
- EOF
- sed --quiet --expression='
- /^-----BEGIN PGP MESSAGE-----$/,/^-----END PGP MESSAGE-----$/{
- /^$/,${
- # Remove 24-bit Radix-64 checksum
- s/=....$//
- # Indent four spaces
- /^[^-]/s/^/ /p
- }
- }' < "$SECFILE"
- if [ -n "$ssh_fingerprint" ]; then
- echo 'checker = ssh-keyscan -t '"$ssh_keytype"' %%(host)s 2>/dev/null | grep --fixed-strings --line-regexp --quiet --regexp=%%(host)s" %(ssh_fingerprint)s"'
- echo "ssh_fingerprint = ${ssh_fingerprint}"
- fi
-fi
-
-trap - EXIT
-
-set +e
-# Remove the password file, if any
-if [ -n "$SECFILE" ]; then
- shred --remove "$SECFILE" 2>/dev/null
-fi
-# Remove the key rings
-shred --remove "$RINGDIR"/sec* 2>/dev/null
-rm --recursive --force "$RINGDIR"
=== removed file 'mandos-keygen.xml'
--- mandos-keygen.xml 2019-07-18 00:02:43 +0000
+++ mandos-keygen.xml 1970-01-01 00:00:00 +0000
@@ -1,590 +0,0 @@
-
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@recompile.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@recompile.se
-
-
-
-
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8
-
-
-
- &COMMANDNAME;
-
- Generate key and password for Mandos client and server.
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
- FILE
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is a program to generate the
- TLS and OpenPGP keys used by
- mandos-client
- 8mandos. The keys are
- normally written to /etc/keys/mandos for later installation into
- the initrd image, but this, and most other things, can be
- changed with command line options.
-
-
- This program can also be used with the
- or
- options to generate a ready-made section for
- clients.conf (see
- mandos-clients.conf
- 5).
-
-
-
-
- PURPOSE
-
- The purpose of this is to enable remote and unattended
- rebooting of client host computer with an
- encrypted root file system. See for details.
-
-
-
-
- OPTIONS
-
-
-
-
-
-
-
- Show a help message and exit
-
-
-
-
-
-
-
-
-
- Target directory for key files. Default is /etc/keys/mandos.
-
-
-
-
-
-
-
-
-
- OpenPGP key type. Default is RSA
.
-
-
-
-
-
-
-
-
-
- OpenPGP key length in bits. Default is 4096.
-
-
-
-
-
-
-
-
-
- OpenPGP subkey type. Default is RSA
-
-
-
-
-
-
-
-
-
- OpenPGP subkey length in bits. Default is 4096.
-
-
-
-
-
-
-
-
-
- Email address of key. Default is empty.
-
-
-
-
-
-
-
-
-
- Comment field for key. Default is empty.
-
-
-
-
-
-
-
-
-
- Key expire time. Default is no expiration. See
- gpg
- 1 for syntax.
-
-
-
-
-
-
-
-
-
- TLS key type. Default is ed25519
-
-
-
-
-
-
-
-
-
- Force overwriting old key.
-
-
-
-
-
-
-
-
- Prompt for a password and encrypt it with the key already
- present in either /etc/keys/mandos or
- the directory specified with the
- option. Outputs, on standard output, a section suitable
- for inclusion in mandos-clients.conf8. The host name or the name
- specified with the option is used
- for the section header. All other options are ignored,
- and no key is created. Note: white space is stripped from
- the beginning and from the end of the password; See .
-
-
-
-
-
-
-
-
- The same as , but read from
- FILE, not the terminal, and
- white space is not stripped from the password in any way.
-
-
-
-
-
-
-
-
- When or
- is given, this option will
- prevent &COMMANDNAME; from calling
- ssh-keyscan to get an SSH fingerprint
- for this host and, if successful, output suitable config
- options to use this fingerprint as a
- option in the output. This is
- otherwise the default behavior.
-
-
-
-
-
-
-
- OVERVIEW
-
-
- This program is a small utility to generate new TLS and OpenPGP
- keys for new Mandos clients, and to generate sections for
- inclusion in clients.conf on the server.
-
-
-
-
- EXIT STATUS
-
- The exit status will be 0 if a new key (or password, if the
- option was used) was successfully
- created, otherwise not.
-
-
-
-
- ENVIRONMENT
-
-
- TMPDIR
-
-
- If set, temporary files will be created here. See
- mktemp
- 1.
-
-
-
-
-
-
-
- FILES
-
- Use the option to change where
- &COMMANDNAME; will write the key files. The
- default file names are shown here.
-
-
-
- /etc/keys/mandos/seckey.txt
-
-
- OpenPGP secret key file which will be created or
- overwritten.
-
-
-
-
- /etc/keys/mandos/pubkey.txt
-
-
- OpenPGP public key file which will be created or
- overwritten.
-
-
-
-
- /etc/keys/mandos/tls-privkey.pem
-
-
- Private key file which will be created or overwritten.
-
-
-
-
- /etc/keys/mandos/tls-pubkey.pem
-
-
- Public key file which will be created or overwritten.
-
-
-
-
- /tmp
-
-
- Temporary files will be written here if
- TMPDIR is not set.
-
-
-
-
-
-
-
- BUGS
-
- The / option
- strips white space from the start and from the end of the
- password before using it. If this is a problem, use the
- option instead, which does not do
- this.
-
-
-
-
-
- EXAMPLE
-
-
- Normal invocation needs no options:
-
-
- &COMMANDNAME;
-
-
-
-
- Create key in another directory and of another type. Force
- overwriting old key files:
-
-
-
-
-&COMMANDNAME; --dir ~/keydir --type RSA --force
-
-
-
-
-
- Prompt for a password, encrypt it with the keys in /etc/keys/mandos and output a
- section suitable for clients.conf.
-
-
- &COMMANDNAME; --password
-
-
-
-
- Prompt for a password, encrypt it with the keys in the
- client-key directory and output a section
- suitable for clients.conf.
-
-
-
-
-&COMMANDNAME; --password --dir client-key
-
-
-
-
-
-
- SECURITY
-
- The , ,
- , and
- options can be used to create keys of low security. If in
- doubt, leave them to the default values.
-
-
- The key expire time is not guaranteed to be
- honored by mandos
- 8.
-
-
-
-
- SEE ALSO
-
- intro
- 8mandos,
- gpg
- 1,
- mandos-clients.conf
- 5,
- mandos
- 8,
- mandos-client
- 8mandos,
- ssh-keyscan
- 1
-
-
-
-
-
-
-
-
-
=== removed file 'mandos-monitor'
--- mandos-monitor 2019-11-03 19:09:41 +0000
+++ mandos-monitor 1970-01-01 00:00:00 +0000
@@ -1,757 +0,0 @@
-#!/usr/bin/python3 -bbI
-# -*- mode: python; coding: utf-8 -*-
-#
-# Mandos Monitor - Control and monitor the Mandos server
-#
-# Copyright © 2009-2019 Teddy Hogeborn
-# Copyright © 2009-2019 Björn Påhlsson
-#
-# This file is part of Mandos.
-#
-# Mandos 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.
-#
-# Mandos 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 Mandos. If not, see .
-#
-# Contact the authors at .
-#
-
-from __future__ import (division, absolute_import, print_function,
- unicode_literals)
-try:
- from future_builtins import *
-except ImportError:
- pass
-
-import sys
-import os
-import warnings
-import datetime
-import locale
-import logging
-
-import urwid.curses_display
-import urwid
-
-from dbus.mainloop.glib import DBusGMainLoop
-from gi.repository import GLib
-
-import dbus
-
-if sys.version_info.major == 2:
- str = unicode
-
-log = logging.getLogger(os.path.basename(sys.argv[0]))
-logging.basicConfig(level="NOTSET", # Show all messages
- format="%(message)s") # Show basic log messages
-
-logging.captureWarnings(True) # Show warnings via the logging system
-
-locale.setlocale(locale.LC_ALL, "")
-
-logging.getLogger("dbus.proxies").setLevel(logging.CRITICAL)
-
-# Some useful constants
-domain = "se.recompile"
-server_interface = domain + ".Mandos"
-client_interface = domain + ".Mandos.Client"
-version = "1.8.9"
-
-try:
- dbus.OBJECT_MANAGER_IFACE
-except AttributeError:
- dbus.OBJECT_MANAGER_IFACE = "org.freedesktop.DBus.ObjectManager"
-
-
-def isoformat_to_datetime(iso):
- "Parse an ISO 8601 date string to a datetime.datetime()"
- if not iso:
- return None
- d, t = iso.split("T", 1)
- year, month, day = d.split("-", 2)
- hour, minute, second = t.split(":", 2)
- second, fraction = divmod(float(second), 1)
- return datetime.datetime(int(year),
- int(month),
- int(day),
- int(hour),
- int(minute),
- int(second), # Whole seconds
- int(fraction*1000000)) # Microseconds
-
-
-class MandosClientPropertyCache(object):
- """This wraps a Mandos Client D-Bus proxy object, caches the
- properties and calls a hook function when any of them are
- changed.
- """
- def __init__(self, proxy_object=None, properties=None, **kwargs):
- self.proxy = proxy_object # Mandos Client proxy object
- self.properties = dict() if properties is None else properties
- self.property_changed_match = (
- self.proxy.connect_to_signal("PropertiesChanged",
- self.properties_changed,
- dbus.PROPERTIES_IFACE,
- byte_arrays=True))
-
- if properties is None:
- self.properties.update(self.proxy.GetAll(
- client_interface,
- dbus_interface=dbus.PROPERTIES_IFACE))
-
- super(MandosClientPropertyCache, self).__init__(**kwargs)
-
- def properties_changed(self, interface, properties, invalidated):
- """This is called whenever we get a PropertiesChanged signal
- It updates the changed properties in the "properties" dict.
- """
- # Update properties dict with new value
- if interface == client_interface:
- self.properties.update(properties)
-
- def delete(self):
- self.property_changed_match.remove()
-
-
-class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
- """A Mandos Client which is visible on the screen.
- """
-
- def __init__(self, server_proxy_object=None, update_hook=None,
- delete_hook=None, **kwargs):
- # Called on update
- self.update_hook = update_hook
- # Called on delete
- self.delete_hook = delete_hook
- # Mandos Server proxy object
- self.server_proxy_object = server_proxy_object
-
- self._update_timer_callback_tag = None
-
- # The widget shown normally
- self._text_widget = urwid.Text("")
- # The widget shown when we have focus
- self._focus_text_widget = urwid.Text("")
- super(MandosClientWidget, self).__init__(**kwargs)
- self.update()
- self.opened = False
-
- self.match_objects = (
- self.proxy.connect_to_signal("CheckerCompleted",
- self.checker_completed,
- client_interface,
- byte_arrays=True),
- self.proxy.connect_to_signal("CheckerStarted",
- self.checker_started,
- client_interface,
- byte_arrays=True),
- self.proxy.connect_to_signal("GotSecret",
- self.got_secret,
- client_interface,
- byte_arrays=True),
- self.proxy.connect_to_signal("NeedApproval",
- self.need_approval,
- client_interface,
- byte_arrays=True),
- self.proxy.connect_to_signal("Rejected",
- self.rejected,
- client_interface,
- byte_arrays=True))
- log.debug("Created client %s", self.properties["Name"])
-
- def using_timer(self, flag):
- """Call this method with True or False when timer should be
- activated or deactivated.
- """
- if flag and self._update_timer_callback_tag is None:
- # Will update the shown timer value every second
- self._update_timer_callback_tag = (
- GLib.timeout_add(1000,
- glib_safely(self.update_timer)))
- elif not (flag or self._update_timer_callback_tag is None):
- GLib.source_remove(self._update_timer_callback_tag)
- self._update_timer_callback_tag = None
-
- def checker_completed(self, exitstatus, condition, command):
- if exitstatus == 0:
- log.debug('Checker for client %s (command "%s")'
- " succeeded", self.properties["Name"], command)
- self.update()
- return
- # Checker failed
- if os.WIFEXITED(condition):
- log.info('Checker for client %s (command "%s") failed'
- " with exit code %d", self.properties["Name"],
- command, os.WEXITSTATUS(condition))
- elif os.WIFSIGNALED(condition):
- log.info('Checker for client %s (command "%s") was'
- " killed by signal %d", self.properties["Name"],
- command, os.WTERMSIG(condition))
- self.update()
-
- def checker_started(self, command):
- """Server signals that a checker started."""
- log.debug('Client %s started checker "%s"',
- self.properties["Name"], command)
-
- def got_secret(self):
- log.info("Client %s received its secret",
- self.properties["Name"])
-
- def need_approval(self, timeout, default):
- if not default:
- message = "Client %s needs approval within %f seconds"
- else:
- message = "Client %s will get its secret in %f seconds"
- log.info(message, self.properties["Name"], timeout/1000)
-
- def rejected(self, reason):
- log.info("Client %s was rejected; reason: %s",
- self.properties["Name"], reason)
-
- def selectable(self):
- """Make this a "selectable" widget.
- This overrides the method from urwid.FlowWidget."""
- return True
-
- def rows(self, maxcolrow, focus=False):
- """How many rows this widget will occupy might depend on
- whether we have focus or not.
- This overrides the method from urwid.FlowWidget"""
- return self.current_widget(focus).rows(maxcolrow, focus=focus)
-
- def current_widget(self, focus=False):
- if focus or self.opened:
- return self._focus_widget
- return self._widget
-
- def update(self):
- "Called when what is visible on the screen should be updated."
- # How to add standout mode to a style
- with_standout = {"normal": "standout",
- "bold": "bold-standout",
- "underline-blink":
- "underline-blink-standout",
- "bold-underline-blink":
- "bold-underline-blink-standout",
- }
-
- # Rebuild focus and non-focus widgets using current properties
-
- # Base part of a client. Name!
- base = "{name}: ".format(name=self.properties["Name"])
- if not self.properties["Enabled"]:
- message = "DISABLED"
- self.using_timer(False)
- elif self.properties["ApprovalPending"]:
- timeout = datetime.timedelta(
- milliseconds=self.properties["ApprovalDelay"])
- last_approval_request = isoformat_to_datetime(
- self.properties["LastApprovalRequest"])
- if last_approval_request is not None:
- timer = max(timeout - (datetime.datetime.utcnow()
- - last_approval_request),
- datetime.timedelta())
- else:
- timer = datetime.timedelta()
- if self.properties["ApprovedByDefault"]:
- message = "Approval in {}. (d)eny?"
- else:
- message = "Denial in {}. (a)pprove?"
- message = message.format(str(timer).rsplit(".", 1)[0])
- self.using_timer(True)
- elif self.properties["LastCheckerStatus"] != 0:
- # When checker has failed, show timer until client expires
- expires = self.properties["Expires"]
- if expires == "":
- timer = datetime.timedelta(0)
- else:
- expires = (datetime.datetime.strptime
- (expires, "%Y-%m-%dT%H:%M:%S.%f"))
- timer = max(expires - datetime.datetime.utcnow(),
- datetime.timedelta())
- message = ("A checker has failed! Time until client"
- " gets disabled: {}"
- .format(str(timer).rsplit(".", 1)[0]))
- self.using_timer(True)
- else:
- message = "enabled"
- self.using_timer(False)
- self._text = "{}{}".format(base, message)
-
- if not urwid.supports_unicode():
- self._text = self._text.encode("ascii", "replace")
- textlist = [("normal", self._text)]
- self._text_widget.set_text(textlist)
- self._focus_text_widget.set_text([(with_standout[text[0]],
- text[1])
- if isinstance(text, tuple)
- else text
- for text in textlist])
- self._widget = self._text_widget
- self._focus_widget = urwid.AttrWrap(self._focus_text_widget,
- "standout")
- # Run update hook, if any
- if self.update_hook is not None:
- self.update_hook()
-
- def update_timer(self):
- """called by GLib. Will indefinitely loop until
- GLib.source_remove() on tag is called
- """
- self.update()
- return True # Keep calling this
-
- def delete(self, **kwargs):
- if self._update_timer_callback_tag is not None:
- GLib.source_remove(self._update_timer_callback_tag)
- self._update_timer_callback_tag = None
- for match in self.match_objects:
- match.remove()
- self.match_objects = ()
- if self.delete_hook is not None:
- self.delete_hook(self)
- return super(MandosClientWidget, self).delete(**kwargs)
-
- def render(self, maxcolrow, focus=False):
- """Render differently if we have focus.
- This overrides the method from urwid.FlowWidget"""
- return self.current_widget(focus).render(maxcolrow,
- focus=focus)
-
- def keypress(self, maxcolrow, key):
- """Handle keys.
- This overrides the method from urwid.FlowWidget"""
- if key == "+":
- self.proxy.Set(client_interface, "Enabled",
- dbus.Boolean(True), ignore_reply=True,
- dbus_interface=dbus.PROPERTIES_IFACE)
- elif key == "-":
- self.proxy.Set(client_interface, "Enabled", False,
- ignore_reply=True,
- dbus_interface=dbus.PROPERTIES_IFACE)
- elif key == "a":
- self.proxy.Approve(dbus.Boolean(True, variant_level=1),
- dbus_interface=client_interface,
- ignore_reply=True)
- elif key == "d":
- self.proxy.Approve(dbus.Boolean(False, variant_level=1),
- dbus_interface=client_interface,
- ignore_reply=True)
- elif key == "R" or key == "_" or key == "ctrl k":
- self.server_proxy_object.RemoveClient(self.proxy
- .object_path,
- ignore_reply=True)
- elif key == "s":
- self.proxy.Set(client_interface, "CheckerRunning",
- dbus.Boolean(True), ignore_reply=True,
- dbus_interface=dbus.PROPERTIES_IFACE)
- elif key == "S":
- self.proxy.Set(client_interface, "CheckerRunning",
- dbus.Boolean(False), ignore_reply=True,
- dbus_interface=dbus.PROPERTIES_IFACE)
- elif key == "C":
- self.proxy.CheckedOK(dbus_interface=client_interface,
- ignore_reply=True)
- # xxx
-# elif key == "p" or key == "=":
-# self.proxy.pause()
-# elif key == "u" or key == ":":
-# self.proxy.unpause()
-# elif key == "RET":
-# self.open()
- else:
- return key
-
- def properties_changed(self, interface, properties, invalidated):
- """Call self.update() if any properties changed.
- This overrides the method from MandosClientPropertyCache"""
- old_values = {key: self.properties.get(key)
- for key in properties.keys()}
- super(MandosClientWidget, self).properties_changed(
- interface, properties, invalidated)
- if any(old_values[key] != self.properties.get(key)
- for key in old_values):
- self.update()
-
-
-def glib_safely(func, retval=True):
- def safe_func(*args, **kwargs):
- try:
- return func(*args, **kwargs)
- except Exception:
- log.exception("")
- return retval
- return safe_func
-
-
-class ConstrainedListBox(urwid.ListBox):
- """Like a normal urwid.ListBox, but will consume all "up" or
- "down" key presses, thus not allowing any containing widgets to
- use them as an excuse to shift focus away from this widget.
- """
- def keypress(self, *args, **kwargs):
- ret = (super(ConstrainedListBox, self)
- .keypress(*args, **kwargs))
- if ret in ("up", "down"):
- return
- return ret
-
-
-class UserInterface(object):
- """This is the entire user interface - the whole screen
- with boxes, lists of client widgets, etc.
- """
- def __init__(self, max_log_length=1000):
- DBusGMainLoop(set_as_default=True)
-
- self.screen = urwid.curses_display.Screen()
-
- self.screen.register_palette((
- ("normal",
- "default", "default", None),
- ("bold",
- "bold", "default", "bold"),
- ("underline-blink",
- "underline,blink", "default", "underline,blink"),
- ("standout",
- "standout", "default", "standout"),
- ("bold-underline-blink",
- "bold,underline,blink", "default",
- "bold,underline,blink"),
- ("bold-standout",
- "bold,standout", "default", "bold,standout"),
- ("underline-blink-standout",
- "underline,blink,standout", "default",
- "underline,blink,standout"),
- ("bold-underline-blink-standout",
- "bold,underline,blink,standout", "default",
- "bold,underline,blink,standout"),
- ))
-
- if urwid.supports_unicode():
- self.divider = "─" # \u2500
- else:
- self.divider = "_" # \u005f
-
- self.screen.start()
-
- self.size = self.screen.get_cols_rows()
-
- self.clients = urwid.SimpleListWalker([])
- self.clients_dict = {}
-
- # We will add Text widgets to this list
- self.log = urwid.SimpleListWalker([])
- self.max_log_length = max_log_length
-
- # We keep a reference to the log widget so we can remove it
- # from the ListWalker without it getting destroyed
- self.logbox = ConstrainedListBox(self.log)
-
- # This keeps track of whether self.uilist currently has
- # self.logbox in it or not
- self.log_visible = True
- self.log_wrap = "any"
-
- self.loghandler = UILogHandler(self)
-
- self.rebuild()
- self.add_log_line(("bold",
- "Mandos Monitor version " + version))
- self.add_log_line(("bold", "q: Quit ?: Help"))
-
- self.busname = domain + ".Mandos"
- self.main_loop = GLib.MainLoop()
-
- def client_not_found(self, key_id, address):
- log.info("Client with address %s and key ID %s could"
- " not be found", address, key_id)
-
- def rebuild(self):
- """This rebuilds the User Interface.
- Call this when the widget layout needs to change"""
- self.uilist = []
- # self.uilist.append(urwid.ListBox(self.clients))
- self.uilist.append(urwid.Frame(ConstrainedListBox(self.
- clients),
- # header=urwid.Divider(),
- header=None,
- footer=urwid.Divider(
- div_char=self.divider)))
- if self.log_visible:
- self.uilist.append(self.logbox)
- self.topwidget = urwid.Pile(self.uilist)
-
- def add_log_line(self, markup):
- self.log.append(urwid.Text(markup, wrap=self.log_wrap))
- if self.max_log_length:
- if len(self.log) > self.max_log_length:
- del self.log[0:(len(self.log) - self.max_log_length)]
- self.logbox.set_focus(len(self.logbox.body.contents)-1,
- coming_from="above")
- self.refresh()
-
- def toggle_log_display(self):
- """Toggle visibility of the log buffer."""
- self.log_visible = not self.log_visible
- self.rebuild()
- log.debug("Log visibility changed to: %s", self.log_visible)
-
- def change_log_display(self):
- """Change type of log display.
- Currently, this toggles wrapping of text lines."""
- if self.log_wrap == "clip":
- self.log_wrap = "any"
- else:
- self.log_wrap = "clip"
- for textwidget in self.log:
- textwidget.set_wrap_mode(self.log_wrap)
- log.debug("Wrap mode: %s", self.log_wrap)
-
- def find_and_remove_client(self, path, interfaces):
- """Find a client by its object path and remove it.
-
- This is connected to the InterfacesRemoved signal from the
- Mandos server object."""
- if client_interface not in interfaces:
- # Not a Mandos client object; ignore
- return
- try:
- client = self.clients_dict[path]
- except KeyError:
- # not found?
- log.warning("Unknown client %s removed", path)
- return
- client.delete()
-
- def add_new_client(self, path, ifs_and_props):
- """Find a client by its object path and remove it.
-
- This is connected to the InterfacesAdded signal from the
- Mandos server object.
- """
- if client_interface not in ifs_and_props:
- # Not a Mandos client object; ignore
- return
- client_proxy_object = self.bus.get_object(self.busname, path)
- self.add_client(MandosClientWidget(
- server_proxy_object=self.mandos_serv,
- proxy_object=client_proxy_object,
- update_hook=self.refresh,
- delete_hook=self.remove_client,
- properties=dict(ifs_and_props[client_interface])),
- path=path)
-
- def add_client(self, client, path=None):
- self.clients.append(client)
- if path is None:
- path = client.proxy.object_path
- self.clients_dict[path] = client
- self.clients.sort(key=lambda c: c.properties["Name"])
- self.refresh()
-
- def remove_client(self, client, path=None):
- self.clients.remove(client)
- if path is None:
- path = client.proxy.object_path
- del self.clients_dict[path]
- self.refresh()
-
- def refresh(self):
- """Redraw the screen"""
- canvas = self.topwidget.render(self.size, focus=True)
- self.screen.draw_screen(self.size, canvas)
-
- def run(self):
- """Start the main loop and exit when it's done."""
- log.addHandler(self.loghandler)
- self.orig_log_propagate = log.propagate
- log.propagate = False
- self.orig_log_level = log.level
- log.setLevel("INFO")
- self.bus = dbus.SystemBus()
- mandos_dbus_objc = self.bus.get_object(
- self.busname, "/", follow_name_owner_changes=True)
- self.mandos_serv = dbus.Interface(
- mandos_dbus_objc, dbus_interface=server_interface)
- try:
- mandos_clients = (self.mandos_serv
- .GetAllClientsWithProperties())
- if not mandos_clients:
- log.warning("Note: Server has no clients.")
- except dbus.exceptions.DBusException:
- log.warning("Note: No Mandos server running.")
- mandos_clients = dbus.Dictionary()
-
- (self.mandos_serv
- .connect_to_signal("InterfacesRemoved",
- self.find_and_remove_client,
- dbus_interface=dbus.OBJECT_MANAGER_IFACE,
- byte_arrays=True))
- (self.mandos_serv
- .connect_to_signal("InterfacesAdded",
- self.add_new_client,
- dbus_interface=dbus.OBJECT_MANAGER_IFACE,
- byte_arrays=True))
- (self.mandos_serv
- .connect_to_signal("ClientNotFound",
- self.client_not_found,
- dbus_interface=server_interface,
- byte_arrays=True))
- for path, client in mandos_clients.items():
- client_proxy_object = self.bus.get_object(self.busname,
- path)
- self.add_client(MandosClientWidget(
- server_proxy_object=self.mandos_serv,
- proxy_object=client_proxy_object,
- properties=client,
- update_hook=self.refresh,
- delete_hook=self.remove_client),
- path=path)
-
- self.refresh()
- self._input_callback_tag = (
- GLib.io_add_watch(
- GLib.IOChannel.unix_new(sys.stdin.fileno()),
- GLib.PRIORITY_DEFAULT, GLib.IO_IN,
- glib_safely(self.process_input)))
- self.main_loop.run()
- # Main loop has finished, we should close everything now
- GLib.source_remove(self._input_callback_tag)
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", BytesWarning)
- self.screen.stop()
-
- def stop(self):
- self.main_loop.quit()
- log.removeHandler(self.loghandler)
- log.propagate = self.orig_log_propagate
-
- def process_input(self, source, condition):
- keys = self.screen.get_input()
- translations = {"ctrl n": "down", # Emacs
- "ctrl p": "up", # Emacs
- "ctrl v": "page down", # Emacs
- "meta v": "page up", # Emacs
- " ": "page down", # less
- "f": "page down", # less
- "b": "page up", # less
- "j": "down", # vi
- "k": "up", # vi
- }
- for key in keys:
- try:
- key = translations[key]
- except KeyError: # :-)
- pass
-
- if key == "q" or key == "Q":
- self.stop()
- break
- elif key == "window resize":
- self.size = self.screen.get_cols_rows()
- self.refresh()
- elif key == "ctrl l":
- self.screen.clear()
- self.refresh()
- elif key == "l" or key == "D":
- self.toggle_log_display()
- self.refresh()
- elif key == "w" or key == "i":
- self.change_log_display()
- self.refresh()
- elif key == "?" or key == "f1" or key == "esc":
- if not self.log_visible:
- self.log_visible = True
- self.rebuild()
- self.add_log_line(("bold",
- " ".join(("q: Quit",
- "?: Help",
- "l: Log window toggle",
- "TAB: Switch window",
- "w: Wrap (log lines)",
- "v: Toggle verbose log",
- ))))
- self.add_log_line(("bold",
- " ".join(("Clients:",
- "+: Enable",
- "-: Disable",
- "R: Remove",
- "s: Start new checker",
- "S: Stop checker",
- "C: Checker OK",
- "a: Approve",
- "d: Deny",
- ))))
- self.refresh()
- elif key == "tab":
- if self.topwidget.get_focus() is self.logbox:
- self.topwidget.set_focus(0)
- else:
- self.topwidget.set_focus(self.logbox)
- self.refresh()
- elif key == "v":
- if log.level < logging.INFO:
- log.setLevel(logging.INFO)
- log.info("Verbose mode: Off")
- else:
- log.setLevel(logging.NOTSET)
- log.info("Verbose mode: On")
- # elif (key == "end" or key == "meta >" or key == "G"
- # or key == ">"):
- # pass # xxx end-of-buffer
- # elif (key == "home" or key == "meta <" or key == "g"
- # or key == "<"):
- # pass # xxx beginning-of-buffer
- # elif key == "ctrl e" or key == "$":
- # pass # xxx move-end-of-line
- # elif key == "ctrl a" or key == "^":
- # pass # xxx move-beginning-of-line
- # elif key == "ctrl b" or key == "meta (" or key == "h":
- # pass # xxx left
- # elif key == "ctrl f" or key == "meta )" or key == "l":
- # pass # xxx right
- # elif key == "a":
- # pass # scroll up log
- # elif key == "z":
- # pass # scroll down log
- elif self.topwidget.selectable():
- self.topwidget.keypress(self.size, key)
- self.refresh()
- return True
-
-
-class UILogHandler(logging.Handler):
- def __init__(self, ui, *args, **kwargs):
- self.ui = ui
- super(UILogHandler, self).__init__(*args, **kwargs)
- self.setFormatter(
- logging.Formatter("%(asctime)s: %(message)s"))
- def emit(self, record):
- msg = self.format(record)
- if record.levelno > logging.INFO:
- msg = ("bold", msg)
- self.ui.add_log_line(msg)
-
-
-ui = UserInterface()
-try:
- ui.run()
-except KeyboardInterrupt:
- with warnings.catch_warnings():
- warnings.filterwarnings("ignore", "", BytesWarning)
- ui.screen.stop()
-except Exception:
- with warnings.catch_warnings():
- warnings.filterwarnings("ignore", "", BytesWarning)
- ui.screen.stop()
- raise
=== removed file 'mandos-monitor.xml'
--- mandos-monitor.xml 2019-02-10 04:20:26 +0000
+++ mandos-monitor.xml 1970-01-01 00:00:00 +0000
@@ -1,249 +0,0 @@
-
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@recompile.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@recompile.se
-
-
-
-
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8
-
-
-
- &COMMANDNAME;
-
- Text-based GUI to control the Mandos server.
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is an interactive program to
- monitor and control the operations of the Mandos server (see
- mandos8).
-
-
-
-
- PURPOSE
-
- The purpose of this is to enable remote and unattended
- rebooting of client host computer with an
- encrypted root file system. See for details.
-
-
-
-
- OVERVIEW
-
-
- This program is used to monitor and control the Mandos server.
- In particular, it can be used to approve Mandos clients which
- have been configured to require approval. It also shows all
- significant events reported by the Mandos server.
-
-
-
-
- KEYS
-
- This program is used to monitor and control the Mandos server.
- In particular, it can be used to approve Mandos clients which
- have been configured to require approval. It also shows all
- significant events reported by the Mandos server.
-
-
- Global Keys
-
- Keys
- Function
-
-
-
- q, Q
- Quit
-
-
- Ctrl-L
- Redraw screen
-
-
- ?, F1
- Show help
-
-
- l, D
- Toggle log window
-
-
- TAB
- Switch window
-
-
- w, i
- Toggle log window line wrap
-
-
- v
- Toggle verbose logging
-
-
- Up, Ctrl-P, k
- Move up a line
-
-
- Down, Ctrl-N, j
- Move down a line
-
-
- PageUp, Meta-V, b
- Move up a page
-
-
- PageDown, Ctrl-V, SPACE, f
- Move down a page
-
-
-
- Client List Keys
-
- Keys
- Function
-
-
-
- +
- Enable client
-
-
- -
- Disable client
-
-
- a
- Approve client
-
-
- d
- Deny client
-
-
- R, _, Ctrl-K
- Remove client
-
-
- s
- Start checker for client
-
-
- S
- Stop checker for client
-
-
- C
- Force a successful check for this client.
-
-
-
-
-
- BUGS
-
- This program can currently only be used to monitor and control a
- Mandos server with the default D-Bus bus name of
- se.recompile.Mandos
.
-
-
-
-
-
- EXAMPLE
-
-
- This program takes no options:
-
-
- &COMMANDNAME;
-
-
-
-
-
- SECURITY
-
- This program must be permitted to access the Mandos server via
- the D-Bus interface. This normally requires the root user, but
- could be configured otherwise by reconfiguring the D-Bus server.
-
-
-
-
- SEE ALSO
-
- intro
- 8mandos,
- mandos
- 8,
- mandos-ctl
- 8
-
-
-
-
-
-
-
-
-
=== removed file 'mandos-options.xml'
--- mandos-options.xml 2019-07-25 21:42:40 +0000
+++ mandos-options.xml 1970-01-01 00:00:00 +0000
@@ -1,125 +0,0 @@
-
-
-
-
-
-
-
-
-
- If this is specified, the server will only announce the service
- and listen to requests on the specified network interface.
- Default is to use all available interfaces. Note: a failure to bind to the specified
- interface is not considered critical, and the server will not
- exit, but instead continue normally.
-
-
-
- If this option is used, the server will only listen to the
- specified IPv6 address. If a link-local address is specified, an
- interface should be set, since a link-local address is only valid
- on a single interface. By default, the server will listen to all
- available addresses. If set, this must normally be an IPv6
- address; an IPv4 address can only be specified using IPv4-mapped
- IPv6 address syntax: ::FFFF:192.0.2.3
. (Only if IPv6 usage is
- disabled (see below) must this be an IPv4
- address.)
-
-
-
- If this option is used, the server will bind to that port. By
- default, the server will listen to an arbitrary port given by the
- operating system.
-
-
-
- If the server is run in debug mode, it will run in the foreground
- and print a lot of debugging information. The default is to
- not run in debug mode.
-
-
-
- GnuTLS priority string for the TLS handshake.
- The default is
-
- SECURE128:!CTYPE-X.509:+CTYPE-RAWPK:!RSA:!VERS-ALL:+VERS-TLS1.3:%PROFILE_ULTRA
- when using raw public keys in TLS, and
- SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP:!RSA:+SIGN-DSA-SHA256
- when using OpenPGP keys in TLS,. See gnutls_priority_init
- 3 for the syntax.
- Warning: changing this may make the
- TLS handshake fail, making server-client
- communication impossible. Changing this option may also make the
- network traffic decryptable by an attacker.
-
-
-
- Zeroconf service name. The default is
- Mandos
. This only needs to be
- changed if for some reason is would be necessary to run more than
- one server on the same host. This would not
- normally be useful. If there are name collisions on the same
- network, the newer server will automatically
- rename itself to Mandos #2
, and
- so on; therefore, this option is not needed in that case.
-
-
-
- This option controls whether the server will provide a D-Bus
- system bus interface. The default is to provide such an
- interface.
-
-
-
- This option controls whether the server will use IPv6 sockets and
- addresses. The default is to use IPv6. This option should
- never normally be turned off, even in
- IPv4-only environments. This is because
- mandos-client
- 8mandos will normally use
- IPv6 link-local addresses, and will not be able to find or connect
- to the server if this option is turned off. Only
- advanced users should consider changing this option.
-
-
-
- This option controls whether the server will restore its state
- from the last time it ran. Default is to restore last state.
-
-
-
- Directory to save (and restore) state in. Default is
- /var/lib/mandos
.
-
-
-
- If this option is used, the server will not create a new network
- socket, but will instead use the supplied file descriptor. By
- default, the server will create a new network socket.
-
-
-
- This option will make the server run in the foreground and not
- write a PID file. The default is to not run
- in the foreground, except in mode, which
- implies this option.
-
-
-
- This option controls whether the server will announce its
- existence using Zeroconf. Default is to use Zeroconf. If
- Zeroconf is not used, a number or a
- is required.
-
-
-
=== removed file 'mandos-to-cryptroot-unlock'
--- mandos-to-cryptroot-unlock 2019-07-24 11:02:24 +0000
+++ mandos-to-cryptroot-unlock 1970-01-01 00:00:00 +0000
@@ -1,82 +0,0 @@
-#!/bin/sh
-#
-# Script to get password from plugin-runner to cryptroot-unlock
-#
-# Copyright © 2018 Teddy Hogeborn
-# Copyright © 2018 Björn Påhlsson
-#
-# This file is part of Mandos.
-#
-# Mandos 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.
-#
-# Mandos 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 Mandos. If not, see .
-#
-# Contact the authors at .
-
-# This script is made to run in the initramfs, and must not be run in
-# the normal system environment.
-
-# Temporary file for the password
-passfile=$(mktemp -p /run -t mandos.XXXXXX)
-trap "rm -f -- $passfile 2>/dev/null" EXIT
-
-# Disable the plugins which conflict with "askpass" as distributed by
-# cryptsetup.
-cat <<-EOF >>/conf/conf.d/mandos/plugin-runner.conf
-
- --disable=askpass-fifo
- --disable=password-prompt
- --disable=plymouth
-EOF
-
-# In case a password is retrieved by other means than by plugin-runner
-# (such as typing it on the console into the prompt given by the
-# "askpass" program), this dummy plugin will be made to exit
-# successfully, thereby forcing plugin-runner to stop all its plugins
-# and also exit itself.
-cat <<-EOF > /lib/mandos/plugins.d/dummy
- #!/bin/sh
-
- while [ -e /run/mandos-keep-running ]; do
- sleep 1
- done
-
- # exit successfully to force plugin-runner to finish
- exit 0
-EOF
-chmod u=rwx,go=rx /lib/mandos/plugins.d/dummy
-
-# This file is the flag which keeps the dummy plugin running
-touch /run/mandos-keep-running
-
-# Keep running plugin-runner and trying any password, until either a
-# password is accepted by cryptroot-unlock, or plugin-runner fails, or
-# the file /run/mandos-keep-running has been removed.
-while command -v cryptroot-unlock >/dev/null 2>&1; do
- /lib/mandos/plugin-runner > "$passfile" &
- echo $! > /run/mandos-plugin-runner.pid
- wait %% || break
-
- # Try this password ten times (or ten seconds)
- for loop in 1 2 3 4 5 6 7 8 9 10; do
- if [ -e /run/mandos-keep-running ]; then
- cryptroot-unlock < "$passfile" >/dev/null 2>&1 && break 2
- sleep 1
- else
- break 2
- fi
- done
-done
-
-exec >/dev/null 2>&1
-
-rm -f /run/mandos-plugin-runner.pid /run/mandos-keep-running
=== removed file 'mandos.conf.xml'
--- mandos.conf.xml 2019-06-20 18:54:10 +0000
+++ mandos.conf.xml 1970-01-01 00:00:00 +0000
@@ -1,308 +0,0 @@
-
-
-/etc/mandos/mandos.conf">
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@recompile.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@recompile.se
-
-
-
-
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &CONFNAME;
- 5
-
-
-
- &CONFNAME;
-
- Configuration file for the Mandos server
-
-
-
-
- &CONFPATH;
-
-
-
- DESCRIPTION
-
- The file &CONFPATH; is a simple configuration file for
- mandos
- 8, and is read by it at
- startup. The configuration file starts with [DEFAULT]
on a line by itself, followed by
- any number of option=value
entries,
- with continuations in the style of RFC 822. option: value
is also accepted. Note that
- leading whitespace is removed from values. Lines beginning with
- #
or ;
are ignored and may be used
- to provide comments.
-
-
-
-
- OPTIONS
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- FILES
-
- The file described here is &CONFPATH;
-
-
-
-
- BUGS
-
- The [DEFAULT] is necessary because the Python
- built-in module ConfigParser
- requires it.
-
-
-
-
-
- EXAMPLE
-
-
- No options are actually required:
-
-
-[DEFAULT]
-
-
-
-
- An example using all the options:
-
-
-[DEFAULT]
-# A configuration example
-interface = enp1s0
-address = fe80::aede:48ff:fe71:f6f2
-port = 1025
-debug = True
-priority = SECURE128:!CTYPE-X.509:+CTYPE-RAWPK:!RSA:!VERS-ALL:+VERS-TLS1.3:%PROFILE_ULTRA
-servicename = Daena
-use_dbus = False
-use_ipv6 = True
-restore = True
-statedir = /var/lib/mandos
-
-
-
-
-
- SEE ALSO
-
- intro
- 8mandos,
- gnutls_priority_init3,
- mandos
- 8,
- mandos-clients.conf
- 5
-
-
-
-
-
- RFC 4291: IP Version 6 Addressing
- Architecture
-
-
-
-
- Section 2.2: Text Representation of
- Addresses
-
-
-
- Section 2.5.5.2: IPv4-Mapped IPv6
- Address
-
-
-
- Section 2.5.6, Link-Local IPv6 Unicast
- Addresses
-
-
- The clients use IPv6 link-local addresses, which are
- immediately usable since a link-local addresses is
- automatically assigned to a network interface when it
- is brought up.
-
-
-
-
-
-
-
-
- Zeroconf
-
-
-
- Zeroconf is the network protocol standard used by clients
- for finding the Mandos server on the local network.
-
-
-
-
-
-
-
-
-
-
-
=== removed file 'mandos.lsm'
--- mandos.lsm 2019-09-03 19:06:41 +0000
+++ mandos.lsm 1970-01-01 00:00:00 +0000
@@ -1,23 +0,0 @@
-Begin4
-Title: Mandos
-Version: 1.8.9
-Entered-date: 2019-09-03
-Description: The Mandos system allows computers to have encrypted
- root file systems and at the same time be capable of
- remote and/or unattended reboots.
-Keywords: boot, encryption, luks, cryptsetup, network, openpgp,
- tls, dm-crypt
-Author: teddy@recompile.se (Teddy Hogeborn),
- belorn@recompile.se (Björn Påhlsson)
-Maintained-by: teddy@recompile.se (Teddy Hogeborn),
- belorn@recompile.se (Björn Påhlsson)
-Primary-site: https://www.recompile.se/mandos
- 234K mandos_1.8.9.orig.tar.gz
-Alternate-site: ftp://ftp.recompile.se/pub/mandos
- 234K mandos_1.8.9.orig.tar.gz
-Platforms: Requires GCC, GNU libC, Avahi, GnuPG, Python 2.7, and
- various other libraries. While made for Debian
- GNU/Linux, it is probably portable to other
- distributions, but not other Unixes.
-Copying-policy: GNU General Public License version 3.0 or later
-End
=== removed file 'mandos.service'
--- mandos.service 2017-08-20 14:14:14 +0000
+++ mandos.service 1970-01-01 00:00:00 +0000
@@ -1,35 +0,0 @@
-[Unit]
-Description=Server of encrypted passwords to Mandos clients
-Documentation=man:intro(8mandos) man:mandos(8)
-## If the server is configured to listen to a specific IP or network
-## interface, it may be necessary to change "network.target" to
-## "network-online.target".
-After=network.target
-## If the server is configured to not use ZeroConf, these two lines
-## become unnecessary and should be removed or commented out.
-After=avahi-daemon.service
-Requisite=avahi-daemon.service
-
-[Service]
-## If the server's D-Bus interface is disabled, the "BusName" setting
-## should be removed or commented out.
-BusName=se.recompile.Mandos
-ExecStart=/usr/sbin/mandos --foreground
-Restart=always
-KillMode=mixed
-## Using socket activation won't work, because systemd always does
-## bind() on the socket, and also won't announce the ZeroConf service.
-#ExecStart=/usr/sbin/mandos --foreground --socket=0
-#StandardInput=socket
-# Restrict what the Mandos daemon can do. Note that this also affects
-# "checker" programs!
-PrivateTmp=yes
-PrivateDevices=yes
-ProtectSystem=full
-ProtectHome=yes
-CapabilityBoundingSet=CAP_KILL CAP_SETGID CAP_SETUID CAP_DAC_OVERRIDE CAP_NET_RAW
-ProtectKernelTunables=yes
-ProtectControlGroups=yes
-
-[Install]
-WantedBy=multi-user.target
=== removed file 'mandos.xml'
--- mandos.xml 2019-07-24 06:16:09 +0000
+++ mandos.xml 1970-01-01 00:00:00 +0000
@@ -1,806 +0,0 @@
-
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@recompile.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@recompile.se
-
-
-
-
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8
-
-
-
- &COMMANDNAME;
-
- Gives encrypted passwords to authenticated Mandos clients
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
- &COMMANDNAME;
-
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is a server daemon which
- handles incoming request for passwords for a pre-defined list of
- client host computers. For an introduction, see
- intro
- 8mandos. The Mandos server
- uses Zeroconf to announce itself on the local network, and uses
- TLS to communicate securely with and to authenticate the
- clients. The Mandos server uses IPv6 to allow Mandos clients to
- use IPv6 link-local addresses, since the clients will probably
- not have any other addresses configured (see ). Any authenticated client is then given
- the stored pre-encrypted password for that specific client.
-
-
-
-
- PURPOSE
-
- The purpose of this is to enable remote and unattended
- rebooting of client host computer with an
- encrypted root file system. See for details.
-
-
-
-
- OPTIONS
-
-
-
-
-
-
- Show a help message and exit
-
-
-
-
-
-
- NAME
-
- NAME
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Run the server’s self-tests. This includes any unit
- tests, etc.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Set the debugging log level.
- LEVEL is a string, one of
- CRITICAL
,
- ERROR
,
- WARNING
,
- INFO
, or
- DEBUG
, in order of
- increasing verbosity. The default level is
- WARNING
.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Directory to search for configuration files. Default is
- /etc/mandos
. See
- mandos.conf
- 5 and
- mandos-clients.conf
- 5.
-
-
-
-
-
-
-
-
- Prints the program version and exit.
-
-
-
-
-
-
-
-
-
- See also .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- See also .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- OVERVIEW
-
-
- This program is the server part. It is a normal server program
- and will run in a normal system environment, not in an initial
- RAM disk environment.
-
-
-
-
- NETWORK PROTOCOL
-
- The Mandos server announces itself as a Zeroconf service of type
- _mandos._tcp
. The Mandos
- client connects to the announced address and port, and sends a
- line of text where the first whitespace-separated field is the
- protocol version, which currently is
- 1
. The client and server then
- start a TLS protocol handshake with a slight quirk: the Mandos
- server program acts as a TLS client
while the
- connecting Mandos client acts as a TLS server
.
- The Mandos client must supply a TLS public key, and the key ID
- of this public key is used by the Mandos server to look up (in a
- list read from clients.conf at start time)
- which binary blob to give the client. No other authentication
- or authorization is done by the server.
-
-
- Mandos Protocol (Version 1)
-
- Mandos Client
- Direction
- Mandos Server
-
-
-
- Connect
- ->
-
-
- 1\r\n
- ->
-
-
- TLS handshake as TLS server
-
- <->
- TLS handshake as TLS client
-
-
-
- Public key (part of TLS handshake)
- ->
-
-
-
- <-
- Binary blob (client will assume OpenPGP data)
-
-
-
- <-
- Close
-
-
-
-
-
- CHECKING
-
- The server will, by default, continually check that the clients
- are still up. If a client has not been confirmed as being up
- for some time, the client is assumed to be compromised and is no
- longer eligible to receive the encrypted password. (Manual
- intervention is required to re-enable a client.) The timeout,
- extended timeout, checker program, and interval between checks
- can be configured both globally and per client; see
- mandos-clients.conf
- 5.
-
-
-
-
- APPROVAL
-
- The server can be configured to require manual approval for a
- client before it is sent its secret. The delay to wait for such
- approval and the default action (approve or deny) can be
- configured both globally and per client; see
- mandos-clients.conf
- 5. By default all clients
- will be approved immediately without delay.
-
-
- This can be used to deny a client its secret if not manually
- approved within a specified time. It can also be used to make
- the server delay before giving a client its secret, allowing
- optional manual denying of this specific client.
-
-
-
-
-
- LOGGING
-
- The server will send log message with various severity levels to
- /dev/log. With the
- option, it will log even more messages,
- and also show them on the console.
-
-
-
-
- PERSISTENT STATE
-
- Client settings, initially read from
- clients.conf, are persistent across
- restarts, and run-time changes will override settings in
- clients.conf. However, if a setting is
- changed (or a client added, or removed) in
- clients.conf, this will take precedence.
-
-
-
-
- D-BUS INTERFACE
-
- The server will by default provide a D-Bus system bus interface.
- This interface will only be accessible by the root user or a
- Mandos-specific user, if such a user exists. For documentation
- of the D-Bus API, see the file DBUS-API.
-
-
-
-
- EXIT STATUS
-
- The server will exit with a non-zero exit status only when a
- critical error is encountered.
-
-
-
-
- ENVIRONMENT
-
-
- PATH
-
-
- To start the configured checker (see ), the server uses
- /bin/sh, which in turn uses
- PATH to search for matching commands if
- an absolute path is not given. See
- sh1
- .
-
-
-
-
-
-
-
- FILES
-
- Use the option to change where
- &COMMANDNAME; looks for its configurations
- files. The default file names are listed here.
-
-
-
- /etc/mandos/mandos.conf
-
-
- Server-global settings. See
- mandos.conf
- 5 for details.
-
-
-
-
- /etc/mandos/clients.conf
-
-
- List of clients and client-specific settings. See
- mandos-clients.conf
- 5 for details.
-
-
-
-
- /run/mandos.pid
-
-
- The file containing the process id of the
- &COMMANDNAME; process started last.
- Note: If the /run directory does not
- exist, /var/run/mandos.pid will be
- used instead.
-
-
-
-
- /var/lib/mandos
-
-
- Directory where persistent state will be saved. Change
- this with the option. See
- also the option.
-
-
-
-
- /dev/log
-
-
- The Unix domain socket to where local syslog messages are
- sent.
-
-
-
-
- /bin/sh
-
-
- This is used to start the configured checker command for
- each client. See
- mandos-clients.conf
- 5 for details.
-
-
-
-
-
-
-
- BUGS
-
- This server might, on especially fatal errors, emit a Python
- backtrace. This could be considered a feature.
-
-
- There is no fine-grained control over logging and debug output.
-
-
-
-
-
- EXAMPLE
-
-
- Normal invocation needs no options:
-
-
- &COMMANDNAME;
-
-
-
-
- Run the server in debug mode, read configuration files from
- the ~/mandos directory,
- and use the Zeroconf service name Test
to not
- collide with any other official Mandos server on this host:
-
-
-
-
-&COMMANDNAME; --debug --configdir ~/mandos --servicename Test
-
-
-
-
-
- Run the server normally, but only listen to one interface and
- only on the link-local address on that interface:
-
-
-
-
-&COMMANDNAME; --interface eth7 --address fe80::aede:48ff:fe71:f6f2
-
-
-
-
-
-
- SECURITY
-
- SERVER
-
- Running this &COMMANDNAME; server program
- should not in itself present any security risk to the host
- computer running it. The program switches to a non-root user
- soon after startup.
-
-
-
- CLIENTS
-
- The server only gives out its stored data to clients which
- does have the correct key ID of the stored key ID. This is
- guaranteed by the fact that the client sends its public key in
- the TLS handshake; this ensures it to be genuine. The server
- computes the key ID of the key itself and looks up the key ID
- in its list of clients. The clients.conf
- file (see
- mandos-clients.conf
- 5)
- must be made non-readable by anyone
- except the user starting the server (usually root).
-
-
- As detailed in , the status of all
- client computers will continually be checked and be assumed
- compromised if they are gone for too long.
-
-
- For more details on client-side security, see
- mandos-client
- 8mandos.
-
-
-
-
-
- SEE ALSO
-
- intro
- 8mandos,
- mandos-clients.conf
- 5,
- mandos.conf
- 5,
- mandos-client
- 8mandos,
- sh
- 1
-
-
-
-
- Zeroconf
-
-
-
- Zeroconf is the network protocol standard used by clients
- for finding this Mandos server on the local network.
-
-
-
-
-
- Avahi
-
-
-
- Avahi is the library this server calls to implement
- Zeroconf service announcements.
-
-
-
-
-
- GnuTLS
-
-
-
- GnuTLS is the library this server uses to implement TLS for
- communicating securely with the client, and at the same time
- confidently get the client’s public key.
-
-
-
-
-
- RFC 4291: IP Version 6 Addressing
- Architecture
-
-
-
-
- Section 2.2: Text Representation of
- Addresses
-
-
-
- Section 2.5.5.2: IPv4-Mapped IPv6
- Address
-
-
-
- Section 2.5.6, Link-Local IPv6 Unicast
- Addresses
-
-
- The clients use IPv6 link-local addresses, which are
- immediately usable since a link-local addresses is
- automatically assigned to a network interfaces when it
- is brought up.
-
-
-
-
-
-
-
-
- RFC 5246: The Transport Layer Security (TLS)
- Protocol Version 1.2
-
-
-
- TLS 1.2 is the protocol implemented by GnuTLS.
-
-
-
-
-
- RFC 4880: OpenPGP Message Format
-
-
-
- The data sent to clients is binary encrypted OpenPGP data.
-
-
-
-
-
- RFC 7250: Using Raw Public Keys in Transport
- Layer Security (TLS) and Datagram Transport Layer Security
- (DTLS)
-
-
-
- This is implemented by GnuTLS version 3.6.6 and is, if
- present, used by this server so that raw public keys can be
- used.
-
-
-
-
-
- RFC 6091: Using OpenPGP Keys for Transport Layer
- Security (TLS) Authentication
-
-
-
- This is implemented by GnuTLS before version 3.6.0 and is,
- if present, used by this server so that OpenPGP keys can be
- used.
-
-
-
-
-
-
-
-
-
-
-
=== removed directory 'network-hooks.d'
=== removed file 'network-hooks.d/bridge'
--- network-hooks.d/bridge 2018-02-08 10:23:55 +0000
+++ network-hooks.d/bridge 1970-01-01 00:00:00 +0000
@@ -1,93 +0,0 @@
-#!/bin/sh
-#
-# This is an example of a Mandos client network hook. This hook
-# brings up a bridge interface as specified in a separate
-# configuration file. To be used, this file and any needed
-# configuration file(s) should be copied into the
-# /etc/mandos/network-hooks.d directory.
-#
-# Copyright © 2012-2018 Teddy Hogeborn
-# Copyright © 2012-2018 Björn Påhlsson
-#
-# 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. This file is offered as-is,
-# without any warranty.
-
-set -e
-
-CONFIG="$MANDOSNETHOOKDIR/bridge.conf"
-
-addrtoif(){
- grep -liFe "$1" /sys/class/net/*/address \
- | sed -e 's,.*/\([^/]*\)/[^/]*,\1,' -e "/^${BRIDGE}\$/d"
-}
-
-# Read config file, which must set "BRIDGE", "PORT_ADDRESSES", and
-# optionally "IPADDRS" and "ROUTES".
-if [ -e "$CONFIG" ]; then
- . "$CONFIG"
-fi
-
-if [ -z "$BRIDGE" ] || [ -z "$PORT_ADDRESSES" ]; then
- exit
-fi
-
-if [ -n "$DEVICE" ]; then
- case "$DEVICE" in
- *,"$BRIDGE"|*,"$BRIDGE",*|"$BRIDGE",*|"$BRIDGE") :;;
- *) exit;;
- esac
-fi
-
-brctl="/sbin/brctl"
-for b in "$brctl" /usr/sbin/brctl; do
- if [ -e "$b" ]; then
- brctl="$b"
- break
- fi
-done
-
-do_start(){
- "$brctl" addbr "$BRIDGE"
- for address in $PORT_ADDRESSES; do
- interface=`addrtoif "$address"`
- "$brctl" addif "$BRIDGE" "$interface"
- ip link set dev "$interface" up
- done
- ip link set dev "$BRIDGE" up
- sleep "${DELAY%%.*}"
- if [ -n "$IPADDRS" ]; then
- for ipaddr in $IPADDRS; do
- ip addr add "$ipaddr" dev "$BRIDGE"
- done
- fi
- if [ -n "$ROUTES" ]; then
- for route in $ROUTES; do
- ip route add "$route" dev "$BRIDGE"
- done
- fi
-}
-
-do_stop(){
- ip link set dev "$BRIDGE" down
- for address in $PORT_ADDRESSES; do
- interface=`addrtoif "$address"`
- ip link set dev "$interface" down
- "$brctl" delif "$BRIDGE" "$interface"
- done
- "$brctl" delbr "$BRIDGE"
-}
-
-case "${MODE:-$1}" in
- start|stop)
- do_"${MODE:-$1}"
- ;;
- files)
- echo /bin/ip
- echo "$brctl"
- ;;
- modules)
- echo bridge
- ;;
-esac
=== removed file 'network-hooks.d/bridge.conf'
--- network-hooks.d/bridge.conf 2011-12-31 13:25:58 +0000
+++ network-hooks.d/bridge.conf 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
-## Required
-
-#BRIDGE=br0
-
-#PORT_ADDRESSES="00:11:22:33:44:55 11:22:33:44:55:66"
-
-## Optional
-
-#IPADDRS="192.0.2.3/24 2001:DB8::aede:48ff:fe71:f6f2/32"
-
-#ROUTES="192.0.2.0/24 2001:DB8::/32"
=== removed file 'network-hooks.d/openvpn'
--- network-hooks.d/openvpn 2018-02-08 10:23:55 +0000
+++ network-hooks.d/openvpn 1970-01-01 00:00:00 +0000
@@ -1,66 +0,0 @@
-#!/bin/sh
-#
-# This is an example of a Mandos client network hook. This hook
-# brings up an OpenVPN interface as specified in a separate
-# configuration file. To be used, this file and any needed
-# configuration file(s) should be copied into the
-# /etc/mandos/network-hooks.d directory.
-#
-# Copyright © 2012-2018 Teddy Hogeborn
-# Copyright © 2012-2018 Björn Påhlsson
-#
-# 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. This file is offered as-is,
-# without any warranty.
-
-set -e
-
-CONFIG="openvpn.conf"
-
-# Extract the "dev" setting from the config file
-VPNDEVICE=`sed -n -e 's/[[:space:]]#.*//' \
- -e 's/^[[:space:]]*dev[[:space:]]\+//p' \
- "$MANDOSNETHOOKDIR/$CONFIG"`
-
-PIDFILE=/run/openvpn-mandos.pid
-
-# Exit if no device set in config
-if [ -z "$VPNDEVICE" ]; then
- exit
-fi
-
-# Exit if DEVICE is set and it doesn't match the VPN interface
-if [ -n "$DEVICE" ]; then
- case "$DEVICE" in
- *,"$VPNDEVICE"*|"$VPNDEVICE"*) :;;
- *) exit;;
- esac
-fi
-
-openvpn=/usr/sbin/openvpn
-
-do_start(){
- "$openvpn" --cd "$MANDOSNETHOOKDIR" --daemon 'openvpn(Mandos)' \
- --writepid "$PIDFILE" --config "$CONFIG"
- sleep "$DELAY"
-}
-
-do_stop(){
- PID="`cat \"$PIDFILE\"`"
- if [ "$PID" -gt 0 ]; then
- kill "$PID"
- fi
-}
-
-case "${MODE:-$1}" in
- start|stop)
- do_"${MODE:-$1}"
- ;;
- files)
- echo "$openvpn"
- ;;
- modules)
- echo tun
- ;;
-esac
=== removed file 'network-hooks.d/openvpn.conf'
--- network-hooks.d/openvpn.conf 2011-12-02 16:52:50 +0000
+++ network-hooks.d/openvpn.conf 1970-01-01 00:00:00 +0000
@@ -1,19 +0,0 @@
-# Sample OpenVPN configuration file
-# Uncomment and change - see openvpn(8)
-
-# Network device.
-#dev tun
-
-# Our remote peer
-#remote 192.0.2.3
-#float 192.0.2.3
-#port 1194
-
-# VPN endpoints
-#ifconfig 10.1.0.1 10.1.0.2
-
-# A pre-shared static key
-#secret openvpn.key
-
-# Cipher
-#cipher AES-128-CBC
=== removed file 'network-hooks.d/wireless'
--- network-hooks.d/wireless 2018-02-08 10:23:55 +0000
+++ network-hooks.d/wireless 1970-01-01 00:00:00 +0000
@@ -1,165 +0,0 @@
-#!/bin/sh
-#
-# This is an example of a Mandos client network hook. This hook
-# brings up a wireless interface as specified in a separate
-# configuration file. To be used, this file and any needed
-# configuration file(s) should be copied into the
-# /etc/mandos/network-hooks.d directory.
-#
-# Copyright © 2012-2018 Teddy Hogeborn
-# Copyright © 2012-2018 Björn Påhlsson
-#
-# 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. This file is offered as-is,
-# without any warranty.
-
-set -e
-
-RUNDIR="/run"
-CTRL="$RUNDIR/wpa_supplicant-global"
-CTRLDIR="$RUNDIR/wpa_supplicant"
-PIDFILE="$RUNDIR/wpa_supplicant-mandos.pid"
-
-CONFIG="$MANDOSNETHOOKDIR/wireless.conf"
-
-addrtoif(){
- grep -liFe "$1" /sys/class/net/*/address \
- | sed -e 's,.*/\([^/]*\)/[^/]*,\1,'
-}
-
-# Read config file
-if [ -e "$CONFIG" ]; then
- . "$CONFIG"
-else
- exit
-fi
-
-ifkeys=`sed -n -e 's/^ADDRESS_\([^=]*\)=.*/\1/p' "$CONFIG" | sort -u`
-
-# Exit if DEVICE is set and is not any of the wireless interfaces
-if [ -n "$DEVICE" ]; then
- while :; do
- for KEY in $ifkeys; do
- ADDRESS=`eval 'echo "$ADDRESS_'"$KEY"\"`
- INTERFACE=`addrtoif "$ADDRESS"`
-
- case "$DEVICE" in
- *,"$INTERFACE"|*,"$INTERFACE",*|"$INTERFACE",*|"$INTERFACE")
- break 2;;
- esac
- done
- exit
- done
-fi
-
-wpa_supplicant=/sbin/wpa_supplicant
-wpa_cli=/sbin/wpa_cli
-ip=/bin/ip
-
-# Used by the wpa_interface_* functions in the wireless.conf file
-wpa_cli_set(){
- case "$1" in
- ssid|psk) arg="\"$2\"" ;;
- *) arg="$2" ;;
- esac
- "$wpa_cli" -p "$CTRLDIR" -i "$INTERFACE" set_network "$NETWORK" \
- "$1" "$arg" 2>&1 | sed -e '/^OK$/d'
-}
-
-if [ $VERBOSITY -gt 0 ]; then
- WPAS_OPTIONS="-d $WPAS_OPTIONS"
-fi
-if [ -n "$PIDFILE" ]; then
- WPAS_OPTIONS="-P$PIDFILE $WPAS_OPTIONS"
-fi
-
-do_start(){
- mkdir -m u=rwx,go= -p "$CTRLDIR"
- "$wpa_supplicant" -B -g "$CTRL" -p "$CTRLDIR" $WPAS_OPTIONS
- for KEY in $ifkeys; do
- ADDRESS=`eval 'echo "$ADDRESS_'"$KEY"\"`
- INTERFACE=`addrtoif "$ADDRESS"`
- DRIVER=`eval 'echo "$WPA_DRIVER_'"$KEY"\"`
- IFDELAY=`eval 'echo "$DELAY_'"$KEY"\"`
- "$wpa_cli" -g "$CTRL" interface_add "$INTERFACE" "" \
- "${DRIVER:-wext}" "$CTRLDIR" > /dev/null \
- | sed -e '/^OK$/d'
- NETWORK=`"$wpa_cli" -p "$CTRLDIR" -i "$INTERFACE" add_network`
- eval wpa_interface_"$KEY"
- "$wpa_cli" -p "$CTRLDIR" -i "$INTERFACE" enable_network \
- "$NETWORK" | sed -e '/^OK$/d'
- sleep "${IFDELAY:-$DELAY}" &
- sleep=$!
- while :; do
- kill -0 $sleep 2>/dev/null || break
- STATE=`"$wpa_cli" -p "$CTRLDIR" -i "$INTERFACE" status \
- | sed -n -e 's/^wpa_state=//p'`
- if [ "$STATE" = COMPLETED ]; then
- while :; do
- kill -0 $sleep 2>/dev/null || break 2
- UP=`cat /sys/class/net/"$INTERFACE"/operstate`
- if [ "$UP" = up ]; then
- kill $sleep 2>/dev/null
- break 2
- fi
- sleep 1
- done
- fi
- sleep 1
- done &
- wait $sleep || :
- IPADDRS=`eval 'echo "$IPADDRS_'"$KEY"\"`
- if [ -n "$IPADDRS" ]; then
- if [ "$IPADDRS" = dhcp ]; then
- ipconfig -c dhcp -d "$INTERFACE" || :
- #dhclient "$INTERFACE"
- else
- for ipaddr in $IPADDRS; do
- "$ip" addr add "$ipaddr" dev "$INTERFACE"
- done
- fi
- fi
- ROUTES=`eval 'echo "$ROUTES_'"$KEY"\"`
- if [ -n "$ROUTES" ]; then
- for route in $ROUTES; do
- "$ip" route add "$route" dev "$INTERFACE"
- done
- fi
- done
-}
-
-do_stop(){
- "$wpa_cli" -g "$CTRL" terminate 2>&1 | sed -e '/^OK$/d'
- for KEY in $ifkeys; do
- ADDRESS=`eval 'echo "$ADDRESS_'"$KEY"\"`
- INTERFACE=`addrtoif "$ADDRESS"`
- "$ip" addr show scope global permanent dev "$INTERFACE" \
- | while read type addr rest; do
- case "$type" in
- inet|inet6)
- "$ip" addr del "$addr" dev "$INTERFACE"
- ;;
- esac
- done
- "$ip" link set dev "$INTERFACE" down
- done
-}
-
-case "${MODE:-$1}" in
- start|stop)
- do_"${MODE:-$1}"
- ;;
- files)
- echo "$wpa_supplicant"
- echo "$wpa_cli"
- echo "$ip"
- ;;
- modules)
- if [ "$IPADDRS" = dhcp ]; then
- echo af_packet
- fi
- sed -n -e 's/#.*$//' -e 's/[ ]*$//' \
- -e 's/^MODULE_[^=]\+=//p' "$CONFIG"
- ;;
-esac
=== removed file 'network-hooks.d/wireless.conf'
--- network-hooks.d/wireless.conf 2011-12-31 13:25:58 +0000
+++ network-hooks.d/wireless.conf 1970-01-01 00:00:00 +0000
@@ -1,23 +0,0 @@
-# Extra options for wpa_supplicant, if any
-#WPAS_OPTIONS=""
-
-# wlan0
-ADDRESS_0=00:11:22:33:44:55
-MODULE_0=ath9k
-#WPA_DRIVER_0=wext
-wpa_interface_0(){
- # Use this format to set simple things:
- wpa_cli_set ssid home
- wpa_cli_set psk "secret passphrase"
- # Use this format to do more complex things with wpa_cli:
- #"$wpa_cli" -p "$CTRLDIR" -i "$INTERFACE" bssid "$NETWORK" 00:11:22:33:44:55
- #"$wpa_cli" -g "$CTRL" ping
-}
-#DELAY_0=10
-IPADDRS_0=dhcp
-#IPADDRS_0="192.0.2.3/24 2001:DB8::aede:48ff:fe71:f6f2/32"
-#ROUTES_0="192.0.2.0/24 2001:DB8::/32"
-
-#ADDRESS_1=11:22:33:44:55:66
-#MODULE_1=...
-#...
=== removed file 'overview.xml'
--- overview.xml 2019-02-09 23:23:26 +0000
+++ overview.xml 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
-
-
-
- This is part of the Mandos system for allowing computers to have
- encrypted root file systems and at the same time be capable of
- remote and/or unattended reboots. The computers run a small client
- program in the initial RAM disk environment which
- will communicate with a server over a network. All network
- communication is encrypted using TLS. The
- clients are identified by the server using a TLS key; each client
- has one unique to it. The server sends the clients an encrypted
- password. The encrypted password is decrypted by the clients using
- a separate OpenPGP key, and the password is then used to unlock the
- root file system, whereupon the computers can continue booting
- normally.
-
=== renamed file 'plugin-runner.c' => 'plugbasedclient.c'
--- plugin-runner.c 2019-07-07 20:50:21 +0000
+++ plugbasedclient.c 2008-07-29 03:35:39 +0000
@@ -1,1331 +1,348 @@
-/* -*- coding: utf-8; mode: c; mode: orgtbl -*- */
+/* -*- coding: utf-8 -*- */
/*
* Mandos plugin runner - Run Mandos plugins
*
- * Copyright © 2008-2018 Teddy Hogeborn
- * Copyright © 2008-2018 Björn Påhlsson
- *
- * This file is part of Mandos.
- *
- * Mandos 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.
- *
- * Mandos is distributed in the hope that it will be useful, but
+ * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
+ *
+ * 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 Mandos. If not, see .
+ * along with this program. If not, see
+ * .
*
- * Contact the authors at .
+ * Contact the authors at .
*/
-#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), getline(),
- O_CLOEXEC, pipe2() */
-#include /* size_t, NULL */
-#include /* malloc(), exit(), EXIT_SUCCESS,
- realloc() */
-#include /* bool, true, false */
-#include /* fileno(), fprintf(),
- stderr, STDOUT_FILENO, fclose() */
-#include /* fstat(), struct stat, waitpid(),
- WIFEXITED(), WEXITSTATUS(), wait(),
- pid_t, uid_t, gid_t, getuid(),
- getgid() */
-#include /* fd_set, select(), FD_ZERO(),
- FD_SET(), FD_ISSET(), FD_CLR */
-#include /* wait(), waitpid(), WIFEXITED(),
- WEXITSTATUS(), WTERMSIG() */
-#include /* struct stat, fstat(), S_ISREG() */
-#include /* and, or, not */
-#include /* struct dirent, scandirat() */
-#include /* fcntl(), F_GETFD, F_SETFD,
- FD_CLOEXEC, write(), STDOUT_FILENO,
- struct stat, fstat(), close(),
- setgid(), setuid(), S_ISREG(),
- faccessat() pipe2(), fork(),
- _exit(), dup2(), fexecve(), read()
- */
-#include /* fcntl(), F_GETFD, F_SETFD,
- FD_CLOEXEC, openat(), scandirat(),
- pipe2() */
-#include /* strsep, strlen(), strsignal(),
- strcmp(), strncmp() */
-#include /* errno */
-#include