=== removed file '.bzrignore'
--- .bzrignore 2008-09-06 16:33:54 +0000
+++ .bzrignore 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
-*.5
-*.8
-*.8mandos
-plugin-runner
-plugins.d/password-prompt
-plugins.d/mandos-client
-confdir
-keydir
=== 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
-.
-
=== modified file 'Makefile'
--- Makefile 2008-09-07 01:20:43 +0000
+++ Makefile 2008-07-29 03:35:39 +0000
@@ -1,11 +1,4 @@
-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
+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
#
@@ -14,239 +7,25 @@
OPTIMIZE=-Os
LANGUAGE=-std=gnu99
-## Use these settings for a traditional /usr/local install
-# PREFIX=$(DESTDIR)/usr/local
-# CONFDIR=$(PREFIX)/lib/mandos
-# KEYDIR=$(PREFIX)/lib/mandos/keys
-# MANDIR=$(PREFIX)/man
-# INITRAMFSTOOLS=/etc/initramfs-tools
-
-PREFIX=$(DESTDIR)/usr
-CONFDIR=$(DESTDIR)/etc/mandos
-KEYDIR=$(DESTDIR)/etc/keys/mandos
-MANDIR=$(PREFIX)/share/man
-INITRAMFSTOOLS=$(DESTDIR)/usr/share/initramfs-tools
-
-GNUTLS_CFLAGS=$(shell libgnutls-config --cflags)
-GNUTLS_LIBS=$(shell libgnutls-config --libs)
-AVAHI_CFLAGS=$(shell pkg-config --cflags-only-I avahi-core)
-AVAHI_LIBS=$(shell pkg-config --libs avahi-core)
-GPGME_CFLAGS=$(shell gpgme-config --cflags)
-GPGME_LIBS=$(shell gpgme-config --libs)
-
# Do not change these two
-CFLAGS=$(WARN) $(DEBUG) $(FORTIFY) $(COVERAGE) $(OPTIMIZE) \
- $(LANGUAGE) $(GNUTLS_CFLAGS) $(AVAHI_CFLAGS) $(GPGME_CFLAGS)
+CFLAGS=$(WARN) $(DEBUG) $(FORTIFY) $(COVERAGE) $(OPTIMIZE) $(LANGUAGE)
LDFLAGS=$(COVERAGE)
-# Commands to format a DocBook document into a manual page
-DOCBOOKTOMAN=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 $<); \
- $(MANPOST) $(notdir $@)
-# DocBook-to-man post-processing to fix a '\n' escape bug
-MANPOST=sed --in-place --expression='s,\\\\en,\\en,g;s,\\n,\\en,g'
-
-PLUGINS=plugins.d/password-prompt plugins.d/mandos-client
-PROGS=plugin-runner $(PLUGINS)
-DOCS=mandos.8 plugin-runner.8mandos mandos-keygen.8 \
- plugins.d/mandos-client.8mandos \
- plugins.d/password-prompt.8mandos mandos.conf.5 \
- mandos-clients.conf.5
-
-objects=$(addsuffix .o,$(PROGS))
+PROGS=plugbasedclient plugins.d/mandosclient plugins.d/passprompt
+
+objects=$(shell for p in $(PROGS); do echo $${p}.o; done)
all: $(PROGS)
-doc: $(DOCS)
-
-%.5: %.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-
-%.8: %.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-
-%.8mandos: %.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-
-mandos.8: mandos.xml mandos-options.xml overview.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-
-mandos-keygen.8: mandos-keygen.xml overview.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-
-mandos.conf.5: mandos.conf.xml mandos-options.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-
-plugin-runner.8mandos: plugin-runner.xml overview.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-
-plugins.d/mandos-client.8mandos: plugins.d/mandos-client.xml \
- mandos-options.xml \
- overview.xml legalnotice.xml
- $(DOCBOOKTOMAN)
-
-plugins.d/mandos-client: plugins.d/mandos-client.o
- $(LINK.o) $(GNUTLS_LIBS) $(AVAHI_LIBS) $(GPGME_LIBS) \
- $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@
-
-.PHONY : all doc clean distclean run-client run-server install \
- install-server install-client uninstall uninstall-server \
- uninstall-client purge purge-server purge-client
-
+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 $(PROGS) $(objects) $(DOCS) core
-
-distclean: clean
-mostlyclean: clean
-maintainer-clean: clean
- -rm --force --recursive keydir confdir
-
-check:
- ./mandos --check
-
-# Run the client with a local config and key
-run-client: all keydir/seckey.txt keydir/pubkey.txt
- ./plugin-runner --plugin-dir=plugins.d \
- --config-file=plugin-runner.conf \
- --options-for=mandos-client:--seckey=keydir/seckey.txt,--pubkey=keydir/pubkey.txt
-
-# Used by run-client
-keydir/seckey.txt keydir/pubkey.txt: 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
- ./mandos --debug --configdir=confdir
-
-# 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
- install --directory confdir
- install --mode=u=rw $< $@
-# Add a client password
- ./mandos-keygen --dir keydir --password >> $@
-
-install: install-server install-client
-
-install-server: doc
- install --directory $(CONFDIR) $(MANDIR)/man5 \
- $(MANDIR)/man8
- install --mode=u=rwx,go=rx mandos $(PREFIX)/sbin/mandos
- install --mode=u=rw,go=r --target-directory=$(CONFDIR) \
- mandos.conf
- install --mode=u=rw --target-directory=$(CONFDIR) \
- clients.conf
- install --mode=u=rwx,go=rx init.d-mandos \
- $(DESTDIR)/etc/init.d/mandos
- install --mode=u=rw,go=r default-mandos \
- $(DESTDIR)/etc/default/mandos
- update-rc.d mandos defaults
- gzip --best --to-stdout mandos.8 \
- > $(MANDIR)/man8/mandos.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
-
-install-client: all doc $(INITRAMFSTOOLS)/hooks/.
- install --directory $(PREFIX)/lib/mandos $(CONFDIR) \
- $(MANDIR)/man8
- install --directory --mode=u=rwx $(KEYDIR)
- install --directory --mode=u=rwx \
- $(PREFIX)/lib/mandos/plugins.d
- if [ "$(CONFDIR)" != "$(PREFIX)/lib/mandos" ]; then \
- install --mode=u=rwx \
- --directory "$(CONFDIR)/plugins.d"; \
- install --mode=u=rw,go=r etc-plugins.d-README \
- $(CONFDIR)/plugins.d/README ; \
- fi
- install --mode=u=rwx,go=rx \
- --target-directory=$(PREFIX)/lib/mandos plugin-runner
- install --mode=u=rwx,go=rx --target-directory=$(PREFIX)/sbin \
- mandos-keygen
- install --mode=u=rwx,go=rx \
- --target-directory=$(PREFIX)/lib/mandos/plugins.d \
- plugins.d/password-prompt
- install --mode=u=rwxs,go=rx \
- --target-directory=$(PREFIX)/lib/mandos/plugins.d \
- plugins.d/mandos-client
- install --mode=u=rwx,go=rx \
- --target-directory=$(PREFIX)/lib/mandos/plugins.d \
- plugins.d/usplash
- install initramfs-tools-hook \
- $(INITRAMFSTOOLS)/hooks/mandos
- install initramfs-tools-hook-conf \
- $(INITRAMFSTOOLS)/conf-hooks.d/mandos
- install initramfs-tools-script \
- $(INITRAMFSTOOLS)/scripts/local-top/mandos
- 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/password-prompt.8mandos \
- > $(MANDIR)/man8/password-prompt.8mandos.gz
- gzip --best --to-stdout plugins.d/mandos-client.8mandos \
- > $(MANDIR)/man8/mandos-client.8mandos.gz
-# Post-installation stuff
- -$(PREFIX)/sbin/mandos-keygen --dir "$(KEYDIR)"
- update-initramfs -k all -u
- echo "Now run mandos-keygen --password --dir $(KEYDIR)"
-
-uninstall: uninstall-server uninstall-client
-
-uninstall-server:
- -rm --force $(PREFIX)/sbin/mandos \
- $(MANDIR)/man8/mandos.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 \
- $(PREFIX)/lib/mandos/plugin-runner \
- $(PREFIX)/lib/mandos/plugins.d/password-prompt \
- $(PREFIX)/lib/mandos/plugins.d/mandos-client \
- $(PREFIX)/lib/mandos/plugins.d/usplash \
- $(INITRAMFSTOOLS)/hooks/mandos \
- $(INITRAMFSTOOLS)/conf-hooks.d/mandos \
- $(INITRAMFSTOOLS)/scripts/local-top/mandos \
- $(MANDIR)/man8/plugin-runner.8mandos.gz \
- $(MANDIR)/man8/mandos-keygen.8.gz \
- $(MANDIR)/man8/password-prompt.8mandos.gz \
- $(MANDIR)/man8/mandos-client.8mandos.gz
- if [ "$(CONFDIR)" != "$(PREFIX)/lib/mandos" ]; then \
- rm --force $(CONFDIR)/plugins.d/README; \
- fi
- -rmdir $(PREFIX)/lib/mandos/plugins.d $(CONFDIR)/plugins.d \
- $(PREFIX)/lib/mandos $(CONFDIR) $(KEYDIR)
- update-initramfs -k all -u
-
-purge: purge-server purge-client
-
-purge-server: uninstall-server
- -rm --force $(CONFDIR)/mandos.conf $(CONFDIR)/clients.conf \
- $(DESTDIR)/etc/default/mandos \
- $(DESTDIR)/etc/init.d/mandos \
- $(DESTDIR)/var/run/mandos.pid
- -rmdir $(CONFDIR)
-
-purge-client: uninstall-client
- -shred --remove $(KEYDIR)/seckey.txt
- -rm --force $(CONFDIR)/plugin-runner.conf \
- $(KEYDIR)/pubkey.txt $(KEYDIR)/seckey.txt
- -rmdir $(KEYDIR) $(CONFDIR)/plugins.d $(CONFDIR)
+ -rm -f $(PROGS) $(objects) core
=== removed file 'README'
--- README 2008-09-05 07:11:24 +0000
+++ README 1970-01-01 00:00:00 +0000
@@ -1,131 +0,0 @@
--*- org -*-
-
-* Mandos
- - Have your cake and eat it too!
-
- 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 it to get the password, use it to decrypt
- the root file, and 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
- server 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.)
-
-* FAQ - 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,
- all *before* the Mandos server timeout kicks in and the Mandos
- server refuses to give out the key to anyone.
-
- Now, as the typical SOP 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 OpenPGP
- private key corresponding to that client.
-
-** 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 reboots at the same time they will
- stay down until someone types in the password on one of them.
-
-** Faking ping replies?
- The default for the server is 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.
- It could, for instance, be changed to an SSH command with strict
- keychecking, which could not be faked. Or IPsec could be used for
- the ping packets, making them secure.
-
-* Security Summary
- So, in summary: The only weakness in the Mandos system is from
- people who have:
- 1. The power to come in and physically take your servers, *and*
- 2. 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.
=== modified file 'TODO'
--- TODO 2008-09-06 16:31:49 +0000
+++ TODO 2008-08-02 14:33:47 +0000
@@ -1,85 +1,35 @@
-*- org -*-
-* plugin-runner
-
-* mandos-client
-** [#B] Temporarily lower kernel log level
- for less printouts during sucessfull boot.
+* Mandos client
+** header files/symbols tally
+** check exit codes of all system calls
** IPv4 support
-** use strsep instead of strtok?
-** Do not depend on GnuPG key rings on disk
- This would mean creating new GnuPG key rings with GPGME by
- importing the key files from scratch on every program start.
-** Keydir move: /etc/mandos -> /etc/keys/mandos
- Must create in preinst if not pre-depending on cryptsetup
-
-* password-prompt
-
-* mandos (server)
-** [#A] /etc/init.d/mandos-server :teddy:
-** [#B] Log level :bugs:
-** /etc/mandos/clients.d/*.conf
- Watch this directory and add/remove/update clients?
-** config for TXT record
-** [#B] Run-time communication with server :bugs:
- Probably using D-Bus
- See also [[*Mandos-tools]]
-** Implement --foreground :bugs:
- [[info:standards:Option%20Table][Table of Long Options]]
-** Implement --socket
- [[info:standards:Option%20Table][Table of Long Options]]
-** Date+time on console log messages :bugs:
- Is this the default?
-** delete hook when clients fall out by timeout
+** protocol version header
+** use strsep instead of strtok?
+
+* Pluginbasedclient
+** 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?
+** 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
All of this probably using D-Bus
** List clients
+** Enable client
** Disable client
-** Enable client
-** Reboot timer
-
-* Man pages
-** Use xinclude for common sections
- Like authors, etc.
-
* Installer
-** Client-side
-*** Update initrd.img after installation
- This seems to use some kind of "trigger" system
- [[file:/usr/share/doc/dpkg/triggers.txt.gz]]
- dpkg-trigger(1), deb-triggers(5)
-*** mandos-keygen
-**** "--passfile" option
- Using the "secfile" option instead of "secret"
-**** [#A] "--test" option
- For testing decryption before rebooting.
-** Server-side
-*** [#A] Create mandos user and group for server
-*** [#A] Create /var/run/mandos directory with perm and ownership
-*** [#A] install rc.d script and do update-rc.d
- between config files and man pages
-
-
-* [#A] Package
-** /usr/share/initramfs-tools/hooks/mandos
-*** Do not install in initrd.img if configured not to.
- Use "/etc/initramfs-tools/conf.d/mandos"? Definitely a debconf
- question.
-** /etc/bash_completion.d/mandos
- From XML sources directly?
-** unperish
-** bzr-builddeb
-
-* INSTALL file
-
-* Web site
-
-* Mailing list
-
-* Announce project on news
- [[news:comp.os.linux.announce]]
#+STARTUP: showall
=== 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-----
+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
+-----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-----
+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
+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-----
+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
+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-----
+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
+-----END RSA PRIVATE KEY-----
=== modified file 'clients.conf'
--- clients.conf 2008-08-27 01:18:25 +0000
+++ clients.conf 2008-07-29 03:35:39 +0000
@@ -1,65 +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 considered invalid - that is, ineligible
-# to get the data this server holds.
-;timeout = 1h
-
-# 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 marked
-# invalid, and any running checker killed.
-;interval = 5m
-
-# What command to run as "the checker".
-;checker = fping -q -- %(host)s
-
-
-;####
-;# Example client
-;[foo]
-;
-;# 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 fingerprint is not space or case sensitive
-;fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27
-;
-;# If "secret" is not specified, a file can be read for the data.
-;;secfile = /etc/mandos/bar-secret.txt.asc
-;
-;# 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 = 5m
-;####
+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
=== 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 'default-mandos'
--- default-mandos 2008-09-05 08:38:30 +0000
+++ default-mandos 1970-01-01 00:00:00 +0000
@@ -1,4 +0,0 @@
-# Directory where configuration files are located. Default is
-# "/etc/mandos".
-#
-#CONFIGDIR=/etc/mandos
=== removed file 'etc-plugins.d-README'
--- etc-plugins.d-README 2008-09-06 16:11:50 +0000
+++ etc-plugins.d-README 1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
-Any plugins found here 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:
-
-# update-initramfs -k all -u
=== removed file 'init.d-mandos'
--- init.d-mandos 2008-09-05 16:24:33 +0000
+++ init.d-mandos 1970-01-01 00:00:00 +0000
@@ -1,159 +0,0 @@
-#! /bin/sh
-### BEGIN INIT INFO
-# Provides: mandos
-# Required-Start: $remote_fs
-# Required-Stop: $remote_fs
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Mandos server
-# Description: Gives encrypted passwords to Mandos clients
-### END INIT INFO
-
-# Author: Teddy Hogeborn
-# Author: Björn Påhlsson
-#
-# Please remove the "Author" lines above and replace them
-# with your own name if you copy and modify this script.
-
-# 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=""
-PIDFILE=/var/run/$NAME.pid
-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.0-6) to ensure that this file is present.
-. /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
- ;;
- #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|restart|force-reload}" >&2
- exit 3
- ;;
-esac
-
-:
=== removed file 'initramfs-tools-hook'
--- initramfs-tools-hook 2008-09-06 15:34:21 +0000
+++ initramfs-tools-hook 1970-01-01 00:00:00 +0000
@@ -1,162 +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 the
-# 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 /usr/local; do
- if [ -d "$d"/lib/mandos ]; then
- prefix="$d"
- break
- fi
-done
-if [ -z "$prefix" ]; then
- # Mandos not found
- exit 1
-fi
-
-for d in /etc/keys/mandos /usr/local/lib/mandos/keys; do
- if [ -d "$d" ]; then
- keydir="$d"
- break
- fi
-done
-if [ -z "$keydir" ]; then
- # Mandos key directory not found
- exit 1
-fi
-
-mandos_user="`{ getent passwd mandos \
- || getent passwd nobody \
- || echo ::65534::::; } \
- | awk --field-separator=: '{ print $3 }'`"
-mandos_group="`{ getent group mandos \
- || getent group nogroup \
- || echo ::65534:; } \
- | awk --field-separator=: '{ print $3 }'`"
-
-# 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"
-
-# Make directories
-install --directory --mode=u=rwx,go=rx "${DESTDIR}${CONFDIR}" \
- "${DESTDIR}${MANDOSDIR}"
-install --owner=${mandos_user} --group=${mandos_group} --directory \
- --mode=u=rwx "${DESTDIR}${PLUGINDIR}"
-
-# Copy the Mandos plugin runner
-copy_exec "$prefix"/lib/mandos/plugin-runner "${MANDOSDIR}"
-
-# Copy the plugins
-
-# Copy the packaged plugins
-for file in "$prefix"/lib/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-new|*.dpkg-divert) : ;;
- "*") :;;
- *) copy_exec "$file" "${PLUGINDIR}";;
- esac
-done
-
-# Copy any user-supplied plugins
-for file in /etc/mandos/plugins.d/*; do
- base="`basename \"$file\"`"
- case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-new|*.dpkg-divert) : ;;
- "*") :;;
- *) copy_exec "$file" "${PLUGINDIR}";;
- esac
-done
-
-# GPGME needs /usr/bin/gpg
-if [ ! -e "${DESTDIR}/usr/bin/gpg" \
- -a -n "`ls \"${DESTDIR}\"/usr/lib/libgpgme.so* \
- 2>/dev/null`" ]; then
- copy_exec /usr/bin/gpg
-fi
-
-# Config files
-for file in /etc/mandos/*; do
- if [ -d "$file" ]; then
- continue
- fi
- cp --archive --sparse=always "$file" "${DESTDIR}${CONFDIR}"
-done
-
-# Key files
-for file in "$keydir"/*; do
- if [ -d "$file" ]; then
- continue
- fi
- cp --archive --sparse=always "$file" "${DESTDIR}${CONFDIR}"
- chown ${mandos_user}:${mandos_group} \
- "${DESTDIR}${CONFDIR}/`basename \"$file\"`"
-done
-
-# /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-hook-conf",
-# installed as "/usr/share/initramfs-tools/conf-hooks.d/mandos".)
-#
-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 /lib /usr/lib; do
- find "${DESTDIR}$dir" \! -perm -u+rw,g+r -prune -or -print0 \
- | xargs --null --no-run-if-empty chmod a+rX
-done
=== removed file 'initramfs-tools-hook-conf'
--- initramfs-tools-hook-conf 2008-08-12 19:22:34 +0000
+++ initramfs-tools-hook-conf 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-UMASK=027
=== removed file 'initramfs-tools-script'
--- initramfs-tools-script 2008-08-14 02:24:59 +0000
+++ initramfs-tools-script 1970-01-01 00:00:00 +0000
@@ -1,74 +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/local-top/mandos" which will
-# eventually be "/scripts/local-top/mandos" in the initrd.img file.
-
-# No initramfs pre-requirements; we must instead run BEFORE cryptroot.
-# This is not a problem, since cryptroot forces itself to run LAST.
-PREREQ=""
-prereqs()
-{
- echo "$PREREQ"
-}
-
-case $1 in
-prereqs)
- prereqs
- exit 0
- ;;
-esac
-
-test -w /conf/conf.d/cryptroot
-
-# Do not replace cryptroot file unless we need to.
-replace_cryptroot=no
-
-# Our keyscript
-mandos=/lib/mandos/plugin-runner
-
-# parse /conf/conf.d/cryptroot. Format:
-# target=sda2_crypt,source=/dev/sda2,key=none,keyscript=/foo/bar/baz
-exec 3>/conf/conf.d/cryptroot.mandos
-while read options; do
- newopts=""
- # 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"
- ;;
- "") : ;;
- *)
- newopts="$newopts,$opt"
- ;;
- esac
- done
- IFS="$old_ifs"
- unset old_ifs
- # If there was no keyscript option, add one.
- if [ -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 /conf/conf.d/cryptroot.mandos
-fi
=== 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-----
+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
+-----END RSA PRIVATE KEY-----
=== removed file 'legalnotice.xml'
--- legalnotice.xml 2008-09-06 17:24:58 +0000
+++ legalnotice.xml 1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
-
-
-
-
- This manual page 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 manual page 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
- http://www.gnu.org/licenses/.
-
-
=== removed file 'mandos-clients.conf.xml'
--- mandos-clients.conf.xml 2008-09-04 13:36:59 +0000
+++ mandos-clients.conf.xml 1970-01-01 00:00:00 +0000
@@ -1,397 +0,0 @@
-
-
-
-/etc/mandos/clients.conf">
-
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &VERSION;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2008
- 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. All clients listed will be regarded as valid, even
- if a client was declared invalid in a previous run of the
- server.
-
-
- 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.
-
-
- The timeout is how long the server will wait for a
- successful checker run until a client is considered
- invalid - that is, ineligible to get the data this server
- holds. By default Mandos will use 1 hour.
-
-
- The TIME is specified as a
- space-separated number of values, each of which is a
- number and a one-character suffix. The suffix must be one
- of d
, s
, m
,
- h
, and w
for days, seconds,
- minutes, hours, and weeks, respectively. The values are
- added together to give the total time value, so all of
- 330s
,
- 110s 110s 110s
, and
- 5m 30s
will give a value
- of five minutes and thirty seconds.
-
-
-
-
-
-
-
-
- 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 above
- timeout
occurs, at which
- time the client will be marked invalid, and any running
- checker killed. The default interval is 5 minutes.
-
-
- The format of TIME is the same
- as for timeout above.
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- This option allows you to override 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
.
-
-
- In addition to normal start time expansion, this option
- will also be subject to runtime expansion; see .
-
-
-
-
-
-
-
-
- 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 hexidecimal form,
- but spaces or upper/lower case are not significant.
-
-
-
-
-
-
-
-
- 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
- . 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 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.
-
-
-
-
-
-
-
-
- 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.
-
-
-
-
-
-
-
-
- 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. See the
- source code for details, and 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 = 1h
-interval = 5m
-checker = fping -q -- %(host)s
-
-# Client "foo"
-[foo]
-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 = 1m
-
-# Client "bar"
-[bar]
-fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27
-secfile = /etc/mandos/bar-secret
-timeout = 15m
-
-
-
-
-
-
- SEE ALSO
-
- mandos-keygen
- 8,
- mandos.conf
- 5,
- mandos
- 8
-
-
-
-
-
-
-
-
=== removed file 'mandos-keygen'
--- mandos-keygen 2008-09-06 15:34:21 +0000
+++ mandos-keygen 1970-01-01 00:00:00 +0000
@@ -1,300 +0,0 @@
-#!/bin/sh -e
-#
-# Mandos key generator - create a new OpenPGP key for a Mandos client
-#
-# 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 this program. If not, see .
-#
-# Contact the authors at .
-#
-
-VERSION="1.0"
-
-KEYDIR="/etc/keys/mandos"
-KEYTYPE=DSA
-KEYLENGTH=2048
-SUBKEYTYPE=ELG-E
-SUBKEYLENGTH=2048
-KEYNAME="`hostname --fqdn`"
-KEYEMAIL=""
-KEYCOMMENT="Mandos client key"
-KEYEXPIRE=0
-FORCE=no
-KEYCOMMENT_ORIG="$KEYCOMMENT"
-mode=keygen
-
-# Parse options
-TEMP=`getopt --options vhd:t:l:n:e:c:x:f \
- --longoptions version,help,password,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,force \
- --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"
-
-# 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" -o -e "$PUBKEYFILE" \) \
- -a "$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`"
-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\"; \
-shred --remove \"$RINGDIR\"/sec*;
-test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
-rm --recursive --force \"$RINGDIR\";
-stty echo; \
-" EXIT
-
-umask 077
-
-if [ "$mode" = keygen ]; then
- # Create batch file for GnuPG
- cat >"$BATCHFILE" <<-EOF
- Key-Type: $KEYTYPE
- Key-Length: $KEYLENGTH
- #Key-Usage: encrypt,sign,auth
- Subkey-Type: $SUBKEYTYPE
- Subkey-Length: $SUBKEYLENGTH
- #Subkey-Usage: encrypt,sign,auth
- Name-Real: $KEYNAME
- $KEYCOMMENTLINE
- $KEYEMAILLINE
- Expire-Date: $KEYEXPIRE
- #Preferences:
- #Handle:
- #%pubring pubring.gpg
- #%secring secring.gpg
- %commit
- EOF
-
- # 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"
-
- # Backup any old key files
- if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
- 2>/dev/null; then
- shred --remove "$SECKEYFILE"
- 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 keys 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
- # Import keys 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"
-
- FILECOMMENT="Encrypted password for a Mandos client"
-
- stty -echo
- echo -n "Enter passphrase: " >&2
- head --lines=1 | tr --delete '\n' \
- | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
- --homedir "$RINGDIR" --trust-model always --armor --encrypt \
- --recipient "$FINGERPRINT" --comment "$FILECOMMENT" \
- > "$SECFILE"
- echo >&2
- stty echo
-
- cat <<-EOF
- [$KEYNAME]
- host = $KEYNAME
- 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"
-fi
-
-trap - EXIT
-
-set +e
-# Remove the password file, if any
-if [ -n "$SECFILE" ]; then
- shred --remove "$SECFILE"
-fi
-# Remove the key rings
-shred --remove "$RINGDIR"/sec*
-rm --recursive --force "$RINGDIR"
=== removed file 'mandos-keygen.xml'
--- mandos-keygen.xml 2008-09-06 16:31:49 +0000
+++ mandos-keygen.xml 1970-01-01 00:00:00 +0000
@@ -1,492 +0,0 @@
-
-
-
-
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &VERSION;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2008
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8
-
-
-
- &COMMANDNAME;
-
- Generate key and password for Mandos client and server.
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is a program to generate the
- OpenPGP key used by
- mandos-client
- 8mandos. The key is
- normally written to /etc/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
- option 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/mandos.
-
-
-
-
-
-
-
-
-
- Key type. Default is DSA
.
-
-
-
-
-
-
-
-
-
- Key length in bits. Default is 2048.
-
-
-
-
-
-
-
-
-
- Subkey type. Default is ELG-E
(Elgamal
- encryption-only).
-
-
-
-
-
-
-
-
-
- Subkey length in bits. Default is 2048.
-
-
-
-
-
-
-
-
-
- Email address of key. Default is empty.
-
-
-
-
-
-
-
-
-
- Comment field for key. The default value is
- Mandos client key
.
-
-
-
-
-
-
-
-
-
- Key expire time. Default is no expiration. See
- gpg
- 1 for syntax.
-
-
-
-
-
-
-
-
-
- Force overwriting old key.
-
-
-
-
-
-
-
-
- Prompt for a password and encrypt it with the key already
- present in either /etc/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.
-
-
-
-
-
-
-
- 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
-
- 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/mandos/seckey.txt
-
-
- OpenPGP secret key file which will be created or
- overwritten.
-
-
-
-
- /etc/mandos/pubkey.txt
-
-
- OpenPGP public key file which will be created or
- overwritten.
-
-
-
-
- /tmp
-
-
- Temporary files will be written here if
- TMPDIR is not set.
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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 key in
- /etc/mandos and output a section suitable
- for clients.conf.
-
-
- &COMMANDNAME; --password
-
-
-
-
- Prompt for a password, encrypt it with the key 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
-
- gpg
- 1,
- mandos-clients.conf
- 5,
- mandos
- 8,
- mandos-client
- 8mandos
-
-
-
-
-
-
-
-
-
=== removed file 'mandos-options.xml'
--- mandos-options.xml 2008-09-06 16:31:49 +0000
+++ mandos-options.xml 1970-01-01 00:00:00 +0000
@@ -1,69 +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 be an IPv6 address; an
- IPv4 address can only be specified using IPv4-mapped IPv6 address
- syntax: ::FFFF:192.0.2.3
.
-
-
-
- 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 SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP
. See
- gnutls_priority_init
- 3 for the syntax.
- Warning: changing this may make the
- TLS handshake fail, making server-client
- communication impossible.
-
-
-
- Zeroconf service name. The default is
- Mandos
. This only needs to be
- changed this if it, for some reason, is necessary to run more than
- one server on the same host, which 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.
-
-
-
=== removed file 'mandos.conf.xml'
--- mandos.conf.xml 2008-09-04 13:36:59 +0000
+++ mandos.conf.xml 1970-01-01 00:00:00 +0000
@@ -1,240 +0,0 @@
-
-
-
-/etc/mandos/mandos.conf">
-
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &VERSION;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2008
- 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 = eth0
-address = 2001:db8:f983:bd0b:30de:ae4a:71f2:f672
-port = 1025
-debug = true
-priority = SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP
-servicename = Daena
-
-
-
-
-
- SEE ALSO
-
- 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 interfaces 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.xml'
--- mandos.xml 2008-09-06 16:31:49 +0000
+++ mandos.xml 1970-01-01 00:00:00 +0000
@@ -1,659 +0,0 @@
-
-
-
-
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &VERSION;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2008
- 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. 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.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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.
-
-
-
-
-
-
-
- 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 an OpenPGP certificate, and the
- fingerprint of this certificate 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
-
-
-
- OpenPGP 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. The timeout,
- checker program, and interval between checks can be configured
- both globally and per client; see
- mandos-clients.conf
- 5.
-
-
-
-
- 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.
-
-
-
-
- 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.
-
-
-
-
- /var/run/mandos.pid
-
-
- The file containing the process id of
- &COMMANDNAME;.
-
-
-
-
- /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.
-
-
- Currently, if a client is declared invalid
due to
- having timed out, the server does not record this fact onto
- permanent storage. This has some security implications, see
- .
-
-
- There is currently no way of querying the server of the current
- status of clients, other than analyzing its syslog output.
-
-
- There is no fine-grained control over logging and debug output.
-
-
- Debug mode is conflated with running in the foreground.
-
-
- The console log messages does not show a time stamp.
-
-
- This server does not check the expire time of clients’ OpenPGP
- keys.
-
-
-
-
- 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 OpenPGP key of the stored fingerprint. This is
- guaranteed by the fact that the client sends its OpenPGP
- public key in the TLS handshake; this ensures it to be
- genuine. The server computes the fingerprint of the key
- itself and looks up the fingerprint in its list of
- clients. The clients.conf file (see
- mandos-clients.conf
- 5)
- must be made non-readable by anyone
- except the user running the server.
-
-
- As detailed in , the status of all
- client computers will continually be checked and be assumed
- compromised if they are gone for too long.
-
-
- If a client is compromised, its downtime should be duly noted
- by the server which would therefore declare the client
- invalid. But if the server was ever restarted, it would
- re-read its client list from its configuration file and again
- regard all clients therein as valid, and hence eligible to
- receive their passwords. Therefore, be careful when
- restarting servers if it is suspected that a client has, in
- fact, been compromised by parties who may now be running a
- fake Mandos client with the keys from the non-encrypted
- initial RAM image of the client host. What
- should be done in that case (if restarting the server program
- really is necessary) is to stop the server program, edit the
- configuration file to omit any suspect clients, and restart
- the server program.
-
-
- For more details on client-side security, see
- mandos-client
- 8mandos.
-
-
-
-
-
- SEE ALSO
-
-
- mandos-clients.conf
- 5,
- mandos.conf
- 5,
- mandos-client
- 8mandos,
- sh1
-
-
-
-
-
- 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 OpenPGP 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 4346: The Transport Layer Security (TLS)
- Protocol Version 1.1
-
-
-
- TLS 1.1 is the protocol implemented by GnuTLS.
-
-
-
-
-
- RFC 4880: OpenPGP Message Format
-
-
-
- The data sent to clients is binary encrypted OpenPGP data.
-
-
-
-
-
- RFC 5081: Using OpenPGP Keys for Transport Layer
- Security
-
-
-
- This is implemented by GnuTLS and used by this server so
- that OpenPGP keys can be used.
-
-
-
-
-
-
-
-
-
-
-
=== removed file 'overview.xml'
--- overview.xml 2008-09-01 08:29:23 +0000
+++ overview.xml 1970-01-01 00:00:00 +0000
@@ -1,15 +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. The clients are
- identified by the server using a OpenPGP 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 the same
- 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 2008-09-07 01:44:44 +0000
+++ plugbasedclient.c 2008-08-02 10:48:24 +0000
@@ -21,86 +21,59 @@
* Contact the authors at .
*/
-#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), getline(),
- asprintf() */
-#include /* size_t, NULL */
-#include /* malloc(), exit(), EXIT_FAILURE,
- EXIT_SUCCESS, realloc() */
-#include /* bool, true, false */
-#include /* perror, popen(), fileno(),
- fprintf(), stderr, STDOUT_FILENO */
-#include /* DIR, opendir(), stat(), struct
- stat, waitpid(), WIFEXITED(),
- WEXITSTATUS(), wait(), pid_t,
- uid_t, gid_t, getuid(), getgid(),
- dirfd() */
-#include /* fd_set, select(), FD_ZERO(),
- FD_SET(), FD_ISSET(), FD_CLR */
-#include /* wait(), waitpid(), WIFEXITED(),
- WEXITSTATUS() */
-#include /* struct stat, stat(), S_ISREG() */
+#define _GNU_SOURCE /* TEMP_FAILURE_RETRY() */
+
+#include /* popen(), fileno(), fprintf(),
+ stderr, STDOUT_FILENO */
#include /* and, or, not */
+#include /* DIR, opendir(), stat(),
+ struct stat, waitpid(),
+ WIFEXITED(), WEXITSTATUS(),
+ wait() */
+#include /* wait() */
#include /* DIR, struct dirent, opendir(),
- readdir(), closedir(), dirfd() */
+ readdir(), closedir() */
+#include /* struct stat, stat(), S_ISREG() */
#include /* struct stat, stat(), S_ISREG(),
- fcntl(), setuid(), setgid(),
- F_GETFD, F_SETFD, FD_CLOEXEC,
- access(), pipe(), fork(), close()
- dup2, STDOUT_FILENO, _exit(),
- execv(), write(), read(),
- close() */
-#include /* fcntl(), F_GETFD, F_SETFD,
- FD_CLOEXEC */
-#include /* strsep, strlen(), asprintf() */
+ fcntl() */
+#include /* fcntl() */
+#include /* NULL */
+#include /* EXIT_FAILURE */
+#include /* fd_set, select(), FD_ZERO(),
+ FD_SET(), FD_ISSET() */
+#include /* strlen(), strcpy(), strcat() */
+#include /* true */
+#include /* waitpid(), WIFEXITED(),
+ WEXITSTATUS() */
#include /* errno */
-#include /* struct argp_option, struct
- argp_state, struct argp,
- argp_parse(), ARGP_ERR_UNKNOWN,
- ARGP_KEY_END, ARGP_KEY_ARG,
- error_t */
-#include /* struct sigaction, sigemptyset(),
- sigaddset(), sigaction(),
- sigprocmask(), SIG_BLOCK, SIGCHLD,
- SIG_UNBLOCK, kill() */
-#include /* errno, EBADF */
-
-#define BUFFER_SIZE 256
-
-#define PDIR "/lib/mandos/plugins.d"
-#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
-
-const char *argp_program_version = "plugin-runner 1.0";
-const char *argp_program_bug_address = "";
-
-struct plugin;
-
-typedef struct plugin{
- char *name; /* can be NULL or any plugin name */
- char **argv;
- int argc;
- char **environ;
- int envc;
- bool disabled;
-
- /* Variables used for running processes*/
+#include /* struct argp_option,
+ struct argp_state, struct argp,
+ argp_parse() */
+
+struct process;
+
+typedef struct process{
pid_t pid;
int fd;
char *buffer;
size_t buffer_size;
size_t buffer_length;
bool eof;
- volatile bool completed;
- volatile int status;
+ bool completed;
+ int status;
+ struct process *next;
+} process;
+
+typedef struct plugin{
+ char *name; /* can be NULL or any plugin name */
+ char **argv;
+ int argc;
+ bool disabled;
struct plugin *next;
} plugin;
-static plugin *plugin_list = NULL;
-
-/* Gets an existing plugin based on name,
- or if none is found, creates a new one */
-static plugin *getplugin(char *name){
- /* Check for exiting plugin with that name */
- for (plugin *p = plugin_list; p != NULL; p = p->next){
+plugin *getplugin(char *name, plugin **plugin_list){
+ for (plugin *p = *plugin_list; p != NULL; p = p->next){
if ((p->name == name)
or (p->name and name and (strcmp(p->name, name) == 0))){
return p;
@@ -109,98 +82,34 @@
/* Create a new plugin */
plugin *new_plugin = malloc(sizeof(plugin));
if (new_plugin == NULL){
- return NULL;
- }
- char *copy_name = NULL;
- if(name != NULL){
- copy_name = strdup(name);
- if(copy_name == NULL){
- return NULL;
- }
- }
-
- *new_plugin = (plugin) { .name = copy_name,
- .argc = 1,
- .disabled = false,
- .next = plugin_list };
-
+ perror("malloc");
+ exit(EXIT_FAILURE);
+ }
+ new_plugin->name = name;
new_plugin->argv = malloc(sizeof(char *) * 2);
if (new_plugin->argv == NULL){
- free(copy_name);
- free(new_plugin);
- return NULL;
+ perror("malloc");
+ exit(EXIT_FAILURE);
}
- new_plugin->argv[0] = copy_name;
+ new_plugin->argv[0] = name;
new_plugin->argv[1] = NULL;
-
- new_plugin->environ = malloc(sizeof(char *));
- if(new_plugin->environ == NULL){
- free(copy_name);
- free(new_plugin->argv);
- free(new_plugin);
- return NULL;
- }
- new_plugin->environ[0] = NULL;
-
+ new_plugin->argc = 1;
+ new_plugin->disabled = false;
+ new_plugin->next = *plugin_list;
/* Append the new plugin to the list */
- plugin_list = new_plugin;
+ *plugin_list = new_plugin;
return new_plugin;
}
-/* Helper function for add_argument and add_environment */
-static bool add_to_char_array(const char *new, char ***array,
- int *len){
- /* Resize the pointed-to array to hold one more pointer */
- *array = realloc(*array, sizeof(char *)
- * (size_t) ((*len) + 2));
- /* Malloc check */
- if(*array == NULL){
- return false;
- }
- /* Make a copy of the new string */
- char *copy = strdup(new);
- if(copy == NULL){
- return false;
- }
- /* Insert the copy */
- (*array)[*len] = copy;
- (*len)++;
- /* Add a new terminating NULL pointer to the last element */
- (*array)[*len] = NULL;
- return true;
-}
-
-/* Add to a plugin's argument vector */
-static bool add_argument(plugin *p, const char *arg){
- if(p == NULL){
- return false;
- }
- return add_to_char_array(arg, &(p->argv), &(p->argc));
-}
-
-/* Add to a plugin's environment */
-static bool add_environment(plugin *p, const char *def, bool replace){
- if(p == NULL){
- return false;
- }
- /* namelen = length of name of environment variable */
- size_t namelen = (size_t)(strchrnul(def, '=') - def);
- /* Search for this environment variable */
- for(char **e = p->environ; *e != NULL; e++){
- if(strncmp(*e, def, namelen + 1) == 0){
- /* It already exists */
- if(replace){
- char *new = realloc(*e, strlen(def) + 1);
- if(new == NULL){
- return false;
- }
- *e = new;
- strcpy(*e, def);
- }
- return true;
- }
- }
- return add_to_char_array(def, &(p->environ), &(p->envc));
+void addargument(plugin *p, char *arg){
+ p->argv[p->argc] = arg;
+ p->argv = realloc(p->argv, sizeof(char *) * (size_t)(p->argc + 2));
+ if (p->argv == NULL){
+ perror("malloc");
+ exit(EXIT_FAILURE);
+ }
+ p->argc++;
+ p->argv[p->argc] = NULL;
}
/*
@@ -208,7 +117,7 @@
* Descriptor Flags".
* *Note File Descriptor Flags:(libc)Descriptor Flags.
*/
-static int set_cloexec_flag(int fd)
+int set_cloexec_flag(int fd)
{
int ret = fcntl(fd, F_GETFD, 0);
/* If reading the flags failed, return error indication now. */
@@ -219,121 +128,55 @@
return fcntl(fd, F_SETFD, ret | FD_CLOEXEC);
}
-
-/* Mark processes as completed when they exit, and save their exit
+#define BUFFER_SIZE 256
+
+const char *argp_program_version = "plugbasedclient 0.9";
+const char *argp_program_bug_address = "";
+
+process *process_list = NULL;
+
+/* Mark a process as completed when it exits, and save its exit
status. */
void handle_sigchld(__attribute__((unused)) int sig){
- while(true){
- plugin *proc = plugin_list;
- int status;
- pid_t pid = waitpid(-1, &status, WNOHANG);
- if(pid == 0){
- /* Only still running child processes */
- break;
- }
- if(pid == -1){
- if (errno != ECHILD){
- perror("waitpid");
- }
- /* No child processes */
- break;
- }
-
- /* A child exited, find it in process_list */
- while(proc != NULL and proc->pid != pid){
- proc = proc->next;
- }
- if(proc == NULL){
- /* Process not found in process list */
- continue;
- }
- proc->status = status;
- proc->completed = true;
- }
-}
-
-/* Prints out a password to stdout */
-bool print_out_password(const char *buffer, size_t length){
- ssize_t ret;
- for(size_t written = 0; written < length; written += (size_t)ret){
- ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buffer + written,
- length - written));
- if(ret < 0){
- return false;
- }
- }
- return true;
-}
-
-/* Removes and free a plugin from the plugin list */
-static void free_plugin(plugin *plugin_node){
-
- for(char **arg = plugin_node->argv; *arg != NULL; arg++){
- free(*arg);
- }
- free(plugin_node->argv);
- for(char **env = plugin_node->environ; *env != NULL; env++){
- free(*env);
- }
- free(plugin_node->environ);
- free(plugin_node->buffer);
-
- /* Removes the plugin from the singly-linked list */
- if(plugin_node == plugin_list){
- /* First one - simple */
- plugin_list = plugin_list->next;
- } else {
- /* Second one or later */
- for(plugin *p = plugin_list; p != NULL; p = p->next){
- if(p->next == plugin_node){
- p->next = plugin_node->next;
- break;
- }
- }
- }
-
- free(plugin_node);
-}
-
-static void free_plugin_list(void){
- while(plugin_list != NULL){
- free_plugin(plugin_list);
- }
+ process *proc = process_list;
+ int status;
+ pid_t pid = wait(&status);
+ while(proc != NULL and proc->pid != pid){
+ proc = proc->next;
+ }
+ if(proc == NULL){
+ /* Process not found in process list */
+ return;
+ }
+ proc->status = status;
+ proc->completed = true;
}
int main(int argc, char *argv[]){
- char *plugindir = NULL;
- char *argfile = NULL;
- FILE *conffp;
+ const char *plugindir = "/conf/conf.d/mandos/plugins.d";
size_t d_name_len;
DIR *dir = NULL;
struct dirent *dirst;
struct stat st;
fd_set rfds_all;
int ret, maxfd = 0;
- uid_t uid = 65534;
- gid_t gid = 65534;
bool debug = false;
int exitstatus = EXIT_SUCCESS;
- struct sigaction old_sigchld_action;
- struct sigaction sigchld_action = { .sa_handler = handle_sigchld,
- .sa_flags = SA_NOCLDSTOP };
- char **custom_argv = NULL;
- int custom_argc = 0;
/* Establish a signal handler */
+ struct sigaction old_sigchld_action,
+ sigchld_action = { .sa_handler = handle_sigchld,
+ .sa_flags = SA_NOCLDSTOP };
sigemptyset(&sigchld_action.sa_mask);
ret = sigaddset(&sigchld_action.sa_mask, SIGCHLD);
- if(ret == -1){
+ if(ret < 0){
perror("sigaddset");
- exitstatus = EXIT_FAILURE;
- goto fallback;
+ exit(EXIT_FAILURE);
}
ret = sigaction(SIGCHLD, &sigchld_action, &old_sigchld_action);
- if(ret == -1){
+ if(ret < 0){
perror("sigaction");
- exitstatus = EXIT_FAILURE;
- goto fallback;
+ exit(EXIT_FAILURE);
}
/* The options we understand. */
@@ -341,287 +184,76 @@
{ .name = "global-options", .key = 'g',
.arg = "OPTION[,OPTION[,...]]",
.doc = "Options passed to all plugins" },
- { .name = "global-env", .key = 'G',
- .arg = "VAR=value",
- .doc = "Environment variable passed to all plugins" },
{ .name = "options-for", .key = 'o',
.arg = "PLUGIN:OPTION[,OPTION[,...]]",
.doc = "Options passed only to specified plugin" },
- { .name = "env-for", .key = 'E',
- .arg = "PLUGIN:ENV=value",
- .doc = "Environment variable passed to specified plugin" },
{ .name = "disable", .key = 'd',
.arg = "PLUGIN",
.doc = "Disable a specific plugin", .group = 1 },
- { .name = "enable", .key = 'e',
- .arg = "PLUGIN",
- .doc = "Enable a specific plugin", .group = 1 },
{ .name = "plugin-dir", .key = 128,
.arg = "DIRECTORY",
.doc = "Specify a different plugin directory", .group = 2 },
- { .name = "config-file", .key = 129,
- .arg = "FILE",
- .doc = "Specify a different configuration file", .group = 2 },
- { .name = "userid", .key = 130,
- .arg = "ID", .flags = 0,
- .doc = "User ID the plugins will run as", .group = 3 },
- { .name = "groupid", .key = 131,
- .arg = "ID", .flags = 0,
- .doc = "Group ID the plugins will run as", .group = 3 },
- { .name = "debug", .key = 132,
- .doc = "Debug mode", .group = 4 },
+ { .name = "debug", .key = 129,
+ .doc = "Debug mode", .group = 3 },
{ .name = NULL }
};
- error_t parse_opt (int key, char *arg, __attribute__((unused))
- struct argp_state *state) {
+ error_t parse_opt (int key, char *arg, struct argp_state *state) {
+ /* Get the INPUT argument from `argp_parse', which we know is a
+ pointer to our plugin list pointer. */
+ plugin **plugins = state->input;
switch (key) {
- case 'g': /* --global-options */
- if (arg != NULL){
- char *p;
- while((p = strsep(&arg, ",")) != NULL){
- if(p[0] == '\0'){
- continue;
- }
- if(not add_argument(getplugin(NULL), p)){
- perror("add_argument");
- return ARGP_ERR_UNKNOWN;
- }
- }
- }
- break;
- case 'G': /* --global-env */
- if(arg == NULL){
- break;
- }
- if(not add_environment(getplugin(NULL), arg, true)){
- perror("add_environment");
- }
- break;
- case 'o': /* --options-for */
- if (arg != NULL){
- char *p_name = strsep(&arg, ":");
- if(p_name[0] == '\0' or arg == NULL){
- break;
- }
- char *opt = strsep(&arg, ":");
- if(opt[0] == '\0' or opt == NULL){
- break;
- }
- char *p;
- while((p = strsep(&opt, ",")) != NULL){
- if(p[0] == '\0'){
- continue;
- }
- if(not add_argument(getplugin(p_name), p)){
- perror("add_argument");
- return ARGP_ERR_UNKNOWN;
- }
- }
- }
- break;
- case 'E': /* --env-for */
- if(arg == NULL){
- break;
- }
- {
- char *envdef = strchr(arg, ':');
- if(envdef == NULL){
- break;
- }
- *envdef = '\0';
- if(not add_environment(getplugin(arg), envdef+1, true)){
- perror("add_environment");
- }
- }
- break;
- case 'd': /* --disable */
- if (arg != NULL){
- plugin *p = getplugin(arg);
- if(p == NULL){
- return ARGP_ERR_UNKNOWN;
- }
- p->disabled = true;
- }
- break;
- case 'e': /* --enable */
- if (arg != NULL){
- plugin *p = getplugin(arg);
- if(p == NULL){
- return ARGP_ERR_UNKNOWN;
- }
- p->disabled = false;
- }
- break;
- case 128: /* --plugin-dir */
- free(plugindir);
- plugindir = strdup(arg);
- if(plugindir == NULL){
- perror("strdup");
- }
- break;
- case 129: /* --config-file */
- /* This is already done by parse_opt_config_file() */
- break;
- case 130: /* --userid */
- uid = (uid_t)strtol(arg, NULL, 10);
- break;
- case 131: /* --groupid */
- gid = (gid_t)strtol(arg, NULL, 10);
- break;
- case 132: /* --debug */
+ case 'g':
+ if (arg != NULL){
+ char *p = strtok(arg, ",");
+ do{
+ addargument(getplugin(NULL, plugins), p);
+ p = strtok(NULL, ",");
+ } while (p);
+ }
+ break;
+ case 'o':
+ if (arg != NULL){
+ char *name = strtok(arg, ":");
+ char *p = strtok(NULL, ":");
+ if(p){
+ p = strtok(p, ",");
+ do{
+ addargument(getplugin(name, plugins), p);
+ p = strtok(NULL, ",");
+ } while (p);
+ }
+ }
+ break;
+ case 'd':
+ if (arg != NULL){
+ getplugin(arg, plugins)->disabled = true;
+ }
+ break;
+ case 128:
+ plugindir = arg;
+ break;
+ case 129:
debug = true;
break;
case ARGP_KEY_ARG:
- fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg);
- break;
- case ARGP_KEY_END:
- break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
- }
-
- /* This option parser is the same as parse_opt() above, except it
- ignores everything but the --config-file option. */
- error_t parse_opt_config_file (int key, char *arg,
- __attribute__((unused))
- struct argp_state *state) {
- switch (key) {
- case 'g': /* --global-options */
- case 'G': /* --global-env */
- case 'o': /* --options-for */
- case 'E': /* --env-for */
- case 'd': /* --disable */
- case 'e': /* --enable */
- case 128: /* --plugin-dir */
- break;
- case 129: /* --config-file */
- free(argfile);
- argfile = strdup(arg);
- if(argfile == NULL){
- perror("strdup");
- }
- break;
- case 130: /* --userid */
- case 131: /* --groupid */
- case 132: /* --debug */
- case ARGP_KEY_ARG:
- case ARGP_KEY_END:
- break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
- }
-
- struct argp argp = { .options = options,
- .parser = parse_opt_config_file,
+ argp_usage (state);
+ break;
+ case ARGP_KEY_END:
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+
+ plugin *plugin_list = NULL;
+
+ struct argp argp = { .options = options, .parser = parse_opt,
.args_doc = "",
.doc = "Mandos plugin runner -- Run plugins" };
- /* Parse using the parse_opt_config_file in order to get the custom
- config file location, if any. */
- ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
- if (ret == ARGP_ERR_UNKNOWN){
- fprintf(stderr, "Unknown error while parsing arguments\n");
- exitstatus = EXIT_FAILURE;
- goto fallback;
- }
-
- /* Reset to the normal argument parser */
- argp.parser = parse_opt;
-
- /* Open the configfile if available */
- if (argfile == NULL){
- conffp = fopen(AFILE, "r");
- } else {
- conffp = fopen(argfile, "r");
- }
- if(conffp != NULL){
- char *org_line = NULL;
- char *p, *arg, *new_arg, *line;
- size_t size = 0;
- ssize_t sret;
- const char whitespace_delims[] = " \r\t\f\v\n";
- const char comment_delim[] = "#";
-
- custom_argc = 1;
- custom_argv = malloc(sizeof(char*) * 2);
- if(custom_argv == NULL){
- perror("malloc");
- exitstatus = EXIT_FAILURE;
- goto fallback;
- }
- custom_argv[0] = argv[0];
- custom_argv[1] = NULL;
-
- /* for each line in the config file, strip whitespace and ignore
- commented text */
- while(true){
- sret = getline(&org_line, &size, conffp);
- if(sret == -1){
- break;
- }
-
- line = org_line;
- arg = strsep(&line, comment_delim);
- while((p = strsep(&arg, whitespace_delims)) != NULL){
- if(p[0] == '\0'){
- continue;
- }
- new_arg = strdup(p);
- if(new_arg == NULL){
- perror("strdup");
- exitstatus = EXIT_FAILURE;
- free(org_line);
- goto fallback;
- }
-
- custom_argc += 1;
- custom_argv = realloc(custom_argv, sizeof(char *)
- * ((unsigned int) custom_argc + 1));
- if(custom_argv == NULL){
- perror("realloc");
- exitstatus = EXIT_FAILURE;
- free(org_line);
- goto fallback;
- }
- custom_argv[custom_argc-1] = new_arg;
- custom_argv[custom_argc] = NULL;
- }
- }
- free(org_line);
- } else {
- /* Check for harmful errors and go to fallback. Other errors might
- not affect opening plugins */
- if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
- perror("fopen");
- exitstatus = EXIT_FAILURE;
- goto fallback;
- }
- }
- /* If there was any arguments from configuration file,
- pass them to parser as command arguments */
- if(custom_argv != NULL){
- ret = argp_parse (&argp, custom_argc, custom_argv, ARGP_IN_ORDER,
- 0, NULL);
- if (ret == ARGP_ERR_UNKNOWN){
- fprintf(stderr, "Unknown error while parsing arguments\n");
- exitstatus = EXIT_FAILURE;
- goto fallback;
- }
- }
-
- /* Parse actual command line arguments, to let them override the
- config file */
- ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
- if (ret == ARGP_ERR_UNKNOWN){
- fprintf(stderr, "Unknown error while parsing arguments\n");
- exitstatus = EXIT_FAILURE;
- goto fallback;
- }
+ argp_parse (&argp, argc, argv, 0, 0, &plugin_list);
if(debug){
for(plugin *p = plugin_list; p != NULL; p=p->next){
@@ -630,33 +262,14 @@
for(char **a = p->argv; *a != NULL; a++){
fprintf(stderr, "\tArg: %s\n", *a);
}
- fprintf(stderr, "...and %u environment variables\n", p->envc);
- for(char **a = p->environ; *a != NULL; a++){
- fprintf(stderr, "\t%s\n", *a);
- }
}
}
- /* Strip permissions down to nobody */
- ret = setuid(uid);
- if (ret == -1){
- perror("setuid");
- }
- setgid(gid);
- if (ret == -1){
- perror("setgid");
- }
-
- if (plugindir == NULL){
- dir = opendir(PDIR);
- } else {
- dir = opendir(plugindir);
- }
-
+ dir = opendir(plugindir);
if(dir == NULL){
perror("Could not open plugin dir");
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
/* Set the FD_CLOEXEC flag on the directory, if possible */
@@ -667,30 +280,24 @@
if(ret < 0){
perror("set_cloexec_flag");
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
}
}
FD_ZERO(&rfds_all);
- /* Read and execute any executable in the plugin directory*/
while(true){
dirst = readdir(dir);
- /* All directory entries have been processed */
+ // All directory entries have been processed
if(dirst == NULL){
- if (errno == EBADF){
- perror("readdir");
- exitstatus = EXIT_FAILURE;
- goto fallback;
- }
break;
}
d_name_len = strlen(dirst->d_name);
- /* Ignore dotfiles, backup files and other junk */
+ // Ignore dotfiles, backup files and other junk
{
bool bad_name = false;
@@ -711,9 +318,11 @@
break;
}
}
+
if(bad_name){
continue;
}
+
for(const char **suf = bad_suffixes; *suf != NULL; suf++){
size_t suf_len = strlen(*suf);
if((d_name_len >= suf_len)
@@ -732,26 +341,19 @@
continue;
}
}
-
- char *filename;
- if(plugindir == NULL){
- ret = asprintf(&filename, PDIR "/%s", dirst->d_name);
- } else {
- ret = asprintf(&filename, "%s/%s", plugindir, dirst->d_name);
- }
- if(ret < 0){
- perror("asprintf");
- continue;
- }
-
- ret = stat(filename, &st);
- if (ret == -1){
- perror("stat");
- free(filename);
- continue;
- }
-
- /* Ignore non-executable files */
+
+ char *filename = malloc(d_name_len + strlen(plugindir) + 2);
+ if (filename == NULL){
+ perror("malloc");
+ exitstatus = EXIT_FAILURE;
+ goto end;
+ }
+ strcpy(filename, plugindir); /* Spurious warning */
+ strcat(filename, "/"); /* Spurious warning */
+ strcat(filename, dirst->d_name); /* Spurious warning */
+
+ stat(filename, &st);
+
if (not S_ISREG(st.st_mode) or (access(filename, X_OK) != 0)){
if(debug){
fprintf(stderr, "Ignoring plugin dir entry \"%s\""
@@ -760,14 +362,7 @@
free(filename);
continue;
}
-
- plugin *p = getplugin(dirst->d_name);
- if(p == NULL){
- perror("getplugin");
- free(filename);
- continue;
- }
- if(p->disabled){
+ if(getplugin(dirst->d_name, &plugin_list)->disabled){
if(debug){
fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
dirst->d_name);
@@ -775,68 +370,42 @@
free(filename);
continue;
}
+ plugin *p = getplugin(dirst->d_name, &plugin_list);
{
/* Add global arguments to argument list for this plugin */
- plugin *g = getplugin(NULL);
- if(g != NULL){
- for(char **a = g->argv + 1; *a != NULL; a++){
- if(not add_argument(p, *a)){
- perror("add_argument");
- }
- }
- /* Add global environment variables */
- for(char **e = g->environ; *e != NULL; e++){
- if(not add_environment(p, *e, false)){
- perror("add_environment");
- }
- }
- }
- }
- /* If this plugin has any environment variables, we will call
- using execve and need to duplicate the environment from this
- process, too. */
- if(p->environ[0] != NULL){
- for(char **e = environ; *e != NULL; e++){
- if(not add_environment(p, *e, false)){
- perror("add_environment");
- }
- }
- }
-
- int pipefd[2];
+ plugin *g = getplugin(NULL, &plugin_list);
+ for(char **a = g->argv + 1; *a != NULL; a++){
+ addargument(p, *a);
+ }
+ }
+ int pipefd[2];
ret = pipe(pipefd);
if (ret == -1){
perror("pipe");
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
- /* Ask OS to automatic close the pipe on exec */
ret = set_cloexec_flag(pipefd[0]);
if(ret < 0){
perror("set_cloexec_flag");
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
ret = set_cloexec_flag(pipefd[1]);
if(ret < 0){
perror("set_cloexec_flag");
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
/* Block SIGCHLD until process is safely in process list */
ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
perror("sigprocmask");
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
- /* Starting a new process to be watched */
+ // Starting a new process to be watched
pid_t pid = fork();
- if(pid == -1){
- perror("fork");
- exitstatus = EXIT_FAILURE;
- goto fallback;
- }
if(pid == 0){
/* this is the child process */
ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
@@ -849,158 +418,151 @@
perror("sigprocmask");
_exit(EXIT_FAILURE);
}
-
- ret = dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
- if(ret == -1){
- perror("dup2");
- _exit(EXIT_FAILURE);
- }
+ dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
if(dirfd(dir) < 0){
/* If dir has no file descriptor, we could not set FD_CLOEXEC
above and must now close it manually here. */
closedir(dir);
}
- if(p->environ[0] == NULL){
- if(execv(filename, p->argv) < 0){
- perror("execv");
- _exit(EXIT_FAILURE);
- }
- } else {
- if(execve(filename, p->argv, p->environ) < 0){
- perror("execve");
- _exit(EXIT_FAILURE);
- }
+ if(execv(filename, p->argv) < 0){
+ perror("execv");
+ _exit(EXIT_FAILURE);
}
/* no return */
}
- /* Parent process */
- close(pipefd[1]); /* Close unused write end of pipe */
+ /* parent process */
free(filename);
- plugin *new_plugin = getplugin(dirst->d_name);
- if (new_plugin == NULL){
- perror("getplugin");
+ close(pipefd[1]); /* close unused write end of pipe */
+ process *new_process = malloc(sizeof(process));
+ if (new_process == NULL){
+ perror("malloc");
ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
- perror("sigprocmask");
+ perror("sigprocmask");
}
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
- new_plugin->pid = pid;
- new_plugin->fd = pipefd[0];
-
+ *new_process = (struct process){ .pid = pid,
+ .fd = pipefd[0],
+ .next = process_list };
+ // List handling
+ process_list = new_process;
/* Unblock SIGCHLD so signal handler can be run if this process
has already completed */
ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
perror("sigprocmask");
exitstatus = EXIT_FAILURE;
- goto fallback;
- }
-
- FD_SET(new_plugin->fd, &rfds_all);
-
- if (maxfd < new_plugin->fd){
- maxfd = new_plugin->fd;
- }
-
+ goto end;
+ }
+
+ FD_SET(new_process->fd, &rfds_all);
+
+ if (maxfd < new_process->fd){
+ maxfd = new_process->fd;
+ }
+
+ }
+
+ /* Free the plugin list */
+ for(plugin *next; plugin_list != NULL; plugin_list = next){
+ next = plugin_list->next;
+ free(plugin_list->argv);
+ free(plugin_list);
}
closedir(dir);
dir = NULL;
-
- for(plugin *p = plugin_list; p != NULL; p = p->next){
- if(p->pid != 0){
- break;
- }
- if(p->next == NULL){
- fprintf(stderr, "No plugin processes started. Incorrect plugin"
- " directory?\n");
- free_plugin_list();
- }
+
+ if (process_list == NULL){
+ fprintf(stderr, "No plugin processes started, exiting\n");
+ exitstatus = EXIT_FAILURE;
+ goto end;
}
-
- /* Main loop while running plugins exist */
- while(plugin_list){
+ while(process_list){
fd_set rfds = rfds_all;
int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
if (select_ret == -1){
perror("select");
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
/* OK, now either a process completed, or something can be read
from one of them */
- for(plugin *proc = plugin_list; proc != NULL;){
+ for(process *proc = process_list; proc ; proc = proc->next){
/* Is this process completely done? */
if(proc->eof and proc->completed){
/* Only accept the plugin output if it exited cleanly */
if(not WIFEXITED(proc->status)
or WEXITSTATUS(proc->status) != 0){
/* Bad exit by plugin */
-
if(debug){
if(WIFEXITED(proc->status)){
- fprintf(stderr, "Plugin %u exited with status %d\n",
- (unsigned int) (proc->pid),
- WEXITSTATUS(proc->status));
+ fprintf(stderr, "Plugin %d exited with status %d\n",
+ proc->pid, WEXITSTATUS(proc->status));
} else if(WIFSIGNALED(proc->status)) {
- fprintf(stderr, "Plugin %u killed by signal %d\n",
- (unsigned int) (proc->pid),
- WTERMSIG(proc->status));
+ fprintf(stderr, "Plugin %d killed by signal %d\n",
+ proc->pid, WTERMSIG(proc->status));
} else if(WCOREDUMP(proc->status)){
- fprintf(stderr, "Plugin %d dumped core\n",
- (unsigned int) (proc->pid));
+ fprintf(stderr, "Plugin %d dumped core\n", proc->pid);
}
}
-
/* Remove the plugin */
FD_CLR(proc->fd, &rfds_all);
-
/* Block signal while modifying process_list */
- ret = sigprocmask(SIG_BLOCK, &sigchld_action.sa_mask, NULL);
+ ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
perror("sigprocmask");
exitstatus = EXIT_FAILURE;
- goto fallback;
- }
-
+ goto end;
+ }
+ /* Delete this process entry from the list */
+ if(process_list == proc){
+ /* First one - simple */
+ process_list = proc->next;
+ } else {
+ /* Second one or later */
+ for(process *p = process_list; p != NULL; p = p->next){
+ if(p->next == proc){
+ p->next = proc->next;
+ break;
+ }
+ }
+ }
/* We are done modifying process list, so unblock signal */
ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask,
NULL);
if(ret < 0){
perror("sigprocmask");
- exitstatus = EXIT_FAILURE;
- goto fallback;
- }
-
- if(plugin_list == NULL){
- break;
- }
-
- plugin *next_plugin = proc->next;
- free_plugin(proc);
- proc = next_plugin;
- continue;
+ }
+ free(proc->buffer);
+ free(proc);
+ /* We deleted this process from the list, so we can't go
+ proc->next. Therefore, start over from the beginning of
+ the process list */
+ break;
}
-
/* This process exited nicely, so print its buffer */
-
- bool bret = print_out_password(proc->buffer,
- proc->buffer_length);
- if(not bret){
- perror("print_out_password");
- exitstatus = EXIT_FAILURE;
+ for(size_t written = 0; written < proc->buffer_length;
+ written += (size_t)ret){
+ ret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,
+ proc->buffer + written,
+ proc->buffer_length
+ - written));
+ if(ret < 0){
+ perror("write");
+ exitstatus = EXIT_FAILURE;
+ goto end;
+ }
}
- goto fallback;
+ goto end;
}
-
/* This process has not completed. Does it have any output? */
if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
/* This process had nothing to say at this time */
- proc = proc->next;
continue;
}
/* Before reading, make the process' data buffer large enough */
@@ -1010,7 +572,7 @@
if (proc->buffer == NULL){
perror("malloc");
exitstatus = EXIT_FAILURE;
- goto fallback;
+ goto end;
}
proc->buffer_size += BUFFER_SIZE;
}
@@ -1019,7 +581,6 @@
BUFFER_SIZE);
if(ret < 0){
/* Read error from this process; ignore the error */
- proc = proc->next;
continue;
}
if(ret == 0){
@@ -1030,41 +591,20 @@
}
}
}
-
-
- fallback:
-
- if(plugin_list == NULL or exitstatus != EXIT_SUCCESS){
- /* Fallback if all plugins failed, none are found or an error
- occured */
- bool bret;
- fprintf(stderr, "Going to fallback mode using getpass(3)\n");
- char *passwordbuffer = getpass("Password: ");
- size_t len = strlen(passwordbuffer);
- /* Strip trailing newline */
- if(len > 0 and passwordbuffer[len-1] == '\n'){
- passwordbuffer[len-1] = '\0'; /* not strictly necessary */
- len--;
- }
- bret = print_out_password(passwordbuffer, len);
- if(not bret){
- perror("print_out_password");
- exitstatus = EXIT_FAILURE;
- }
+ if(process_list == NULL){
+ fprintf(stderr, "All plugin processes failed, exiting\n");
+ exitstatus = EXIT_FAILURE;
}
+ end:
/* Restore old signal handler */
- ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
- if(ret == -1){
- perror("sigaction");
- exitstatus = EXIT_FAILURE;
- }
-
- if(custom_argv != NULL){
- for(char **arg = custom_argv+1; *arg != NULL; arg++){
- free(*arg);
- }
- free(custom_argv);
+ sigaction(SIGCHLD, &old_sigchld_action, NULL);
+
+ /* Free the plugin list */
+ for(plugin *next; plugin_list != NULL; plugin_list = next){
+ next = plugin_list->next;
+ free(plugin_list->argv);
+ free(plugin_list);
}
if(dir != NULL){
@@ -1072,15 +612,12 @@
}
/* Free the process list and kill the processes */
- for(plugin *p = plugin_list; p != NULL; p = p->next){
- if(p->pid != 0){
- close(p->fd);
- ret = kill(p->pid, SIGTERM);
- if(ret == -1 and errno != ESRCH){
- /* Set-uid proccesses might not get closed */
- perror("kill");
- }
- }
+ for(process *next; process_list != NULL; process_list = next){
+ next = process_list->next;
+ close(process_list->fd);
+ kill(process_list->pid, SIGTERM);
+ free(process_list->buffer);
+ free(process_list);
}
/* Wait for any remaining child processes to terminate */
@@ -1090,11 +627,6 @@
if(errno != ECHILD){
perror("wait");
}
-
- free_plugin_list();
-
- free(plugindir);
- free(argfile);
return exitstatus;
}
=== removed file 'plugin-runner.conf'
--- plugin-runner.conf 2008-09-06 16:31:49 +0000
+++ plugin-runner.conf 1970-01-01 00:00:00 +0000
@@ -1,9 +0,0 @@
-## This is the configuration file for plugin-runner. It should be
-## installed as "/etc/mandos/plugin-runner.conf", which will be copied
-## to "/conf/conf.d/mandos/plugin-runner.conf" in the initrd.img file.
-##
-## The default network interface for mandos-client(8mandos) is
-## "eth0". Uncomment this line and change it if necessary.
-##
-
-#--options-for=mandos-client:--interface=eth0
=== removed file 'plugin-runner.xml'
--- plugin-runner.xml 2008-09-06 16:31:49 +0000
+++ plugin-runner.xml 1970-01-01 00:00:00 +0000
@@ -1,638 +0,0 @@
-
-
-
-
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &VERSION;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2008
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8mandos
-
-
-
- &COMMANDNAME;
-
- Run Mandos plugins, pass data from first to succeed.
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is a program which is meant to
- be specified as a keyscript
for the root disk in
- crypttab
- 5. The aim of this
- program is therefore to output a password, which then
- cryptsetup
- 8 will use to unlock the
- root disk.
-
-
- This program is not meant to be invoked directly, but can be in
- order to test it. Note that any password obtained will simply
- be output on standard output.
-
-
-
-
- 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
-
-
-
-
-
-
- This option will add an environment variable setting to
- all plugins. This will override any inherited environment
- variable.
-
-
-
-
-
-
-
-
-
- This option will add an environment variable setting to
- the PLUGIN plugin. This will
- override any inherited environment variables or
- environment variables specified using
- .
-
-
-
-
-
-
-
-
-
- Pass some options to all plugins.
- OPTIONS is a comma separated
- list of options. This is not a very useful option, except
- for specifying the
- option to all plugins.
-
-
-
-
-
-
-
-
-
- Pass some options to a specific plugin. PLUGIN is the name (file basename) of a
- plugin, and OPTIONS is a comma
- separated list of options.
-
-
- Note that since options are not split on whitespace, the
- way to pass, to the plugin
- foo
, the option
- with the option argument
- baz
is either
- --options-for=foo:--bar=baz or
- --options-for=foo:--bar,baz. Using
- --options-for="foo:--bar baz". will
- not work.
-
-
-
-
-
-
-
-
-
- Disable the plugin named
- PLUGIN. The plugin will not be
- started.
-
-
-
-
-
-
-
-
-
- Re-enable the plugin named
- PLUGIN. This is only useful to
- undo a previous option, maybe
- from the configuration file.
-
-
-
-
-
-
-
-
- Change to group ID ID on
- startup. The default is 65534. All plugins will be
- started using this group ID. Note:
- This must be a number, not a name.
-
-
-
-
-
-
-
-
- Change to user ID ID on
- startup. The default is 65534. All plugins will be
- started using this user ID. Note:
- This must be a number, not a name.
-
-
-
-
-
-
-
-
- Specify a different plugin directory. The default is
- /lib/mandos/plugins.d, which will
- exist in the initial RAM disk
- environment.
-
-
-
-
-
-
-
-
- Specify a different file to read additional options from.
- See . Other command line options
- will override options specified in the file.
-
-
-
-
-
-
-
-
- Enable debug mode. This will enable a lot of output to
- standard error about what the program is doing. The
- program will still perform all other functions normally.
- The default is to not run in debug
- mode.
-
-
- The plugins will not be affected by
- this option. Use
-
- if complete debugging eruption is desired.
-
-
-
-
-
-
-
-
-
- Gives a help message about options and their meanings.
-
-
-
-
-
-
-
-
- Gives a short usage message.
-
-
-
-
-
-
-
-
-
- Prints the program version.
-
-
-
-
-
-
-
- OVERVIEW
-
-
- This program will run on the client side in the initial
- RAM disk environment, and is responsible for
- getting a password. It does this by running plugins, one of
- which will normally be the actual client program communicating
- with the server.
-
-
-
- PLUGINS
-
- This program will get a password by running a number of
- plugins, which are simply executable
- programs in a directory in the initial RAM
- disk environment. The default directory is
- /lib/mandos/plugins.d, but this can be
- changed with the option. The
- plugins are started in parallel, and the first plugin to output
- a password and exit with a successful exit
- code will make this plugin-runner output the password from that
- plugin, stop any other plugins, and exit.
-
-
-
- WRITING PLUGINS
-
- A plugin is simply a program which prints a password to its
- standard output and then exits with a successful (zero) exit
- status. If the exit status is not zero, any output on
- standard output will be ignored by the plugin runner. Any
- output on its standard error channel will simply be passed to
- the standard error of the plugin runner, usually the system
- console.
-
-
- If the password is a single-line, manually entered passprase,
- a final trailing newline character should
- not be printed.
-
-
- The plugin will run in the initial RAM disk environment, so
- care must be taken not to depend on any files or running
- services not available there.
-
-
- The plugin must exit cleanly and free all allocated resources
- upon getting the TERM signal, since this is what the plugin
- runner uses to stop all other plugins when one plugin has
- output a password and exited cleanly.
-
-
- The plugin must not use resources, like for instance reading
- from the standard input, without knowing that no other plugin
- is also using it.
-
-
- It is useful, but not required, for the plugin to take the
- option.
-
-
-
-
-
- FALLBACK
-
- If no plugins succeed, this program will, as a fallback, ask for
- a password on the console using getpass3,
- and output it. This is not meant to be the normal mode of
- operation, as there is a separate plugin for getting a password
- from the console.
-
-
-
-
- EXIT STATUS
-
- Exit status of this program is zero if no errors were
- encountered, and otherwise not. The fallback (see ) may or may not have succeeded in either
- case.
-
-
-
-
- ENVIRONMENT
-
- This program does not use any environment variables itself, it
- only passes on its environment to all the plugins. The
- environment passed to plugins can be modified using the
- and
- options.
-
-
-
-
- FILES
-
-
-
- /conf/conf.d/mandos/plugin-runner.conf
-
-
- Since this program will be run as a keyscript, there is
- little to no opportunity to pass command line arguments
- to it. Therefore, it will also
- read this file and use its contents as
- whitespace-separated command line options. Also,
- everything from a #
character to the end
- of a line is ignored.
-
-
- This program is meant to run in the initial RAM disk
- environment, so that is where this file is assumed to
- exist. The file does not need to exist in the normal
- file system.
-
-
- This file will be processed before
- the normal command line options, so the latter can
- override the former, if need be.
-
-
- This file name is the default; the file to read for
- arguments can be changed using the
- option.
-
-
-
-
-
-
-
-
- BUGS
-
- The option is ignored when
- specified from within a configuration file.
-
-
-
-
- EXAMPLE
-
-
- Normal invocation needs no options:
-
-
- &COMMANDNAME;
-
-
-
-
- Run the program, but not the plugins, in debug mode:
-
-
-
-
- &COMMANDNAME; --debug
-
-
-
-
-
- Run all plugins, but run the foo
plugin in
- debug mode:
-
-
-
-
- &COMMANDNAME; --options-for=foo:--debug
-
-
-
-
-
- Run all plugins, but not the program, in debug mode:
-
-
-
-
- &COMMANDNAME; --global-options=--debug
-
-
-
-
-
- Run plugins from a different directory, read a different
- configuration file, and add two options to the
- mandos-client
- 8mandos plugin:
-
-
-
-
-&COMMANDNAME; --config-file=/etc/mandos/plugin-runner.conf --plugin-dir /usr/lib/mandos/plugins.d --options-for=mandos-client:--pubkey=/etc/keys/mandos/pubkey.txt,--seckey=/etc/keys/mandos/seckey.txt
-
-
-
-
-
- SECURITY
-
- This program will, when starting, try to switch to another user.
- If it is started as root, it will succeed, and will by default
- switch to user and group 65534, which are assumed to be
- non-privileged. This user and group is then what all plugins
- will be started as. Therefore, the only way to run a plugin as
- a privileged user is to have the set-user-ID or set-group-ID bit
- set on the plugin executable file (see
- execve2
- ).
-
-
- If this program is used as a keyscript in crypttab5
- , there is a slight risk that if this program
- fails to work, there might be no way to boot the system except
- for booting from another media and editing the initial RAM disk
- image to not run this program. This is, however, unlikely,
- since the password-prompt8mandos
- plugin will read a password from the console in
- case of failure of the other plugins, and this plugin runner
- will also, in case of catastrophic failure, itself fall back to
- asking and outputting a password on the console (see ).
-
-
-
-
- SEE ALSO
-
- cryptsetup
- 8,
- crypttab
- 5,
- execve
- 2,
- mandos
- 8,
- password-prompt
- 8mandos,
- mandos-client
- 8mandos
-
-
-
-
-
-
-
-
-
=== removed file 'plugins.d/mandos-client.xml'
--- plugins.d/mandos-client.xml 2008-09-06 16:33:08 +0000
+++ plugins.d/mandos-client.xml 1970-01-01 00:00:00 +0000
@@ -1,610 +0,0 @@
-
-
-
-
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &VERSION;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2008
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8mandos
-
-
-
- &COMMANDNAME;
-
- Client for Mandos
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is a client program that
- communicates with mandos8
- to get a password. It uses IPv6 link-local addresses to get
- network connectivity, Zeroconf to find servers, and TLS with an
- OpenPGP key to ensure authenticity and confidentiality. It
- keeps running, trying all servers on the network, until it
- receives a satisfactory reply or a TERM signal is received.
-
-
- This program is not meant to be run directly; it is really meant
- to run as a plugin of the Mandos
- plugin-runner
- 8mandos, which runs in the
- initial RAM disk environment because it is
- specified as a keyscript
in the
- crypttab5
- file.
-
-
-
-
- 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
-
- This program is commonly not invoked from the command line; it
- is normally started by the Mandos
- plugin runner, see plugin-runner8mandos
- . Any command line options this program accepts
- are therefore normally provided by the plugin runner, and not
- directly.
-
-
-
-
-
-
-
-
- Do not use Zeroconf to locate servers. Connect directly
- to only one specified Mandos
- server. Note that an IPv6 address has colon characters in
- it, so the last colon character is
- assumed to separate the address from the port number.
-
-
- This option is normally only useful for testing and
- debugging.
-
-
-
-
-
-
-
-
-
- Network interface that will be brought up and scanned for
- Mandos servers to connect to. The default it
- eth0
.
-
-
- If the option is used, this
- specifies the interface to use to connect to the address
- given.
-
-
-
-
-
-
-
-
-
- OpenPGP public key file name. The default name is
- /conf/conf.d/mandos/pubkey.txt
.
-
-
-
-
-
-
-
-
-
- OpenPGP secret key file name. The default name is
- /conf/conf.d/mandos/seckey.txt
.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Sets the number of bits to use for the prime number in the
- TLS Diffie-Hellman key exchange. Default is 1024.
-
-
-
-
-
-
-
-
- Enable debug mode. This will enable a lot of output to
- standard error about what the program is doing. The
- program will still perform all other functions normally.
-
-
- It will also enable debug mode in the Avahi and GnuTLS
- libraries, making them print large amounts of debugging
- output.
-
-
-
-
-
-
-
-
-
- Gives a help message about options and their meanings.
-
-
-
-
-
-
-
-
- Gives a short usage message.
-
-
-
-
-
-
-
-
-
- Prints the program version.
-
-
-
-
-
-
-
- OVERVIEW
-
-
- This program is the client part. It is a plugin started by
- plugin-runner
- 8mandos which will run in
- an initial RAM disk environment.
-
-
- This program could, theoretically, be used as a keyscript in
- /etc/crypttab, but it would then be
- impossible to enter a password for the encrypted root disk at
- the console, since this program does not read from the console
- at all. This is why a separate plugin runner (
- plugin-runner
- 8mandos) is used to run
- both this program and others in in parallel,
- one of which will prompt for passwords on
- the system console.
-
-
-
-
- EXIT STATUS
-
- This program will exit with a successful (zero) exit status if a
- server could be found and the password received from it could be
- successfully decrypted and output on standard output. The
- program will exit with a non-zero exit status only if a critical
- error occurs. Otherwise, it will forever connect to new
- Mandos servers as they appear, trying
- to get a decryptable password and print it.
-
-
-
-
- ENVIRONMENT
-
- This program does not use any environment variables, not even
- the ones provided by cryptsetup8
- .
-
-
-
-
- FILES
-
-
- /conf/conf.d/mandos/pubkey.txt
- /conf/conf.d/mandos/seckey.txt
-
-
- OpenPGP public and private key files, in ASCII
- Armor
format. These are the default file names,
- they can be changed with the and
- options.
-
-
-
-
-
-
-
-
-
-
-
-
-
- EXAMPLE
-
- Note that normally, command line options will not be given
- directly, but via options for the Mandos plugin-runner
- 8mandos.
-
-
-
- Normal invocation needs no options, if the network interface
- is eth0
:
-
-
- &COMMANDNAME;
-
-
-
-
- Search for Mandos servers (and connect to them) using another
- interface:
-
-
-
- &COMMANDNAME; --interface eth1
-
-
-
-
- Run in debug mode, and use a custom key:
-
-
-
-
-&COMMANDNAME; --debug --pubkey keydir/pubkey.txt --seckey keydir/seckey.txt
-
-
-
-
-
- Run in debug mode, with a custom key, and do not use Zeroconf
- to locate a server; connect directly to the IPv6 address
- 2001:db8:f983:bd0b:30de:ae4a:71f2:f672
,
- port 4711, using interface eth2:
-
-
-
-
-&COMMANDNAME; --debug --pubkey keydir/pubkey.txt --seckey keydir/seckey.txt --connect 2001:db8:f983:bd0b:30de:ae4a:71f2:f672:4711 --interface eth2
-
-
-
-
-
-
- SECURITY
-
- This program is set-uid to root, but will switch back to the
- original (and presumably non-privileged) user and group after
- bringing up the network interface.
-
-
- To use this program for its intended purpose (see ), the password for the root file system will
- have to be given out to be stored in a server computer, after
- having been encrypted using an OpenPGP key. This encrypted data
- which will be stored in a server can only be decrypted by the
- OpenPGP key, and the data will only be given out to those
- clients who can prove they actually have that key. This key,
- however, is stored unencrypted on the client side in its initial
- RAM disk image file system. This is normally
- readable by all, but this is normally fixed during installation
- of this program; file permissions are set so that no-one is able
- to read that file.
-
-
- The only remaining weak point is that someone with physical
- access to the client hard drive might turn off the client
- computer, read the OpenPGP keys directly from the hard drive,
- and communicate with the server. The defense against this is
- that the server is supposed to notice the client disappearing
- and will stop giving out the encrypted data. Therefore, it is
- important to set the timeout and checker interval values tightly
- on the server. See mandos8.
-
-
- It will also help if the checker program on the server is
- configured to request something from the client which can not be
- spoofed by someone else on the network, unlike unencrypted
- ICMP echo (ping
) replies.
-
-
- Note: This makes it completely insecure to
- have Mandos clients which dual-boot
- to another operating system which is not
- trusted to keep the initial RAM disk image
- confidential.
-
-
-
-
- SEE ALSO
-
- cryptsetup
- 8,
- crypttab
- 5,
- mandos
- 8,
- password-prompt
- 8mandos,
- plugin-runner
- 8mandos
-
-
-
-
- Zeroconf
-
-
-
- Zeroconf is the network protocol standard used for finding
- Mandos servers on the local network.
-
-
-
-
-
- Avahi
-
-
-
- Avahi is the library this program calls to find Zeroconf
- services.
-
-
-
-
-
- GnuTLS
-
-
-
- GnuTLS is the library this client uses to implement TLS for
- communicating securely with the server, and at the same time
- send the public OpenPGP key to the server.
-
-
-
-
-
- GPGME
-
-
-
- GPGME is the library used to decrypt the OpenPGP data sent
- by the server.
-
-
-
-
-
- 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
-
-
- This client uses 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 4346: The Transport Layer Security (TLS)
- Protocol Version 1.1
-
-
-
- TLS 1.1 is the protocol implemented by GnuTLS.
-
-
-
-
-
- RFC 4880: OpenPGP Message Format
-
-
-
- The data received from the server is binary encrypted
- OpenPGP data.
-
-
-
-
-
- RFC 5081: Using OpenPGP Keys for Transport Layer
- Security
-
-
-
- This is implemented by GnuTLS and used by this program so
- that OpenPGP keys can be used.
-
-
-
-
-
-
-
-
-
-
-
-
=== renamed file 'plugins.d/mandos-client.c' => 'plugins.d/mandosclient.c'
--- plugins.d/mandos-client.c 2008-09-07 01:44:44 +0000
+++ plugins.d/mandosclient.c 2008-08-02 14:33:47 +0000
@@ -32,50 +32,12 @@
#define _LARGEFILE_SOURCE
#define _FILE_OFFSET_BITS 64
-#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), asprintf() */
-
-#include /* fprintf(), stderr, fwrite(),
- stdout, ferror() */
-#include /* uint16_t, uint32_t */
-#include /* NULL, size_t, ssize_t */
-#include /* free(), EXIT_SUCCESS, EXIT_FAILURE,
- srand() */
-#include /* bool, true */
-#include /* memset(), strcmp(), strlen(),
- strerror(), asprintf(), strcpy() */
-#include /* ioctl */
-#include /* socket(), inet_pton(), sockaddr,
- sockaddr_in6, PF_INET6,
- SOCK_STREAM, INET6_ADDRSTRLEN,
- uid_t, gid_t, open(), opendir(), DIR */
-#include /* open() */
-#include /* socket(), struct sockaddr_in6,
- struct in6_addr, inet_pton(),
- connect() */
-#include /* open() */
-#include /* opendir(), struct dirent, readdir() */
-#include /* PRIu16 */
-#include /* assert() */
-#include /* perror(), errno */
-#include /* time() */
-#include /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
- SIOCSIFFLAGS, if_indextoname(),
- if_nametoindex(), IF_NAMESIZE */
-#include
-#include /* close(), SEEK_SET, off_t, write(),
- getuid(), getgid(), setuid(),
- setgid() */
-#include /* inet_pton(), htons */
-#include /* not, and */
-#include /* struct argp_option, error_t, struct
- argp_state, struct argp,
- argp_parse(), ARGP_KEY_ARG,
- ARGP_KEY_END, ARGP_ERR_UNKNOWN */
-
-/* Avahi */
-/* All Avahi types, constants and functions
- Avahi*, avahi_*,
- AVAHI_* */
+#include
+#include
+#include
+#include
+#include /* if_nametoindex */
+
#include
#include
#include
@@ -83,112 +45,56 @@
#include
#include
-/* GnuTLS */
-#include /* All GnuTLS types, constants and
- functions:
- gnutls_*
- init_gnutls_session(),
- GNUTLS_* */
-#include /* gnutls_certificate_set_openpgp_key_file(),
- GNUTLS_OPENPGP_FMT_BASE64 */
-
-/* GPGME */
-#include /* All GPGME types, constants and
- functions:
- gpgme_*
- GPGME_PROTOCOL_OpenPGP,
- GPG_ERR_NO_* */
+//mandos client part
+#include /* socket(), inet_pton() */
+#include /* socket(), struct sockaddr_in6,
+ struct in6_addr, inet_pton() */
+#include /* All GnuTLS stuff */
+#include /* GnuTLS with openpgp stuff */
+
+#include /* close() */
+#include
+#include /* true */
+#include /* memset */
+#include /* inet_pton() */
+#include /* not */
+
+// gpgme
+#include /* perror() */
+#include
+
+// getopt long
+#include
#define BUFFER_SIZE 256
-
-/*
- #define PATHDIR "/conf/conf.d/mandos"
-*/
-
-#define PATHDIR "/conf/conf.d/mandos"
-#define SECKEY "seckey.txt"
-#define PUBKEY "pubkey.txt"
+#define DH_BITS 1024
+
+static const char *certdir = "/conf/conf.d/mandos";
+static const char *certfile = "openpgp-client.txt";
+static const char *certkey = "openpgp-client-key.txt";
bool debug = false;
-static const char mandos_protocol_version[] = "1";
-const char *argp_program_version = "mandos-client 1.0";
-const char *argp_program_bug_address = "";
-/* Used for passing in values through the Avahi callback functions */
typedef struct {
- AvahiSimplePoll *simple_poll;
- AvahiServer *server;
+ gnutls_session_t session;
gnutls_certificate_credentials_t cred;
- unsigned int dh_bits;
gnutls_dh_params_t dh_params;
- const char *priority;
+} encrypted_session;
+
+
+static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
+ char **new_packet,
+ const char *homedir){
+ gpgme_data_t dh_crypto, dh_plain;
gpgme_ctx_t ctx;
-} mandos_context;
-
-/*
- * Make room in "buffer" for at least BUFFER_SIZE additional bytes.
- * "buffer_capacity" is how much is currently allocated,
- * "buffer_length" is how much is already used.
- */
-size_t adjustbuffer(char **buffer, size_t buffer_length,
- size_t buffer_capacity){
- if (buffer_length + BUFFER_SIZE > buffer_capacity){
- *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
- if (buffer == NULL){
- return 0;
- }
- buffer_capacity += BUFFER_SIZE;
- }
- return buffer_capacity;
-}
-
-/*
- * Initialize GPGME.
- */
-static bool init_gpgme(mandos_context *mc, const char *seckey,
- const char *pubkey, const char *tempdir){
- int ret;
gpgme_error_t rc;
+ ssize_t ret;
+ ssize_t new_packet_capacity = 0;
+ ssize_t new_packet_length = 0;
gpgme_engine_info_t engine_info;
-
-
- /*
- * Helper function to insert pub and seckey to the enigne keyring.
- */
- bool import_key(const char *filename){
- int fd;
- gpgme_data_t pgp_data;
-
- fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
- if(fd == -1){
- perror("open");
- return false;
- }
-
- rc = gpgme_data_new_from_fd(&pgp_data, fd);
- if (rc != GPG_ERR_NO_ERROR){
- fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
- gpgme_strsource(rc), gpgme_strerror(rc));
- return false;
- }
-
- rc = gpgme_op_import(mc->ctx, pgp_data);
- if (rc != GPG_ERR_NO_ERROR){
- fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
- gpgme_strsource(rc), gpgme_strerror(rc));
- return false;
- }
-
- ret = TEMP_FAILURE_RETRY(close(fd));
- if(ret == -1){
- perror("close");
- }
- gpgme_data_release(pgp_data);
- return true;
- }
-
+
if (debug){
- fprintf(stderr, "Initialize gpgme\n");
+ fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
}
/* Init GPGME */
@@ -197,65 +103,31 @@
if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
- return false;
+ return -1;
}
- /* Set GPGME home directory for the OpenPGP engine only */
+ /* Set GPGME home directory */
rc = gpgme_get_engine_info (&engine_info);
if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
- return false;
+ return -1;
}
while(engine_info != NULL){
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
- engine_info->file_name, tempdir);
+ engine_info->file_name, homedir);
break;
}
engine_info = engine_info->next;
}
if(engine_info == NULL){
- fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
- return false;
- }
-
- /* Create new GPGME "context" */
- rc = gpgme_new(&(mc->ctx));
- if (rc != GPG_ERR_NO_ERROR){
- fprintf(stderr, "bad gpgme_new: %s: %s\n",
- gpgme_strsource(rc), gpgme_strerror(rc));
- return false;
- }
-
- if (not import_key(pubkey) or not import_key(seckey)){
- return false;
- }
-
- return true;
-}
-
-/*
- * Decrypt OpenPGP data.
- * Returns -1 on error
- */
-static ssize_t pgp_packet_decrypt (const mandos_context *mc,
- const char *cryptotext,
- size_t crypto_size,
- char **plaintext){
- gpgme_data_t dh_crypto, dh_plain;
- gpgme_error_t rc;
- ssize_t ret;
- size_t plaintext_capacity = 0;
- ssize_t plaintext_length = 0;
-
- if (debug){
- fprintf(stderr, "Trying to decrypt OpenPGP data\n");
- }
-
- /* Create new GPGME data buffer from memory cryptotext */
- rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
- 0);
+ fprintf(stderr, "Could not set home dir to %s\n", homedir);
+ return -1;
+ }
+
+ /* Create new GPGME data buffer from packet buffer */
+ rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
@@ -267,262 +139,232 @@
if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
- gpgme_data_release(dh_crypto);
- return -1;
- }
-
- /* Decrypt data from the cryptotext data buffer to the plaintext
- data buffer */
- rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
+ return -1;
+ }
+
+ /* Create new GPGME "context" */
+ rc = gpgme_new(&ctx);
+ if (rc != GPG_ERR_NO_ERROR){
+ fprintf(stderr, "bad gpgme_new: %s: %s\n",
+ gpgme_strsource(rc), gpgme_strerror(rc));
+ return -1;
+ }
+
+ /* Decrypt data from the FILE pointer to the plaintext data
+ buffer */
+ rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
- plaintext_length = -1;
- if (debug){
- gpgme_decrypt_result_t result;
- result = gpgme_op_decrypt_result(mc->ctx);
- if (result == NULL){
- fprintf(stderr, "gpgme_op_decrypt_result failed\n");
- } else {
- fprintf(stderr, "Unsupported algorithm: %s\n",
- result->unsupported_algorithm);
- fprintf(stderr, "Wrong key usage: %u\n",
- result->wrong_key_usage);
- if(result->file_name != NULL){
- fprintf(stderr, "File name: %s\n", result->file_name);
- }
- gpgme_recipient_t recipient;
- recipient = result->recipients;
- if(recipient){
- while(recipient != NULL){
- fprintf(stderr, "Public key algorithm: %s\n",
- gpgme_pubkey_algo_name(recipient->pubkey_algo));
- fprintf(stderr, "Key ID: %s\n", recipient->keyid);
- fprintf(stderr, "Secret key available: %s\n",
- recipient->status == GPG_ERR_NO_SECKEY
- ? "No" : "Yes");
- recipient = recipient->next;
- }
+ return -1;
+ }
+
+ if(debug){
+ fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
+ }
+
+ if (debug){
+ gpgme_decrypt_result_t result;
+ result = gpgme_op_decrypt_result(ctx);
+ if (result == NULL){
+ fprintf(stderr, "gpgme_op_decrypt_result failed\n");
+ } else {
+ fprintf(stderr, "Unsupported algorithm: %s\n",
+ result->unsupported_algorithm);
+ fprintf(stderr, "Wrong key usage: %d\n",
+ result->wrong_key_usage);
+ if(result->file_name != NULL){
+ fprintf(stderr, "File name: %s\n", result->file_name);
+ }
+ gpgme_recipient_t recipient;
+ recipient = result->recipients;
+ if(recipient){
+ while(recipient != NULL){
+ fprintf(stderr, "Public key algorithm: %s\n",
+ gpgme_pubkey_algo_name(recipient->pubkey_algo));
+ fprintf(stderr, "Key ID: %s\n", recipient->keyid);
+ fprintf(stderr, "Secret key available: %s\n",
+ recipient->status == GPG_ERR_NO_SECKEY
+ ? "No" : "Yes");
+ recipient = recipient->next;
}
}
}
- goto decrypt_end;
}
- if(debug){
- fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
- }
+ /* Delete the GPGME FILE pointer cryptotext data buffer */
+ gpgme_data_release(dh_crypto);
/* Seek back to the beginning of the GPGME plaintext data buffer */
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
- perror("gpgme_data_seek");
- plaintext_length = -1;
- goto decrypt_end;
+ perror("pgpme_data_seek");
}
- *plaintext = NULL;
+ *new_packet = 0;
while(true){
- plaintext_capacity = adjustbuffer(plaintext,
- (size_t)plaintext_length,
- plaintext_capacity);
- if (plaintext_capacity == 0){
- perror("adjustbuffer");
- plaintext_length = -1;
- goto decrypt_end;
+ if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
+ *new_packet = realloc(*new_packet,
+ (unsigned int)new_packet_capacity
+ + BUFFER_SIZE);
+ if (*new_packet == NULL){
+ perror("realloc");
+ return -1;
+ }
+ new_packet_capacity += BUFFER_SIZE;
}
- ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
+ ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
BUFFER_SIZE);
/* Print the data, if any */
if (ret == 0){
- /* EOF */
break;
}
if(ret < 0){
perror("gpgme_data_read");
- plaintext_length = -1;
- goto decrypt_end;
- }
- plaintext_length += ret;
- }
-
- if(debug){
- fprintf(stderr, "Decrypted password is: ");
- for(ssize_t i = 0; i < plaintext_length; i++){
- fprintf(stderr, "%02hhX ", (*plaintext)[i]);
- }
- fprintf(stderr, "\n");
- }
-
- decrypt_end:
-
- /* Delete the GPGME cryptotext data buffer */
- gpgme_data_release(dh_crypto);
+ return -1;
+ }
+ new_packet_length += ret;
+ }
+
+ /* FIXME: check characters before printing to screen so to not print
+ terminal control characters */
+ /* if(debug){ */
+ /* fprintf(stderr, "decrypted password is: "); */
+ /* fwrite(*new_packet, 1, new_packet_length, stderr); */
+ /* fprintf(stderr, "\n"); */
+ /* } */
/* Delete the GPGME plaintext data buffer */
gpgme_data_release(dh_plain);
- return plaintext_length;
+ return new_packet_length;
}
static const char * safer_gnutls_strerror (int value) {
- const char *ret = gnutls_strerror (value); /* Spurious warning */
+ const char *ret = gnutls_strerror (value);
if (ret == NULL)
ret = "(unknown)";
return ret;
}
-/* GnuTLS log function callback */
static void debuggnutls(__attribute__((unused)) int level,
const char* string){
- fprintf(stderr, "GnuTLS: %s", string);
+ fprintf(stderr, "%s", string);
}
-static int init_gnutls_global(mandos_context *mc,
- const char *pubkeyfilename,
- const char *seckeyfilename){
+static int initgnutls(encrypted_session *es){
+ const char *err;
int ret;
if(debug){
fprintf(stderr, "Initializing GnuTLS\n");
}
-
- ret = gnutls_global_init();
- if (ret != GNUTLS_E_SUCCESS) {
- fprintf (stderr, "GnuTLS global_init: %s\n",
- safer_gnutls_strerror(ret));
+
+ if ((ret = gnutls_global_init ())
+ != GNUTLS_E_SUCCESS) {
+ fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
return -1;
}
-
+
if (debug){
- /* "Use a log level over 10 to enable all debugging options."
- * - GnuTLS manual
- */
gnutls_global_set_log_level(11);
gnutls_global_set_log_function(debuggnutls);
}
- /* OpenPGP credentials */
- gnutls_certificate_allocate_credentials(&mc->cred);
- if (ret != GNUTLS_E_SUCCESS){
- fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
- warning */
+ /* openpgp credentials */
+ if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
+ != GNUTLS_E_SUCCESS) {
+ fprintf (stderr, "memory error: %s\n",
safer_gnutls_strerror(ret));
- gnutls_global_deinit ();
return -1;
}
if(debug){
- fprintf(stderr, "Attempting to use OpenPGP public key %s and"
- " secret key %s as GnuTLS credentials\n", pubkeyfilename,
- seckeyfilename);
+ fprintf(stderr, "Attempting to use OpenPGP certificate %s"
+ " and keyfile %s as GnuTLS credentials\n", certfile,
+ certkey);
}
ret = gnutls_certificate_set_openpgp_key_file
- (mc->cred, pubkeyfilename, seckeyfilename,
- GNUTLS_OPENPGP_FMT_BASE64);
+ (es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
if (ret != GNUTLS_E_SUCCESS) {
- fprintf(stderr,
- "Error[%d] while reading the OpenPGP key pair ('%s',"
- " '%s')\n", ret, pubkeyfilename, seckeyfilename);
- fprintf(stderr, "The GnuTLS error is: %s\n",
+ fprintf
+ (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
+ " '%s')\n",
+ ret, certfile, certkey);
+ fprintf(stdout, "The Error is: %s\n",
safer_gnutls_strerror(ret));
- goto globalfail;
- }
-
- /* GnuTLS server initialization */
- ret = gnutls_dh_params_init(&mc->dh_params);
- if (ret != GNUTLS_E_SUCCESS) {
- fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
- " %s\n", safer_gnutls_strerror(ret));
- goto globalfail;
- }
- ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
- if (ret != GNUTLS_E_SUCCESS) {
- fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
- safer_gnutls_strerror(ret));
- goto globalfail;
- }
-
- gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
-
- return 0;
-
- globalfail:
-
- gnutls_certificate_free_credentials(mc->cred);
- gnutls_global_deinit();
- gnutls_dh_params_deinit(mc->dh_params);
- return -1;
-}
-
-static int init_gnutls_session(mandos_context *mc,
- gnutls_session_t *session){
- int ret;
- /* GnuTLS session creation */
- ret = gnutls_init(session, GNUTLS_SERVER);
- if (ret != GNUTLS_E_SUCCESS){
+ return -1;
+ }
+
+ //GnuTLS server initialization
+ if ((ret = gnutls_dh_params_init (&es->dh_params))
+ != GNUTLS_E_SUCCESS) {
+ fprintf (stderr, "Error in dh parameter initialization: %s\n",
+ safer_gnutls_strerror(ret));
+ return -1;
+ }
+
+ if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
+ != GNUTLS_E_SUCCESS) {
+ fprintf (stderr, "Error in prime generation: %s\n",
+ safer_gnutls_strerror(ret));
+ return -1;
+ }
+
+ gnutls_certificate_set_dh_params (es->cred, es->dh_params);
+
+ // GnuTLS session creation
+ if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
+ != GNUTLS_E_SUCCESS){
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
safer_gnutls_strerror(ret));
}
- {
- const char *err;
- ret = gnutls_priority_set_direct(*session, mc->priority, &err);
- if (ret != GNUTLS_E_SUCCESS) {
- fprintf(stderr, "Syntax error at: %s\n", err);
- fprintf(stderr, "GnuTLS error: %s\n",
- safer_gnutls_strerror(ret));
- gnutls_deinit (*session);
- return -1;
- }
+ if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
+ != GNUTLS_E_SUCCESS) {
+ fprintf(stderr, "Syntax error at: %s\n", err);
+ fprintf(stderr, "GnuTLS error: %s\n",
+ safer_gnutls_strerror(ret));
+ return -1;
}
- ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
- mc->cred);
- if (ret != GNUTLS_E_SUCCESS) {
- fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
+ if ((ret = gnutls_credentials_set
+ (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
+ != GNUTLS_E_SUCCESS) {
+ fprintf(stderr, "Error setting a credentials set: %s\n",
safer_gnutls_strerror(ret));
- gnutls_deinit (*session);
return -1;
}
/* ignore client certificate if any. */
- gnutls_certificate_server_set_request (*session,
+ gnutls_certificate_server_set_request (es->session,
GNUTLS_CERT_IGNORE);
- gnutls_dh_set_prime_bits (*session, mc->dh_bits);
+ gnutls_dh_set_prime_bits (es->session, DH_BITS);
return 0;
}
-/* Avahi log function callback */
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
__attribute__((unused)) const char *txt){}
-/* Called when a Mandos server is found */
static int start_mandos_communication(const char *ip, uint16_t port,
- AvahiIfIndex if_index,
- mandos_context *mc){
+ AvahiIfIndex if_index){
int ret, tcp_sd;
- union { struct sockaddr in; struct sockaddr_in6 in6; } to;
+ struct sockaddr_in6 to;
+ encrypted_session es;
char *buffer = NULL;
char *decrypted_buffer;
size_t buffer_length = 0;
size_t buffer_capacity = 0;
ssize_t decrypted_buffer_size;
- size_t written;
+ size_t written = 0;
int retval = 0;
char interface[IF_NAMESIZE];
- gnutls_session_t session;
-
- ret = init_gnutls_session (mc, &session);
- if (ret != 0){
- return -1;
- }
if(debug){
- fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
- "\n", ip, port);
+ fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
+ ip, port);
}
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
@@ -531,112 +373,93 @@
return -1;
}
- if(debug){
- if(if_indextoname((unsigned int)if_index, interface) == NULL){
+ if(if_indextoname((unsigned int)if_index, interface) == NULL){
+ if(debug){
perror("if_indextoname");
- return -1;
}
+ return -1;
+ }
+
+ if(debug){
fprintf(stderr, "Binding to interface %s\n", interface);
}
- memset(&to, 0, sizeof(to));
- to.in6.sin6_family = AF_INET6;
- /* It would be nice to have a way to detect if we were passed an
- IPv4 address here. Now we assume an IPv6 address. */
- ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
+ memset(&to,0,sizeof(to)); /* Spurious warning */
+ to.sin6_family = AF_INET6;
+ ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
if (ret < 0 ){
perror("inet_pton");
return -1;
- }
+ }
if(ret == 0){
fprintf(stderr, "Bad address: %s\n", ip);
return -1;
}
- to.in6.sin6_port = htons(port); /* Spurious warning */
+ to.sin6_port = htons(port); /* Spurious warning */
- to.in6.sin6_scope_id = (uint32_t)if_index;
+ to.sin6_scope_id = (uint32_t)if_index;
if(debug){
- fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
- port);
- char addrstr[INET6_ADDRSTRLEN] = "";
- if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
- sizeof(addrstr)) == NULL){
- perror("inet_ntop");
- } else {
- if(strcmp(addrstr, ip) != 0){
- fprintf(stderr, "Canonical address form: %s\n", addrstr);
- }
- }
+ fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
+/* char addrstr[INET6_ADDRSTRLEN]; */
+/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
+/* sizeof(addrstr)) == NULL){ */
+/* perror("inet_ntop"); */
+/* } else { */
+/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
+/* addrstr, ntohs(to.sin6_port)); */
+/* } */
}
- ret = connect(tcp_sd, &to.in, sizeof(to));
+ ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
if (ret < 0){
perror("connect");
return -1;
}
- const char *out = mandos_protocol_version;
- written = 0;
- while (true){
- size_t out_size = strlen(out);
- ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
- out_size - written));
- if (ret == -1){
- perror("write");
- retval = -1;
- goto mandos_end;
- }
- written += (size_t)ret;
- if(written < out_size){
- continue;
- } else {
- if (out == mandos_protocol_version){
- written = 0;
- out = "\r\n";
- } else {
- break;
- }
- }
+ ret = initgnutls (&es);
+ if (ret != 0){
+ retval = -1;
+ return -1;
}
+ gnutls_transport_set_ptr (es.session,
+ (gnutls_transport_ptr_t) tcp_sd);
+
if(debug){
fprintf(stderr, "Establishing TLS session with %s\n", ip);
}
- gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
-
- do{
- ret = gnutls_handshake (session);
- } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
+ ret = gnutls_handshake (es.session);
if (ret != GNUTLS_E_SUCCESS){
if(debug){
- fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
+ fprintf(stderr, "\n*** Handshake failed ***\n");
gnutls_perror (ret);
}
retval = -1;
- goto mandos_end;
+ goto exit;
}
- /* Read OpenPGP packet that contains the wanted password */
+ //Retrieve OpenPGP packet that contains the wanted password
if(debug){
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
ip);
}
-
+
while(true){
- buffer_capacity = adjustbuffer(&buffer, buffer_length,
- buffer_capacity);
- if (buffer_capacity == 0){
- perror("adjustbuffer");
- retval = -1;
- goto mandos_end;
+ if (buffer_length + BUFFER_SIZE > buffer_capacity){
+ buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
+ if (buffer == NULL){
+ perror("realloc");
+ goto exit;
+ }
+ buffer_capacity += BUFFER_SIZE;
}
- ret = gnutls_record_recv(session, buffer+buffer_length,
- BUFFER_SIZE);
+ ret = gnutls_record_recv
+ (es.session, buffer+buffer_length, BUFFER_SIZE);
if (ret == 0){
break;
}
@@ -646,40 +469,32 @@
case GNUTLS_E_AGAIN:
break;
case GNUTLS_E_REHANDSHAKE:
- do{
- ret = gnutls_handshake (session);
- } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
+ ret = gnutls_handshake (es.session);
if (ret < 0){
- fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
+ fprintf(stderr, "\n*** Handshake failed ***\n");
gnutls_perror (ret);
retval = -1;
- goto mandos_end;
+ goto exit;
}
break;
default:
fprintf(stderr, "Unknown error while reading data from"
- " encrypted session with Mandos server\n");
+ " encrypted session with mandos server\n");
retval = -1;
- gnutls_bye (session, GNUTLS_SHUT_RDWR);
- goto mandos_end;
+ gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
+ goto exit;
}
} else {
buffer_length += (size_t) ret;
}
}
- if(debug){
- fprintf(stderr, "Closing TLS session\n");
- }
-
- gnutls_bye (session, GNUTLS_SHUT_RDWR);
-
if (buffer_length > 0){
- decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
+ decrypted_buffer_size = pgp_packet_decrypt(buffer,
buffer_length,
- &decrypted_buffer);
+ &decrypted_buffer,
+ certdir);
if (decrypted_buffer_size >= 0){
- written = 0;
while(written < (size_t) decrypted_buffer_size){
ret = (int)fwrite (decrypted_buffer + written, 1,
(size_t)decrypted_buffer_size - written,
@@ -698,38 +513,43 @@
} else {
retval = -1;
}
- } else {
- retval = -1;
- }
-
- /* Shutdown procedure */
-
- mandos_end:
+ }
+
+ //shutdown procedure
+
+ if(debug){
+ fprintf(stderr, "Closing TLS session\n");
+ }
+
free(buffer);
- ret = TEMP_FAILURE_RETRY(close(tcp_sd));
- if(ret == -1){
- perror("close");
- }
- gnutls_deinit (session);
+ gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
+ exit:
+ close(tcp_sd);
+ gnutls_deinit (es.session);
+ gnutls_certificate_free_credentials (es.cred);
+ gnutls_global_deinit ();
return retval;
}
-static void resolve_callback(AvahiSServiceResolver *r,
- AvahiIfIndex interface,
- AVAHI_GCC_UNUSED AvahiProtocol protocol,
- AvahiResolverEvent event,
- const char *name,
- const char *type,
- const char *domain,
- const char *host_name,
- const AvahiAddress *address,
- uint16_t port,
- AVAHI_GCC_UNUSED AvahiStringList *txt,
- AVAHI_GCC_UNUSED AvahiLookupResultFlags
- flags,
- void* userdata) {
- mandos_context *mc = userdata;
- assert(r);
+static AvahiSimplePoll *simple_poll = NULL;
+static AvahiServer *server = NULL;
+
+static void resolve_callback(
+ AvahiSServiceResolver *r,
+ AvahiIfIndex interface,
+ AVAHI_GCC_UNUSED AvahiProtocol protocol,
+ AvahiResolverEvent event,
+ const char *name,
+ const char *type,
+ const char *domain,
+ const char *host_name,
+ const AvahiAddress *address,
+ uint16_t port,
+ AVAHI_GCC_UNUSED AvahiStringList *txt,
+ AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
+ AVAHI_GCC_UNUSED void* userdata) {
+
+ assert(r); /* Spurious warning */
/* Called whenever a service has been resolved successfully or
timed out */
@@ -737,9 +557,9 @@
switch (event) {
default:
case AVAHI_RESOLVER_FAILURE:
- fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
- " of type '%s' in domain '%s': %s\n", name, type, domain,
- avahi_strerror(avahi_server_errno(mc->server)));
+ fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
+ " type '%s' in domain '%s': %s\n", name, type, domain,
+ avahi_strerror(avahi_server_errno(server)));
break;
case AVAHI_RESOLVER_FOUND:
@@ -747,248 +567,151 @@
char ip[AVAHI_ADDRESS_STR_MAX];
avahi_address_snprint(ip, sizeof(ip), address);
if(debug){
- fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
- PRIu16 ") on port %d\n", name, host_name, ip,
- interface, port);
+ fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
+ " port %d\n", name, host_name, ip, port);
}
- int ret = start_mandos_communication(ip, port, interface, mc);
+ int ret = start_mandos_communication(ip, port, interface);
if (ret == 0){
- avahi_simple_poll_quit(mc->simple_poll);
+ exit(EXIT_SUCCESS);
}
}
}
avahi_s_service_resolver_free(r);
}
-static void browse_callback( AvahiSServiceBrowser *b,
- AvahiIfIndex interface,
- AvahiProtocol protocol,
- AvahiBrowserEvent event,
- const char *name,
- const char *type,
- const char *domain,
- AVAHI_GCC_UNUSED AvahiLookupResultFlags
- flags,
- void* userdata) {
- mandos_context *mc = userdata;
- assert(b);
-
- /* Called whenever a new services becomes available on the LAN or
- is removed from the LAN */
-
- switch (event) {
- default:
- case AVAHI_BROWSER_FAILURE:
-
- fprintf(stderr, "(Avahi browser) %s\n",
- avahi_strerror(avahi_server_errno(mc->server)));
- avahi_simple_poll_quit(mc->simple_poll);
- return;
-
- case AVAHI_BROWSER_NEW:
- /* We ignore the returned Avahi resolver object. In the callback
- function we free it. If the Avahi server is terminated before
- the callback function is called the Avahi server will free the
- resolver for us. */
-
- if (!(avahi_s_service_resolver_new(mc->server, interface,
- protocol, name, type, domain,
- AVAHI_PROTO_INET6, 0,
- resolve_callback, mc)))
- fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
- name, avahi_strerror(avahi_server_errno(mc->server)));
- break;
-
- case AVAHI_BROWSER_REMOVE:
- break;
-
- case AVAHI_BROWSER_ALL_FOR_NOW:
- case AVAHI_BROWSER_CACHE_EXHAUSTED:
- if(debug){
- fprintf(stderr, "No Mandos server found, still searching...\n");
+static void browse_callback(
+ AvahiSServiceBrowser *b,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiBrowserEvent event,
+ const char *name,
+ const char *type,
+ const char *domain,
+ AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
+ void* userdata) {
+
+ AvahiServer *s = userdata;
+ assert(b); /* Spurious warning */
+
+ /* Called whenever a new services becomes available on the LAN or
+ is removed from the LAN */
+
+ switch (event) {
+ default:
+ case AVAHI_BROWSER_FAILURE:
+
+ fprintf(stderr, "(Browser) %s\n",
+ avahi_strerror(avahi_server_errno(server)));
+ avahi_simple_poll_quit(simple_poll);
+ return;
+
+ case AVAHI_BROWSER_NEW:
+ /* We ignore the returned resolver object. In the callback
+ function we free it. If the server is terminated before
+ the callback function is called the server will free
+ the resolver for us. */
+
+ if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
+ type, domain,
+ AVAHI_PROTO_INET6, 0,
+ resolve_callback, s)))
+ fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
+ avahi_strerror(avahi_server_errno(s)));
+ break;
+
+ case AVAHI_BROWSER_REMOVE:
+ break;
+
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ break;
}
- break;
- }
-}
-
-int main(int argc, char *argv[]){
+}
+
+/* Combines file name and path and returns the malloced new
+ string. some sane checks could/should be added */
+static const char *combinepath(const char *first, const char *second){
+ size_t f_len = strlen(first);
+ size_t s_len = strlen(second);
+ char *tmp = malloc(f_len + s_len + 2);
+ if (tmp == NULL){
+ return NULL;
+ }
+ if(f_len > 0){
+ memcpy(tmp, first, f_len);
+ }
+ tmp[f_len] = '/';
+ if(s_len > 0){
+ memcpy(tmp + f_len + 1, second, s_len);
+ }
+ tmp[f_len + 1 + s_len] = '\0';
+ return tmp;
+}
+
+
+int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
+ AvahiServerConfig config;
AvahiSServiceBrowser *sb = NULL;
int error;
int ret;
- int exitcode = EXIT_SUCCESS;
- const char *interface = "eth0";
- struct ifreq network;
- int sd;
- uid_t uid;
- gid_t gid;
+ int returncode = EXIT_SUCCESS;
+ const char *interface = NULL;
+ AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
char *connect_to = NULL;
- char tempdir[] = "/tmp/mandosXXXXXX";
- AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
- const char *seckey = PATHDIR "/" SECKEY;
- const char *pubkey = PATHDIR "/" PUBKEY;
-
- mandos_context mc = { .simple_poll = NULL, .server = NULL,
- .dh_bits = 1024, .priority = "SECURE256"
- ":!CTYPE-X.509:+CTYPE-OPENPGP" };
- bool gnutls_initalized = false;
- bool gpgme_initalized = false;
-
- {
- struct argp_option options[] = {
- { .name = "debug", .key = 128,
- .doc = "Debug mode", .group = 3 },
- { .name = "connect", .key = 'c',
- .arg = "ADDRESS:PORT",
- .doc = "Connect directly to a specific Mandos server",
- .group = 1 },
- { .name = "interface", .key = 'i',
- .arg = "NAME",
- .doc = "Interface that will be used to search for Mandos"
- " servers",
- .group = 1 },
- { .name = "seckey", .key = 's',
- .arg = "FILE",
- .doc = "OpenPGP secret key file base name",
- .group = 1 },
- { .name = "pubkey", .key = 'p',
- .arg = "FILE",
- .doc = "OpenPGP public key file base name",
- .group = 2 },
- { .name = "dh-bits", .key = 129,
- .arg = "BITS",
- .doc = "Bit length of the prime number used in the"
- " Diffie-Hellman key exchange",
- .group = 2 },
- { .name = "priority", .key = 130,
- .arg = "STRING",
- .doc = "GnuTLS priority string for the TLS handshake",
- .group = 1 },
- { .name = NULL }
- };
-
- error_t parse_opt (int key, char *arg,
- struct argp_state *state) {
- /* Get the INPUT argument from `argp_parse', which we know is
- a pointer to our plugin list pointer. */
- switch (key) {
- case 128: /* --debug */
- debug = true;
- break;
- case 'c': /* --connect */
- connect_to = arg;
- break;
- case 'i': /* --interface */
- interface = arg;
- break;
- case 's': /* --seckey */
- seckey = arg;
- break;
- case 'p': /* --pubkey */
- pubkey = arg;
- break;
- case 129: /* --dh-bits */
- errno = 0;
- mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
- if (errno){
- perror("strtol");
- exit(EXIT_FAILURE);
- }
- break;
- case 130: /* --priority */
- mc.priority = arg;
- break;
- case ARGP_KEY_ARG:
- argp_usage (state);
- case ARGP_KEY_END:
- break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
- }
-
- struct argp argp = { .options = options, .parser = parse_opt,
- .args_doc = "",
- .doc = "Mandos client -- Get and decrypt"
- " passwords from a Mandos server" };
- ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
- if (ret == ARGP_ERR_UNKNOWN){
- fprintf(stderr, "Unknown error while parsing arguments\n");
- exitcode = EXIT_FAILURE;
- goto end;
- }
- }
-
- /* If the interface is down, bring it up */
- {
- sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
- if(sd < 0) {
- perror("socket");
- exitcode = EXIT_FAILURE;
- goto end;
- }
- strcpy(network.ifr_name, interface);
- ret = ioctl(sd, SIOCGIFFLAGS, &network);
- if(ret == -1){
- perror("ioctl SIOCGIFFLAGS");
- exitcode = EXIT_FAILURE;
- goto end;
- }
- if((network.ifr_flags & IFF_UP) == 0){
- network.ifr_flags |= IFF_UP;
- ret = ioctl(sd, SIOCSIFFLAGS, &network);
- if(ret == -1){
- perror("ioctl SIOCSIFFLAGS");
- exitcode = EXIT_FAILURE;
- goto end;
- }
- }
- ret = TEMP_FAILURE_RETRY(close(sd));
- if(ret == -1){
- perror("close");
- }
- }
-
- uid = getuid();
- gid = getgid();
-
- ret = setuid(uid);
- if (ret == -1){
- perror("setuid");
- }
-
- setgid(gid);
- if (ret == -1){
- perror("setgid");
- }
-
- ret = init_gnutls_global(&mc, pubkey, seckey);
- if (ret == -1){
- fprintf(stderr, "init_gnutls_global failed\n");
- exitcode = EXIT_FAILURE;
- goto end;
- } else {
- gnutls_initalized = true;
- }
-
- if(mkdtemp(tempdir) == NULL){
- perror("mkdtemp");
- tempdir[0] = '\0';
- goto end;
- }
-
- if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
- fprintf(stderr, "gpgme_initalized failed\n");
- exitcode = EXIT_FAILURE;
- goto end;
- } else {
- gpgme_initalized = true;
- }
-
- if_index = (AvahiIfIndex) if_nametoindex(interface);
- if(if_index == 0){
- fprintf(stderr, "No such interface: \"%s\"\n", interface);
- exit(EXIT_FAILURE);
+
+ while (true){
+ static struct option long_options[] = {
+ {"debug", no_argument, (int *)&debug, 1},
+ {"connect", required_argument, 0, 'C'},
+ {"interface", required_argument, 0, 'i'},
+ {"certdir", required_argument, 0, 'd'},
+ {"certkey", required_argument, 0, 'c'},
+ {"certfile", required_argument, 0, 'k'},
+ {0, 0, 0, 0} };
+
+ int option_index = 0;
+ ret = getopt_long (argc, argv, "i:", long_options,
+ &option_index);
+
+ if (ret == -1){
+ break;
+ }
+
+ switch(ret){
+ case 0:
+ break;
+ case 'i':
+ interface = optarg;
+ break;
+ case 'C':
+ connect_to = optarg;
+ break;
+ case 'd':
+ certdir = optarg;
+ break;
+ case 'c':
+ certfile = optarg;
+ break;
+ case 'k':
+ certkey = optarg;
+ break;
+ default:
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ certfile = combinepath(certdir, certfile);
+ if (certfile == NULL){
+ perror("combinepath");
+ goto exit;
+ }
+
+ if(interface != NULL){
+ if_index = (AvahiIfIndex) if_nametoindex(interface);
+ if(if_index == 0){
+ fprintf(stderr, "No such interface: \"%s\"\n", interface);
+ exit(EXIT_FAILURE);
+ }
}
if(connect_to != NULL){
@@ -997,151 +720,103 @@
char *address = strrchr(connect_to, ':');
if(address == NULL){
fprintf(stderr, "No colon in address\n");
- exitcode = EXIT_FAILURE;
- goto end;
+ exit(EXIT_FAILURE);
}
errno = 0;
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
if(errno){
perror("Bad port number");
- exitcode = EXIT_FAILURE;
- goto end;
+ exit(EXIT_FAILURE);
}
*address = '\0';
address = connect_to;
- ret = start_mandos_communication(address, port, if_index, &mc);
+ ret = start_mandos_communication(address, port, if_index);
if(ret < 0){
- exitcode = EXIT_FAILURE;
+ exit(EXIT_FAILURE);
} else {
- exitcode = EXIT_SUCCESS;
+ exit(EXIT_SUCCESS);
}
- goto end;
+ }
+
+ certkey = combinepath(certdir, certkey);
+ if (certkey == NULL){
+ perror("combinepath");
+ goto exit;
}
if (not debug){
avahi_set_log_function(empty_log);
}
- /* Initialize the pseudo-RNG for Avahi */
+ /* Initialize the psuedo-RNG */
srand((unsigned int) time(NULL));
-
- /* Allocate main Avahi loop object */
- mc.simple_poll = avahi_simple_poll_new();
- if (mc.simple_poll == NULL) {
- fprintf(stderr, "Avahi: Failed to create simple poll"
- " object.\n");
- exitcode = EXIT_FAILURE;
- goto end;
- }
-
- {
- AvahiServerConfig config;
- /* Do not publish any local Zeroconf records */
- avahi_server_config_init(&config);
- config.publish_hinfo = 0;
- config.publish_addresses = 0;
- config.publish_workstation = 0;
- config.publish_domain = 0;
-
- /* Allocate a new server */
- mc.server = avahi_server_new(avahi_simple_poll_get
- (mc.simple_poll), &config, NULL,
- NULL, &error);
-
- /* Free the Avahi configuration data */
- avahi_server_config_free(&config);
- }
-
- /* Check if creating the Avahi server object succeeded */
- if (mc.server == NULL) {
- fprintf(stderr, "Failed to create Avahi server: %s\n",
+
+ /* Allocate main loop object */
+ if (!(simple_poll = avahi_simple_poll_new())) {
+ fprintf(stderr, "Failed to create simple poll object.\n");
+
+ goto exit;
+ }
+
+ /* Do not publish any local records */
+ avahi_server_config_init(&config);
+ config.publish_hinfo = 0;
+ config.publish_addresses = 0;
+ config.publish_workstation = 0;
+ config.publish_domain = 0;
+
+ /* Allocate a new server */
+ server = avahi_server_new(avahi_simple_poll_get(simple_poll),
+ &config, NULL, NULL, &error);
+
+ /* Free the configuration data */
+ avahi_server_config_free(&config);
+
+ /* Check if creating the server object succeeded */
+ if (!server) {
+ fprintf(stderr, "Failed to create server: %s\n",
avahi_strerror(error));
- exitcode = EXIT_FAILURE;
- goto end;
+ returncode = EXIT_FAILURE;
+ goto exit;
}
- /* Create the Avahi service browser */
- sb = avahi_s_service_browser_new(mc.server, if_index,
+ /* Create the service browser */
+ sb = avahi_s_service_browser_new(server, if_index,
AVAHI_PROTO_INET6,
"_mandos._tcp", NULL, 0,
- browse_callback, &mc);
- if (sb == NULL) {
+ browse_callback, server);
+ if (!sb) {
fprintf(stderr, "Failed to create service browser: %s\n",
- avahi_strerror(avahi_server_errno(mc.server)));
- exitcode = EXIT_FAILURE;
- goto end;
+ avahi_strerror(avahi_server_errno(server)));
+ returncode = EXIT_FAILURE;
+ goto exit;
}
/* Run the main loop */
-
+
if (debug){
- fprintf(stderr, "Starting Avahi loop search\n");
+ fprintf(stderr, "Starting avahi loop search\n");
}
- avahi_simple_poll_loop(mc.simple_poll);
-
- end:
-
+ avahi_simple_poll_loop(simple_poll);
+
+ exit:
+
if (debug){
fprintf(stderr, "%s exiting\n", argv[0]);
}
/* Cleanup things */
- if (sb != NULL)
+ if (sb)
avahi_s_service_browser_free(sb);
- if (mc.server != NULL)
- avahi_server_free(mc.server);
-
- if (mc.simple_poll != NULL)
- avahi_simple_poll_free(mc.simple_poll);
-
- if (gnutls_initalized){
- gnutls_certificate_free_credentials(mc.cred);
- gnutls_global_deinit ();
- gnutls_dh_params_deinit(mc.dh_params);
- }
-
- if(gpgme_initalized){
- gpgme_release(mc.ctx);
- }
-
- /* Removes the temp directory used by GPGME */
- if(tempdir[0] != '\0'){
- DIR *d;
- struct dirent *direntry;
- d = opendir(tempdir);
- if(d == NULL){
- perror("opendir");
- } else {
- while(true){
- direntry = readdir(d);
- if(direntry == NULL){
- break;
- }
- if (direntry->d_type == DT_REG){
- char *fullname = NULL;
- ret = asprintf(&fullname, "%s/%s", tempdir,
- direntry->d_name);
- if(ret < 0){
- perror("asprintf");
- continue;
- }
- ret = unlink(fullname);
- if(ret == -1){
- fprintf(stderr, "unlink(\"%s\"): %s",
- fullname, strerror(errno));
- }
- free(fullname);
- }
- }
- closedir(d);
- }
- ret = rmdir(tempdir);
- if(ret == -1){
- perror("rmdir");
- }
- }
-
- return exitcode;
+ if (server)
+ avahi_server_free(server);
+
+ if (simple_poll)
+ avahi_simple_poll_free(simple_poll);
+ free(certfile);
+ free(certkey);
+
+ return returncode;
}
=== renamed file 'plugins.d/password-prompt.c' => 'plugins.d/passprompt.c'
--- plugins.d/password-prompt.c 2008-09-07 01:44:44 +0000
+++ plugins.d/passprompt.c 2008-08-02 10:48:24 +0000
@@ -33,10 +33,10 @@
sigaction, sigemptyset(),
sigaction(), sigaddset(), SIGINT,
SIGQUIT, SIGHUP, SIGTERM */
-#include /* NULL, size_t, ssize_t */
+#include /* NULL, size_t */
#include /* ssize_t */
#include /* EXIT_SUCCESS, EXIT_FAILURE,
- getopt_long, getenv() */
+ getopt_long */
#include /* fprintf(), stderr, getline(),
stdin, feof(), perror(), fputc(),
stdout, getopt_long */
@@ -44,18 +44,12 @@
#include /* or, not */
#include /* bool, false, true */
#include /* strlen, rindex, strncmp, strcmp */
-#include /* struct argp_option, struct
- argp_state, struct argp,
- argp_parse(), error_t,
- ARGP_KEY_ARG, ARGP_KEY_END,
- ARGP_ERR_UNKNOWN */
+#include /* getopt_long */
volatile bool quit_now = false;
bool debug = false;
-const char *argp_program_version = "password-prompt 1.0";
-const char *argp_program_bug_address = "";
-static void termination_handler(__attribute__((unused))int signum){
+void termination_handler(__attribute__((unused))int signum){
quit_now = true;
}
@@ -69,48 +63,32 @@
struct sigaction old_action,
new_action = { .sa_handler = termination_handler,
.sa_flags = 0 };
- {
- struct argp_option options[] = {
- { .name = "prefix", .key = 'p',
- .arg = "PREFIX", .flags = 0,
- .doc = "Prefix shown before the prompt", .group = 2 },
- { .name = "debug", .key = 128,
- .doc = "Debug mode", .group = 3 },
- { .name = NULL }
- };
-
- error_t parse_opt (int key, char *arg, struct argp_state *state) {
- /* Get the INPUT argument from `argp_parse', which we know is a
- pointer to our plugin list pointer. */
- switch (key) {
- case 'p':
- prefix = arg;
- break;
- case 128:
- debug = true;
- break;
- case ARGP_KEY_ARG:
- argp_usage (state);
- break;
- case ARGP_KEY_END:
- break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
+
+ while (true){
+ static struct option long_options[] = {
+ {"debug", no_argument, (int *)&debug, 1},
+ {"prefix", required_argument, 0, 'p'},
+ {0, 0, 0, 0} };
+
+ int option_index = 0;
+ ret = getopt_long (argc, argv, "p:", long_options, &option_index);
+
+ if (ret == -1){
+ break;
}
-
- struct argp argp = { .options = options, .parser = parse_opt,
- .args_doc = "",
- .doc = "Mandos password-prompt -- Read and"
- " output a password" };
- ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
- if (ret == ARGP_ERR_UNKNOWN){
- fprintf(stderr, "Unknown error while parsing arguments\n");
- return EXIT_FAILURE;
+
+ switch(ret){
+ case 0:
+ break;
+ case 'p':
+ prefix = optarg;
+ break;
+ default:
+ fprintf(stderr, "bad arguments\n");
+ exit(EXIT_FAILURE);
}
}
-
+
if (debug){
fprintf(stderr, "Starting %s\n", argv[0]);
}
@@ -119,7 +97,6 @@
}
if (tcgetattr(STDIN_FILENO, &t_old) != 0){
- perror("tcgetattr");
return EXIT_FAILURE;
}
@@ -127,43 +104,16 @@
sigaddset(&new_action.sa_mask, SIGINT);
sigaddset(&new_action.sa_mask, SIGHUP);
sigaddset(&new_action.sa_mask, SIGTERM);
- ret = sigaction(SIGINT, NULL, &old_action);
- if(ret == -1){
- perror("sigaction");
- return EXIT_FAILURE;
- }
- if (old_action.sa_handler != SIG_IGN){
- ret = sigaction(SIGINT, &new_action, NULL);
- if(ret == -1){
- perror("sigaction");
- return EXIT_FAILURE;
- }
- }
- ret = sigaction(SIGHUP, NULL, &old_action);
- if(ret == -1){
- perror("sigaction");
- return EXIT_FAILURE;
- }
- if (old_action.sa_handler != SIG_IGN){
- ret = sigaction(SIGHUP, &new_action, NULL);
- if(ret == -1){
- perror("sigaction");
- return EXIT_FAILURE;
- }
- }
- ret = sigaction(SIGTERM, NULL, &old_action);
- if(ret == -1){
- perror("sigaction");
- return EXIT_FAILURE;
- }
- if (old_action.sa_handler != SIG_IGN){
- ret = sigaction(SIGTERM, &new_action, NULL);
- if(ret == -1){
- perror("sigaction");
- return EXIT_FAILURE;
- }
- }
-
+ sigaction(SIGINT, NULL, &old_action);
+ if (old_action.sa_handler != SIG_IGN)
+ sigaction(SIGINT, &new_action, NULL);
+ sigaction(SIGHUP, NULL, &old_action);
+ if (old_action.sa_handler != SIG_IGN)
+ sigaction(SIGHUP, &new_action, NULL);
+ sigaction(SIGTERM, NULL, &old_action);
+ if (old_action.sa_handler != SIG_IGN)
+ sigaction(SIGTERM, &new_action, NULL);
+
if (debug){
fprintf(stderr, "Removing echo flag from terminal attributes\n");
@@ -181,58 +131,22 @@
}
while(true){
if (quit_now){
- if(debug){
- fprintf(stderr, "Interrupted by signal, exiting.\n");
- }
status = EXIT_FAILURE;
break;
}
if(prefix){
- fprintf(stderr, "%s ", prefix);
- }
- {
- const char *cryptsource = getenv("cryptsource");
- const char *crypttarget = getenv("crypttarget");
- const char *const prompt
- = "Enter passphrase to unlock the disk";
- if(cryptsource == NULL){
- if(crypttarget == NULL){
- fprintf(stderr, "%s: ", prompt);
- } else {
- fprintf(stderr, "%s (%s): ", prompt, crypttarget);
- }
- } else {
- if(crypttarget == NULL){
- fprintf(stderr, "%s %s: ", prompt, cryptsource);
- } else {
- fprintf(stderr, "%s %s (%s): ", prompt, cryptsource,
- crypttarget);
- }
- }
- }
+ fprintf(stderr, "%s Password: ", prefix);
+ } else {
+ fprintf(stderr, "Password: ");
+ }
ret = getline(&buffer, &n, stdin);
if (ret > 0){
+ fprintf(stdout, "%s", buffer);
status = EXIT_SUCCESS;
- /* Make n = data size instead of allocated buffer size */
- n = (size_t)ret;
- /* Strip final newline */
- if(n>0 and buffer[n-1] == '\n'){
- buffer[n-1] = '\0'; /* not strictly necessary */
- n--;
- }
- size_t written = 0;
- while(written < n){
- ret = write(STDOUT_FILENO, buffer + written, n - written);
- if(ret < 0){
- perror("write");
- status = EXIT_FAILURE;
- break;
- }
- written += (size_t)ret;
- }
break;
}
+ // ret == 0 makes no other sence than to retry to read from stdin
if (ret < 0){
if (errno != EINTR and not feof(stdin)){
perror("getline");
@@ -240,31 +154,18 @@
break;
}
}
- /* if(ret == 0), then the only sensible thing to do is to retry to
- read from stdin */
fputc('\n', stderr);
- if(debug and not quit_now){
- /* If quit_now is true, we were interrupted by a signal, and
- will print that later, so no need to show this too. */
- fprintf(stderr, "getline() returned 0, retrying.\n");
- }
}
- free(buffer);
-
if (debug){
fprintf(stderr, "Restoring terminal attributes\n");
}
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
perror("tcsetattr+echo");
}
-
+
if (debug){
- fprintf(stderr, "%s is exiting with status %d\n", argv[0],
- status);
- }
- if(status == EXIT_SUCCESS){
- fputc('\n', stderr);
+ fprintf(stderr, "%s is exiting\n", argv[0]);
}
return status;
=== removed file 'plugins.d/password-prompt.xml'
--- plugins.d/password-prompt.xml 2008-09-06 16:31:49 +0000
+++ plugins.d/password-prompt.xml 1970-01-01 00:00:00 +0000
@@ -1,304 +0,0 @@
-
-
-
-
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &VERSION;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2008
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8mandos
-
-
-
- &COMMANDNAME;
- Prompt for a password and output it.
-
-
-
-
- &COMMANDNAME;
-
-
- PREFIX
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
- DESCRIPTION
-
- All &COMMANDNAME; does is prompt for a
- password and output any given password to standard output. This
- is not very useful on its own. This program is really meant to
- run as a plugin in the Mandos
- client-side system, where it is used as a fallback and
- alternative to retrieving passwords from a Mandos server.
-
-
- This program is little more than a getpass3
- wrapper, although actual use of that function is not guaranteed
- or implied.
-
-
-
-
- OPTIONS
-
- This program is commonly not invoked from the command line; it
- is normally started by the Mandos
- plugin runner, see plugin-runner8mandos
- . Any command line options this program accepts
- are therefore normally provided by the plugin runner, and not
- directly.
-
-
-
-
-
-
-
-
- Prefix string shown before the password prompt.
-
-
-
-
-
-
-
-
- Enable debug mode. This will enable a lot of output to
- standard error about what the program is doing. The
- program will still perform all other functions normally.
-
-
-
-
-
-
-
-
-
- Gives a help message about options and their meanings.
-
-
-
-
-
-
-
-
- Gives a short usage message.
-
-
-
-
-
-
-
-
-
- Prints the program version.
-
-
-
-
-
-
-
- EXIT STATUS
-
- If exit status is 0, the output from the program is the password
- as it was read. Otherwise, if exit status is other than 0, the
- program has encountered an error, and any output so far could be
- corrupt and/or truncated, and should therefore be ignored.
-
-
-
-
- ENVIRONMENT
-
-
- cryptsource
- crypttarget
-
-
- If set, these environment variables will be assumed to
- contain the source device name and the target device
- mapper name, respectively, and will be shown as part of
- the prompt.
-
-
- These variables will normally be inherited from
- plugin-runner
- 8mandos, which will
- normally have inherited them from
- /scripts/local-top/cryptroot in the
- initial RAM disk environment, which will
- have set them from parsing kernel arguments and
- /conf/conf.d/cryptroot (also in the
- initial RAM disk environment), which in turn will have been
- created when the initial RAM disk image was created by
- /usr/share/initramfs-tools/hooks/cryptroot, by
- extracting the information of the root file system from
- /etc/crypttab.
-
-
- This behavior is meant to exactly mirror the behavior of
- askpass, the default password prompter.
-
-
-
-
-
-
-
- BUGS
-
- None are known at this time.
-
-
-
-
- EXAMPLE
-
- Note that normally, command line options will not be given
- directly, but via options for the Mandos plugin-runner
- 8mandos.
-
-
-
- Normal invocation needs no options:
-
-
- &COMMANDNAME;
-
-
-
-
- Show a prefix before the prompt; in this case, a host name.
- It might be useful to be reminded of which host needs a
- password, in case of KVM switches, etc.
-
-
-
-
-&COMMANDNAME; --prefix=host.example.org:
-
-
-
-
-
- Run in debug mode.
-
-
-
- &COMMANDNAME; --debug
-
-
-
-
-
- SECURITY
-
- On its own, this program is very simple, and does not exactly
- present any security risks. The one thing that could be
- considered worthy of note is this: This program is meant to be
- run by plugin-runner8mandos
- , and will, when run standalone, outside, in a
- normal environment, immediately output on its standard output
- any presumably secret password it just received. Therefore,
- when running this program standalone (which should never
- normally be done), take care not to type in any real secret
- password by force of habit, since it would then immediately be
- shown as output.
-
-
- To further alleviate any risk of being locked out of a system,
- the plugin-runner
- 8mandos has a fallback
- mode which does the same thing as this program, only with less
- features.
-
-
-
-
- SEE ALSO
-
- crypttab
- 5
- mandos-client
- 8mandos
- plugin-runner
- 8mandos,
-
-
-
-
-
-
-
-
=== removed file 'plugins.d/usplash'
--- plugins.d/usplash 2008-08-14 02:24:59 +0000
+++ plugins.d/usplash 1970-01-01 00:00:00 +0000
@@ -1,42 +0,0 @@
-#!/bin/sh -e
-
-# If not on a tty, then get rid of possibly disrupting stderr output
-if ! tty -s; then
- exec 2>/dev/null
-fi
-
-test -x /sbin/usplash
-
-usplash="`pidof usplash -o $$`"
-test -n "$usplash"
-
-# We get some variables from cryptsetup:
-# $cryptsource the device node, like "/dev/sda3"
-# $crypttarget the device mapper name, like "sda3_crypt".
-
-prompt="Enter passphrase to unlock"
-if [ -n "$crypttarget" ]; then
- prompt="$prompt the disk $crypttarget"
-fi
-if [ -n "$cryptsource" ]; then
- prompt="$prompt ($cryptsource)"
-fi
-
-splash_input_password(){
- test -p /dev/.initramfs/usplash_outfifo || return 1
- /sbin/usplash_write "INPUTQUIET $1" || return 1
- cat /dev/.initramfs/usplash_outfifo 2> /dev/null || return 1
-}
-
-# Usplash keeps waiting for input even if some other plugin provided
-# the password, so we must kill it
-trap "kill -TERM $usplash; sleep 2; kill -KILL $usplash;
- kill -TERM $$" TERM HUP
-
-password="`splash_input_password \"$prompt: \" password`"
-
-trap - TERM
-
-/sbin/usplash_write "TIMEOUT 15"
-
-echo -n "$password"
=== renamed file 'mandos.conf' => 'server.conf'
--- mandos.conf 2008-08-18 23:55:28 +0000
+++ server.conf 2008-07-29 03:35:39 +0000
@@ -1,38 +1,7 @@
-# This file must have exactly one section named "DEFAULT".
-[DEFAULT]
-
-# These are the default values for the server, uncomment and change
-# them if needed.
-
-
-# If "interface" is set, the server will only listen to a specific
-# network interface.
-;interface =
-
-
-# If "address" is set, the server will only listen to a specific
-# address. This must currently be an IPv6 address; an IPv4 address
-# can be specified using the "::FFFF:192.0.2.3" syntax. Also, if this
-# is a link-local address, an interface should be set above.
-;address =
-
-
-# If "port" is set, the server to bind to that port. By default, the
-# server will listen to an arbitrary port.
-;port =
-
-
-# If "debug" is true, the server will run in the foreground and print
-# a lot of debugging information.
-;debug = False
-
-
-# GnuTLS priority for the TLS handshake. See gnutls_priority_init(3).
-;priority = SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP
-
-
-# Zeroconf service name. You need to change this if you for some
-# reason want to run more than one server on the same *host*.
-# If there are name collisions on the same *network*, the server will
-# rename itself to "Mandos #2", etc.
-;servicename = Mandos
+[server]
+#interface =
+#address =
+#port =
+#debug =
+#priority = SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP
+#servicename = Mandos
=== renamed file 'mandos' => 'server.py'
--- mandos 2008-09-05 18:37:28 +0000
+++ server.py 2008-07-31 19:48:05 +0000
@@ -6,9 +6,9 @@
# This program is partly derived from an example program for an Avahi
# service publisher, downloaded from
# . This includes the
-# methods "add" and "remove" in the "AvahiService" class, the
-# "server_state_changed" and "entry_group_state_changed" functions,
-# and some lines in "main".
+# following functions: "AvahiService.add", "AvahiService.remove",
+# "server_state_changed", "entry_group_state_changed", and some lines
+# in "main".
#
# Everything else is
# Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
@@ -24,8 +24,7 @@
# 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
-# .
+# along with this program. If not, see .
#
# Contact the authors at .
#
@@ -55,7 +54,6 @@
import stat
import logging
import logging.handlers
-import pwd
import dbus
import gobject
@@ -63,20 +61,26 @@
from dbus.mainloop.glib import DBusGMainLoop
import ctypes
-version = "1.0"
+# Brief description of the operation of this program:
+#
+# This server announces itself as a Zeroconf service. Connecting
+# clients use the TLS protocol, with the unusual quirk that this
+# server program acts as a TLS "client" while a connecting client acts
+# as a TLS "server". The client (acting as a TLS "server") must
+# supply an OpenPGP certificate, and the fingerprint of this
+# certificate is used by this server to look up (in a list read from a
+# file at start time) which binary blob to give the client. No other
+# authentication or authorization is done by this server.
+
logger = logging.Logger('mandos')
syslogger = logging.handlers.SysLogHandler\
- (facility = logging.handlers.SysLogHandler.LOG_DAEMON,
- address = "/dev/log")
+ (facility = logging.handlers.SysLogHandler.LOG_DAEMON)
syslogger.setFormatter(logging.Formatter\
- ('Mandos: %(levelname)s: %(message)s'))
+ ('%(levelname)s: %(message)s'))
logger.addHandler(syslogger)
+del syslogger
-console = logging.StreamHandler()
-console.setFormatter(logging.Formatter('%(name)s: %(levelname)s:'
- ' %(message)s'))
-logger.addHandler(console)
class AvahiError(Exception):
def __init__(self, value):
@@ -92,24 +96,25 @@
class AvahiService(object):
- """An Avahi (Zeroconf) service.
- Attributes:
+ """
interface: integer; avahi.IF_UNSPEC or an interface index.
Used to optionally bind to the specified interface.
- name: string; Example: 'Mandos'
- type: string; Example: '_mandos._tcp'.
- See
- port: integer; what port to announce
- TXT: list of strings; TXT record for the service
- domain: string; Domain to publish on, default to .local if empty.
- host: string; Host to publish records for, default is localhost
- max_renames: integer; maximum number of renames
- rename_count: integer; counter so we only rename after collisions
- a sensible number of times
+ name = string; Example: "Mandos"
+ type = string; Example: "_mandos._tcp".
+ See
+ port = integer; what port to announce
+ TXT = list of strings; TXT record for the service
+ domain = string; Domain to publish on, default to .local if empty.
+ host = string; Host to publish records for, default to localhost
+ if empty.
+ max_renames = integer; maximum number of renames
+ rename_count = integer; counter so we only rename after collisions
+ a sensible number of times
"""
def __init__(self, interface = avahi.IF_UNSPEC, name = None,
type = None, port = None, TXT = None, domain = "",
- host = "", max_renames = 32768):
+ host = "", max_renames = 12):
+ """An Avahi (Zeroconf) service. """
self.interface = interface
self.name = name
self.type = type
@@ -121,20 +126,14 @@
self.domain = domain
self.host = host
self.rename_count = 0
- self.max_renames = max_renames
def rename(self):
"""Derived from the Avahi example code"""
if self.rename_count >= self.max_renames:
- logger.critical(u"No suitable Zeroconf service name found"
- u" after %i retries, exiting.",
- rename_count)
+ logger.critical(u"No suitable service name found after %i"
+ u" retries, exiting.", rename_count)
raise AvahiServiceError("Too many renames")
- self.name = server.GetAlternativeServiceName(self.name)
- logger.info(u"Changing Zeroconf service name to %r ...",
- str(self.name))
- syslogger.setFormatter(logging.Formatter\
- ('Mandos (%s): %%(levelname)s:'
- ' %%(message)s' % self.name))
+ name = server.GetAlternativeServiceName(name)
+ logger.notice(u"Changing name to %r ...", name)
self.remove()
self.add()
self.rename_count += 1
@@ -152,7 +151,7 @@
avahi.DBUS_INTERFACE_ENTRY_GROUP)
group.connect_to_signal('StateChanged',
entry_group_state_changed)
- logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
+ logger.debug(u"Adding service '%s' of type '%s' ...",
service.name, service.type)
group.AddService(
self.interface, # interface
@@ -176,7 +175,7 @@
fingerprint: string (40 or 32 hexadecimal digits); used to
uniquely identify the client
secret: bytestring; sent verbatim (over TLS) to client
- host: string; available for use by the checker command
+ fqdn: string (FQDN); available for use by the checker command
created: datetime.datetime(); object creation, not client host
last_checked_ok: datetime.datetime() or None if not yet checked OK
timeout: datetime.timedelta(); How long from last_checked_ok
@@ -222,38 +221,38 @@
interval = property(lambda self: self._interval,
_set_interval)
del _set_interval
- def __init__(self, name = None, stop_hook=None, config={}):
- """Note: the 'checker' key in 'config' sets the
- 'checker_command' attribute and *not* the 'checker'
- attribute."""
+ def __init__(self, name=None, stop_hook=None, fingerprint=None,
+ secret=None, secfile=None, fqdn=None, timeout=None,
+ interval=-1, checker=None):
+ """Note: the 'checker' argument sets the 'checker_command'
+ attribute and not the 'checker' attribute.."""
self.name = name
logger.debug(u"Creating client %r", self.name)
- # Uppercase and remove spaces from fingerprint for later
- # comparison purposes with return value from the fingerprint()
- # function
- self.fingerprint = config["fingerprint"].upper()\
- .replace(u" ", u"")
+ # Uppercase and remove spaces from fingerprint
+ # for later comparison purposes with return value of
+ # the fingerprint() function
+ self.fingerprint = fingerprint.upper().replace(u" ", u"")
logger.debug(u" Fingerprint: %s", self.fingerprint)
- if "secret" in config:
- self.secret = config["secret"].decode(u"base64")
- elif "secfile" in config:
- sf = open(config["secfile"])
+ if secret:
+ self.secret = secret.decode(u"base64")
+ elif secfile:
+ sf = open(secfile)
self.secret = sf.read()
sf.close()
else:
raise TypeError(u"No secret or secfile for client %s"
% self.name)
- self.host = config.get("host", "")
+ self.fqdn = fqdn
self.created = datetime.datetime.now()
self.last_checked_ok = None
- self.timeout = string_to_delta(config["timeout"])
- self.interval = string_to_delta(config["interval"])
+ self.timeout = string_to_delta(timeout)
+ self.interval = string_to_delta(interval)
self.stop_hook = stop_hook
self.checker = None
self.checker_initiator_tag = None
self.stop_initiator_tag = None
self.checker_callback_tag = None
- self.check_command = config["checker"]
+ self.check_command = checker
def start(self):
"""Start this client's checker and timeout hooks"""
# Schedule a new checker to be started an 'interval' from now,
@@ -272,8 +271,8 @@
The possibility that a client might be restarted is left open,
but not currently used."""
# If this client doesn't have a secret, it is already stopped.
- if hasattr(self, "secret") and self.secret:
- logger.info(u"Stopping client %s", self.name)
+ if self.secret:
+ logger.debug(u"Stopping client %s", self.name)
self.secret = None
else:
return False
@@ -298,8 +297,8 @@
self.checker = None
if os.WIFEXITED(condition) \
and (os.WEXITSTATUS(condition) == 0):
- logger.info(u"Checker for %(name)s succeeded",
- vars(self))
+ logger.debug(u"Checker for %(name)s succeeded",
+ vars(self))
self.last_checked_ok = now
gobject.source_remove(self.stop_initiator_tag)
self.stop_initiator_tag = gobject.timeout_add\
@@ -309,8 +308,8 @@
logger.warning(u"Checker for %(name)s crashed?",
vars(self))
else:
- logger.info(u"Checker for %(name)s failed",
- vars(self))
+ logger.debug(u"Checker for %(name)s failed",
+ vars(self))
def start_checker(self):
"""Start a new checker subprocess if one is not running.
If a checker already exists, leave it running and do
@@ -326,7 +325,7 @@
if self.checker is None:
try:
# In case check_command has exactly one % operator
- command = self.check_command % self.host
+ command = self.check_command % self.fqdn
except TypeError:
# Escape attributes for the shell
escaped_attrs = dict((key, re.escape(str(val)))
@@ -339,19 +338,15 @@
u' %s', self.check_command, error)
return True # Try again later
try:
- logger.info(u"Starting checker %r for %s",
- command, self.name)
- # We don't need to redirect stdout and stderr, since
- # in normal mode, that is already done by daemon(),
- # and in debug mode we don't want to. (Stdin is
- # always replaced by /dev/null.)
+ logger.debug(u"Starting checker %r for %s",
+ command, self.name)
self.checker = subprocess.Popen(command,
close_fds=True,
shell=True, cwd="/")
self.checker_callback_tag = gobject.child_watch_add\
(self.checker.pid,
self.checker_callback)
- except OSError, error:
+ except subprocess.OSError, error:
logger.error(u"Failed to start subprocess: %s",
error)
# Re-run this periodically if run by gobject.timeout_add
@@ -363,7 +358,7 @@
self.checker_callback_tag = None
if getattr(self, "checker", None) is None:
return
- logger.debug(u"Stopping checker for %(name)s", vars(self))
+ logger.debug("Stopping checker for %(name)s", vars(self))
try:
os.kill(self.checker.pid, signal.SIGTERM)
#os.sleep(0.5)
@@ -401,26 +396,20 @@
def fingerprint(openpgp):
"Convert an OpenPGP bytestring to a hexdigit fingerprint string"
+ # New empty GnuTLS certificate
+ crt = gnutls.library.types.gnutls_openpgp_crt_t()
+ gnutls.library.functions.gnutls_openpgp_crt_init\
+ (ctypes.byref(crt))
# New GnuTLS "datum" with the OpenPGP public key
datum = gnutls.library.types.gnutls_datum_t\
(ctypes.cast(ctypes.c_char_p(openpgp),
ctypes.POINTER(ctypes.c_ubyte)),
ctypes.c_uint(len(openpgp)))
- # New empty GnuTLS certificate
- crt = gnutls.library.types.gnutls_openpgp_crt_t()
- gnutls.library.functions.gnutls_openpgp_crt_init\
- (ctypes.byref(crt))
# Import the OpenPGP public key into the certificate
- gnutls.library.functions.gnutls_openpgp_crt_import\
- (crt, ctypes.byref(datum),
- gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
- # Verify the self signature in the key
- crtverify = ctypes.c_uint();
- gnutls.library.functions.gnutls_openpgp_crt_verify_self\
- (crt, 0, ctypes.byref(crtverify))
- if crtverify.value != 0:
- gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
- raise gnutls.errors.CertificateSecurityError("Verify failed")
+ ret = gnutls.library.functions.gnutls_openpgp_crt_import\
+ (crt,
+ ctypes.byref(datum),
+ gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
# New buffer for the fingerprint
buffer = ctypes.create_string_buffer(20)
buffer_length = ctypes.c_size_t()
@@ -442,20 +431,10 @@
Note: This will run in its own forked process."""
def handle(self):
- logger.info(u"TCP connection from: %s",
+ logger.debug(u"TCP connection from: %s",
unicode(self.client_address))
session = gnutls.connection.ClientSession\
(self.request, gnutls.connection.X509Credentials())
-
- line = self.request.makefile().readline()
- logger.debug(u"Protocol version: %r", line)
- try:
- if int(line.strip().split()[0]) > 1:
- raise RuntimeError
- except (ValueError, IndexError, RuntimeError), error:
- logger.error(u"Unknown protocol version: %s", error)
- return
-
# Note: gnutls.connection.X509Credentials is really a generic
# GnuTLS certificate credentials object so long as no X.509
# keys are added to it. Therefore, we can use it here despite
@@ -474,14 +453,14 @@
try:
session.handshake()
except gnutls.errors.GNUTLSError, error:
- logger.warning(u"Handshake failed: %s", error)
+ logger.debug(u"Handshake failed: %s", error)
# Do not run session.bye() here: the session is not
# established. Just abandon the request.
return
try:
fpr = fingerprint(peer_certificate(session))
except (TypeError, gnutls.errors.GNUTLSError), error:
- logger.warning(u"Bad certificate: %s", error)
+ logger.debug(u"Bad certificate: %s", error)
session.bye()
return
logger.debug(u"Fingerprint: %s", fpr)
@@ -491,16 +470,14 @@
client = c
break
if not client:
- logger.warning(u"Client not found for fingerprint: %s",
- fpr)
+ logger.debug(u"Client not found for fingerprint: %s", fpr)
session.bye()
return
# Have to check if client.still_valid(), since it is possible
# that the client timed out while establishing the GnuTLS
# session.
if not client.still_valid():
- logger.warning(u"Client %(name)s is invalid",
- vars(client))
+ logger.debug(u"Client %(name)s is invalid", vars(client))
session.bye()
return
sent_size = 0
@@ -518,7 +495,6 @@
Attributes:
settings: Server settings
clients: Set() of Client objects
- enabled: Boolean; whether this server is activated yet
"""
address_family = socket.AF_INET6
def __init__(self, *args, **kwargs):
@@ -528,7 +504,6 @@
if "clients" in kwargs:
self.clients = kwargs["clients"]
del kwargs["clients"]
- self.enabled = False
return super(type(self), self).__init__(*args, **kwargs)
def server_bind(self):
"""This overrides the normal server_bind() function
@@ -543,9 +518,9 @@
self.settings["interface"])
except socket.error, error:
if error[0] == errno.EPERM:
- logger.error(u"No permission to"
- u" bind to interface %s",
- self.settings["interface"])
+ logger.warning(u"No permission to"
+ u" bind to interface %s",
+ self.settings["interface"])
else:
raise error
# Only bind(2) the socket if we really need to.
@@ -554,22 +529,10 @@
in6addr_any = "::"
self.server_address = (in6addr_any,
self.server_address[1])
- elif not self.server_address[1]:
+ elif self.server_address[1] is None:
self.server_address = (self.server_address[0],
0)
-# if self.settings["interface"]:
-# self.server_address = (self.server_address[0],
-# 0, # port
-# 0, # flowinfo
-# if_nametoindex
-# (self.settings
-# ["interface"]))
return super(type(self), self).server_bind()
- def server_activate(self):
- if self.enabled:
- return super(type(self), self).server_activate()
- def enable(self):
- self.enabled = True
def string_to_delta(interval):
@@ -585,36 +548,31 @@
datetime.timedelta(1)
>>> string_to_delta(u'1w')
datetime.timedelta(7)
- >>> string_to_delta('5m 30s')
- datetime.timedelta(0, 330)
"""
- timevalue = datetime.timedelta(0)
- for s in interval.split():
- try:
- suffix=unicode(s[-1])
- value=int(s[:-1])
- if suffix == u"d":
- delta = datetime.timedelta(value)
- elif suffix == u"s":
- delta = datetime.timedelta(0, value)
- elif suffix == u"m":
- delta = datetime.timedelta(0, 0, 0, 0, value)
- elif suffix == u"h":
- delta = datetime.timedelta(0, 0, 0, 0, 0, value)
- elif suffix == u"w":
- delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
- else:
- raise ValueError
- except (ValueError, IndexError):
+ try:
+ suffix=unicode(interval[-1])
+ value=int(interval[:-1])
+ if suffix == u"d":
+ delta = datetime.timedelta(value)
+ elif suffix == u"s":
+ delta = datetime.timedelta(0, value)
+ elif suffix == u"m":
+ delta = datetime.timedelta(0, 0, 0, 0, value)
+ elif suffix == u"h":
+ delta = datetime.timedelta(0, 0, 0, 0, 0, value)
+ elif suffix == u"w":
+ delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
+ else:
raise ValueError
- timevalue += delta
- return timevalue
+ except (ValueError, IndexError):
+ raise ValueError
+ return delta
def server_state_changed(state):
"""Derived from the Avahi example code"""
if state == avahi.SERVER_COLLISION:
- logger.error(u"Zeroconf server name collision")
+ logger.warning(u"Server name collision")
service.remove()
elif state == avahi.SERVER_RUNNING:
service.add()
@@ -622,32 +580,40 @@
def entry_group_state_changed(state, error):
"""Derived from the Avahi example code"""
- logger.debug(u"Avahi state change: %i", state)
+ logger.debug(u"state change: %i", state)
if state == avahi.ENTRY_GROUP_ESTABLISHED:
- logger.debug(u"Zeroconf service established.")
+ logger.debug(u"Service established.")
elif state == avahi.ENTRY_GROUP_COLLISION:
- logger.warning(u"Zeroconf service name collision.")
+ logger.warning(u"Service name collision.")
service.rename()
elif state == avahi.ENTRY_GROUP_FAILURE:
- logger.critical(u"Avahi: Error in group state changed %s",
+ logger.critical(u"Error in group state changed %s",
unicode(error))
raise AvahiGroupError("State changed: %s", str(error))
-def if_nametoindex(interface):
+def if_nametoindex(interface, _func=[None]):
"""Call the C function if_nametoindex(), or equivalent"""
- global if_nametoindex
+ if _func[0] is not None:
+ return _func[0](interface)
try:
if "ctypes.util" not in sys.modules:
import ctypes.util
- if_nametoindex = ctypes.cdll.LoadLibrary\
- (ctypes.util.find_library("c")).if_nametoindex
+ while True:
+ try:
+ libc = ctypes.cdll.LoadLibrary\
+ (ctypes.util.find_library("c"))
+ _func[0] = libc.if_nametoindex
+ return _func[0](interface)
+ except IOError, e:
+ if e != errno.EINTR:
+ raise
except (OSError, AttributeError):
if "struct" not in sys.modules:
import struct
if "fcntl" not in sys.modules:
import fcntl
- def if_nametoindex(interface):
+ def the_hard_way(interface):
"Get an interface index the hard way, i.e. using fcntl()"
SIOCGIFINDEX = 0x8933 # From /usr/include/linux/sockios.h
s = socket.socket()
@@ -656,10 +622,11 @@
s.close()
interface_index = struct.unpack("I", ifreq[16:20])[0]
return interface_index
- return if_nametoindex(interface)
-
-
-def daemon(nochdir = False, noclose = False):
+ _func[0] = the_hard_way
+ return _func[0](interface)
+
+
+def daemon(nochdir, noclose):
"""See daemon(3). Standard BSD Unix function.
This should really exist as os.daemon, but it doesn't (yet)."""
if os.fork():
@@ -667,8 +634,6 @@
os.setsid()
if not nochdir:
os.chdir("/")
- if os.fork():
- sys.exit()
if not noclose:
# Close all standard open file descriptors
null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
@@ -686,7 +651,7 @@
global main_loop_started
main_loop_started = False
- parser = OptionParser(version = "%%prog %s" % version)
+ parser = OptionParser()
parser.add_option("-i", "--interface", type="string",
metavar="IF", help="Bind to interface IF")
parser.add_option("-a", "--address", type="string",
@@ -695,7 +660,7 @@
help="Port number to receive requests on")
parser.add_option("--check", action="store_true", default=False,
help="Run self-test")
- parser.add_option("--debug", action="store_true",
+ parser.add_option("--debug", action="store_true", default=False,
help="Debug mode; run in foreground and log to"
" terminal")
parser.add_option("--priority", type="string", help="GnuTLS"
@@ -726,12 +691,13 @@
# Parse config file for server-global settings
server_config = ConfigParser.SafeConfigParser(server_defaults)
del server_defaults
- server_config.read(os.path.join(options.configdir, "mandos.conf"))
+ server_config.read(os.path.join(options.configdir, "server.conf"))
+ server_section = "server"
# Convert the SafeConfigParser object to a dict
- server_settings = server_config.defaults()
+ server_settings = dict(server_config.items(server_section))
# Use getboolean on the boolean config option
server_settings["debug"] = server_config.getboolean\
- ("DEFAULT", "debug")
+ (server_section, "debug")
del server_config
# Override the settings from the config file with command line
@@ -744,69 +710,20 @@
del options
# Now we have our good server settings in "server_settings"
- debug = server_settings["debug"]
-
- if not debug:
- syslogger.setLevel(logging.WARNING)
- console.setLevel(logging.WARNING)
-
- if server_settings["servicename"] != "Mandos":
- syslogger.setFormatter(logging.Formatter\
- ('Mandos (%s): %%(levelname)s:'
- ' %%(message)s'
- % server_settings["servicename"]))
-
# Parse config file with clients
client_defaults = { "timeout": "1h",
"interval": "5m",
- "checker": "fping -q -- %(host)s",
- "host": "",
+ "checker": "fping -q -- %%(fqdn)s",
}
client_config = ConfigParser.SafeConfigParser(client_defaults)
client_config.read(os.path.join(server_settings["configdir"],
"clients.conf"))
- clients = Set()
- tcp_server = IPv6_TCPServer((server_settings["address"],
- server_settings["port"]),
- tcp_handler,
- settings=server_settings,
- clients=clients)
- pidfilename = "/var/run/mandos.pid"
- try:
- pidfile = open(pidfilename, "w")
- except IOError, error:
- logger.error("Could not open file %r", pidfilename)
-
- uid = 65534
- gid = 65534
- try:
- uid = pwd.getpwnam("mandos").pw_uid
- except KeyError:
- try:
- uid = pwd.getpwnam("nobody").pw_uid
- except KeyError:
- pass
- try:
- gid = pwd.getpwnam("mandos").pw_gid
- except KeyError:
- try:
- gid = pwd.getpwnam("nogroup").pw_gid
- except KeyError:
- pass
- try:
- os.setuid(uid)
- os.setgid(gid)
- except OSError, error:
- if error[0] != errno.EPERM:
- raise error
-
global service
service = AvahiService(name = server_settings["servicename"],
type = "_mandos._tcp", );
if server_settings["interface"]:
- service.interface = if_nametoindex\
- (server_settings["interface"])
+ service.interface = if_nametoindex(server_settings["interface"])
global main_loop
global bus
@@ -815,50 +732,36 @@
DBusGMainLoop(set_as_default=True )
main_loop = gobject.MainLoop()
bus = dbus.SystemBus()
- server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
- avahi.DBUS_PATH_SERVER),
- avahi.DBUS_INTERFACE_SERVER)
+ server = dbus.Interface(
+ bus.get_object( avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER ),
+ avahi.DBUS_INTERFACE_SERVER )
# End of Avahi example code
+ debug = server_settings["debug"]
+
+ if debug:
+ console = logging.StreamHandler()
+ # console.setLevel(logging.DEBUG)
+ console.setFormatter(logging.Formatter\
+ ('%(levelname)s: %(message)s'))
+ logger.addHandler(console)
+ del console
+
+ clients = Set()
def remove_from_clients(client):
clients.remove(client)
if not clients:
- logger.critical(u"No clients left, exiting")
+ logger.debug(u"No clients left, exiting")
sys.exit()
- clients.update(Set(Client(name = section,
+ clients.update(Set(Client(name=section,
stop_hook = remove_from_clients,
- config
- = dict(client_config.items(section)))
+ **(dict(client_config\
+ .items(section))))
for section in client_config.sections()))
- if not clients:
- logger.critical(u"No clients defined")
- sys.exit(1)
-
- if debug:
- # Redirect stdin so all checkers get /dev/null
- null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
- os.dup2(null, sys.stdin.fileno())
- if null > 2:
- os.close(null)
- else:
- # No console logging
- logger.removeHandler(console)
- # Close all input and output, do double fork, etc.
- daemon()
-
- try:
- pid = os.getpid()
- pidfile.write(str(pid) + "\n")
- pidfile.close()
- del pidfile
- except IOError, err:
- logger.error(u"Could not write to file %r with PID %d",
- pidfilename, pid)
- except NameError:
- # "pidfile" was never created
- pass
- del pidfilename
+
+ if not debug:
+ daemon(False, False)
def cleanup():
"Cleanup function; run on exit"
@@ -884,13 +787,15 @@
for client in clients:
client.start()
- tcp_server.enable()
- tcp_server.server_activate()
-
+ tcp_server = IPv6_TCPServer((server_settings["address"],
+ server_settings["port"]),
+ tcp_handler,
+ settings=server_settings,
+ clients=clients)
# Find out what port we got
service.port = tcp_server.socket.getsockname()[1]
- logger.info(u"Now listening on address %r, port %d, flowinfo %d,"
- u" scope_id %d" % tcp_server.socket.getsockname())
+ logger.debug(u"Now listening on address %r, port %d, flowinfo %d,"
+ u" scope_id %d" % tcp_server.socket.getsockname())
#service.interface = tcp_server.socket.getsockname()[3]
@@ -909,7 +814,7 @@
tcp_server.handle_request\
(*args[2:], **kwargs) or True)
- logger.debug(u"Starting main loop")
+ logger.debug("Starting main loop")
main_loop_started = True
main_loop.run()
except AvahiError, error: