=== 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 @@ - - - - - -
- - - <para id="interface"> - 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. <emphasis - >Note:</emphasis> a failure to bind to the specified - interface is not considered critical, and the server will not - exit, but instead continue normally. - </para> - - <para id="address"> - 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: <quote><systemitem class="ipaddress" - >::FFFF:192.0.2.3</systemitem ></quote>. - </para> - - <para id="port"> - 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. - </para> - - <para id="debug"> - 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 - <emphasis>not</emphasis> run in debug mode. - </para> - - <para id="priority"> - GnuTLS priority string for the <acronym>TLS</acronym> handshake. - The default is <quote><literal - >SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP</literal></quote>. See - <citerefentry><refentrytitle>gnutls_priority_init</refentrytitle> - <manvolnum>3</manvolnum></citerefentry> for the syntax. - <emphasis>Warning</emphasis>: changing this may make the - <acronym>TLS</acronym> handshake fail, making server-client - communication impossible. - </para> - - <para id="servicename"> - Zeroconf service name. The default is - <quote><literal>Mandos</literal></quote>. This only needs to be - changed this if it, for some reason, is necessary to run more than - one server on the same <emphasis>host</emphasis>, which would not - normally be useful. If there are name collisions on the same - <emphasis>network</emphasis>, the newer server will automatically - rename itself to <quote><literal>Mandos #2</literal></quote>, and - so on; therefore, this option is not needed in that case. - </para> - -</section> === 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 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" - "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ -<!ENTITY VERSION "1.0"> -<!ENTITY CONFNAME "mandos.conf"> -<!ENTITY CONFPATH "<filename>/etc/mandos/mandos.conf</filename>"> -<!ENTITY TIMESTAMP "2008-09-04"> -]> - -<refentry xmlns:xi="http://www.w3.org/2001/XInclude"> - <refentryinfo> - <title>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: